libv4l: Add MR97310A decompression
authorhans@rhel5-devel.localdomain <hans@rhel5-devel.localdomain>
Wed, 11 Mar 2009 12:30:03 +0000 (13:30 +0100)
committerhans@rhel5-devel.localdomain <hans@rhel5-devel.localdomain>
Wed, 11 Mar 2009 12:30:03 +0000 (13:30 +0100)
From: Kyle Guinn <elyk03@gmail.com>

libv4l: Add MR97310A decompression

Priority: normal

Signed-off-by: Kyle Guinn <elyk03@gmail.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
lib/libv4lconvert/Makefile
lib/libv4lconvert/libv4lconvert-priv.h
lib/libv4lconvert/libv4lconvert.c
lib/libv4lconvert/mr97310a.c [new file with mode: 0644]

index 16ff2e1..09e01bf 100644 (file)
@@ -10,8 +10,9 @@ CONVERT_LIB   = libv4lconvert.so
 override CPPFLAGS += -fPIC
 endif
 
-CONVERT_OBJS  = libv4lconvert.o tinyjpeg.o sn9c10x.o sn9c20x.o pac207.o flip.o crop.o \
-               jidctflt.o spca561-decompress.o rgbyuv.o spca501.o bayer.o
+CONVERT_OBJS  = libv4lconvert.o tinyjpeg.o sn9c10x.o sn9c20x.o pac207.o \
+               mr97310a.o flip.o crop.o jidctflt.o spca561-decompress.o \
+               rgbyuv.o spca501.o bayer.o
 TARGETS       = $(CONVERT_LIB) libv4lconvert.pc
 INCLUDES      = ../include/libv4lconvert.h
 
index 08a7a7c..afe3e00 100644 (file)
 #define V4L2_PIX_FMT_PAC207 v4l2_fourcc('P','2','0','7')
 #endif
 
+#ifndef V4L2_PIX_FMT_MR97310A
+#define V4L2_PIX_FMT_MR97310A v4l2_fourcc('M','3','1','0')
+#endif
+
 #ifndef V4L2_PIX_FMT_PJPG
 #define V4L2_PIX_FMT_PJPG v4l2_fourcc('P', 'J', 'P', 'G')
 #endif
