File: jl2005bcd.c

package info (click to toggle)
v4l-utils 1.32.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 12,276 kB
  • sloc: ansic: 85,528; cpp: 69,473; perl: 11,915; sh: 1,333; python: 883; php: 119; makefile: 39
file content (219 lines) | stat: -rw-r--r-- 6,339 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
/* jl2005bcd.c
 *
 * Converts raw output from Jeilin JL2005B/C/D to Bayer output.
 *
 * The code is based upon what is found in libgphoto2/camlibs/jl2005c,
 *   Copyright (c) 2010 Theodore Kilgore <kilgota@auburn.edu>
 *
 * The decompression code used is
 *   Copyright (c) 2010 Hans de Goede <hdegoede@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 <stdlib.h>
#include <string.h>

#ifdef HAVE_JPEG
#include "libv4lconvert-priv.h"
#include "jpeg_memsrcdest.h"
#include "libv4lsyscall-priv.h"


#define JPEG_HEADER_SIZE	338
#define JPEG_HEIGHT_OFFSET	 94

static int find_eoi(struct v4lconvert_data *data,
        const unsigned char *jpeg_data, int jpeg_data_idx, int jpeg_data_size)
{
	int i;

	for (i = jpeg_data_idx; i < (jpeg_data_size - 1); i++)
		if (jpeg_data[i] == 0xff && jpeg_data[i + 1] == 0xd9)
			break;

	if (i >= (jpeg_data_size - 1)) {
		V4LCONVERT_ERR("incomplete jl2005bcd frame\n");
		return -1;
	}

	return i + 2; /* + 2 -> Point to after EOI marker */
}


