[vlc-devel] [PATCH] codec: jpeg encoder implemented
Maxim Bublis
b at codemonkey.ru
Fri Jan 24 16:22:28 CET 2014
This patch implements jpeg encoder using libjpeg.
---
modules/codec/jpeg.c | 228 ++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 188 insertions(+), 40 deletions(-)
diff --git a/modules/codec/jpeg.c b/modules/codec/jpeg.c
index d65ebed..cf9b435 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,20 +30,27 @@
#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; \
+ \
+/**@}*/ \
+
/*
* 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;
-
- bool b_error;
+ JPEG_SYS_COMMON_MEMBERS
};
static int OpenDecoder(vlc_object_t *);
@@ -52,15 +59,39 @@ 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
+};
+
+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")
+
+#ifdef ENABLE_SOUT
+ /* 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)
+#endif
vlc_module_end()
/*
@@ -82,7 +113,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;
@@ -96,10 +127,9 @@ 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->b_error = true;
p_sys->err.output_message(p_jpeg);
longjmp(p_sys->setjmp_buffer, 1);
}
@@ -107,13 +137,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);
}
/*
@@ -134,7 +164,6 @@ static picture_t *DecodeBlock(decoder_t *p_dec, block_t **pp_block)
}
p_block = *pp_block;
- p_sys->b_error = false;
if (p_block->i_flags & BLOCK_FLAG_DISCONTINUITY)
{
@@ -144,8 +173,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))
@@ -154,30 +183,12 @@ static picture_t *DecodeBlock(decoder_t *p_dec, block_t **pp_block)
}
jpeg_create_decompress(&p_jpeg);
- if (p_sys->b_error)
- {
- goto error;
- }
-
jpeg_mem_src(&p_jpeg, p_block->p_buffer, p_block->i_buffer);
- if (p_sys->b_error)
- {
- goto error;
- }
-
jpeg_read_header(&p_jpeg, TRUE);
- if (p_sys->b_error)
- {
- goto error;
- }
p_jpeg.out_color_space = JCS_RGB;
jpeg_start_decompress(&p_jpeg);
- if (p_sys->b_error)
- {
- goto error;
- }
/* Set output properties */
p_dec->fmt_out.i_codec = VLC_CODEC_RGB24;
@@ -210,10 +221,6 @@ static picture_t *DecodeBlock(decoder_t *p_dec, block_t **pp_block)
{
jpeg_read_scanlines(&p_jpeg, p_row_pointers + p_jpeg.output_scanline,
p_jpeg.output_height - p_jpeg.output_scanline);
- if (p_sys->b_error)
- {
- goto error;
- }
}
jpeg_finish_decompress(&p_jpeg);
@@ -248,3 +255,144 @@ 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;
+
+ 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, 100, 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