[vlc-devel] [PATCH v2] codec: jpeg encoder implemented

Maxim Bublis b at codemonkey.ru
Tue Jan 28 10:00:07 CET 2014


This patch implements jpeg encoder using libjpeg.

---
 modules/codec/jpeg.c | 211 +++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 197 insertions(+), 14 deletions(-)

diff --git a/modules/codec/jpeg.c b/modules/codec/jpeg.c
index 32964cc..54bf75c 100644
--- a/modules/codec/jpeg.c
+++ b/modules/codec/jpeg.c
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * jpeg.c: jpeg decoder module making use of libjpeg.
  *****************************************************************************
- * Copyright (C) 2013 VLC authors and VideoLAN
+ * Copyright (C) 2013-2014 VLC authors and VideoLAN
  *
  * Authors: Maxim Bublis <b at codemonkey.ru>
  *
@@ -30,18 +30,32 @@
 #include <jpeglib.h>
 #include <setjmp.h>
 
+/* JPEG_SYS_COMMON_MEMBERS:
+ * members common to encoder and decoder descriptors
+ */
+#define JPEG_SYS_COMMON_MEMBERS                             \
+/**@{*/                                                     \
+    /* libjpeg error handler manager */                     \
+    struct jpeg_error_mgr err;                              \
+                                                            \
+    /* setjmp buffer for internal libjpeg error handling */ \
+    jmp_buf setjmp_buffer;                                  \
+                                                            \
+    vlc_object_t *p_obj;                                    \
+                                                            \
+/**@}*/                                                     \
+
+#define ENC_CFG_PREFIX "sout-jpeg-"
+#define ENC_QUALITY_TEXT N_("Quality level")
+#define ENC_QUALITY_LONGTEXT N_("Quality level " \
+    "for encoding (this can enlarge or reduce output image size).")
+
 /*
  * jpeg decoder descriptor
  */
 struct decoder_sys_t
 {
-    /* libjpeg error handler manager */
-    struct jpeg_error_mgr err;
-
-    /* setjmp buffer for internal libjpeg error handling */
-    jmp_buf setjmp_buffer;
-
-    decoder_t *p_dec;
+    JPEG_SYS_COMMON_MEMBERS
 };
 
 static int  OpenDecoder(vlc_object_t *);
@@ -50,15 +64,41 @@ static void CloseDecoder(vlc_object_t *);
 static picture_t *DecodeBlock(decoder_t *, block_t **);
 
 /*
+ * jpeg encoder descriptor
+ */
+struct encoder_sys_t
+{
+    JPEG_SYS_COMMON_MEMBERS
+
+    int i_quality;
+};
+
+static int  OpenEncoder(vlc_object_t *);
+static void CloseEncoder(vlc_object_t *);
+
+static block_t *EncodeBlock(encoder_t *, picture_t *);
+
+/*
  * Module descriptor
  */
 vlc_module_begin()
     set_category(CAT_INPUT)
     set_subcategory(SUBCAT_INPUT_VCODEC)
+    /* decoder main module */
     set_description(N_("JPEG image decoder"))
     set_capability("decoder", 1000)
     set_callbacks(OpenDecoder, CloseDecoder)
     add_shortcut("jpeg")
+
+    /* encoder submodule */
+    add_submodule()
+    add_shortcut("jpeg")
+    set_section(N_("Encoding"), NULL)
+    set_description(N_("JPEG image encoder"))
+    set_capability("encoder", 1000)
+    set_callbacks(OpenEncoder, CloseEncoder)
+    add_integer_with_range(ENC_CFG_PREFIX "quality", 95, 0, 100,
+                           ENC_QUALITY_TEXT, ENC_QUALITY_LONGTEXT, true)
 vlc_module_end()
 
 /*
@@ -80,7 +120,7 @@ static int OpenDecoder(vlc_object_t *p_this)
         return VLC_ENOMEM;
     }
 
-    p_dec->p_sys->p_dec = p_dec;
+    p_dec->p_sys->p_obj = p_this;
 
     /* Set output properties */
     p_dec->fmt_out.i_cat = VIDEO_ES;
@@ -94,7 +134,7 @@ static int OpenDecoder(vlc_object_t *p_this)
 /*
  * Exit error handler for libjpeg
  */
-static void user_error_exit(j_common_ptr p_jpeg)
+static void decoder_error_exit(j_common_ptr p_jpeg)
 {
     decoder_sys_t *p_sys = (decoder_sys_t *)p_jpeg->err;
     p_sys->err.output_message(p_jpeg);
@@ -104,13 +144,13 @@ static void user_error_exit(j_common_ptr p_jpeg)
 /*
  * Emit message error handler for libjpeg
  */
-static void user_error_message(j_common_ptr p_jpeg)
+static void decoder_error_message(j_common_ptr p_jpeg)
 {
     char error_msg[JMSG_LENGTH_MAX];
 
     decoder_sys_t *p_sys = (decoder_sys_t *)p_jpeg->err;
     p_sys->err.format_message(p_jpeg, error_msg);
-    msg_Err(p_sys->p_dec, "%s", error_msg);
+    msg_Err(p_sys->p_obj, "%s", error_msg);
 }
 
 /*
@@ -140,8 +180,8 @@ static picture_t *DecodeBlock(decoder_t *p_dec, block_t **pp_block)
     }
 
     p_jpeg.err = jpeg_std_error(&p_sys->err);
-    p_sys->err.error_exit = user_error_exit;
-    p_sys->err.output_message = user_error_message;
+    p_sys->err.error_exit = decoder_error_exit;
+    p_sys->err.output_message = decoder_error_message;
 
     /* libjpeg longjmp's there in case of error */
     if (setjmp(p_sys->setjmp_buffer))
@@ -222,3 +262,146 @@ static void CloseDecoder(vlc_object_t *p_this)
 
     free(p_sys);
 }
