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