--- /dev/null
+/* 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
{ 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 },
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:
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 */
}
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;