1 /*
2  * sq905c.c
3  *
4  * Here is the decompression function for the SQ905C cameras. The functions
5  * used are adapted from the libgphoto2 functions for the same cameras,
6  * which was
7  * Copyright (c) 2005 and 2007 Theodore Kilgore <kilgota@auburn.edu>
8  * This version for libv4lconvert is
9  * Copyright (c) 2009 Theodore Kilgore <kilgota@auburn.edu>
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., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
24  */
25 
26 #include <stdlib.h>
27 
28 #include "libv4lconvert-priv.h"
29 
30 
31 #define CLIP(x) ((x) < 0 ? 0 : ((x) > 0xff) ? 0xff : (x))
32 
33 
34 	static int
sq905c_first_decompress(unsigned char * output,const unsigned char * input,unsigned int outputsize)35 sq905c_first_decompress(unsigned char *output, const unsigned char *input,
36 		unsigned int outputsize)
37 {
38 	unsigned char parity = 0;
39 	unsigned char nibble_to_keep[2];
40 	unsigned char temp1 = 0, temp2 = 0;
41 	unsigned char input_byte;
42 	unsigned char lookup = 0;
43 	unsigned int i = 0;
44 	unsigned int bytes_used = 0;
45 	unsigned int bytes_done = 0;
46 	unsigned int bit_counter = 8;
47 	unsigned int cycles = 0;
48 	int table[9] = { -1, 0, 2, 6, 0x0e, 0x0e, 0x0e, 0x0e, 0xfb};
49 	unsigned char lookup_table[16] = {
50 		0, 2, 6, 0x0e, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4,
51 		0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb
52 	};
53 	unsigned char translator[16] = {
54 		8, 7, 9, 6, 10, 11, 12, 13,
55 		14, 15, 5, 4, 3, 2, 1, 0
56 	};
57 
58 	nibble_to_keep[0] = 0;
59 	nibble_to_keep[1] = 0;
60 
61 	while (bytes_done < outputsize) {
62 		while (parity < 2) {
63 			while (lookup > table[cycles]) {
64 				if (bit_counter == 8) {
65 					input_byte = input[bytes_used];
66 					bytes_used++;
67 					temp1 = input_byte;
68 					bit_counter = 0;
69 				}
70 				input_byte = temp1;
71 				temp2 = (temp2 << 1) & 0xFF;
72 				input_byte = input_byte >> 7;
73 				temp2 = temp2 | input_byte;
74 				temp1 = (temp1 << 1) & 0xFF;
75 				bit_counter++;
76 				cycles++;
77 				if (cycles > 8)
78 					return -1;
79 				lookup = temp2 & 0xff;
80 			}
81 			temp2 = 0;
82 			for (i = 0; i < 17; i++) {
83 				if (i == 16)
84 					return -1;
85 				if (lookup == lookup_table[i]) {
86 					nibble_to_keep[parity] = translator[i];
87 					break;
88 				}
89 			}
90 			cycles = 0;
91 			parity++;
92 		}
93 		output[bytes_done] = (nibble_to_keep[0]<<4)|nibble_to_keep[1];
94 		bytes_done++;
95 		parity = 0;
96 	}
97 	return 0;
98 }
99 
100 	static int
sq905c_second_decompress(unsigned char * uncomp,unsigned char * in,int width,int height)101 sq905c_second_decompress(unsigned char *uncomp, unsigned char *in,
102 		int width, int height)
103 {
104 	int diff = 0;
105 	int tempval = 0;
106 	int i, m;
107 	unsigned char delta_left = 0;
108 	unsigned char delta_right = 0;
109 	int input_counter = 0;
110 	int delta_table[] = {
111 		-144, -110, -77, -53, -35, -21, -11, -3,
112 		2, 10, 20, 34, 52, 76, 110, 144
113 	};
114 	unsigned char *templine_red;
115 	unsigned char *templine_green;
116 	unsigned char *templine_blue;
117 
118 	templine_red = malloc(width);
119 	if (!templine_red) {
120 		return -1;
121 	}
122 	for (i = 0; i < width; i++)
123 		templine_red[i] = 0x80;
124 	templine_green = malloc(width);
125 	if (!templine_green) {
126 		free(templine_red);
127 		return -1;
128 	}
129 	for (i = 0; i < width; i++)
130 		templine_green[i] = 0x80;
131 	templine_blue = malloc(width);
132 	if (!templine_blue) {
133 		free(templine_red);
134 		free(templine_green);
135 		return -1;
136 	}
137 	for (i = 0; i < width; i++)
138 		templine_blue[i] = 0x80;
139 	for (m = 0; m < height / 2; m++) {
140 		/* First we do an even-numbered line */
141 		for (i = 0; i < width / 2; i++) {
142 			delta_right = in[input_counter] & 0x0f;
143 			delta_left = (in[input_counter] >> 4) & 0xff;
144 			input_counter++;
145 			/* left pixel (red) */
146 			diff = delta_table[delta_left];
147 			if (!i)
148 				tempval = templine_red[0] + diff;
149 			else
150 				tempval = (templine_red[i] +
151 					uncomp[2 * m * width + 2 * i - 2]) / 2 + diff;
152 			tempval = CLIP(tempval);
153 			uncomp[2 * m * width + 2 * i] = tempval;
154 			templine_red[i] = tempval;
155 			/* right pixel (green) */
156 			diff = delta_table[delta_right];
157 			if (!i)
158 				tempval = templine_green[1] + diff;
159 			else if (2 * i == width - 2)
160 				tempval = (templine_green[i] +
161 					uncomp[2 * m * width + 2 * i - 1]) / 2 + diff;
162 			else
163 				tempval = (templine_green[i + 1] +
164 					uncomp[2 * m * width + 2 * i - 1]) / 2 + diff;
165 			tempval = CLIP(tempval);
166 			uncomp[2 * m * width + 2 * i + 1] = tempval;
167 			templine_green[i] = tempval;
168 		}
169 		/* then an odd-numbered line */
170 		for (i = 0; i < width/2; i++) {
171 			delta_right = in[input_counter] & 0x0f;
172 			delta_left = (in[input_counter] >> 4) & 0xff;
173 			input_counter++;
174 			/* left pixel (green) */
175 			diff = delta_table[delta_left];
176 			if (!i)
177 				tempval = templine_green[0] + diff;
178 			else
179 				tempval = (templine_green[i] +
180 					uncomp[(2 * m + 1) * width + 2 * i - 2]) / 2 + diff;
181 			tempval = CLIP(tempval);
182 			uncomp[(2*m+1)*width+2*i] = tempval;
183 			templine_green[i] = tempval;
184 			/* right pixel (blue) */
185 			diff = delta_table[delta_right];
186 			if (!i)
187 				tempval = templine_blue[0] + diff;
188 			else
189 				tempval = (templine_blue[i] +
190 					uncomp[(2 * m + 1) * width + 2 * i - 1]) / 2 + diff;
191 			tempval = CLIP(tempval);
192 			uncomp[(2 * m + 1) * width + 2 * i + 1] = tempval;
193 			templine_blue[i] = tempval;
194 		}
195 	}
196 	free(templine_green);
197 	free(templine_red);
198 	free(templine_blue);
199 	return 0;
200 }
201 
v4lconvert_decode_sq905c(const unsigned char * src,unsigned char * dst,int width,int height)202 void v4lconvert_decode_sq905c(const unsigned char *src, unsigned char *dst,
203 		int width, int height)
204 {
205 	int size;
206 	unsigned char *temp_data;
207 	const unsigned char *raw;
208 	/* here we get rid of the 0x50 bytes of header in src. */
209 	raw = src + 0x50;
210 	size = width * height / 2;
211 	temp_data = malloc(size);
212 	if (!temp_data)
213 		goto out;
214 	sq905c_first_decompress(temp_data, raw, size);
215 	sq905c_second_decompress(dst, temp_data, width, height);
216 out:
217 	free(temp_data);
218 }
219