int v4lconvert_decode_jl2005bcd(struct v4lconvert_data *data,
		const unsigned char *src, int src_size,
                unsigned char *dest, int width, int height)
{
	unsigned char jpeg_stripe[50000];
	int q;
	struct jpeg_compress_struct cinfo;
	struct jpeg_decompress_struct dinfo;
	struct jpeg_error_mgr jcerr, jderr;
	JOCTET *jpeg_header = NULL;
#if JPEG_LIB_VERSION >= 90
	size_t jpeg_header_size = 0;
#else
	unsigned long jpeg_header_size = 0;
#endif
	int i, x, y, x1, y1, jpeg_data_size, jpeg_data_idx, eoi, size;

	/* src_size had better be bigger than 16 */
	if (src_size < 16)
		return 1;

	/* The first 16 bytes of src are a raw frame header */
	q = src[13] & 0x7f;

	if (height != src[4] << 3) {
		V4LCONVERT_ERR("Height is %d, not %d\n", src[4] << 3, height);
		return 1;
	}

	if (width != src[5] << 3) {
		V4LCONVERT_ERR("Width is %d, not %d\n", src[5] << 3, width);
		return 1;
	}

	/*
	 * And the fun begins, first of all create a dummy jpeg, which we use
	 * to get the headers from to feed to libjpeg when decompressing the
	 * stripes. This way we can use libjpeg's quant table handling
	 * (and built in default huffman tables).
	 */
	cinfo.err = jpeg_std_error (&jcerr);
	jpeg_create_compress (&cinfo);
	jpeg_mem_dest (&cinfo, &jpeg_header, &jpeg_header_size);
	cinfo.image_width = 16;
	cinfo.image_height = 16;
	cinfo.input_components = 3;
	cinfo.in_color_space = JCS_RGB;
	jpeg_set_defaults (&cinfo);
	/* Make comp[0] (which will be green) 1x2 subsampled */
	cinfo.comp_info[0].h_samp_factor = 1;
	cinfo.comp_info[0].v_samp_factor = 2;
	/* Make comp[1] and [2] use huffman table and quanttable 0, as all
	 * components use luminance settings with the jl2005c/d/e */
	cinfo.comp_info[1].quant_tbl_no = 0;
	cinfo.comp_info[1].dc_tbl_no = 0;
	cinfo.comp_info[1].ac_tbl_no = 0;
	cinfo.comp_info[2].quant_tbl_no = 0;
	cinfo.comp_info[2].dc_tbl_no = 0;
	cinfo.comp_info[2].ac_tbl_no = 0;
	/* Apply the quality setting from the header */
	if (q <= 0)
		i = 5000;
	else if (q <= 50)
		i = 5000 / q;
	else if (q <= 100)
		i = 2 * (100 - q);
	else
		i = 0;
	jpeg_set_linear_quality(&cinfo, i, TRUE);

	jpeg_start_compress (&cinfo, TRUE);
	while( cinfo.next_scanline < cinfo.image_height ) {
		JOCTET row[16 * 3];
		JSAMPROW row_pointer[1] = { row };
		jpeg_write_scanlines (&cinfo, row_pointer, 1);
	}
	jpeg_finish_compress (&cinfo);
	jpeg_destroy_compress (&cinfo);

	JSAMPLE green[8 * 16];
	JSAMPLE red[8 * 8];
	JSAMPLE blue[8 * 8];
	JSAMPROW green_row_pointer[16];
	JSAMPROW red_row_pointer[8];
	JSAMPROW blue_row_pointer[8];

	for (i = 0; i < 16; i++)
		green_row_pointer[i] = green + i * 8;

	for (i = 0; i < 8; i++) {
		red_row_pointer[i] = red + i * 8;
		blue_row_pointer[i] = blue + i * 8;
	}

	JSAMPARRAY samp_image[3] = { green_row_pointer,
				     red_row_pointer,
				     blue_row_pointer };

	memcpy(jpeg_stripe, jpeg_header, JPEG_HEADER_SIZE);
	jpeg_stripe[JPEG_HEIGHT_OFFSET    ] = height >> 8;
	jpeg_stripe[JPEG_HEIGHT_OFFSET + 1] = height;
	jpeg_stripe[JPEG_HEIGHT_OFFSET + 2] = 0;
	jpeg_stripe[JPEG_HEIGHT_OFFSET + 3] = 8;
	free (jpeg_header);
	/* Get past the raw frame header. */
	src += 16;
	jpeg_data_size = src_size - 16;

	jpeg_data_idx = 0;


	dinfo.err = jpeg_std_error (&jderr);
	jpeg_create_decompress (&dinfo);
	for (x = 0; x < width; x += 16) {
		eoi = find_eoi(data, src, jpeg_data_idx, jpeg_data_size);
		if (eoi < 0)
			return eoi;

		size = eoi - jpeg_data_idx;
		if ((JPEG_HEADER_SIZE + size) > sizeof(jpeg_stripe)) {
			V4LCONVERT_ERR("stripe size too big %d > %zd\n",
				       JPEG_HEADER_SIZE + size,
				       sizeof(jpeg_stripe));
			return 1;
		}
		memcpy (jpeg_stripe + JPEG_HEADER_SIZE,	
			src + jpeg_data_idx, size);

		jpeg_mem_src (&dinfo, jpeg_stripe, JPEG_HEADER_SIZE + size);
		jpeg_read_header (&dinfo, TRUE);
		dinfo.raw_data_out = TRUE;
#if JPEG_LIB_VERSION >= 70
		dinfo.do_fancy_upsampling = FALSE;
#endif
		jpeg_start_decompress (&dinfo);
		for (y = 0; y < height; y += 16) {
			jpeg_read_raw_data (&dinfo, samp_image, 16);
			for (y1 = 0; y1 < 16; y1 += 2) {
				for (x1 = 0; x1 < 16; x1 += 2) {
					dest[((y + y1 + 0) * width
							+ x + x1 + 0)]
						= red[y1 * 4 + x1 / 2];
					dest[((y + y1 + 0) * width
							+ x + x1 + 1)]
						= green[y1 * 8 + x1 / 2];
					dest[((y + y1 + 1) * width
							+ x + x1 + 0)]
						= green[y1 * 8 + 8 + x1 / 2];
					dest[((y + y1 + 1) * width
							+ x + x1 + 1)]
						= blue[y1 * 4 + x1 / 2];
				}
			}
		}
		jpeg_finish_decompress (&dinfo);

		/* Set jpeg_data_idx for the next stripe */
		jpeg_data_idx = (jpeg_data_idx + size + 0x0f) & ~0x0f;
	}
	jpeg_destroy_decompress(&dinfo);
	return 0;
}

#endif /* HAVE_JPEG */