blob: 607035de79d5c4cb64d42f7b7bf781d2022d535a [file] [log] [blame]
fbarchard@google.com492768c2013-04-09 23:00:56 +00001/*
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
13#ifdef HAVE_JPEG
14#include "libyuv/mjpeg_decoder.h"
15#endif
16
17#ifdef __cplusplus
18namespace libyuv {
19extern "C" {
20#endif
21
22#ifdef HAVE_JPEG
23struct I420Buffers {
24 uint8* y;
25 int y_stride;
26 uint8* u;
27 int u_stride;
28 uint8* v;
29 int v_stride;
30 int w;
31 int h;
32};
33
34static void JpegCopyI420(void* opaque,
35 const uint8* const* data,
36 const int* strides,
37 int rows) {
38 I420Buffers* dest = static_cast<I420Buffers*>(opaque);
39 I420Copy(data[0], strides[0],
40 data[1], strides[1],
41 data[2], strides[2],
42 dest->y, dest->y_stride,
43 dest->u, dest->u_stride,
44 dest->v, dest->v_stride,
45 dest->w, rows);
46 dest->y += rows * dest->y_stride;
47 dest->u += ((rows + 1) >> 1) * dest->u_stride;
48 dest->v += ((rows + 1) >> 1) * dest->v_stride;
49 dest->h -= rows;
50}
51
52static void JpegI422ToI420(void* opaque,
53 const uint8* const* data,
54 const int* strides,
55 int rows) {
56 I420Buffers* dest = static_cast<I420Buffers*>(opaque);
57 I422ToI420(data[0], strides[0],
58 data[1], strides[1],
59 data[2], strides[2],
60 dest->y, dest->y_stride,
61 dest->u, dest->u_stride,
62 dest->v, dest->v_stride,
63 dest->w, rows);
64 dest->y += rows * dest->y_stride;
65 dest->u += ((rows + 1) >> 1) * dest->u_stride;
66 dest->v += ((rows + 1) >> 1) * dest->v_stride;
67 dest->h -= rows;
68}
69
70static void JpegI444ToI420(void* opaque,
71 const uint8* const* data,
72 const int* strides,
73 int rows) {
74 I420Buffers* dest = static_cast<I420Buffers*>(opaque);
75 I444ToI420(data[0], strides[0],
76 data[1], strides[1],
77 data[2], strides[2],
78 dest->y, dest->y_stride,
79 dest->u, dest->u_stride,
80 dest->v, dest->v_stride,
81 dest->w, rows);
82 dest->y += rows * dest->y_stride;
83 dest->u += ((rows + 1) >> 1) * dest->u_stride;
84 dest->v += ((rows + 1) >> 1) * dest->v_stride;
85 dest->h -= rows;
86}
87
88static void JpegI411ToI420(void* opaque,
89 const uint8* const* data,
90 const int* strides,
91 int rows) {
92 I420Buffers* dest = static_cast<I420Buffers*>(opaque);
93 I411ToI420(data[0], strides[0],
94 data[1], strides[1],
95 data[2], strides[2],
96 dest->y, dest->y_stride,
97 dest->u, dest->u_stride,
98 dest->v, dest->v_stride,
99 dest->w, rows);
100 dest->y += rows * dest->y_stride;
101 dest->u += ((rows + 1) >> 1) * dest->u_stride;
102 dest->v += ((rows + 1) >> 1) * dest->v_stride;
103 dest->h -= rows;
104}
105
106static void JpegI400ToI420(void* opaque,
107 const uint8* const* data,
108 const int* strides,
109 int rows) {
110 I420Buffers* dest = static_cast<I420Buffers*>(opaque);
111 I400ToI420(data[0], strides[0],
112 dest->y, dest->y_stride,
113 dest->u, dest->u_stride,
114 dest->v, dest->v_stride,
115 dest->w, rows);
116 dest->y += rows * dest->y_stride;
117 dest->u += ((rows + 1) >> 1) * dest->u_stride;
118 dest->v += ((rows + 1) >> 1) * dest->v_stride;
119 dest->h -= rows;
120}
121
122// Query size of MJPG in pixels.
123LIBYUV_API
124int MJPGSize(const uint8* sample, size_t sample_size,
125 int* width, int* height) {
126 MJpegDecoder mjpeg_decoder;
127 bool ret = mjpeg_decoder.LoadFrame(sample, sample_size);
128 if (ret) {
129 *width = mjpeg_decoder.GetWidth();
130 *height = mjpeg_decoder.GetHeight();
131 }
132 mjpeg_decoder.UnloadFrame();
133 return ret ? 0 : -1; // -1 for runtime failure.
134}
135
136// MJPG (Motion JPeg) to I420
137// TODO(fbarchard): review w and h requirement. dw and dh may be enough.
138LIBYUV_API
139int MJPGToI420(const uint8* sample,
140 size_t sample_size,
141 uint8* y, int y_stride,
142 uint8* u, int u_stride,
143 uint8* v, int v_stride,
144 int w, int h,
145 int dw, int dh) {
146 if (sample_size == kUnknownDataSize) {
147 // ERROR: MJPEG frame size unknown
148 return -1;
149 }
150
151 // TODO(fbarchard): Port MJpeg to C.
152 MJpegDecoder mjpeg_decoder;
153 bool ret = mjpeg_decoder.LoadFrame(sample, sample_size);
154 if (ret && (mjpeg_decoder.GetWidth() != w ||
155 mjpeg_decoder.GetHeight() != h)) {
156 // ERROR: MJPEG frame has unexpected dimensions
157 mjpeg_decoder.UnloadFrame();
158 return 1; // runtime failure
159 }
160 if (ret) {
161 I420Buffers bufs = { y, y_stride, u, u_stride, v, v_stride, dw, dh };
162 // YUV420
163 if (mjpeg_decoder.GetColorSpace() ==
164 MJpegDecoder::kColorSpaceYCbCr &&
165 mjpeg_decoder.GetNumComponents() == 3 &&
166 mjpeg_decoder.GetVertSampFactor(0) == 2 &&
167 mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
168 mjpeg_decoder.GetVertSampFactor(1) == 1 &&
169 mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
170 mjpeg_decoder.GetVertSampFactor(2) == 1 &&
171 mjpeg_decoder.GetHorizSampFactor(2) == 1) {
172 ret = mjpeg_decoder.DecodeToCallback(&JpegCopyI420, &bufs, dw, dh);
173 // YUV422
174 } else if (mjpeg_decoder.GetColorSpace() ==
175 MJpegDecoder::kColorSpaceYCbCr &&
176 mjpeg_decoder.GetNumComponents() == 3 &&
177 mjpeg_decoder.GetVertSampFactor(0) == 1 &&
178 mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
179 mjpeg_decoder.GetVertSampFactor(1) == 1 &&
180 mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
181 mjpeg_decoder.GetVertSampFactor(2) == 1 &&
182 mjpeg_decoder.GetHorizSampFactor(2) == 1) {
183 ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToI420, &bufs, dw, dh);
184 // YUV444
185 } else if (mjpeg_decoder.GetColorSpace() ==
186 MJpegDecoder::kColorSpaceYCbCr &&
187 mjpeg_decoder.GetNumComponents() == 3 &&
188 mjpeg_decoder.GetVertSampFactor(0) == 1 &&
189 mjpeg_decoder.GetHorizSampFactor(0) == 1 &&
190 mjpeg_decoder.GetVertSampFactor(1) == 1 &&
191 mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
192 mjpeg_decoder.GetVertSampFactor(2) == 1 &&
193 mjpeg_decoder.GetHorizSampFactor(2) == 1) {
194 ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToI420, &bufs, dw, dh);
195 // YUV411
196 } else if (mjpeg_decoder.GetColorSpace() ==
197 MJpegDecoder::kColorSpaceYCbCr &&
198 mjpeg_decoder.GetNumComponents() == 3 &&
199 mjpeg_decoder.GetVertSampFactor(0) == 1 &&
200 mjpeg_decoder.GetHorizSampFactor(0) == 4 &&
201 mjpeg_decoder.GetVertSampFactor(1) == 1 &&
202 mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
203 mjpeg_decoder.GetVertSampFactor(2) == 1 &&
204 mjpeg_decoder.GetHorizSampFactor(2) == 1) {
205 ret = mjpeg_decoder.DecodeToCallback(&JpegI411ToI420, &bufs, dw, dh);
206 // YUV400
207 } else if (mjpeg_decoder.GetColorSpace() ==
208 MJpegDecoder::kColorSpaceGrayscale &&
209 mjpeg_decoder.GetNumComponents() == 1 &&
210 mjpeg_decoder.GetVertSampFactor(0) == 1 &&
211 mjpeg_decoder.GetHorizSampFactor(0) == 1) {
212 ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToI420, &bufs, dw, dh);
213 } else {
214 // TODO(fbarchard): Implement conversion for any other colorspace/sample
215 // factors that occur in practice. 411 is supported by libjpeg
216 // ERROR: Unable to convert MJPEG frame because format is not supported
217 mjpeg_decoder.UnloadFrame();
218 return 1;
219 }
220 }
221 return 0;
222}
223#endif
224
225#ifdef __cplusplus
226} // extern "C"
227} // namespace libyuv
228#endif