This is libv4l split into 4 patches for v4l-dvb tree inclusion, many thanks
to Thierry Merle for preparing this patch series.

Signed-off-by: Hans de Goede <j.w.r.degoede@hhs.nl>

diff -r cb6162341029 -r 006f05659861 v4l2-apps/lib/libv4l/include/libv4lconvert.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/v4l2-apps/lib/libv4l/include/libv4lconvert.h	Mon Jun 30 22:23:16 2008 +0200
@@ -0,0 +1,67 @@
+/*
+#             (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# 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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef __LIBV4LCONVERT_H
+#define __LIBV4LCONVERT_H
+
+/* These headers are not needed by us, but by linux/videodev2.h,
+   which is broken on some systems and doesn't include them itself :( */
+#include <sys/time.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+/* end broken header workaround includes */
+#include <linux/videodev2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+struct v4lconvert_data;
+
+struct v4lconvert_data *v4lconvert_create(int fd);
+void v4lconvert_destroy(struct v4lconvert_data *data);
+
+/* With regards to dest_fmt just like VIDIOC_TRY_FMT, except that the try
+   format will succeed and return the requested V4L2_PIX_FMT_foo in dest_fmt if
+   the cam has a format from which v4lconvert can convert to dest_fmt.
+   The real format to which the cam should be set is returned through src_fmt
+   when not NULL. */
+int v4lconvert_try_format(struct v4lconvert_data *data,
+  struct v4l2_format *dest_fmt, /* in / out */
+  struct v4l2_format *src_fmt /* out */
+);
+
+/* Just like VIDIOC_ENUM_FMT, except that the emulated formats are added at
+   the end of the list */
+int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt);
+
+/* return value of -1 on error, otherwise the amount of bytes written to
+   dest */
+int v4lconvert_convert(struct v4lconvert_data *data,
+  const struct v4l2_format *src_fmt,  /* in */
+  const struct v4l2_format *dest_fmt, /* in */
+  unsigned char *src, int src_size, unsigned char *dest, int dest_size);
+
+/* get a string describing the last error*/
+const char *v4lconvert_get_error_message(struct v4lconvert_data *data);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
diff -r cb6162341029 -r 006f05659861 v4l2-apps/lib/libv4l/libv4lconvert/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/Makefile	Mon Jun 30 22:23:16 2008 +0200
@@ -0,0 +1,46 @@
+CC            = gcc
+LD            = gcc
+
+CPPFLAGS      = -fPIC -I../include -I../../../../linux/include
+
+CFLAGS := -g -O1
+CFLAGS += -Wall -W -Wno-unused -Wpointer-arith -Wstrict-prototypes
+
+LDFLAGS       = -shared
+
+CONVERT_LIB   = libv4lconvert.so
+CONVERT_OBJS  = libv4lconvert.o tinyjpeg.o \
+		jidctflt.o spca561-decompress.o rgbyuv.o spca501.o bayer.o
+TARGETS       = $(CONVERT_LIB)
+INCLUDES      = ../include/libv4lconvert.h
+
+ifeq ($(LIB_RELEASE),)
+LIB_RELEASE = 0
+endif
+
+ifeq ($(DESTDIR),)
+DESTDIR = /usr/local
+endif
+
+all: $(TARGETS)
+
+$(CONVERT_LIB): $(CONVERT_OBJS)
+
+install: all
+	mkdir -p $(DESTDIR)/include
+	cp $(INCLUDES) $(DESTDIR)/include
+	mkdir -p $(DESTDIR)/lib
+	cp $(CONVERT_LIB).$(LIB_RELEASE) $(DESTDIR)/lib
+	cd $(DESTDIR)/lib && \
+	  ln -f -s $(CONVERT_LIB).$(LIB_RELEASE) $(CONVERT_LIB)
+
+clean::
+	rm -f *.so* *.o log *~
+	rm -f *.d
+
+%.o: %.c
+	$(CC) -c -MMD $(CPPFLAGS) $(CFLAGS) -o $@ $<
+
+%.so:
+	$(CC) $(LDFLAGS) -Wl,-soname,$@.$(LIB_RELEASE) -o $@.$(LIB_RELEASE) $^
+	ln -f -s $@.$(LIB_RELEASE) $@
diff -r cb6162341029 -r 006f05659861 v4l2-apps/lib/libv4l/libv4lconvert/bayer.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/bayer.c	Mon Jun 30 22:23:16 2008 +0200
@@ -0,0 +1,597 @@
+/*
+ * lib4lconvert, video4linux2 format conversion lib
+ *             (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+ *
+ * This library 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 library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Note: original bayer_to_bgr24 code from :
+ * 1394-Based Digital Camera Control Library
+ *
+ * Bayer pattern decoding functions
+ *
+ * Written by Damien Douxchamps and Frederic Devernay
+ *
+ * Note that the original bayer.c in libdc1394 supports many different
+ * bayer decode algorithms, for lib4lconvert the one in this file has been
+ * chosen (and optimized a bit) and the other algorithm's have been removed,
+ * see bayer.c from libdc1394 for all supported algorithms
+ */
+
+#include <string.h>
+#include "libv4lconvert-priv.h"
+
+/**************************************************************
+ *     Color conversion functions for cameras that can        *
+ * output raw-Bayer pattern images, such as some Basler and   *
+ * Point Grey camera. Most of the algos presented here come   *
+ * from http://www-ise.stanford.edu/~tingchen/ and have been  *
+ * converted from Matlab to C and extended to all elementary  *
+ * patterns.                                                  *
+ **************************************************************/
+
+/* insprired by OpenCV's Bayer decoding */
+static void v4lconvert_border_bayer_line_to_bgr24(
+  const unsigned char* bayer, const unsigned char* adjacent_bayer,
+  unsigned char *bgr, int width, int start_with_green, int blue_line)
+{
+  int t0, t1;
+
+  if (start_with_green) {
+    /* First pixel */
+    if (blue_line) {
+      *bgr++ = bayer[1];
+      *bgr++ = bayer[0];
+      *bgr++ = adjacent_bayer[0];
+    } else {
+      *bgr++ = adjacent_bayer[0];
+      *bgr++ = bayer[0];
+      *bgr++ = bayer[1];
+    }
+    /* Second pixel */
+    t0 = (bayer[0] + bayer[2] + adjacent_bayer[1] + 1) / 3;
+    t1 = (adjacent_bayer[0] + adjacent_bayer[2] + 1) >> 1;
+    if (blue_line) {
+      *bgr++ = bayer[1];
+      *bgr++ = t0;
+      *bgr++ = t1;
+    } else {
+      *bgr++ = t1;
+      *bgr++ = t0;
+      *bgr++ = bayer[1];
+    }
+    bayer++;
+    adjacent_bayer++;
+    width -= 2;
+  } else {
+    /* First pixel */
+    t0 = (bayer[1] + adjacent_bayer[0] + 1) >> 1;
+    if (blue_line) {
+      *bgr++ = bayer[0];
+      *bgr++ = t0;
+      *bgr++ = adjacent_bayer[1];
+    } else {
+      *bgr++ = adjacent_bayer[1];
+      *bgr++ = t0;
+      *bgr++ = bayer[0];
+    }
+    width--;
+  }
+
+  if (blue_line) {
+    for ( ; width > 2; width -= 2) {
+      t0 = (bayer[0] + bayer[2] + 1) >> 1;
+      *bgr++ = t0;
+      *bgr++ = bayer[1];
+      *bgr++ = adjacent_bayer[1];
+      bayer++;
+      adjacent_bayer++;
+
+      t0 = (bayer[0] + bayer[2] + adjacent_bayer[1] + 1) / 3;
+      t1 = (adjacent_bayer[0] + adjacent_bayer[2] + 1) >> 1;
+      *bgr++ = bayer[1];
+      *bgr++ = t0;
+      *bgr++ = t1;
+      bayer++;
+      adjacent_bayer++;
+    }
+  } else {
+    for ( ; width > 2; width -= 2) {
+      t0 = (bayer[0] + bayer[2] + 1) >> 1;
+      *bgr++ = adjacent_bayer[1];
+      *bgr++ = bayer[1];
+      *bgr++ = t0;
+      bayer++;
+      adjacent_bayer++;
+
+      t0 = (bayer[0] + bayer[2] + adjacent_bayer[1] + 1) / 3;
+      t1 = (adjacent_bayer[0] + adjacent_bayer[2] + 1) >> 1;
+      *bgr++ = t1;
+      *bgr++ = t0;
+      *bgr++ = bayer[1];
+      bayer++;
+      adjacent_bayer++;
+    }
+  }
+
+  if (width == 2) {
+    /* Second to last pixel */
+    t0 = (bayer[0] + bayer[2] + 1) >> 1;
+    if (blue_line) {
+      *bgr++ = t0;
+      *bgr++ = bayer[1];
+      *bgr++ = adjacent_bayer[1];
+    } else {
+      *bgr++ = adjacent_bayer[1];
+      *bgr++ = bayer[1];
+      *bgr++ = t0;
+    }
+    /* Last pixel */
+    t0 = (bayer[1] + adjacent_bayer[2] + 1) >> 1;
+    if (blue_line) {
+      *bgr++ = bayer[2];
+      *bgr++ = t0;
+      *bgr++ = adjacent_bayer[1];
+    } else {
+      *bgr++ = adjacent_bayer[1];
+      *bgr++ = t0;
+      *bgr++ = bayer[2];
+    }
+  } else {
+    /* Last pixel */
+    if (blue_line) {
+      *bgr++ = bayer[0];
+      *bgr++ = bayer[1];
+      *bgr++ = adjacent_bayer[1];
+    } else {
+      *bgr++ = adjacent_bayer[1];
+      *bgr++ = bayer[1];
+      *bgr++ = bayer[0];
+    }
+  }
+}
+
+/* From libdc1394, which on turn was based on OpenCV's Bayer decoding */
+void v4lconvert_bayer_to_bgr24(const unsigned char *bayer,
+  unsigned char *bgr, int width, int height, unsigned int pixfmt)
+{
+    int blue_line = pixfmt == V4L2_PIX_FMT_SBGGR8
+	|| pixfmt == V4L2_PIX_FMT_SGBRG8;
+    int start_with_green = pixfmt == V4L2_PIX_FMT_SGBRG8
+	|| pixfmt == V4L2_PIX_FMT_SGRBG8;
+
+    /* render the first line */
+    v4lconvert_border_bayer_line_to_bgr24(bayer, bayer + width, bgr, width,
+      start_with_green, blue_line);
+    bgr += width * 3;
+
+    /* reduce height by 2 because of the special case top/bottom line */
+    for (height -= 2; height; height--) {
+	int t0, t1;
+	/* (width - 2) because of the border */
+	const unsigned char *bayerEnd = bayer + (width - 2);
+
+	if (start_with_green) {
+	    /* OpenCV has a bug in the next line, which was
+	       t0 = (bayer[0] + bayer[width * 2] + 1) >> 1; */
+	    t0 = (bayer[1] + bayer[width * 2 + 1] + 1) >> 1;
+	    /* Write first pixel */
+	    t1 = (bayer[0] + bayer[width * 2] + bayer[width + 1] + 1) / 3;
+	    if (blue_line) {
+	      *bgr++ = t0;
+	      *bgr++ = t1;
+	      *bgr++ = bayer[width];
+	    } else {
+	      *bgr++ = bayer[width];
+	      *bgr++ = t1;
+	      *bgr++ = t0;
+	    }
+
+	    /* Write second pixel */
+	    t1 = (bayer[width] + bayer[width + 2] + 1) >> 1;
+	    if (blue_line) {
+	      *bgr++ = t0;
+	      *bgr++ = bayer[width + 1];
+	      *bgr++ = t1;
+	    } else {
+	      *bgr++ = t1;
+	      *bgr++ = bayer[width + 1];
+	      *bgr++ = t0;
+	    }
+	    bayer++;
+	} else {
+	    /* Write first pixel */
+	    t0 = (bayer[0] + bayer[width * 2] + 1) >> 1;
+	    if (blue_line) {
+	      *bgr++ = t0;
+	      *bgr++ = bayer[width];
+	      *bgr++ = bayer[width + 1];
+	    } else {
+	      *bgr++ = bayer[width + 1];
+	      *bgr++ = bayer[width];
+	      *bgr++ = t0;
+	    }
+	}
+
+	if (blue_line) {
+	    for (; bayer <= bayerEnd - 2; bayer += 2) {
+		t0 = (bayer[0] + bayer[2] + bayer[width * 2] +
+		      bayer[width * 2 + 2] + 2) >> 2;
+		t1 = (bayer[1] + bayer[width] +
+		      bayer[width + 2] + bayer[width * 2 + 1] +
+		      2) >> 2;
+		*bgr++ = t0;
+		*bgr++ = t1;
+		*bgr++ = bayer[width + 1];
+
+		t0 = (bayer[2] + bayer[width * 2 + 2] + 1) >> 1;
+		t1 = (bayer[width + 1] + bayer[width + 3] +
+		      1) >> 1;
+		*bgr++ = t0;
+		*bgr++ = bayer[width + 2];
+		*bgr++ = t1;
+	    }
+	} else {
+	    for (; bayer <= bayerEnd - 2; bayer += 2) {
+		t0 = (bayer[0] + bayer[2] + bayer[width * 2] +
+		      bayer[width * 2 + 2] + 2) >> 2;
+		t1 = (bayer[1] + bayer[width] +
+		      bayer[width + 2] + bayer[width * 2 + 1] +
+		      2) >> 2;
+		*bgr++ = bayer[width + 1];
+		*bgr++ = t1;
+		*bgr++ = t0;
+
+		t0 = (bayer[2] + bayer[width * 2 + 2] + 1) >> 1;
+		t1 = (bayer[width + 1] + bayer[width + 3] +
+		      1) >> 1;
+		*bgr++ = t1;
+		*bgr++ = bayer[width + 2];
+		*bgr++ = t0;
+	    }
+	}
+
+	if (bayer < bayerEnd) {
+	    /* write second to last pixel */
+	    t0 = (bayer[0] + bayer[2] + bayer[width * 2] +
+		  bayer[width * 2 + 2] + 2) >> 2;
+	    t1 = (bayer[1] + bayer[width] +
+		  bayer[width + 2] + bayer[width * 2 + 1] +
+		  2) >> 2;
+	    if (blue_line) {
+	      *bgr++ = t0;
+	      *bgr++ = t1;
+	      *bgr++ = bayer[width + 1];
+	    } else {
+	      *bgr++ = bayer[width + 1];
+	      *bgr++ = t1;
+	      *bgr++ = t0;
+	    }
+	    /* write last pixel */
+	    t0 = (bayer[2] + bayer[width * 2 + 2] + 1) >> 1;
+	    if (blue_line) {
+	      *bgr++ = t0;
+	      *bgr++ = bayer[width + 2];
+	      *bgr++ = bayer[width + 1];
+	    } else {
+	      *bgr++ = bayer[width + 1];
+	      *bgr++ = bayer[width + 2];
+	      *bgr++ = t0;
+	    }
+	    bayer++;
+	} else {
+	    /* write last pixel */
+	    t0 = (bayer[0] + bayer[width * 2] + 1) >> 1;
+	    t1 = (bayer[1] + bayer[width * 2 + 1] + bayer[width] + 1) / 3;
+	    if (blue_line) {
+	      *bgr++ = t0;
+	      *bgr++ = t1;
+	      *bgr++ = bayer[width + 1];
+	    } else {
+	      *bgr++ = bayer[width + 1];
+	      *bgr++ = t1;
+	      *bgr++ = t0;
+	    }
+	}
+
+	/* skip 2 border pixels */
+	bayer += 2;
+
+	blue_line = !blue_line;
+	start_with_green = !start_with_green;
+    }
+
+    /* render the last line */
+    v4lconvert_border_bayer_line_to_bgr24(bayer + width, bayer, bgr, width,
+      !start_with_green, !blue_line);
+}
+
+static void v4lconvert_border_bayer_line_to_y(
+  const unsigned char* bayer, const unsigned char* adjacent_bayer,
+  unsigned char *y, int width, int start_with_green, int blue_line)
+{
+  int t0, t1;
+
+  if (start_with_green) {
+    /* First pixel */
+    if (blue_line) {
+      *y++ = (8453*adjacent_bayer[0] + 16594*bayer[0] + 3223*bayer[1] + 524288)
+	     >> 15;
+    } else {
+      *y++ = (8453*bayer[1] + 16594*bayer[0] + 3223*adjacent_bayer[0] + 524288)
+	     >> 15;
+    }
+    /* Second pixel */
+    t0 = bayer[0] + bayer[2] + adjacent_bayer[1];
+    t1 = adjacent_bayer[0] + adjacent_bayer[2];
+    if (blue_line) {
+      *y++ = (4226*t1 + 5531*t0 + 3223*bayer[1] + 524288) >> 15;
+    } else {
+      *y++ = (8453*bayer[1] + 5531*t0 + 1611*t1 + 524288) >> 15;
+    }
+    bayer++;
+    adjacent_bayer++;
+    width -= 2;
+  } else {
+    /* First pixel */
+    t0 = bayer[1] + adjacent_bayer[0];
+    if (blue_line) {
+      *y++ = (8453*adjacent_bayer[1] + 8297*t0 + 3223*bayer[0] + 524288)
+	     >> 15;
+    } else {
+      *y++ = (8453*bayer[0] + 8297*t0 + 3223*adjacent_bayer[1] + 524288)
+	     >> 15;
+    }
+    width--;
+  }
+
+  if (blue_line) {
+    for ( ; width > 2; width -= 2) {
+      t0 = bayer[0] + bayer[2];
+      *y++ = (8453*adjacent_bayer[1] + 16594*bayer[1] + 1611*t0 + 524288)
+	     >> 15;
+      bayer++;
+      adjacent_bayer++;
+
+      t0 = bayer[0] + bayer[2] + adjacent_bayer[1];
+      t1 = adjacent_bayer[0] + adjacent_bayer[2];
+      *y++ = (4226*t1 + 5531*t0 + 3223*bayer[1] + 524288) >> 15;
+      bayer++;
+      adjacent_bayer++;
+    }
+  } else {
+    for ( ; width > 2; width -= 2) {
+      t0 = bayer[0] + bayer[2];
+      *y++ = (4226*t0 + 16594*bayer[1] + 3223*adjacent_bayer[1] + 524288)
+	     >> 15;
+      bayer++;
+      adjacent_bayer++;
+
+      t0 = bayer[0] + bayer[2] + adjacent_bayer[1];
+      t1 = adjacent_bayer[0] + adjacent_bayer[2];
+      *y++ = (8453*bayer[1] + 5531*t0 + 1611*t1 + 524288) >> 15;
+      bayer++;
+      adjacent_bayer++;
+    }
+  }
+
+  if (width == 2) {
+    /* Second to last pixel */
+    t0 = bayer[0] + bayer[2];
+    if (blue_line) {
+      *y++ = (8453*adjacent_bayer[1] + 16594*bayer[1] + 1611*t0 + 524288)
+	     >> 15;
+    } else {
+      *y++ = (4226*t0 + 16594*bayer[1] + 3223*adjacent_bayer[1] + 524288)
+	     >> 15;
+    }
+    /* Last pixel */
+    t0 = bayer[1] + adjacent_bayer[2];
+    if (blue_line) {
+      *y++ = (8453*adjacent_bayer[1] + 8297*t0 + 3223*bayer[2] + 524288)
+	     >> 15;
+    } else {
+      *y++ = (8453*bayer[2] + 8297*t0 + 3223*adjacent_bayer[1] + 524288)
+	     >> 15;
+    }
+  } else {
+    /* Last pixel */
+    if (blue_line) {
+      *y++ = (8453*adjacent_bayer[1] + 16594*bayer[1] + 3223*bayer[0] + 524288)
+	     >> 15;
+    } else {
+      *y++ = (8453*bayer[0] + 16594*bayer[1] + 3223*adjacent_bayer[1] + 524288)
+	     >> 15;
+    }
+  }
+}
+
+void v4lconvert_bayer_to_yuv420(const unsigned char *bayer,
+  unsigned char *yuv, int width, int height, unsigned int pixfmt)
+{
+  int blue_line = 0, start_with_green = 0, x, y;
+  unsigned char *ydst = yuv;
+  unsigned char *udst = yuv + width * height;
+  unsigned char *vdst = udst + width * height / 4;
+
+  /* First calculate the u and v planes 2x2 pixels at a time */
+  switch (pixfmt) {
+    case V4L2_PIX_FMT_SBGGR8:
+      for (y = 0; y < height; y += 2) {
+	for (x = 0; x < width; x += 2) {
+	  int b, g, r;
+	  b  = bayer[x];
+	  g  = bayer[x+1];
+	  g += bayer[x+width];
+	  r  = bayer[x+width+1];
+	  *udst++ = (-4878 * r - 4789 * g + 14456 * b + 4210688) >> 15;
+	  *vdst++ = (14456 * r - 6052 * g -  2351 * b + 4210688) >> 15;
+	}
+	bayer += 2 * width;
+      }
+      blue_line = 1;
+      break;
+
+    case V4L2_PIX_FMT_SRGGB8:
+      for (y = 0; y < height; y += 2) {
+	for (x = 0; x < width; x += 2) {
+	  int b, g, r;
+	  r  = bayer[x];
+	  g  = bayer[x+1];
+	  g += bayer[x+width];
+	  b  = bayer[x+width+1];
+	  *udst++ = (-4878 * r - 4789 * g + 14456 * b + 4210688) >> 15;
+	  *vdst++ = (14456 * r - 6052 * g -  2351 * b + 4210688) >> 15;
+	}
+	bayer += 2 * width;
+      }
+      break;
+
+    case V4L2_PIX_FMT_SGBRG8:
+      for (y = 0; y < height; y += 2) {
+	for (x = 0; x < width; x += 2) {
+	  int b, g, r;
+	  g  = bayer[x];
+	  b  = bayer[x+1];
+	  r  = bayer[x+width];
+	  g += bayer[x+width+1];
+	  *udst++ = (-4878 * r - 4789 * g + 14456 * b + 4210688) >> 15;
+	  *vdst++ = (14456 * r - 6052 * g -  2351 * b + 4210688) >> 15;
+	}
+	bayer += 2 * width;
+      }
+      blue_line = 1;
+      start_with_green = 1;
+      break;
+
+    case V4L2_PIX_FMT_SGRBG8:
+      for (y = 0; y < height; y += 2) {
+	for (x = 0; x < width; x += 2) {
+	  int b, g, r;
+	  g  = bayer[x];
+	  r  = bayer[x+1];
+	  b  = bayer[x+width];
+	  g += bayer[x+width+1];
+	  *udst++ = (-4878 * r - 4789 * g + 14456 * b + 4210688) >> 15;
+	  *vdst++ = (14456 * r - 6052 * g -  2351 * b + 4210688) >> 15;
+	}
+	bayer += 2 * width;
+      }
+      start_with_green = 1;
+      break;
+  }
+
+  bayer -= width * height;
+
+  /* render the first line */
+  v4lconvert_border_bayer_line_to_y(bayer, bayer + width, ydst, width,
+    start_with_green, blue_line);
+  ydst += width;
+
+  /* reduce height by 2 because of the border */
+  for (height -= 2; height; height--) {
+    int t0, t1;
+    /* (width - 2) because of the border */
+    const unsigned char *bayerEnd = bayer + (width - 2);
+
+    if (start_with_green) {
+      t0 = bayer[1] + bayer[width * 2 + 1];
+      /* Write first pixel */
+      t1 = bayer[0] + bayer[width * 2] + bayer[width + 1];
+      if (blue_line)
+	*ydst++ = (8453*bayer[width] + 5516*t1 + 1661*t0 + 524288) >> 15;
+      else
+	*ydst++ = (4226*t0 + 5516*t1 + 3223*bayer[width] + 524288) >> 15;
+
+      /* Write second pixel */
+      t1 = bayer[width] + bayer[width + 2];
+      if (blue_line)
+	*ydst++ = (4226*t1 + 16594*bayer[width+1] + 1611*t0 + 524288) >> 15;
+      else
+	*ydst++ = (4226*t0 + 16594*bayer[width+1] + 1611*t1 + 524288) >> 15;
+      bayer++;
+    } else {
+      /* Write first pixel */
+      t0 = bayer[0] + bayer[width * 2];
+      if (blue_line) {
+	*ydst++ = (8453*bayer[width+1] + 16594*bayer[width] + 1661*t0 +
+		   524288) >> 15;
+      } else {
+	*ydst++ = (4226*t0 + 16594*bayer[width] + 3223*bayer[width+1] +
+		   524288) >> 15;
+      }
+    }
+
+    if (blue_line) {
+      for (; bayer <= bayerEnd - 2; bayer += 2) {
+	t0 = bayer[0] + bayer[2] + bayer[width * 2] + bayer[width * 2 + 2];
+	t1 = bayer[1] + bayer[width] + bayer[width + 2] + bayer[width * 2 + 1];
+	*ydst++ = (8453*bayer[width+1] + 4148*t1 + 806*t0 + 524288) >> 15;
+
+	t0 = bayer[2] + bayer[width * 2 + 2];
+	t1 = bayer[width + 1] + bayer[width + 3];
+	*ydst++ = (4226*t1 + 16594*bayer[width+2] + 1611*t0 + 524288) >> 15;
+      }
+    } else {
+      for (; bayer <= bayerEnd - 2; bayer += 2) {
+	t0 = bayer[0] + bayer[2] + bayer[width * 2] + bayer[width * 2 + 2];
+	t1 = bayer[1] + bayer[width] + bayer[width + 2] + bayer[width * 2 + 1];
+	*ydst++ = (2113*t0 + 4148*t1 + 3223*bayer[width+1] + 524288) >> 15;
+
+	t0 = bayer[2] + bayer[width * 2 + 2];
+	t1 = bayer[width + 1] + bayer[width + 3];
+	*ydst++ = (4226*t0 + 16594*bayer[width+2] + 1611*t1 + 524288) >> 15;
+      }
+    }
+
+    if (bayer < bayerEnd) {
+      /* Write second to last pixel */
+      t0 = bayer[0] + bayer[2] + bayer[width * 2] + bayer[width * 2 + 2];
+      t1 = bayer[1] + bayer[width] + bayer[width + 2] + bayer[width * 2 + 1];
+      if (blue_line)
+	*ydst++ = (8453*bayer[width+1] + 4148*t1 + 806*t0 + 524288) >> 15;
+      else
+	*ydst++ = (2113*t0 + 4148*t1 + 3223*bayer[width+1] + 524288) >> 15;
+
+      /* write last pixel */
+      t0 = bayer[2] + bayer[width * 2 + 2];
+      if (blue_line) {
+	*ydst++ = (8453*bayer[width+1] + 16594*bayer[width+2] + 1661*t0 +
+		   524288) >> 15;
+      } else {
+	*ydst++ = (4226*t0 + 16594*bayer[width+2] + 3223*bayer[width+1] +
+		   524288) >> 15;
+      }
+      bayer++;
+    } else {
+      /* write last pixel */
+      t0 = bayer[0] + bayer[width * 2];
+      t1 = bayer[1] + bayer[width * 2 + 1] + bayer[width];
+      if (blue_line)
+	*ydst++ = (8453*bayer[width+1] + 5516*t1 + 1661*t0 + 524288) >> 15;
+      else
+	*ydst++ = (4226*t0 + 5516*t1 + 3223*bayer[width+1] + 524288) >> 15;
+    }
+
+    /* skip 2 border pixels */
+    bayer += 2;
+
+    blue_line = !blue_line;
+    start_with_green = !start_with_green;
+  }
+
+  /* render the last line */
+  v4lconvert_border_bayer_line_to_y(bayer + width, bayer, ydst, width,
+    !start_with_green, !blue_line);
+}
diff -r cb6162341029 -r 006f05659861 v4l2-apps/lib/libv4l/libv4lconvert/jidctflt.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/jidctflt.c	Mon Jun 30 22:23:16 2008 +0200
@@ -0,0 +1,286 @@
+/*
+ * jidctflt.c
+ *
+ * Copyright (C) 1994-1998, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ *
+ * The authors make NO WARRANTY or representation, either express or implied,
+ * with respect to this software, its quality, accuracy, merchantability, or
+ * fitness for a particular purpose.  This software is provided "AS IS", and you,
+ * its user, assume the entire risk as to its quality and accuracy.
+ *
+ * This software is copyright (C) 1991-1998, Thomas G. Lane.
+ * All Rights Reserved except as specified below.
+ *
+ * Permission is hereby granted to use, copy, modify, and distribute this
+ * software (or portions thereof) for any purpose, without fee, subject to these
+ * conditions:
+ * (1) If any part of the source code for this software is distributed, then this
+ * README file must be included, with this copyright and no-warranty notice
+ * unaltered; and any additions, deletions, or changes to the original files
+ * must be clearly indicated in accompanying documentation.
+ * (2) If only executable code is distributed, then the accompanying
+ * documentation must state that "this software is based in part on the work of
+ * the Independent JPEG Group".
+ * (3) Permission for use of this software is granted only if the user accepts
+ * full responsibility for any undesirable consequences; the authors accept
+ * NO LIABILITY for damages of any kind.
+ *
+ * These conditions apply to any software derived from or based on the IJG code,
+ * not just to the unmodified library.  If you use our work, you ought to
+ * acknowledge us.
+ *
+ * Permission is NOT granted for the use of any IJG author's name or company name
+ * in advertising or publicity relating to this software or products derived from
+ * it.  This software may be referred to only as "the Independent JPEG Group's
+ * software".
+ *
+ * We specifically permit and encourage the use of this software as the basis of
+ * commercial products, provided that all warranty or liability claims are
+ * assumed by the product vendor.
+ *
+ *
+ * This file contains a floating-point implementation of the
+ * inverse DCT (Discrete Cosine Transform).  In the IJG code, this routine
+ * must also perform dequantization of the input coefficients.
+ *
+ * This implementation should be more accurate than either of the integer
+ * IDCT implementations.  However, it may not give the same results on all
+ * machines because of differences in roundoff behavior.  Speed will depend
+ * on the hardware's floating point capacity.
+ *
+ * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
+ * on each row (or vice versa, but it's more convenient to emit a row at
+ * a time).  Direct algorithms are also available, but they are much more
+ * complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on Arai, Agui, and Nakajima's algorithm for
+ * scaled DCT.  Their original paper (Trans. IEICE E-71(11):1095) is in
+ * Japanese, but the algorithm is described in the Pennebaker & Mitchell
+ * JPEG textbook (see REFERENCES section in file README).  The following code
+ * is based directly on figure 4-8 in P&M.
+ * While an 8-point DCT cannot be done in less than 11 multiplies, it is
+ * possible to arrange the computation so that many of the multiplies are
+ * simple scalings of the final outputs.  These multiplies can then be
+ * folded into the multiplications or divisions by the JPEG quantization
+ * table entries.  The AA&N method leaves only 5 multiplies and 29 adds
+ * to be done in the DCT itself.
+ * The primary disadvantage of this method is that with a fixed-point
+ * implementation, accuracy is lost due to imprecise representation of the
+ * scaled quantization values.  However, that problem does not arise if
+ * we use floating point arithmetic.
+ */
+
+#include <stdint.h>
+#include "tinyjpeg-internal.h"
+
+#define FAST_FLOAT float
+#define DCTSIZE	   8
+#define DCTSIZE2   (DCTSIZE*DCTSIZE)
+
+#define DEQUANTIZE(coef,quantval)  (((FAST_FLOAT) (coef)) * (quantval))
+
+#if defined(__GNUC__) && (defined(__i686__)) // || defined(__x86_64__))
+
+static inline unsigned char descale_and_clamp(int x, int shift)
+{
+  __asm__ (
+      "add %3,%1\n"
+      "\tsar %2,%1\n"
+      "\tsub $-128,%1\n"
+      "\tcmovl %5,%1\n"	/* Use the sub to compare to 0 */
+      "\tcmpl %4,%1\n"
+      "\tcmovg %4,%1\n"
+      : "=r"(x)
+      : "0"(x), "Ir"(shift), "ir"(1UL<<(shift-1)), "r" (0xff), "r" (0)
+      );
+  return x;
+}
+
+#else
+static inline unsigned char descale_and_clamp(int x, int shift)
+{
+  x += (1UL<<(shift-1));
+  if (x<0)
+    x = (x >> shift) | ((~(0UL)) << (32-(shift)));
+  else
+    x >>= shift;
+  x += 128;
+  if (x>255)
+    return 255;
+  else if (x<0)
+    return 0;
+  else
+    return x;
+}
+#endif
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients.
+ */
+
+void
+tinyjpeg_idct_float (struct component *compptr, uint8_t *output_buf, int stride)
+{
+  FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+  FAST_FLOAT tmp10, tmp11, tmp12, tmp13;
+  FAST_FLOAT z5, z10, z11, z12, z13;
+  int16_t *inptr;
+  FAST_FLOAT *quantptr;
+  FAST_FLOAT *wsptr;
+  uint8_t *outptr;
+  int ctr;
+  FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */
+
+  /* Pass 1: process columns from input, store into work array. */
+
+  inptr = compptr->DCT;
+  quantptr = compptr->Q_table;
+  wsptr = workspace;
+  for (ctr = DCTSIZE; ctr > 0; ctr--) {
+    /* Due to quantization, we will usually find that many of the input
+     * coefficients are zero, especially the AC terms.  We can exploit this
+     * by short-circuiting the IDCT calculation for any column in which all
+     * the AC terms are zero.  In that case each output is equal to the
+     * DC coefficient (with scale factor as needed).
+     * With typical images and quantization tables, half or more of the
+     * column DCT calculations can be simplified this way.
+     */
+
+    if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
+	inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
+	inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
+	inptr[DCTSIZE*7] == 0) {
+      /* AC terms all zero */
+      FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+
+      wsptr[DCTSIZE*0] = dcval;
+      wsptr[DCTSIZE*1] = dcval;
+      wsptr[DCTSIZE*2] = dcval;
+      wsptr[DCTSIZE*3] = dcval;
+      wsptr[DCTSIZE*4] = dcval;
+      wsptr[DCTSIZE*5] = dcval;
+      wsptr[DCTSIZE*6] = dcval;
+      wsptr[DCTSIZE*7] = dcval;
+
+      inptr++;			/* advance pointers to next column */
+      quantptr++;
+      wsptr++;
+      continue;
+    }
+
+    /* Even part */
+
+    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+    tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+    tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+    tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+    tmp10 = tmp0 + tmp2;	/* phase 3 */
+    tmp11 = tmp0 - tmp2;
+
+    tmp13 = tmp1 + tmp3;	/* phases 5-3 */
+    tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */
+
+    tmp0 = tmp10 + tmp13;	/* phase 2 */
+    tmp3 = tmp10 - tmp13;
+    tmp1 = tmp11 + tmp12;
+    tmp2 = tmp11 - tmp12;
+
+    /* Odd part */
+
+    tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+    tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+    tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+    tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+    z13 = tmp6 + tmp5;		/* phase 6 */
+    z10 = tmp6 - tmp5;
+    z11 = tmp4 + tmp7;
+    z12 = tmp4 - tmp7;
+
+    tmp7 = z11 + z13;		/* phase 5 */
+    tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */
+
+    z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */
+    tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */
+    tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */
+
+    tmp6 = tmp12 - tmp7;	/* phase 2 */
+    tmp5 = tmp11 - tmp6;
+    tmp4 = tmp10 + tmp5;
+
+    wsptr[DCTSIZE*0] = tmp0 + tmp7;
+    wsptr[DCTSIZE*7] = tmp0 - tmp7;
+    wsptr[DCTSIZE*1] = tmp1 + tmp6;
+    wsptr[DCTSIZE*6] = tmp1 - tmp6;
+    wsptr[DCTSIZE*2] = tmp2 + tmp5;
+    wsptr[DCTSIZE*5] = tmp2 - tmp5;
+    wsptr[DCTSIZE*4] = tmp3 + tmp4;
+    wsptr[DCTSIZE*3] = tmp3 - tmp4;
+
+    inptr++;			/* advance pointers to next column */
+    quantptr++;
+    wsptr++;
+  }
+
+  /* Pass 2: process rows from work array, store into output array. */
+  /* Note that we must descale the results by a factor of 8 == 2**3. */
+
+  wsptr = workspace;
+  outptr = output_buf;
+  for (ctr = 0; ctr < DCTSIZE; ctr++) {
+    /* Rows of zeroes can be exploited in the same way as we did with columns.
+     * However, the column calculation has created many nonzero AC terms, so
+     * the simplification applies less often (typically 5% to 10% of the time).
+     * And testing floats for zero is relatively expensive, so we don't bother.
+     */
+
+    /* Even part */
+
+    tmp10 = wsptr[0] + wsptr[4];
+    tmp11 = wsptr[0] - wsptr[4];
+
+    tmp13 = wsptr[2] + wsptr[6];
+    tmp12 = (wsptr[2] - wsptr[6]) * ((FAST_FLOAT) 1.414213562) - tmp13;
+
+    tmp0 = tmp10 + tmp13;
+    tmp3 = tmp10 - tmp13;
+    tmp1 = tmp11 + tmp12;
+    tmp2 = tmp11 - tmp12;
+
+    /* Odd part */
+
+    z13 = wsptr[5] + wsptr[3];
+    z10 = wsptr[5] - wsptr[3];
+    z11 = wsptr[1] + wsptr[7];
+    z12 = wsptr[1] - wsptr[7];
+
+    tmp7 = z11 + z13;
+    tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562);
+
+    z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */
+    tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */
+    tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */
+
+    tmp6 = tmp12 - tmp7;
+    tmp5 = tmp11 - tmp6;
+    tmp4 = tmp10 + tmp5;
+
+    /* Final output stage: scale down by a factor of 8 and range-limit */
+
+    outptr[0] = descale_and_clamp((int)(tmp0 + tmp7), 3);
+    outptr[7] = descale_and_clamp((int)(tmp0 - tmp7), 3);
+    outptr[1] = descale_and_clamp((int)(tmp1 + tmp6), 3);
+    outptr[6] = descale_and_clamp((int)(tmp1 - tmp6), 3);
+    outptr[2] = descale_and_clamp((int)(tmp2 + tmp5), 3);
+    outptr[5] = descale_and_clamp((int)(tmp2 - tmp5), 3);
+    outptr[4] = descale_and_clamp((int)(tmp3 + tmp4), 3);
+    outptr[3] = descale_and_clamp((int)(tmp3 - tmp4), 3);
+
+
+    wsptr += DCTSIZE;		/* advance pointer to next row */
+    outptr += stride;
+  }
+}
+
diff -r cb6162341029 -r 006f05659861 v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert-priv.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert-priv.h	Mon Jun 30 22:23:16 2008 +0200
@@ -0,0 +1,80 @@
+/*
+#             (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# 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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef __LIBV4LCONVERT_PRIV_H
+#define __LIBV4LCONVERT_PRIV_H
+
+#include <stdio.h>
+#include "libv4lconvert.h"
+#include "tinyjpeg.h"
+
+#ifndef V4L2_PIX_FMT_SPCA501
+#define V4L2_PIX_FMT_SPCA501 v4l2_fourcc('S','5','0','1')
+#endif
+
+#ifndef V4L2_PIX_FMT_SPCA561
+#define V4L2_PIX_FMT_SPCA561 v4l2_fourcc('S','5','6','1')
+#endif
+
+#ifndef V4L2_PIX_FMT_SGBRG8
+#define V4L2_PIX_FMT_SGBRG8 v4l2_fourcc('G','B','R','G')
+#endif
+
+#ifndef V4L2_PIX_FMT_SGRBG8
+#define V4L2_PIX_FMT_SGRBG8 v4l2_fourcc('G','R','B','G')
+#endif
+
+#ifndef V4L2_PIX_FMT_SRGGB8
+#define V4L2_PIX_FMT_SRGGB8 v4l2_fourcc('R','G','G','B')
+#endif
+
+#define V4LCONVERT_ERROR_MSG_SIZE 256
+
+#define V4LCONVERT_ERR(...) \
+  snprintf(data->error_msg, V4LCONVERT_ERROR_MSG_SIZE, \
+  "v4l-convert: error " __VA_ARGS__)
+
+
+struct v4lconvert_data {
+  int fd;
+  int supported_src_formats; /* bitfield */
+  int no_formats;
+  char error_msg[V4LCONVERT_ERROR_MSG_SIZE];
+  struct jdec_private *jdec;
+};
+
+
+void v4lconvert_yuv420_to_bgr24(const unsigned char *src, unsigned char *dst,
+  int width, int height);
+
+void v4lconvert_spca501_to_yuv420(const unsigned char *src, unsigned char *dst,
+  int width, int height);
+
+void v4lconvert_spca501_to_bgr24(const unsigned char *src, unsigned char *dst,
+  int width, int height);
+
+void v4lconvert_decode_spca561(const unsigned char *src, unsigned char *dst,
+  int width, int height);
+
+void v4lconvert_bayer_to_bgr24(const unsigned char *bayer,
+  unsigned char *rgb, int width, int height, unsigned int pixfmt);
+
+void v4lconvert_bayer_to_yuv420(const unsigned char *bayer,
+  unsigned char *yuv, int width, int height, unsigned int pixfmt);
+
+#endif
diff -r cb6162341029 -r 006f05659861 v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert.c	Mon Jun 30 22:23:16 2008 +0200
@@ -0,0 +1,347 @@
+/*
+#             (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# 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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syscall.h>
+#include <unistd.h>
+#include "libv4lconvert.h"
+#include "libv4lconvert-priv.h"
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+static const unsigned int supported_src_pixfmts[] = {
+  V4L2_PIX_FMT_BGR24,
+  V4L2_PIX_FMT_YUV420,
+  V4L2_PIX_FMT_MJPEG,
+  V4L2_PIX_FMT_JPEG,
+  V4L2_PIX_FMT_SBGGR8,
+  V4L2_PIX_FMT_SGBRG8,
+  V4L2_PIX_FMT_SGRBG8,
+  V4L2_PIX_FMT_SRGGB8,
+  V4L2_PIX_FMT_SPCA501,
+  V4L2_PIX_FMT_SPCA561,
+  -1
+};
+
+static const unsigned int supported_dst_pixfmts[] = {
+  V4L2_PIX_FMT_BGR24,
+  V4L2_PIX_FMT_YUV420,
+  -1
+};
+
+
+struct v4lconvert_data *v4lconvert_create(int fd)
+{
+  int i, j;
+  struct v4lconvert_data *data = calloc(1, sizeof(struct v4lconvert_data));
+
+  if (!data)
+    return NULL;
+
+  data->fd = fd;
+  data->jdec = NULL;
+
+  /* Check supported formats */
+  for (i = 0; ; i++) {
+    struct v4l2_fmtdesc fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
+
+    fmt.index = i;
+
+    if (syscall(SYS_ioctl, fd, VIDIOC_ENUM_FMT, &fmt))
+      break;
+
+    for (j = 0; supported_src_pixfmts[j] != -1; j++)
+      if (fmt.pixelformat == supported_src_pixfmts[j]) {
+	data->supported_src_formats |= 1 << j;
+	break;
+      }
+  }
+
+  data->no_formats = i;
+
+  return data;
+}
+
+void v4lconvert_destroy(struct v4lconvert_data *data)
+{
+  if (data->jdec) {
+    unsigned char *comps[3] = { NULL, NULL, NULL };
+    tinyjpeg_set_components(data->jdec, comps, 3);
+    tinyjpeg_free(data->jdec);
+  }
+  free(data);
+}
+
+/* See libv4lconvert.h for description of in / out parameters */
+int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt)
+{
+  if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+      fmt->index < data->no_formats ||
+      !data->supported_src_formats)
+    return syscall(SYS_ioctl, data->fd, VIDIOC_ENUM_FMT, fmt);
+
+  fmt->flags = 0;
+  fmt->pixelformat = -1;
+  memset(fmt->reserved, 0, 4);
+
+  /* Note bgr24 and yuv420 are the first 2 in our mask of supported formats */
+  switch (fmt->index - data->no_formats) {
+    case 0:
+      if (!(data->supported_src_formats & 1)) {
+	strcpy((char *)fmt->description, "BGR24");
+	fmt->pixelformat = V4L2_PIX_FMT_BGR24;
+      } else if (!(data->supported_src_formats & 2)) {
+	strcpy((char *)fmt->description, "YUV420");
+	fmt->pixelformat = V4L2_PIX_FMT_YUV420;
+      }
+      break;
+    case 1:
+      if (!(data->supported_src_formats & 3)) {
+	strcpy((char *)fmt->description, "YUV420");
+	fmt->pixelformat = V4L2_PIX_FMT_YUV420;
+      }
+      break;
+  }
+  if (fmt->pixelformat == -1) {
+    errno = EINVAL;
+    return -1;
+  }
+
+  return 0;
+}
+
+/* See libv4lconvert.h for description of in / out parameters */
+int v4lconvert_try_format(struct v4lconvert_data *data,
+  struct v4l2_format *dest_fmt, struct v4l2_format *src_fmt)
+{
+  int i;
+  unsigned int try_pixfmt, closest_fmt_size_diff = -1;
+  unsigned int desired_pixfmt = dest_fmt->fmt.pix.pixelformat;
+  struct v4l2_format try_fmt, closest_fmt = { .type = -1 };
+
+  for (i = 0; supported_dst_pixfmts[i] != -1; i++)
+    if (supported_dst_pixfmts[i] == desired_pixfmt)
+      break;
+
+  /* Can we do conversion to the requested format & type? */
+  if (supported_dst_pixfmts[i] == -1 ||
+      dest_fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+    int ret = syscall(SYS_ioctl, data->fd, VIDIOC_TRY_FMT, dest_fmt);
+    if (src_fmt)
+      *src_fmt = *dest_fmt;
+    return ret;
+  }
+
+  for (i = 0; (try_pixfmt = supported_src_pixfmts[i]) != -1; i++) {
+    /* is this format supported? */
+    if (!(data->supported_src_formats & (1 << i)))
+      continue;
+
+    try_fmt = *dest_fmt;
+    try_fmt.fmt.pix.pixelformat = try_pixfmt;
+
+    if (!syscall(SYS_ioctl, data->fd, VIDIOC_TRY_FMT, &try_fmt))
+    {
+      if (try_fmt.fmt.pix.pixelformat == try_pixfmt) {
+	int size_x_diff = abs((int)try_fmt.fmt.pix.width -
+			      (int)dest_fmt->fmt.pix.width);
+	int size_y_diff = abs((int)try_fmt.fmt.pix.height -
+			      (int)dest_fmt->fmt.pix.height);
+	unsigned int size_diff = size_x_diff * size_x_diff +
+				 size_y_diff * size_y_diff;
+	if (size_diff < closest_fmt_size_diff) {
+	  closest_fmt_size_diff = size_diff;
+	  closest_fmt = try_fmt;
+	}
+      }
+    }
+  }
+
+  if (closest_fmt.type == -1) {
+    errno = EINVAL;
+    return -1;
+  }
+
+  *dest_fmt = closest_fmt;
+
+  /* Are we converting? */
+  if (closest_fmt.fmt.pix.pixelformat != desired_pixfmt) {
+    dest_fmt->fmt.pix.pixelformat = desired_pixfmt;
+    switch (dest_fmt->fmt.pix.pixelformat) {
+      case V4L2_PIX_FMT_BGR24:
+	dest_fmt->fmt.pix.bytesperline = dest_fmt->fmt.pix.width * 3;
+	dest_fmt->fmt.pix.sizeimage = dest_fmt->fmt.pix.width *
+				      dest_fmt->fmt.pix.height * 3;
+	break;
+      case V4L2_PIX_FMT_YUV420:
+	dest_fmt->fmt.pix.bytesperline = dest_fmt->fmt.pix.width;
+	dest_fmt->fmt.pix.sizeimage = (dest_fmt->fmt.pix.width *
+				       dest_fmt->fmt.pix.height * 3) / 2;
+	break;
+    }
+  }
+
+  if (src_fmt)
+    *src_fmt = closest_fmt;
+
+  return 0;
+}
+
+int v4lconvert_convert(struct v4lconvert_data *data,
+  const struct v4l2_format *src_fmt,  /* in */
+  const struct v4l2_format *dest_fmt, /* in */
+  unsigned char *src, int src_size, unsigned char *dest, int dest_size)
+{
+  unsigned int header_width, header_height;
+  int result, needed;
+  unsigned char *components[3];
+
+  /* Special case when no conversion is needed */
+  if(!memcmp(src_fmt, dest_fmt, sizeof(*src_fmt))) {
+    int to_copy = MIN(dest_size, src_size);
+    memcpy(dest, src, to_copy);
+    return to_copy;
+  }
+
+  /* sanity check, is the dest buffer large enough? */
+  switch (dest_fmt->fmt.pix.pixelformat) {
+    case V4L2_PIX_FMT_BGR24:
+      needed = dest_fmt->fmt.pix.width * dest_fmt->fmt.pix.height * 3;
+      break;
+    case V4L2_PIX_FMT_YUV420:
+      needed = (dest_fmt->fmt.pix.width * dest_fmt->fmt.pix.height * 3) / 2;
+      break;
+    default:
+      V4LCONVERT_ERR("Unknown dest format in conversion\n");
+      errno = EINVAL;
+      return -1;
+  }
+
+  if (dest_size < needed) {
+    V4LCONVERT_ERR("destination buffer too small\n");
+    errno = EFAULT;
+    return -1;
+  }
+
+  switch (src_fmt->fmt.pix.pixelformat) {
+    case V4L2_PIX_FMT_MJPEG:
+    case V4L2_PIX_FMT_JPEG:
+      if (!data->jdec) {
+	data->jdec = tinyjpeg_init();
+	if (!data->jdec) {
+	  V4LCONVERT_ERR("out of memory!\n");
+	  errno = ENOMEM;
+	  return -1;
+	}
+      }
+      tinyjpeg_set_flags(data->jdec,
+			 (src_fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)?
+			 TINYJPEG_FLAGS_MJPEG_TABLE : 0);
+      if (tinyjpeg_parse_header(data->jdec, src, src_size)) {
+	V4LCONVERT_ERR("parsing JPEG header: %s\n",
+	  tinyjpeg_get_errorstring(data->jdec));
+	errno = EIO;
+	return -1;
+      }
+      tinyjpeg_get_size(data->jdec, &header_width, &header_height);
+
+      if (header_width != dest_fmt->fmt.pix.width || header_height != dest_fmt->fmt.pix.height) {
+	V4LCONVERT_ERR("unexpected width / height in JPEG header\n");
+	V4LCONVERT_ERR("expected: %dx%d, header: %ux%u\n",
+	  dest_fmt->fmt.pix.width, dest_fmt->fmt.pix.height,
+	  header_width, header_height);
+	errno = EIO;
+	return -1;
+      }
+
+      components[0] = dest;
+      components[1] = components[0] + dest_fmt->fmt.pix.width *
+				      dest_fmt->fmt.pix.height;
+      components[2] = components[1] + (dest_fmt->fmt.pix.width *
+				       dest_fmt->fmt.pix.height) / 4;
+
+      if (dest_fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24) {
+	tinyjpeg_set_components(data->jdec, components, 1);
+	result = tinyjpeg_decode(data->jdec, TINYJPEG_FMT_BGR24);
+      } else {
+	tinyjpeg_set_components(data->jdec, components, 3);
+	result = tinyjpeg_decode(data->jdec, TINYJPEG_FMT_YUV420P);
+      }
+
+      if (result) {
+	V4LCONVERT_ERR("decompressing JPEG: %s\n",
+	  tinyjpeg_get_errorstring(data->jdec));
+	errno = EIO;
+	return -1;
+      }
+      break;
+
+    case V4L2_PIX_FMT_SBGGR8:
+    case V4L2_PIX_FMT_SGBRG8:
+    case V4L2_PIX_FMT_SGRBG8:
+    case V4L2_PIX_FMT_SRGGB8:
+      if (dest_fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24)
+	v4lconvert_bayer_to_bgr24(src, dest, dest_fmt->fmt.pix.width,
+		    dest_fmt->fmt.pix.height, src_fmt->fmt.pix.pixelformat);
+      else
+	v4lconvert_bayer_to_yuv420(src, dest, dest_fmt->fmt.pix.width,
+		    dest_fmt->fmt.pix.height, src_fmt->fmt.pix.pixelformat);
+      break;
+
+    case V4L2_PIX_FMT_SPCA501:
+      if (dest_fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24)
+	v4lconvert_spca501_to_bgr24(src, dest, dest_fmt->fmt.pix.width,
+				    dest_fmt->fmt.pix.height);
+      else
+	v4lconvert_spca501_to_yuv420(src, dest, dest_fmt->fmt.pix.width,
+				     dest_fmt->fmt.pix.height);
+      break;
+
+    case V4L2_PIX_FMT_SPCA561:
+    {
+      static unsigned char tmpbuf[640 * 480];
+      v4lconvert_decode_spca561(src, tmpbuf, dest_fmt->fmt.pix.width,
+				dest_fmt->fmt.pix.height);
+      if (dest_fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24)
+	v4lconvert_bayer_to_bgr24(tmpbuf, dest, dest_fmt->fmt.pix.width,
+		    dest_fmt->fmt.pix.height, V4L2_PIX_FMT_SGBRG8);
+      else
+	v4lconvert_bayer_to_yuv420(tmpbuf, dest, dest_fmt->fmt.pix.width,
+		    dest_fmt->fmt.pix.height, V4L2_PIX_FMT_SGBRG8);
+      break;
+    }
+    case V4L2_PIX_FMT_BGR24:
+      /* dest must be V4L2_PIX_FMT_YUV420 then */
+      printf("FIXME add bgr24 -> yuv420 conversion\n");
+      break;
+    case V4L2_PIX_FMT_YUV420:
+      /* dest must be V4L2_PIX_FMT_BGR24 then */
+      v4lconvert_yuv420_to_bgr24(src, dest, dest_fmt->fmt.pix.width,
+				 dest_fmt->fmt.pix.height);
+      break;
+  }
+
+  return needed;
+}
+
+const char *v4lconvert_get_error_message(struct v4lconvert_data *data)
+{
+  return data->error_msg;
+}
diff -r cb6162341029 -r 006f05659861 v4l2-apps/lib/libv4l/libv4lconvert/rgbyuv.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/rgbyuv.c	Mon Jun 30 22:23:16 2008 +0200
@@ -0,0 +1,82 @@
+/*
+
+# RGB <-> YUV conversion routines
+
+#             (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# 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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+#define RGB2YUV(r,g,b,y,u,v) \
+    (y) = ((  8453*(r) + 16594*(g) +  3223*(b) +  524288) >> 15); \
+    (u) = (( -4878*(r) -  9578*(g) + 14456*(b) + 4210688) >> 15); \
+    (v) = (( 14456*(r) - 12105*(g) -  2351*(b) + 4210688) >> 15)
+
+#define YUV2R(y, u, v) ({ \
+  int r = (y) + ((((v)-128)*1436) >> 10); r > 255 ? 255 : r < 0 ? 0 : r; })
+#define YUV2G(y, u, v) ({ \
+  int g = (y) - ((((u)-128)*352 + ((v)-128)*731) >> 10); g > 255 ? 255 : g < 0 ? 0 : g; })
+#define YUV2B(y, u, v) ({ \
+  int b = (y) + ((((u)-128)*1814) >> 10); b > 255 ? 255 : b < 0 ? 0 : b; })
+
+#define CLIP(color) (unsigned char)(((color)>0xFF)?0xff:(((color)<0)?0:(color)))
+
+void v4lconvert_yuv420_to_bgr24(const unsigned char *src, unsigned char *dest,
+  int width, int height)
+{
+  int i,j;
+
+  const unsigned char *ysrc = src;
+  const unsigned char *usrc = src + width * height;
+  const unsigned char *vsrc = usrc + (width * height) / 4;
+
+  for (i = 0; i < height; i++) {
+    for (j = 0; j < width; j += 2) {
+#if 1 /* fast slightly less accurate multiplication free code */
+      int u1 = (((*usrc - 128) << 7) +  (*usrc - 128)) >> 6;
+      int rg = (((*usrc - 128) << 1) +  (*usrc - 128) +
+		((*vsrc - 128) << 2) + ((*vsrc - 128) << 1)) >> 3;
+      int v1 = (((*vsrc - 128) << 1) +  (*vsrc - 128)) >> 1;
+
+      *dest++ = CLIP(*ysrc + u1);
+      *dest++ = CLIP(*ysrc - rg);
+      *dest++ = CLIP(*ysrc + v1);
+      ysrc++;
+
+      *dest++ = CLIP(*ysrc + u1);
+      *dest++ = CLIP(*ysrc - rg);
+      *dest++ = CLIP(*ysrc + v1);
+#else
+      *dest++ = YUV2B(*ysrc, *usrc, *vsrc);
+      *dest++ = YUV2G(*ysrc, *usrc, *vsrc);
+      *dest++ = YUV2R(*ysrc, *usrc, *vsrc);
+      ysrc++;
+
+      *dest++ = YUV2B(*ysrc, *usrc, *vsrc);
+      *dest++ = YUV2G(*ysrc, *usrc, *vsrc);
+      *dest++ = YUV2R(*ysrc, *usrc, *vsrc);
+#endif
+      ysrc++;
+      usrc++;
+      vsrc++;
+    }
+    /* Rewind u and v for next line */
+    if (i&1) {
+      usrc -= width / 2;
+      vsrc -= width / 2;
+    }
+  }
+}
diff -r cb6162341029 -r 006f05659861 v4l2-apps/lib/libv4l/libv4lconvert/spca501.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/spca501.c	Mon Jun 30 22:23:16 2008 +0200
@@ -0,0 +1,67 @@
+/*
+#             (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+# 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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "libv4lconvert-priv.h"
+
+void v4lconvert_spca501_to_yuv420(const unsigned char *src, unsigned char *dst,
+  int width, int height)
+{
+  int i,j;
+
+  for (i = 0; i < height; i += 2) {
+    unsigned long *lsrc = (unsigned long *)(src + (i / 2) * 3 * width);
+
+    /* -128 - 127 --> 0 - 255 and copy first line Y */
+    unsigned long *ldst = (unsigned long *)(dst + i * width);
+    for (j = 0; j < width; j += sizeof(long)) {
+      *ldst = *lsrc++;
+      *ldst++ ^= 0x8080808080808080ULL;
+    }
+
+    /* -128 - 127 --> 0 - 255 and copy 1 line U */
+    ldst = (unsigned long *)(dst + width * height + i * width / 4);
+    for (j = 0; j < width/2; j += sizeof(long)) {
+      *ldst = *lsrc++;
+      *ldst++ ^= 0x8080808080808080ULL;
+    }
+
+    /* -128 - 127 --> 0 - 255 and copy second line Y */
+    ldst = (unsigned long *)(dst + i * width + width);
+    for (j = 0; j < width; j += sizeof(long)) {
+      *ldst = *lsrc++;
+      *ldst++ ^= 0x8080808080808080ULL;
+    }
+
+    /* -128 - 127 --> 0 - 255 and copy 1 line V */
+    ldst = (unsigned long *)(dst + (width * height * 5) / 4 + i * width / 4);
+    for (j = 0; j < width/2; j += sizeof(long)) {
+      *ldst = *lsrc++;
+      *ldst++ ^= 0x8080808080808080ULL;
+    }
+  }
+}
+
+/* IMPROVEME (maybe?) make this convert in one go?? */
+void v4lconvert_spca501_to_bgr24(const unsigned char *src, unsigned char *dst,
+  int width, int height)
+{
+  unsigned char buf[(width * height * 6) / 4];
+
+  v4lconvert_spca501_to_yuv420(src, buf, width, height);
+  v4lconvert_yuv420_to_bgr24(buf, dst, width, height);
+}
diff -r cb6162341029 -r 006f05659861 v4l2-apps/lib/libv4l/libv4lconvert/spca561-decompress.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/spca561-decompress.c	Mon Jun 30 22:23:16 2008 +0200
@@ -0,0 +1,1002 @@
+/*
+
+# Spca561decoder (C) 2005 Andrzej Szombierski [qq@kuku.eu.org]
+
+# 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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+# Note this code was originally licensed under the GNU GPL instead of the
+# GNU LGPL, its license has been changed with permission, see the permission
+# mail at the end of this file.
+
+*/
+
+/*
+ *	Decoder for compressed spca561 images
+ *	It was developed for "Labtec WebCam Elch 2(SPCA561A)" (046d:0929)
+ *	but it might work with other spca561 cameras
+ */
+#include <string.h>
+
+/*fixme: not reentrant */
+static unsigned int bit_bucket;
+static const unsigned char *input_ptr;
+
+static inline void refill(int *bitfill)
+{
+	if (*bitfill < 8) {
+		bit_bucket = (bit_bucket << 8) | *(input_ptr++);
+		*bitfill += 8;
+	}
+}
+
+static inline int nbits(int *bitfill, int n)
+{
+	bit_bucket = (bit_bucket << 8) | *(input_ptr++);
+	*bitfill -= n;
+	return (bit_bucket >> (*bitfill & 0xff)) & ((1 << n) - 1);
+}
+
+static inline int _nbits(int *bitfill, int n)
+{
+	*bitfill -= n;
+	return (bit_bucket >> (*bitfill & 0xff)) & ((1 << n) - 1);
+}
+
+static int fun_A(int *bitfill)
+{
+	int ret;
+	static int tab[] = {
+		12, 13, 14, 15, 16, 17, 18, 19, -12, -13, -14, -15,
+		-16, -17, -18, -19, -19
+	};
+
+	ret = tab[nbits(bitfill, 4)];
+
+	refill(bitfill);
+	return ret;
+}
+static int fun_B(int *bitfill)
+{
+	static int tab1[] =
+	    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 31, 31,
+		31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+		    16, 17,
+		18,
+		19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30
+	};
+	static int tab[] =
+	    { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, -5,
+		-6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17,
+		    -18, -19
+	};
+	unsigned int tmp;
+
+	tmp = nbits(bitfill, 7) - 68;
+	refill(bitfill);
+	if (tmp > 47)
+		return 0xff;
+	return tab[tab1[tmp]];
+}
+static int fun_C(int *bitfill, int gkw)
+{
+	static int tab1[] =
+	    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 23, 23, 23, 23, 23, 23,
+		23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+		    12, 13,
+		14,
+		15, 16, 17, 18, 19, 20, 21, 22
+	};
+	static int tab[] =
+	    { 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, -9, -10, -11,
+		-12, -13, -14, -15, -16, -17, -18, -19
+	};
+	unsigned int tmp;
+
+	if (gkw == 0xfe) {
+		if (nbits(bitfill, 1) == 0)
+			return 7;
+		else
+			return -8;
+	}
+
+	if (gkw != 0xff)
+		return 0xff;
+
+	tmp = nbits(bitfill, 7) - 72;
+	if (tmp > 43)
+		return 0xff;
+
+	refill(bitfill);
+	return tab[tab1[tmp]];
+}
+static int fun_D(int *bitfill, int gkw)
+{
+	if (gkw == 0xfd) {
+		if (nbits(bitfill, 1) == 0)
+			return 12;
+		return -13;
+	}
+
+	if (gkw == 0xfc) {
+		if (nbits(bitfill, 1) == 0)
+			return 13;
+		return -14;
+	}
+
+	if (gkw == 0xfe) {
+		switch (nbits(bitfill, 2)) {
+		case 0:
+			return 14;
+		case 1:
+			return -15;
+		case 2:
+			return 15;
+		case 3:
+			return -16;
+		}
+	}
+
+	if (gkw == 0xff) {
+		switch (nbits(bitfill, 3)) {
+		case 4:
+			return 16;
+		case 5:
+			return -17;
+		case 6:
+			return 17;
+		case 7:
+			return -18;
+		case 2:
+			return _nbits(bitfill, 1) ? 0xed : 0x12;
+		case 3:
+			(*bitfill)--;
+			return 18;
+		}
+		return 0xff;
+	}
+	return gkw;
+}
+
+static int fun_E(int cur_byte, int *bitfill)
+{
+	static int tab0[] = { 0, -1, 1, -2, 2, -3, 3, -4 };
+	static int tab1[] = { 4, -5, 5, -6, 6, -7, 7, -8 };
+	static int tab2[] = { 8, -9, 9, -10, 10, -11, 11, -12 };
+	static int tab3[] = { 12, -13, 13, -14, 14, -15, 15, -16 };
+	static int tab4[] = { 16, -17, 17, -18, 18, -19, 19, -19 };
+
+	if ((cur_byte & 0xf0) >= 0x80) {
+		*bitfill -= 4;
+		return tab0[(cur_byte >> 4) & 7];
+	}
+	if ((cur_byte & 0xc0) == 0x40) {
+		*bitfill -= 5;
+		return tab1[(cur_byte >> 3) & 7];
+
+	}
+	if ((cur_byte & 0xe0) == 0x20) {
+		*bitfill -= 6;
+		return tab2[(cur_byte >> 2) & 7];
+
+	}
+	if ((cur_byte & 0xf0) == 0x10) {
+		*bitfill -= 7;
+		return tab3[(cur_byte >> 1) & 7];
+
+	}
+	if ((cur_byte & 0xf8) == 8) {
+		*bitfill -= 8;
+		return tab4[cur_byte & 7];
+	}
+	return 0xff;
+}
+
+static int fun_F(int cur_byte, int *bitfill)
+{
+	*bitfill -= 5;
+	switch (cur_byte & 0xf8) {
+	case 0x80:
+		return 0;
+	case 0x88:
+		return -1;
+	case 0x90:
+		return 1;
+	case 0x98:
+		return -2;
+	case 0xa0:
+		return 2;
+	case 0xa8:
+		return -3;
+	case 0xb0:
+		return 3;
+	case 0xb8:
+		return -4;
+	case 0xc0:
+		return 4;
+	case 0xc8:
+		return -5;
+	case 0xd0:
+		return 5;
+	case 0xd8:
+		return -6;
+	case 0xe0:
+		return 6;
+	case 0xe8:
+		return -7;
+	case 0xf0:
+		return 7;
+	case 0xf8:
+		return -8;
+	}
+
+	*bitfill -= 1;
+	switch (cur_byte & 0xfc) {
+	case 0x40:
+		return 8;
+	case 0x44:
+		return -9;
+	case 0x48:
+		return 9;
+	case 0x4c:
+		return -10;
+	case 0x50:
+		return 10;
+	case 0x54:
+		return -11;
+	case 0x58:
+		return 11;
+	case 0x5c:
+		return -12;
+	case 0x60:
+		return 12;
+	case 0x64:
+		return -13;
+	case 0x68:
+		return 13;
+	case 0x6c:
+		return -14;
+	case 0x70:
+		return 14;
+	case 0x74:
+		return -15;
+	case 0x78:
+		return 15;
+	case 0x7c:
+		return -16;
+	}
+
+	*bitfill -= 1;
+	switch (cur_byte & 0xfe) {
+	case 0x20:
+		return 16;
+	case 0x22:
+		return -17;
+	case 0x24:
+		return 17;
+	case 0x26:
+		return -18;
+	case 0x28:
+		return 18;
+	case 0x2a:
+		return -19;
+	case 0x2c:
+		return 19;
+	}
+
+	*bitfill += 7;
+	return 0xff;
+}
+
+static int internal_spca561_decode(int width, int height,
+				   const unsigned char *inbuf,
+				   unsigned char *outbuf)
+{
+	/* buffers */
+	static int accum[8 * 8 * 8];
+	static int i_hits[8 * 8 * 8];
+
+	const static int nbits_A[] =
+	    { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+		    1, 1,
+		1, 1, 1, 1, 1,
+		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+		    1, 1,
+		1, 1, 1, 1, 1,
+		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+		    1, 1,
+		1, 1, 1, 1, 1,
+		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+		    1, 1,
+		1, 1, 1, 1, 1,
+		8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 7, 7,
+		    7, 7,
+		7, 7, 7, 7, 7,
+		7, 7, 7, 7, 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+		    3, 3,
+		3, 3, 3, 3, 3,
+		3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+		    5, 5,
+		5, 5, 5, 5, 5,
+		5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3,
+		    3, 3,
+		3, 3, 3, 3, 3,
+		3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+	};
+	const static int tab_A[] =
+	    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		    0, 0,
+		0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		    0, 0,
+		0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		    0, 0,
+		0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		    0, 0,
+		0, 0, 0, 0,
+		0, 0, 0, 0, 11, -11, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,
+		    10, 10,
+		255, 254, -4,
+		-4, -5, -5, -6, -6, -7, -7, -8, -8, -9, -9, -10, -10, -1,
+		    -1, -1,
+		-1, -1, -1,
+		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+		    -1, -1,
+		-1, -1,
+		-1, -1, -1, -1, -1, -1, -1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3,
+		    3, 3, 3,
+		3, 3, 3,
+		-2, -2, -2, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -3, -3,
+		    -3, 1,
+		1, 1, 1, 1,
+		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+		    1, 1,
+		1, 1, 1, 1,
+		1
+	};
+
+	const static int nbits_B[] =
+	    { 0, 8, 7, 7, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4,
+		4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3,
+		    3, 3,
+		3, 3, 3, 3, 3,
+		3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2,
+		    2, 2,
+		2, 2, 2, 2, 2,
+		2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+		    2, 2,
+		2, 2, 2, 2, 2,
+		2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+		    2, 2,
+		2, 2, 2, 2, 2,
+		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+		    1, 1,
+		1, 1, 1, 1, 1,
+		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+		    1, 1,
+		1, 1, 1, 1, 1,
+		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+		    1, 1,
+		1, 1, 1, 1, 1,
+		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+		    1, 1,
+		1, 1, 1, 1, 1,
+		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	};
+	const static int tab_B[] =
+	    { 0xff, -4, 3, 3, -3, -3, -3, -3, 2, 2, 2, 2, 2, 2, 2, 2, -2,
+		-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+		    1, 1,
+		1, 1, 1, 1,
+		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+		    1, 1,
+		1, 1, 1, 1,
+		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+		    -1, -1,
+		-1, -1,
+		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+		    -1, -1,
+		-1, -1,
+		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+		    -1, -1,
+		-1, -1,
+		-1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		    0, 0, 0,
+		0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		    0, 0,
+		0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		    0, 0,
+		0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		    0, 0,
+		0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		    0, 0,
+		0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0,
+	};
+
+	const static int nbits_C[] =
+	    { 0, 0, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5,
+		5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+		    4, 4,
+		4, 4, 4, 4, 4,
+		4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3,
+		    3, 3,
+		3, 3, 3, 3, 3,
+		3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+		    3, 3,
+		3, 3, 3, 3, 3,
+		3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+		    3, 3,
+		3, 3, 3, 3, 3,
+		2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+		    2, 2,
+		2, 2, 2, 2, 2,
+		2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+		    2, 2,
+		2, 2, 2, 2, 2,
+		2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+		    2, 2,
+		2, 2, 2, 2, 2,
+		2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+		    2, 2,
+		2, 2, 2, 2, 2,
+		2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+	};
+	const static int tab_C[] =
+	    { 0xff, 0xfe, 6, -7, 5, 5, -6, -6, 4, 4, 4, 4, -5, -5, -5, -5,
+		3, 3, 3, 3, 3, 3, 3, 3, -4, -4, -4, -4, -4, -4, -4, -4, 2,
+		    2, 2, 2,
+		2, 2, 2,
+		2, 2, 2, 2, 2, 2, 2, 2, 2, -3, -3, -3, -3, -3, -3, -3, -3,
+		    -3, -3,
+		-3, -3, -3,
+		-3, -3, -3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+		    1, 1,
+		1, 1, 1, 1,
+		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2,
+		    -2, -2,
+		-2, -2, -2,
+		-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+		    -2, -2,
+		-2, -2,
+		-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		    0, 0, 0,
+		0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		    0, 0,
+		0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1,
+		    -1, -1,
+		-1, -1, -1,
+		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+		    -1, -1,
+		-1, -1,
+		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+		    -1, -1,
+		-1, -1,
+		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+		    -1,
+	};
+
+	const static int nbits_D[] =
+	    { 0, 0, 0, 0, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6,
+		6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5,
+		    5, 5,
+		5, 5, 5, 5, 5,
+		5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4,
+		    4, 4,
+		4, 4, 4, 4, 4,
+		4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+		    4, 4,
+		4, 4, 4, 4, 4,
+		4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+		    4, 4,
+		4, 4, 4, 4, 4,
+		3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+		    3, 3,
+		3, 3, 3, 3, 3,
+		3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+		    3, 3,
+		3, 3, 3, 3, 3,
+		3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+		    3, 3,
+		3, 3, 3, 3, 3,
+		3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+		    3, 3,
+		3, 3, 3, 3, 3,
+		3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
+	};
+	const static int tab_D[] =
+	    { 0xff, 0xfe, 0xfd, 0xfc, 10, -11, 11, -12, 8, 8, -9, -9, 9, 9,
+		-10, -10, 6, 6, 6, 6, -7, -7, -7, -7, 7, 7, 7, 7, -8, -8,
+		    -8, -8,
+		4, 4, 4, 4,
+		4, 4, 4, 4, -5, -5, -5, -5, -5, -5, -5, -5, 5, 5, 5, 5, 5,
+		    5, 5, 5,
+		-6, -6,
+		-6, -6, -6, -6, -6, -6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+		    2, 2,
+		2, 2, -3,
+		-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,
+		    3, 3,
+		3, 3, 3, 3,
+		3, 3, 3, 3, 3, 3, 3, 3, 3, 3, -4, -4, -4, -4, -4, -4, -4,
+		    -4, -4,
+		-4, -4, -4,
+		-4, -4, -4, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		    0, 0, 0,
+		0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1,
+		    -1, -1,
+		-1, -1, -1,
+		-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+		    -1, -1,
+		-1, -1,
+		-1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+		    1, 1, 1,
+		1, 1, 1,
+		1, 1, 1, 1, 1, 1, 1, 1, 1, -2, -2, -2, -2, -2, -2, -2, -2,
+		    -2, -2,
+		-2, -2, -2,
+		-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+		    -2, -2,
+		-2, -2
+	};
+
+	/* a_curve[19 + i] = ... [-19..19] => [-160..160] */
+	const static int a_curve[] =
+	    { -160, -144, -128, -112, -98, -88, -80, -72, -64, -56, -48,
+		-40, -32, -24, -18, -12, -8, -5, -2, 0, 2, 5, 8, 12, 18,
+		    24, 32,
+		40, 48, 56, 64,
+		72, 80, 88, 98, 112, 128, 144, 160
+	};
+	/* clamp0_255[256 + i] = min(max(i,255),0) */
+	const static unsigned char clamp0_255[] =
+	    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		    0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		    0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		    0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		    0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		    0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		    0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		    0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		    1, 2,
+		3, 4, 5, 6, 7, 8, 9, 10,
+		11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+		    26, 27,
+		28, 29, 30, 31, 32, 33,
+		34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+		    49, 50,
+		51, 52, 53, 54, 55, 56,
+		57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
+		    72, 73,
+		74, 75, 76, 77, 78, 79,
+		80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+		    95, 96,
+		97, 98, 99, 100, 101,
+		102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
+		    114,
+		115, 116, 117, 118, 119,
+		120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131,
+		    132,
+		133, 134, 135, 136, 137,
+		138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+		    150,
+		151, 152, 153, 154, 155,
+		156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
+		    168,
+		169, 170, 171, 172, 173,
+		174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185,
+		    186,
+		187, 188, 189, 190, 191,
+		192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203,
+		    204,
+		205, 206, 207, 208, 209,
+		210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221,
+		    222,
+		223, 224, 225, 226, 227,
+		228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+		    240,
+		241, 242, 243, 244, 245,
+		246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 255, 255,
+		    255,
+		255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		    255,
+		255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		    255,
+		255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		    255,
+		255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		    255,
+		255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		    255,
+		255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		    255,
+		255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		    255,
+		255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		    255,
+		255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		    255,
+		255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		    255,
+		255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		    255,
+		255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		    255,
+		255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		    255,
+		255, 255, 255, 255, 255,
+		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+		    255,
+		255
+	};
+	/* abs_clamp15[19 + i] = min(abs(i), 15) */
+	const static int abs_clamp15[] =
+	    { 15, 15, 15, 15, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3,
+		2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+		    15, 15,
+		15
+	};
+	/* diff_encoding[256 + i] = ... */
+	const static int diff_encoding[] =
+	    { 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+		    7, 7,
+		7, 7, 7, 7, 7, 7, 7,
+		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+		    7, 7,
+		7, 7, 7, 7, 7, 7, 7,
+		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+		    7, 7,
+		7, 7, 7, 7, 7, 7, 7,
+		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+		    7, 7,
+		7, 7, 7, 7, 7, 7, 7,
+		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+		    7, 7,
+		7, 7, 7, 7, 7, 7, 7,
+		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+		    7, 7,
+		7, 7, 7, 7, 7, 7, 7,
+		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+		    7, 7,
+		7, 7, 7, 7, 7, 7, 7,
+		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 5,
+		    5, 5,
+		5, 5, 5, 5, 5, 3, 3,
+		3, 3, 1, 1, 0, 2, 2, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+		    6, 6,
+		6, 6, 6, 6, 6, 6, 6,
+		6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+		    6, 6,
+		6, 6, 6, 6, 6, 6, 6,
+		6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+		    6, 6,
+		6, 6, 6, 6, 6, 6, 6,
+		6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+		    6, 6,
+		6, 6, 6, 6, 6, 6, 6,
+		6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+		    6, 6,
+		6, 6, 6, 6, 6, 6, 6,
+		6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+		    6, 6,
+		6, 6, 6, 6, 6, 6, 6,
+		6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+		    6, 6,
+		6, 6, 6, 6, 6, 6, 6,
+		6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+		    6, 6,
+		6, 6, 6, 6, 6, 6, 6,
+		6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+		    6, 6,
+		6, 6, 6, 6, 6, 6
+	};
+
+	int block;
+	int bitfill = 0;
+	int xwidth = width + 6;
+	int off_up_right = 2 - 2 * xwidth;
+	int off_up_left = -2 - 2 * xwidth;
+	int pixel_U = 0, saved_pixel_UR = 0;
+	int pixel_x = 0, pixel_y = 2;
+	unsigned char *output_ptr = outbuf;
+
+	memset(i_hits, 0, sizeof(i_hits));
+	memset(accum, 0, sizeof(accum));
+
+	memcpy(outbuf + xwidth * 2 + 3, inbuf + 0x14, width);
+	memcpy(outbuf + xwidth * 3 + 3, inbuf + 0x14 + width, width);
+
+	input_ptr = inbuf + 0x14 + width * 2;
+	output_ptr = outbuf + (xwidth) * 4 + 3;
+
+	bit_bucket = 0;
+
+	for (block = 0; block < ((height - 2) * width) / 32; ++block) {
+		int b_it, var_7 = 0;
+		int cur_byte;
+
+		refill(&bitfill);
+
+		cur_byte = (bit_bucket >> (bitfill & 7)) & 0xff;
+
+		if ((cur_byte & 0x80) == 0) {
+			var_7 = 0;
+			bitfill--;
+		} else if ((cur_byte & 0xC0) == 0x80) {
+			var_7 = 1;
+			bitfill -= 2;
+		} else if ((cur_byte & 0xc0) == 0xc0) {
+			var_7 = 2;
+			bitfill -= 2;
+		}
+
+		for (b_it = 0; b_it < 32; b_it++) {
+			int index;
+			int pixel_L, pixel_UR, pixel_UL;
+			int multiplier;
+			int dL, dC, dR;
+			int gkw;	/* God knows what */
+
+			refill(&bitfill);
+			cur_byte = bit_bucket >> (bitfill & 7) & 0xff;
+
+			pixel_L = output_ptr[-2];
+			pixel_UR = output_ptr[off_up_right];
+			pixel_UL = output_ptr[off_up_left];
+
+			dL = diff_encoding[0x100 + pixel_UL - pixel_L];
+			dC = diff_encoding[0x100 + pixel_U - pixel_UL];
+			dR = diff_encoding[0x100 + pixel_UR - pixel_U];
+
+			if (pixel_x < 2) {
+				pixel_L = pixel_UL = pixel_U =
+				    output_ptr[-xwidth * 2];
+				pixel_UR = output_ptr[off_up_right];
+				dL = dC = 0;
+				dR = diff_encoding[0x100 + pixel_UR -
+						   pixel_U];
+			} else if (pixel_x > width - 3)
+				dR = 0;
+
+			multiplier = 4;
+			index = dR + dC * 8 + dL * 64;
+
+			if (pixel_L + pixel_U * 2 <= 144
+			    && (pixel_y & 1) == 0
+			    && (b_it & 3) == 0 && (dR < 5) && (dC < 5)
+			    && (dL < 5)) {
+				multiplier = 1;
+			} else if (pixel_L <= 48
+				   && dL <= 4 && dC <= 4 && dL >= 1
+				   && dC >= 1) {
+				multiplier = 2;
+			} else if (var_7 == 1) {
+				multiplier = 2;
+			} else if (dC + dL >= 11 || var_7 == 2) {
+				multiplier = 8;
+			}
+
+			if (i_hits[index] < 7) {
+				bitfill -= nbits_A[cur_byte];
+				gkw = tab_A[cur_byte];
+				if (gkw == 0xfe)
+					gkw = fun_A(&bitfill);
+			} else if (i_hits[index] >= accum[index]) {
+				bitfill -= nbits_B[cur_byte];
+				gkw = tab_B[cur_byte];
+				if (cur_byte == 0)
+					gkw = fun_B(&bitfill);
+			} else if (i_hits[index] * 2 >= accum[index]) {
+				bitfill -= nbits_C[cur_byte];
+				gkw = tab_C[cur_byte];
+				if (cur_byte < 2)
+					gkw = fun_C(&bitfill, gkw);
+			} else if (i_hits[index] * 4 >= accum[index]) {
+				bitfill -= nbits_D[cur_byte];
+				gkw = tab_D[cur_byte];
+				if (cur_byte < 4)
+					gkw = fun_D(&bitfill, gkw);
+			} else if (i_hits[index] * 8 >= accum[index]) {
+				gkw = fun_E(cur_byte, &bitfill);
+			} else {
+				gkw = fun_F(cur_byte, &bitfill);
+			}
+
+			if (gkw == 0xff)
+				return -3;
+
+			{
+				int tmp1, tmp2;
+
+				tmp1 =
+				    (pixel_U + pixel_L) * 3 - pixel_UL * 2;
+				tmp1 += (tmp1 < 0) ? 3 : 0;
+				tmp2 = a_curve[19 + gkw] * multiplier;
+				tmp2 += (tmp2 < 0) ? 1 : 0;
+
+				*(output_ptr++) =
+				    clamp0_255[0x100 + (tmp1 >> 2) -
+					       (tmp2 >> 1)];
+			}
+			pixel_U = saved_pixel_UR;
+			saved_pixel_UR = pixel_UR;
+
+			if (++pixel_x == width) {
+				output_ptr += 6;
+				pixel_x = 0;
+				pixel_y++;
+			}
+
+			accum[index] += abs_clamp15[19 + gkw];
+
+			if (i_hits[index]++ == 15) {
+				i_hits[index] = 8;
+				accum[index] /= 2;
+			}
+		}
+	}
+	return 0;
+}
+
+/* FIXME, change internal_spca561_decode not to need the extra border
+   around its dest buffer */
+void v4lconvert_decode_spca561(const unsigned char *inbuf,
+  unsigned char *outbuf, int width, int height)
+{
+	int i;
+	static unsigned char tmpbuf[650 * 490];
+	if (internal_spca561_decode(width, height, inbuf, tmpbuf) != 0)
+		return;
+	for (i = 0; i < height; i++)
+		memcpy(outbuf + i * width,
+		       tmpbuf + (i + 2) * (width + 6) + 3, width);
+}
+
+/*************** License Change Permission Notice ***************
+
+Return-Path: <qq@kuku.eu.org>
+Received: from koko.hhs.nl ([145.52.2.16] verified)
+  by hhs.nl (CommuniGate Pro SMTP 4.3.6)
+  with ESMTP id 88574071 for j.w.r.degoede@hhs.nl; Mon, 16 Jun 2008 16:36:24 +0200
+Received: from exim (helo=koko)
+	by koko.hhs.nl with local-smtp (Exim 4.62)
+	(envelope-from <qq@kuku.eu.org>)
+	id 1K8Fom-0002iJ-3K
+	for j.w.r.degoede@hhs.nl; Mon, 16 Jun 2008 16:36:24 +0200
+Received: from [192.87.102.74] (port=41377 helo=filter6-ams.mf.surf.net)
+	by koko.hhs.nl with esmtp (Exim 4.62)
+	(envelope-from <qq@kuku.eu.org>)
+	id 1K8Fol-0002iC-Qo
+	for j.w.r.degoede@hhs.nl; Mon, 16 Jun 2008 16:36:23 +0200
+Received: from kuku.eu.org (pa90.wielkopole.sdi.tpnet.pl [217.99.123.90])
+	by filter6-ams.mf.surf.net (8.13.8/8.13.8/Debian-3) with ESMTP id m5GEa55r001787
+	for <j.w.r.degoede@hhs.nl>; Mon, 16 Jun 2008 16:36:06 +0200
+Received: (qmail 2243 invoked by uid 500); 16 Jun 2008 14:29:37 -0000
+Date: Mon, 16 Jun 2008 16:29:37 +0200 (CEST)
+From: Andrzej Szombierski <qq@kuku.eu.org>
+To: Hans de Goede <j.w.r.degoede@hhs.nl>
+Subject: Re: spca561 decoder license question
+In-Reply-To: <485673B6.4050003@hhs.nl>
+Message-ID: <Pine.LNX.4.44L.0806161614560.7665-100000@kuku.eu.org>
+References: <485673B6.4050003@hhs.nl>
+MIME-Version: 1.0
+Content-Type: TEXT/PLAIN; charset=iso-8859-2
+Content-Transfer-Encoding: QUOTED-PRINTABLE
+X-Canit-CHI2: 0.00
+X-Bayes-Prob: 0.0001 (Score 0, tokens from: @@RPTN)
+X-Spam-Score: 2.00 (**) [Tag at 6.00] RBL(uceprotect-blacklist.surfnet.nl,2.0)
+X-CanItPRO-Stream: hhs:j.w.r.degoede@hhs.nl (inherits from hhs:default,base:default)
+X-Canit-Stats-ID: 85673281 - 37e52c8b07bc
+X-Scanned-By: CanIt (www . roaringpenguin . com) on 192.87.102.74
+X-Anti-Virus: Kaspersky Anti-Virus for MailServers 5.5.2/RELEASE, bases: 16062008 #776409, status: clean
+
+On Mon, 16 Jun 2008, Hans de Goede wrote:
+
+> Hi,
+>=20
+> I don't know if you're still subscribed to the spca devel mailing list, s=
+o let=20
+> me start with a short intro.
+>
+> I'm a Linux enthusiast / developer currently helping Jean-Fran=E7ois Moin=
+e with=20
+> porting gspca to video4linux2 and cleaning up the code to get it ready fo=
+r=20
+> mainline kernel inclusion.
+>=20
+> As part of this process the decompression code for all supported cams mus=
+t be=20
+> moved to userspace, as doing in kernel decompression is considered unwant=
+ed by=20
+> the mainline people (I agree) as it should be done in userspace.
+>
+
+Sounds reasonable.
+=20
+> As such I'm working on a library which does decompression of custom cam f=
+ormats=20
+> in userspace.
+>
+
+Nice. I hope that the library won't be limited to spca-supported webcams,=
+=20
+and as an application developer I would be able to just request RGB data=20
+from any /dev/video*, right?
+
+> I do not want to license this library as GPL (as the current spca code is=
+), as=20
+> it should be usable by as much software as possible. Instead I want to li=
+cense=20
+> it under the LGPL version 2.1 or later.
+
+Also sounds reasonable.
+
+>=20
+> So my question us my I have your permission to relicense your spca561=20
+> decompression code under the LGPL?
+>=20
+
+Yes, of course.=20
+
+> Thanks & Regards,
+>=20
+> Hans
+>=20
+>
+
+--=20
+:: Andrzej Szombierski :: qq@kuku.eu.org :: http://kuku.eu.org ::
+:: anszom@bezkitu.com  :: radio bez kitu :: http://bezkitu.com ::
+
+*/
diff -r cb6162341029 -r 006f05659861 v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg-internal.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg-internal.h	Mon Jun 30 22:23:16 2008 +0200
@@ -0,0 +1,121 @@
+/*
+ * Small jpeg decoder library (Internal header)
+ *
+ * Copyright (c) 2006, Luc Saillard <luc@saillard.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *  this list of conditions and the following disclaimer in the documentation
+ *  and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the author nor the names of its contributors may be
+ *  used to endorse or promote products derived from this software without
+ *  specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#ifndef __TINYJPEG_INTERNAL_H_
+#define __TINYJPEG_INTERNAL_H_
+
+#include <setjmp.h>
+
+#define SANITY_CHECK 1
+
+struct jdec_private;
+
+#define HUFFMAN_HASH_NBITS 9
+#define HUFFMAN_HASH_SIZE  (1UL<<HUFFMAN_HASH_NBITS)
+#define HUFFMAN_HASH_MASK  (HUFFMAN_HASH_SIZE-1)
+
+#define HUFFMAN_TABLES	   4
+#define COMPONENTS	   3
+#define JPEG_MAX_WIDTH	   2048
+#define JPEG_MAX_HEIGHT	   2048
+
+struct huffman_table
+{
+  /* Fast look up table, using HUFFMAN_HASH_NBITS bits we can have directly the symbol,
+   * if the symbol is <0, then we need to look into the tree table */
+  short int lookup[HUFFMAN_HASH_SIZE];
+  /* code size: give the number of bits of a symbol is encoded */
+  unsigned char code_size[HUFFMAN_HASH_SIZE];
+  /* some place to store value that is not encoded in the lookup table
+   * IMPROVEME: Calculate if 256 value is enough to store all values
+   */
+  uint16_t slowtable[16-HUFFMAN_HASH_NBITS][256];
+};
+
+struct component
+{
+  unsigned int Hfactor;
+  unsigned int Vfactor;
+  float *Q_table;		/* Pointer to the quantisation table to use */
+  struct huffman_table *AC_table;
+  struct huffman_table *DC_table;
+  short int previous_DC;	/* Previous DC coefficient */
+  short int DCT[64];		/* DCT coef */
+#if SANITY_CHECK
+  unsigned int cid;
+#endif
+};
+
+
+typedef void (*decode_MCU_fct) (struct jdec_private *priv);
+typedef void (*convert_colorspace_fct) (struct jdec_private *priv);
+
+struct jdec_private
+{
+  /* Public variables */
+  uint8_t *components[COMPONENTS];
+  unsigned int width, height;	/* Size of the image */
+  unsigned int flags;
+
+  /* Private variables */
+  const unsigned char *stream_begin, *stream_end;
+  unsigned int stream_length;
+
+  const unsigned char *stream;	/* Pointer to the current stream */
+  unsigned int reservoir, nbits_in_reservoir;
+
+  struct component component_infos[COMPONENTS];
+  float Q_tables[COMPONENTS][64];		/* quantization tables */
+  struct huffman_table HTDC[HUFFMAN_TABLES];	/* DC huffman tables   */
+  struct huffman_table HTAC[HUFFMAN_TABLES];	/* AC huffman tables   */
+  int default_huffman_table_initialized;
+  int restart_interval;
+  int restarts_to_go;				/* MCUs left in this restart interval */
+  int last_rst_marker_seen;			/* Rst marker is incremented each time */
+
+  /* Temp space used after the IDCT to store each components */
+  uint8_t Y[64*4], Cr[64], Cb[64];
+
+  jmp_buf jump_state;
+  /* Internal Pointer use for colorspace conversion, do not modify it !!! */
+  uint8_t *plane[COMPONENTS];
+
+  char error_string[256];
+};
+
+#define IDCT tinyjpeg_idct_float
+void tinyjpeg_idct_float (struct component *compptr, uint8_t *output_buf, int stride);
+
+#endif
+
diff -r cb6162341029 -r 006f05659861 v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg.c	Mon Jun 30 22:23:16 2008 +0200
@@ -0,0 +1,2164 @@
+/*
+ * Small jpeg decoder library
+ *
+ * Copyright (c) 2006, Luc Saillard <luc@saillard.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *  this list of conditions and the following disclaimer in the documentation
+ *  and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the author nor the names of its contributors may be
+ *  used to endorse or promote products derived from this software without
+ *  specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "tinyjpeg.h"
+#include "tinyjpeg-internal.h"
+
+enum std_markers {
+   DQT  = 0xDB, /* Define Quantization Table */
+   SOF  = 0xC0, /* Start of Frame (size information) */
+   DHT  = 0xC4, /* Huffman Table */
+   SOI  = 0xD8, /* Start of Image */
+   SOS  = 0xDA, /* Start of Scan */
+   RST  = 0xD0, /* Reset Marker d0 -> .. */
+   RST7 = 0xD7, /* Reset Marker .. -> d7 */
+   EOI  = 0xD9, /* End of Image */
+   DRI  = 0xDD, /* Define Restart Interval */
+   APP0 = 0xE0,
+};
+
+#define cY	0
+#define cCb	1
+#define cCr	2
+
+#define BLACK_Y 0
+#define BLACK_U 127
+#define BLACK_V 127
+
+#if DEBUG
+#if LOG2FILE
+
+#define trace(fmt, args...) do { \
+   FILE *f = fopen("/tmp/jpeg.log", "a"); \
+   fprintf(f, fmt, ## args); \
+   fflush(f); \
+   fclose(f); \
+} while(0)
+
+#else
+
+#define trace(fmt, args...) do { \
+   fprintf(stderr, fmt, ## args); \
+   fflush(stderr); \
+} while(0)
+#endif
+
+#else
+#define trace(fmt, args...) do { } while (0)
+#endif
+
+#define error(fmt, args...) do { \
+   snprintf(priv->error_string, sizeof(priv->error_string), fmt, ## args); \
+   return -1; \
+} while(0)
+
+
+#if 0
+static char *print_bits(unsigned int value, char *bitstr)
+{
+  int i, j;
+  i=31;
+  while (i>0)
+   {
+     if (value & (1UL<<i))
+       break;
+     i--;
+   }
+  j=0;
+  while (i>=0)
+   {
+     bitstr[j++] = (value & (1UL<<i))?'1':'0';
+     i--;
+   }
+  bitstr[j] = 0;
+  return bitstr;
+}
+
+static void print_next_16bytes(int offset, const unsigned char *stream)
+{
+  trace("%4.4x: %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
+	offset,
+	stream[0], stream[1], stream[2], stream[3],
+	stream[4], stream[5], stream[6], stream[7],
+	stream[8], stream[9], stream[10], stream[11],
+	stream[12], stream[13], stream[14], stream[15]);
+}
+
+#endif
+
+
+static const unsigned char zigzag[64] =
+{
+   0,  1,  5,  6, 14, 15, 27, 28,
+   2,  4,  7, 13, 16, 26, 29, 42,
+   3,  8, 12, 17, 25, 30, 41, 43,
+   9, 11, 18, 24, 31, 40, 44, 53,
+  10, 19, 23, 32, 39, 45, 52, 54,
+  20, 22, 33, 38, 46, 51, 55, 60,
+  21, 34, 37, 47, 50, 56, 59, 61,
+  35, 36, 48, 49, 57, 58, 62, 63
+};
+
+/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */
+/* IMPORTANT: these are only valid for 8-bit data precision! */
+static const unsigned char bits_dc_luminance[17] =
+{
+  0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
+};
+static const unsigned char val_dc_luminance[] =
+{
+  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+};
+
+static const unsigned char bits_dc_chrominance[17] =
+{
+  0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
+};
+static const unsigned char val_dc_chrominance[] =
+{
+  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+};
+
+static const unsigned char bits_ac_luminance[17] =
+{
+  0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
+};
+static const unsigned char val_ac_luminance[] =
+{
+  0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+  0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+  0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+  0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+  0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+  0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+  0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+  0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+  0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+  0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+  0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+  0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+  0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+  0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+  0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+  0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+  0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+  0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+  0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+  0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+  0xf9, 0xfa
+};
+
+static const unsigned char bits_ac_chrominance[17] =
+{
+  0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
+};
+
+static const unsigned char val_ac_chrominance[] =
+{
+  0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+  0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+  0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+  0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+  0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+  0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+  0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+  0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+  0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+  0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+  0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+  0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+  0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+  0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+  0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+  0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+  0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+  0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+  0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+  0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+  0xf9, 0xfa
+};
+
+
+/*
+ * 4 functions to manage the stream
+ *
+ *  fill_nbits: put at least nbits in the reservoir of bits.
+ *              But convert any 0xff,0x00 into 0xff
+ *  get_nbits: read nbits from the stream, and put it in result,
+ *             bits is removed from the stream and the reservoir is filled
+ *             automaticaly. The result is signed according to the number of
+ *             bits.
+ *  look_nbits: read nbits from the stream without marking as read.
+ *  skip_nbits: read nbits from the stream but do not return the result.
+ *
+ * stream: current pointer in the jpeg data (read bytes per bytes)
+ * nbits_in_reservoir: number of bits filled into the reservoir
+ * reservoir: register that contains bits information. Only nbits_in_reservoir
+ *            is valid.
+ *                          nbits_in_reservoir
+ *                        <--    17 bits    -->
+ *            Ex: 0000 0000 1010 0000 1111 0000   <== reservoir
+ *                        ^
+ *                        bit 1
+ *            To get two bits from this example
+ *                 result = (reservoir >> 15) & 3
+ *
+ */
+#define fill_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \
+   while (nbits_in_reservoir<nbits_wanted) \
+    { \
+      unsigned char c; \
+      if (stream >= priv->stream_end) \
+	longjmp(priv->jump_state, -EIO); \
+      c = *stream++; \
+      reservoir <<= 8; \
+      if (c == 0xff && *stream == 0x00) \
+	stream++; \
+      reservoir |= c; \
+      nbits_in_reservoir+=8; \
+    } \
+}  while(0);
+
+/* Signed version !!!! */
+#define get_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted,result) do { \
+   fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \
+   result = ((reservoir)>>(nbits_in_reservoir-(nbits_wanted))); \
+   nbits_in_reservoir -= (nbits_wanted);  \
+   reservoir &= ((1U<<nbits_in_reservoir)-1); \
+   if ((unsigned int)result < (1UL<<((nbits_wanted)-1))) \
+       result += (0xFFFFFFFFUL<<(nbits_wanted))+1; \
+}  while(0);
+
+#define look_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted,result) do { \
+   fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \
+   result = ((reservoir)>>(nbits_in_reservoir-(nbits_wanted))); \
+}  while(0);
+
+/* To speed up the decoding, we assume that the reservoir have enough bit
+ * slow version:
+ * #define skip_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \
+ *   fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \
+ *   nbits_in_reservoir -= (nbits_wanted); \
+ *   reservoir &= ((1U<<nbits_in_reservoir)-1); \
+ * }  while(0);
+ */
+#define skip_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \
+   nbits_in_reservoir -= (nbits_wanted); \
+   reservoir &= ((1U<<nbits_in_reservoir)-1); \
+}  while(0);
+
+
+#define be16_to_cpu(x) (((x)[0]<<8)|(x)[1])
+
+static void resync(struct jdec_private *priv);
+
+/**
+ * Get the next (valid) huffman code in the stream.
+ *
+ * To speedup the procedure, we look HUFFMAN_HASH_NBITS bits and the code is
+ * lower than HUFFMAN_HASH_NBITS we have automaticaly the length of the code
+ * and the value by using two lookup table.
+ * Else if the value is not found, just search (linear) into an array for each
+ * bits is the code is present.
+ *
+ * If the code is not present for any reason, -1 is return.
+ */
+static int get_next_huffman_code(struct jdec_private *priv, struct huffman_table *huffman_table)
+{
+  int value, hcode;
+  unsigned int extra_nbits, nbits;
+  uint16_t *slowtable;
+
+  look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, HUFFMAN_HASH_NBITS, hcode);
+  value = huffman_table->lookup[hcode];
+  if (value >= 0)
+  {
+     unsigned int code_size = huffman_table->code_size[value];
+     skip_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, code_size);
+     return value;
+  }
+
+  /* Decode more bits each time ... */
+  for (extra_nbits=0; extra_nbits<16-HUFFMAN_HASH_NBITS; extra_nbits++)
+   {
+     nbits = HUFFMAN_HASH_NBITS + 1 + extra_nbits;
+
+     look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, nbits, hcode);
+     slowtable = huffman_table->slowtable[extra_nbits];
+     /* Search if the code is in this array */
+     while (slowtable[0]) {
+	if (slowtable[0] == hcode) {
+	   skip_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, nbits);
+	   return slowtable[1];
+	}
+	slowtable+=2;
+     }
+   }
+  return 0;
+}
+
+
+
+
+/**
+ *
+ * Decode a single block that contains the DCT coefficients.
+ * The table coefficients is already dezigzaged at the end of the operation.
+ *
+ */
+static void process_Huffman_data_unit(struct jdec_private *priv, int component)
+{
+  unsigned char j;
+  unsigned int huff_code;
+  unsigned char size_val, count_0;
+
+  struct component *c = &priv->component_infos[component];
+  short int DCT[64];
+
+  /* Initialize the DCT coef table */
+  memset(DCT, 0, sizeof(DCT));
+
+  /* DC coefficient decoding */
+  huff_code = get_next_huffman_code(priv, c->DC_table);
+  if (huff_code) {
+     get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, huff_code, DCT[0]);
+     DCT[0] += c->previous_DC;
+     c->previous_DC = DCT[0];
+  } else {
+     DCT[0] = c->previous_DC;
+  }
+
+
+  /* AC coefficient decoding */
+  j = 1;
+  while (j<64)
+   {
+     huff_code = get_next_huffman_code(priv, c->AC_table);
+
+     size_val = huff_code & 0xF;
+     count_0 = huff_code >> 4;
+
+     if (size_val == 0)
+      { /* RLE */
+	if (count_0 == 0)
+	  break;	/* EOB found, go out */
+	else if (count_0 == 0xF)
+	  j += 16;	/* skip 16 zeros */
+      }
+     else
+      {
+	j += count_0;	/* skip count_0 zeroes */
+	get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, size_val, DCT[j]);
+	j++;
+      }
+   }
+
+  for (j = 0; j < 64; j++)
+    c->DCT[j] = DCT[zigzag[j]];
+}
+
+/*
+ * Takes two array of bits, and build the huffman table for size, and code
+ *
+ * lookup will return the symbol if the code is less or equal than HUFFMAN_HASH_NBITS.
+ * code_size will be used to known how many bits this symbol is encoded.
+ * slowtable will be used when the first lookup didn't give the result.
+ */
+static void build_huffman_table(const unsigned char *bits, const unsigned char *vals, struct huffman_table *table)
+{
+  unsigned int i, j, code, code_size, val, nbits;
+  unsigned char huffsize[257], *hz;
+  unsigned int huffcode[257], *hc;
+  int next_free_entry;
+
+  /*
+   * Build a temp array
+   *   huffsize[X] => numbers of bits to write vals[X]
+   */
+  hz = huffsize;
+  for (i=1; i<=16; i++)
+   {
+     for (j=1; j<=bits[i]; j++)
+       *hz++ = i;
+   }
+  *hz = 0;
+
+  memset(table->lookup, 0xff, sizeof(table->lookup));
+  for (i=0; i<(16-HUFFMAN_HASH_NBITS); i++)
+    table->slowtable[i][0] = 0;
+
+  /* Build a temp array
+   *   huffcode[X] => code used to write vals[X]
+   */
+  code = 0;
+  hc = huffcode;
+  hz = huffsize;
+  nbits = *hz;
+  while (*hz)
+   {
+     while (*hz == nbits) {
+	*hc++ = code++;
+	hz++;
+     }
+     code <<= 1;
+     nbits++;
+   }
+
+  /*
+   * Build the lookup table, and the slowtable if needed.
+   */
+  next_free_entry = -1;
+  for (i=0; huffsize[i]; i++)
+   {
+     val = vals[i];
+     code = huffcode[i];
+     code_size = huffsize[i];
+
+     trace("val=%2.2x code=%8.8x codesize=%2.2d\n", i, code, code_size);
+
+     table->code_size[val] = code_size;
+     if (code_size <= HUFFMAN_HASH_NBITS)
+      {
+	/*
+	 * Good: val can be put in the lookup table, so fill all value of this
+	 * column with value val
+	 */
+	int repeat = 1UL<<(HUFFMAN_HASH_NBITS - code_size);
+	code <<= HUFFMAN_HASH_NBITS - code_size;
+	while ( repeat-- )
+	  table->lookup[code++] = val;
+
+      }
+     else
+      {
+	/* Perhaps sorting the array will be an optimization */
+	uint16_t *slowtable = table->slowtable[code_size-HUFFMAN_HASH_NBITS-1];
+	while(slowtable[0])
+	  slowtable+=2;
+	slowtable[0] = code;
+	slowtable[1] = val;
+	slowtable[2] = 0;
+	/* TODO: NEED TO CHECK FOR AN OVERFLOW OF THE TABLE */
+      }
+
+   }
+
+}
+
+static void build_default_huffman_tables(struct jdec_private *priv)
+{
+  if (   (priv->flags & TINYJPEG_FLAGS_MJPEG_TABLE)
+      && priv->default_huffman_table_initialized)
+    return;
+
+  build_huffman_table(bits_dc_luminance, val_dc_luminance, &priv->HTDC[0]);
+  build_huffman_table(bits_ac_luminance, val_ac_luminance, &priv->HTAC[0]);
+
+  build_huffman_table(bits_dc_chrominance, val_dc_chrominance, &priv->HTDC[1]);
+  build_huffman_table(bits_ac_chrominance, val_ac_chrominance, &priv->HTAC[1]);
+
+  priv->default_huffman_table_initialized = 1;
+}
+
+
+
+/*******************************************************************************
+ *
+ * Colorspace conversion routine
+ *
+ *
+ * Note:
+ * YCbCr is defined per CCIR 601-1, except that Cb and Cr are
+ * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
+ * The conversion equations to be implemented are therefore
+ *      R = Y                + 1.40200 * Cr
+ *      G = Y - 0.34414 * Cb - 0.71414 * Cr
+ *      B = Y + 1.77200 * Cb
+ *
+ ******************************************************************************/
+
+static unsigned char clamp(int i)
+{
+  if (i<0)
+    return 0;
+  else if (i>255)
+    return 255;
+  else
+    return i;
+}
+
+
+/**
+ *  YCrCb -> YUV420P (1x1)
+ *  .---.
+ *  | 1 |
+ *  `---'
+ */
+static void YCrCB_to_YUV420P_1x1(struct jdec_private *priv)
+{
+  const unsigned char *s, *y;
+  unsigned char *p;
+  int i,j;
+
+  p = priv->plane[0];
+  y = priv->Y;
+  for (i=0; i<8; i++)
+   {
+     memcpy(p, y, 8);
+     p+=priv->width;
+     y+=8;
+   }
+
+  p = priv->plane[1];
+  s = priv->Cb;
+  for (i=0; i<8; i+=2)
+   {
+     for (j=0; j<8; j+=2, s+=2)
+       *p++ = *s;
+     s += 8; /* Skip one line */
+     p += priv->width/2 - 4;
+   }
+
+  p = priv->plane[2];
+  s = priv->Cr;
+  for (i=0; i<8; i+=2)
+   {
+     for (j=0; j<8; j+=2, s+=2)
+       *p++ = *s;
+     s += 8; /* Skip one line */
+     p += priv->width/2 - 4;
+   }
+}
+
+/**
+ *  YCrCb -> YUV420P (2x1)
+ *  .-------.
+ *  | 1 | 2 |
+ *  `-------'
+ */
+static void YCrCB_to_YUV420P_2x1(struct jdec_private *priv)
+{
+  unsigned char *p;
+  const unsigned char *s, *y1;
+  unsigned int i;
+
+  p = priv->plane[0];
+  y1 = priv->Y;
+  for (i=0; i<8; i++)
+   {
+     memcpy(p, y1, 16);
+     p += priv->width;
+     y1 += 16;
+   }
+
+  p = priv->plane[1];
+  s = priv->Cb;
+  for (i=0; i<8; i+=2)
+   {
+     memcpy(p, s, 8);
+     s += 16; /* Skip one line */
+     p += priv->width/2;
+   }
+
+  p = priv->plane[2];
+  s = priv->Cr;
+  for (i=0; i<8; i+=2)
+   {
+     memcpy(p, s, 8);
+     s += 16; /* Skip one line */
+     p += priv->width/2;
+   }
+}
+
+
+/**
+ *  YCrCb -> YUV420P (1x2)
+ *  .---.
+ *  | 1 |
+ *  |---|
+ *  | 2 |
+ *  `---'
+ */
+static void YCrCB_to_YUV420P_1x2(struct jdec_private *priv)
+{
+  const unsigned char *s, *y;
+  unsigned char *p;
+  int i,j;
+
+  p = priv->plane[0];
+  y = priv->Y;
+  for (i=0; i<16; i++)
+   {
+     memcpy(p, y, 8);
+     p+=priv->width;
+     y+=8;
+   }
+
+  p = priv->plane[1];
+  s = priv->Cb;
+  for (i=0; i<8; i++)
+   {
+     for (j=0; j<8; j+=2, s+=2)
+       *p++ = *s;
+     p += priv->width/2 - 4;
+   }
+
+  p = priv->plane[2];
+  s = priv->Cr;
+  for (i=0; i<8; i++)
+   {
+     for (j=0; j<8; j+=2, s+=2)
+       *p++ = *s;
+     p += priv->width/2 - 4;
+   }
+}
+
+/**
+ *  YCrCb -> YUV420P (2x2)
+ *  .-------.
+ *  | 1 | 2 |
+ *  |---+---|
+ *  | 3 | 4 |
+ *  `-------'
+ */
+static void YCrCB_to_YUV420P_2x2(struct jdec_private *priv)
+{
+  unsigned char *p;
+  const unsigned char *s, *y1;
+  unsigned int i;
+
+  p = priv->plane[0];
+  y1 = priv->Y;
+  for (i=0; i<16; i++)
+   {
+     memcpy(p, y1, 16);
+     p += priv->width;
+     y1 += 16;
+   }
+
+  p = priv->plane[1];
+  s = priv->Cb;
+  for (i=0; i<8; i++)
+   {
+     memcpy(p, s, 8);
+     s += 8;
+     p += priv->width/2;
+   }
+
+  p = priv->plane[2];
+  s = priv->Cr;
+  for (i=0; i<8; i++)
+   {
+     memcpy(p, s, 8);
+     s += 8;
+     p += priv->width/2;
+   }
+}
+
+/**
+ *  YCrCb -> RGB24 (1x1)
+ *  .---.
+ *  | 1 |
+ *  `---'
+ */
+static void YCrCB_to_RGB24_1x1(struct jdec_private *priv)
+{
+  const unsigned char *Y, *Cb, *Cr;
+  unsigned char *p;
+  int i,j;
+  int offset_to_next_row;
+
+#define SCALEBITS       10
+#define ONE_HALF        (1UL << (SCALEBITS-1))
+#define FIX(x)          ((int)((x) * (1UL<<SCALEBITS) + 0.5))
+
+  p = priv->plane[0];
+  Y = priv->Y;
+  Cb = priv->Cb;
+  Cr = priv->Cr;
+  offset_to_next_row = priv->width*3 - 8*3;
+  for (i=0; i<8; i++) {
+
+    for (j=0; j<8; j++) {
+
+       int y, cb, cr;
+       int add_r, add_g, add_b;
+       int r, g , b;
+
+       y  = (*Y++) << SCALEBITS;
+       cb = *Cb++ - 128;
+       cr = *Cr++ - 128;
+       add_r = FIX(1.40200) * cr + ONE_HALF;
+       add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
+       add_b = FIX(1.77200) * cb + ONE_HALF;
+
+       r = (y + add_r) >> SCALEBITS;
+       *p++ = clamp(r);
+       g = (y + add_g) >> SCALEBITS;
+       *p++ = clamp(g);
+       b = (y + add_b) >> SCALEBITS;
+       *p++ = clamp(b);
+
+    }
+
+    p += offset_to_next_row;
+  }
+
+#undef SCALEBITS
+#undef ONE_HALF
+#undef FIX
+
+}
+
+/**
+ *  YCrCb -> BGR24 (1x1)
+ *  .---.
+ *  | 1 |
+ *  `---'
+ */
+static void YCrCB_to_BGR24_1x1(struct jdec_private *priv)
+{
+  const unsigned char *Y, *Cb, *Cr;
+  unsigned char *p;
+  int i,j;
+  int offset_to_next_row;
+
+#define SCALEBITS       10
+#define ONE_HALF        (1UL << (SCALEBITS-1))
+#define FIX(x)          ((int)((x) * (1UL<<SCALEBITS) + 0.5))
+
+  p = priv->plane[0];
+  Y = priv->Y;
+  Cb = priv->Cb;
+  Cr = priv->Cr;
+  offset_to_next_row = priv->width*3 - 8*3;
+  for (i=0; i<8; i++) {
+
+    for (j=0; j<8; j++) {
+
+       int y, cb, cr;
+       int add_r, add_g, add_b;
+       int r, g , b;
+
+       y  = (*Y++) << SCALEBITS;
+       cb = *Cb++ - 128;
+       cr = *Cr++ - 128;
+       add_r = FIX(1.40200) * cr + ONE_HALF;
+       add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
+       add_b = FIX(1.77200) * cb + ONE_HALF;
+
+       b = (y + add_b) >> SCALEBITS;
+       *p++ = clamp(b);
+       g = (y + add_g) >> SCALEBITS;
+       *p++ = clamp(g);
+       r = (y + add_r) >> SCALEBITS;
+       *p++ = clamp(r);
+
+    }
+
+    p += offset_to_next_row;
+  }
+
+#undef SCALEBITS
+#undef ONE_HALF
+#undef FIX
+
+}
+
+
+/**
+ *  YCrCb -> RGB24 (2x1)
+ *  .-------.
+ *  | 1 | 2 |
+ *  `-------'
+ */
+static void YCrCB_to_RGB24_2x1(struct jdec_private *priv)
+{
+  const unsigned char *Y, *Cb, *Cr;
+  unsigned char *p;
+  int i,j;
+  int offset_to_next_row;
+
+#define SCALEBITS       10
+#define ONE_HALF        (1UL << (SCALEBITS-1))
+#define FIX(x)          ((int)((x) * (1UL<<SCALEBITS) + 0.5))
+
+  p = priv->plane[0];
+  Y = priv->Y;
+  Cb = priv->Cb;
+  Cr = priv->Cr;
+  offset_to_next_row = priv->width*3 - 16*3;
+  for (i=0; i<8; i++) {
+
+    for (j=0; j<8; j++) {
+
+       int y, cb, cr;
+       int add_r, add_g, add_b;
+       int r, g , b;
+
+       y  = (*Y++) << SCALEBITS;
+       cb = *Cb++ - 128;
+       cr = *Cr++ - 128;
+       add_r = FIX(1.40200) * cr + ONE_HALF;
+       add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
+       add_b = FIX(1.77200) * cb + ONE_HALF;
+
+       r = (y + add_r) >> SCALEBITS;
+       *p++ = clamp(r);
+       g = (y + add_g) >> SCALEBITS;
+       *p++ = clamp(g);
+       b = (y + add_b) >> SCALEBITS;
+       *p++ = clamp(b);
+
+       y  = (*Y++) << SCALEBITS;
+       r = (y + add_r) >> SCALEBITS;
+       *p++ = clamp(r);
+       g = (y + add_g) >> SCALEBITS;
+       *p++ = clamp(g);
+       b = (y + add_b) >> SCALEBITS;
+       *p++ = clamp(b);
+
+    }
+
+    p += offset_to_next_row;
+  }
+
+#undef SCALEBITS
+#undef ONE_HALF
+#undef FIX
+
+}
+
+/*
+ *  YCrCb -> BGR24 (2x1)
+ *  .-------.
+ *  | 1 | 2 |
+ *  `-------'
+ */
+static void YCrCB_to_BGR24_2x1(struct jdec_private *priv)
+{
+  const unsigned char *Y, *Cb, *Cr;
+  unsigned char *p;
+  int i,j;
+  int offset_to_next_row;
+
+#define SCALEBITS       10
+#define ONE_HALF        (1UL << (SCALEBITS-1))
+#define FIX(x)          ((int)((x) * (1UL<<SCALEBITS) + 0.5))
+
+  p = priv->plane[0];
+  Y = priv->Y;
+  Cb = priv->Cb;
+  Cr = priv->Cr;
+  offset_to_next_row = priv->width*3 - 16*3;
+  for (i=0; i<8; i++) {
+
+    for (j=0; j<8; j++) {
+
+       int y, cb, cr;
+       int add_r, add_g, add_b;
+       int r, g , b;
+
+       cb = *Cb++ - 128;
+       cr = *Cr++ - 128;
+       add_r = FIX(1.40200) * cr + ONE_HALF;
+       add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
+       add_b = FIX(1.77200) * cb + ONE_HALF;
+
+       y  = (*Y++) << SCALEBITS;
+       b = (y + add_b) >> SCALEBITS;
+       *p++ = clamp(b);
+       g = (y + add_g) >> SCALEBITS;
+       *p++ = clamp(g);
+       r = (y + add_r) >> SCALEBITS;
+       *p++ = clamp(r);
+
+       y  = (*Y++) << SCALEBITS;
+       b = (y + add_b) >> SCALEBITS;
+       *p++ = clamp(b);
+       g = (y + add_g) >> SCALEBITS;
+       *p++ = clamp(g);
+       r = (y + add_r) >> SCALEBITS;
+       *p++ = clamp(r);
+
+    }
+
+    p += offset_to_next_row;
+  }
+
+#undef SCALEBITS
+#undef ONE_HALF
+#undef FIX
+
+}
+
+/**
+ *  YCrCb -> RGB24 (1x2)
+ *  .---.
+ *  | 1 |
+ *  |---|
+ *  | 2 |
+ *  `---'
+ */
+static void YCrCB_to_RGB24_1x2(struct jdec_private *priv)
+{
+  const unsigned char *Y, *Cb, *Cr;
+  unsigned char *p, *p2;
+  int i,j;
+  int offset_to_next_row;
+
+#define SCALEBITS       10
+#define ONE_HALF        (1UL << (SCALEBITS-1))
+#define FIX(x)          ((int)((x) * (1UL<<SCALEBITS) + 0.5))
+
+  p = priv->plane[0];
+  p2 = priv->plane[0] + priv->width*3;
+  Y = priv->Y;
+  Cb = priv->Cb;
+  Cr = priv->Cr;
+  offset_to_next_row = 2*priv->width*3 - 8*3;
+  for (i=0; i<8; i++) {
+
+    for (j=0; j<8; j++) {
+
+       int y, cb, cr;
+       int add_r, add_g, add_b;
+       int r, g , b;
+
+       cb = *Cb++ - 128;
+       cr = *Cr++ - 128;
+       add_r = FIX(1.40200) * cr + ONE_HALF;
+       add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
+       add_b = FIX(1.77200) * cb + ONE_HALF;
+
+       y  = (*Y++) << SCALEBITS;
+       r = (y + add_r) >> SCALEBITS;
+       *p++ = clamp(r);
+       g = (y + add_g) >> SCALEBITS;
+       *p++ = clamp(g);
+       b = (y + add_b) >> SCALEBITS;
+       *p++ = clamp(b);
+
+       y  = (Y[8-1]) << SCALEBITS;
+       r = (y + add_r) >> SCALEBITS;
+       *p2++ = clamp(r);
+       g = (y + add_g) >> SCALEBITS;
+       *p2++ = clamp(g);
+       b = (y + add_b) >> SCALEBITS;
+       *p2++ = clamp(b);
+
+    }
+    Y += 8;
+    p += offset_to_next_row;
+    p2 += offset_to_next_row;
+  }
+
+#undef SCALEBITS
+#undef ONE_HALF
+#undef FIX
+
+}
+
+/*
+ *  YCrCb -> BGR24 (1x2)
+ *  .---.
+ *  | 1 |
+ *  |---|
+ *  | 2 |
+ *  `---'
+ */
+static void YCrCB_to_BGR24_1x2(struct jdec_private *priv)
+{
+  const unsigned char *Y, *Cb, *Cr;
+  unsigned char *p, *p2;
+  int i,j;
+  int offset_to_next_row;
+
+#define SCALEBITS       10
+#define ONE_HALF        (1UL << (SCALEBITS-1))
+#define FIX(x)          ((int)((x) * (1UL<<SCALEBITS) + 0.5))
+
+  p = priv->plane[0];
+  p2 = priv->plane[0] + priv->width*3;
+  Y = priv->Y;
+  Cb = priv->Cb;
+  Cr = priv->Cr;
+  offset_to_next_row = 2*priv->width*3 - 8*3;
+  for (i=0; i<8; i++) {
+
+    for (j=0; j<8; j++) {
+
+       int y, cb, cr;
+       int add_r, add_g, add_b;
+       int r, g , b;
+
+       cb = *Cb++ - 128;
+       cr = *Cr++ - 128;
+       add_r = FIX(1.40200) * cr + ONE_HALF;
+       add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
+       add_b = FIX(1.77200) * cb + ONE_HALF;
+
+       y  = (*Y++) << SCALEBITS;
+       b = (y + add_b) >> SCALEBITS;
+       *p++ = clamp(b);
+       g = (y + add_g) >> SCALEBITS;
+       *p++ = clamp(g);
+       r = (y + add_r) >> SCALEBITS;
+       *p++ = clamp(r);
+
+       y  = (Y[8-1]) << SCALEBITS;
+       b = (y + add_b) >> SCALEBITS;
+       *p2++ = clamp(b);
+       g = (y + add_g) >> SCALEBITS;
+       *p2++ = clamp(g);
+       r = (y + add_r) >> SCALEBITS;
+       *p2++ = clamp(r);
+
+    }
+    Y += 8;
+    p += offset_to_next_row;
+    p2 += offset_to_next_row;
+  }
+
+#undef SCALEBITS
+#undef ONE_HALF
+#undef FIX
+
+}
+
+
+/**
+ *  YCrCb -> RGB24 (2x2)
+ *  .-------.
+ *  | 1 | 2 |
+ *  |---+---|
+ *  | 3 | 4 |
+ *  `-------'
+ */
+static void YCrCB_to_RGB24_2x2(struct jdec_private *priv)
+{
+  const unsigned char *Y, *Cb, *Cr;
+  unsigned char *p, *p2;
+  int i,j;
+  int offset_to_next_row;
+
+#define SCALEBITS       10
+#define ONE_HALF        (1UL << (SCALEBITS-1))
+#define FIX(x)          ((int)((x) * (1UL<<SCALEBITS) + 0.5))
+
+  p = priv->plane[0];
+  p2 = priv->plane[0] + priv->width*3;
+  Y = priv->Y;
+  Cb = priv->Cb;
+  Cr = priv->Cr;
+  offset_to_next_row = (priv->width*3*2) - 16*3;
+  for (i=0; i<8; i++) {
+
+    for (j=0; j<8; j++) {
+
+       int y, cb, cr;
+       int add_r, add_g, add_b;
+       int r, g , b;
+
+       cb = *Cb++ - 128;
+       cr = *Cr++ - 128;
+       add_r = FIX(1.40200) * cr + ONE_HALF;
+       add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
+       add_b = FIX(1.77200) * cb + ONE_HALF;
+
+       y  = (*Y++) << SCALEBITS;
+       r = (y + add_r) >> SCALEBITS;
+       *p++ = clamp(r);
+       g = (y + add_g) >> SCALEBITS;
+       *p++ = clamp(g);
+       b = (y + add_b) >> SCALEBITS;
+       *p++ = clamp(b);
+
+       y  = (*Y++) << SCALEBITS;
+       r = (y + add_r) >> SCALEBITS;
+       *p++ = clamp(r);
+       g = (y + add_g) >> SCALEBITS;
+       *p++ = clamp(g);
+       b = (y + add_b) >> SCALEBITS;
+       *p++ = clamp(b);
+
+       y  = (Y[16-2]) << SCALEBITS;
+       r = (y + add_r) >> SCALEBITS;
+       *p2++ = clamp(r);
+       g = (y + add_g) >> SCALEBITS;
+       *p2++ = clamp(g);
+       b = (y + add_b) >> SCALEBITS;
+       *p2++ = clamp(b);
+
+       y  = (Y[16-1]) << SCALEBITS;
+       r = (y + add_r) >> SCALEBITS;
+       *p2++ = clamp(r);
+       g = (y + add_g) >> SCALEBITS;
+       *p2++ = clamp(g);
+       b = (y + add_b) >> SCALEBITS;
+       *p2++ = clamp(b);
+    }
+    Y  += 16;
+    p  += offset_to_next_row;
+    p2 += offset_to_next_row;
+  }
+
+#undef SCALEBITS
+#undef ONE_HALF
+#undef FIX
+
+}
+
+
+/*
+ *  YCrCb -> BGR24 (2x2)
+ *  .-------.
+ *  | 1 | 2 |
+ *  |---+---|
+ *  | 3 | 4 |
+ *  `-------'
+ */
+static void YCrCB_to_BGR24_2x2(struct jdec_private *priv)
+{
+  const unsigned char *Y, *Cb, *Cr;
+  unsigned char *p, *p2;
+  int i,j;
+  int offset_to_next_row;
+
+#define SCALEBITS       10
+#define ONE_HALF        (1UL << (SCALEBITS-1))
+#define FIX(x)          ((int)((x) * (1UL<<SCALEBITS) + 0.5))
+
+  p = priv->plane[0];
+  p2 = priv->plane[0] + priv->width*3;
+  Y = priv->Y;
+  Cb = priv->Cb;
+  Cr = priv->Cr;
+  offset_to_next_row = (priv->width*3*2) - 16*3;
+  for (i=0; i<8; i++) {
+
+    for (j=0; j<8; j++) {
+
+       int y, cb, cr;
+       int add_r, add_g, add_b;
+       int r, g , b;
+
+       cb = *Cb++ - 128;
+       cr = *Cr++ - 128;
+       add_r = FIX(1.40200) * cr + ONE_HALF;
+       add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
+       add_b = FIX(1.77200) * cb + ONE_HALF;
+
+       y  = (*Y++) << SCALEBITS;
+       b = (y + add_b) >> SCALEBITS;
+       *p++ = clamp(b);
+       g = (y + add_g) >> SCALEBITS;
+       *p++ = clamp(g);
+       r = (y + add_r) >> SCALEBITS;
+       *p++ = clamp(r);
+
+       y  = (*Y++) << SCALEBITS;
+       b = (y + add_b) >> SCALEBITS;
+       *p++ = clamp(b);
+       g = (y + add_g) >> SCALEBITS;
+       *p++ = clamp(g);
+       r = (y + add_r) >> SCALEBITS;
+       *p++ = clamp(r);
+
+       y  = (Y[16-2]) << SCALEBITS;
+       b = (y + add_b) >> SCALEBITS;
+       *p2++ = clamp(b);
+       g = (y + add_g) >> SCALEBITS;
+       *p2++ = clamp(g);
+       r = (y + add_r) >> SCALEBITS;
+       *p2++ = clamp(r);
+
+       y  = (Y[16-1]) << SCALEBITS;
+       b = (y + add_b) >> SCALEBITS;
+       *p2++ = clamp(b);
+       g = (y + add_g) >> SCALEBITS;
+       *p2++ = clamp(g);
+       r = (y + add_r) >> SCALEBITS;
+       *p2++ = clamp(r);
+    }
+    Y  += 16;
+    p  += offset_to_next_row;
+    p2 += offset_to_next_row;
+  }
+
+#undef SCALEBITS
+#undef ONE_HALF
+#undef FIX
+
+}
+
+
+
+/**
+ *  YCrCb -> Grey (1x1)
+ *  .---.
+ *  | 1 |
+ *  `---'
+ */
+static void YCrCB_to_Grey_1x1(struct jdec_private *priv)
+{
+  const unsigned char *y;
+  unsigned char *p;
+  unsigned int i;
+  int offset_to_next_row;
+
+  p = priv->plane[0];
+  y = priv->Y;
+  offset_to_next_row = priv->width;
+
+  for (i=0; i<8; i++) {
+     memcpy(p, y, 8);
+     y+=8;
+     p += offset_to_next_row;
+  }
+}
+
+/**
+ *  YCrCb -> Grey (2x1)
+ *  .-------.
+ *  | 1 | 2 |
+ *  `-------'
+ */
+static void YCrCB_to_Grey_2x1(struct jdec_private *priv)
+{
+  const unsigned char *y;
+  unsigned char *p;
+  unsigned int i;
+
+  p = priv->plane[0];
+  y = priv->Y;
+
+  for (i=0; i<8; i++) {
+     memcpy(p, y, 16);
+     y += 16;
+     p += priv->width;
+  }
+}
+
+
+/**
+ *  YCrCb -> Grey (1x2)
+ *  .---.
+ *  | 1 |
+ *  |---|
+ *  | 2 |
+ *  `---'
+ */
+static void YCrCB_to_Grey_1x2(struct jdec_private *priv)
+{
+  const unsigned char *y;
+  unsigned char *p;
+  unsigned int i;
+
+  p = priv->plane[0];
+  y = priv->Y;
+
+  for (i=0; i<16; i++) {
+     memcpy(p, y, 8);
+     y += 8;
+     p += priv->width;
+  }
+}
+
+/**
+ *  YCrCb -> Grey (2x2)
+ *  .-------.
+ *  | 1 | 2 |
+ *  |---+---|
+ *  | 3 | 4 |
+ *  `-------'
+ */
+static void YCrCB_to_Grey_2x2(struct jdec_private *priv)
+{
+  const unsigned char *y;
+  unsigned char *p;
+  unsigned int i;
+
+  p = priv->plane[0];
+  y = priv->Y;
+
+  for (i=0; i<16; i++) {
+     memcpy(p, y, 16);
+     y += 16;
+     p += priv->width;
+  }
+}
+
+
+/*
+ * Decode all the 3 components for 1x1
+ */
+static void decode_MCU_1x1_3planes(struct jdec_private *priv)
+{
+  // Y
+  process_Huffman_data_unit(priv, cY);
+  IDCT(&priv->component_infos[cY], priv->Y, 8);
+
+  // Cb
+  process_Huffman_data_unit(priv, cCb);
+  IDCT(&priv->component_infos[cCb], priv->Cb, 8);
+
+  // Cr
+  process_Huffman_data_unit(priv, cCr);
+  IDCT(&priv->component_infos[cCr], priv->Cr, 8);
+}
+
+/*
+ * Decode a 1x1 directly in 1 color
+ */
+static void decode_MCU_1x1_1plane(struct jdec_private *priv)
+{
+  // Y
+  process_Huffman_data_unit(priv, cY);
+  IDCT(&priv->component_infos[cY], priv->Y, 8);
+
+  // Cb
+  process_Huffman_data_unit(priv, cCb);
+  IDCT(&priv->component_infos[cCb], priv->Cb, 8);
+
+  // Cr
+  process_Huffman_data_unit(priv, cCr);
+  IDCT(&priv->component_infos[cCr], priv->Cr, 8);
+}
+
+
+/*
+ * Decode a 2x1
+ *  .-------.
+ *  | 1 | 2 |
+ *  `-------'
+ */
+static void decode_MCU_2x1_3planes(struct jdec_private *priv)
+{
+  // Y
+  process_Huffman_data_unit(priv, cY);
+  IDCT(&priv->component_infos[cY], priv->Y, 16);
+  process_Huffman_data_unit(priv, cY);
+  IDCT(&priv->component_infos[cY], priv->Y+8, 16);
+
+  // Cb
+  process_Huffman_data_unit(priv, cCb);
+  IDCT(&priv->component_infos[cCb], priv->Cb, 8);
+
+  // Cr
+  process_Huffman_data_unit(priv, cCr);
+  IDCT(&priv->component_infos[cCr], priv->Cr, 8);
+}
+
+/*
+ * Decode a 2x1
+ *  .-------.
+ *  | 1 | 2 |
+ *  `-------'
+ */
+static void decode_MCU_2x1_1plane(struct jdec_private *priv)
+{
+  // Y
+  process_Huffman_data_unit(priv, cY);
+  IDCT(&priv->component_infos[cY], priv->Y, 16);
+  process_Huffman_data_unit(priv, cY);
+  IDCT(&priv->component_infos[cY], priv->Y+8, 16);
+
+  // Cb
+  process_Huffman_data_unit(priv, cCb);
+
+  // Cr
+  process_Huffman_data_unit(priv, cCr);
+}
+
+
+/*
+ * Decode a 2x2
+ *  .-------.
+ *  | 1 | 2 |
+ *  |---+---|
+ *  | 3 | 4 |
+ *  `-------'
+ */
+static void decode_MCU_2x2_3planes(struct jdec_private *priv)
+{
+  // Y
+  process_Huffman_data_unit(priv, cY);
+  IDCT(&priv->component_infos[cY], priv->Y, 16);
+  process_Huffman_data_unit(priv, cY);
+  IDCT(&priv->component_infos[cY], priv->Y+8, 16);
+  process_Huffman_data_unit(priv, cY);
+  IDCT(&priv->component_infos[cY], priv->Y+64*2, 16);
+  process_Huffman_data_unit(priv, cY);
+  IDCT(&priv->component_infos[cY], priv->Y+64*2+8, 16);
+
+  // Cb
+  process_Huffman_data_unit(priv, cCb);
+  IDCT(&priv->component_infos[cCb], priv->Cb, 8);
+
+  // Cr
+  process_Huffman_data_unit(priv, cCr);
+  IDCT(&priv->component_infos[cCr], priv->Cr, 8);
+}
+
+/*
+ * Decode a 2x2 directly in GREY format (8bits)
+ *  .-------.
+ *  | 1 | 2 |
+ *  |---+---|
+ *  | 3 | 4 |
+ *  `-------'
+ */
+static void decode_MCU_2x2_1plane(struct jdec_private *priv)
+{
+  // Y
+  process_Huffman_data_unit(priv, cY);
+  IDCT(&priv->component_infos[cY], priv->Y, 16);
+  process_Huffman_data_unit(priv, cY);
+  IDCT(&priv->component_infos[cY], priv->Y+8, 16);
+  process_Huffman_data_unit(priv, cY);
+  IDCT(&priv->component_infos[cY], priv->Y+64*2, 16);
+  process_Huffman_data_unit(priv, cY);
+  IDCT(&priv->component_infos[cY], priv->Y+64*2+8, 16);
+
+  // Cb
+  process_Huffman_data_unit(priv, cCb);
+
+  // Cr
+  process_Huffman_data_unit(priv, cCr);
+}
+
+/*
+ * Decode a 1x2 mcu
+ *  .---.
+ *  | 1 |
+ *  |---|
+ *  | 2 |
+ *  `---'
+ */
+static void decode_MCU_1x2_3planes(struct jdec_private *priv)
+{
+  // Y
+  process_Huffman_data_unit(priv, cY);
+  IDCT(&priv->component_infos[cY], priv->Y, 8);
+  process_Huffman_data_unit(priv, cY);
+  IDCT(&priv->component_infos[cY], priv->Y+64, 8);
+
+  // Cb
+  process_Huffman_data_unit(priv, cCb);
+  IDCT(&priv->component_infos[cCb], priv->Cb, 8);
+
+  // Cr
+  process_Huffman_data_unit(priv, cCr);
+  IDCT(&priv->component_infos[cCr], priv->Cr, 8);
+}
+
+/*
+ * Decode a 1x2 mcu
+ *  .---.
+ *  | 1 |
+ *  |---|
+ *  | 2 |
+ *  `---'
+ */
+static void decode_MCU_1x2_1plane(struct jdec_private *priv)
+{
+  // Y
+  process_Huffman_data_unit(priv, cY);
+  IDCT(&priv->component_infos[cY], priv->Y, 8);
+  process_Huffman_data_unit(priv, cY);
+  IDCT(&priv->component_infos[cY], priv->Y+64, 8);
+
+  // Cb
+  process_Huffman_data_unit(priv, cCb);
+
+  // Cr
+  process_Huffman_data_unit(priv, cCr);
+}
+
+static void print_SOF(const unsigned char *stream)
+{
+  int width, height, nr_components, precision;
+#if DEBUG
+  const char *nr_components_to_string[] = {
+     "????",
+     "Grayscale",
+     "????",
+     "YCbCr",
+     "CYMK"
+  };
+#endif
+
+  precision = stream[2];
+  height = be16_to_cpu(stream+3);
+  width  = be16_to_cpu(stream+5);
+  nr_components = stream[7];
+
+  trace("> SOF marker\n");
+  trace("Size:%dx%d nr_components:%d (%s)  precision:%d\n",
+      width, height,
+      nr_components, nr_components_to_string[nr_components],
+      precision);
+}
+
+/*******************************************************************************
+ *
+ * JPEG/JFIF Parsing functions
+ *
+ * Note: only a small subset of the jpeg file format is supported. No markers,
+ * nor progressive stream is supported.
+ *
+ ******************************************************************************/
+
+static void build_quantization_table(float *qtable, const unsigned char *ref_table)
+{
+  /* Taken from libjpeg. Copyright Independent JPEG Group's LLM idct.
+   * For float AA&N IDCT method, divisors are equal to quantization
+   * coefficients scaled by scalefactor[row]*scalefactor[col], where
+   *   scalefactor[0] = 1
+   *   scalefactor[k] = cos(k*PI/16) * sqrt(2)    for k=1..7
+   * We apply a further scale factor of 8.
+   * What's actually stored is 1/divisor so that the inner loop can
+   * use a multiplication rather than a division.
+   */
+  int i, j;
+  static const double aanscalefactor[8] = {
+     1.0, 1.387039845, 1.306562965, 1.175875602,
+     1.0, 0.785694958, 0.541196100, 0.275899379
+  };
+  const unsigned char *zz = zigzag;
+
+  for (i=0; i<8; i++) {
+     for (j=0; j<8; j++) {
+       *qtable++ = ref_table[*zz++] * aanscalefactor[i] * aanscalefactor[j];
+     }
+   }
+
+}
+
+static int parse_DQT(struct jdec_private *priv, const unsigned char *stream)
+{
+  int qi;
+  float *table;
+  const unsigned char *dqt_block_end;
+
+  trace("> DQT marker\n");
+  dqt_block_end = stream + be16_to_cpu(stream);
+  stream += 2;	/* Skip length */
+
+  while (stream < dqt_block_end)
+   {
+     qi = *stream++;
+#if SANITY_CHECK
+     if (qi>>4)
+       error("16 bits quantization table is not supported\n");
+     if (qi>4)
+       error("No more 4 quantization table is supported (got %d)\n", qi);
+#endif
+     table = priv->Q_tables[qi];
+     build_quantization_table(table, stream);
+     stream += 64;
+   }
+  trace("< DQT marker\n");
+  return 0;
+}
+
+static int parse_SOF(struct jdec_private *priv, const unsigned char *stream)
+{
+  int i, width, height, nr_components, cid, sampling_factor;
+  int Q_table;
+  struct component *c;
+
+  trace("> SOF marker\n");
+  print_SOF(stream);
+
+  height = be16_to_cpu(stream+3);
+  width  = be16_to_cpu(stream+5);
+  nr_components = stream[7];
+#if SANITY_CHECK
+  if (stream[2] != 8)
+    error("Precision other than 8 is not supported\n");
+  if (width>JPEG_MAX_WIDTH || height>JPEG_MAX_HEIGHT)
+    error("Width and Height (%dx%d) seems suspicious\n", width, height);
+  if (nr_components != 3)
+    error("We only support YUV images\n");
+  if (height%8)
+    error("Height need to be a multiple of 8 (current height is %d)\n", height);
+  if (width%16)
+    error("Width need to be a multiple of 16 (current Width is %d)\n", width);
+#endif
+  stream += 8;
+  for (i=0; i<nr_components; i++) {
+     cid = *stream++;
+     sampling_factor = *stream++;
+     Q_table = *stream++;
+     c = &priv->component_infos[i];
+#if SANITY_CHECK
+     c->cid = cid;
+#endif
+     c->Vfactor = sampling_factor&0xf;
+     c->Hfactor = sampling_factor>>4;
+     c->Q_table = priv->Q_tables[Q_table];
+     trace("Component:%d  factor:%dx%d  Quantization table:%d\n",
+	 cid, c->Hfactor, c->Hfactor, Q_table );
+
+  }
+  priv->width = width;
+  priv->height = height;
+
+  trace("< SOF marker\n");
+
+  return 0;
+}
+
+static int parse_SOS(struct jdec_private *priv, const unsigned char *stream)
+{
+  unsigned int i, cid, table;
+  unsigned int nr_components = stream[2];
+
+  trace("> SOS marker\n");
+
+#if SANITY_CHECK
+  if (nr_components != 3)
+    error("We only support YCbCr image\n");
+#endif
+
+  stream += 3;
+  for (i=0;i<nr_components;i++) {
+     cid = *stream++;
+     table = *stream++;
+#if SANITY_CHECK
+     if ((table&0xf)>=4)
+	error("We do not support more than 2 AC Huffman table\n");
+     if ((table>>4)>=4)
+	error("We do not support more than 2 DC Huffman table\n");
+     if (cid != priv->component_infos[i].cid)
+	error("SOS cid order (%d:%d) isn't compatible with the SOF marker (%d:%d)\n",
+	      i, cid, i, priv->component_infos[i].cid);
+     trace("ComponentId:%d  tableAC:%d tableDC:%d\n", cid, table&0xf, table>>4);
+#endif
+     priv->component_infos[i].AC_table = &priv->HTAC[table&0xf];
+     priv->component_infos[i].DC_table = &priv->HTDC[table>>4];
+  }
+  priv->stream = stream+3;
+
+  /* ITU-T T.81 (9/92) chapter E.1.3 clearly states that RSTm is to be set to 0 at the beginning of each scan */
+  priv->last_rst_marker_seen = 0;
+
+  trace("< SOS marker\n");
+
+  return 0;
+}
+
+static int parse_DHT(struct jdec_private *priv, const unsigned char *stream)
+{
+  unsigned int count, i;
+  unsigned char huff_bits[17];
+  int length, index;
+
+  length = be16_to_cpu(stream) - 2;
+  stream += 2;	/* Skip length */
+
+  trace("> DHT marker (length=%d)\n", length);
+
+  while (length>0) {
+     index = *stream++;
+
+     /* We need to calculate the number of bytes 'vals' will takes */
+     huff_bits[0] = 0;
+     count = 0;
+     for (i=1; i<17; i++) {
+	huff_bits[i] = *stream++;
+	count += huff_bits[i];
+     }
+#if SANITY_CHECK
+     if (count > 1024)
+       error("No more than 1024 bytes is allowed to describe a huffman table");
+     if ( (index &0xf) >= HUFFMAN_TABLES)
+       error("No mode than %d Huffman tables is supported\n", HUFFMAN_TABLES);
+     trace("Huffman table %s n%d\n", (index&0xf0)?"AC":"DC", index&0xf);
+     trace("Length of the table: %d\n", count);
+#endif
+
+     if (index & 0xf0 )
+       build_huffman_table(huff_bits, stream, &priv->HTAC[index&0xf]);
+     else
+       build_huffman_table(huff_bits, stream, &priv->HTDC[index&0xf]);
+
+     length -= 1;
+     length -= 16;
+     length -= count;
+     stream += count;
+  }
+  trace("< DHT marker\n");
+  return 0;
+}
+
+static int parse_DRI(struct jdec_private *priv, const unsigned char *stream)
+{
+  unsigned int length;
+
+  trace("> DRI marker\n");
+
+  length = be16_to_cpu(stream);
+
+#if SANITY_CHECK
+  if (length != 4)
+    error("Length of DRI marker need to be 4\n");
+#endif
+
+  priv->restart_interval = be16_to_cpu(stream+2);
+
+#if DEBUG
+  trace("Restart interval = %d\n", priv->restart_interval);
+#endif
+
+  trace("< DRI marker\n");
+
+  return 0;
+}
+
+
+
+static void resync(struct jdec_private *priv)
+{
+  int i;
+
+  /* Init DC coefficients */
+  for (i=0; i<COMPONENTS; i++)
+     priv->component_infos[i].previous_DC = 0;
+
+  priv->reservoir = 0;
+  priv->nbits_in_reservoir = 0;
+  if (priv->restart_interval > 0)
+    priv->restarts_to_go = priv->restart_interval;
+  else
+    priv->restarts_to_go = -1;
+}
+
+static int find_next_rst_marker(struct jdec_private *priv)
+{
+  int rst_marker_found = 0;
+  int marker;
+  const unsigned char *stream = priv->stream;
+
+  /* Parse marker */
+  while (!rst_marker_found)
+   {
+     while (*stream++ != 0xff)
+      {
+	if (stream >= priv->stream_end)
+	  error("EOF while search for a RST marker.");
+      }
+     /* Skip any padding ff byte (this is normal) */
+     while (*stream == 0xff)
+       stream++;
+
+     marker = *stream++;
+     if ((RST+priv->last_rst_marker_seen) == marker)
+       rst_marker_found = 1;
+     else if (marker >= RST && marker <= RST7)
+       error("Wrong Reset marker found, abording");
+     else if (marker == EOI)
+       return 0;
+   }
+
+  priv->stream = stream;
+  priv->last_rst_marker_seen++;
+  priv->last_rst_marker_seen &= 7;
+
+  return 0;
+}
+
+static int parse_JFIF(struct jdec_private *priv, const unsigned char *stream)
+{
+  int chuck_len;
+  int marker;
+  int sos_marker_found = 0;
+  int dht_marker_found = 0;
+  const unsigned char *next_chunck;
+
+  /* Parse marker */
+  while (!sos_marker_found)
+   {
+     if (*stream++ != 0xff)
+       goto bogus_jpeg_format;
+     /* Skip any padding ff byte (this is normal) */
+     while (*stream == 0xff)
+       stream++;
+
+     marker = *stream++;
+     chuck_len = be16_to_cpu(stream);
+     next_chunck = stream + chuck_len;
+     switch (marker)
+      {
+       case SOF:
+	 if (parse_SOF(priv, stream) < 0)
+	   return -1;
+	 break;
+       case DQT:
+	 if (parse_DQT(priv, stream) < 0)
+	   return -1;
+	 break;
+       case SOS:
+	 if (parse_SOS(priv, stream) < 0)
+	   return -1;
+	 sos_marker_found = 1;
+	 break;
+       case DHT:
+	 if (parse_DHT(priv, stream) < 0)
+	   return -1;
+	 dht_marker_found = 1;
+	 break;
+       case DRI:
+	 if (parse_DRI(priv, stream) < 0)
+	   return -1;
+	 break;
+       default:
+	 trace("> Unknown marker %2.2x\n", marker);
+	 break;
+      }
+
+     stream = next_chunck;
+   }
+
+  if (!dht_marker_found) {
+    trace("No Huffman table loaded, using the default one\n");
+    build_default_huffman_tables(priv);
+  }
+
+#ifdef SANITY_CHECK
+  if (   (priv->component_infos[cY].Hfactor < priv->component_infos[cCb].Hfactor)
+      || (priv->component_infos[cY].Hfactor < priv->component_infos[cCr].Hfactor))
+    error("Horizontal sampling factor for Y should be greater than horitontal sampling factor for Cb or Cr\n");
+  if (   (priv->component_infos[cY].Vfactor < priv->component_infos[cCb].Vfactor)
+      || (priv->component_infos[cY].Vfactor < priv->component_infos[cCr].Vfactor))
+    error("Vertical sampling factor for Y should be greater than vertical sampling factor for Cb or Cr\n");
+  if (   (priv->component_infos[cCb].Hfactor!=1)
+      || (priv->component_infos[cCr].Hfactor!=1)
+      || (priv->component_infos[cCb].Vfactor!=1)
+      || (priv->component_infos[cCr].Vfactor!=1))
+    error("Sampling other than 1x1 for Cr and Cb is not supported");
+#endif
+
+  return 0;
+bogus_jpeg_format:
+  error("Bogus jpeg format\n");
+  return -1;
+}
+
+/*******************************************************************************
+ *
+ * Functions exported of the library.
+ *
+ * Note: Some applications can access directly to internal pointer of the
+ * structure. It's is not recommended, but if you have many images to
+ * uncompress with the same parameters, some functions can be called to speedup
+ * the decoding.
+ *
+ ******************************************************************************/
+
+/**
+ * Allocate a new tinyjpeg decoder object.
+ *
+ * Before calling any other functions, an object need to be called.
+ */
+struct jdec_private *tinyjpeg_init(void)
+{
+  struct jdec_private *priv;
+
+  priv = (struct jdec_private *)calloc(1, sizeof(struct jdec_private));
+  if (priv == NULL)
+    return NULL;
+  return priv;
+}
+
+/**
+ * Free a tinyjpeg object.
+ *
+ * No others function can be called after this one.
+ */
+void tinyjpeg_free(struct jdec_private *priv)
+{
+  int i;
+  for (i=0; i<COMPONENTS; i++) {
+     if (priv->components[i])
+       free(priv->components[i]);
+     priv->components[i] = NULL;
+  }
+  free(priv);
+}
+
+/**
+ * Initialize the tinyjpeg object and prepare the decoding of the stream.
+ *
+ * Check if the jpeg can be decoded with this jpeg decoder.
+ * Fill some table used for preprocessing.
+ */
+int tinyjpeg_parse_header(struct jdec_private *priv, const unsigned char *buf, unsigned int size)
+{
+  int ret;
+
+  /* Identify the file */
+  if ((buf[0] != 0xFF) || (buf[1] != SOI))
+    error("Not a JPG file ?\n");
+
+  priv->stream_begin = buf+2;
+  priv->stream_length = size-2;
+  priv->stream_end = priv->stream_begin + priv->stream_length;
+
+  ret = parse_JFIF(priv, priv->stream_begin);
+
+  return ret;
+}
+
+static const decode_MCU_fct decode_mcu_3comp_table[4] = {
+   decode_MCU_1x1_3planes,
+   decode_MCU_1x2_3planes,
+   decode_MCU_2x1_3planes,
+   decode_MCU_2x2_3planes,
+};
+
+static const decode_MCU_fct decode_mcu_1comp_table[4] = {
+   decode_MCU_1x1_1plane,
+   decode_MCU_1x2_1plane,
+   decode_MCU_2x1_1plane,
+   decode_MCU_2x2_1plane,
+};
+
+static const convert_colorspace_fct convert_colorspace_yuv420p[4] = {
+   YCrCB_to_YUV420P_1x1,
+   YCrCB_to_YUV420P_1x2,
+   YCrCB_to_YUV420P_2x1,
+   YCrCB_to_YUV420P_2x2,
+};
+
+static const convert_colorspace_fct convert_colorspace_rgb24[4] = {
+   YCrCB_to_RGB24_1x1,
+   YCrCB_to_RGB24_1x2,
+   YCrCB_to_RGB24_2x1,
+   YCrCB_to_RGB24_2x2,
+};
+
+static const convert_colorspace_fct convert_colorspace_bgr24[4] = {
+   YCrCB_to_BGR24_1x1,
+   YCrCB_to_BGR24_1x2,
+   YCrCB_to_BGR24_2x1,
+   YCrCB_to_BGR24_2x2,
+};
+
+static const convert_colorspace_fct convert_colorspace_grey[4] = {
+   YCrCB_to_Grey_1x1,
+   YCrCB_to_Grey_1x2,
+   YCrCB_to_Grey_2x1,
+   YCrCB_to_Grey_2x2,
+};
+
+/**
+ * Decode and convert the jpeg image into @pixfmt@ image
+ *
+ * Note: components will be automaticaly allocated if no memory is attached.
+ */
+int tinyjpeg_decode(struct jdec_private *priv, int pixfmt)
+{
+  unsigned int x, y, xstride_by_mcu, ystride_by_mcu;
+  unsigned int bytes_per_blocklines[3], bytes_per_mcu[3];
+  decode_MCU_fct decode_MCU;
+  const decode_MCU_fct *decode_mcu_table;
+  const convert_colorspace_fct *colorspace_array_conv;
+  convert_colorspace_fct convert_to_pixfmt;
+
+  if (setjmp(priv->jump_state))
+    return -1;
+
+  /* To keep gcc happy initialize some array */
+  bytes_per_mcu[1] = 0;
+  bytes_per_mcu[2] = 0;
+  bytes_per_blocklines[1] = 0;
+  bytes_per_blocklines[2] = 0;
+
+  decode_mcu_table = decode_mcu_3comp_table;
+  switch (pixfmt) {
+     case TINYJPEG_FMT_YUV420P:
+       colorspace_array_conv = convert_colorspace_yuv420p;
+       if (priv->components[0] == NULL)
+	 priv->components[0] = (uint8_t *)malloc(priv->width * priv->height);
+       if (priv->components[1] == NULL)
+	 priv->components[1] = (uint8_t *)malloc(priv->width * priv->height/4);
+       if (priv->components[2] == NULL)
+	 priv->components[2] = (uint8_t *)malloc(priv->width * priv->height/4);
+       bytes_per_blocklines[0] = priv->width;
+       bytes_per_blocklines[1] = priv->width/4;
+       bytes_per_blocklines[2] = priv->width/4;
+       bytes_per_mcu[0] = 8;
+       bytes_per_mcu[1] = 4;
+       bytes_per_mcu[2] = 4;
+       break;
+
+     case TINYJPEG_FMT_RGB24:
+       colorspace_array_conv = convert_colorspace_rgb24;
+       if (priv->components[0] == NULL)
+	 priv->components[0] = (uint8_t *)malloc(priv->width * priv->height * 3);
+       bytes_per_blocklines[0] = priv->width * 3;
+       bytes_per_mcu[0] = 3*8;
+       break;
+
+     case TINYJPEG_FMT_BGR24:
+       colorspace_array_conv = convert_colorspace_bgr24;
+       if (priv->components[0] == NULL)
+	 priv->components[0] = (uint8_t *)malloc(priv->width * priv->height * 3);
+       bytes_per_blocklines[0] = priv->width * 3;
+       bytes_per_mcu[0] = 3*8;
+       break;
+
+     case TINYJPEG_FMT_GREY:
+       decode_mcu_table = decode_mcu_1comp_table;
+       colorspace_array_conv = convert_colorspace_grey;
+       if (priv->components[0] == NULL)
+	 priv->components[0] = (uint8_t *)malloc(priv->width * priv->height);
+       bytes_per_blocklines[0] = priv->width;
+       bytes_per_mcu[0] = 8;
+       break;
+
+     default:
+       trace("Bad pixel format\n");
+       return -1;
+  }
+
+  xstride_by_mcu = ystride_by_mcu = 8;
+  if ((priv->component_infos[cY].Hfactor | priv->component_infos[cY].Vfactor) == 1) {
+     decode_MCU = decode_mcu_table[0];
+     convert_to_pixfmt = colorspace_array_conv[0];
+     trace("Use decode 1x1 sampling\n");
+  } else if (priv->component_infos[cY].Hfactor == 1) {
+     decode_MCU = decode_mcu_table[1];
+     convert_to_pixfmt = colorspace_array_conv[1];
+     ystride_by_mcu = 16;
+     trace("Use decode 1x2 sampling (not supported)\n");
+  } else if (priv->component_infos[cY].Vfactor == 2) {
+     decode_MCU = decode_mcu_table[3];
+     convert_to_pixfmt = colorspace_array_conv[3];
+     xstride_by_mcu = 16;
+     ystride_by_mcu = 16;
+     trace("Use decode 2x2 sampling\n");
+  } else {
+     decode_MCU = decode_mcu_table[2];
+     convert_to_pixfmt = colorspace_array_conv[2];
+     xstride_by_mcu = 16;
+     trace("Use decode 2x1 sampling\n");
+  }
+
+  resync(priv);
+
+  /* Don't forget to that block can be either 8 or 16 lines */
+  bytes_per_blocklines[0] *= ystride_by_mcu;
+  bytes_per_blocklines[1] *= ystride_by_mcu;
+  bytes_per_blocklines[2] *= ystride_by_mcu;
+
+  bytes_per_mcu[0] *= xstride_by_mcu/8;
+  bytes_per_mcu[1] *= xstride_by_mcu/8;
+  bytes_per_mcu[2] *= xstride_by_mcu/8;
+
+  /* Just the decode the image by macroblock (size is 8x8, 8x16, or 16x16) */
+  for (y=0; y < priv->height/ystride_by_mcu; y++)
+   {
+     //trace("Decoding row %d\n", y);
+     priv->plane[0] = priv->components[0] + (y * bytes_per_blocklines[0]);
+     priv->plane[1] = priv->components[1] + (y * bytes_per_blocklines[1]);
+     priv->plane[2] = priv->components[2] + (y * bytes_per_blocklines[2]);
+     for (x=0; x < priv->width; x+=xstride_by_mcu)
+      {
+	decode_MCU(priv);
+	convert_to_pixfmt(priv);
+	priv->plane[0] += bytes_per_mcu[0];
+	priv->plane[1] += bytes_per_mcu[1];
+	priv->plane[2] += bytes_per_mcu[2];
+	if (priv->restarts_to_go>0)
+	 {
+	   priv->restarts_to_go--;
+	   if (priv->restarts_to_go == 0)
+	    {
+	      priv->stream -= (priv->nbits_in_reservoir/8);
+	      resync(priv);
+	      if (find_next_rst_marker(priv) < 0)
+		return -1;
+	    }
+	 }
+      }
+   }
+
+  return 0;
+}
+
+const char *tinyjpeg_get_errorstring(struct jdec_private *priv)
+{
+  return priv->error_string;
+}
+
+void tinyjpeg_get_size(struct jdec_private *priv, unsigned int *width, unsigned int *height)
+{
+  *width = priv->width;
+  *height = priv->height;
+}
+
+int tinyjpeg_get_components(struct jdec_private *priv, unsigned char **components)
+{
+  int i;
+  for (i=0; priv->components[i] && i<COMPONENTS; i++)
+    components[i] = priv->components[i];
+  return 0;
+}
+
+int tinyjpeg_set_components(struct jdec_private *priv, unsigned char **components, unsigned int ncomponents)
+{
+  unsigned int i;
+  if (ncomponents > COMPONENTS)
+    ncomponents = COMPONENTS;
+  for (i=0; i<ncomponents; i++)
+    priv->components[i] = components[i];
+  return 0;
+}
+
+int tinyjpeg_set_flags(struct jdec_private *priv, int flags)
+{
+  int oldflags = priv->flags;
+  priv->flags = flags;
+  return oldflags;
+}
+
diff -r cb6162341029 -r 006f05659861 v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg.h	Mon Jun 30 22:23:16 2008 +0200
@@ -0,0 +1,73 @@
+/*
+ * Small jpeg decoder library (header file)
+ *
+ * Copyright (c) 2006, Luc Saillard <luc@saillard.org>
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *  this list of conditions and the following disclaimer in the documentation
+ *  and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the author nor the names of its contributors may be
+ *  used to endorse or promote products derived from this software without
+ *  specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#ifndef __JPEGDEC_H__
+#define __JPEGDEC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct jdec_private;
+
+/* Flags that can be set by any applications */
+#define TINYJPEG_FLAGS_MJPEG_TABLE	(1<<1)
+
+/* Format accepted in outout */
+enum tinyjpeg_fmt {
+   TINYJPEG_FMT_GREY = 1,
+   TINYJPEG_FMT_BGR24,
+   TINYJPEG_FMT_RGB24,
+   TINYJPEG_FMT_YUV420P,
+};
+
+struct jdec_private *tinyjpeg_init(void);
+void tinyjpeg_free(struct jdec_private *priv);
+
+int tinyjpeg_parse_header(struct jdec_private *priv, const unsigned char *buf, unsigned int size);
+int tinyjpeg_decode(struct jdec_private *priv, int pixel_format);
+const char *tinyjpeg_get_errorstring(struct jdec_private *priv);
+void tinyjpeg_get_size(struct jdec_private *priv, unsigned int *width, unsigned int *height);
+int tinyjpeg_get_components(struct jdec_private *priv, unsigned char **components);
+int tinyjpeg_set_components(struct jdec_private *priv, unsigned char **components, unsigned int ncomponents);
+int tinyjpeg_set_flags(struct jdec_private *priv, int flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
+
