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 <string.h> // for memset()
14
15 #include "libyuv/cpu_id.h"
16 #include "libyuv/format_conversion.h"
17 #ifdef HAVE_JPEG
18 #include "libyuv/mjpeg_decoder.h"
19 #endif
20 #include "libyuv/rotate_argb.h"
21 #include "libyuv/video_common.h"
22 #include "libyuv/row.h"
23
24 #ifdef __cplusplus
25 namespace libyuv {
26 extern "C" {
27 #endif
28
29 // Copy ARGB with optional flipping
30 LIBYUV_API
ARGBCopy(const uint8 * src_argb,int src_stride_argb,uint8 * dst_argb,int dst_stride_argb,int width,int height)31 int ARGBCopy(const uint8* src_argb, int src_stride_argb,
32 uint8* dst_argb, int dst_stride_argb,
33 int width, int height) {
34 if (!src_argb || !dst_argb ||
35 width <= 0 || height == 0) {
36 return -1;
37 }
38 // Negative height means invert the image.
39 if (height < 0) {
40 height = -height;
41 src_argb = src_argb + (height - 1) * src_stride_argb;
42 src_stride_argb = -src_stride_argb;
43 }
44
45 CopyPlane(src_argb, src_stride_argb, dst_argb, dst_stride_argb,
46 width * 4, height);
47 return 0;
48 }
49
50 // Convert I444 to ARGB.
51 LIBYUV_API
I444ToARGB(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_argb,int dst_stride_argb,int width,int height)52 int I444ToARGB(const uint8* src_y, int src_stride_y,
53 const uint8* src_u, int src_stride_u,
54 const uint8* src_v, int src_stride_v,
55 uint8* dst_argb, int dst_stride_argb,
56 int width, int height) {
57 if (!src_y || !src_u || !src_v ||
58 !dst_argb ||
59 width <= 0 || height == 0) {
60 return -1;
61 }
62 // Negative height means invert the image.
63 if (height < 0) {
64 height = -height;
65 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
66 dst_stride_argb = -dst_stride_argb;
67 }
68 void (*I444ToARGBRow)(const uint8* y_buf,
69 const uint8* u_buf,
70 const uint8* v_buf,
71 uint8* rgb_buf,
72 int width) = I444ToARGBRow_C;
73 #if defined(HAS_I444TOARGBROW_SSSE3)
74 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
75 I444ToARGBRow = I444ToARGBRow_Any_SSSE3;
76 if (IS_ALIGNED(width, 8)) {
77 I444ToARGBRow = I444ToARGBRow_Unaligned_SSSE3;
78 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
79 I444ToARGBRow = I444ToARGBRow_SSSE3;
80 }
81 }
82 }
83 #endif
84
85 for (int y = 0; y < height; ++y) {
86 I444ToARGBRow(src_y, src_u, src_v, dst_argb, width);
87 dst_argb += dst_stride_argb;
88 src_y += src_stride_y;
89 src_u += src_stride_u;
90 src_v += src_stride_v;
91 }
92 return 0;
93 }
94
95 // Convert I422 to ARGB.
96 LIBYUV_API
I422ToARGB(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_argb,int dst_stride_argb,int width,int height)97 int I422ToARGB(const uint8* src_y, int src_stride_y,
98 const uint8* src_u, int src_stride_u,
99 const uint8* src_v, int src_stride_v,
100 uint8* dst_argb, int dst_stride_argb,
101 int width, int height) {
102 if (!src_y || !src_u || !src_v ||
103 !dst_argb ||
104 width <= 0 || height == 0) {
105 return -1;
106 }
107 // Negative height means invert the image.
108 if (height < 0) {
109 height = -height;
110 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
111 dst_stride_argb = -dst_stride_argb;
112 }
113 void (*I422ToARGBRow)(const uint8* y_buf,
114 const uint8* u_buf,
115 const uint8* v_buf,
116 uint8* rgb_buf,
117 int width) = I422ToARGBRow_C;
118 #if defined(HAS_I422TOARGBROW_NEON)
119 if (TestCpuFlag(kCpuHasNEON)) {
120 I422ToARGBRow = I422ToARGBRow_Any_NEON;
121 if (IS_ALIGNED(width, 16)) {
122 I422ToARGBRow = I422ToARGBRow_NEON;
123 }
124 }
125 #elif defined(HAS_I422TOARGBROW_SSSE3)
126 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
127 I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
128 if (IS_ALIGNED(width, 8)) {
129 I422ToARGBRow = I422ToARGBRow_Unaligned_SSSE3;
130 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
131 I422ToARGBRow = I422ToARGBRow_SSSE3;
132 }
133 }
134 }
135 #endif
136
137 for (int y = 0; y < height; ++y) {
138 I422ToARGBRow(src_y, src_u, src_v, dst_argb, width);
139 dst_argb += dst_stride_argb;
140 src_y += src_stride_y;
141 src_u += src_stride_u;
142 src_v += src_stride_v;
143 }
144 return 0;
145 }
146
147 // Convert I411 to ARGB.
148 LIBYUV_API
I411ToARGB(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_argb,int dst_stride_argb,int width,int height)149 int I411ToARGB(const uint8* src_y, int src_stride_y,
150 const uint8* src_u, int src_stride_u,
151 const uint8* src_v, int src_stride_v,
152 uint8* dst_argb, int dst_stride_argb,
153 int width, int height) {
154 if (!src_y || !src_u || !src_v ||
155 !dst_argb ||
156 width <= 0 || height == 0) {
157 return -1;
158 }
159 // Negative height means invert the image.
160 if (height < 0) {
161 height = -height;
162 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
163 dst_stride_argb = -dst_stride_argb;
164 }
165 void (*I411ToARGBRow)(const uint8* y_buf,
166 const uint8* u_buf,
167 const uint8* v_buf,
168 uint8* rgb_buf,
169 int width) = I411ToARGBRow_C;
170 #if defined(HAS_I411TOARGBROW_SSSE3)
171 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
172 I411ToARGBRow = I411ToARGBRow_Any_SSSE3;
173 if (IS_ALIGNED(width, 8)) {
174 I411ToARGBRow = I411ToARGBRow_Unaligned_SSSE3;
175 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
176 I411ToARGBRow = I411ToARGBRow_SSSE3;
177 }
178 }
179 }
180 #endif
181
182 for (int y = 0; y < height; ++y) {
183 I411ToARGBRow(src_y, src_u, src_v, dst_argb, width);
184 dst_argb += dst_stride_argb;
185 src_y += src_stride_y;
186 src_u += src_stride_u;
187 src_v += src_stride_v;
188 }
189 return 0;
190 }
191
192
193 // Convert I400 to ARGB.
194 LIBYUV_API
I400ToARGB_Reference(const uint8 * src_y,int src_stride_y,uint8 * dst_argb,int dst_stride_argb,int width,int height)195 int I400ToARGB_Reference(const uint8* src_y, int src_stride_y,
196 uint8* dst_argb, int dst_stride_argb,
197 int width, int height) {
198 if (!src_y || !dst_argb ||
199 width <= 0 || height == 0) {
200 return -1;
201 }
202 // Negative height means invert the image.
203 if (height < 0) {
204 height = -height;
205 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
206 dst_stride_argb = -dst_stride_argb;
207 }
208 void (*YToARGBRow)(const uint8* y_buf,
209 uint8* rgb_buf,
210 int width) = YToARGBRow_C;
211 #if defined(HAS_YTOARGBROW_SSE2)
212 if (TestCpuFlag(kCpuHasSSE2) &&
213 IS_ALIGNED(width, 8) &&
214 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
215 YToARGBRow = YToARGBRow_SSE2;
216 }
217 #endif
218
219 for (int y = 0; y < height; ++y) {
220 YToARGBRow(src_y, dst_argb, width);
221 dst_argb += dst_stride_argb;
222 src_y += src_stride_y;
223 }
224 return 0;
225 }
226
227 // Convert I400 to ARGB.
228 LIBYUV_API
I400ToARGB(const uint8 * src_y,int src_stride_y,uint8 * dst_argb,int dst_stride_argb,int width,int height)229 int I400ToARGB(const uint8* src_y, int src_stride_y,
230 uint8* dst_argb, int dst_stride_argb,
231 int width, int height) {
232 if (!src_y || !dst_argb ||
233 width <= 0 || height == 0) {
234 return -1;
235 }
236 // Negative height means invert the image.
237 if (height < 0) {
238 height = -height;
239 src_y = src_y + (height - 1) * src_stride_y;
240 src_stride_y = -src_stride_y;
241 }
242 void (*I400ToARGBRow)(const uint8* src_y, uint8* dst_argb, int pix) =
243 I400ToARGBRow_C;
244 #if defined(HAS_I400TOARGBROW_SSE2)
245 if (TestCpuFlag(kCpuHasSSE2) &&
246 IS_ALIGNED(width, 8) &&
247 IS_ALIGNED(src_y, 8) && IS_ALIGNED(src_stride_y, 8) &&
248 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
249 I400ToARGBRow = I400ToARGBRow_SSE2;
250 }
251 #endif
252
253 for (int y = 0; y < height; ++y) {
254 I400ToARGBRow(src_y, dst_argb, width);
255 src_y += src_stride_y;
256 dst_argb += dst_stride_argb;
257 }
258 return 0;
259 }
260
261 // Convert BGRA to ARGB.
262 LIBYUV_API
BGRAToARGB(const uint8 * src_bgra,int src_stride_bgra,uint8 * dst_argb,int dst_stride_argb,int width,int height)263 int BGRAToARGB(const uint8* src_bgra, int src_stride_bgra,
264 uint8* dst_argb, int dst_stride_argb,
265 int width, int height) {
266 if (!src_bgra || !dst_argb ||
267 width <= 0 || height == 0) {
268 return -1;
269 }
270 // Negative height means invert the image.
271 if (height < 0) {
272 height = -height;
273 src_bgra = src_bgra + (height - 1) * src_stride_bgra;
274 src_stride_bgra = -src_stride_bgra;
275 }
276 void (*BGRAToARGBRow)(const uint8* src_bgra, uint8* dst_argb, int pix) =
277 BGRAToARGBRow_C;
278 #if defined(HAS_BGRATOARGBROW_SSSE3)
279 if (TestCpuFlag(kCpuHasSSSE3) &&
280 IS_ALIGNED(width, 4) &&
281 IS_ALIGNED(src_bgra, 16) && IS_ALIGNED(src_stride_bgra, 16) &&
282 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
283 BGRAToARGBRow = BGRAToARGBRow_SSSE3;
284 }
285 #endif
286
287 for (int y = 0; y < height; ++y) {
288 BGRAToARGBRow(src_bgra, dst_argb, width);
289 src_bgra += src_stride_bgra;
290 dst_argb += dst_stride_argb;
291 }
292 return 0;
293 }
294
295 // Convert ABGR to ARGB.
296 LIBYUV_API
ABGRToARGB(const uint8 * src_abgr,int src_stride_abgr,uint8 * dst_argb,int dst_stride_argb,int width,int height)297 int ABGRToARGB(const uint8* src_abgr, int src_stride_abgr,
298 uint8* dst_argb, int dst_stride_argb,
299 int width, int height) {
300 if (!src_abgr || !dst_argb ||
301 width <= 0 || height == 0) {
302 return -1;
303 }
304 // Negative height means invert the image.
305 if (height < 0) {
306 height = -height;
307 src_abgr = src_abgr + (height - 1) * src_stride_abgr;
308 src_stride_abgr = -src_stride_abgr;
309 }
310 void (*ABGRToARGBRow)(const uint8* src_abgr, uint8* dst_argb, int pix) =
311 ABGRToARGBRow_C;
312 #if defined(HAS_ABGRTOARGBROW_SSSE3)
313 if (TestCpuFlag(kCpuHasSSSE3) &&
314 IS_ALIGNED(width, 4) &&
315 IS_ALIGNED(src_abgr, 16) && IS_ALIGNED(src_stride_abgr, 16) &&
316 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
317 ABGRToARGBRow = ABGRToARGBRow_SSSE3;
318 }
319 #endif
320
321 for (int y = 0; y < height; ++y) {
322 ABGRToARGBRow(src_abgr, dst_argb, width);
323 src_abgr += src_stride_abgr;
324 dst_argb += dst_stride_argb;
325 }
326 return 0;
327 }
328
329 // Convert RGBA to ARGB.
330 LIBYUV_API
RGBAToARGB(const uint8 * src_rgba,int src_stride_rgba,uint8 * dst_argb,int dst_stride_argb,int width,int height)331 int RGBAToARGB(const uint8* src_rgba, int src_stride_rgba,
332 uint8* dst_argb, int dst_stride_argb,
333 int width, int height) {
334 if (!src_rgba || !dst_argb ||
335 width <= 0 || height == 0) {
336 return -1;
337 }
338 // Negative height means invert the image.
339 if (height < 0) {
340 height = -height;
341 src_rgba = src_rgba + (height - 1) * src_stride_rgba;
342 src_stride_rgba = -src_stride_rgba;
343 }
344 void (*RGBAToARGBRow)(const uint8* src_rgba, uint8* dst_argb, int pix) =
345 RGBAToARGBRow_C;
346 #if defined(HAS_RGBATOARGBROW_SSSE3)
347 if (TestCpuFlag(kCpuHasSSSE3) &&
348 IS_ALIGNED(width, 4) &&
349 IS_ALIGNED(src_rgba, 16) && IS_ALIGNED(src_stride_rgba, 16) &&
350 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
351 RGBAToARGBRow = RGBAToARGBRow_SSSE3;
352 }
353 #endif
354
355 for (int y = 0; y < height; ++y) {
356 RGBAToARGBRow(src_rgba, dst_argb, width);
357 src_rgba += src_stride_rgba;
358 dst_argb += dst_stride_argb;
359 }
360 return 0;
361 }
362
363 // Convert RAW to ARGB.
364 LIBYUV_API
RAWToARGB(const uint8 * src_raw,int src_stride_raw,uint8 * dst_argb,int dst_stride_argb,int width,int height)365 int RAWToARGB(const uint8* src_raw, int src_stride_raw,
366 uint8* dst_argb, int dst_stride_argb,
367 int width, int height) {
368 if (!src_raw || !dst_argb ||
369 width <= 0 || height == 0) {
370 return -1;
371 }
372 // Negative height means invert the image.
373 if (height < 0) {
374 height = -height;
375 src_raw = src_raw + (height - 1) * src_stride_raw;
376 src_stride_raw = -src_stride_raw;
377 }
378 void (*RAWToARGBRow)(const uint8* src_raw, uint8* dst_argb, int pix) =
379 RAWToARGBRow_C;
380 #if defined(HAS_RAWTOARGBROW_SSSE3)
381 if (TestCpuFlag(kCpuHasSSSE3) &&
382 IS_ALIGNED(width, 16) &&
383 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
384 RAWToARGBRow = RAWToARGBRow_SSSE3;
385 }
386 #endif
387
388 for (int y = 0; y < height; ++y) {
389 RAWToARGBRow(src_raw, dst_argb, width);
390 src_raw += src_stride_raw;
391 dst_argb += dst_stride_argb;
392 }
393 return 0;
394 }
395
396 // Convert RGB24 to ARGB.
397 LIBYUV_API
RGB24ToARGB(const uint8 * src_rgb24,int src_stride_rgb24,uint8 * dst_argb,int dst_stride_argb,int width,int height)398 int RGB24ToARGB(const uint8* src_rgb24, int src_stride_rgb24,
399 uint8* dst_argb, int dst_stride_argb,
400 int width, int height) {
401 if (!src_rgb24 || !dst_argb ||
402 width <= 0 || height == 0) {
403 return -1;
404 }
405 // Negative height means invert the image.
406 if (height < 0) {
407 height = -height;
408 src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
409 src_stride_rgb24 = -src_stride_rgb24;
410 }
411 void (*RGB24ToARGBRow)(const uint8* src_rgb24, uint8* dst_argb, int pix) =
412 RGB24ToARGBRow_C;
413 #if defined(HAS_RGB24TOARGBROW_SSSE3)
414 if (TestCpuFlag(kCpuHasSSSE3) &&
415 IS_ALIGNED(width, 16) &&
416 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
417 RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
418 }
419 #endif
420
421 for (int y = 0; y < height; ++y) {
422 RGB24ToARGBRow(src_rgb24, dst_argb, width);
423 src_rgb24 += src_stride_rgb24;
424 dst_argb += dst_stride_argb;
425 }
426 return 0;
427 }
428
429 // Convert RGB565 to ARGB.
430 LIBYUV_API
RGB565ToARGB(const uint8 * src_rgb565,int src_stride_rgb565,uint8 * dst_argb,int dst_stride_argb,int width,int height)431 int RGB565ToARGB(const uint8* src_rgb565, int src_stride_rgb565,
432 uint8* dst_argb, int dst_stride_argb,
433 int width, int height) {
434 if (!src_rgb565 || !dst_argb ||
435 width <= 0 || height == 0) {
436 return -1;
437 }
438 // Negative height means invert the image.
439 if (height < 0) {
440 height = -height;
441 src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
442 src_stride_rgb565 = -src_stride_rgb565;
443 }
444 void (*RGB565ToARGBRow)(const uint8* src_rgb565, uint8* dst_argb, int pix) =
445 RGB565ToARGBRow_C;
446 #if defined(HAS_RGB565TOARGBROW_SSE2)
447 if (TestCpuFlag(kCpuHasSSE2) &&
448 IS_ALIGNED(width, 8) &&
449 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
450 RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
451 }
452 #endif
453
454 for (int y = 0; y < height; ++y) {
455 RGB565ToARGBRow(src_rgb565, dst_argb, width);
456 src_rgb565 += src_stride_rgb565;
457 dst_argb += dst_stride_argb;
458 }
459 return 0;
460 }
461
462 // Convert ARGB1555 to ARGB.
463 LIBYUV_API
ARGB1555ToARGB(const uint8 * src_argb1555,int src_stride_argb1555,uint8 * dst_argb,int dst_stride_argb,int width,int height)464 int ARGB1555ToARGB(const uint8* src_argb1555, int src_stride_argb1555,
465 uint8* dst_argb, int dst_stride_argb,
466 int width, int height) {
467 if (!src_argb1555 || !dst_argb ||
468 width <= 0 || height == 0) {
469 return -1;
470 }
471 // Negative height means invert the image.
472 if (height < 0) {
473 height = -height;
474 src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
475 src_stride_argb1555 = -src_stride_argb1555;
476 }
477 void (*ARGB1555ToARGBRow)(const uint8* src_argb1555, uint8* dst_argb,
478 int pix) = ARGB1555ToARGBRow_C;
479 #if defined(HAS_ARGB1555TOARGBROW_SSE2)
480 if (TestCpuFlag(kCpuHasSSE2) &&
481 IS_ALIGNED(width, 8) &&
482 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
483 ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
484 }
485 #endif
486
487 for (int y = 0; y < height; ++y) {
488 ARGB1555ToARGBRow(src_argb1555, dst_argb, width);
489 src_argb1555 += src_stride_argb1555;
490 dst_argb += dst_stride_argb;
491 }
492 return 0;
493 }
494
495 // Convert ARGB4444 to ARGB.
496 LIBYUV_API
ARGB4444ToARGB(const uint8 * src_argb4444,int src_stride_argb4444,uint8 * dst_argb,int dst_stride_argb,int width,int height)497 int ARGB4444ToARGB(const uint8* src_argb4444, int src_stride_argb4444,
498 uint8* dst_argb, int dst_stride_argb,
499 int width, int height) {
500 if (!src_argb4444 || !dst_argb ||
501 width <= 0 || height == 0) {
502 return -1;
503 }
504 // Negative height means invert the image.
505 if (height < 0) {
506 height = -height;
507 src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
508 src_stride_argb4444 = -src_stride_argb4444;
509 }
510 void (*ARGB4444ToARGBRow)(const uint8* src_argb4444, uint8* dst_argb,
511 int pix) = ARGB4444ToARGBRow_C;
512 #if defined(HAS_ARGB4444TOARGBROW_SSE2)
513 if (TestCpuFlag(kCpuHasSSE2) &&
514 IS_ALIGNED(width, 8) &&
515 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
516 ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
517 }
518 #endif
519
520 for (int y = 0; y < height; ++y) {
521 ARGB4444ToARGBRow(src_argb4444, dst_argb, width);
522 src_argb4444 += src_stride_argb4444;
523 dst_argb += dst_stride_argb;
524 }
525 return 0;
526 }
527
528 // Convert NV12 to ARGB.
529 LIBYUV_API
NV12ToARGB(const uint8 * src_y,int src_stride_y,const uint8 * src_uv,int src_stride_uv,uint8 * dst_argb,int dst_stride_argb,int width,int height)530 int NV12ToARGB(const uint8* src_y, int src_stride_y,
531 const uint8* src_uv, int src_stride_uv,
532 uint8* dst_argb, int dst_stride_argb,
533 int width, int height) {
534 if (!src_y || !src_uv || !dst_argb ||
535 width <= 0 || height == 0) {
536 return -1;
537 }
538 // Negative height means invert the image.
539 if (height < 0) {
540 height = -height;
541 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
542 dst_stride_argb = -dst_stride_argb;
543 }
544 void (*NV12ToARGBRow)(const uint8* y_buf,
545 const uint8* uv_buf,
546 uint8* rgb_buf,
547 int width) = NV12ToARGBRow_C;
548 #if defined(HAS_NV12TOARGBROW_SSSE3)
549 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
550 NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
551 if (IS_ALIGNED(width, 8)) {
552 NV12ToARGBRow = NV12ToARGBRow_Unaligned_SSSE3;
553 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
554 NV12ToARGBRow = NV12ToARGBRow_SSSE3;
555 }
556 }
557 }
558 #endif
559 #if defined(HAS_NV12TOARGBROW_NEON)
560 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
561 NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
562 if (IS_ALIGNED(width, 8)) {
563 NV12ToARGBRow = NV12ToARGBRow_NEON;
564 }
565 }
566 #endif
567
568 for (int y = 0; y < height; ++y) {
569 NV12ToARGBRow(src_y, src_uv, dst_argb, width);
570 dst_argb += dst_stride_argb;
571 src_y += src_stride_y;
572 if (y & 1) {
573 src_uv += src_stride_uv;
574 }
575 }
576 return 0;
577 }
578
579 // Convert NV21 to ARGB.
580 LIBYUV_API
NV21ToARGB(const uint8 * src_y,int src_stride_y,const uint8 * src_uv,int src_stride_uv,uint8 * dst_argb,int dst_stride_argb,int width,int height)581 int NV21ToARGB(const uint8* src_y, int src_stride_y,
582 const uint8* src_uv, int src_stride_uv,
583 uint8* dst_argb, int dst_stride_argb,
584 int width, int height) {
585 if (!src_y || !src_uv || !dst_argb ||
586 width <= 0 || height == 0) {
587 return -1;
588 }
589 // Negative height means invert the image.
590 if (height < 0) {
591 height = -height;
592 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
593 dst_stride_argb = -dst_stride_argb;
594 }
595 void (*NV21ToARGBRow)(const uint8* y_buf,
596 const uint8* uv_buf,
597 uint8* rgb_buf,
598 int width) = NV21ToARGBRow_C;
599 #if defined(HAS_NV21TOARGBROW_SSSE3)
600 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
601 NV21ToARGBRow = NV21ToARGBRow_Any_SSSE3;
602 if (IS_ALIGNED(width, 8)) {
603 NV21ToARGBRow = NV21ToARGBRow_Unaligned_SSSE3;
604 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
605 NV21ToARGBRow = NV21ToARGBRow_SSSE3;
606 }
607 }
608 }
609 #endif
610 #if defined(HAS_NV21TOARGBROW_NEON)
611 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
612 NV21ToARGBRow = NV21ToARGBRow_Any_NEON;
613 if (IS_ALIGNED(width, 8)) {
614 NV21ToARGBRow = NV21ToARGBRow_NEON;
615 }
616 }
617 #endif
618
619 for (int y = 0; y < height; ++y) {
620 NV21ToARGBRow(src_y, src_uv, dst_argb, width);
621 dst_argb += dst_stride_argb;
622 src_y += src_stride_y;
623 if (y & 1) {
624 src_uv += src_stride_uv;
625 }
626 }
627 return 0;
628 }
629
630 // Convert M420 to ARGB.
631 LIBYUV_API
M420ToARGB(const uint8 * src_m420,int src_stride_m420,uint8 * dst_argb,int dst_stride_argb,int width,int height)632 int M420ToARGB(const uint8* src_m420, int src_stride_m420,
633 uint8* dst_argb, int dst_stride_argb,
634 int width, int height) {
635 if (!src_m420 || !dst_argb ||
636 width <= 0 || height == 0) {
637 return -1;
638 }
639 // Negative height means invert the image.
640 if (height < 0) {
641 height = -height;
642 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
643 dst_stride_argb = -dst_stride_argb;
644 }
645 void (*NV12ToARGBRow)(const uint8* y_buf,
646 const uint8* uv_buf,
647 uint8* rgb_buf,
648 int width) = NV12ToARGBRow_C;
649 #if defined(HAS_NV12TOARGBROW_SSSE3)
650 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
651 NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
652 if (IS_ALIGNED(width, 8)) {
653 NV12ToARGBRow = NV12ToARGBRow_Unaligned_SSSE3;
654 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
655 NV12ToARGBRow = NV12ToARGBRow_SSSE3;
656 }
657 }
658 }
659 #endif
660
661 for (int y = 0; y < height - 1; y += 2) {
662 NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb, width);
663 NV12ToARGBRow(src_m420 + src_stride_m420, src_m420 + src_stride_m420 * 2,
664 dst_argb + dst_stride_argb, width);
665 dst_argb += dst_stride_argb * 2;
666 src_m420 += src_stride_m420 * 3;
667 }
668 if (height & 1) {
669 NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb, width);
670 }
671 return 0;
672 }
673
674 // Convert YUY2 to ARGB.
675 LIBYUV_API
YUY2ToARGB(const uint8 * src_yuy2,int src_stride_yuy2,uint8 * dst_argb,int dst_stride_argb,int width,int height)676 int YUY2ToARGB(const uint8* src_yuy2, int src_stride_yuy2,
677 uint8* dst_argb, int dst_stride_argb,
678 int width, int height) {
679 if (!src_yuy2 || !dst_argb ||
680 width <= 0 || height == 0) {
681 return -1;
682 }
683 // Negative height means invert the image.
684 if (height < 0) {
685 height = -height;
686 src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
687 src_stride_yuy2 = -src_stride_yuy2;
688 }
689 void (*YUY2ToUV422Row)(const uint8* src_yuy2, uint8* dst_u, uint8* dst_v,
690 int pix) = YUY2ToUV422Row_C;
691 void (*YUY2ToYRow)(const uint8* src_yuy2,
692 uint8* dst_y, int pix) = YUY2ToYRow_C;
693 #if defined(HAS_YUY2TOYROW_SSE2)
694 if (TestCpuFlag(kCpuHasSSE2)) {
695 if (width > 16) {
696 YUY2ToUV422Row = YUY2ToUV422Row_Any_SSE2;
697 YUY2ToYRow = YUY2ToYRow_Any_SSE2;
698 }
699 if (IS_ALIGNED(width, 16)) {
700 YUY2ToUV422Row = YUY2ToUV422Row_Unaligned_SSE2;
701 YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2;
702 if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) {
703 YUY2ToUV422Row = YUY2ToUV422Row_SSE2;
704 YUY2ToYRow = YUY2ToYRow_SSE2;
705 }
706 }
707 }
708 #elif defined(HAS_YUY2TOYROW_NEON)
709 if (TestCpuFlag(kCpuHasNEON)) {
710 if (width > 8) {
711 YUY2ToYRow = YUY2ToYRow_Any_NEON;
712 if (width > 16) {
713 YUY2ToUV422Row = YUY2ToUV422Row_Any_NEON;
714 }
715 }
716 if (IS_ALIGNED(width, 8)) {
717 YUY2ToYRow = YUY2ToYRow_NEON;
718 if (IS_ALIGNED(width, 16)) {
719 YUY2ToUV422Row = YUY2ToUV422Row_NEON;
720 }
721 }
722 }
723 #endif
724
725 void (*I422ToARGBRow)(const uint8* y_buf,
726 const uint8* u_buf,
727 const uint8* v_buf,
728 uint8* argb_buf,
729 int width) = I422ToARGBRow_C;
730 #if defined(HAS_I422TOARGBROW_NEON)
731 if (TestCpuFlag(kCpuHasNEON)) {
732 I422ToARGBRow = I422ToARGBRow_Any_NEON;
733 if (IS_ALIGNED(width, 16)) {
734 I422ToARGBRow = I422ToARGBRow_NEON;
735 }
736 }
737 #elif defined(HAS_I422TOARGBROW_SSSE3)
738 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
739 I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
740 if (IS_ALIGNED(width, 8) &&
741 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
742 I422ToARGBRow = I422ToARGBRow_SSSE3;
743 }
744 }
745 #endif
746
747 SIMD_ALIGNED(uint8 rowy[kMaxStride]);
748 SIMD_ALIGNED(uint8 rowu[kMaxStride]);
749 SIMD_ALIGNED(uint8 rowv[kMaxStride]);
750
751 for (int y = 0; y < height; ++y) {
752 YUY2ToUV422Row(src_yuy2, rowu, rowv, width);
753 YUY2ToYRow(src_yuy2, rowy, width);
754 I422ToARGBRow(rowy, rowu, rowv, dst_argb, width);
755 src_yuy2 += src_stride_yuy2;
756 dst_argb += dst_stride_argb;
757 }
758 return 0;
759 }
760
761 // Convert UYVY to ARGB.
762 LIBYUV_API
UYVYToARGB(const uint8 * src_uyvy,int src_stride_uyvy,uint8 * dst_argb,int dst_stride_argb,int width,int height)763 int UYVYToARGB(const uint8* src_uyvy, int src_stride_uyvy,
764 uint8* dst_argb, int dst_stride_argb,
765 int width, int height) {
766 if (!src_uyvy || !dst_argb ||
767 width <= 0 || height == 0) {
768 return -1;
769 }
770 // Negative height means invert the image.
771 if (height < 0) {
772 height = -height;
773 src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
774 src_stride_uyvy = -src_stride_uyvy;
775 }
776 void (*UYVYToUV422Row)(const uint8* src_uyvy, uint8* dst_u, uint8* dst_v,
777 int pix) = UYVYToUV422Row_C;
778 void (*UYVYToYRow)(const uint8* src_uyvy,
779 uint8* dst_y, int pix) = UYVYToYRow_C;
780 #if defined(HAS_UYVYTOYROW_SSE2)
781 if (TestCpuFlag(kCpuHasSSE2)) {
782 if (width > 16) {
783 UYVYToUV422Row = UYVYToUV422Row_Any_SSE2;
784 UYVYToYRow = UYVYToYRow_Any_SSE2;
785 }
786 if (IS_ALIGNED(width, 16)) {
787 UYVYToUV422Row = UYVYToUV422Row_Unaligned_SSE2;
788 UYVYToYRow = UYVYToYRow_Unaligned_SSE2;
789 if (IS_ALIGNED(src_uyvy, 16) && IS_ALIGNED(src_stride_uyvy, 16)) {
790 UYVYToUV422Row = UYVYToUV422Row_SSE2;
791 UYVYToYRow = UYVYToYRow_SSE2;
792 }
793 }
794 }
795 #endif
796 void (*I422ToARGBRow)(const uint8* y_buf,
797 const uint8* u_buf,
798 const uint8* v_buf,
799 uint8* argb_buf,
800 int width) = I422ToARGBRow_C;
801 #if defined(HAS_I422TOARGBROW_NEON)
802 if (TestCpuFlag(kCpuHasNEON)) {
803 I422ToARGBRow = I422ToARGBRow_Any_NEON;
804 if (IS_ALIGNED(width, 16)) {
805 I422ToARGBRow = I422ToARGBRow_NEON;
806 }
807 }
808 #elif defined(HAS_I422TOARGBROW_SSSE3)
809 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
810 I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
811 if (IS_ALIGNED(width, 8) &&
812 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
813 I422ToARGBRow = I422ToARGBRow_SSSE3;
814 }
815 }
816 #endif
817
818 SIMD_ALIGNED(uint8 rowy[kMaxStride]);
819 SIMD_ALIGNED(uint8 rowu[kMaxStride]);
820 SIMD_ALIGNED(uint8 rowv[kMaxStride]);
821
822 for (int y = 0; y < height; ++y) {
823 UYVYToUV422Row(src_uyvy, rowu, rowv, width);
824 UYVYToYRow(src_uyvy, rowy, width);
825 I422ToARGBRow(rowy, rowu, rowv, dst_argb, width);
826 src_uyvy += src_stride_uyvy;
827 dst_argb += dst_stride_argb;
828 }
829 return 0;
830 }
831
832 #ifdef HAVE_JPEG
833 struct ARGBBuffers {
834 uint8* argb;
835 int argb_stride;
836 int w;
837 int h;
838 };
839
JpegI420ToARGB(void * opaque,const uint8 * const * data,const int * strides,int rows)840 static void JpegI420ToARGB(void* opaque,
841 const uint8* const* data,
842 const int* strides,
843 int rows) {
844 ARGBBuffers* dest = static_cast<ARGBBuffers*>(opaque);
845 I420ToARGB(data[0], strides[0],
846 data[1], strides[1],
847 data[2], strides[2],
848 dest->argb, dest->argb_stride,
849 dest->w, rows);
850 dest->argb += rows * dest->argb_stride;
851 dest->h -= rows;
852 }
853
JpegI422ToARGB(void * opaque,const uint8 * const * data,const int * strides,int rows)854 static void JpegI422ToARGB(void* opaque,
855 const uint8* const* data,
856 const int* strides,
857 int rows) {
858 ARGBBuffers* dest = static_cast<ARGBBuffers*>(opaque);
859 I422ToARGB(data[0], strides[0],
860 data[1], strides[1],
861 data[2], strides[2],
862 dest->argb, dest->argb_stride,
863 dest->w, rows);
864 dest->argb += rows * dest->argb_stride;
865 dest->h -= rows;
866 }
867
JpegI444ToARGB(void * opaque,const uint8 * const * data,const int * strides,int rows)868 static void JpegI444ToARGB(void* opaque,
869 const uint8* const* data,
870 const int* strides,
871 int rows) {
872 ARGBBuffers* dest = static_cast<ARGBBuffers*>(opaque);
873 I444ToARGB(data[0], strides[0],
874 data[1], strides[1],
875 data[2], strides[2],
876 dest->argb, dest->argb_stride,
877 dest->w, rows);
878 dest->argb += rows * dest->argb_stride;
879 dest->h -= rows;
880 }
881
JpegI411ToARGB(void * opaque,const uint8 * const * data,const int * strides,int rows)882 static void JpegI411ToARGB(void* opaque,
883 const uint8* const* data,
884 const int* strides,
885 int rows) {
886 ARGBBuffers* dest = static_cast<ARGBBuffers*>(opaque);
887 I411ToARGB(data[0], strides[0],
888 data[1], strides[1],
889 data[2], strides[2],
890 dest->argb, dest->argb_stride,
891 dest->w, rows);
892 dest->argb += rows * dest->argb_stride;
893 dest->h -= rows;
894 }
895
JpegI400ToARGB(void * opaque,const uint8 * const * data,const int * strides,int rows)896 static void JpegI400ToARGB(void* opaque,
897 const uint8* const* data,
898 const int* strides,
899 int rows) {
900 ARGBBuffers* dest = static_cast<ARGBBuffers*>(opaque);
901 I400ToARGB(data[0], strides[0],
902 dest->argb, dest->argb_stride,
903 dest->w, rows);
904 dest->argb += rows * dest->argb_stride;
905 dest->h -= rows;
906 }
907
908 // MJPG (Motion JPeg) to ARGB
909 // TODO(fbarchard): review w and h requirement. dw and dh may be enough.
910 LIBYUV_API
MJPGToARGB(const uint8 * sample,size_t sample_size,uint8 * argb,int argb_stride,int w,int h,int dw,int dh)911 int MJPGToARGB(const uint8* sample,
912 size_t sample_size,
913 uint8* argb, int argb_stride,
914 int w, int h,
915 int dw, int dh) {
916 if (sample_size == kUnknownDataSize) {
917 // ERROR: MJPEG frame size unknown
918 return -1;
919 }
920
921 // TODO(fbarchard): Port to C
922 MJpegDecoder mjpeg_decoder;
923 bool ret = mjpeg_decoder.LoadFrame(sample, sample_size);
924 if (ret && (mjpeg_decoder.GetWidth() != w ||
925 mjpeg_decoder.GetHeight() != h)) {
926 // ERROR: MJPEG frame has unexpected dimensions
927 mjpeg_decoder.UnloadFrame();
928 return 1; // runtime failure
929 }
930 if (ret) {
931 ARGBBuffers bufs = { argb, argb_stride, dw, dh };
932 // YUV420
933 if (mjpeg_decoder.GetColorSpace() ==
934 MJpegDecoder::kColorSpaceYCbCr &&
935 mjpeg_decoder.GetNumComponents() == 3 &&
936 mjpeg_decoder.GetVertSampFactor(0) == 2 &&
937 mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
938 mjpeg_decoder.GetVertSampFactor(1) == 1 &&
939 mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
940 mjpeg_decoder.GetVertSampFactor(2) == 1 &&
941 mjpeg_decoder.GetHorizSampFactor(2) == 1) {
942 ret = mjpeg_decoder.DecodeToCallback(&JpegI420ToARGB, &bufs, dw, dh);
943 // YUV422
944 } else if (mjpeg_decoder.GetColorSpace() ==
945 MJpegDecoder::kColorSpaceYCbCr &&
946 mjpeg_decoder.GetNumComponents() == 3 &&
947 mjpeg_decoder.GetVertSampFactor(0) == 1 &&
948 mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
949 mjpeg_decoder.GetVertSampFactor(1) == 1 &&
950 mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
951 mjpeg_decoder.GetVertSampFactor(2) == 1 &&
952 mjpeg_decoder.GetHorizSampFactor(2) == 1) {
953 ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToARGB, &bufs, dw, dh);
954 // YUV444
955 } else if (mjpeg_decoder.GetColorSpace() ==
956 MJpegDecoder::kColorSpaceYCbCr &&
957 mjpeg_decoder.GetNumComponents() == 3 &&
958 mjpeg_decoder.GetVertSampFactor(0) == 1 &&
959 mjpeg_decoder.GetHorizSampFactor(0) == 1 &&
960 mjpeg_decoder.GetVertSampFactor(1) == 1 &&
961 mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
962 mjpeg_decoder.GetVertSampFactor(2) == 1 &&
963 mjpeg_decoder.GetHorizSampFactor(2) == 1) {
964 ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToARGB, &bufs, dw, dh);
965 // YUV411
966 } else if (mjpeg_decoder.GetColorSpace() ==
967 MJpegDecoder::kColorSpaceYCbCr &&
968 mjpeg_decoder.GetNumComponents() == 3 &&
969 mjpeg_decoder.GetVertSampFactor(0) == 1 &&
970 mjpeg_decoder.GetHorizSampFactor(0) == 4 &&
971 mjpeg_decoder.GetVertSampFactor(1) == 1 &&
972 mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
973 mjpeg_decoder.GetVertSampFactor(2) == 1 &&
974 mjpeg_decoder.GetHorizSampFactor(2) == 1) {
975 ret = mjpeg_decoder.DecodeToCallback(&JpegI411ToARGB, &bufs, dw, dh);
976 // YUV400
977 } else if (mjpeg_decoder.GetColorSpace() ==
978 MJpegDecoder::kColorSpaceGrayscale &&
979 mjpeg_decoder.GetNumComponents() == 1 &&
980 mjpeg_decoder.GetVertSampFactor(0) == 1 &&
981 mjpeg_decoder.GetHorizSampFactor(0) == 1) {
982 ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToARGB, &bufs, dw, dh);
983 } else {
984 // TODO(fbarchard): Implement conversion for any other colorspace/sample
985 // factors that occur in practice. 411 is supported by libjpeg
986 // ERROR: Unable to convert MJPEG frame because format is not supported
987 mjpeg_decoder.UnloadFrame();
988 return 1;
989 }
990 }
991 return 0;
992 }
993 #endif
994
995 // Convert camera sample to I420 with cropping, rotation and vertical flip.
996 // src_width is used for source stride computation
997 // src_height is used to compute location of planes, and indicate inversion
998 // sample_size is measured in bytes and is the size of the frame.
999 // With MJPEG it is the compressed size of the frame.
1000 LIBYUV_API
ConvertToARGB(const uint8 * sample,size_t sample_size,uint8 * dst_argb,int argb_stride,int crop_x,int crop_y,int src_width,int src_height,int dst_width,int dst_height,RotationMode rotation,uint32 format)1001 int ConvertToARGB(const uint8* sample, size_t sample_size,
1002 uint8* dst_argb, int argb_stride,
1003 int crop_x, int crop_y,
1004 int src_width, int src_height,
1005 int dst_width, int dst_height,
1006 RotationMode rotation,
1007 uint32 format) {
1008 if (dst_argb == NULL || sample == NULL ||
1009 src_width <= 0 || dst_width <= 0 ||
1010 src_height == 0 || dst_height == 0) {
1011 return -1;
1012 }
1013 int aligned_src_width = (src_width + 1) & ~1;
1014 const uint8* src;
1015 const uint8* src_uv;
1016 int abs_src_height = (src_height < 0) ? -src_height : src_height;
1017 int inv_dst_height = (dst_height < 0) ? -dst_height : dst_height;
1018 if (src_height < 0) {
1019 inv_dst_height = -inv_dst_height;
1020 }
1021 int r = 0;
1022
1023 // One pass rotation is available for some formats. For the rest, convert
1024 // to I420 (with optional vertical flipping) into a temporary I420 buffer,
1025 // and then rotate the I420 to the final destination buffer.
1026 // For in-place conversion, if destination dst_argb is same as source sample,
1027 // also enable temporary buffer.
1028 bool need_buf = (rotation && format != FOURCC_ARGB) || dst_argb == sample;
1029 uint8* tmp_argb = dst_argb;
1030 int tmp_argb_stride = argb_stride;
1031 uint8* buf = NULL;
1032 int abs_dst_height = (dst_height < 0) ? -dst_height : dst_height;
1033 if (need_buf) {
1034 int argb_size = dst_width * abs_dst_height * 4;
1035 buf = new uint8[argb_size];
1036 if (!buf) {
1037 return 1; // Out of memory runtime error.
1038 }
1039 dst_argb = buf;
1040 argb_stride = dst_width;
1041 }
1042
1043 switch (format) {
1044 // Single plane formats
1045 case FOURCC_YUY2:
1046 src = sample + (aligned_src_width * crop_y + crop_x) * 2;
1047 r = YUY2ToARGB(src, aligned_src_width * 2,
1048 dst_argb, argb_stride,
1049 dst_width, inv_dst_height);
1050 break;
1051 case FOURCC_UYVY:
1052 src = sample + (aligned_src_width * crop_y + crop_x) * 2;
1053 r = UYVYToARGB(src, aligned_src_width * 2,
1054 dst_argb, argb_stride,
1055 dst_width, inv_dst_height);
1056 break;
1057 // case FOURCC_V210:
1058 // stride is multiple of 48 pixels (128 bytes).
1059 // pixels come in groups of 6 = 16 bytes
1060 // src = sample + (aligned_src_width + 47) / 48 * 128 * crop_y +
1061 // crop_x / 6 * 16;
1062 // r = V210ToARGB(src, (aligned_src_width + 47) / 48 * 128,
1063 // dst_argb, argb_stride,
1064 // dst_width, inv_dst_height);
1065 // break;
1066 case FOURCC_24BG:
1067 src = sample + (src_width * crop_y + crop_x) * 3;
1068 r = RGB24ToARGB(src, src_width * 3,
1069 dst_argb, argb_stride,
1070 dst_width, inv_dst_height);
1071 break;
1072 case FOURCC_RAW:
1073 src = sample + (src_width * crop_y + crop_x) * 3;
1074 r = RAWToARGB(src, src_width * 3,
1075 dst_argb, argb_stride,
1076 dst_width, inv_dst_height);
1077 break;
1078 case FOURCC_ARGB:
1079 src = sample + (src_width * crop_y + crop_x) * 4;
1080 r = ARGBToARGB(src, src_width * 4,
1081 dst_argb, argb_stride,
1082 dst_width, inv_dst_height);
1083 break;
1084 case FOURCC_BGRA:
1085 src = sample + (src_width * crop_y + crop_x) * 4;
1086 r = BGRAToARGB(src, src_width * 4,
1087 dst_argb, argb_stride,
1088 dst_width, inv_dst_height);
1089 break;
1090 case FOURCC_ABGR:
1091 src = sample + (src_width * crop_y + crop_x) * 4;
1092 r = ABGRToARGB(src, src_width * 4,
1093 dst_argb, argb_stride,
1094 dst_width, inv_dst_height);
1095 break;
1096 case FOURCC_RGBA:
1097 src = sample + (src_width * crop_y + crop_x) * 4;
1098 r = RGBAToARGB(src, src_width * 4,
1099 dst_argb, argb_stride,
1100 dst_width, inv_dst_height);
1101 break;
1102 case FOURCC_RGBP:
1103 src = sample + (src_width * crop_y + crop_x) * 2;
1104 r = RGB565ToARGB(src, src_width * 2,
1105 dst_argb, argb_stride,
1106 dst_width, inv_dst_height);
1107 break;
1108 case FOURCC_RGBO:
1109 src = sample + (src_width * crop_y + crop_x) * 2;
1110 r = ARGB1555ToARGB(src, src_width * 2,
1111 dst_argb, argb_stride,
1112 dst_width, inv_dst_height);
1113 break;
1114 case FOURCC_R444:
1115 src = sample + (src_width * crop_y + crop_x) * 2;
1116 r = ARGB4444ToARGB(src, src_width * 2,
1117 dst_argb, argb_stride,
1118 dst_width, inv_dst_height);
1119 break;
1120 // TODO(fbarchard): Support cropping Bayer by odd numbers
1121 // by adjusting fourcc.
1122 case FOURCC_BGGR:
1123 src = sample + (src_width * crop_y + crop_x);
1124 r = BayerBGGRToARGB(src, src_width,
1125 dst_argb, argb_stride,
1126 dst_width, inv_dst_height);
1127 break;
1128
1129 case FOURCC_GBRG:
1130 src = sample + (src_width * crop_y + crop_x);
1131 r = BayerGBRGToARGB(src, src_width,
1132 dst_argb, argb_stride,
1133 dst_width, inv_dst_height);
1134 break;
1135
1136 case FOURCC_GRBG:
1137 src = sample + (src_width * crop_y + crop_x);
1138 r = BayerGRBGToARGB(src, src_width,
1139 dst_argb, argb_stride,
1140 dst_width, inv_dst_height);
1141 break;
1142
1143 case FOURCC_RGGB:
1144 src = sample + (src_width * crop_y + crop_x);
1145 r = BayerRGGBToARGB(src, src_width,
1146 dst_argb, argb_stride,
1147 dst_width, inv_dst_height);
1148 break;
1149
1150 case FOURCC_I400:
1151 src = sample + src_width * crop_y + crop_x;
1152 r = I400ToARGB(src, src_width,
1153 dst_argb, argb_stride,
1154 dst_width, inv_dst_height);
1155 break;
1156
1157 // Biplanar formats
1158 case FOURCC_NV12:
1159 src = sample + (src_width * crop_y + crop_x);
1160 src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x;
1161 r = NV12ToARGB(src, src_width,
1162 src_uv, aligned_src_width,
1163 dst_argb, argb_stride,
1164 dst_width, inv_dst_height);
1165 break;
1166 case FOURCC_NV21:
1167 src = sample + (src_width * crop_y + crop_x);
1168 src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x;
1169 // Call NV12 but with u and v parameters swapped.
1170 r = NV21ToARGB(src, src_width,
1171 src_uv, aligned_src_width,
1172 dst_argb, argb_stride,
1173 dst_width, inv_dst_height);
1174 break;
1175 case FOURCC_M420:
1176 src = sample + (src_width * crop_y) * 12 / 8 + crop_x;
1177 r = M420ToARGB(src, src_width,
1178 dst_argb, argb_stride,
1179 dst_width, inv_dst_height);
1180 break;
1181 // case FOURCC_Q420:
1182 // src = sample + (src_width + aligned_src_width * 2) * crop_y + crop_x;
1183 // src_uv = sample + (src_width + aligned_src_width * 2) * crop_y +
1184 // src_width + crop_x * 2;
1185 // r = Q420ToARGB(src, src_width * 3,
1186 // src_uv, src_width * 3,
1187 // dst_argb, argb_stride,
1188 // dst_width, inv_dst_height);
1189 // break;
1190 // Triplanar formats
1191 case FOURCC_I420:
1192 case FOURCC_YU12:
1193 case FOURCC_YV12: {
1194 const uint8* src_y = sample + (src_width * crop_y + crop_x);
1195 const uint8* src_u;
1196 const uint8* src_v;
1197 int halfwidth = (src_width + 1) / 2;
1198 int halfheight = (abs_src_height + 1) / 2;
1199 if (format == FOURCC_YV12) {
1200 src_v = sample + src_width * abs_src_height +
1201 (halfwidth * crop_y + crop_x) / 2;
1202 src_u = sample + src_width * abs_src_height +
1203 halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
1204 } else {
1205 src_u = sample + src_width * abs_src_height +
1206 (halfwidth * crop_y + crop_x) / 2;
1207 src_v = sample + src_width * abs_src_height +
1208 halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
1209 }
1210 r = I420ToARGB(src_y, src_width,
1211 src_u, halfwidth,
1212 src_v, halfwidth,
1213 dst_argb, argb_stride,
1214 dst_width, inv_dst_height);
1215 break;
1216 }
1217 case FOURCC_I422:
1218 case FOURCC_YV16: {
1219 const uint8* src_y = sample + src_width * crop_y + crop_x;
1220 const uint8* src_u;
1221 const uint8* src_v;
1222 int halfwidth = (src_width + 1) / 2;
1223 if (format == FOURCC_YV16) {
1224 src_v = sample + src_width * abs_src_height +
1225 halfwidth * crop_y + crop_x / 2;
1226 src_u = sample + src_width * abs_src_height +
1227 halfwidth * (abs_src_height + crop_y) + crop_x / 2;
1228 } else {
1229 src_u = sample + src_width * abs_src_height +
1230 halfwidth * crop_y + crop_x / 2;
1231 src_v = sample + src_width * abs_src_height +
1232 halfwidth * (abs_src_height + crop_y) + crop_x / 2;
1233 }
1234 r = I422ToARGB(src_y, src_width,
1235 src_u, halfwidth,
1236 src_v, halfwidth,
1237 dst_argb, argb_stride,
1238 dst_width, inv_dst_height);
1239 break;
1240 }
1241 case FOURCC_I444:
1242 case FOURCC_YV24: {
1243 const uint8* src_y = sample + src_width * crop_y + crop_x;
1244 const uint8* src_u;
1245 const uint8* src_v;
1246 if (format == FOURCC_YV24) {
1247 src_v = sample + src_width * (abs_src_height + crop_y) + crop_x;
1248 src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
1249 } else {
1250 src_u = sample + src_width * (abs_src_height + crop_y) + crop_x;
1251 src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
1252 }
1253 r = I444ToARGB(src_y, src_width,
1254 src_u, src_width,
1255 src_v, src_width,
1256 dst_argb, argb_stride,
1257 dst_width, inv_dst_height);
1258 break;
1259 }
1260 case FOURCC_I411: {
1261 int quarterwidth = (src_width + 3) / 4;
1262 const uint8* src_y = sample + src_width * crop_y + crop_x;
1263 const uint8* src_u = sample + src_width * abs_src_height +
1264 quarterwidth * crop_y + crop_x / 4;
1265 const uint8* src_v = sample + src_width * abs_src_height +
1266 quarterwidth * (abs_src_height + crop_y) + crop_x / 4;
1267 r = I411ToARGB(src_y, src_width,
1268 src_u, quarterwidth,
1269 src_v, quarterwidth,
1270 dst_argb, argb_stride,
1271 dst_width, inv_dst_height);
1272 break;
1273 }
1274 #ifdef HAVE_JPEG
1275 case FOURCC_MJPG:
1276 r = MJPGToARGB(sample, sample_size,
1277 dst_argb, argb_stride,
1278 src_width, abs_src_height, dst_width, inv_dst_height);
1279 break;
1280 #endif
1281 default:
1282 r = -1; // unknown fourcc - return failure code.
1283 }
1284
1285 if (need_buf) {
1286 if (!r) {
1287 r = ARGBRotate(dst_argb, argb_stride,
1288 tmp_argb, tmp_argb_stride,
1289 dst_width, abs_dst_height, rotation);
1290 }
1291 delete buf;
1292 }
1293
1294 return r;
1295 }
1296
1297 #ifdef __cplusplus
1298 } // extern "C"
1299 } // namespace libyuv
1300 #endif
1301