The patch number 14285 was added via h...@rhel5-devel.localdomain
to http://linuxtv.org/hg/v4l-dvb master development tree.

Kernel patches in this development tree may be modified to be backward
compatible with older kernels. Compatibility modifications will be
removed before inclusion into the mainstream Kernel

If anyone has any objections, please let us know by sending a message to:
        Linux Media Mailing List <linux-me...@vger.kernel.org>

------

From: Hans de Goede  <hdego...@redhat.com>
libv4l: Add support for decoding CPIA1 compressed YUV


libv4l: Add support for decoding CPIA1 compressed YUV

Priority: normal

Signed-off-by: Hans de Goede <hdego...@redhat.com>


---

 v4l2-apps/libv4l/libv4lconvert/Makefile             |    2 
 v4l2-apps/libv4l/libv4lconvert/cpia1.c              |  216 ++++++++++++
 v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h |   11 
 v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c      |   11 
 4 files changed, 239 insertions(+), 1 deletion(-)

diff -r df4757f5b969 -r ac4289e939ef v4l2-apps/libv4l/libv4lconvert/Makefile
--- a/v4l2-apps/libv4l/libv4lconvert/Makefile   Wed Dec 30 02:40:38 2009 +0100
+++ b/v4l2-apps/libv4l/libv4lconvert/Makefile   Mon Jan 04 09:55:15 2010 +0100
@@ -15,7 +15,7 @@
 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 sn9c2028-decomp.o spca501.o sq905c.o bayer.o hm12.o \
-               stv0680.o \
+               stv0680.o cpia1.o \
                control/libv4lcontrol.o processing/libv4lprocessing.o \
                processing/whitebalance.o processing/autogain.o \
                processing/gamma.o helper.o
