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_argb.h"
12
13 #include "libyuv/cpu_id.h"
14 #include "libyuv/format_conversion.h"
15 #ifdef HAVE_JPEG
16 #include "libyuv/mjpeg_decoder.h"
17 #endif
18 #include "libyuv/rotate_argb.h"
19 #include "libyuv/row.h"
20 #include "libyuv/video_common.h"
21
22 #ifdef __cplusplus
23 namespace libyuv {
24 extern "C" {
25 #endif
26
27 // Convert camera sample to I420 with cropping, rotation and vertical flip.
28 // src_width is used for source stride computation
29 // src_height is used to compute location of planes, and indicate inversion
30 // sample_size is measured in bytes and is the size of the frame.
31 // With MJPEG it is the compressed size of the frame.
32 LIBYUV_API
ConvertToARGB(const uint8 * sample,size_t sample_size,uint8 * crop_argb,int argb_stride,int crop_x,int crop_y,int src_width,int src_height,int crop_width,int crop_height,enum RotationMode rotation,uint32 fourcc)33 int ConvertToARGB(const uint8* sample, size_t sample_size,
34 uint8* crop_argb, int argb_stride,
35 int crop_x, int crop_y,
36 int src_width, int src_height,
37 int crop_width, int crop_height,
38 enum RotationMode rotation,
39 uint32 fourcc) {
40 uint32 format = CanonicalFourCC(fourcc);
41 int aligned_src_width = (src_width + 1) & ~1;
42 const uint8* src;
43 const uint8* src_uv;
44 int abs_src_height = (src_height < 0) ? -src_height : src_height;
45 int inv_crop_height = (crop_height < 0) ? -crop_height : crop_height;
46 int r = 0;
47
48 // One pass rotation is available for some formats. For the rest, convert
49 // to I420 (with optional vertical flipping) into a temporary I420 buffer,
50 // and then rotate the I420 to the final destination buffer.
51 // For in-place conversion, if destination crop_argb is same as source sample,
52 // also enable temporary buffer.
53 LIBYUV_BOOL need_buf = (rotation && format != FOURCC_ARGB) ||
54 crop_argb == sample;
55 uint8* tmp_argb = crop_argb;
56 int tmp_argb_stride = argb_stride;
57 uint8* rotate_buffer = NULL;
58 int abs_crop_height = (crop_height < 0) ? -crop_height : crop_height;
59
60 if (crop_argb == NULL || sample == NULL ||
61 src_width <= 0 || crop_width <= 0 ||
62 src_height == 0 || crop_height == 0) {
63 return -1;
64 }
65 if (src_height < 0) {
66 inv_crop_height = -inv_crop_height;
67 }
68
69 if (need_buf) {
70 int argb_size = crop_width * abs_crop_height * 4;
71 rotate_buffer = (uint8*)malloc(argb_size);
72 if (!rotate_buffer) {
73 return 1; // Out of memory runtime error.
74 }
75 crop_argb = rotate_buffer;
76 argb_stride = crop_width;
77 }
78
79 switch (format) {
80 // Single plane formats
81 case FOURCC_YUY2:
82 src = sample + (aligned_src_width * crop_y + crop_x) * 2;
83 r = YUY2ToARGB(src, aligned_src_width * 2,
84 crop_argb, argb_stride,
85 crop_width, inv_crop_height);
86 break;
87 case FOURCC_UYVY:
88 src = sample + (aligned_src_width * crop_y + crop_x) * 2;
89 r = UYVYToARGB(src, aligned_src_width * 2,
90 crop_argb, argb_stride,
91 crop_width, inv_crop_height);
92 break;
93 case FOURCC_24BG:
94 src = sample + (src_width * crop_y + crop_x) * 3;
95 r = RGB24ToARGB(src, src_width * 3,
96 crop_argb, argb_stride,
97 crop_width, inv_crop_height);
98 break;
99 case FOURCC_RAW:
100 src = sample + (src_width * crop_y + crop_x) * 3;
101 r = RAWToARGB(src, src_width * 3,
102 crop_argb, argb_stride,
103 crop_width, inv_crop_height);
104 break;
105 case FOURCC_ARGB:
106 src = sample + (src_width * crop_y + crop_x) * 4;
107 r = ARGBToARGB(src, src_width * 4,
108 crop_argb, argb_stride,
109 crop_width, inv_crop_height);
110 break;
111 case FOURCC_BGRA:
112 src = sample + (src_width * crop_y + crop_x) * 4;
113 r = BGRAToARGB(src, src_width * 4,
114 crop_argb, argb_stride,
115 crop_width, inv_crop_height);
116 break;
117 case FOURCC_ABGR:
118 src = sample + (src_width * crop_y + crop_x) * 4;
119 r = ABGRToARGB(src, src_width * 4,
120 crop_argb, argb_stride,
121 crop_width, inv_crop_height);
122 break;
123 case FOURCC_RGBA:
124 src = sample + (src_width * crop_y + crop_x) * 4;
125 r = RGBAToARGB(src, src_width * 4,
126 crop_argb, argb_stride,
127 crop_width, inv_crop_height);
128 break;
129 case FOURCC_RGBP:
130 src = sample + (src_width * crop_y + crop_x) * 2;
131 r = RGB565ToARGB(src, src_width * 2,
132 crop_argb, argb_stride,
133 crop_width, inv_crop_height);
134 break;
135 case FOURCC_RGBO:
136 src = sample + (src_width * crop_y + crop_x) * 2;
137 r = ARGB1555ToARGB(src, src_width * 2,
138 crop_argb, argb_stride,
139 crop_width, inv_crop_height);
140 break;
141 case FOURCC_R444:
142 src = sample + (src_width * crop_y + crop_x) * 2;
143 r = ARGB4444ToARGB(src, src_width * 2,
144 crop_argb, argb_stride,
145 crop_width, inv_crop_height);
146 break;
147 // TODO(fbarchard): Support cropping Bayer by odd numbers
148 // by adjusting fourcc.
149 case FOURCC_BGGR:
150 src = sample + (src_width * crop_y + crop_x);
151 r = BayerBGGRToARGB(src, src_width,
152 crop_argb, argb_stride,
153 crop_width, inv_crop_height);
154 break;
155
156 case FOURCC_GBRG:
157 src = sample + (src_width * crop_y + crop_x);
158 r = BayerGBRGToARGB(src, src_width,
159 crop_argb, argb_stride,
160 crop_width, inv_crop_height);
161 break;
162
163 case FOURCC_GRBG:
164 src = sample + (src_width * crop_y + crop_x);
165 r = BayerGRBGToARGB(src, src_width,
166 crop_argb, argb_stride,
167 crop_width, inv_crop_height);
168 break;
169
170 case FOURCC_RGGB:
171 src = sample + (src_width * crop_y + crop_x);
172 r = BayerRGGBToARGB(src, src_width,
173 crop_argb, argb_stride,
174 crop_width, inv_crop_height);
175 break;
176
177 case FOURCC_I400:
178 src = sample + src_width * crop_y + crop_x;
179 r = I400ToARGB(src, src_width,
180 crop_argb, argb_stride,
181 crop_width, inv_crop_height);
182 break;
183
184 // Biplanar formats
185 case FOURCC_NV12:
186 src = sample + (src_width * crop_y + crop_x);
187 src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x;
188 r = NV12ToARGB(src, src_width,
189 src_uv, aligned_src_width,
190 crop_argb, argb_stride,
191 crop_width, inv_crop_height);
192 break;
193 case FOURCC_NV21:
194 src = sample + (src_width * crop_y + crop_x);
195 src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x;
196 // Call NV12 but with u and v parameters swapped.
197 r = NV21ToARGB(src, src_width,
198 src_uv, aligned_src_width,
199 crop_argb, argb_stride,
200 crop_width, inv_crop_height);
201 break;
202 case FOURCC_M420:
203 src = sample + (src_width * crop_y) * 12 / 8 + crop_x;
204 r = M420ToARGB(src, src_width,
205 crop_argb, argb_stride,
206 crop_width, inv_crop_height);
207 break;
208 // case FOURCC_Q420:
209 // src = sample + (src_width + aligned_src_width * 2) * crop_y + crop_x;
210 // src_uv = sample + (src_width + aligned_src_width * 2) * crop_y +
211 // src_width + crop_x * 2;
212 // r = Q420ToARGB(src, src_width * 3,
213 // src_uv, src_width * 3,
214 // crop_argb, argb_stride,
215 // crop_width, inv_crop_height);
216 // break;
217 // Triplanar formats
218 case FOURCC_I420:
219 case FOURCC_YU12:
220 case FOURCC_YV12: {
221 const uint8* src_y = sample + (src_width * crop_y + crop_x);
222 const uint8* src_u;
223 const uint8* src_v;
224 int halfwidth = (src_width + 1) / 2;
225 int halfheight = (abs_src_height + 1) / 2;
226 if (format == FOURCC_YV12) {
227 src_v = sample + src_width * abs_src_height +
228 (halfwidth * crop_y + crop_x) / 2;
229 src_u = sample + src_width * abs_src_height +
230 halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
231 } else {
232 src_u = sample + src_width * abs_src_height +
233 (halfwidth * crop_y + crop_x) / 2;
234 src_v = sample + src_width * abs_src_height +
235 halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
236 }
237 r = I420ToARGB(src_y, src_width,
238 src_u, halfwidth,
239 src_v, halfwidth,
240 crop_argb, argb_stride,
241 crop_width, inv_crop_height);
242 break;
243 }
244 case FOURCC_I422:
245 case FOURCC_YV16: {
246 const uint8* src_y = sample + src_width * crop_y + crop_x;
247 const uint8* src_u;
248 const uint8* src_v;
249 int halfwidth = (src_width + 1) / 2;
250 if (format == FOURCC_YV16) {
251 src_v = sample + src_width * abs_src_height +
252 halfwidth * crop_y + crop_x / 2;
253 src_u = sample + src_width * abs_src_height +
254 halfwidth * (abs_src_height + crop_y) + crop_x / 2;
255 } else {
256 src_u = sample + src_width * abs_src_height +
257 halfwidth * crop_y + crop_x / 2;
258 src_v = sample + src_width * abs_src_height +
259 halfwidth * (abs_src_height + crop_y) + crop_x / 2;
260 }
261 r = I422ToARGB(src_y, src_width,
262 src_u, halfwidth,
263 src_v, halfwidth,
264 crop_argb, argb_stride,
265 crop_width, inv_crop_height);
266 break;
267 }
268 case FOURCC_I444:
269 case FOURCC_YV24: {
270 const uint8* src_y = sample + src_width * crop_y + crop_x;
271 const uint8* src_u;
272 const uint8* src_v;
273 if (format == FOURCC_YV24) {
274 src_v = sample + src_width * (abs_src_height + crop_y) + crop_x;
275 src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
276 } else {
277 src_u = sample + src_width * (abs_src_height + crop_y) + crop_x;
278 src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
279 }
280 r = I444ToARGB(src_y, src_width,
281 src_u, src_width,
282 src_v, src_width,
283 crop_argb, argb_stride,
284 crop_width, inv_crop_height);
285 break;
286 }
287 case FOURCC_I411: {
288 int quarterwidth = (src_width + 3) / 4;
289 const uint8* src_y = sample + src_width * crop_y + crop_x;
290 const uint8* src_u = sample + src_width * abs_src_height +
291 quarterwidth * crop_y + crop_x / 4;
292 const uint8* src_v = sample + src_width * abs_src_height +
293 quarterwidth * (abs_src_height + crop_y) + crop_x / 4;
294 r = I411ToARGB(src_y, src_width,
295 src_u, quarterwidth,
296 src_v, quarterwidth,
297 crop_argb, argb_stride,
298 crop_width, inv_crop_height);
299 break;
300 }
301 #ifdef HAVE_JPEG
302 case FOURCC_MJPG:
303 r = MJPGToARGB(sample, sample_size,
304 crop_argb, argb_stride,
305 src_width, abs_src_height, crop_width, inv_crop_height);
306 break;
307 #endif
308 default:
309 r = -1; // unknown fourcc - return failure code.
310 }
311
312 if (need_buf) {
313 if (!r) {
314 r = ARGBRotate(crop_argb, argb_stride,
315 tmp_argb, tmp_argb_stride,
316 crop_width, abs_crop_height, rotation);
317 }
318 free(rotate_buffer);
319 }
320
321 return r;
322 }
323
324 #ifdef __cplusplus
325 } // extern "C"
326 } // namespace libyuv
327 #endif
328