Improved JL2005BCD patch for libv4lcnvert
authorTheodore Kilgore <kilgota@banach.math.auburn.edu>
Fri, 16 Dec 2011 19:53:03 +0000 (13:53 -0600)
committerHans de Goede <hdegoede@redhat.com>
Thu, 29 Dec 2011 15:42:29 +0000 (16:42 +0100)
Hans,

The patch below supercedes the previous one I sent.

Two particular items of interest:

1. The Bayer tiling question seems to be resolved.

2. White balance is enabled and seems to help a lot. I am not certain if
one ought to enable a gamma setting as well, but things look pretty decent
without it, seems to me.

Other remarks:

It is pretty clear that these cameras have an internal gain setting which
relies upon internal feedback for self-correction. It works pretty well
most of the time, but sometimes it overcorrects and thereby goes a little
bit crazy.

I have tried it out with a bunch of cameras now. I did not check
individually which one is which, but I have a fairly large set of them
which includes the B and C and D variants, and some of the fancy ones have
the LCD previewer on the back but definitely do not send preview
thumbnails in webcam mode. So all of them seem to work. I would dare to
presume that your camera will work, too, whenever you get around to
checking it.

Patch below created by git diff from my recently downloaded git tree, as
was the last one. Patch is

Signed-off-by Theodore Kilgore <kilgota@auburn.edu>

include/linux/videodev2.h
lib/libv4lconvert/Makefile
lib/libv4lconvert/control/libv4lcontrol.c
lib/libv4lconvert/jl2005bcd.c [new file with mode: 0644]
lib/libv4lconvert/libv4lconvert-priv.h
lib/libv4lconvert/libv4lconvert.c

index 9d14523..95fb72e 100644 (file)
@@ -401,6 +401,7 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_SPCA561  v4l2_fourcc('S', '5', '6', '1') /* compressed GBRG bayer */
 #define V4L2_PIX_FMT_PAC207   v4l2_fourcc('P', '2', '0', '7') /* compressed BGGR bayer */
 #define V4L2_PIX_FMT_MR97310A v4l2_fourcc('M', '3', '1', '0') /* compressed BGGR bayer */
+#define V4L2_PIX_FMT_JL2005BCD v4l2_fourcc('J', 'L', '2', '0') /* compressed RGGB bayer */
 #define V4L2_PIX_FMT_SN9C2028 v4l2_fourcc('S', 'O', 'N', 'X') /* compressed GBRG bayer */
 #define V4L2_PIX_FMT_SQ905C   v4l2_fourcc('9', '0', '5', 'C') /* compressed RGGB bayer */
 #define V4L2_PIX_FMT_PJPG     v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */
index c9ca05d..7826438 100644 (file)
@@ -10,6 +10,7 @@ override CPPFLAGS += -fPIC
 endif
 
 CONVERT_OBJS  = libv4lconvert.o tinyjpeg.o sn9c10x.o sn9c20x.o pac207.o \
+               jl2005bcd.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 cpia1.o se401.o jpgl.o jpeg.o jpeg_memsrcdest.o \
index 1b38af3..7d11eb1 100644 (file)
@@ -607,6 +607,8 @@ static const struct v4lcontrol_flags_info v4lcontrol_flags[] = {
                V4LCONTROL_HFLIPPED | V4LCONTROL_VFLIPPED },
 
        /* Second: devices which should use some software processing by default */
+       /* jl2005bcd devices */
+       { 0x0979, 0x0227, 0,    NULL, NULL, V4LCONTROL_WANTS_WB },
        /* sn9c101 / sn9c102 based devices (sonixb) */
        { 0x0c45, 0x6011, 0,    NULL, NULL, 0, 1500 }, /* OV6650, no WB needed */
        { 0x0c45, 0x6019, 0,    NULL, NULL, 0, 1500 }, /* OV7630, no WB needed */