+
+/*
+ * Probe the encoder and return score
+ */
+static int OpenEncoder(vlc_object_t *p_this)
+{
+    encoder_t *p_enc = (encoder_t *)p_this;
+
+    if (p_enc->fmt_out.i_codec != VLC_CODEC_JPEG)
+    {
+        return VLC_EGENERIC;
+    }
+
+    /* Allocate the memory needed to store encoder's structure */
+    p_enc->p_sys = malloc(sizeof(encoder_sys_t));
+    if (p_enc->p_sys == NULL)
+    {
+        return VLC_ENOMEM;
+    }
+
+    p_enc->p_sys->p_obj = p_this;
+
+    p_enc->pf_encode_video = EncodeBlock;
+
+    p_enc->p_sys->i_quality = var_GetInteger(p_enc, ENC_CFG_PREFIX "quality");
+
+    return VLC_SUCCESS;
+}
+
+/*
+ * Exit error handler for libjpeg
+ */
+static void encoder_error_exit(j_common_ptr p_jpeg)
+{
+    encoder_sys_t *p_sys = (encoder_sys_t *)p_jpeg->err;
+    p_sys->err.output_message(p_jpeg);
+    longjmp(p_sys->setjmp_buffer, 1);
+}
+
+/*
+ * Emit message error handler for libjpeg
+ */
+static void encoder_error_message(j_common_ptr p_jpeg)
+{
+    char error_msg[JMSG_LENGTH_MAX];
+
+    encoder_sys_t *p_sys = (encoder_sys_t *)p_jpeg->err;
+    p_sys->err.format_message(p_jpeg, error_msg);
+    msg_Err(p_sys->p_obj, "%s", error_msg);
+}
+
+static block_t *EncodeBlock(encoder_t *p_enc, picture_t *p_pic)
+{
+    encoder_sys_t *p_sys = p_enc->p_sys;
+
+    const int bytesPerPixel = p_enc->fmt_out.video.i_bits_per_pixel ?
+                                p_enc->fmt_out.video.i_bits_per_pixel / 8 : 3;
+    const int blocksize = bytesPerPixel * p_enc->fmt_in.video.i_visible_width * p_enc->fmt_in.video.i_visible_height;
+
+    block_t *p_block = block_Alloc(blocksize);
+    if (p_block == NULL)
+    {
+        return NULL;
+    }
+
+    struct jpeg_compress_struct p_jpeg;
+    JSAMPIMAGE p_row_pointers = NULL;
+
+    p_jpeg.err = jpeg_std_error(&p_sys->err);
+    p_sys->err.error_exit = encoder_error_exit;
+    p_sys->err.output_message = encoder_error_message;
+
+    /* libjpeg longjmp's there in case of error */
+    if (setjmp(p_sys->setjmp_buffer))
+    {
+        goto error;
+    }
+
+    jpeg_create_compress(&p_jpeg);
+    jpeg_mem_dest(&p_jpeg, &p_block->p_buffer, &p_block->i_buffer);
+
+    p_jpeg.image_width = p_enc->fmt_in.video.i_visible_width;
+    p_jpeg.image_height = p_enc->fmt_in.video.i_visible_height;
+    p_jpeg.input_components = bytesPerPixel;
+    p_jpeg.in_color_space = JCS_YCbCr;
+
+    jpeg_set_defaults(&p_jpeg);
+    jpeg_set_colorspace(&p_jpeg, JCS_YCbCr);
+
+    p_jpeg.raw_data_in = TRUE;
+    p_jpeg.do_fancy_downsampling = FALSE;
+
+    jpeg_set_quality(&p_jpeg, p_sys->i_quality, TRUE);
+
+    jpeg_start_compress(&p_jpeg, TRUE);
+
+    /* Encode picture */
+    p_row_pointers = malloc(sizeof(JSAMPIMAGE) * p_pic->i_planes);
+    for (int i = 0; i < p_pic->i_planes; i++)
+    {
+        p_row_pointers[i] = malloc(sizeof(JSAMPARRAY) * p_pic->p[i].i_lines);
+        for (int j = 0; j < p_pic->p[i].i_lines; j++)
+        {
+            p_row_pointers[i][j] = p_pic->p[i].p_pixels + p_pic->p[i].i_pitch * j;
+        }
+    }
+
+    while (p_jpeg.next_scanline < p_jpeg.image_height)
+    {
+        jpeg_write_raw_data(&p_jpeg, p_row_pointers, p_jpeg.max_v_samp_factor * DCTSIZE);
+        for (int i = 0; i < p_pic->i_planes; i++)
+        {
+            p_row_pointers[i] += p_jpeg.comp_info[i].v_samp_factor * DCTSIZE;
+        }
+    }
+
+    jpeg_finish_compress(&p_jpeg);
+    jpeg_destroy_compress(&p_jpeg);
+
+    free(p_row_pointers);
+
+    return p_block;
+
+error:
+    jpeg_destroy_compress(&p_jpeg);
+
+    free(p_row_pointers);
+
+    block_Release(p_block);
+
+    return NULL;
+}
+
+/*
+ * jpeg encoder destruction
+ */
+static void CloseEncoder(vlc_object_t *p_this)
+{
+    encoder_t *p_enc = (encoder_t *)p_this;
+    encoder_sys_t *p_sys = p_enc->p_sys;
+
+    free(p_sys);
+}
-- 
1.8.3.4 (Apple Git-47)




More information about the vlc-devel mailing list