Line data Source code
1 : /*
2 : * Copyright 2011 The LibYuv Project Authors. All rights reserved.
3 : *
4 : * Use of this source code is governed by a BSD-style license
5 : * that can be found in the LICENSE file in the root of the source
6 : * tree. An additional intellectual property rights grant can be found
7 : * in the file PATENTS. All contributing project authors may
8 : * be found in the AUTHORS file in the root of the source tree.
9 : */
10 :
11 : #include "libyuv/convert.h"
12 : #include "libyuv/convert_argb.h"
13 :
14 : #ifdef HAVE_JPEG
15 : #include "libyuv/mjpeg_decoder.h"
16 : #endif
17 :
18 : #ifdef __cplusplus
19 : namespace libyuv {
20 : extern "C" {
21 : #endif
22 :
23 : #ifdef HAVE_JPEG
24 : struct I420Buffers {
25 : uint8* y;
26 : int y_stride;
27 : uint8* u;
28 : int u_stride;
29 : uint8* v;
30 : int v_stride;
31 : int w;
32 : int h;
33 : };
34 :
35 0 : static void JpegCopyI420(void* opaque,
36 : const uint8* const* data,
37 : const int* strides,
38 : int rows) {
39 0 : I420Buffers* dest = (I420Buffers*)(opaque);
40 0 : I420Copy(data[0], strides[0], data[1], strides[1], data[2], strides[2],
41 : dest->y, dest->y_stride, dest->u, dest->u_stride, dest->v,
42 0 : dest->v_stride, dest->w, rows);
43 0 : dest->y += rows * dest->y_stride;
44 0 : dest->u += ((rows + 1) >> 1) * dest->u_stride;
45 0 : dest->v += ((rows + 1) >> 1) * dest->v_stride;
46 0 : dest->h -= rows;
47 0 : }
48 :
49 0 : static void JpegI422ToI420(void* opaque,
50 : const uint8* const* data,
51 : const int* strides,
52 : int rows) {
53 0 : I420Buffers* dest = (I420Buffers*)(opaque);
54 0 : I422ToI420(data[0], strides[0], data[1], strides[1], data[2], strides[2],
55 : dest->y, dest->y_stride, dest->u, dest->u_stride, dest->v,
56 0 : dest->v_stride, dest->w, rows);
57 0 : dest->y += rows * dest->y_stride;
58 0 : dest->u += ((rows + 1) >> 1) * dest->u_stride;
59 0 : dest->v += ((rows + 1) >> 1) * dest->v_stride;
60 0 : dest->h -= rows;
61 0 : }
62 :
63 0 : static void JpegI444ToI420(void* opaque,
64 : const uint8* const* data,
65 : const int* strides,
66 : int rows) {
67 0 : I420Buffers* dest = (I420Buffers*)(opaque);
68 0 : I444ToI420(data[0], strides[0], data[1], strides[1], data[2], strides[2],
69 : dest->y, dest->y_stride, dest->u, dest->u_stride, dest->v,
70 0 : dest->v_stride, dest->w, rows);
71 0 : dest->y += rows * dest->y_stride;
72 0 : dest->u += ((rows + 1) >> 1) * dest->u_stride;
73 0 : dest->v += ((rows + 1) >> 1) * dest->v_stride;
74 0 : dest->h -= rows;
75 0 : }
76 :
77 0 : static void JpegI400ToI420(void* opaque,
78 : const uint8* const* data,
79 : const int* strides,
80 : int rows) {
81 0 : I420Buffers* dest = (I420Buffers*)(opaque);
82 0 : I400ToI420(data[0], strides[0], dest->y, dest->y_stride, dest->u,
83 0 : dest->u_stride, dest->v, dest->v_stride, dest->w, rows);
84 0 : dest->y += rows * dest->y_stride;
85 0 : dest->u += ((rows + 1) >> 1) * dest->u_stride;
86 0 : dest->v += ((rows + 1) >> 1) * dest->v_stride;
87 0 : dest->h -= rows;
88 0 : }
89 :
90 : // Query size of MJPG in pixels.
91 : LIBYUV_API
92 0 : int MJPGSize(const uint8* sample, size_t sample_size, int* width, int* height) {
93 0 : MJpegDecoder mjpeg_decoder;
94 0 : LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size);
95 0 : if (ret) {
96 0 : *width = mjpeg_decoder.GetWidth();
97 0 : *height = mjpeg_decoder.GetHeight();
98 : }
99 0 : mjpeg_decoder.UnloadFrame();
100 0 : return ret ? 0 : -1; // -1 for runtime failure.
101 : }
102 :
103 : // MJPG (Motion JPeg) to I420
104 : // TODO(fbarchard): review w and h requirement. dw and dh may be enough.
105 : LIBYUV_API
106 0 : int MJPGToI420(const uint8* sample,
107 : size_t sample_size,
108 : uint8* y,
109 : int y_stride,
110 : uint8* u,
111 : int u_stride,
112 : uint8* v,
113 : int v_stride,
114 : int w,
115 : int h,
116 : int dw,
117 : int dh) {
118 0 : if (sample_size == kUnknownDataSize) {
119 : // ERROR: MJPEG frame size unknown
120 0 : return -1;
121 : }
122 :
123 : // TODO(fbarchard): Port MJpeg to C.
124 0 : MJpegDecoder mjpeg_decoder;
125 0 : LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size);
126 0 : if (ret &&
127 0 : (mjpeg_decoder.GetWidth() != w || mjpeg_decoder.GetHeight() != h)) {
128 : // ERROR: MJPEG frame has unexpected dimensions
129 0 : mjpeg_decoder.UnloadFrame();
130 0 : return 1; // runtime failure
131 : }
132 0 : if (ret) {
133 0 : I420Buffers bufs = {y, y_stride, u, u_stride, v, v_stride, dw, dh};
134 : // YUV420
135 0 : if (mjpeg_decoder.GetColorSpace() == MJpegDecoder::kColorSpaceYCbCr &&
136 0 : mjpeg_decoder.GetNumComponents() == 3 &&
137 0 : mjpeg_decoder.GetVertSampFactor(0) == 2 &&
138 0 : mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
139 0 : mjpeg_decoder.GetVertSampFactor(1) == 1 &&
140 0 : mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
141 0 : mjpeg_decoder.GetVertSampFactor(2) == 1 &&
142 0 : mjpeg_decoder.GetHorizSampFactor(2) == 1) {
143 0 : ret = mjpeg_decoder.DecodeToCallback(&JpegCopyI420, &bufs, dw, dh);
144 : // YUV422
145 0 : } else if (mjpeg_decoder.GetColorSpace() ==
146 0 : MJpegDecoder::kColorSpaceYCbCr &&
147 0 : mjpeg_decoder.GetNumComponents() == 3 &&
148 0 : mjpeg_decoder.GetVertSampFactor(0) == 1 &&
149 0 : mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
150 0 : mjpeg_decoder.GetVertSampFactor(1) == 1 &&
151 0 : mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
152 0 : mjpeg_decoder.GetVertSampFactor(2) == 1 &&
153 0 : mjpeg_decoder.GetHorizSampFactor(2) == 1) {
154 0 : ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToI420, &bufs, dw, dh);
155 : // YUV444
156 0 : } else if (mjpeg_decoder.GetColorSpace() ==
157 0 : MJpegDecoder::kColorSpaceYCbCr &&
158 0 : mjpeg_decoder.GetNumComponents() == 3 &&
159 0 : mjpeg_decoder.GetVertSampFactor(0) == 1 &&
160 0 : mjpeg_decoder.GetHorizSampFactor(0) == 1 &&
161 0 : mjpeg_decoder.GetVertSampFactor(1) == 1 &&
162 0 : mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
163 0 : mjpeg_decoder.GetVertSampFactor(2) == 1 &&
164 0 : mjpeg_decoder.GetHorizSampFactor(2) == 1) {
165 0 : ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToI420, &bufs, dw, dh);
166 : // YUV400
167 0 : } else if (mjpeg_decoder.GetColorSpace() ==
168 0 : MJpegDecoder::kColorSpaceGrayscale &&
169 0 : mjpeg_decoder.GetNumComponents() == 1 &&
170 0 : mjpeg_decoder.GetVertSampFactor(0) == 1 &&
171 0 : mjpeg_decoder.GetHorizSampFactor(0) == 1) {
172 0 : ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToI420, &bufs, dw, dh);
173 : } else {
174 : // TODO(fbarchard): Implement conversion for any other colorspace/sample
175 : // factors that occur in practice.
176 : // ERROR: Unable to convert MJPEG frame because format is not supported
177 0 : mjpeg_decoder.UnloadFrame();
178 0 : return 1;
179 : }
180 : }
181 0 : return ret ? 0 : 1;
182 : }
183 :
184 : #ifdef HAVE_JPEG
185 : struct ARGBBuffers {
186 : uint8* argb;
187 : int argb_stride;
188 : int w;
189 : int h;
190 : };
191 :
192 0 : static void JpegI420ToARGB(void* opaque,
193 : const uint8* const* data,
194 : const int* strides,
195 : int rows) {
196 0 : ARGBBuffers* dest = (ARGBBuffers*)(opaque);
197 0 : I420ToARGB(data[0], strides[0], data[1], strides[1], data[2], strides[2],
198 0 : dest->argb, dest->argb_stride, dest->w, rows);
199 0 : dest->argb += rows * dest->argb_stride;
200 0 : dest->h -= rows;
201 0 : }
202 :
203 0 : static void JpegI422ToARGB(void* opaque,
204 : const uint8* const* data,
205 : const int* strides,
206 : int rows) {
207 0 : ARGBBuffers* dest = (ARGBBuffers*)(opaque);
208 0 : I422ToARGB(data[0], strides[0], data[1], strides[1], data[2], strides[2],
209 0 : dest->argb, dest->argb_stride, dest->w, rows);
210 0 : dest->argb += rows * dest->argb_stride;
211 0 : dest->h -= rows;
212 0 : }
213 :
214 0 : static void JpegI444ToARGB(void* opaque,
215 : const uint8* const* data,
216 : const int* strides,
217 : int rows) {
218 0 : ARGBBuffers* dest = (ARGBBuffers*)(opaque);
219 0 : I444ToARGB(data[0], strides[0], data[1], strides[1], data[2], strides[2],
220 0 : dest->argb, dest->argb_stride, dest->w, rows);
221 0 : dest->argb += rows * dest->argb_stride;
222 0 : dest->h -= rows;
223 0 : }
224 :
225 0 : static void JpegI400ToARGB(void* opaque,
226 : const uint8* const* data,
227 : const int* strides,
228 : int rows) {
229 0 : ARGBBuffers* dest = (ARGBBuffers*)(opaque);
230 0 : I400ToARGB(data[0], strides[0], dest->argb, dest->argb_stride, dest->w, rows);
231 0 : dest->argb += rows * dest->argb_stride;
232 0 : dest->h -= rows;
233 0 : }
234 :
235 : // MJPG (Motion JPeg) to ARGB
236 : // TODO(fbarchard): review w and h requirement. dw and dh may be enough.
237 : LIBYUV_API
238 0 : int MJPGToARGB(const uint8* sample,
239 : size_t sample_size,
240 : uint8* argb,
241 : int argb_stride,
242 : int w,
243 : int h,
244 : int dw,
245 : int dh) {
246 0 : if (sample_size == kUnknownDataSize) {
247 : // ERROR: MJPEG frame size unknown
248 0 : return -1;
249 : }
250 :
251 : // TODO(fbarchard): Port MJpeg to C.
252 0 : MJpegDecoder mjpeg_decoder;
253 0 : LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size);
254 0 : if (ret &&
255 0 : (mjpeg_decoder.GetWidth() != w || mjpeg_decoder.GetHeight() != h)) {
256 : // ERROR: MJPEG frame has unexpected dimensions
257 0 : mjpeg_decoder.UnloadFrame();
258 0 : return 1; // runtime failure
259 : }
260 0 : if (ret) {
261 0 : ARGBBuffers bufs = {argb, argb_stride, dw, dh};
262 : // YUV420
263 0 : if (mjpeg_decoder.GetColorSpace() == MJpegDecoder::kColorSpaceYCbCr &&
264 0 : mjpeg_decoder.GetNumComponents() == 3 &&
265 0 : mjpeg_decoder.GetVertSampFactor(0) == 2 &&
266 0 : mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
267 0 : mjpeg_decoder.GetVertSampFactor(1) == 1 &&
268 0 : mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
269 0 : mjpeg_decoder.GetVertSampFactor(2) == 1 &&
270 0 : mjpeg_decoder.GetHorizSampFactor(2) == 1) {
271 0 : ret = mjpeg_decoder.DecodeToCallback(&JpegI420ToARGB, &bufs, dw, dh);
272 : // YUV422
273 0 : } else if (mjpeg_decoder.GetColorSpace() ==
274 0 : MJpegDecoder::kColorSpaceYCbCr &&
275 0 : mjpeg_decoder.GetNumComponents() == 3 &&
276 0 : mjpeg_decoder.GetVertSampFactor(0) == 1 &&
277 0 : mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
278 0 : mjpeg_decoder.GetVertSampFactor(1) == 1 &&
279 0 : mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
280 0 : mjpeg_decoder.GetVertSampFactor(2) == 1 &&
281 0 : mjpeg_decoder.GetHorizSampFactor(2) == 1) {
282 0 : ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToARGB, &bufs, dw, dh);
283 : // YUV444
284 0 : } else if (mjpeg_decoder.GetColorSpace() ==
285 0 : MJpegDecoder::kColorSpaceYCbCr &&
286 0 : mjpeg_decoder.GetNumComponents() == 3 &&
287 0 : mjpeg_decoder.GetVertSampFactor(0) == 1 &&
288 0 : mjpeg_decoder.GetHorizSampFactor(0) == 1 &&
289 0 : mjpeg_decoder.GetVertSampFactor(1) == 1 &&
290 0 : mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
291 0 : mjpeg_decoder.GetVertSampFactor(2) == 1 &&
292 0 : mjpeg_decoder.GetHorizSampFactor(2) == 1) {
293 0 : ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToARGB, &bufs, dw, dh);
294 : // YUV400
295 0 : } else if (mjpeg_decoder.GetColorSpace() ==
296 0 : MJpegDecoder::kColorSpaceGrayscale &&
297 0 : mjpeg_decoder.GetNumComponents() == 1 &&
298 0 : mjpeg_decoder.GetVertSampFactor(0) == 1 &&
299 0 : mjpeg_decoder.GetHorizSampFactor(0) == 1) {
300 0 : ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToARGB, &bufs, dw, dh);
301 : } else {
302 : // TODO(fbarchard): Implement conversion for any other colorspace/sample
303 : // factors that occur in practice.
304 : // ERROR: Unable to convert MJPEG frame because format is not supported
305 0 : mjpeg_decoder.UnloadFrame();
306 0 : return 1;
307 : }
308 : }
309 0 : return ret ? 0 : 1;
310 : }
311 : #endif
312 :
313 : #endif
314 :
315 : #ifdef __cplusplus
316 : } // extern "C"
317 : } // namespace libyuv
318 : #endif
|