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/planar_functions.h" // For CopyPlane and ARGBShuffle.
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 // Copy ARGB with optional flipping
28 LIBYUV_API
ARGBCopy(const uint8_t * src_argb,int src_stride_argb,uint8_t * dst_argb,int dst_stride_argb,int width,int height)29 int ARGBCopy(const uint8_t* src_argb,
30 int src_stride_argb,
31 uint8_t* dst_argb,
32 int dst_stride_argb,
33 int width,
34 int height) {
35 if (!src_argb || !dst_argb || 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, width * 4,
46 height);
47 return 0;
48 }
49
50 // Convert I420 to ARGB with matrix
I420ToARGBMatrix(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_argb,int dst_stride_argb,const struct YuvConstants * yuvconstants,int width,int height)51 static int I420ToARGBMatrix(const uint8_t* src_y,
52 int src_stride_y,
53 const uint8_t* src_u,
54 int src_stride_u,
55 const uint8_t* src_v,
56 int src_stride_v,
57 uint8_t* dst_argb,
58 int dst_stride_argb,
59 const struct YuvConstants* yuvconstants,
60 int width,
61 int height) {
62 int y;
63 void (*I422ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
64 const uint8_t* v_buf, uint8_t* rgb_buf,
65 const struct YuvConstants* yuvconstants, int width) =
66 I422ToARGBRow_C;
67 if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
68 return -1;
69 }
70 // Negative height means invert the image.
71 if (height < 0) {
72 height = -height;
73 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
74 dst_stride_argb = -dst_stride_argb;
75 }
76 #if defined(HAS_I422TOARGBROW_SSSE3)
77 if (TestCpuFlag(kCpuHasSSSE3)) {
78 I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
79 if (IS_ALIGNED(width, 8)) {
80 I422ToARGBRow = I422ToARGBRow_SSSE3;
81 }
82 }
83 #endif
84 #if defined(HAS_I422TOARGBROW_AVX2)
85 if (TestCpuFlag(kCpuHasAVX2)) {
86 I422ToARGBRow = I422ToARGBRow_Any_AVX2;
87 if (IS_ALIGNED(width, 16)) {
88 I422ToARGBRow = I422ToARGBRow_AVX2;
89 }
90 }
91 #endif
92 #if defined(HAS_I422TOARGBROW_NEON)
93 if (TestCpuFlag(kCpuHasNEON)) {
94 I422ToARGBRow = I422ToARGBRow_Any_NEON;
95 if (IS_ALIGNED(width, 8)) {
96 I422ToARGBRow = I422ToARGBRow_NEON;
97 }
98 }
99 #endif
100 #if defined(HAS_I422TOARGBROW_MSA)
101 if (TestCpuFlag(kCpuHasMSA)) {
102 I422ToARGBRow = I422ToARGBRow_Any_MSA;
103 if (IS_ALIGNED(width, 8)) {
104 I422ToARGBRow = I422ToARGBRow_MSA;
105 }
106 }
107 #endif
108
109 for (y = 0; y < height; ++y) {
110 I422ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
111 dst_argb += dst_stride_argb;
112 src_y += src_stride_y;
113 if (y & 1) {
114 src_u += src_stride_u;
115 src_v += src_stride_v;
116 }
117 }
118 return 0;
119 }
120
121 // Convert I420 to ARGB.
122 LIBYUV_API
I420ToARGB(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_argb,int dst_stride_argb,int width,int height)123 int I420ToARGB(const uint8_t* src_y,
124 int src_stride_y,
125 const uint8_t* src_u,
126 int src_stride_u,
127 const uint8_t* src_v,
128 int src_stride_v,
129 uint8_t* dst_argb,
130 int dst_stride_argb,
131 int width,
132 int height) {
133 return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
134 src_stride_v, dst_argb, dst_stride_argb,
135 &kYuvI601Constants, width, height);
136 }
137
138 // Convert I420 to ABGR.
139 LIBYUV_API
I420ToABGR(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_abgr,int dst_stride_abgr,int width,int height)140 int I420ToABGR(const uint8_t* src_y,
141 int src_stride_y,
142 const uint8_t* src_u,
143 int src_stride_u,
144 const uint8_t* src_v,
145 int src_stride_v,
146 uint8_t* dst_abgr,
147 int dst_stride_abgr,
148 int width,
149 int height) {
150 return I420ToARGBMatrix(src_y, src_stride_y, src_v,
151 src_stride_v, // Swap U and V
152 src_u, src_stride_u, dst_abgr, dst_stride_abgr,
153 &kYvuI601Constants, // Use Yvu matrix
154 width, height);
155 }
156
157 // Convert J420 to ARGB.
158 LIBYUV_API
J420ToARGB(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_argb,int dst_stride_argb,int width,int height)159 int J420ToARGB(const uint8_t* src_y,
160 int src_stride_y,
161 const uint8_t* src_u,
162 int src_stride_u,
163 const uint8_t* src_v,
164 int src_stride_v,
165 uint8_t* dst_argb,
166 int dst_stride_argb,
167 int width,
168 int height) {
169 return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
170 src_stride_v, dst_argb, dst_stride_argb,
171 &kYuvJPEGConstants, width, height);
172 }
173
174 // Convert J420 to ABGR.
175 LIBYUV_API
J420ToABGR(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_abgr,int dst_stride_abgr,int width,int height)176 int J420ToABGR(const uint8_t* src_y,
177 int src_stride_y,
178 const uint8_t* src_u,
179 int src_stride_u,
180 const uint8_t* src_v,
181 int src_stride_v,
182 uint8_t* dst_abgr,
183 int dst_stride_abgr,
184 int width,
185 int height) {
186 return I420ToARGBMatrix(src_y, src_stride_y, src_v,
187 src_stride_v, // Swap U and V
188 src_u, src_stride_u, dst_abgr, dst_stride_abgr,
189 &kYvuJPEGConstants, // Use Yvu matrix
190 width, height);
191 }
192
193 // Convert H420 to ARGB.
194 LIBYUV_API
H420ToARGB(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_argb,int dst_stride_argb,int width,int height)195 int H420ToARGB(const uint8_t* src_y,
196 int src_stride_y,
197 const uint8_t* src_u,
198 int src_stride_u,
199 const uint8_t* src_v,
200 int src_stride_v,
201 uint8_t* dst_argb,
202 int dst_stride_argb,
203 int width,
204 int height) {
205 return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
206 src_stride_v, dst_argb, dst_stride_argb,
207 &kYuvH709Constants, width, height);
208 }
209
210 // Convert H420 to ABGR.
211 LIBYUV_API
H420ToABGR(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_abgr,int dst_stride_abgr,int width,int height)212 int H420ToABGR(const uint8_t* src_y,
213 int src_stride_y,
214 const uint8_t* src_u,
215 int src_stride_u,
216 const uint8_t* src_v,
217 int src_stride_v,
218 uint8_t* dst_abgr,
219 int dst_stride_abgr,
220 int width,
221 int height) {
222 return I420ToARGBMatrix(src_y, src_stride_y, src_v,
223 src_stride_v, // Swap U and V
224 src_u, src_stride_u, dst_abgr, dst_stride_abgr,
225 &kYvuH709Constants, // Use Yvu matrix
226 width, height);
227 }
228
229 // Convert I422 to ARGB with matrix
I422ToARGBMatrix(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_argb,int dst_stride_argb,const struct YuvConstants * yuvconstants,int width,int height)230 static int I422ToARGBMatrix(const uint8_t* src_y,
231 int src_stride_y,
232 const uint8_t* src_u,
233 int src_stride_u,
234 const uint8_t* src_v,
235 int src_stride_v,
236 uint8_t* dst_argb,
237 int dst_stride_argb,
238 const struct YuvConstants* yuvconstants,
239 int width,
240 int height) {
241 int y;
242 void (*I422ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
243 const uint8_t* v_buf, uint8_t* rgb_buf,
244 const struct YuvConstants* yuvconstants, int width) =
245 I422ToARGBRow_C;
246 if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
247 return -1;
248 }
249 // Negative height means invert the image.
250 if (height < 0) {
251 height = -height;
252 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
253 dst_stride_argb = -dst_stride_argb;
254 }
255 // Coalesce rows.
256 if (src_stride_y == width && src_stride_u * 2 == width &&
257 src_stride_v * 2 == width && dst_stride_argb == width * 4) {
258 width *= height;
259 height = 1;
260 src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
261 }
262 #if defined(HAS_I422TOARGBROW_SSSE3)
263 if (TestCpuFlag(kCpuHasSSSE3)) {
264 I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
265 if (IS_ALIGNED(width, 8)) {
266 I422ToARGBRow = I422ToARGBRow_SSSE3;
267 }
268 }
269 #endif
270 #if defined(HAS_I422TOARGBROW_AVX2)
271 if (TestCpuFlag(kCpuHasAVX2)) {
272 I422ToARGBRow = I422ToARGBRow_Any_AVX2;
273 if (IS_ALIGNED(width, 16)) {
274 I422ToARGBRow = I422ToARGBRow_AVX2;
275 }
276 }
277 #endif
278 #if defined(HAS_I422TOARGBROW_NEON)
279 if (TestCpuFlag(kCpuHasNEON)) {
280 I422ToARGBRow = I422ToARGBRow_Any_NEON;
281 if (IS_ALIGNED(width, 8)) {
282 I422ToARGBRow = I422ToARGBRow_NEON;
283 }
284 }
285 #endif
286 #if defined(HAS_I422TOARGBROW_MSA)
287 if (TestCpuFlag(kCpuHasMSA)) {
288 I422ToARGBRow = I422ToARGBRow_Any_MSA;
289 if (IS_ALIGNED(width, 8)) {
290 I422ToARGBRow = I422ToARGBRow_MSA;
291 }
292 }
293 #endif
294
295 for (y = 0; y < height; ++y) {
296 I422ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
297 dst_argb += dst_stride_argb;
298 src_y += src_stride_y;
299 src_u += src_stride_u;
300 src_v += src_stride_v;
301 }
302 return 0;
303 }
304
305 // Convert I422 to ARGB.
306 LIBYUV_API
I422ToARGB(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_argb,int dst_stride_argb,int width,int height)307 int I422ToARGB(const uint8_t* src_y,
308 int src_stride_y,
309 const uint8_t* src_u,
310 int src_stride_u,
311 const uint8_t* src_v,
312 int src_stride_v,
313 uint8_t* dst_argb,
314 int dst_stride_argb,
315 int width,
316 int height) {
317 return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
318 src_stride_v, dst_argb, dst_stride_argb,
319 &kYuvI601Constants, width, height);
320 }
321
322 // Convert I422 to ABGR.
323 LIBYUV_API
I422ToABGR(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_abgr,int dst_stride_abgr,int width,int height)324 int I422ToABGR(const uint8_t* src_y,
325 int src_stride_y,
326 const uint8_t* src_u,
327 int src_stride_u,
328 const uint8_t* src_v,
329 int src_stride_v,
330 uint8_t* dst_abgr,
331 int dst_stride_abgr,
332 int width,
333 int height) {
334 return I422ToARGBMatrix(src_y, src_stride_y, src_v,
335 src_stride_v, // Swap U and V
336 src_u, src_stride_u, dst_abgr, dst_stride_abgr,
337 &kYvuI601Constants, // Use Yvu matrix
338 width, height);
339 }
340
341 // Convert J422 to ARGB.
342 LIBYUV_API
J422ToARGB(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_argb,int dst_stride_argb,int width,int height)343 int J422ToARGB(const uint8_t* src_y,
344 int src_stride_y,
345 const uint8_t* src_u,
346 int src_stride_u,
347 const uint8_t* src_v,
348 int src_stride_v,
349 uint8_t* dst_argb,
350 int dst_stride_argb,
351 int width,
352 int height) {
353 return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
354 src_stride_v, dst_argb, dst_stride_argb,
355 &kYuvJPEGConstants, width, height);
356 }
357
358 // Convert J422 to ABGR.
359 LIBYUV_API
J422ToABGR(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_abgr,int dst_stride_abgr,int width,int height)360 int J422ToABGR(const uint8_t* src_y,
361 int src_stride_y,
362 const uint8_t* src_u,
363 int src_stride_u,
364 const uint8_t* src_v,
365 int src_stride_v,
366 uint8_t* dst_abgr,
367 int dst_stride_abgr,
368 int width,
369 int height) {
370 return I422ToARGBMatrix(src_y, src_stride_y, src_v,
371 src_stride_v, // Swap U and V
372 src_u, src_stride_u, dst_abgr, dst_stride_abgr,
373 &kYvuJPEGConstants, // Use Yvu matrix
374 width, height);
375 }
376
377 // Convert H422 to ARGB.
378 LIBYUV_API
H422ToARGB(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_argb,int dst_stride_argb,int width,int height)379 int H422ToARGB(const uint8_t* src_y,
380 int src_stride_y,
381 const uint8_t* src_u,
382 int src_stride_u,
383 const uint8_t* src_v,
384 int src_stride_v,
385 uint8_t* dst_argb,
386 int dst_stride_argb,
387 int width,
388 int height) {
389 return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
390 src_stride_v, dst_argb, dst_stride_argb,
391 &kYuvH709Constants, width, height);
392 }
393
394 // Convert H422 to ABGR.
395 LIBYUV_API
H422ToABGR(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_abgr,int dst_stride_abgr,int width,int height)396 int H422ToABGR(const uint8_t* src_y,
397 int src_stride_y,
398 const uint8_t* src_u,
399 int src_stride_u,
400 const uint8_t* src_v,
401 int src_stride_v,
402 uint8_t* dst_abgr,
403 int dst_stride_abgr,
404 int width,
405 int height) {
406 return I422ToARGBMatrix(src_y, src_stride_y, src_v,
407 src_stride_v, // Swap U and V
408 src_u, src_stride_u, dst_abgr, dst_stride_abgr,
409 &kYvuH709Constants, // Use Yvu matrix
410 width, height);
411 }
412
413 // Convert 10 bit YUV to ARGB with matrix
414 // TODO(fbarchard): Consider passing scale multiplier to I210ToARGB to
415 // multiply 10 bit yuv into high bits to allow any number of bits.
I010ToAR30Matrix(const uint16_t * src_y,int src_stride_y,const uint16_t * src_u,int src_stride_u,const uint16_t * src_v,int src_stride_v,uint8_t * dst_ar30,int dst_stride_ar30,const struct YuvConstants * yuvconstants,int width,int height)416 static int I010ToAR30Matrix(const uint16_t* src_y,
417 int src_stride_y,
418 const uint16_t* src_u,
419 int src_stride_u,
420 const uint16_t* src_v,
421 int src_stride_v,
422 uint8_t* dst_ar30,
423 int dst_stride_ar30,
424 const struct YuvConstants* yuvconstants,
425 int width,
426 int height) {
427 int y;
428 void (*I210ToAR30Row)(const uint16_t* y_buf, const uint16_t* u_buf,
429 const uint16_t* v_buf, uint8_t* rgb_buf,
430 const struct YuvConstants* yuvconstants, int width) =
431 I210ToAR30Row_C;
432 if (!src_y || !src_u || !src_v || !dst_ar30 || width <= 0 || height == 0) {
433 return -1;
434 }
435 // Negative height means invert the image.
436 if (height < 0) {
437 height = -height;
438 dst_ar30 = dst_ar30 + (height - 1) * dst_stride_ar30;
439 dst_stride_ar30 = -dst_stride_ar30;
440 }
441 #if defined(HAS_I210TOAR30ROW_SSSE3)
442 if (TestCpuFlag(kCpuHasSSSE3)) {
443 I210ToAR30Row = I210ToAR30Row_Any_SSSE3;
444 if (IS_ALIGNED(width, 8)) {
445 I210ToAR30Row = I210ToAR30Row_SSSE3;
446 }
447 }
448 #endif
449 #if defined(HAS_I210TOAR30ROW_AVX2)
450 if (TestCpuFlag(kCpuHasAVX2)) {
451 I210ToAR30Row = I210ToAR30Row_Any_AVX2;
452 if (IS_ALIGNED(width, 16)) {
453 I210ToAR30Row = I210ToAR30Row_AVX2;
454 }
455 }
456 #endif
457 for (y = 0; y < height; ++y) {
458 I210ToAR30Row(src_y, src_u, src_v, dst_ar30, yuvconstants, width);
459 dst_ar30 += dst_stride_ar30;
460 src_y += src_stride_y;
461 if (y & 1) {
462 src_u += src_stride_u;
463 src_v += src_stride_v;
464 }
465 }
466 return 0;
467 }
468
469 // Convert I010 to AR30.
470 LIBYUV_API
I010ToAR30(const uint16_t * src_y,int src_stride_y,const uint16_t * src_u,int src_stride_u,const uint16_t * src_v,int src_stride_v,uint8_t * dst_ar30,int dst_stride_ar30,int width,int height)471 int I010ToAR30(const uint16_t* src_y,
472 int src_stride_y,
473 const uint16_t* src_u,
474 int src_stride_u,
475 const uint16_t* src_v,
476 int src_stride_v,
477 uint8_t* dst_ar30,
478 int dst_stride_ar30,
479 int width,
480 int height) {
481 return I010ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
482 src_stride_v, dst_ar30, dst_stride_ar30,
483 &kYuvI601Constants, width, height);
484 }
485
486 // Convert H010 to AR30.
487 LIBYUV_API
H010ToAR30(const uint16_t * src_y,int src_stride_y,const uint16_t * src_u,int src_stride_u,const uint16_t * src_v,int src_stride_v,uint8_t * dst_ar30,int dst_stride_ar30,int width,int height)488 int H010ToAR30(const uint16_t* src_y,
489 int src_stride_y,
490 const uint16_t* src_u,
491 int src_stride_u,
492 const uint16_t* src_v,
493 int src_stride_v,
494 uint8_t* dst_ar30,
495 int dst_stride_ar30,
496 int width,
497 int height) {
498 return I010ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
499 src_stride_v, dst_ar30, dst_stride_ar30,
500 &kYuvH709Constants, width, height);
501 }
502
503 // Convert I010 to AB30.
504 LIBYUV_API
I010ToAB30(const uint16_t * src_y,int src_stride_y,const uint16_t * src_u,int src_stride_u,const uint16_t * src_v,int src_stride_v,uint8_t * dst_ab30,int dst_stride_ab30,int width,int height)505 int I010ToAB30(const uint16_t* src_y,
506 int src_stride_y,
507 const uint16_t* src_u,
508 int src_stride_u,
509 const uint16_t* src_v,
510 int src_stride_v,
511 uint8_t* dst_ab30,
512 int dst_stride_ab30,
513 int width,
514 int height) {
515 return I010ToAR30Matrix(src_y, src_stride_y, src_v, src_stride_v, src_u,
516 src_stride_u, dst_ab30, dst_stride_ab30,
517 &kYvuI601Constants, width, height);
518 }
519
520 // Convert H010 to AB30.
521 LIBYUV_API
H010ToAB30(const uint16_t * src_y,int src_stride_y,const uint16_t * src_u,int src_stride_u,const uint16_t * src_v,int src_stride_v,uint8_t * dst_ab30,int dst_stride_ab30,int width,int height)522 int H010ToAB30(const uint16_t* src_y,
523 int src_stride_y,
524 const uint16_t* src_u,
525 int src_stride_u,
526 const uint16_t* src_v,
527 int src_stride_v,
528 uint8_t* dst_ab30,
529 int dst_stride_ab30,
530 int width,
531 int height) {
532 return I010ToAR30Matrix(src_y, src_stride_y, src_v, src_stride_v, src_u,
533 src_stride_u, dst_ab30, dst_stride_ab30,
534 &kYvuH709Constants, width, height);
535 }
536
537 // Convert 10 bit YUV to ARGB with matrix
I010ToARGBMatrix(const uint16_t * src_y,int src_stride_y,const uint16_t * src_u,int src_stride_u,const uint16_t * src_v,int src_stride_v,uint8_t * dst_argb,int dst_stride_argb,const struct YuvConstants * yuvconstants,int width,int height)538 static int I010ToARGBMatrix(const uint16_t* src_y,
539 int src_stride_y,
540 const uint16_t* src_u,
541 int src_stride_u,
542 const uint16_t* src_v,
543 int src_stride_v,
544 uint8_t* dst_argb,
545 int dst_stride_argb,
546 const struct YuvConstants* yuvconstants,
547 int width,
548 int height) {
549 int y;
550 void (*I210ToARGBRow)(const uint16_t* y_buf, const uint16_t* u_buf,
551 const uint16_t* v_buf, uint8_t* rgb_buf,
552 const struct YuvConstants* yuvconstants, int width) =
553 I210ToARGBRow_C;
554 if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
555 return -1;
556 }
557 // Negative height means invert the image.
558 if (height < 0) {
559 height = -height;
560 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
561 dst_stride_argb = -dst_stride_argb;
562 }
563 #if defined(HAS_I210TOARGBROW_SSSE3)
564 if (TestCpuFlag(kCpuHasSSSE3)) {
565 I210ToARGBRow = I210ToARGBRow_Any_SSSE3;
566 if (IS_ALIGNED(width, 8)) {
567 I210ToARGBRow = I210ToARGBRow_SSSE3;
568 }
569 }
570 #endif
571 #if defined(HAS_I210TOARGBROW_AVX2)
572 if (TestCpuFlag(kCpuHasAVX2)) {
573 I210ToARGBRow = I210ToARGBRow_Any_AVX2;
574 if (IS_ALIGNED(width, 16)) {
575 I210ToARGBRow = I210ToARGBRow_AVX2;
576 }
577 }
578 #endif
579 for (y = 0; y < height; ++y) {
580 I210ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
581 dst_argb += dst_stride_argb;
582 src_y += src_stride_y;
583 if (y & 1) {
584 src_u += src_stride_u;
585 src_v += src_stride_v;
586 }
587 }
588 return 0;
589 }
590
591 // Convert I010 to ARGB.
592 LIBYUV_API
I010ToARGB(const uint16_t * src_y,int src_stride_y,const uint16_t * src_u,int src_stride_u,const uint16_t * src_v,int src_stride_v,uint8_t * dst_argb,int dst_stride_argb,int width,int height)593 int I010ToARGB(const uint16_t* src_y,
594 int src_stride_y,
595 const uint16_t* src_u,
596 int src_stride_u,
597 const uint16_t* src_v,
598 int src_stride_v,
599 uint8_t* dst_argb,
600 int dst_stride_argb,
601 int width,
602 int height) {
603 return I010ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
604 src_stride_v, dst_argb, dst_stride_argb,
605 &kYuvI601Constants, width, height);
606 }
607
608 // Convert I010 to ABGR.
609 LIBYUV_API
I010ToABGR(const uint16_t * src_y,int src_stride_y,const uint16_t * src_u,int src_stride_u,const uint16_t * src_v,int src_stride_v,uint8_t * dst_abgr,int dst_stride_abgr,int width,int height)610 int I010ToABGR(const uint16_t* src_y,
611 int src_stride_y,
612 const uint16_t* src_u,
613 int src_stride_u,
614 const uint16_t* src_v,
615 int src_stride_v,
616 uint8_t* dst_abgr,
617 int dst_stride_abgr,
618 int width,
619 int height) {
620 return I010ToARGBMatrix(src_y, src_stride_y, src_v,
621 src_stride_v, // Swap U and V
622 src_u, src_stride_u, dst_abgr, dst_stride_abgr,
623 &kYvuI601Constants, // Use Yvu matrix
624 width, height);
625 }
626
627 // Convert H010 to ARGB.
628 LIBYUV_API
H010ToARGB(const uint16_t * src_y,int src_stride_y,const uint16_t * src_u,int src_stride_u,const uint16_t * src_v,int src_stride_v,uint8_t * dst_argb,int dst_stride_argb,int width,int height)629 int H010ToARGB(const uint16_t* src_y,
630 int src_stride_y,
631 const uint16_t* src_u,
632 int src_stride_u,
633 const uint16_t* src_v,
634 int src_stride_v,
635 uint8_t* dst_argb,
636 int dst_stride_argb,
637 int width,
638 int height) {
639 return I010ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
640 src_stride_v, dst_argb, dst_stride_argb,
641 &kYuvH709Constants, width, height);
642 }
643
644 // Convert H010 to ABGR.
645 LIBYUV_API
H010ToABGR(const uint16_t * src_y,int src_stride_y,const uint16_t * src_u,int src_stride_u,const uint16_t * src_v,int src_stride_v,uint8_t * dst_abgr,int dst_stride_abgr,int width,int height)646 int H010ToABGR(const uint16_t* src_y,
647 int src_stride_y,
648 const uint16_t* src_u,
649 int src_stride_u,
650 const uint16_t* src_v,
651 int src_stride_v,
652 uint8_t* dst_abgr,
653 int dst_stride_abgr,
654 int width,
655 int height) {
656 return I010ToARGBMatrix(src_y, src_stride_y, src_v,
657 src_stride_v, // Swap U and V
658 src_u, src_stride_u, dst_abgr, dst_stride_abgr,
659 &kYvuH709Constants, // Use Yvu matrix
660 width, height);
661 }
662
663 // Convert I444 to ARGB with matrix
I444ToARGBMatrix(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_argb,int dst_stride_argb,const struct YuvConstants * yuvconstants,int width,int height)664 static int I444ToARGBMatrix(const uint8_t* src_y,
665 int src_stride_y,
666 const uint8_t* src_u,
667 int src_stride_u,
668 const uint8_t* src_v,
669 int src_stride_v,
670 uint8_t* dst_argb,
671 int dst_stride_argb,
672 const struct YuvConstants* yuvconstants,
673 int width,
674 int height) {
675 int y;
676 void (*I444ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
677 const uint8_t* v_buf, uint8_t* rgb_buf,
678 const struct YuvConstants* yuvconstants, int width) =
679 I444ToARGBRow_C;
680 if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
681 return -1;
682 }
683 // Negative height means invert the image.
684 if (height < 0) {
685 height = -height;
686 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
687 dst_stride_argb = -dst_stride_argb;
688 }
689 // Coalesce rows.
690 if (src_stride_y == width && src_stride_u == width && src_stride_v == width &&
691 dst_stride_argb == width * 4) {
692 width *= height;
693 height = 1;
694 src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
695 }
696 #if defined(HAS_I444TOARGBROW_SSSE3)
697 if (TestCpuFlag(kCpuHasSSSE3)) {
698 I444ToARGBRow = I444ToARGBRow_Any_SSSE3;
699 if (IS_ALIGNED(width, 8)) {
700 I444ToARGBRow = I444ToARGBRow_SSSE3;
701 }
702 }
703 #endif
704 #if defined(HAS_I444TOARGBROW_AVX2)
705 if (TestCpuFlag(kCpuHasAVX2)) {
706 I444ToARGBRow = I444ToARGBRow_Any_AVX2;
707 if (IS_ALIGNED(width, 16)) {
708 I444ToARGBRow = I444ToARGBRow_AVX2;
709 }
710 }
711 #endif
712 #if defined(HAS_I444TOARGBROW_NEON)
713 if (TestCpuFlag(kCpuHasNEON)) {
714 I444ToARGBRow = I444ToARGBRow_Any_NEON;
715 if (IS_ALIGNED(width, 8)) {
716 I444ToARGBRow = I444ToARGBRow_NEON;
717 }
718 }
719 #endif
720 #if defined(HAS_I444TOARGBROW_MSA)
721 if (TestCpuFlag(kCpuHasMSA)) {
722 I444ToARGBRow = I444ToARGBRow_Any_MSA;
723 if (IS_ALIGNED(width, 8)) {
724 I444ToARGBRow = I444ToARGBRow_MSA;
725 }
726 }
727 #endif
728
729 for (y = 0; y < height; ++y) {
730 I444ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
731 dst_argb += dst_stride_argb;
732 src_y += src_stride_y;
733 src_u += src_stride_u;
734 src_v += src_stride_v;
735 }
736 return 0;
737 }
738
739 // Convert I444 to ARGB.
740 LIBYUV_API
I444ToARGB(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_argb,int dst_stride_argb,int width,int height)741 int I444ToARGB(const uint8_t* src_y,
742 int src_stride_y,
743 const uint8_t* src_u,
744 int src_stride_u,
745 const uint8_t* src_v,
746 int src_stride_v,
747 uint8_t* dst_argb,
748 int dst_stride_argb,
749 int width,
750 int height) {
751 return I444ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
752 src_stride_v, dst_argb, dst_stride_argb,
753 &kYuvI601Constants, width, height);
754 }
755
756 // Convert I444 to ABGR.
757 LIBYUV_API
I444ToABGR(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_abgr,int dst_stride_abgr,int width,int height)758 int I444ToABGR(const uint8_t* src_y,
759 int src_stride_y,
760 const uint8_t* src_u,
761 int src_stride_u,
762 const uint8_t* src_v,
763 int src_stride_v,
764 uint8_t* dst_abgr,
765 int dst_stride_abgr,
766 int width,
767 int height) {
768 return I444ToARGBMatrix(src_y, src_stride_y, src_v,
769 src_stride_v, // Swap U and V
770 src_u, src_stride_u, dst_abgr, dst_stride_abgr,
771 &kYvuI601Constants, // Use Yvu matrix
772 width, height);
773 }
774
775 // Convert J444 to ARGB.
776 LIBYUV_API
J444ToARGB(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_argb,int dst_stride_argb,int width,int height)777 int J444ToARGB(const uint8_t* src_y,
778 int src_stride_y,
779 const uint8_t* src_u,
780 int src_stride_u,
781 const uint8_t* src_v,
782 int src_stride_v,
783 uint8_t* dst_argb,
784 int dst_stride_argb,
785 int width,
786 int height) {
787 return I444ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
788 src_stride_v, dst_argb, dst_stride_argb,
789 &kYuvJPEGConstants, width, height);
790 }
791
792 // Convert I420 with Alpha to preattenuated ARGB.
I420AlphaToARGBMatrix(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,const uint8_t * src_a,int src_stride_a,uint8_t * dst_argb,int dst_stride_argb,const struct YuvConstants * yuvconstants,int width,int height,int attenuate)793 static int I420AlphaToARGBMatrix(const uint8_t* src_y,
794 int src_stride_y,
795 const uint8_t* src_u,
796 int src_stride_u,
797 const uint8_t* src_v,
798 int src_stride_v,
799 const uint8_t* src_a,
800 int src_stride_a,
801 uint8_t* dst_argb,
802 int dst_stride_argb,
803 const struct YuvConstants* yuvconstants,
804 int width,
805 int height,
806 int attenuate) {
807 int y;
808 void (*I422AlphaToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
809 const uint8_t* v_buf, const uint8_t* a_buf,
810 uint8_t* dst_argb,
811 const struct YuvConstants* yuvconstants,
812 int width) = I422AlphaToARGBRow_C;
813 void (*ARGBAttenuateRow)(const uint8_t* src_argb, uint8_t* dst_argb,
814 int width) = ARGBAttenuateRow_C;
815 if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
816 return -1;
817 }
818 // Negative height means invert the image.
819 if (height < 0) {
820 height = -height;
821 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
822 dst_stride_argb = -dst_stride_argb;
823 }
824 #if defined(HAS_I422ALPHATOARGBROW_SSSE3)
825 if (TestCpuFlag(kCpuHasSSSE3)) {
826 I422AlphaToARGBRow = I422AlphaToARGBRow_Any_SSSE3;
827 if (IS_ALIGNED(width, 8)) {
828 I422AlphaToARGBRow = I422AlphaToARGBRow_SSSE3;
829 }
830 }
831 #endif
832 #if defined(HAS_I422ALPHATOARGBROW_AVX2)
833 if (TestCpuFlag(kCpuHasAVX2)) {
834 I422AlphaToARGBRow = I422AlphaToARGBRow_Any_AVX2;
835 if (IS_ALIGNED(width, 16)) {
836 I422AlphaToARGBRow = I422AlphaToARGBRow_AVX2;
837 }
838 }
839 #endif
840 #if defined(HAS_I422ALPHATOARGBROW_NEON)
841 if (TestCpuFlag(kCpuHasNEON)) {
842 I422AlphaToARGBRow = I422AlphaToARGBRow_Any_NEON;
843 if (IS_ALIGNED(width, 8)) {
844 I422AlphaToARGBRow = I422AlphaToARGBRow_NEON;
845 }
846 }
847 #endif
848 #if defined(HAS_I422ALPHATOARGBROW_MSA)
849 if (TestCpuFlag(kCpuHasMSA)) {
850 I422AlphaToARGBRow = I422AlphaToARGBRow_Any_MSA;
851 if (IS_ALIGNED(width, 8)) {
852 I422AlphaToARGBRow = I422AlphaToARGBRow_MSA;
853 }
854 }
855 #endif
856 #if defined(HAS_ARGBATTENUATEROW_SSSE3)
857 if (TestCpuFlag(kCpuHasSSSE3)) {
858 ARGBAttenuateRow = ARGBAttenuateRow_Any_SSSE3;
859 if (IS_ALIGNED(width, 4)) {
860 ARGBAttenuateRow = ARGBAttenuateRow_SSSE3;
861 }
862 }
863 #endif
864 #if defined(HAS_ARGBATTENUATEROW_AVX2)
865 if (TestCpuFlag(kCpuHasAVX2)) {
866 ARGBAttenuateRow = ARGBAttenuateRow_Any_AVX2;
867 if (IS_ALIGNED(width, 8)) {
868 ARGBAttenuateRow = ARGBAttenuateRow_AVX2;
869 }
870 }
871 #endif
872 #if defined(HAS_ARGBATTENUATEROW_NEON)
873 if (TestCpuFlag(kCpuHasNEON)) {
874 ARGBAttenuateRow = ARGBAttenuateRow_Any_NEON;
875 if (IS_ALIGNED(width, 8)) {
876 ARGBAttenuateRow = ARGBAttenuateRow_NEON;
877 }
878 }
879 #endif
880 #if defined(HAS_ARGBATTENUATEROW_MSA)
881 if (TestCpuFlag(kCpuHasMSA)) {
882 ARGBAttenuateRow = ARGBAttenuateRow_Any_MSA;
883 if (IS_ALIGNED(width, 8)) {
884 ARGBAttenuateRow = ARGBAttenuateRow_MSA;
885 }
886 }
887 #endif
888
889 for (y = 0; y < height; ++y) {
890 I422AlphaToARGBRow(src_y, src_u, src_v, src_a, dst_argb, yuvconstants,
891 width);
892 if (attenuate) {
893 ARGBAttenuateRow(dst_argb, dst_argb, width);
894 }
895 dst_argb += dst_stride_argb;
896 src_a += src_stride_a;
897 src_y += src_stride_y;
898 if (y & 1) {
899 src_u += src_stride_u;
900 src_v += src_stride_v;
901 }
902 }
903 return 0;
904 }
905
906 // Convert I420 with Alpha to ARGB.
907 LIBYUV_API
I420AlphaToARGB(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,const uint8_t * src_a,int src_stride_a,uint8_t * dst_argb,int dst_stride_argb,int width,int height,int attenuate)908 int I420AlphaToARGB(const uint8_t* src_y,
909 int src_stride_y,
910 const uint8_t* src_u,
911 int src_stride_u,
912 const uint8_t* src_v,
913 int src_stride_v,
914 const uint8_t* src_a,
915 int src_stride_a,
916 uint8_t* dst_argb,
917 int dst_stride_argb,
918 int width,
919 int height,
920 int attenuate) {
921 return I420AlphaToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
922 src_stride_v, src_a, src_stride_a, dst_argb,
923 dst_stride_argb, &kYuvI601Constants, width,
924 height, attenuate);
925 }
926
927 // Convert I420 with Alpha to ABGR.
928 LIBYUV_API
I420AlphaToABGR(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,const uint8_t * src_a,int src_stride_a,uint8_t * dst_abgr,int dst_stride_abgr,int width,int height,int attenuate)929 int I420AlphaToABGR(const uint8_t* src_y,
930 int src_stride_y,
931 const uint8_t* src_u,
932 int src_stride_u,
933 const uint8_t* src_v,
934 int src_stride_v,
935 const uint8_t* src_a,
936 int src_stride_a,
937 uint8_t* dst_abgr,
938 int dst_stride_abgr,
939 int width,
940 int height,
941 int attenuate) {
942 return I420AlphaToARGBMatrix(
943 src_y, src_stride_y, src_v, src_stride_v, // Swap U and V
944 src_u, src_stride_u, src_a, src_stride_a, dst_abgr, dst_stride_abgr,
945 &kYvuI601Constants, // Use Yvu matrix
946 width, height, attenuate);
947 }
948
949 // Convert I400 to ARGB.
950 LIBYUV_API
I400ToARGB(const uint8_t * src_y,int src_stride_y,uint8_t * dst_argb,int dst_stride_argb,int width,int height)951 int I400ToARGB(const uint8_t* src_y,
952 int src_stride_y,
953 uint8_t* dst_argb,
954 int dst_stride_argb,
955 int width,
956 int height) {
957 int y;
958 void (*I400ToARGBRow)(const uint8_t* y_buf, uint8_t* rgb_buf, int width) =
959 I400ToARGBRow_C;
960 if (!src_y || !dst_argb || width <= 0 || height == 0) {
961 return -1;
962 }
963 // Negative height means invert the image.
964 if (height < 0) {
965 height = -height;
966 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
967 dst_stride_argb = -dst_stride_argb;
968 }
969 // Coalesce rows.
970 if (src_stride_y == width && dst_stride_argb == width * 4) {
971 width *= height;
972 height = 1;
973 src_stride_y = dst_stride_argb = 0;
974 }
975 #if defined(HAS_I400TOARGBROW_SSE2)
976 if (TestCpuFlag(kCpuHasSSE2)) {
977 I400ToARGBRow = I400ToARGBRow_Any_SSE2;
978 if (IS_ALIGNED(width, 8)) {
979 I400ToARGBRow = I400ToARGBRow_SSE2;
980 }
981 }
982 #endif
983 #if defined(HAS_I400TOARGBROW_AVX2)
984 if (TestCpuFlag(kCpuHasAVX2)) {
985 I400ToARGBRow = I400ToARGBRow_Any_AVX2;
986 if (IS_ALIGNED(width, 16)) {
987 I400ToARGBRow = I400ToARGBRow_AVX2;
988 }
989 }
990 #endif
991 #if defined(HAS_I400TOARGBROW_NEON)
992 if (TestCpuFlag(kCpuHasNEON)) {
993 I400ToARGBRow = I400ToARGBRow_Any_NEON;
994 if (IS_ALIGNED(width, 8)) {
995 I400ToARGBRow = I400ToARGBRow_NEON;
996 }
997 }
998 #endif
999 #if defined(HAS_I400TOARGBROW_MSA)
1000 if (TestCpuFlag(kCpuHasMSA)) {
1001 I400ToARGBRow = I400ToARGBRow_Any_MSA;
1002 if (IS_ALIGNED(width, 16)) {
1003 I400ToARGBRow = I400ToARGBRow_MSA;
1004 }
1005 }
1006 #endif
1007
1008 for (y = 0; y < height; ++y) {
1009 I400ToARGBRow(src_y, dst_argb, width);
1010 dst_argb += dst_stride_argb;
1011 src_y += src_stride_y;
1012 }
1013 return 0;
1014 }
1015
1016 // Convert J400 to ARGB.
1017 LIBYUV_API
J400ToARGB(const uint8_t * src_y,int src_stride_y,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1018 int J400ToARGB(const uint8_t* src_y,
1019 int src_stride_y,
1020 uint8_t* dst_argb,
1021 int dst_stride_argb,
1022 int width,
1023 int height) {
1024 int y;
1025 void (*J400ToARGBRow)(const uint8_t* src_y, uint8_t* dst_argb, int width) =
1026 J400ToARGBRow_C;
1027 if (!src_y || !dst_argb || width <= 0 || height == 0) {
1028 return -1;
1029 }
1030 // Negative height means invert the image.
1031 if (height < 0) {
1032 height = -height;
1033 src_y = src_y + (height - 1) * src_stride_y;
1034 src_stride_y = -src_stride_y;
1035 }
1036 // Coalesce rows.
1037 if (src_stride_y == width && dst_stride_argb == width * 4) {
1038 width *= height;
1039 height = 1;
1040 src_stride_y = dst_stride_argb = 0;
1041 }
1042 #if defined(HAS_J400TOARGBROW_SSE2)
1043 if (TestCpuFlag(kCpuHasSSE2)) {
1044 J400ToARGBRow = J400ToARGBRow_Any_SSE2;
1045 if (IS_ALIGNED(width, 8)) {
1046 J400ToARGBRow = J400ToARGBRow_SSE2;
1047 }
1048 }
1049 #endif
1050 #if defined(HAS_J400TOARGBROW_AVX2)
1051 if (TestCpuFlag(kCpuHasAVX2)) {
1052 J400ToARGBRow = J400ToARGBRow_Any_AVX2;
1053 if (IS_ALIGNED(width, 16)) {
1054 J400ToARGBRow = J400ToARGBRow_AVX2;
1055 }
1056 }
1057 #endif
1058 #if defined(HAS_J400TOARGBROW_NEON)
1059 if (TestCpuFlag(kCpuHasNEON)) {
1060 J400ToARGBRow = J400ToARGBRow_Any_NEON;
1061 if (IS_ALIGNED(width, 8)) {
1062 J400ToARGBRow = J400ToARGBRow_NEON;
1063 }
1064 }
1065 #endif
1066 #if defined(HAS_J400TOARGBROW_MSA)
1067 if (TestCpuFlag(kCpuHasMSA)) {
1068 J400ToARGBRow = J400ToARGBRow_Any_MSA;
1069 if (IS_ALIGNED(width, 16)) {
1070 J400ToARGBRow = J400ToARGBRow_MSA;
1071 }
1072 }
1073 #endif
1074 for (y = 0; y < height; ++y) {
1075 J400ToARGBRow(src_y, dst_argb, width);
1076 src_y += src_stride_y;
1077 dst_argb += dst_stride_argb;
1078 }
1079 return 0;
1080 }
1081
1082 // Shuffle table for converting BGRA to ARGB.
1083 static const uvec8 kShuffleMaskBGRAToARGB = {
1084 3u, 2u, 1u, 0u, 7u, 6u, 5u, 4u, 11u, 10u, 9u, 8u, 15u, 14u, 13u, 12u};
1085
1086 // Shuffle table for converting ABGR to ARGB.
1087 static const uvec8 kShuffleMaskABGRToARGB = {
1088 2u, 1u, 0u, 3u, 6u, 5u, 4u, 7u, 10u, 9u, 8u, 11u, 14u, 13u, 12u, 15u};
1089
1090 // Shuffle table for converting RGBA to ARGB.
1091 static const uvec8 kShuffleMaskRGBAToARGB = {
1092 1u, 2u, 3u, 0u, 5u, 6u, 7u, 4u, 9u, 10u, 11u, 8u, 13u, 14u, 15u, 12u};
1093
1094 // Convert BGRA to ARGB.
1095 LIBYUV_API
BGRAToARGB(const uint8_t * src_bgra,int src_stride_bgra,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1096 int BGRAToARGB(const uint8_t* src_bgra,
1097 int src_stride_bgra,
1098 uint8_t* dst_argb,
1099 int dst_stride_argb,
1100 int width,
1101 int height) {
1102 return ARGBShuffle(src_bgra, src_stride_bgra, dst_argb, dst_stride_argb,
1103 (const uint8_t*)(&kShuffleMaskBGRAToARGB), width, height);
1104 }
1105
1106 // Convert ARGB to BGRA (same as BGRAToARGB).
1107 LIBYUV_API
ARGBToBGRA(const uint8_t * src_bgra,int src_stride_bgra,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1108 int ARGBToBGRA(const uint8_t* src_bgra,
1109 int src_stride_bgra,
1110 uint8_t* dst_argb,
1111 int dst_stride_argb,
1112 int width,
1113 int height) {
1114 return ARGBShuffle(src_bgra, src_stride_bgra, dst_argb, dst_stride_argb,
1115 (const uint8_t*)(&kShuffleMaskBGRAToARGB), width, height);
1116 }
1117
1118 // Convert ABGR to ARGB.
1119 LIBYUV_API
ABGRToARGB(const uint8_t * src_abgr,int src_stride_abgr,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1120 int ABGRToARGB(const uint8_t* src_abgr,
1121 int src_stride_abgr,
1122 uint8_t* dst_argb,
1123 int dst_stride_argb,
1124 int width,
1125 int height) {
1126 return ARGBShuffle(src_abgr, src_stride_abgr, dst_argb, dst_stride_argb,
1127 (const uint8_t*)(&kShuffleMaskABGRToARGB), width, height);
1128 }
1129
1130 // Convert ARGB to ABGR to (same as ABGRToARGB).
1131 LIBYUV_API
ARGBToABGR(const uint8_t * src_abgr,int src_stride_abgr,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1132 int ARGBToABGR(const uint8_t* src_abgr,
1133 int src_stride_abgr,
1134 uint8_t* dst_argb,
1135 int dst_stride_argb,
1136 int width,
1137 int height) {
1138 return ARGBShuffle(src_abgr, src_stride_abgr, dst_argb, dst_stride_argb,
1139 (const uint8_t*)(&kShuffleMaskABGRToARGB), width, height);
1140 }
1141
1142 // Convert RGBA to ARGB.
1143 LIBYUV_API
RGBAToARGB(const uint8_t * src_rgba,int src_stride_rgba,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1144 int RGBAToARGB(const uint8_t* src_rgba,
1145 int src_stride_rgba,
1146 uint8_t* dst_argb,
1147 int dst_stride_argb,
1148 int width,
1149 int height) {
1150 return ARGBShuffle(src_rgba, src_stride_rgba, dst_argb, dst_stride_argb,
1151 (const uint8_t*)(&kShuffleMaskRGBAToARGB), width, height);
1152 }
1153
1154 // Convert RGB24 to ARGB.
1155 LIBYUV_API
RGB24ToARGB(const uint8_t * src_rgb24,int src_stride_rgb24,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1156 int RGB24ToARGB(const uint8_t* src_rgb24,
1157 int src_stride_rgb24,
1158 uint8_t* dst_argb,
1159 int dst_stride_argb,
1160 int width,
1161 int height) {
1162 int y;
1163 void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
1164 RGB24ToARGBRow_C;
1165 if (!src_rgb24 || !dst_argb || width <= 0 || height == 0) {
1166 return -1;
1167 }
1168 // Negative height means invert the image.
1169 if (height < 0) {
1170 height = -height;
1171 src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
1172 src_stride_rgb24 = -src_stride_rgb24;
1173 }
1174 // Coalesce rows.
1175 if (src_stride_rgb24 == width * 3 && dst_stride_argb == width * 4) {
1176 width *= height;
1177 height = 1;
1178 src_stride_rgb24 = dst_stride_argb = 0;
1179 }
1180 #if defined(HAS_RGB24TOARGBROW_SSSE3)
1181 if (TestCpuFlag(kCpuHasSSSE3)) {
1182 RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
1183 if (IS_ALIGNED(width, 16)) {
1184 RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
1185 }
1186 }
1187 #endif
1188 #if defined(HAS_RGB24TOARGBROW_NEON)
1189 if (TestCpuFlag(kCpuHasNEON)) {
1190 RGB24ToARGBRow = RGB24ToARGBRow_Any_NEON;
1191 if (IS_ALIGNED(width, 8)) {
1192 RGB24ToARGBRow = RGB24ToARGBRow_NEON;
1193 }
1194 }
1195 #endif
1196 #if defined(HAS_RGB24TOARGBROW_MSA)
1197 if (TestCpuFlag(kCpuHasMSA)) {
1198 RGB24ToARGBRow = RGB24ToARGBRow_Any_MSA;
1199 if (IS_ALIGNED(width, 16)) {
1200 RGB24ToARGBRow = RGB24ToARGBRow_MSA;
1201 }
1202 }
1203 #endif
1204
1205 for (y = 0; y < height; ++y) {
1206 RGB24ToARGBRow(src_rgb24, dst_argb, width);
1207 src_rgb24 += src_stride_rgb24;
1208 dst_argb += dst_stride_argb;
1209 }
1210 return 0;
1211 }
1212
1213 // Convert RAW to ARGB.
1214 LIBYUV_API
RAWToARGB(const uint8_t * src_raw,int src_stride_raw,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1215 int RAWToARGB(const uint8_t* src_raw,
1216 int src_stride_raw,
1217 uint8_t* dst_argb,
1218 int dst_stride_argb,
1219 int width,
1220 int height) {
1221 int y;
1222 void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
1223 RAWToARGBRow_C;
1224 if (!src_raw || !dst_argb || width <= 0 || height == 0) {
1225 return -1;
1226 }
1227 // Negative height means invert the image.
1228 if (height < 0) {
1229 height = -height;
1230 src_raw = src_raw + (height - 1) * src_stride_raw;
1231 src_stride_raw = -src_stride_raw;
1232 }
1233 // Coalesce rows.
1234 if (src_stride_raw == width * 3 && dst_stride_argb == width * 4) {
1235 width *= height;
1236 height = 1;
1237 src_stride_raw = dst_stride_argb = 0;
1238 }
1239 #if defined(HAS_RAWTOARGBROW_SSSE3)
1240 if (TestCpuFlag(kCpuHasSSSE3)) {
1241 RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
1242 if (IS_ALIGNED(width, 16)) {
1243 RAWToARGBRow = RAWToARGBRow_SSSE3;
1244 }
1245 }
1246 #endif
1247 #if defined(HAS_RAWTOARGBROW_NEON)
1248 if (TestCpuFlag(kCpuHasNEON)) {
1249 RAWToARGBRow = RAWToARGBRow_Any_NEON;
1250 if (IS_ALIGNED(width, 8)) {
1251 RAWToARGBRow = RAWToARGBRow_NEON;
1252 }
1253 }
1254 #endif
1255 #if defined(HAS_RAWTOARGBROW_MSA)
1256 if (TestCpuFlag(kCpuHasMSA)) {
1257 RAWToARGBRow = RAWToARGBRow_Any_MSA;
1258 if (IS_ALIGNED(width, 16)) {
1259 RAWToARGBRow = RAWToARGBRow_MSA;
1260 }
1261 }
1262 #endif
1263
1264 for (y = 0; y < height; ++y) {
1265 RAWToARGBRow(src_raw, dst_argb, width);
1266 src_raw += src_stride_raw;
1267 dst_argb += dst_stride_argb;
1268 }
1269 return 0;
1270 }
1271
1272 // Convert RGB565 to ARGB.
1273 LIBYUV_API
RGB565ToARGB(const uint8_t * src_rgb565,int src_stride_rgb565,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1274 int RGB565ToARGB(const uint8_t* src_rgb565,
1275 int src_stride_rgb565,
1276 uint8_t* dst_argb,
1277 int dst_stride_argb,
1278 int width,
1279 int height) {
1280 int y;
1281 void (*RGB565ToARGBRow)(const uint8_t* src_rgb565, uint8_t* dst_argb,
1282 int width) = RGB565ToARGBRow_C;
1283 if (!src_rgb565 || !dst_argb || width <= 0 || height == 0) {
1284 return -1;
1285 }
1286 // Negative height means invert the image.
1287 if (height < 0) {
1288 height = -height;
1289 src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
1290 src_stride_rgb565 = -src_stride_rgb565;
1291 }
1292 // Coalesce rows.
1293 if (src_stride_rgb565 == width * 2 && dst_stride_argb == width * 4) {
1294 width *= height;
1295 height = 1;
1296 src_stride_rgb565 = dst_stride_argb = 0;
1297 }
1298 #if defined(HAS_RGB565TOARGBROW_SSE2)
1299 if (TestCpuFlag(kCpuHasSSE2)) {
1300 RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
1301 if (IS_ALIGNED(width, 8)) {
1302 RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
1303 }
1304 }
1305 #endif
1306 #if defined(HAS_RGB565TOARGBROW_AVX2)
1307 if (TestCpuFlag(kCpuHasAVX2)) {
1308 RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2;
1309 if (IS_ALIGNED(width, 16)) {
1310 RGB565ToARGBRow = RGB565ToARGBRow_AVX2;
1311 }
1312 }
1313 #endif
1314 #if defined(HAS_RGB565TOARGBROW_NEON)
1315 if (TestCpuFlag(kCpuHasNEON)) {
1316 RGB565ToARGBRow = RGB565ToARGBRow_Any_NEON;
1317 if (IS_ALIGNED(width, 8)) {
1318 RGB565ToARGBRow = RGB565ToARGBRow_NEON;
1319 }
1320 }
1321 #endif
1322 #if defined(HAS_RGB565TOARGBROW_MSA)
1323 if (TestCpuFlag(kCpuHasMSA)) {
1324 RGB565ToARGBRow = RGB565ToARGBRow_Any_MSA;
1325 if (IS_ALIGNED(width, 16)) {
1326 RGB565ToARGBRow = RGB565ToARGBRow_MSA;
1327 }
1328 }
1329 #endif
1330
1331 for (y = 0; y < height; ++y) {
1332 RGB565ToARGBRow(src_rgb565, dst_argb, width);
1333 src_rgb565 += src_stride_rgb565;
1334 dst_argb += dst_stride_argb;
1335 }
1336 return 0;
1337 }
1338
1339 // Convert ARGB1555 to ARGB.
1340 LIBYUV_API
ARGB1555ToARGB(const uint8_t * src_argb1555,int src_stride_argb1555,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1341 int ARGB1555ToARGB(const uint8_t* src_argb1555,
1342 int src_stride_argb1555,
1343 uint8_t* dst_argb,
1344 int dst_stride_argb,
1345 int width,
1346 int height) {
1347 int y;
1348 void (*ARGB1555ToARGBRow)(const uint8_t* src_argb1555, uint8_t* dst_argb,
1349 int width) = ARGB1555ToARGBRow_C;
1350 if (!src_argb1555 || !dst_argb || width <= 0 || height == 0) {
1351 return -1;
1352 }
1353 // Negative height means invert the image.
1354 if (height < 0) {
1355 height = -height;
1356 src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
1357 src_stride_argb1555 = -src_stride_argb1555;
1358 }
1359 // Coalesce rows.
1360 if (src_stride_argb1555 == width * 2 && dst_stride_argb == width * 4) {
1361 width *= height;
1362 height = 1;
1363 src_stride_argb1555 = dst_stride_argb = 0;
1364 }
1365 #if defined(HAS_ARGB1555TOARGBROW_SSE2)
1366 if (TestCpuFlag(kCpuHasSSE2)) {
1367 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
1368 if (IS_ALIGNED(width, 8)) {
1369 ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
1370 }
1371 }
1372 #endif
1373 #if defined(HAS_ARGB1555TOARGBROW_AVX2)
1374 if (TestCpuFlag(kCpuHasAVX2)) {
1375 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2;
1376 if (IS_ALIGNED(width, 16)) {
1377 ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2;
1378 }
1379 }
1380 #endif
1381 #if defined(HAS_ARGB1555TOARGBROW_NEON)
1382 if (TestCpuFlag(kCpuHasNEON)) {
1383 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_NEON;
1384 if (IS_ALIGNED(width, 8)) {
1385 ARGB1555ToARGBRow = ARGB1555ToARGBRow_NEON;
1386 }
1387 }
1388 #endif
1389 #if defined(HAS_ARGB1555TOARGBROW_MSA)
1390 if (TestCpuFlag(kCpuHasMSA)) {
1391 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_MSA;
1392 if (IS_ALIGNED(width, 16)) {
1393 ARGB1555ToARGBRow = ARGB1555ToARGBRow_MSA;
1394 }
1395 }
1396 #endif
1397
1398 for (y = 0; y < height; ++y) {
1399 ARGB1555ToARGBRow(src_argb1555, dst_argb, width);
1400 src_argb1555 += src_stride_argb1555;
1401 dst_argb += dst_stride_argb;
1402 }
1403 return 0;
1404 }
1405
1406 // Convert ARGB4444 to ARGB.
1407 LIBYUV_API
ARGB4444ToARGB(const uint8_t * src_argb4444,int src_stride_argb4444,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1408 int ARGB4444ToARGB(const uint8_t* src_argb4444,
1409 int src_stride_argb4444,
1410 uint8_t* dst_argb,
1411 int dst_stride_argb,
1412 int width,
1413 int height) {
1414 int y;
1415 void (*ARGB4444ToARGBRow)(const uint8_t* src_argb4444, uint8_t* dst_argb,
1416 int width) = ARGB4444ToARGBRow_C;
1417 if (!src_argb4444 || !dst_argb || width <= 0 || height == 0) {
1418 return -1;
1419 }
1420 // Negative height means invert the image.
1421 if (height < 0) {
1422 height = -height;
1423 src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
1424 src_stride_argb4444 = -src_stride_argb4444;
1425 }
1426 // Coalesce rows.
1427 if (src_stride_argb4444 == width * 2 && dst_stride_argb == width * 4) {
1428 width *= height;
1429 height = 1;
1430 src_stride_argb4444 = dst_stride_argb = 0;
1431 }
1432 #if defined(HAS_ARGB4444TOARGBROW_SSE2)
1433 if (TestCpuFlag(kCpuHasSSE2)) {
1434 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
1435 if (IS_ALIGNED(width, 8)) {
1436 ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
1437 }
1438 }
1439 #endif
1440 #if defined(HAS_ARGB4444TOARGBROW_AVX2)
1441 if (TestCpuFlag(kCpuHasAVX2)) {
1442 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2;
1443 if (IS_ALIGNED(width, 16)) {
1444 ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2;
1445 }
1446 }
1447 #endif
1448 #if defined(HAS_ARGB4444TOARGBROW_NEON)
1449 if (TestCpuFlag(kCpuHasNEON)) {
1450 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_NEON;
1451 if (IS_ALIGNED(width, 8)) {
1452 ARGB4444ToARGBRow = ARGB4444ToARGBRow_NEON;
1453 }
1454 }
1455 #endif
1456 #if defined(HAS_ARGB4444TOARGBROW_MSA)
1457 if (TestCpuFlag(kCpuHasMSA)) {
1458 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MSA;
1459 if (IS_ALIGNED(width, 16)) {
1460 ARGB4444ToARGBRow = ARGB4444ToARGBRow_MSA;
1461 }
1462 }
1463 #endif
1464
1465 for (y = 0; y < height; ++y) {
1466 ARGB4444ToARGBRow(src_argb4444, dst_argb, width);
1467 src_argb4444 += src_stride_argb4444;
1468 dst_argb += dst_stride_argb;
1469 }
1470 return 0;
1471 }
1472
1473 // Convert AR30 to ARGB.
1474 LIBYUV_API
AR30ToARGB(const uint8_t * src_ar30,int src_stride_ar30,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1475 int AR30ToARGB(const uint8_t* src_ar30,
1476 int src_stride_ar30,
1477 uint8_t* dst_argb,
1478 int dst_stride_argb,
1479 int width,
1480 int height) {
1481 int y;
1482 if (!src_ar30 || !dst_argb || width <= 0 || height == 0) {
1483 return -1;
1484 }
1485 // Negative height means invert the image.
1486 if (height < 0) {
1487 height = -height;
1488 src_ar30 = src_ar30 + (height - 1) * src_stride_ar30;
1489 src_stride_ar30 = -src_stride_ar30;
1490 }
1491 // Coalesce rows.
1492 if (src_stride_ar30 == width * 4 && dst_stride_argb == width * 4) {
1493 width *= height;
1494 height = 1;
1495 src_stride_ar30 = dst_stride_argb = 0;
1496 }
1497 for (y = 0; y < height; ++y) {
1498 AR30ToARGBRow_C(src_ar30, dst_argb, width);
1499 src_ar30 += src_stride_ar30;
1500 dst_argb += dst_stride_argb;
1501 }
1502 return 0;
1503 }
1504
1505 // Convert AR30 to ABGR.
1506 LIBYUV_API
AR30ToABGR(const uint8_t * src_ar30,int src_stride_ar30,uint8_t * dst_abgr,int dst_stride_abgr,int width,int height)1507 int AR30ToABGR(const uint8_t* src_ar30,
1508 int src_stride_ar30,
1509 uint8_t* dst_abgr,
1510 int dst_stride_abgr,
1511 int width,
1512 int height) {
1513 int y;
1514 if (!src_ar30 || !dst_abgr || width <= 0 || height == 0) {
1515 return -1;
1516 }
1517 // Negative height means invert the image.
1518 if (height < 0) {
1519 height = -height;
1520 src_ar30 = src_ar30 + (height - 1) * src_stride_ar30;
1521 src_stride_ar30 = -src_stride_ar30;
1522 }
1523 // Coalesce rows.
1524 if (src_stride_ar30 == width * 4 && dst_stride_abgr == width * 4) {
1525 width *= height;
1526 height = 1;
1527 src_stride_ar30 = dst_stride_abgr = 0;
1528 }
1529 for (y = 0; y < height; ++y) {
1530 AR30ToABGRRow_C(src_ar30, dst_abgr, width);
1531 src_ar30 += src_stride_ar30;
1532 dst_abgr += dst_stride_abgr;
1533 }
1534 return 0;
1535 }
1536
1537 // Convert AR30 to AB30.
1538 LIBYUV_API
AR30ToAB30(const uint8_t * src_ar30,int src_stride_ar30,uint8_t * dst_ab30,int dst_stride_ab30,int width,int height)1539 int AR30ToAB30(const uint8_t* src_ar30,
1540 int src_stride_ar30,
1541 uint8_t* dst_ab30,
1542 int dst_stride_ab30,
1543 int width,
1544 int height) {
1545 int y;
1546 if (!src_ar30 || !dst_ab30 || width <= 0 || height == 0) {
1547 return -1;
1548 }
1549 // Negative height means invert the image.
1550 if (height < 0) {
1551 height = -height;
1552 src_ar30 = src_ar30 + (height - 1) * src_stride_ar30;
1553 src_stride_ar30 = -src_stride_ar30;
1554 }
1555 // Coalesce rows.
1556 if (src_stride_ar30 == width * 4 && dst_stride_ab30 == width * 4) {
1557 width *= height;
1558 height = 1;
1559 src_stride_ar30 = dst_stride_ab30 = 0;
1560 }
1561 for (y = 0; y < height; ++y) {
1562 AR30ToAB30Row_C(src_ar30, dst_ab30, width);
1563 src_ar30 += src_stride_ar30;
1564 dst_ab30 += dst_stride_ab30;
1565 }
1566 return 0;
1567 }
1568
1569 // Convert NV12 to ARGB with matrix
NV12ToARGBMatrix(const uint8_t * src_y,int src_stride_y,const uint8_t * src_uv,int src_stride_uv,uint8_t * dst_argb,int dst_stride_argb,const struct YuvConstants * yuvconstants,int width,int height)1570 static int NV12ToARGBMatrix(const uint8_t* src_y,
1571 int src_stride_y,
1572 const uint8_t* src_uv,
1573 int src_stride_uv,
1574 uint8_t* dst_argb,
1575 int dst_stride_argb,
1576 const struct YuvConstants* yuvconstants,
1577 int width,
1578 int height) {
1579 int y;
1580 void (*NV12ToARGBRow)(
1581 const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
1582 const struct YuvConstants* yuvconstants, int width) = NV12ToARGBRow_C;
1583 if (!src_y || !src_uv || !dst_argb || width <= 0 || height == 0) {
1584 return -1;
1585 }
1586 // Negative height means invert the image.
1587 if (height < 0) {
1588 height = -height;
1589 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
1590 dst_stride_argb = -dst_stride_argb;
1591 }
1592 #if defined(HAS_NV12TOARGBROW_SSSE3)
1593 if (TestCpuFlag(kCpuHasSSSE3)) {
1594 NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
1595 if (IS_ALIGNED(width, 8)) {
1596 NV12ToARGBRow = NV12ToARGBRow_SSSE3;
1597 }
1598 }
1599 #endif
1600 #if defined(HAS_NV12TOARGBROW_AVX2)
1601 if (TestCpuFlag(kCpuHasAVX2)) {
1602 NV12ToARGBRow = NV12ToARGBRow_Any_AVX2;
1603 if (IS_ALIGNED(width, 16)) {
1604 NV12ToARGBRow = NV12ToARGBRow_AVX2;
1605 }
1606 }
1607 #endif
1608 #if defined(HAS_NV12TOARGBROW_NEON)
1609 if (TestCpuFlag(kCpuHasNEON)) {
1610 NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
1611 if (IS_ALIGNED(width, 8)) {
1612 NV12ToARGBRow = NV12ToARGBRow_NEON;
1613 }
1614 }
1615 #endif
1616 #if defined(HAS_NV12TOARGBROW_MSA)
1617 if (TestCpuFlag(kCpuHasMSA)) {
1618 NV12ToARGBRow = NV12ToARGBRow_Any_MSA;
1619 if (IS_ALIGNED(width, 8)) {
1620 NV12ToARGBRow = NV12ToARGBRow_MSA;
1621 }
1622 }
1623 #endif
1624
1625 for (y = 0; y < height; ++y) {
1626 NV12ToARGBRow(src_y, src_uv, dst_argb, yuvconstants, width);
1627 dst_argb += dst_stride_argb;
1628 src_y += src_stride_y;
1629 if (y & 1) {
1630 src_uv += src_stride_uv;
1631 }
1632 }
1633 return 0;
1634 }
1635
1636 // Convert NV21 to ARGB with matrix
NV21ToARGBMatrix(const uint8_t * src_y,int src_stride_y,const uint8_t * src_vu,int src_stride_vu,uint8_t * dst_argb,int dst_stride_argb,const struct YuvConstants * yuvconstants,int width,int height)1637 static int NV21ToARGBMatrix(const uint8_t* src_y,
1638 int src_stride_y,
1639 const uint8_t* src_vu,
1640 int src_stride_vu,
1641 uint8_t* dst_argb,
1642 int dst_stride_argb,
1643 const struct YuvConstants* yuvconstants,
1644 int width,
1645 int height) {
1646 int y;
1647 void (*NV21ToARGBRow)(
1648 const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
1649 const struct YuvConstants* yuvconstants, int width) = NV21ToARGBRow_C;
1650 if (!src_y || !src_vu || !dst_argb || width <= 0 || height == 0) {
1651 return -1;
1652 }
1653 // Negative height means invert the image.
1654 if (height < 0) {
1655 height = -height;
1656 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
1657 dst_stride_argb = -dst_stride_argb;
1658 }
1659 #if defined(HAS_NV21TOARGBROW_SSSE3)
1660 if (TestCpuFlag(kCpuHasSSSE3)) {
1661 NV21ToARGBRow = NV21ToARGBRow_Any_SSSE3;
1662 if (IS_ALIGNED(width, 8)) {
1663 NV21ToARGBRow = NV21ToARGBRow_SSSE3;
1664 }
1665 }
1666 #endif
1667 #if defined(HAS_NV21TOARGBROW_AVX2)
1668 if (TestCpuFlag(kCpuHasAVX2)) {
1669 NV21ToARGBRow = NV21ToARGBRow_Any_AVX2;
1670 if (IS_ALIGNED(width, 16)) {
1671 NV21ToARGBRow = NV21ToARGBRow_AVX2;
1672 }
1673 }
1674 #endif
1675 #if defined(HAS_NV21TOARGBROW_NEON)
1676 if (TestCpuFlag(kCpuHasNEON)) {
1677 NV21ToARGBRow = NV21ToARGBRow_Any_NEON;
1678 if (IS_ALIGNED(width, 8)) {
1679 NV21ToARGBRow = NV21ToARGBRow_NEON;
1680 }
1681 }
1682 #endif
1683 #if defined(HAS_NV21TOARGBROW_MSA)
1684 if (TestCpuFlag(kCpuHasMSA)) {
1685 NV21ToARGBRow = NV21ToARGBRow_Any_MSA;
1686 if (IS_ALIGNED(width, 8)) {
1687 NV21ToARGBRow = NV21ToARGBRow_MSA;
1688 }
1689 }
1690 #endif
1691
1692 for (y = 0; y < height; ++y) {
1693 NV21ToARGBRow(src_y, src_vu, dst_argb, yuvconstants, width);
1694 dst_argb += dst_stride_argb;
1695 src_y += src_stride_y;
1696 if (y & 1) {
1697 src_vu += src_stride_vu;
1698 }
1699 }
1700 return 0;
1701 }
1702
1703 // Convert NV12 to ARGB.
1704 LIBYUV_API
NV12ToARGB(const uint8_t * src_y,int src_stride_y,const uint8_t * src_uv,int src_stride_uv,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1705 int NV12ToARGB(const uint8_t* src_y,
1706 int src_stride_y,
1707 const uint8_t* src_uv,
1708 int src_stride_uv,
1709 uint8_t* dst_argb,
1710 int dst_stride_argb,
1711 int width,
1712 int height) {
1713 return NV12ToARGBMatrix(src_y, src_stride_y, src_uv, src_stride_uv, dst_argb,
1714 dst_stride_argb, &kYuvI601Constants, width, height);
1715 }
1716
1717 // Convert NV21 to ARGB.
1718 LIBYUV_API
NV21ToARGB(const uint8_t * src_y,int src_stride_y,const uint8_t * src_vu,int src_stride_vu,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1719 int NV21ToARGB(const uint8_t* src_y,
1720 int src_stride_y,
1721 const uint8_t* src_vu,
1722 int src_stride_vu,
1723 uint8_t* dst_argb,
1724 int dst_stride_argb,
1725 int width,
1726 int height) {
1727 return NV21ToARGBMatrix(src_y, src_stride_y, src_vu, src_stride_vu, dst_argb,
1728 dst_stride_argb, &kYuvI601Constants, width, height);
1729 }
1730
1731 // Convert NV12 to ABGR.
1732 // To output ABGR instead of ARGB swap the UV and use a mirrrored yuc matrix.
1733 // To swap the UV use NV12 instead of NV21.LIBYUV_API
NV12ToABGR(const uint8_t * src_y,int src_stride_y,const uint8_t * src_uv,int src_stride_uv,uint8_t * dst_abgr,int dst_stride_abgr,int width,int height)1734 int NV12ToABGR(const uint8_t* src_y,
1735 int src_stride_y,
1736 const uint8_t* src_uv,
1737 int src_stride_uv,
1738 uint8_t* dst_abgr,
1739 int dst_stride_abgr,
1740 int width,
1741 int height) {
1742 return NV21ToARGBMatrix(src_y, src_stride_y, src_uv, src_stride_uv, dst_abgr,
1743 dst_stride_abgr, &kYvuI601Constants, width, height);
1744 }
1745
1746 // Convert NV21 to ABGR.
1747 LIBYUV_API
NV21ToABGR(const uint8_t * src_y,int src_stride_y,const uint8_t * src_vu,int src_stride_vu,uint8_t * dst_abgr,int dst_stride_abgr,int width,int height)1748 int NV21ToABGR(const uint8_t* src_y,
1749 int src_stride_y,
1750 const uint8_t* src_vu,
1751 int src_stride_vu,
1752 uint8_t* dst_abgr,
1753 int dst_stride_abgr,
1754 int width,
1755 int height) {
1756 return NV12ToARGBMatrix(src_y, src_stride_y, src_vu, src_stride_vu, dst_abgr,
1757 dst_stride_abgr, &kYvuI601Constants, width, height);
1758 }
1759
1760 // TODO(fbarchard): Consider SSSE3 2 step conversion.
1761 // Convert NV12 to RGB24 with matrix
NV12ToRGB24Matrix(const uint8_t * src_y,int src_stride_y,const uint8_t * src_uv,int src_stride_uv,uint8_t * dst_rgb24,int dst_stride_rgb24,const struct YuvConstants * yuvconstants,int width,int height)1762 static int NV12ToRGB24Matrix(const uint8_t* src_y,
1763 int src_stride_y,
1764 const uint8_t* src_uv,
1765 int src_stride_uv,
1766 uint8_t* dst_rgb24,
1767 int dst_stride_rgb24,
1768 const struct YuvConstants* yuvconstants,
1769 int width,
1770 int height) {
1771 int y;
1772 void (*NV12ToRGB24Row)(
1773 const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
1774 const struct YuvConstants* yuvconstants, int width) = NV12ToRGB24Row_C;
1775 if (!src_y || !src_uv || !dst_rgb24 || width <= 0 || height == 0) {
1776 return -1;
1777 }
1778 // Negative height means invert the image.
1779 if (height < 0) {
1780 height = -height;
1781 dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
1782 dst_stride_rgb24 = -dst_stride_rgb24;
1783 }
1784 #if defined(HAS_NV12TORGB24ROW_NEON)
1785 if (TestCpuFlag(kCpuHasNEON)) {
1786 NV12ToRGB24Row = NV12ToRGB24Row_Any_NEON;
1787 if (IS_ALIGNED(width, 8)) {
1788 NV12ToRGB24Row = NV12ToRGB24Row_NEON;
1789 }
1790 }
1791 #endif
1792 #if defined(HAS_NV12TORGB24ROW_SSSE3)
1793 if (TestCpuFlag(kCpuHasSSSE3)) {
1794 NV12ToRGB24Row = NV12ToRGB24Row_Any_SSSE3;
1795 if (IS_ALIGNED(width, 16)) {
1796 NV12ToRGB24Row = NV12ToRGB24Row_SSSE3;
1797 }
1798 }
1799 #endif
1800 #if defined(HAS_NV12TORGB24ROW_AVX2)
1801 if (TestCpuFlag(kCpuHasAVX2)) {
1802 NV12ToRGB24Row = NV12ToRGB24Row_Any_AVX2;
1803 if (IS_ALIGNED(width, 32)) {
1804 NV12ToRGB24Row = NV12ToRGB24Row_AVX2;
1805 }
1806 }
1807 #endif
1808
1809 for (y = 0; y < height; ++y) {
1810 NV12ToRGB24Row(src_y, src_uv, dst_rgb24, yuvconstants, width);
1811 dst_rgb24 += dst_stride_rgb24;
1812 src_y += src_stride_y;
1813 if (y & 1) {
1814 src_uv += src_stride_uv;
1815 }
1816 }
1817 return 0;
1818 }
1819
1820 // Convert NV21 to RGB24 with matrix
NV21ToRGB24Matrix(const uint8_t * src_y,int src_stride_y,const uint8_t * src_vu,int src_stride_vu,uint8_t * dst_rgb24,int dst_stride_rgb24,const struct YuvConstants * yuvconstants,int width,int height)1821 static int NV21ToRGB24Matrix(const uint8_t* src_y,
1822 int src_stride_y,
1823 const uint8_t* src_vu,
1824 int src_stride_vu,
1825 uint8_t* dst_rgb24,
1826 int dst_stride_rgb24,
1827 const struct YuvConstants* yuvconstants,
1828 int width,
1829 int height) {
1830 int y;
1831 void (*NV21ToRGB24Row)(
1832 const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
1833 const struct YuvConstants* yuvconstants, int width) = NV21ToRGB24Row_C;
1834 if (!src_y || !src_vu || !dst_rgb24 || width <= 0 || height == 0) {
1835 return -1;
1836 }
1837 // Negative height means invert the image.
1838 if (height < 0) {
1839 height = -height;
1840 dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
1841 dst_stride_rgb24 = -dst_stride_rgb24;
1842 }
1843 #if defined(HAS_NV21TORGB24ROW_NEON)
1844 if (TestCpuFlag(kCpuHasNEON)) {
1845 NV21ToRGB24Row = NV21ToRGB24Row_Any_NEON;
1846 if (IS_ALIGNED(width, 8)) {
1847 NV21ToRGB24Row = NV21ToRGB24Row_NEON;
1848 }
1849 }
1850 #endif
1851 #if defined(HAS_NV21TORGB24ROW_SSSE3)
1852 if (TestCpuFlag(kCpuHasSSSE3)) {
1853 NV21ToRGB24Row = NV21ToRGB24Row_Any_SSSE3;
1854 if (IS_ALIGNED(width, 16)) {
1855 NV21ToRGB24Row = NV21ToRGB24Row_SSSE3;
1856 }
1857 }
1858 #endif
1859 #if defined(HAS_NV21TORGB24ROW_AVX2)
1860 if (TestCpuFlag(kCpuHasAVX2)) {
1861 NV21ToRGB24Row = NV21ToRGB24Row_Any_AVX2;
1862 if (IS_ALIGNED(width, 32)) {
1863 NV21ToRGB24Row = NV21ToRGB24Row_AVX2;
1864 }
1865 }
1866 #endif
1867
1868 for (y = 0; y < height; ++y) {
1869 NV21ToRGB24Row(src_y, src_vu, dst_rgb24, yuvconstants, width);
1870 dst_rgb24 += dst_stride_rgb24;
1871 src_y += src_stride_y;
1872 if (y & 1) {
1873 src_vu += src_stride_vu;
1874 }
1875 }
1876 return 0;
1877 }
1878
1879 // TODO(fbarchard): NV12ToRAW can be implemented by mirrored matrix.
1880 // Convert NV12 to RGB24.
1881 LIBYUV_API
NV12ToRGB24(const uint8_t * src_y,int src_stride_y,const uint8_t * src_uv,int src_stride_uv,uint8_t * dst_rgb24,int dst_stride_rgb24,int width,int height)1882 int NV12ToRGB24(const uint8_t* src_y,
1883 int src_stride_y,
1884 const uint8_t* src_uv,
1885 int src_stride_uv,
1886 uint8_t* dst_rgb24,
1887 int dst_stride_rgb24,
1888 int width,
1889 int height) {
1890 return NV12ToRGB24Matrix(src_y, src_stride_y, src_uv, src_stride_uv,
1891 dst_rgb24, dst_stride_rgb24, &kYuvI601Constants,
1892 width, height);
1893 }
1894
1895 // Convert NV21 to RGB24.
1896 LIBYUV_API
NV21ToRGB24(const uint8_t * src_y,int src_stride_y,const uint8_t * src_vu,int src_stride_vu,uint8_t * dst_rgb24,int dst_stride_rgb24,int width,int height)1897 int NV21ToRGB24(const uint8_t* src_y,
1898 int src_stride_y,
1899 const uint8_t* src_vu,
1900 int src_stride_vu,
1901 uint8_t* dst_rgb24,
1902 int dst_stride_rgb24,
1903 int width,
1904 int height) {
1905 return NV21ToRGB24Matrix(src_y, src_stride_y, src_vu, src_stride_vu,
1906 dst_rgb24, dst_stride_rgb24, &kYuvI601Constants,
1907 width, height);
1908 }
1909
1910 // Convert M420 to ARGB.
1911 LIBYUV_API
M420ToARGB(const uint8_t * src_m420,int src_stride_m420,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1912 int M420ToARGB(const uint8_t* src_m420,
1913 int src_stride_m420,
1914 uint8_t* dst_argb,
1915 int dst_stride_argb,
1916 int width,
1917 int height) {
1918 int y;
1919 void (*NV12ToARGBRow)(
1920 const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
1921 const struct YuvConstants* yuvconstants, int width) = NV12ToARGBRow_C;
1922 if (!src_m420 || !dst_argb || width <= 0 || height == 0) {
1923 return -1;
1924 }
1925 // Negative height means invert the image.
1926 if (height < 0) {
1927 height = -height;
1928 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
1929 dst_stride_argb = -dst_stride_argb;
1930 }
1931 #if defined(HAS_NV12TOARGBROW_SSSE3)
1932 if (TestCpuFlag(kCpuHasSSSE3)) {
1933 NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
1934 if (IS_ALIGNED(width, 8)) {
1935 NV12ToARGBRow = NV12ToARGBRow_SSSE3;
1936 }
1937 }
1938 #endif
1939 #if defined(HAS_NV12TOARGBROW_AVX2)
1940 if (TestCpuFlag(kCpuHasAVX2)) {
1941 NV12ToARGBRow = NV12ToARGBRow_Any_AVX2;
1942 if (IS_ALIGNED(width, 16)) {
1943 NV12ToARGBRow = NV12ToARGBRow_AVX2;
1944 }
1945 }
1946 #endif
1947 #if defined(HAS_NV12TOARGBROW_NEON)
1948 if (TestCpuFlag(kCpuHasNEON)) {
1949 NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
1950 if (IS_ALIGNED(width, 8)) {
1951 NV12ToARGBRow = NV12ToARGBRow_NEON;
1952 }
1953 }
1954 #endif
1955 #if defined(HAS_NV12TOARGBROW_MSA)
1956 if (TestCpuFlag(kCpuHasMSA)) {
1957 NV12ToARGBRow = NV12ToARGBRow_Any_MSA;
1958 if (IS_ALIGNED(width, 8)) {
1959 NV12ToARGBRow = NV12ToARGBRow_MSA;
1960 }
1961 }
1962 #endif
1963
1964 for (y = 0; y < height - 1; y += 2) {
1965 NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb,
1966 &kYuvI601Constants, width);
1967 NV12ToARGBRow(src_m420 + src_stride_m420, src_m420 + src_stride_m420 * 2,
1968 dst_argb + dst_stride_argb, &kYuvI601Constants, width);
1969 dst_argb += dst_stride_argb * 2;
1970 src_m420 += src_stride_m420 * 3;
1971 }
1972 if (height & 1) {
1973 NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb,
1974 &kYuvI601Constants, width);
1975 }
1976 return 0;
1977 }
1978
1979 // Convert YUY2 to ARGB.
1980 LIBYUV_API
YUY2ToARGB(const uint8_t * src_yuy2,int src_stride_yuy2,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1981 int YUY2ToARGB(const uint8_t* src_yuy2,
1982 int src_stride_yuy2,
1983 uint8_t* dst_argb,
1984 int dst_stride_argb,
1985 int width,
1986 int height) {
1987 int y;
1988 void (*YUY2ToARGBRow)(const uint8_t* src_yuy2, uint8_t* dst_argb,
1989 const struct YuvConstants* yuvconstants, int width) =
1990 YUY2ToARGBRow_C;
1991 if (!src_yuy2 || !dst_argb || width <= 0 || height == 0) {
1992 return -1;
1993 }
1994 // Negative height means invert the image.
1995 if (height < 0) {
1996 height = -height;
1997 src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
1998 src_stride_yuy2 = -src_stride_yuy2;
1999 }
2000 // Coalesce rows.
2001 if (src_stride_yuy2 == width * 2 && dst_stride_argb == width * 4) {
2002 width *= height;
2003 height = 1;
2004 src_stride_yuy2 = dst_stride_argb = 0;
2005 }
2006 #if defined(HAS_YUY2TOARGBROW_SSSE3)
2007 if (TestCpuFlag(kCpuHasSSSE3)) {
2008 YUY2ToARGBRow = YUY2ToARGBRow_Any_SSSE3;
2009 if (IS_ALIGNED(width, 16)) {
2010 YUY2ToARGBRow = YUY2ToARGBRow_SSSE3;
2011 }
2012 }
2013 #endif
2014 #if defined(HAS_YUY2TOARGBROW_AVX2)
2015 if (TestCpuFlag(kCpuHasAVX2)) {
2016 YUY2ToARGBRow = YUY2ToARGBRow_Any_AVX2;
2017 if (IS_ALIGNED(width, 32)) {
2018 YUY2ToARGBRow = YUY2ToARGBRow_AVX2;
2019 }
2020 }
2021 #endif
2022 #if defined(HAS_YUY2TOARGBROW_NEON)
2023 if (TestCpuFlag(kCpuHasNEON)) {
2024 YUY2ToARGBRow = YUY2ToARGBRow_Any_NEON;
2025 if (IS_ALIGNED(width, 8)) {
2026 YUY2ToARGBRow = YUY2ToARGBRow_NEON;
2027 }
2028 }
2029 #endif
2030 #if defined(HAS_YUY2TOARGBROW_MSA)
2031 if (TestCpuFlag(kCpuHasMSA)) {
2032 YUY2ToARGBRow = YUY2ToARGBRow_Any_MSA;
2033 if (IS_ALIGNED(width, 8)) {
2034 YUY2ToARGBRow = YUY2ToARGBRow_MSA;
2035 }
2036 }
2037 #endif
2038 for (y = 0; y < height; ++y) {
2039 YUY2ToARGBRow(src_yuy2, dst_argb, &kYuvI601Constants, width);
2040 src_yuy2 += src_stride_yuy2;
2041 dst_argb += dst_stride_argb;
2042 }
2043 return 0;
2044 }
2045
2046 // Convert UYVY to ARGB.
2047 LIBYUV_API
UYVYToARGB(const uint8_t * src_uyvy,int src_stride_uyvy,uint8_t * dst_argb,int dst_stride_argb,int width,int height)2048 int UYVYToARGB(const uint8_t* src_uyvy,
2049 int src_stride_uyvy,
2050 uint8_t* dst_argb,
2051 int dst_stride_argb,
2052 int width,
2053 int height) {
2054 int y;
2055 void (*UYVYToARGBRow)(const uint8_t* src_uyvy, uint8_t* dst_argb,
2056 const struct YuvConstants* yuvconstants, int width) =
2057 UYVYToARGBRow_C;
2058 if (!src_uyvy || !dst_argb || width <= 0 || height == 0) {
2059 return -1;
2060 }
2061 // Negative height means invert the image.
2062 if (height < 0) {
2063 height = -height;
2064 src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
2065 src_stride_uyvy = -src_stride_uyvy;
2066 }
2067 // Coalesce rows.
2068 if (src_stride_uyvy == width * 2 && dst_stride_argb == width * 4) {
2069 width *= height;
2070 height = 1;
2071 src_stride_uyvy = dst_stride_argb = 0;
2072 }
2073 #if defined(HAS_UYVYTOARGBROW_SSSE3)
2074 if (TestCpuFlag(kCpuHasSSSE3)) {
2075 UYVYToARGBRow = UYVYToARGBRow_Any_SSSE3;
2076 if (IS_ALIGNED(width, 16)) {
2077 UYVYToARGBRow = UYVYToARGBRow_SSSE3;
2078 }
2079 }
2080 #endif
2081 #if defined(HAS_UYVYTOARGBROW_AVX2)
2082 if (TestCpuFlag(kCpuHasAVX2)) {
2083 UYVYToARGBRow = UYVYToARGBRow_Any_AVX2;
2084 if (IS_ALIGNED(width, 32)) {
2085 UYVYToARGBRow = UYVYToARGBRow_AVX2;
2086 }
2087 }
2088 #endif
2089 #if defined(HAS_UYVYTOARGBROW_NEON)
2090 if (TestCpuFlag(kCpuHasNEON)) {
2091 UYVYToARGBRow = UYVYToARGBRow_Any_NEON;
2092 if (IS_ALIGNED(width, 8)) {
2093 UYVYToARGBRow = UYVYToARGBRow_NEON;
2094 }
2095 }
2096 #endif
2097 #if defined(HAS_UYVYTOARGBROW_MSA)
2098 if (TestCpuFlag(kCpuHasMSA)) {
2099 UYVYToARGBRow = UYVYToARGBRow_Any_MSA;
2100 if (IS_ALIGNED(width, 8)) {
2101 UYVYToARGBRow = UYVYToARGBRow_MSA;
2102 }
2103 }
2104 #endif
2105 for (y = 0; y < height; ++y) {
2106 UYVYToARGBRow(src_uyvy, dst_argb, &kYuvI601Constants, width);
2107 src_uyvy += src_stride_uyvy;
2108 dst_argb += dst_stride_argb;
2109 }
2110 return 0;
2111 }
WeavePixels(const uint8_t * src_u,const uint8_t * src_v,int src_pixel_stride_uv,uint8_t * dst_uv,int width)2112 static void WeavePixels(const uint8_t* src_u,
2113 const uint8_t* src_v,
2114 int src_pixel_stride_uv,
2115 uint8_t* dst_uv,
2116 int width) {
2117 int i;
2118 for (i = 0; i < width; ++i) {
2119 dst_uv[0] = *src_u;
2120 dst_uv[1] = *src_v;
2121 dst_uv += 2;
2122 src_u += src_pixel_stride_uv;
2123 src_v += src_pixel_stride_uv;
2124 }
2125 }
2126
2127 // Convert Android420 to ARGB.
2128 LIBYUV_API
Android420ToARGBMatrix(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,int src_pixel_stride_uv,uint8_t * dst_argb,int dst_stride_argb,const struct YuvConstants * yuvconstants,int width,int height)2129 int Android420ToARGBMatrix(const uint8_t* src_y,
2130 int src_stride_y,
2131 const uint8_t* src_u,
2132 int src_stride_u,
2133 const uint8_t* src_v,
2134 int src_stride_v,
2135 int src_pixel_stride_uv,
2136 uint8_t* dst_argb,
2137 int dst_stride_argb,
2138 const struct YuvConstants* yuvconstants,
2139 int width,
2140 int height) {
2141 int y;
2142 uint8_t* dst_uv;
2143 const ptrdiff_t vu_off = src_v - src_u;
2144 int halfwidth = (width + 1) >> 1;
2145 int halfheight = (height + 1) >> 1;
2146 if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
2147 return -1;
2148 }
2149 // Negative height means invert the image.
2150 if (height < 0) {
2151 height = -height;
2152 halfheight = (height + 1) >> 1;
2153 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
2154 dst_stride_argb = -dst_stride_argb;
2155 }
2156
2157 // I420
2158 if (src_pixel_stride_uv == 1) {
2159 return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
2160 src_stride_v, dst_argb, dst_stride_argb,
2161 yuvconstants, width, height);
2162 // NV21
2163 }
2164 if (src_pixel_stride_uv == 2 && vu_off == -1 &&
2165 src_stride_u == src_stride_v) {
2166 return NV21ToARGBMatrix(src_y, src_stride_y, src_v, src_stride_v, dst_argb,
2167 dst_stride_argb, yuvconstants, width, height);
2168 // NV12
2169 }
2170 if (src_pixel_stride_uv == 2 && vu_off == 1 && src_stride_u == src_stride_v) {
2171 return NV12ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, dst_argb,
2172 dst_stride_argb, yuvconstants, width, height);
2173 }
2174
2175 // General case fallback creates NV12
2176 align_buffer_64(plane_uv, halfwidth * 2 * halfheight);
2177 dst_uv = plane_uv;
2178 for (y = 0; y < halfheight; ++y) {
2179 WeavePixels(src_u, src_v, src_pixel_stride_uv, dst_uv, halfwidth);
2180 src_u += src_stride_u;
2181 src_v += src_stride_v;
2182 dst_uv += halfwidth * 2;
2183 }
2184 NV12ToARGBMatrix(src_y, src_stride_y, plane_uv, halfwidth * 2, dst_argb,
2185 dst_stride_argb, yuvconstants, width, height);
2186 free_aligned_buffer_64(plane_uv);
2187 return 0;
2188 }
2189
2190 // Convert Android420 to ARGB.
2191 LIBYUV_API
Android420ToARGB(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,int src_pixel_stride_uv,uint8_t * dst_argb,int dst_stride_argb,int width,int height)2192 int Android420ToARGB(const uint8_t* src_y,
2193 int src_stride_y,
2194 const uint8_t* src_u,
2195 int src_stride_u,
2196 const uint8_t* src_v,
2197 int src_stride_v,
2198 int src_pixel_stride_uv,
2199 uint8_t* dst_argb,
2200 int dst_stride_argb,
2201 int width,
2202 int height) {
2203 return Android420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
2204 src_stride_v, src_pixel_stride_uv, dst_argb,
2205 dst_stride_argb, &kYuvI601Constants, width,
2206 height);
2207 }
2208
2209 // Convert Android420 to ABGR.
2210 LIBYUV_API
Android420ToABGR(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,int src_pixel_stride_uv,uint8_t * dst_abgr,int dst_stride_abgr,int width,int height)2211 int Android420ToABGR(const uint8_t* src_y,
2212 int src_stride_y,
2213 const uint8_t* src_u,
2214 int src_stride_u,
2215 const uint8_t* src_v,
2216 int src_stride_v,
2217 int src_pixel_stride_uv,
2218 uint8_t* dst_abgr,
2219 int dst_stride_abgr,
2220 int width,
2221 int height) {
2222 return Android420ToARGBMatrix(src_y, src_stride_y, src_v, src_stride_v, src_u,
2223 src_stride_u, src_pixel_stride_uv, dst_abgr,
2224 dst_stride_abgr, &kYvuI601Constants, width,
2225 height);
2226 }
2227
2228 #ifdef __cplusplus
2229 } // extern "C"
2230 } // namespace libyuv
2231 #endif
2232