diff --git a/lib/libv4lconvert/jl2005bcd.c b/lib/libv4lconvert/jl2005bcd.c
new file mode 100644 (file)
index 0000000..f3dbf20
--- /dev/null
@@ -0,0 +1,211 @@
+/* jl2005bcd.c\r
+ *\r
+ * Converts raw output from Jeilin JL2005B/C/D to Bayer output.\r
+ *\r
+ * The code is based upon what is found in libgphoto2/camlibs/jl2005c,\r
+ *   Copyright (c) 2010 Theodore Kilgore <kilgota@auburn.edu>\r
+ *\r
+ * The decompression code used is\r
+ *   Copyright (c) 2010 Hans de Goede <hdegoede@redhat.com> \r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU Lesser General Public License as published by\r
+ * the Free Software Foundation; either version 2.1 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU Lesser General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU Lesser General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ */\r
+\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include "libv4lconvert-priv.h"\r
+#include "jpeg_memsrcdest.h"\r
+#include "libv4lsyscall-priv.h"\r
+\r
+\r
+#define JPEG_HEADER_SIZE       338\r
+#define JPEG_HEIGHT_OFFSET      94\r
+\r
+static int\r
+find_eoi(const unsigned char *jpeg_data, int jpeg_data_idx, int jpeg_data_size)\r
+{\r
+       int i;\r
+\r
+       for (i = jpeg_data_idx; i < (jpeg_data_size - 1); i++)\r
+               if (jpeg_data[i] == 0xff && jpeg_data[i + 1] == 0xd9)\r
+                       break;\r
+\r
+       if (i >= (jpeg_data_size - 1)) {\r
+               printf("AAI\n");\r
+               return -1;\r
+       }\r
+\r
+       return i + 2; /* + 2 -> Point to after EOI marker */\r
+}\r
+\r
+\r
+int v4lconvert_decode_jl2005bcd(struct v4lconvert_data *data,\r
+               const unsigned char *src, int src_size,\r
+                unsigned char *dest, int width, int height)\r
+{\r
+       unsigned char jpeg_stripe[50000];\r
+       int q;\r
+       struct jpeg_compress_struct cinfo;\r
+       struct jpeg_decompress_struct dinfo;\r
+       struct jpeg_error_mgr jcerr, jderr;\r
+       JOCTET *jpeg_header = NULL;\r
+       unsigned long jpeg_header_size = 0;\r
+       int i, x, y, x1, y1, jpeg_data_size, jpeg_data_idx, eoi, size;\r
+\r
+       /* src_size had better be bigger than 16 */\r
+       if (src_size < 16)\r
+               return 1;\r
+\r
+       /* The first 16 bytes of src are a raw frame header */\r
+       q = src[13] & 0x7f;\r
+\r
+       if (height != src[4] << 3) {\r
+               printf("Height is %d, not %d\n", src[4] << 3, height);\r
+               return 1;\r
+       }\r
+\r
+       if (width != src[5] << 3) {\r
+               printf("Width is %d, not %d\n", src[5] << 3, width);\r
+               return 1;\r
+       }\r
+       printf("quality is %d\n", q);\r
+       printf("size: %dx%d\n", width, height);\r
+       /*\r
+        * And the fun begins, first of all create a dummy jpeg, which we use\r
+        * to get the headers from to feed to libjpeg when decompressing the\r
+        * stripes. This way we can use libjpeg's quant table handling\r
+        * (and built in default huffman tables).\r
+        */\r
+       cinfo.err = jpeg_std_error (&jcerr);\r
+       jpeg_create_compress (&cinfo);\r
+       jpeg_mem_dest (&cinfo, &jpeg_header, &jpeg_header_size);\r
+       cinfo.image_width = 16;\r
+       cinfo.image_height = 16;\r
+       cinfo.input_components = 3;\r
+       cinfo.in_color_space = JCS_RGB;\r
+       jpeg_set_defaults (&cinfo);\r
+       /* Make comp[0] (which will be green) 1x2 subsampled */\r
+       cinfo.comp_info[0].h_samp_factor = 1;\r
+       cinfo.comp_info[0].v_samp_factor = 2;\r
+       /* Make comp[1] and [2] use huffman table and quanttable 0, as all\r
+        * components use luminance settings with the jl2005c/d/e */\r
+       cinfo.comp_info[1].quant_tbl_no = 0;\r
+       cinfo.comp_info[1].dc_tbl_no = 0;\r
+       cinfo.comp_info[1].ac_tbl_no = 0;\r
+       cinfo.comp_info[2].quant_tbl_no = 0;\r
+       cinfo.comp_info[2].dc_tbl_no = 0;\r
+       cinfo.comp_info[2].ac_tbl_no = 0;\r
+       /* Apply the quality setting from the header */\r
+       if (q <= 0)\r
+               i = 5000;\r
+       else if (q <= 50)\r
+               i = 5000 / q;\r
+       else if (q <= 100)\r
+               i = 2 * (100 - q);\r
+       else\r
+               i = 0;\r
+       jpeg_set_linear_quality(&cinfo, i, TRUE);\r
+\r
+       jpeg_start_compress (&cinfo, TRUE);\r
+       while( cinfo.next_scanline < cinfo.image_height ) {\r
+               JOCTET row[16 * 3];\r
+               JSAMPROW row_pointer[1] = { row };\r
+               jpeg_write_scanlines (&cinfo, row_pointer, 1);\r
+       }\r
+       jpeg_finish_compress (&cinfo);\r
+       jpeg_destroy_compress (&cinfo);\r
+\r
+       JSAMPLE green[8 * 16];\r
+       JSAMPLE red[8 * 8];\r
+       JSAMPLE blue[8 * 8];\r
+       JSAMPROW green_row_pointer[16];\r
+       JSAMPROW red_row_pointer[8];\r
+       JSAMPROW blue_row_pointer[8];\r
+\r
+       for (i = 0; i < 16; i++)\r
+               green_row_pointer[i] = green + i * 8;\r
+\r
+       for (i = 0; i < 8; i++) {\r
+               red_row_pointer[i] = red + i * 8;\r
+               blue_row_pointer[i] = blue + i * 8;\r
+       }\r
+\r
+       JSAMPARRAY samp_image[3] = { green_row_pointer,\r
+                                    red_row_pointer,\r
+                                    blue_row_pointer };\r
+\r
+       memcpy(jpeg_stripe, jpeg_header, JPEG_HEADER_SIZE);\r
+       jpeg_stripe[JPEG_HEIGHT_OFFSET    ] = height >> 8;\r
+       jpeg_stripe[JPEG_HEIGHT_OFFSET + 1] = height;\r
+       jpeg_stripe[JPEG_HEIGHT_OFFSET + 2] = 0;\r
+       jpeg_stripe[JPEG_HEIGHT_OFFSET + 3] = 8;\r
+       free (jpeg_header);\r
+       /* Get past the raw frame header. */\r
+       src += 16;\r
+       jpeg_data_size = src_size - 16;\r
+\r
+       jpeg_data_idx = 0;\r
+\r
+\r
+       dinfo.err = jpeg_std_error (&jderr);\r
+       jpeg_create_decompress (&dinfo);\r
+       for (x = 0; x < width; x += 16) {\r
+               eoi = find_eoi(src, jpeg_data_idx, jpeg_data_size);\r
+               if (eoi < 0)\r
+                       return eoi;\r
+\r
+               size = eoi - jpeg_data_idx;\r
+               if ((JPEG_HEADER_SIZE + size) > sizeof(jpeg_stripe)) {\r
+                       printf("AAAIIIIII\n");\r
+                       return 1;\r
+               }\r
+               memcpy (jpeg_stripe + JPEG_HEADER_SIZE, \r
+                       src + jpeg_data_idx, size);\r
+\r
+               jpeg_mem_src (&dinfo, jpeg_stripe, JPEG_HEADER_SIZE + size);\r
+               jpeg_read_header (&dinfo, TRUE);\r
+               dinfo.raw_data_out = TRUE;\r
+#if JPEG_LIB_VERSION >= 70\r
+               dinfo.do_fancy_upsampling = FALSE;\r
+#endif\r
+               jpeg_start_decompress (&dinfo);\r
+               for (y = 0; y < height; y += 16) {\r
+                       jpeg_read_raw_data (&dinfo, samp_image, 16);\r
+                       for (y1 = 0; y1 < 16; y1 += 2) {\r
+                               for (x1 = 0; x1 < 16; x1 += 2) {\r
+                                       dest[((y + y1 + 0) * width\r
+                                                       + x + x1 + 0)]\r
+                                               = red[y1 * 4 + x1 / 2];\r
+                                       dest[((y + y1 + 0) * width\r
+                                                       + x + x1 + 1)]\r
+                                               = green[y1 * 8 + x1 / 2];\r
+                                       dest[((y + y1 + 1) * width\r
+                                                       + x + x1 + 0)]\r
+                                               = green[y1 * 8 + 8 + x1 / 2];\r
+                                       dest[((y + y1 + 1) * width\r
+                                                       + x + x1 + 1)]\r
+                                               = blue[y1 * 4 + x1 / 2];\r
+                               }\r
+                       }\r
+               }\r
+               jpeg_finish_decompress (&dinfo);\r
+\r
+               /* Set jpeg_data_idx for the next stripe */\r
+               jpeg_data_idx = (jpeg_data_idx + size + 0x0f) & ~0x0f;\r
+       }\r
+       jpeg_destroy_decompress(&dinfo);\r
+       return 0;\r
+}\r
index d183143..9852319 100644 (file)
@@ -218,6 +218,10 @@ int v4lconvert_decode_mr97310a(struct v4lconvert_data *data,
                const unsigned char *src, int src_size, unsigned char *dst,
                int width, int height);
 