@@ -173,6 +177,9 @@ void v4lconvert_decode_sn9c10x(const unsigned char *src, unsigned char *dst,
 void v4lconvert_decode_pac207(const unsigned char *src, unsigned char *dst,
   int width, int height);
 
+void v4lconvert_decode_mr97310a(const unsigned char *src, unsigned char *dst,
+  int width, int height);
+
 void v4lconvert_bayer_to_rgb24(const unsigned char *bayer,
   unsigned char *rgb, int width, int height, unsigned int pixfmt);
 
index 3c51b6c..a1a061f 100644 (file)
@@ -44,23 +44,24 @@ static void v4lconvert_get_framesizes(struct v4lconvert_data *data,
    v4lconvert_try_format for low resolutions */
 static const struct v4lconvert_pixfmt supported_src_pixfmts[] = {
   SUPPORTED_DST_PIXFMTS,
-  { V4L2_PIX_FMT_YUYV,    0 },
-  { V4L2_PIX_FMT_YVYU,    0 },
-  { V4L2_PIX_FMT_UYVY,    0 },
+  { V4L2_PIX_FMT_YUYV,         0 },
+  { V4L2_PIX_FMT_YVYU,         0 },
+  { V4L2_PIX_FMT_UYVY,         0 },
   { V4L2_PIX_FMT_SN9C20X_I420, 0 },
-  { V4L2_PIX_FMT_SBGGR8,  0 },
-  { V4L2_PIX_FMT_SGBRG8,  0 },
-  { V4L2_PIX_FMT_SGRBG8,  0 },
-  { V4L2_PIX_FMT_SRGGB8,  0 },
-  { V4L2_PIX_FMT_SPCA501, 0 },
-  { V4L2_PIX_FMT_SPCA505, 0 },
-  { V4L2_PIX_FMT_SPCA508, 0 },
-  { V4L2_PIX_FMT_MJPEG,   V4LCONVERT_COMPRESSED },
-  { V4L2_PIX_FMT_JPEG,    V4LCONVERT_COMPRESSED },
-  { V4L2_PIX_FMT_SPCA561, V4LCONVERT_COMPRESSED },
-  { V4L2_PIX_FMT_SN9C10X, V4LCONVERT_COMPRESSED },
-  { V4L2_PIX_FMT_PAC207,  V4LCONVERT_COMPRESSED },
-  { V4L2_PIX_FMT_PJPG,    V4LCONVERT_COMPRESSED },
+  { V4L2_PIX_FMT_SBGGR8,       0 },
+  { V4L2_PIX_FMT_SGBRG8,       0 },
+  { V4L2_PIX_FMT_SGRBG8,       0 },
+  { V4L2_PIX_FMT_SRGGB8,       0 },
+  { V4L2_PIX_FMT_SPCA501,      0 },
+  { V4L2_PIX_FMT_SPCA505,      0 },
+  { V4L2_PIX_FMT_SPCA508,      0 },
+  { V4L2_PIX_FMT_MJPEG,        V4LCONVERT_COMPRESSED },
+  { V4L2_PIX_FMT_JPEG,         V4LCONVERT_COMPRESSED },
+  { V4L2_PIX_FMT_SPCA561,      V4LCONVERT_COMPRESSED },
+  { V4L2_PIX_FMT_SN9C10X,      V4LCONVERT_COMPRESSED },
+  { V4L2_PIX_FMT_PAC207,       V4LCONVERT_COMPRESSED },
+  { V4L2_PIX_FMT_MR97310A,     V4LCONVERT_COMPRESSED },
+  { V4L2_PIX_FMT_PJPG,         V4LCONVERT_COMPRESSED },
 };
 
 static const struct v4lconvert_pixfmt supported_dst_pixfmts[] = {
@@ -606,6 +607,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
     case V4L2_PIX_FMT_SPCA561:
     case V4L2_PIX_FMT_SN9C10X:
     case V4L2_PIX_FMT_PAC207:
+    case V4L2_PIX_FMT_MR97310A:
     {
       unsigned char *tmpbuf;
 
@@ -627,6 +629,10 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
          v4lconvert_decode_pac207(src, tmpbuf, width, height);
          src_pix_fmt = V4L2_PIX_FMT_SBGGR8;
          break;
+       case V4L2_PIX_FMT_MR97310A:
+         v4lconvert_decode_mr97310a(src, tmpbuf, width, height);
+         src_pix_fmt = V4L2_PIX_FMT_SBGGR8;
+         break;
       }
       src = tmpbuf;
       /* Deliberate fall through to raw bayer fmt code! */
diff --git a/lib/libv4lconvert/mr97310a.c b/lib/libv4lconvert/mr97310a.c
new file mode 100644 (file)
index 0000000..b5dbea7
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * MR97310A decoder
+ *
+ * Copyright (C) 2004 Theodore Kilgore <kilgota@auburn.edu>
+ *
+ * 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 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.
+ */
+
+#include "libv4lconvert-priv.h"
+
+#define CLIP(x) ((x)<0?0:((x)>0xff)?0xff:(x))
+
+/* FIXME not threadsafe */
+static int decoder_initialized = 0;
+
+static struct {
+       unsigned char is_abs;
+       unsigned char len;
+       signed char val;
+} table[256];
+
+static void init_mr97310a_decoder(void)
+{
+       int i;
+       int is_abs, val, len;
+
+       for (i = 0; i < 256; ++i) {
+               is_abs = 0;
+               val = 0;
+               len = 0;
+               if ((i & 0x80) == 0) {
+                       /* code 0 */
+                       val = 0;
+                       len = 1;
+               } else if ((i & 0xe0) == 0xc0) {
+                       /* code 110 */
+                       val = -3;
+                       len = 3;
+               } else if ((i & 0xe0) == 0xa0) {
+                       /* code 101 */
+                       val = +3;
+                       len = 3;
+               } else if ((i & 0xf0) == 0x80) {
+                       /* code 1000 */
+                       val = +7;
+                       len = 4;
+               } else if ((i & 0xf0) == 0x90) {
+                       /* code 1001 */
+                       val = -7;
+                       len = 4;
+               } else if ((i & 0xf0) == 0xf0) {
+                       /* code 1111 */
+                       val = -15;
+                       len = 4;
+               } else if ((i & 0xf8) == 0xe0) {
+                       /* code 11100 */
+                       val = +15;
+                       len = 5;
+               } else if ((i & 0xf8) == 0xe8) {
+                       /* code 11101xxxxx */
+                       is_abs = 1;
+                       val = 0;  /* value is calculated later */
+                       len = 5;
+               }
+               table[i].is_abs = is_abs;
+               table[i].val = val;
+               table[i].len = len;
+       }
+       decoder_initialized = 1;
+}
+
+static inline unsigned char get_byte(const unsigned char *inp,
+                                    unsigned int bitpos)
+{
+       const unsigned char *addr;
+       addr = inp + (bitpos >> 3);
+       return (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
+}
+
+void v4lconvert_decode_mr97310a(const unsigned char *inp, unsigned char *outp,
+                              int width, int height)
+{
+       int row, col;
+       int val;
+       int bitpos;
+       unsigned char code;
+       unsigned char lp, tp, tlp, trp;
+
+       if (!decoder_initialized)
+               init_mr97310a_decoder();
+
+       bitpos = 0;
+
+       /* main decoding loop */
+       for (row = 0; row < height; ++row) {
+               col = 0;
+
+               /* first two pixels in first two rows are stored as raw 8-bit */
+               if (row < 2) {
+                       code = get_byte(inp, bitpos);
+                       bitpos += 8;
+                       *outp++ = code;
+
+                       code = get_byte(inp, bitpos);
+                       bitpos += 8;
+                       *outp++ = code;
+
+                       col += 2;
+               }
+
+               while (col < width) {
+                       /* get bitcode */
+                       code = get_byte(inp, bitpos);
+                       /* update bit position */
+                       bitpos += table[code].len;
+
+                       /* calculate pixel value */
+                       if (table[code].is_abs) {
+                               /* get 5 more bits and use them as absolute value */
+                               code = get_byte(inp, bitpos);
+                               val = (code & 0xf8);
+                               bitpos += 5;
+
+                       } else {
+                               /* value is relative to top or left pixel */
+                               val = table[code].val;
+                               lp = outp[-2];
+                               if (row > 1) {
+                                       tlp = outp[-2*width-2];
+                                       tp  = outp[-2*width];
+                                       trp = outp[-2*width+2];
+                               }
+                               if (row < 2) {
+                                       /* top row: relative to left pixel */
+                                       val += lp;
+                               } else if (col < 2) {
+                                       /* left column: relative to top pixel */
+                                       /* initial estimate */
+                                       val += (2*tp + 2*trp + 1)/4;
+                               } else if (col > width - 3) {
+                                       /* left column: relative to top pixel */
+                                       val += (2*tp + 2*tlp + 1)/4;
+                               /* main area: average of left and top pixel */
+                               } else {
+                                       /* initial estimate for predictor */
+                                       val += (2*lp + tp + trp + 1)/4;
+                               }
+                       }
+                       /* store pixel */
+                       *outp++ = CLIP(val);
+                       ++col;
+               }
+       }
+
+       return;
+}