[vlc-devel] [PATCH] codec: implemented libjpeg module

Maxim Bublis b at codemonkey.ru
Thu Dec 19 12:45:55 CET 2013


---
 configure.ac              |  11 ++
 modules/codec/Makefile.am |   6 ++
 modules/codec/jpeg.c      | 250 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 267 insertions(+)
 create mode 100644 modules/codec/jpeg.c

diff --git a/configure.ac b/configure.ac
index 08fb0eb..d60eae3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2694,6 +2694,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 05a0b00..9673d04 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);
+}
-- 
1.8.3.4 (Apple Git-47)




More information about the vlc-devel mailing list