[vlc-devel] [PATCH v2] Implemented libjpeg decoder module
Maxim Bublis
b at codemonkey.ru
Fri Dec 13 17:30:50 CET 2013
---
configure.ac | 11 ++
modules/codec/Makefile.am | 6 ++
modules/codec/jpeg.c | 250 ++++++++++++++++++++++++++++++++++++++++++++++
src/misc/fourcc.c | 2 -
4 files changed, 267 insertions(+), 2 deletions(-)
create mode 100644 modules/codec/jpeg.c
diff --git a/configure.ac b/configure.ac
index 5f7ed24..d5d42d2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2677,6 +2677,17 @@ AC_CHECK_HEADERS(png.h, [
])
dnl
+dnl JPEG decoder module
+dnl
+AC_ARG_ENABLE(jpeg,
+ [ --enable-jpeg JPEG support (default enabled)])
+AS_IF([test "${enable_jpeg}" != "no"], [
+AC_CHECK_HEADERS(jpeglib.h, [
+ VLC_ADD_PLUGIN([jpeg])
+ ])
+])
+
+dnl
dnl H262 encoder plugin (lib262)
dnl
AC_ARG_ENABLE(x262,
diff --git a/modules/codec/Makefile.am b/modules/codec/Makefile.am
index b74b15a..a2bc1fe 100644
--- a/modules/codec/Makefile.am
+++ b/modules/codec/Makefile.am
@@ -103,6 +103,12 @@ libpng_plugin_la_LIBADD = -lpng -lz $(LIBM)
EXTRA_LTLIBRARIES += libpng_plugin.la
codec_LTLIBRARIES += $(LTLIBpng)
+libjpeg_plugin_la_SOURCES = codec/jpeg.c
+libjpeg_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(codecdir)'
+libjpeg_plugin_la_LIBADD = -ljpeg
+EXTRA_LTLIBRARIES += libjpeg_plugin.la
+codec_LTLIBRARIES += $(LTLIBjpeg)
+
libsdl_image_plugin_la_SOURCES = codec/sdl_image.c
libsdl_image_plugin_la_CFLAGS = $(AM_CFLAGS) $(SDL_IMAGE_CFLAGS)
libsdl_image_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(codecdir)'
diff --git a/modules/codec/jpeg.c b/modules/codec/jpeg.c
new file mode 100644
index 0000000..3283574
--- /dev/null
+++ b/modules/codec/jpeg.c
@@ -0,0 +1,250 @@
+/*****************************************************************************
+ * jpeg.c: jpeg decoder module making use of libjpeg.
+ *****************************************************************************
+ * Copyright (C) 2013 VLC authors and VideoLAN
+ *
+ * Authors: Maxim Bublis <b at codemonkey.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_codec.h>
+#include <jpeglib.h>
+#include <setjmp.h>
+
+/*
+ * 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;
+
+ bool b_error;
+
+ decoder_t *p_dec;
+};
+
+static int OpenDecoder(vlc_object_t *);
+static void CloseDecoder(vlc_object_t *);
+
+static picture_t *DecodeBlock(decoder_t *, block_t **);
+
+/*
+ * Module descriptor
+ */
+vlc_module_begin()
+ set_category(CAT_INPUT)
+ set_subcategory(SUBCAT_INPUT_VCODEC)
+ set_description(N_("JPEG image decoder"))
+ set_capability("decoder", 1000)
+ set_callbacks(OpenDecoder, CloseDecoder)
+ add_shortcut("jpeg")
+vlc_module_end()
+
+/*
+ * Probe the decoder and return score
+ */
+static int OpenDecoder(vlc_object_t *p_this)
+{
+ decoder_t *p_dec = (decoder_t *)p_this;
+
+ if (p_dec->fmt_in.i_codec != VLC_CODEC_JPEG)
+ {
+ return VLC_EGENERIC;
+ }
+
+ /* Allocate the memory needed to store the decoder's structure */
+ p_dec->p_sys = malloc(sizeof(decoder_sys_t));
+ if (p_dec->p_sys == NULL)
+ {
+ return VLC_ENOMEM;
+ }
+
+ p_dec->p_sys->p_dec = p_dec;
+
+ /* Set output properties */
+ p_dec->fmt_out.i_cat = VIDEO_ES;
+
+ /* Set callbacks */
+ p_dec->pf_decode_video = DecodeBlock;
+
+ return VLC_SUCCESS;
+}
+
+/*
+ * Exit error handler for libjpeg
+ */
+static void user_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);
+}
+
+/*
+ * Emit message error handler for libjpeg
+ */
+static void user_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);
+}
+
+/*
+ * This function must be fed with a complete compressed frame.
+ */
+static picture_t *DecodeBlock(decoder_t *p_dec, block_t **pp_block)
+{
+ decoder_sys_t *p_sys = p_dec->p_sys;
+ block_t *p_block;
+ picture_t *p_pic = 0;
+
+ struct jpeg_decompress_struct p_jpeg;
+ JSAMPARRAY p_row_pointers = NULL;
+
+ if (!pp_block || !*pp_block)
+ {
+ return NULL;
+ }
+
+ p_block = *pp_block;
+ p_sys->b_error = false;
+
+ if (p_block->i_flags & BLOCK_FLAG_DISCONTINUITY)
+ {
+ block_Release(p_block);
+ *pp_block = NULL;
+ return NULL;
+ }
+
+ 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;
+
+ /* libjpeg longjmp's there in case of error */
+ if (setjmp(p_sys->setjmp_buffer))
+ {
+ goto error;
+ }
+
+ 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;
+ p_dec->fmt_out.video.i_width = p_jpeg.output_width;
+ p_dec->fmt_out.video.i_height = p_jpeg.output_height;
+ p_dec->fmt_out.video.i_sar_num = 1;
+ p_dec->fmt_out.video.i_sar_den = 1;
+ p_dec->fmt_out.video.i_rmask = 0x000000ff;
+ p_dec->fmt_out.video.i_gmask = 0x0000ff00;
+ p_dec->fmt_out.video.i_bmask = 0x00ff0000;
+
+ /* Get a new picture */
+ p_pic = decoder_NewPicture(p_dec);
+ if (!p_pic)
+ {
+ goto error;
+ }
+
+ /* Decode picture */
+ p_row_pointers = malloc(sizeof(JSAMPROW) * p_jpeg.output_height);
+ if (!p_row_pointers)
+ {
+ goto error;
+ }
+ for (int i = 0; i < (int)p_jpeg.output_height; i++) {
+ p_row_pointers[i] = p_pic->p->p_pixels + p_pic->p->i_pitch * i;
+ }
+
+ while (p_jpeg.output_scanline < p_jpeg.output_height)
+ {
+ 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);
+ jpeg_destroy_decompress(&p_jpeg);
+ free(p_row_pointers);
+
+ p_pic->date = p_block->i_pts > VLC_TS_INVALID ? p_block->i_pts : p_block->i_dts;
+
+ block_Release(p_block);
+ *pp_block = NULL;
+
+ return p_pic;
+
+error:
+
+ jpeg_destroy_decompress(&p_jpeg);
+ free(p_row_pointers);
+
+ block_Release(p_block);
+ *pp_block = NULL;
+
+ return NULL;
+}
+
+/*
+ * jpeg decoder destruction
+ */
+static void CloseDecoder(vlc_object_t *p_this)
+{
+ decoder_t *p_dec = (decoder_t *)p_this;
+ decoder_sys_t *p_sys = p_dec->p_sys;
+
+ free(p_sys);
+}
diff --git a/src/misc/fourcc.c b/src/misc/fourcc.c
index 8cd821a..04a4c71 100644
--- a/src/misc/fourcc.c
+++ b/src/misc/fourcc.c
@@ -351,8 +351,6 @@ static const staticentry_t p_list_video[] = {
A("mjpg"),
A("mJPG"),
A("mjpa"),
- A("jpeg"),
- A("JPEG"),
A("JFIF"),
A("JPGL"),
A("LJPG"),
--
1.8.3.4 (Apple Git-47)
More information about the vlc-devel
mailing list