1 /*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 *  Copyright (C) 2014 Robert Xiao
5 *  All rights reserved.
6 *
7 *  Redistribution and use in source and binary forms, with or without
8 *  modification, are permitted provided that the following conditions
9 *  are met:
10 *
11 *   * Redistributions of source code must retain the above copyright
12 *     notice, this list of conditions and the following disclaimer.
13 *   * Redistributions in binary form must reproduce the above
14 *     copyright notice, this list of conditions and the following
15 *     disclaimer in the documentation and/or other materials provided
16 *     with the distribution.
17 *   * Neither the name of the author nor other contributors may be
18 *     used to endorse or promote products derived from this software
19 *     without specific prior written permission.
20 *
21 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 *  POSSIBILITY OF SUCH DAMAGE.
33 *********************************************************************/
34 
35 /**
36  * @defgroup frame Frame processing
37  */
38 #include "libuvc/libuvc.h"
39 #include "libuvc/libuvc_internal.h"
40 #include <jpeglib.h>
41 #include <setjmp.h>
42 
43 extern uvc_error_t uvc_ensure_frame_size(uvc_frame_t *frame, size_t need_bytes);
44 
45 struct error_mgr {
46   struct jpeg_error_mgr super;
47   jmp_buf jmp;
48 };
49 
_error_exit(j_common_ptr dinfo)50 static void _error_exit(j_common_ptr dinfo) {
51   struct error_mgr *myerr = (struct error_mgr *)dinfo->err;
52   (*dinfo->err->output_message)(dinfo);
53   longjmp(myerr->jmp, 1);
54 }
55 
56 /* ISO/IEC 10918-1:1993(E) K.3.3. Default Huffman tables used by MJPEG UVC devices
57    which don't specify a Huffman table in the JPEG stream. */
58 static const unsigned char dc_lumi_len[] =
59   {0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0};
60 static const unsigned char dc_lumi_val[] =
61   {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
62 
63 static const unsigned char dc_chromi_len[] =
64   {0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
65 static const unsigned char dc_chromi_val[] =
66   {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
67 
68 static const unsigned char ac_lumi_len[] =
69   {0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d};
70 static const unsigned char ac_lumi_val[] =
71   {0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21,
72    0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71,
73    0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1,
74    0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72,
75    0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25,
76    0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37,
77    0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
78    0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
79    0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
80    0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83,
81    0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
82    0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,
83    0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3,
84    0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
85    0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3,
86    0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
87    0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1,
88    0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa};
89 static const unsigned char ac_chromi_len[] =
90   {0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77};
91 static const unsigned char ac_chromi_val[] =
92   {0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31,
93    0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22,
94    0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1,
95    0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1,
96    0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18,
97    0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36,
98    0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47,
99    0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
100    0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
101    0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
102    0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
103    0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a,
104    0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
105    0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
106    0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca,
107    0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
108    0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
109    0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa};
110 
111 #define COPY_HUFF_TABLE(dinfo,tbl,name) do { \
112   if(dinfo->tbl == NULL) dinfo->tbl = jpeg_alloc_huff_table((j_common_ptr)dinfo); \
113   memcpy(dinfo->tbl->bits, name##_len, sizeof(name##_len)); \
114   memset(dinfo->tbl->huffval, 0, sizeof(dinfo->tbl->huffval)); \
115   memcpy(dinfo->tbl->huffval, name##_val, sizeof(name##_val)); \
116 } while(0)
117 
insert_huff_tables(j_decompress_ptr dinfo)118 static void insert_huff_tables(j_decompress_ptr dinfo) {
119   COPY_HUFF_TABLE(dinfo, dc_huff_tbl_ptrs[0], dc_lumi);
120   COPY_HUFF_TABLE(dinfo, dc_huff_tbl_ptrs[1], dc_chromi);
121   COPY_HUFF_TABLE(dinfo, ac_huff_tbl_ptrs[0], ac_lumi);
122   COPY_HUFF_TABLE(dinfo, ac_huff_tbl_ptrs[1], ac_chromi);
123 }
124 
uvc_mjpeg_convert(uvc_frame_t * in,uvc_frame_t * out)125 static uvc_error_t uvc_mjpeg_convert(uvc_frame_t *in, uvc_frame_t *out) {
126   struct jpeg_decompress_struct dinfo;
127   struct error_mgr jerr;
128   size_t lines_read;
129   dinfo.err = jpeg_std_error(&jerr.super);
130   jerr.super.error_exit = _error_exit;
131 
132   if (setjmp(jerr.jmp)) {
133     goto fail;
134   }
135 
136   jpeg_create_decompress(&dinfo);
137   jpeg_mem_src(&dinfo, in->data, in->data_bytes);
138   jpeg_read_header(&dinfo, TRUE);
139 
140   if (dinfo.dc_huff_tbl_ptrs[0] == NULL) {
141     /* This frame is missing the Huffman tables: fill in the standard ones */
142     insert_huff_tables(&dinfo);
143   }
144 
145   if (out->frame_format == UVC_FRAME_FORMAT_RGB)
146     dinfo.out_color_space = JCS_RGB;
147   else if (out->frame_format == UVC_FRAME_FORMAT_GRAY8)
148     dinfo.out_color_space = JCS_GRAYSCALE;
149   else
150     goto fail;
151 
152   dinfo.dct_method = JDCT_IFAST;
153 
154   jpeg_start_decompress(&dinfo);
155 
156   lines_read = 0;
157   while (dinfo.output_scanline < dinfo.output_height) {
158     unsigned char *buffer[1] = {( unsigned char*) out->data + lines_read * out->step };
159     int num_scanlines;
160 
161     num_scanlines = jpeg_read_scanlines(&dinfo, buffer, 1);
162     lines_read += num_scanlines;
163   }
164 
165   jpeg_finish_decompress(&dinfo);
166   jpeg_destroy_decompress(&dinfo);
167   return 0;
168 
169 fail:
170   jpeg_destroy_decompress(&dinfo);
171   return UVC_ERROR_OTHER;
172 }
173 
174 /** @brief Convert an MJPEG frame to RGB
175  * @ingroup frame
176  *
177  * @param in MJPEG frame
178  * @param out RGB frame
179  */
uvc_mjpeg2rgb(uvc_frame_t * in,uvc_frame_t * out)180 uvc_error_t uvc_mjpeg2rgb(uvc_frame_t *in, uvc_frame_t *out) {
181   if (in->frame_format != UVC_FRAME_FORMAT_MJPEG)
182     return UVC_ERROR_INVALID_PARAM;
183 
184   if (uvc_ensure_frame_size(out, in->width * in->height * 3) < 0)
185     return UVC_ERROR_NO_MEM;
186 
187   out->width = in->width;
188   out->height = in->height;
189   out->frame_format = UVC_FRAME_FORMAT_RGB;
190   out->step = in->width * 3;
191   out->sequence = in->sequence;
192   out->capture_time = in->capture_time;
193   out->capture_time_finished = in->capture_time_finished;
194   out->source = in->source;
195 
196   return uvc_mjpeg_convert(in, out);
197 }
198 
199 /** @brief Convert an MJPEG frame to GRAY8
200  * @ingroup frame
201  *
202  * @param in MJPEG frame
203  * @param out GRAY8 frame
204  */
uvc_mjpeg2gray(uvc_frame_t * in,uvc_frame_t * out)205 uvc_error_t uvc_mjpeg2gray(uvc_frame_t *in, uvc_frame_t *out) {
206   if (in->frame_format != UVC_FRAME_FORMAT_MJPEG)
207     return UVC_ERROR_INVALID_PARAM;
208 
209   if (uvc_ensure_frame_size(out, in->width * in->height) < 0)
210     return UVC_ERROR_NO_MEM;
211 
212   out->width = in->width;
213   out->height = in->height;
214   out->frame_format = UVC_FRAME_FORMAT_GRAY8;
215   out->step = in->width;
216   out->sequence = in->sequence;
217   out->capture_time = in->capture_time;
218   out->capture_time_finished = in->capture_time_finished;
219   out->source = in->source;
220 
221   return uvc_mjpeg_convert(in, out);
222 }
223