1 /* Appotech ax203 picframe JPEG-ish compression code
2 * For ax203 picture frames with firmware version 3.5.x
4 * Copyright (c) 2010 Hans de Goede <hdegoede@redhat.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 #include "jpeg_memsrcdest.h"
34 #if defined(HAVE_GD) && defined(HAVE_LIBJPEG)
36 locate_tables_n_write(JOCTET *jpeg, int jpeg_size, JOCTET table_type,
37 uint8_t *outbuf, int *outc)
39 int i, size, found, orig_outc = *outc;
41 /* Reserve space for writing table size */
44 /* Locate tables and write them to outbuf */
45 for (i = 2; i < jpeg_size; i += size) {
46 if (jpeg[i] != 0xff) {
47 gp_log (GP_LOG_ERROR, "ax203",
48 "marker does not start with ff?");
49 return GP_ERROR_CORRUPTED_DATA;
51 if (jpeg[i + 1] == 0xda)
54 found = jpeg[i + 1] == table_type;
56 size = ((jpeg[i] << 8) | jpeg[i + 1]) - 2;
60 memcpy(outbuf + *outc, jpeg + i, size);
65 size = *outc - orig_outc;
66 outbuf[orig_outc ] = size >> 8;
67 outbuf[orig_outc + 1] = size;
73 copy_huffman(uint8_t *dst, JOCTET *src, int n)
77 for (i = 0; i < n; i++) {
78 /* Skip 0xff escaping 0x00's (ax203 special) */
79 if (i && src[i - 1] == 0xff && src[i] == 0x00)
82 dst[copied++] = src[i];
88 /* Store MCU info needed by the picture frame (probably so that it
89 can start decompression with any block to allow transition effects) */
91 add_mcu_info(uint8_t *outbuf, int block_nr, int last_Y, int last_Cb,
92 int last_Cr, int huffman_addr)
94 int info_addr = block_nr * 8;
100 /* This is crazy, but it is what the pictframe wants */
101 huffman_addr -= 8 * block_nr;
103 /* Store last DC vals + huffman data address */
104 outbuf[info_addr + 0] = last_Y;
105 outbuf[info_addr + 1] = last_Y >> 8;
106 outbuf[info_addr + 2] = last_Cb;
107 outbuf[info_addr + 3] = last_Cb >> 8;
108 outbuf[info_addr + 4] = last_Cr;
109 outbuf[info_addr + 5] = last_Cr >> 8;
110 outbuf[info_addr + 6] = huffman_addr;
111 outbuf[info_addr + 7] = huffman_addr >> 8;
115 ax206_compress_jpeg(Camera *camera, int **in, uint8_t *outbuf, int out_size,
116 int width, int height)
118 struct jpeg_compress_struct cinfo;
119 struct jpeg_decompress_struct dinfo;
120 struct jpeg_error_mgr jcerr, jderr;
121 JSAMPROW row_pointer[1];
122 JOCTET *buf = NULL, *regular_jpeg = NULL;
123 jvirt_barray_ptr *in_coefficients;
124 int i, x, y, stop, size, ret, outc;
125 unsigned long regular_jpeg_size = 0, buf_size = 0;
126 int last_dc_val[3] = { 0, 0, 0 };
128 /* We have a rgb24bit image in the desired dimensions, first we
129 compress it into a regular jpeg, which we use as a base for
130 creating the ax203 JPEG-ish format */
131 cinfo.err = jpeg_std_error (&jcerr);
132 jpeg_create_compress (&cinfo);
133 jpeg_mem_dest (&cinfo, ®ular_jpeg, ®ular_jpeg_size);
134 cinfo.image_width = width;
135 cinfo.image_height = height;
136 cinfo.input_components = 3;
137 cinfo.in_color_space = JCS_RGB;
138 jpeg_set_defaults (&cinfo);
139 cinfo.comp_info[0].h_samp_factor = 2;
140 cinfo.comp_info[0].v_samp_factor = 2;
142 jpeg_start_compress (&cinfo, TRUE);
143 while( cinfo.next_scanline < cinfo.image_height ) {
144 JOCTET row[width * 3];
145 for (i = 0; i < width; i++) {
146 int p = in[cinfo.next_scanline][i];
147 row[i * 3 + 0] = gdTrueColorGetRed(p);
148 row[i * 3 + 1] = gdTrueColorGetGreen(p);
149 row[i * 3 + 2] = gdTrueColorGetBlue(p);
151 row_pointer[0] = row;
152 jpeg_write_scanlines (&cinfo, row_pointer, 1);
154 jpeg_finish_compress (&cinfo);
155 jpeg_destroy_compress (&cinfo);
157 /* Write image header to outbuf */
158 outbuf[0] = width >> 8;
160 outbuf[2] = height >> 8;
162 outbuf[4] = 3; /* 2x uv sub-sampling */
179 /* Make outc point to after the MCU info table, so to the start of
180 the quantisation tables */
181 outc = 16 + ((width + 15) / 16) * ((height + 15) / 16) * 8;
183 /* Locate quant tables and write them to outbuf */
184 ret = locate_tables_n_write (regular_jpeg, regular_jpeg_size, 0xdb,
186 if (ret < 0) return ret;
188 /* Locate huffman tables and write them to outbuf */
189 ret = locate_tables_n_write (regular_jpeg, regular_jpeg_size, 0xc4,
191 if (ret < 0) return ret;
193 /* The ax203 has 2 perculiarities in the huffman data for the JPEG
195 1) It wants the MCU huffman data for each new MCU to start on a byte
197 2) The component order in an MCU is Cb Cr Y, rather then Y Cb Cr
199 We solve both these issues by decompressing the regular jpeg we've
200 just created into its raw coefficients, following by creating
201 mini JPEGs with the size of one MCU block, using
202 the raw-coefficients from the regular JPEG we first created.
204 This allows us to both shuffle the component order, and to byte
205 align the start of each MCU. */
207 /* Get the raw coefficients from the regular JPEG */
208 dinfo.err = jpeg_std_error (&jderr);
209 jpeg_create_decompress (&dinfo);
210 jpeg_mem_src (&dinfo, regular_jpeg, regular_jpeg_size);
211 jpeg_read_header (&dinfo, TRUE);
212 in_coefficients = jpeg_read_coefficients (&dinfo);
214 /* Create a JPEG compression object for our mini JPEGs */
215 cinfo.err = jpeg_std_error (&jcerr);
216 jpeg_create_compress (&cinfo);
217 cinfo.image_width = 16;
218 cinfo.image_height = 16;
219 cinfo.input_components = 3;
220 cinfo.in_color_space = JCS_RGB;
222 #if JPEG_LIB_VERSION >= 80
223 cinfo.min_DCT_h_scaled_size = dinfo.min_DCT_h_scaled_size;
224 cinfo.min_DCT_v_scaled_size = dinfo.min_DCT_h_scaled_size;
225 cinfo.jpeg_width = 16;
226 cinfo.jpeg_height = 16;
228 jpeg_set_defaults (&cinfo);
229 /* We will write Cb values as comp. 0, so give it chroma settings */
230 cinfo.comp_info[0].h_samp_factor = 1;
231 cinfo.comp_info[0].v_samp_factor = 1;
232 cinfo.comp_info[0].quant_tbl_no = 1;
233 cinfo.comp_info[0].dc_tbl_no = 1;
234 cinfo.comp_info[0].ac_tbl_no = 1;
235 /* We will write Y values as comp. 2, so give it luma settings */
236 cinfo.comp_info[2].h_samp_factor = 2;
237 cinfo.comp_info[2].v_samp_factor = 2;
238 cinfo.comp_info[2].quant_tbl_no = 0;
239 cinfo.comp_info[2].dc_tbl_no = 0;
240 cinfo.comp_info[2].ac_tbl_no = 0;
242 /* And create a mini JPEG for each MCU with the shuffled component order
243 and extract its huffman data. This fixes our component order problem and
244 gives us the needed byte aligning for free. */
245 for (y = 0; y < (height + 15) / 16; y++) {
246 JBLOCKARRAY in_row[3], out_row[3];
247 jvirt_barray_ptr out_barray[3];
249 /* Notice the shuffling of components happening here !! */
250 in_row[0] = dinfo.mem->access_virt_barray((j_common_ptr)&dinfo,
253 in_row[1] = dinfo.mem->access_virt_barray((j_common_ptr)&dinfo,
256 in_row[2] = dinfo.mem->access_virt_barray((j_common_ptr)&dinfo,
260 for (x = 0; x < (width + 15) / 16; x++) {
261 /* (Re)init our destination buffer */
262 jpeg_mem_dest (&cinfo, &buf, &buf_size);
264 /* Add MCU info block to output */
265 add_mcu_info (outbuf, y * ((width + 15) / 16) + x,
266 last_dc_val[2], last_dc_val[0],
267 last_dc_val[1], outc);
269 /* Allocate virtual arrays to store the coefficients
270 for the mini jpg we are making */
271 out_barray[0] = cinfo.mem->request_virt_barray(
272 (j_common_ptr)&cinfo,
273 JPOOL_IMAGE, 0, 1, 1, 1);
274 out_barray[1] = cinfo.mem->request_virt_barray(
275 (j_common_ptr)&cinfo,
276 JPOOL_IMAGE, 0, 1, 1, 1);
277 out_barray[2] = cinfo.mem->request_virt_barray(
278 (j_common_ptr)&cinfo,
279 JPOOL_IMAGE, 0, 2, 2, 2);
280 jpeg_write_coefficients (&cinfo, out_barray);
282 /* Copy over our 3 (or 6) coefficient blocks, and
284 out_row[0] = cinfo.mem->access_virt_barray(
285 (j_common_ptr)&cinfo,
286 out_barray[0], 0, 1, 1);
287 out_row[1] = cinfo.mem->access_virt_barray(
288 (j_common_ptr)&cinfo,
289 out_barray[1], 0, 1, 1);
290 out_row[2] = cinfo.mem->access_virt_barray(
291 (j_common_ptr)&cinfo,
292 out_barray[2], 0, 2, 1);
294 for (i = 0; i < 2; i++) {
295 memcpy (out_row[i][0][0],
298 out_row[i][0][0][0] -= last_dc_val[i];
299 last_dc_val[i] = in_row[i][0][x][0];
302 memcpy (out_row[2][0][0],
303 in_row[2][0][x * 2 + 0],
305 memcpy (out_row[2][0][1],
306 in_row[2][0][x * 2 + 1],
308 memcpy (out_row[2][1][0],
309 in_row[2][1][x * 2 + 0],
311 memcpy (out_row[2][1][1],
312 in_row[2][1][x * 2 + 1],
314 out_row[2][0][0][0] -= last_dc_val[2];
315 out_row[2][0][1][0] -= last_dc_val[2];
316 out_row[2][1][0][0] -= last_dc_val[2];
317 out_row[2][1][1][0] -= last_dc_val[2];
318 last_dc_val[2] = in_row[2][1][x * 2 + 1][0];
320 jpeg_finish_compress (&cinfo);
323 for (i = 2; i < buf_size && !stop; i += size) {
324 stop = buf[i] == 0xff && buf[i + 1] == 0xda;
326 size = (buf[i] << 8) | buf[i + 1];
329 gp_log (GP_LOG_ERROR, "ax203",
330 "missing in ff da marker?");
331 return GP_ERROR_CORRUPTED_DATA;
334 size = buf_size - i - 2;
335 if ((outc + size) > out_size) {
336 gp_log (GP_LOG_ERROR, "ax203",
337 "jpeg output buffer overflow");
338 return GP_ERROR_FIXED_LIMIT_EXCEEDED;
340 outc += copy_huffman(outbuf + outc, buf + i, size);
342 /* Cleanup our memory dest */
349 /* We're done with the jpeg decompress (input) and
350 compress (output) objs */
351 jpeg_destroy_decompress (&dinfo);
352 jpeg_destroy_compress (&cinfo);