Riccardo Magliocchetti wrote:
Hi,
attached a shiny new jpeg image decoder based on ijg libjpeg. It works
fine here and valgrind is happy with him.
There are a couple of notes:
- i don't have numbers but i don't feel is faster than the cog one
- two test doesn't pass, listing from memory they are:
-- image-jpeg-alpha.swf: image is not recognized as a jpeg
-- negative-color-transform.swf: image differ
Any hint?
- i think that the size of internal buffer set as 65K is much larger
that needed (as seen in gdk pixbuf), something like 8k would be better?
Update: libjpeg uses as default 4k so perhaps that's the right number.
This is a refreshed patch with few changes i have here:
- use 4K for buffer size
- fixed negative-color-transform.swf by using the correct alpha channel
value during rgb -> argb
- image-jpeg-alpha.swf: fails because the alpha channel is ignored by the
jpeg library.
- use existing macro from rgb -> argb conversion
- SWFDEC_ERROR is used instead of SWFDEC_WARNING for libjpeg errors
Benjamin, i'm posting this as a reference and not for requesting inclusion.
cheers,
riccardo
diff --git a/configure.ac b/configure.ac
index 28ab014..6870fe5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -243,12 +243,17 @@ else
fi
AM_CONDITIONAL(HAVE_VIVI, [test "x$HAVE_VIVI" = xyes])
+dnl Test for libjpeg
+AC_CHECK_LIB(jpeg, jpeg_destroy_decompress, HAVE_JPEG=yes, HAVE_JPEG=no)
+if test "$HAVE_JPEG" = no; then
+ AC_MSG_ERROR([Couldn't find libjpeg.])
+fi
AC_SUBST(GLOBAL_CFLAGS)
AC_SUBST(GLOBAL_CFLAGS)
SWFDEC_CFLAGS="-I\$(top_srcdir) $GLIB_CFLAGS $CAIRO_CFLAGS"
-SWFDEC_LIBS="\$(top_builddir)/swfdec/libswfdec-$SWFDEC_MAJORMINOR.la $GLIB_LIBS $CAIRO_LIBS -lz -lm"
+SWFDEC_LIBS="\$(top_builddir)/swfdec/libswfdec-$SWFDEC_MAJORMINOR.la $GLIB_LIBS $CAIRO_LIBS -lz -lm -ljpeg"
AC_SUBST(SWFDEC_LIBS)
AC_SUBST(SWFDEC_CFLAGS)
@@ -280,7 +285,6 @@ data/swfdec.pc
data/swfdec-gtk.pc
doc/Makefile
swfdec/Makefile
-swfdec/jpeg/Makefile
swfdec-gtk/Makefile
player/Makefile
test/Makefile
diff --git a/swfdec/swfdec_image.c b/swfdec/swfdec_image.c
index 92bef53..d307dfc 100644
--- a/swfdec/swfdec_image.c
+++ b/swfdec/swfdec_image.c
@@ -26,8 +26,11 @@
#include <stdio.h>
#include <zlib.h>
#include <string.h>
+#include <jpeglib.h>
+#include <jerror.h>
+#include <setjmp.h>
+#include <stdint.h>
-#include "jpeg.h"
#include "swfdec_image.h"
#include "swfdec_cache.h"
#include "swfdec_cached_image.h"
@@ -37,6 +40,24 @@
G_DEFINE_TYPE (SwfdecImage, swfdec_image, SWFDEC_TYPE_CHARACTER)
+#define JPEG_BUF_SIZE 4096
+
+typedef struct {
+ struct jpeg_source_mgr pub;
+ unsigned char * infile;
+ JOCTET * buffer;
+ gboolean start_of_file;
+} swfdecJpegSourceMgr;
+
+typedef swfdecJpegSourceMgr * swfdec_jpeg_src_ptr;
+
+struct swfdecJpegErrorMgr {
+ struct jpeg_error_mgr pub;
+ jmp_buf setjmp_buffer;
+};
+
+typedef struct swfdecJpegErrorMgr * swfdec_jpeg_error_ptr;
+
static void
swfdec_image_dispose (GObject *object)
{
@@ -132,6 +153,138 @@ swfdec_image_validate_size (SwfdecRenderer *renderer, guint width, guint height)
return TRUE;
}
+static void
+G_GNUC_NORETURN
+swfdec_jpeg_error_exit (j_common_ptr cinfo)
+{
+ swfdec_jpeg_error_ptr err = (swfdec_jpeg_error_ptr) cinfo->err;
+ char buffer[JMSG_LENGTH_MAX];
+
+ (*cinfo->err->format_message) (cinfo, buffer);
+ SWFDEC_ERROR ("Error decoding JPEG image: %s", buffer);
+ longjmp (err->setjmp_buffer, 1);
+}
+
+static void
+swfdec_jpeg_init_source (j_decompress_ptr cinfo)
+{
+ swfdec_jpeg_src_ptr src = (swfdec_jpeg_src_ptr) cinfo->src;
+ src->start_of_file = FALSE;
+}
+
+static gboolean
+swfdec_jpeg_fill_input_buffer (j_decompress_ptr cinfo)
+{
+ swfdec_jpeg_src_ptr src = (swfdec_jpeg_src_ptr) cinfo->src;
+ size_t nbytes;
+
+ nbytes = MIN (sizeof (*src->infile), JPEG_BUF_SIZE);
+ memcpy (src->buffer, src->infile, nbytes);
+
+ if (nbytes <= 0) {
+ /* Insert a fake EOI marker */
+ src->buffer[0] = (JOCTET) 0xff;
+ src->buffer[1] = (JOCTET) JPEG_EOI;
+ nbytes = 2;
+ }
+
+ src->pub.next_input_byte = src->buffer;
+ src->pub.bytes_in_buffer = nbytes;
+ src->infile += nbytes;
+ src->start_of_file = FALSE;
+
+ return TRUE;
+}
+
+static void
+swfdec_jpeg_skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+{
+ swfdec_jpeg_src_ptr src = (swfdec_jpeg_src_ptr) cinfo->src;
+
+ if (num_bytes > 0) {
+ while (num_bytes > (long) src->pub.bytes_in_buffer) {
+ num_bytes -= (long) src->pub.bytes_in_buffer;
+ (void) swfdec_jpeg_fill_input_buffer (cinfo);
+ }
+ src->pub.next_input_byte += (size_t) num_bytes;
+ src->pub.bytes_in_buffer -= (size_t) num_bytes;
+ }
+}
+
+static void
+swfdec_jpeg_term_source (j_decompress_ptr cinfo)
+{
+}
+
+static void
+swfdec_jpeg_rgb_to_argb (struct jpeg_decompress_struct *cinfo,
+ JSAMPROW *rgb, uint32_t *argb)
+{
+ guint size = cinfo->output_width * cinfo->output_components;
+
+ for (guint i = 0, j = 0; i < size; i += 3, j++)
+ argb[j] = SWFDEC_COLOR_COMBINE(rgb[0][i], rgb[0][i+1], rgb[0][i+2], 0xff);
+}
+
+static gboolean
+swfdec_jpeg_decode (unsigned char *data, int length,
+ uint32_t **outdata, guint *width, guint *height)
+{
+ struct jpeg_decompress_struct cinfo;
+ struct swfdecJpegErrorMgr jerr;
+ swfdec_jpeg_src_ptr src;
+ JSAMPROW buf[1];
+ uint32_t *image;
+
+ cinfo.err = jpeg_std_error (&jerr.pub);
+ jerr.pub.error_exit = swfdec_jpeg_error_exit;
+
+ if (setjmp(jerr.setjmp_buffer)) {
+ jpeg_destroy_decompress (&cinfo);
+ return FALSE;
+ }
+
+ jpeg_create_decompress (&cinfo);
+
+ cinfo.src = (struct jpeg_source_mgr *)
+ (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT,
+ sizeof (swfdecJpegSourceMgr));
+ src = (swfdec_jpeg_src_ptr) cinfo.src;
+ src->buffer = (JOCTET *)
+ (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT,
+ JPEG_BUF_SIZE * sizeof (JOCTET));
+ src->pub.init_source = swfdec_jpeg_init_source;
+ src->pub.fill_input_buffer = swfdec_jpeg_fill_input_buffer;
+ src->pub.skip_input_data = swfdec_jpeg_skip_input_data;
+ src->pub.resync_to_restart = jpeg_resync_to_restart;
+ src->pub.term_source = swfdec_jpeg_term_source;
+ src->infile = data;
+ src->pub.bytes_in_buffer = 0;
+ src->pub.next_input_byte = NULL;
+
+ jpeg_read_header (&cinfo, TRUE);
+ jpeg_start_decompress (&cinfo);
+
+ *height = cinfo.output_height;
+ *width = cinfo.output_width;
+
+ buf[0] = g_malloc (cinfo.output_width * cinfo.output_components);
+ image = g_malloc (cinfo.output_width * cinfo.output_height * sizeof (uint32_t));
+ *outdata = image;
+
+ while (cinfo.output_scanline < cinfo.image_height) {
+ jpeg_read_scanlines(&cinfo, buf, 1);
+ swfdec_jpeg_rgb_to_argb (&cinfo, buf, image);
+ image += cinfo.output_width;
+ }
+
+ g_free (buf[0]);
+ jpeg_finish_decompress (&cinfo);
+ jpeg_destroy_decompress (&cinfo);
+
+ return TRUE;
+}
+
/**
* swfdec_jpeg_decode_argb:
*
@@ -146,26 +299,50 @@ swfdec_jpeg_decode_argb (SwfdecRenderer *renderer,
unsigned char *data2, int length2,
void *outdata, guint *width, guint *height)
{
+ unsigned char *tmpdata;
+ int tmplength;
gboolean ret;
- if (data2) {
- unsigned char *tmpdata;
- int tmplength;
+ if (!data1)
+ return FALSE;
- tmplength = length1 + length2;
- tmpdata = g_malloc (tmplength);
+ while (length1 >= 2 && data1[0] == 0xff &&
+ (data1[1] == 0xd8 || data1[1] == 0xd9)) {
+ data1 += 2;
+ length1 -= 2;
+ }
- memcpy (tmpdata, data1, length1);
- memcpy (tmpdata + length1, data2, length2);
- ret = jpeg_decode_argb (tmpdata, tmplength, outdata, width, height);
+ while (length1 >= 2 && data1[length1-2] == 0xff &&
+ (data1[length1-1] == 0xd9 || data1[length1-1] == 0xd8)) {
+ length1 -= 2;
+ }
- g_free (tmpdata);
- } else if (data1) {
- ret = jpeg_decode_argb (data1, length1, outdata, width, height);
- } else {
- ret = FALSE;
+ if (data2) {
+ while (length2 >= 2 && data2[0] == 0xff &&
+ (data2[1] == 0xd8 || data2[1] == 0xd9)) {
+ data2 += 2;
+ length2 -= 2;
+ }
+
+ while (length2 >= 2 && data2[length2-2] == 0xff &&
+ (data2[length2-1] == 0xd9 || data2[length2-1] == 0xd8)) {
+ length2 -= 2;
+ }
}
+ tmplength = length1 + length2 + 4;
+ tmpdata = g_malloc (tmplength);
+ tmpdata[0] = 0xff;
+ tmpdata[1] = 0xd8;
+ memcpy (tmpdata + 2, data1, length1);
+ if (data2)
+ memcpy (tmpdata + 2 + length1, data2, length2);
+ tmpdata[2 + length1 + length2] = 0xff;
+ tmpdata[2 + length1 + length2 + 1] = 0xd9;
+
+ ret = swfdec_jpeg_decode (tmpdata, tmplength, outdata, width, height);
+ g_free (tmpdata);
+
if (ret)
ret = swfdec_image_validate_size (renderer, *width, *height);
return ret;
_______________________________________________
Swfdec mailing list
Swfdec@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/swfdec