• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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