diff -r df4757f5b969 -r ac4289e939ef v4l2-apps/libv4l/libv4lconvert/cpia1.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/v4l2-apps/libv4l/libv4lconvert/cpia1.c    Mon Jan 04 09:55:15 2010 +0100
@@ -0,0 +1,216 @@
+/*
+#             (C) 2010 Hans de Goede <hdego...@redhat.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "libv4lconvert-priv.h"
+#include <string.h>
+
+#define MAGIC_0                0x19
+#define MAGIC_1                0x68
+#define SUBSAMPLE_420  0
+#define SUBSAMPLE_422  1
+#define YUVORDER_YUYV  0
+#define YUVORDER_UYVY  1
+#define NOT_COMPRESSED 0
+#define COMPRESSED     1
+#define NO_DECIMATION  0
+#define DECIMATION_ENAB        1
+#define EOI            0xff    /* End Of Image */
+#define EOL            0xfd    /* End Of Line */
+#define FRAME_HEADER_SIZE      64
+
+/* CPIA YUYV (sometimes sort of compressed) */
+int v4lconvert_cpia1_to_yuv420(struct v4lconvert_data *data,
+  const unsigned char *src, int src_size,
+  unsigned char *dest, int width, int height, int yvu)
+{
+  int x, y, ll, compressed;
+  unsigned char *udest, *vdest;
+
+  if (width > 352 || height > 288) {
+    fprintf(stderr, "FATAL ERROR CPIA1 size > 352x288, please report!\n");
+    return -1;
+  }
+
+  if (data->previous_frame == NULL) {
+    data->previous_frame = malloc(352 * 288 * 3 / 2);
+    if (data->previous_frame == NULL) {
+      fprintf(stderr, "cpia1 decode error: could not allocate buffer!\n");
+      return -1;
+    }
+  }
+
+  if (yvu) {
+    vdest = dest + width * height;
+    udest = vdest + width * height / 4;
+  } else {
+    udest = dest + width * height;
+    vdest = udest + width * height / 4;
+  }
+
+  /* Verify header */
+  if (src_size < FRAME_HEADER_SIZE ||
+      src[0] != MAGIC_0 || src[1] != MAGIC_1 ||
+      src[17] != SUBSAMPLE_420 ||
+      src[18] != YUVORDER_YUYV ||
+      (src[25] - src[24]) * 8 != width ||
+      (src[27] - src[26]) * 4 != height ||
+      (src[28] != NOT_COMPRESSED && src[28] != COMPRESSED) ||
+      (src[29] != NO_DECIMATION && src[29] != DECIMATION_ENAB)) {
+    fprintf(stderr, "cpia1 decode error: invalid header\n");
+    return -1;
+  }
+
+  if (src[29] == DECIMATION_ENAB) {
+    fprintf(stderr, "cpia1 decode error: decimation is not supported\n");
+    return -1;
+  }
+
+  compressed = src[28] == COMPRESSED;
+
+  src += FRAME_HEADER_SIZE;
+  src_size -= FRAME_HEADER_SIZE;
+
+  if (!compressed) {
+    for (y = 0; y < height && src_size > 2; y++) {
+      ll = src[0] | (src[1] << 8);
+      src += 2;
+      src_size -= 2;
+      if (src_size < ll) {
+       fprintf(stderr, "cpia1 decode error: short frame\n");
+       return -1;
+      }
+      if (src[ll - 1] != EOL) {
+       fprintf(stderr, "cpia1 decode error: invalid terminated line\n");
+       return -1;
+      }
+
+      if (!(y & 1)) { /* Even line Y + UV in the form of YUYV */
+       if (ll != 2 * width + 1) {
+         fprintf(stderr, "cpia1 decode error: invalid uncompressed even ll\n");
+         return -1;
+       }
+
+       /* copy the Y values */
+       for (x = 0; x < width; x += 2) {
+         *dest++ = src[0];
+         *dest++ = src[2];
+         src += 4;
+       }
+
+       /* copy the UV values */
+       src -= 2 * width;
+       for (x = 0; x < width; x += 2) {
+         *udest++ = src[1];
+         *vdest++ = src[3];
+         src += 4;
+       }
+      } else { /* Odd line only Y values */
+       if (ll != width + 1) {
+         fprintf(stderr, "cpia1 decode error: invalid uncompressed odd ll\n");
+         return -1;
+       }
+
+       memcpy(dest, src, width);
+       dest += width;
+       src += width;
+      }
+      src++; /* Skip EOL */
+      src_size -= ll;
+    }
+  } else { /* compressed */
+    int ydest_index, uvdest_index;
+
+    /* Pre-fill dest with previous frame, as the cpia1 "compression" consists
+       of simply ommitting certain pixels */
+    memcpy(dest, data->previous_frame, width * height * 3 / 2);
+
+    for (y = 0; y < height && src_size > 2; y++) {
+      ll = src[0] | (src[1] << 8);
+      src += 2;
+      src_size -= 2;
+      if (src_size < ll) {
+       fprintf(stderr, "cpia1 decode error: short frame\n");
+       return -1;
+      }
+      if (src[ll - 1] != EOL) {
+       fprintf(stderr, "cpia1 decode error: invalid terminated line\n");
+       return -1;
+      }
+
+      /* Do this now as we use ll as loop variable below */
+      src_size -= ll;
+      for (x = 0; x < width && ll > 1; ) {
+       if (*src & 1) { /* skip N pixels */
+         int skip = *src >> 1;
+
+         if (skip & 1) {
+           fprintf(stderr,
+                   "cpia1 decode error: odd number of pixels to skip");
+           return -1;
+         }
+
+         if (!(y & 1)) { /* Even line Y + UV in the form of YUYV */
+           dest += skip;
+           udest += skip / 2;
+           vdest += skip / 2;
+         } else { /* Odd line only Y values */
+           dest += skip;
+         }
+         x += skip;
+         src++;
+         ll--;
+       } else {
+         if (!(y & 1)) { /* Even line Y + UV in the form of YUYV */
+           *dest++ = *src++;
+           *udest++ = *src++;
+           *dest++ = *src++;
+           *vdest++ = *src++;
+           ll -= 4;
+         } else { /* Odd line only Y values */
+           *dest++ = *src++;
+           *dest++ = *src++;
+           ll -= 2;
+         }
+         x += 2;
+       }
+      }
+      if (ll != 1 || x != width) {
+       fprintf(stderr, "cpia1 decode error: line length mismatch\n");
+       return -1;
+      }
+      src++; /* Skip EOL */
+    }
+  }
+
+  if (y != height) {
+    fprintf(stderr, "cpia1 decode error: frame height mismatch\n");
+    return -1;
+  }
+
+  if (src_size != 4 ||
+      src[0] != EOI || src[1] != EOI || src[2] != EOI || src[3] != EOI) {
+    fprintf(stderr, "cpia1 decode error: invaled EOI marker\n");
+    return -1;
+  }
+
+  /* Safe frame for decompression of the next frame */
+  dest -= width * height;
+  memcpy(data->previous_frame, dest, width * height * 3 / 2);
+
+  return 0;
+}
diff -r df4757f5b969 -r ac4289e939ef 
v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h
--- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h       Wed Dec 30 
02:40:38 2009 +0100
+++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert-priv.h       Mon Jan 04 
09:55:15 2010 +0100
@@ -100,6 +100,10 @@
 #define V4L2_PIX_FMT_STV0680 v4l2_fourcc('S', '6', '8', '0')
 #endif
 
