da275efab9fdee84941d0d3b04fb1c1b9d957646
[rtmpclient.git] / app / src / main / jni / libuvc / src / frame-mjpeg.c
1 /*********************************************************************
2  * add and modified some function to avoid crash
3  * Copyright (C) 2014-2015 saki@serenegiant All rights reserved.
4  *********************************************************************/
5 /*********************************************************************
6  * Software License Agreement (BSD License)
7  *
8  *  Copyright (C) 2014 Robert Xiao
9  *  All rights reserved.
10  *
11  *  Redistribution and use in source and binary forms, with or without
12  *  modification, are permitted provided that the following conditions
13  *  are met:
14  *
15  *   * Redistributions of source code must retain the above copyright
16  *     notice, this list of conditions and the following disclaimer.
17  *   * Redistributions in binary form must reproduce the above
18  *     copyright notice, this list of conditions and the following
19  *     disclaimer in the documentation and/or other materials provided
20  *     with the distribution.
21  *   * Neither the name of the author nor other contributors may be
22  *     used to endorse or promote products derived from this software
23  *     without specific prior written permission.
24  *
25  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  *  POSSIBILITY OF SUCH DAMAGE.
37  *********************************************************************/
38
39 /**
40  * @defgroup frame Frame processing
41  */
42 #include "libuvc/libuvc.h"
43 #include "libuvc/libuvc_internal.h"
44 #include <jpeglib.h>
45 #include <setjmp.h>
46
47 extern uvc_error_t uvc_ensure_frame_size(uvc_frame_t *frame, size_t need_bytes);
48
49 struct error_mgr {
50         struct jpeg_error_mgr super;
51         jmp_buf jmp;
52 };
53
54 static void _error_exit(j_common_ptr dinfo) {
55         struct error_mgr *myerr = (struct error_mgr *) dinfo->err;
56 #ifndef NDEBUG
57 #if (defined(ANDROID) || defined(__ANDROID__))
58         char err_msg[1024];
59         (*dinfo->err->format_message)(dinfo, err_msg);
60         err_msg[1023] = 0;
61         LOGW("err=%s", err_msg);
62 #else
63         (*dinfo->err->output_message)(dinfo);
64 #endif
65 #endif
66         longjmp(myerr->jmp, 1);
67 }
68
69 /* ISO/IEC 10918-1:1993(E) K.3.3. Default Huffman tables used by MJPEG UVC devices
70  which don't specify a Huffman table in the JPEG stream. */
71 static const unsigned char dc_lumi_len[] = {
72         0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
73 static const unsigned char dc_lumi_val[] = {
74         0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
75
76 static const unsigned char dc_chromi_len[] = {
77         0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
78 static const unsigned char dc_chromi_val[] = {
79         0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
80
81 static const unsigned char ac_lumi_len[] = {
82         0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d };
83 static const unsigned char ac_lumi_val[] = {
84         0x01, 0x02, 0x03, 0x00, 0x04, 0x11,     0x05, 0x12,
85         0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
86         0x22, 0x71,     0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
87         0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
88         0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
89         0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
90         0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
91         0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
92         0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
93         0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
94         0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
95         0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
96         0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
97         0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
98         0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
99         0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
100         0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
101         0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
102         0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
103         0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
104         0xf9, 0xfa
105 };
106 static const unsigned char ac_chromi_len[] = {
107         0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 };
108 static const unsigned char ac_chromi_val[] = {
109         0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
110         0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
111         0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
112         0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
113         0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
114         0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
115         0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
116         0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
117         0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
118         0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
119         0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
120         0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
121         0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
122         0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
123         0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
124         0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
125         0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
126         0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
127         0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
128         0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
129         0xf9, 0xfa
130 };
131
132 #define COPY_HUFF_TABLE(dinfo,tbl,name) do { \
133         if (dinfo->tbl == NULL) dinfo->tbl = jpeg_alloc_huff_table((j_common_ptr)dinfo); \
134                 memcpy(dinfo->tbl->bits, name##_len, sizeof(name##_len)); \
135                 memset(dinfo->tbl->huffval, 0, sizeof(dinfo->tbl->huffval)); \
136                 memcpy(dinfo->tbl->huffval, name##_val, sizeof(name##_val)); \
137         } while(0)
138
139 static inline void insert_huff_tables(j_decompress_ptr dinfo) {
140         COPY_HUFF_TABLE(dinfo, dc_huff_tbl_ptrs[0], dc_lumi);
141         COPY_HUFF_TABLE(dinfo, dc_huff_tbl_ptrs[1], dc_chromi);
142         COPY_HUFF_TABLE(dinfo, ac_huff_tbl_ptrs[0], ac_lumi);
143         COPY_HUFF_TABLE(dinfo, ac_huff_tbl_ptrs[1], ac_chromi);
144 }
145
146 // XXX added to improve the performance of decoding
147 // maximun reading lines for each call of jpeg_read_scanlines
148 // when defined this macro, it's value should be common factor
149 // of all available frame height.
150 // (1, 2, 4, 5, 6, 8, 10, 12, 20, 40...for 720p&1080p)
151 #define MAX_READLINE 8
152
153 #ifndef MAX_READLINE
154 #define MAX_READLINE 1
155 #endif
156 #if MAX_READLINE < 1
157 #undef MAX_READLINE
158 #define MAX_READLINE 1
159 #endif
160
161 /** @brief Convert an MJPEG frame to RGB
162  * @ingroup frame
163  *
164  * @param in MJPEG frame
165  * @param out RGB frame
166  */
167 uvc_error_t uvc_mjpeg2rgb(uvc_frame_t *in, uvc_frame_t *out) {
168         struct jpeg_decompress_struct dinfo;
169         struct error_mgr jerr;
170         size_t lines_read;
171         // local copy
172         uint8_t *data = out->data;
173         const int out_step = out->step;
174
175         int num_scanlines, i;
176         lines_read = 0;
177         unsigned char *buffer[MAX_READLINE];
178
179         out->actual_bytes = 0;  // XXX
180         if (UNLIKELY(in->frame_format != UVC_FRAME_FORMAT_MJPEG))
181                 return UVC_ERROR_INVALID_PARAM;
182
183         if (uvc_ensure_frame_size(out, in->width * in->height * 3) < 0)
184                 return UVC_ERROR_NO_MEM;
185
186         out->width = in->width;
187         out->height = in->height;
188         out->frame_format = UVC_FRAME_FORMAT_RGB;
189         out->step = in->width * 3;
190         out->sequence = in->sequence;
191         out->capture_time = in->capture_time;
192         out->source = in->source;
193
194         dinfo.err = jpeg_std_error(&jerr.super);
195         jerr.super.error_exit = _error_exit;
196
197         if (setjmp(jerr.jmp)) {
198                 goto fail;
199         }
200
201         jpeg_create_decompress(&dinfo);
202         jpeg_mem_src(&dinfo, in->data, in->actual_bytes/*in->data_bytes*/);
203         jpeg_read_header(&dinfo, TRUE);
204
205         if (dinfo.dc_huff_tbl_ptrs[0] == NULL) {
206                 /* This frame is missing the Huffman tables: fill in the standard ones */
207                 insert_huff_tables(&dinfo);
208         }
209
210         dinfo.out_color_space = JCS_RGB;
211         dinfo.dct_method = JDCT_IFAST;
212
213         jpeg_start_decompress(&dinfo);
214
215         if (LIKELY(dinfo.output_height == out->height)) {
216                 for (; dinfo.output_scanline < dinfo.output_height ;) {
217                         buffer[0] = data + (lines_read) * out_step;
218                         for (i = 1; i < MAX_READLINE; i++)
219                                 buffer[i] = buffer[i-1] + out_step;
220                         num_scanlines = jpeg_read_scanlines(&dinfo, buffer, MAX_READLINE);
221                         lines_read += num_scanlines;
222                 }
223                 out->actual_bytes = in->width * in->height * 3; // XXX
224         }
225         jpeg_finish_decompress(&dinfo);
226         jpeg_destroy_decompress(&dinfo);
227         return lines_read == out->height ? UVC_SUCCESS : UVC_ERROR_OTHER;       // XXX
228
229 fail:
230         jpeg_destroy_decompress(&dinfo);
231         return UVC_ERROR_OTHER+1;
232 }
233
234 /** @brief Convert an MJPEG frame to BGR
235  * @ingroup frame
236  *
237  * @param in MJPEG frame
238  * @param out BGR frame
239  */
240 uvc_error_t uvc_mjpeg2bgr(uvc_frame_t *in, uvc_frame_t *out) {
241         struct jpeg_decompress_struct dinfo;
242         struct error_mgr jerr;
243         size_t lines_read;
244
245         int num_scanlines, i;
246         lines_read = 0;
247         unsigned char *buffer[MAX_READLINE];
248
249         out->actual_bytes = 0;  // XXX
250         if (UNLIKELY(in->frame_format != UVC_FRAME_FORMAT_MJPEG))
251                 return UVC_ERROR_INVALID_PARAM;
252
253         if (uvc_ensure_frame_size(out, in->width * in->height * 3) < 0)
254                 return UVC_ERROR_NO_MEM;
255
256         out->width = in->width;
257         out->height = in->height;
258         out->frame_format = UVC_FRAME_FORMAT_BGR;
259         out->step = in->width * 3;
260         out->sequence = in->sequence;
261         out->capture_time = in->capture_time;
262         out->source = in->source;
263
264         dinfo.err = jpeg_std_error(&jerr.super);
265         jerr.super.error_exit = _error_exit;
266
267         if (setjmp(jerr.jmp)) {
268                 goto fail;
269         }
270
271         jpeg_create_decompress(&dinfo);
272         jpeg_mem_src(&dinfo, in->data, in->actual_bytes/*in->data_bytes*/);
273         jpeg_read_header(&dinfo, TRUE);
274
275         if (dinfo.dc_huff_tbl_ptrs[0] == NULL) {
276                 /* This frame is missing the Huffman tables: fill in the standard ones */
277                 insert_huff_tables(&dinfo);
278         }
279
280         dinfo.out_color_space = JCS_EXT_BGR;
281         dinfo.dct_method = JDCT_IFAST;
282
283         jpeg_start_decompress(&dinfo);
284
285         // local copy
286         uint8_t *data = out->data;
287         const int out_step = out->step;
288
289         if (LIKELY(dinfo.output_height == out->height)) {
290                 for (; dinfo.output_scanline < dinfo.output_height ;) {
291                         buffer[0] = data + (lines_read) * out_step;
292                         for (i = 1; i < MAX_READLINE; i++)
293                                 buffer[i] = buffer[i-1] + out_step;
294                         num_scanlines = jpeg_read_scanlines(&dinfo, buffer, MAX_READLINE);
295                         lines_read += num_scanlines;
296                 }
297                 out->actual_bytes = in->width * in->height * 3; // XXX
298         }
299         jpeg_finish_decompress(&dinfo);
300         jpeg_destroy_decompress(&dinfo);
301         return lines_read == out->height ? UVC_SUCCESS : UVC_ERROR_OTHER;       // XXX
302
303 fail:
304         jpeg_destroy_decompress(&dinfo);
305         return UVC_ERROR_OTHER+1;
306 }
307
308 /** @brief Convert an MJPEG frame to RGB565
309  * @ingroup frame
310  *
311  * @param in MJPEG frame
312  * @param out RGB frame
313  */
314 uvc_error_t uvc_mjpeg2rgb565(uvc_frame_t *in, uvc_frame_t *out) {
315         struct jpeg_decompress_struct dinfo;
316         struct error_mgr jerr;
317         size_t lines_read;
318
319         int num_scanlines, i;
320         lines_read = 0;
321         unsigned char *buffer[MAX_READLINE];
322
323         out->actual_bytes = 0;  // XXX
324         if (UNLIKELY(in->frame_format != UVC_FRAME_FORMAT_MJPEG))
325                 return UVC_ERROR_INVALID_PARAM;
326
327         if (uvc_ensure_frame_size(out, in->width * in->height * 2) < 0)
328                 return UVC_ERROR_NO_MEM;
329
330         out->width = in->width;
331         out->height = in->height;
332         out->frame_format = UVC_FRAME_FORMAT_RGB565;
333         out->step = in->width * 2;
334         out->sequence = in->sequence;
335         out->capture_time = in->capture_time;
336         out->source = in->source;
337
338         dinfo.err = jpeg_std_error(&jerr.super);
339         jerr.super.error_exit = _error_exit;
340
341         if (setjmp(jerr.jmp)) {
342                 goto fail;
343         }
344
345         jpeg_create_decompress(&dinfo);
346         jpeg_mem_src(&dinfo, in->data, in->actual_bytes/*in->data_bytes*/);
347         jpeg_read_header(&dinfo, TRUE);
348
349         if (dinfo.dc_huff_tbl_ptrs[0] == NULL) {
350                 /* This frame is missing the Huffman tables: fill in the standard ones */
351                 insert_huff_tables(&dinfo);
352         }
353
354         dinfo.out_color_space = JCS_RGB565;
355         dinfo.dct_method = JDCT_IFAST;
356
357         jpeg_start_decompress(&dinfo);
358
359         // local copy
360         uint8_t *data = out->data;
361         const int out_step = out->step;
362
363         if (LIKELY(dinfo.output_height == out->height)) {
364                 for (; dinfo.output_scanline < dinfo.output_height ;) {
365                         buffer[0] = data + (lines_read) * out_step;
366                         for (i = 1; i < MAX_READLINE; i++)
367                                 buffer[i] = buffer[i-1] + out_step;
368                         num_scanlines = jpeg_read_scanlines(&dinfo, buffer, MAX_READLINE);
369                         lines_read += num_scanlines;
370                 }
371                 out->actual_bytes = in->width * in->height * 2; // XXX
372         }
373         jpeg_finish_decompress(&dinfo);
374         jpeg_destroy_decompress(&dinfo);
375         return lines_read == out->height ? UVC_SUCCESS : UVC_ERROR_OTHER;       // XXX
376
377 fail:
378         jpeg_destroy_decompress(&dinfo);
379         return UVC_ERROR_OTHER+1;
380 }
381
382 /** @brief Convert an MJPEG frame to RGBX
383  * @ingroup frame
384  *
385  * @param in MJPEG frame
386  * @param out RGBX frame
387  */
388 uvc_error_t uvc_mjpeg2rgbx(uvc_frame_t *in, uvc_frame_t *out) {
389         struct jpeg_decompress_struct dinfo;
390         struct error_mgr jerr;
391         size_t lines_read;
392         // local copy
393         uint8_t *data = out->data;
394         const int out_step = out->step;
395
396         int num_scanlines, i;
397         lines_read = 0;
398         unsigned char *buffer[MAX_READLINE];
399
400         out->actual_bytes = 0;  // XXX
401         if (UNLIKELY(in->frame_format != UVC_FRAME_FORMAT_MJPEG))
402                 return UVC_ERROR_INVALID_PARAM;
403
404         if (uvc_ensure_frame_size(out, in->width * in->height * 4) < 0)
405                 return UVC_ERROR_NO_MEM;
406
407         out->width = in->width;
408         out->height = in->height;
409         out->frame_format = UVC_FRAME_FORMAT_RGBX;      // XXX
410         out->step = in->width * 4;
411         out->sequence = in->sequence;
412         out->capture_time = in->capture_time;
413         out->source = in->source;
414
415         dinfo.err = jpeg_std_error(&jerr.super);
416         jerr.super.error_exit = _error_exit;
417
418         if (setjmp(jerr.jmp)) {
419                 goto fail;
420         }
421
422         jpeg_create_decompress(&dinfo);
423         jpeg_mem_src(&dinfo, in->data, in->actual_bytes/*in->data_bytes*/);     // XXX
424         jpeg_read_header(&dinfo, TRUE);
425
426         if (dinfo.dc_huff_tbl_ptrs[0] == NULL) {
427                 /* This frame is missing the Huffman tables: fill in the standard ones */
428                 insert_huff_tables(&dinfo);
429         }
430
431         dinfo.out_color_space = JCS_EXT_RGBA;
432         dinfo.dct_method = JDCT_IFAST;
433
434         jpeg_start_decompress(&dinfo);
435
436         if (LIKELY(dinfo.output_height == out->height)) {
437                 for (; dinfo.output_scanline < dinfo.output_height ;) {
438                         buffer[0] = data + (lines_read) * out_step;
439                         for (i = 1; i < MAX_READLINE; i++)
440                                 buffer[i] = buffer[i-1] + out_step;
441                         num_scanlines = jpeg_read_scanlines(&dinfo, buffer, MAX_READLINE);
442                         lines_read += num_scanlines;
443                 }
444                 out->actual_bytes = in->width * in->height * 4; // XXX
445         }
446         jpeg_finish_decompress(&dinfo);
447         jpeg_destroy_decompress(&dinfo);
448         return lines_read == out->height ? UVC_SUCCESS : UVC_ERROR_OTHER;       // XXX
449
450 fail:
451         jpeg_destroy_decompress(&dinfo);
452         return UVC_ERROR_OTHER+1;
453 }
454
455 static inline unsigned char sat(int i) {
456         return (unsigned char) (i >= 255 ? 255 : (i < 0 ? 0 : i));
457 }
458
459 #define YCbCr_YUYV_2(YCbCr, yuyv) \
460         { \
461                 *(yuyv++) = *(YCbCr+0); \
462                 *(yuyv++) = (*(YCbCr+1) + *(YCbCr+4)) >> 1; \
463                 *(yuyv++) = *(YCbCr+3); \
464                 *(yuyv++) = (*(YCbCr+2) + *(YCbCr+5)) >> 1; \
465         }
466
467 uvc_error_t uvc_mjpeg2yuyv(uvc_frame_t *in, uvc_frame_t *out) {
468
469         out->actual_bytes = 0;  // XXX
470         if (UNLIKELY(in->frame_format != UVC_FRAME_FORMAT_MJPEG))
471                 return UVC_ERROR_INVALID_PARAM;
472
473         if (uvc_ensure_frame_size(out, in->width * in->height * 2) < 0)
474                 return UVC_ERROR_NO_MEM;
475
476         size_t lines_read = 0;
477         int i, j;
478         int num_scanlines;
479         register uint8_t *yuyv, *ycbcr;
480
481         out->width = in->width;
482         out->height = in->height;
483         out->frame_format = UVC_FRAME_FORMAT_YUYV;
484         out->step = in->width * 2;
485         out->sequence = in->sequence;
486         out->capture_time = in->capture_time;
487         out->source = in->source;
488
489         struct jpeg_decompress_struct dinfo;
490         struct error_mgr jerr;
491         dinfo.err = jpeg_std_error(&jerr.super);
492         jerr.super.error_exit = _error_exit;
493
494         if (setjmp(jerr.jmp)) {
495                 goto fail;
496         }
497
498         jpeg_create_decompress(&dinfo);
499         jpeg_mem_src(&dinfo, in->data, in->actual_bytes/*in->data_bytes*/);     // XXX
500         jpeg_read_header(&dinfo, TRUE);
501
502         if (dinfo.dc_huff_tbl_ptrs[0] == NULL) {
503                 /* This frame is missing the Huffman tables: fill in the standard ones */
504                 insert_huff_tables(&dinfo);
505         }
506
507         dinfo.out_color_space = JCS_YCbCr;
508         dinfo.dct_method = JDCT_IFAST;
509
510         // start decompressor
511         jpeg_start_decompress(&dinfo);
512
513         // these dinfo.xxx valiables are only valid after jpeg_start_decompress
514         const int row_stride = dinfo.output_width * dinfo.output_components;
515
516         // allocate buffer
517         register JSAMPARRAY buffer = (*dinfo.mem->alloc_sarray)
518                 ((j_common_ptr) &dinfo, JPOOL_IMAGE, row_stride, MAX_READLINE);
519
520         // local copy
521         uint8_t *data = out->data;
522         const int out_step = out->step;
523
524         if (LIKELY(dinfo.output_height == out->height)) {
525                 for (; dinfo.output_scanline < dinfo.output_height ;) {
526                         // convert lines of mjpeg data to YCbCr
527                         num_scanlines = jpeg_read_scanlines(&dinfo, buffer, MAX_READLINE);
528                         // convert YCbCr to yuyv(YUV422)
529                         for (j = 0; j < num_scanlines; j++) {
530                                 yuyv = data + (lines_read + j) * out_step;
531                                 ycbcr = buffer[j];
532                                 for (i = 0; i < row_stride; i += 24) {  // step by YCbCr x 8 pixels = 3 x 8 bytes
533                                         YCbCr_YUYV_2(ycbcr + i, yuyv);
534                                         YCbCr_YUYV_2(ycbcr + i + 6, yuyv);
535                                         YCbCr_YUYV_2(ycbcr + i + 12, yuyv);
536                                         YCbCr_YUYV_2(ycbcr + i + 18, yuyv);
537                                 }
538                         }
539                         lines_read += num_scanlines;
540                 }
541                 out->actual_bytes = in->width * in->height * 2; // XXX
542         }
543
544         jpeg_finish_decompress(&dinfo);
545         jpeg_destroy_decompress(&dinfo);
546         return lines_read == out->height ? UVC_SUCCESS : UVC_ERROR_OTHER;
547
548 fail:
549         jpeg_destroy_decompress(&dinfo);
550         return lines_read == out->height ? UVC_SUCCESS : UVC_ERROR_OTHER+1;
551 }
552