1 /* jl2005bcd.c
2 *
3 * Converts raw output from Jeilin JL2005B/C/D to Bayer output.
4 *
5 * The code is based upon what is found in libgphoto2/camlibs/jl2005c,
6 * Copyright (c) 2010 Theodore Kilgore <kilgota@auburn.edu>
7 *
8 * The decompression code used is
9 * Copyright (c) 2010 Hans de Goede <hdegoede@redhat.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 2.1 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26 #include <stdlib.h>
27 #include <string.h>
28
29 #ifdef HAVE_JPEG
30 #include "libv4lconvert-priv.h"
31 #include "jpeg_memsrcdest.h"
32 #include "libv4lsyscall-priv.h"
33
34
35 #define JPEG_HEADER_SIZE 338
36 #define JPEG_HEIGHT_OFFSET 94
37
find_eoi(struct v4lconvert_data * data,const unsigned char * jpeg_data,int jpeg_data_idx,int jpeg_data_size)38 static int find_eoi(struct v4lconvert_data *data,
39 const unsigned char *jpeg_data, int jpeg_data_idx, int jpeg_data_size)
40 {
41 int i;
42
43 for (i = jpeg_data_idx; i < (jpeg_data_size - 1); i++)
44 if (jpeg_data[i] == 0xff && jpeg_data[i + 1] == 0xd9)
45 break;
46
47 if (i >= (jpeg_data_size - 1)) {
48 V4LCONVERT_ERR("incomplete jl2005bcd frame\n");
49 return -1;
50 }
51
52 return i + 2; /* + 2 -> Point to after EOI marker */
53 }
54
55
v4lconvert_decode_jl2005bcd(struct v4lconvert_data * data,const unsigned char * src,int src_size,unsigned char * dest,int width,int height)56 int v4lconvert_decode_jl2005bcd(struct v4lconvert_data *data,
57 const unsigned char *src, int src_size,
58 unsigned char *dest, int width, int height)
59 {
60 unsigned char jpeg_stripe[50000];
61 int q;
62 struct jpeg_compress_struct cinfo;
63 struct jpeg_decompress_struct dinfo;
64 struct jpeg_error_mgr jcerr, jderr;
65 JOCTET *jpeg_header = NULL;
66 unsigned long jpeg_header_size = 0;
67 int i, x, y, x1, y1, jpeg_data_size, jpeg_data_idx, eoi, size;
68
69 /* src_size had better be bigger than 16 */
70 if (src_size < 16)
71 return 1;
72
73 /* The first 16 bytes of src are a raw frame header */
74 q = src[13] & 0x7f;
75
76 if (height != src[4] << 3) {
77 V4LCONVERT_ERR("Height is %d, not %d\n", src[4] << 3, height);
78 return 1;
79 }
80
81 if (width != src[5] << 3) {
82 V4LCONVERT_ERR("Width is %d, not %d\n", src[5] << 3, width);
83 return 1;
84 }
85
86 /*
87 * And the fun begins, first of all create a dummy jpeg, which we use
88 * to get the headers from to feed to libjpeg when decompressing the
89 * stripes. This way we can use libjpeg's quant table handling
90 * (and built in default huffman tables).
91 */
92 cinfo.err = jpeg_std_error (&jcerr);
93 jpeg_create_compress (&cinfo);
94 jpeg_mem_dest (&cinfo, &jpeg_header, &jpeg_header_size);
95 cinfo.image_width = 16;
96 cinfo.image_height = 16;
97 cinfo.input_components = 3;
98 cinfo.in_color_space = JCS_RGB;
99 jpeg_set_defaults (&cinfo);
100 /* Make comp[0] (which will be green) 1x2 subsampled */
101 cinfo.comp_info[0].h_samp_factor = 1;
102 cinfo.comp_info[0].v_samp_factor = 2;
103 /* Make comp[1] and [2] use huffman table and quanttable 0, as all
104 * components use luminance settings with the jl2005c/d/e */
105 cinfo.comp_info[1].quant_tbl_no = 0;
106 cinfo.comp_info[1].dc_tbl_no = 0;
107 cinfo.comp_info[1].ac_tbl_no = 0;
108 cinfo.comp_info[2].quant_tbl_no = 0;
109 cinfo.comp_info[2].dc_tbl_no = 0;
110 cinfo.comp_info[2].ac_tbl_no = 0;
111 /* Apply the quality setting from the header */
112 if (q <= 0)
113 i = 5000;
114 else if (q <= 50)
115 i = 5000 / q;
116 else if (q <= 100)
117 i = 2 * (100 - q);
118 else
119 i = 0;
120 jpeg_set_linear_quality(&cinfo, i, TRUE);
121
122 jpeg_start_compress (&cinfo, TRUE);
123 while( cinfo.next_scanline < cinfo.image_height ) {
124 JOCTET row[16 * 3];
125 JSAMPROW row_pointer[1] = { row };
126 jpeg_write_scanlines (&cinfo, row_pointer, 1);
127 }
128 jpeg_finish_compress (&cinfo);
129 jpeg_destroy_compress (&cinfo);
130
131 JSAMPLE green[8 * 16];
132 JSAMPLE red[8 * 8];
133 JSAMPLE blue[8 * 8];
134 JSAMPROW green_row_pointer[16];
135 JSAMPROW red_row_pointer[8];
136 JSAMPROW blue_row_pointer[8];
137
138 for (i = 0; i < 16; i++)
139 green_row_pointer[i] = green + i * 8;
140
141 for (i = 0; i < 8; i++) {
142 red_row_pointer[i] = red + i * 8;
143 blue_row_pointer[i] = blue + i * 8;
144 }
145
146 JSAMPARRAY samp_image[3] = { green_row_pointer,
147 red_row_pointer,
148 blue_row_pointer };
149
150 memcpy(jpeg_stripe, jpeg_header, JPEG_HEADER_SIZE);
151 jpeg_stripe[JPEG_HEIGHT_OFFSET ] = height >> 8;
152 jpeg_stripe[JPEG_HEIGHT_OFFSET + 1] = height;
153 jpeg_stripe[JPEG_HEIGHT_OFFSET + 2] = 0;
154 jpeg_stripe[JPEG_HEIGHT_OFFSET + 3] = 8;
155 free (jpeg_header);
156 /* Get past the raw frame header. */
157 src += 16;
158 jpeg_data_size = src_size - 16;
159
160 jpeg_data_idx = 0;
161
162
163 dinfo.err = jpeg_std_error (&jderr);
164 jpeg_create_decompress (&dinfo);
165 for (x = 0; x < width; x += 16) {
166 eoi = find_eoi(data, src, jpeg_data_idx, jpeg_data_size);
167 if (eoi < 0)
168 return eoi;
169
170 size = eoi - jpeg_data_idx;
171 if ((JPEG_HEADER_SIZE + size) > sizeof(jpeg_stripe)) {
172 V4LCONVERT_ERR("stripe size too big %d > %zd\n",
173 JPEG_HEADER_SIZE + size,
174 sizeof(jpeg_stripe));
175 return 1;
176 }
177 memcpy (jpeg_stripe + JPEG_HEADER_SIZE,
178 src + jpeg_data_idx, size);
179
180 jpeg_mem_src (&dinfo, jpeg_stripe, JPEG_HEADER_SIZE + size);
181 jpeg_read_header (&dinfo, TRUE);
182 dinfo.raw_data_out = TRUE;
183 #if JPEG_LIB_VERSION >= 70
184 dinfo.do_fancy_upsampling = FALSE;
185 #endif
186 jpeg_start_decompress (&dinfo);
187 for (y = 0; y < height; y += 16) {
188 jpeg_read_raw_data (&dinfo, samp_image, 16);
189 for (y1 = 0; y1 < 16; y1 += 2) {
190 for (x1 = 0; x1 < 16; x1 += 2) {
191 dest[((y + y1 + 0) * width
192 + x + x1 + 0)]
193 = red[y1 * 4 + x1 / 2];
194 dest[((y + y1 + 0) * width
195 + x + x1 + 1)]
196 = green[y1 * 8 + x1 / 2];
197 dest[((y + y1 + 1) * width
198 + x + x1 + 0)]
199 = green[y1 * 8 + 8 + x1 / 2];
200 dest[((y + y1 + 1) * width
201 + x + x1 + 1)]
202 = blue[y1 * 4 + x1 / 2];
203 }
204 }
205 }
206 jpeg_finish_decompress (&dinfo);
207
208 /* Set jpeg_data_idx for the next stripe */
209 jpeg_data_idx = (jpeg_data_idx + size + 0x0f) & ~0x0f;
210 }
211 jpeg_destroy_decompress(&dinfo);
212 return 0;
213 }
214
215 #endif /* HAVE_JPEG */
216