+#ifndef V4L2_PIX_FMT_CPIA1
+#define V4L2_PIX_FMT_CPIA1 v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
+#endif
+
 #ifndef V4L2_FMT_FLAG_EMULATED
 #define V4L2_FMT_FLAG_EMULATED 0x0002
 #endif
@@ -152,6 +156,9 @@
 
   /* For mr97310a decoder */
   int frames_dropped;
+
+  /* For cpia1 decoder */
+  unsigned char* previous_frame;
 };
 
 struct v4lconvert_pixfmt {
@@ -218,6 +225,10 @@
 void v4lconvert_spca508_to_yuv420(const unsigned char *src, unsigned char *dst,
   int width, int height, int yvu);
 
+int v4lconvert_cpia1_to_yuv420(struct v4lconvert_data *data,
+  const unsigned char *src, int src_size,
+  unsigned char *dst, int width, int height, int yvu);
+
 void v4lconvert_sn9c20x_to_yuv420(const unsigned char *src, unsigned char *dst,
   int width, int height, int yvu);
 
diff -r df4757f5b969 -r ac4289e939ef 
v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c
--- a/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c    Wed Dec 30 02:40:38 
2009 +0100
+++ b/v4l2-apps/libv4l/libv4lconvert/libv4lconvert.c    Mon Jan 04 09:55:15 
2010 +0100
@@ -56,6 +56,7 @@
   { V4L2_PIX_FMT_SPCA501,      V4LCONVERT_NEEDS_CONVERSION },
   { V4L2_PIX_FMT_SPCA505,      V4LCONVERT_NEEDS_CONVERSION },
   { V4L2_PIX_FMT_SPCA508,      V4LCONVERT_NEEDS_CONVERSION },
+  { V4L2_PIX_FMT_CPIA1,        V4LCONVERT_NEEDS_CONVERSION },
   { V4L2_PIX_FMT_HM12,         V4LCONVERT_NEEDS_CONVERSION },
   { V4L2_PIX_FMT_MJPEG,        V4LCONVERT_COMPRESSED },
   { V4L2_PIX_FMT_JPEG,         V4LCONVERT_COMPRESSED },
@@ -172,6 +173,7 @@
   free(data->rotate90_buf);
   free(data->flip_buf);
   free(data->convert_pixfmt_buf);
+  free(data->previous_frame);
   free(data);
 }
 
@@ -642,6 +644,7 @@
     case V4L2_PIX_FMT_SPCA505:
     case V4L2_PIX_FMT_SPCA508:
     case V4L2_PIX_FMT_SN9C20X_I420:
+    case V4L2_PIX_FMT_CPIA1:
     case V4L2_PIX_FMT_OV511:
     case V4L2_PIX_FMT_OV518:
     {
@@ -677,6 +680,14 @@
        case V4L2_PIX_FMT_SN9C20X_I420:
          v4lconvert_sn9c20x_to_yuv420(src, d, width, height, yvu);
          break;
+       case V4L2_PIX_FMT_CPIA1:
+         if (v4lconvert_cpia1_to_yuv420(data, src, src_size, d,
+                                        width, height, yvu)) {
+           /* Corrupt frame, better get another one */
+           errno = EAGAIN;
+           return -1;
+         }
+         break;
        case V4L2_PIX_FMT_OV511:
          if (v4lconvert_helper_decompress(data, LIBDIR "/" LIBSUBDIR 
"/ov511-decomp",
                     src, src_size, d, d_size, width, height, yvu)) {


---

Patch is available at: 
http://linuxtv.org/hg/v4l-dvb/rev/ac4289e939efb996a62ac86aff847122011a3ecf

_______________________________________________
linuxtv-commits mailing list
linuxtv-commits@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits

Reply via email to