+int v4lconvert_decode_jl2005bcd(struct v4lconvert_data *data,
+               const unsigned char *src, int src_size,
+               unsigned char *dest, int width, int height);
+
 void v4lconvert_decode_sn9c2028(const unsigned char *src, unsigned char *dst,
                int width, int height);
 
index 399d73b..5e31d82 100644 (file)
@@ -78,6 +78,7 @@ static const struct v4lconvert_pixfmt supported_src_pixfmts[] = {
        { V4L2_PIX_FMT_SN9C2028,         0,      9,      9,     1 },
        { V4L2_PIX_FMT_PAC207,           0,      9,      9,     1 },
        { V4L2_PIX_FMT_MR97310A,         0,      9,      9,     1 },
+       { V4L2_PIX_FMT_JL2005BCD,        0,      9,      9,     1 },
        { V4L2_PIX_FMT_SQ905C,           0,      9,      9,     1 },
        /* special */
        { V4L2_PIX_FMT_SE401,            0,      8,      9,     1 },
@@ -591,6 +592,7 @@ static int v4lconvert_processing_needs_double_conversion(
        case V4L2_PIX_FMT_SN9C10X:
        case V4L2_PIX_FMT_PAC207:
        case V4L2_PIX_FMT_MR97310A:
+       case V4L2_PIX_FMT_JL2005BCD:
        case V4L2_PIX_FMT_SN9C2028:
        case V4L2_PIX_FMT_SQ905C:
        case V4L2_PIX_FMT_SBGGR8:
@@ -787,6 +789,7 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
        case V4L2_PIX_FMT_SN9C10X:
        case V4L2_PIX_FMT_PAC207:
        case V4L2_PIX_FMT_MR97310A:
+       case V4L2_PIX_FMT_JL2005BCD:
        case V4L2_PIX_FMT_SN9C2028:
        case V4L2_PIX_FMT_SQ905C:
        case V4L2_PIX_FMT_STV0680: { /* Not compressed but needs some shuffling */
@@ -825,6 +828,11 @@ static int v4lconvert_convert_pixfmt(struct v4lconvert_data *data,
                        }
                        tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
                        break;
+               case V4L2_PIX_FMT_JL2005BCD:
+                       v4lconvert_decode_jl2005bcd(data, src, src_size,
+                                       tmpbuf, width, height);
+                       tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SRGGB8;
+                       break;
                case V4L2_PIX_FMT_SN9C2028:
                        v4lconvert_decode_sn9c2028(src, tmpbuf, width, height);
                        tmpfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;