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
23namespace libyuv {
24extern "C" {
25#endif
26
27// Copy ARGB with optional flipping
28LIBYUV_API
29int ARGBCopy(const uint8* src_argb,
30             int src_stride_argb,
31             uint8* 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 I422 to ARGB with matrix
51static int I420ToARGBMatrix(const uint8* src_y,
52                            int src_stride_y,
53                            const uint8* src_u,
54                            int src_stride_u,
55                            const uint8* src_v,
56                            int src_stride_v,
57                            uint8* 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* y_buf, const uint8* u_buf,
64                        const uint8* v_buf, uint8* 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_DSPR2)
101  if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 4) &&
102      IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
103      IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
104      IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
105      IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) {
106    I422ToARGBRow = I422ToARGBRow_DSPR2;
107  }
108#endif
109#if defined(HAS_I422TOARGBROW_MSA)
110  if (TestCpuFlag(kCpuHasMSA)) {
111    I422ToARGBRow = I422ToARGBRow_Any_MSA;
112    if (IS_ALIGNED(width, 8)) {
113      I422ToARGBRow = I422ToARGBRow_MSA;
114    }
115  }
116#endif
117
118  for (y = 0; y < height; ++y) {
119    I422ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
120    dst_argb += dst_stride_argb;
121    src_y += src_stride_y;
122    if (y & 1) {
123      src_u += src_stride_u;
124      src_v += src_stride_v;
125    }
126  }
127  return 0;
128}
129
130// Convert I420 to ARGB.
131LIBYUV_API
132int I420ToARGB(const uint8* src_y,
133               int src_stride_y,
134               const uint8* src_u,
135               int src_stride_u,
136               const uint8* src_v,
137               int src_stride_v,
138               uint8* dst_argb,
139               int dst_stride_argb,
140               int width,
141               int height) {
142  return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
143                          src_stride_v, dst_argb, dst_stride_argb,
144                          &kYuvI601Constants, width, height);
145}
146
147// Convert I420 to ABGR.
148LIBYUV_API
149int I420ToABGR(const uint8* src_y,
150               int src_stride_y,
151               const uint8* src_u,
152               int src_stride_u,
153               const uint8* src_v,
154               int src_stride_v,
155               uint8* dst_abgr,
156               int dst_stride_abgr,
157               int width,
158               int height) {
159  return I420ToARGBMatrix(src_y, src_stride_y, src_v,
160                          src_stride_v,  // Swap U and V
161                          src_u, src_stride_u, dst_abgr, dst_stride_abgr,
162                          &kYvuI601Constants,  // Use Yvu matrix
163                          width, height);
164}
165
166// Convert J420 to ARGB.
167LIBYUV_API
168int J420ToARGB(const uint8* src_y,
169               int src_stride_y,
170               const uint8* src_u,
171               int src_stride_u,
172               const uint8* src_v,
173               int src_stride_v,
174               uint8* dst_argb,
175               int dst_stride_argb,
176               int width,
177               int height) {
178  return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
179                          src_stride_v, dst_argb, dst_stride_argb,
180                          &kYuvJPEGConstants, width, height);
181}
182
183// Convert J420 to ABGR.
184LIBYUV_API
185int J420ToABGR(const uint8* src_y,
186               int src_stride_y,
187               const uint8* src_u,
188               int src_stride_u,
189               const uint8* src_v,
190               int src_stride_v,
191               uint8* dst_abgr,
192               int dst_stride_abgr,
193               int width,
194               int height) {
195  return I420ToARGBMatrix(src_y, src_stride_y, src_v,
196                          src_stride_v,  // Swap U and V
197                          src_u, src_stride_u, dst_abgr, dst_stride_abgr,
198                          &kYvuJPEGConstants,  // Use Yvu matrix
199                          width, height);
200}
201
202// Convert H420 to ARGB.
203LIBYUV_API
204int H420ToARGB(const uint8* src_y,
205               int src_stride_y,
206               const uint8* src_u,
207               int src_stride_u,
208               const uint8* src_v,
209               int src_stride_v,
210               uint8* dst_argb,
211               int dst_stride_argb,
212               int width,
213               int height) {
214  return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
215                          src_stride_v, dst_argb, dst_stride_argb,
216                          &kYuvH709Constants, width, height);
217}
218
219// Convert H420 to ABGR.
220LIBYUV_API
221int H420ToABGR(const uint8* src_y,
222               int src_stride_y,
223               const uint8* src_u,
224               int src_stride_u,
225               const uint8* src_v,
226               int src_stride_v,
227               uint8* dst_abgr,
228               int dst_stride_abgr,
229               int width,
230               int height) {
231  return I420ToARGBMatrix(src_y, src_stride_y, src_v,
232                          src_stride_v,  // Swap U and V
233                          src_u, src_stride_u, dst_abgr, dst_stride_abgr,
234                          &kYvuH709Constants,  // Use Yvu matrix
235                          width, height);
236}
237
238// Convert I422 to ARGB with matrix
239static int I422ToARGBMatrix(const uint8* src_y,
240                            int src_stride_y,
241                            const uint8* src_u,
242                            int src_stride_u,
243                            const uint8* src_v,
244                            int src_stride_v,
245                            uint8* dst_argb,
246                            int dst_stride_argb,
247                            const struct YuvConstants* yuvconstants,
248                            int width,
249                            int height) {
250  int y;
251  void (*I422ToARGBRow)(const uint8* y_buf, const uint8* u_buf,
252                        const uint8* v_buf, uint8* rgb_buf,
253                        const struct YuvConstants* yuvconstants, int width) =
254      I422ToARGBRow_C;
255  if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
256    return -1;
257  }
258  // Negative height means invert the image.
259  if (height < 0) {
260    height = -height;
261    dst_argb = dst_argb + (height - 1) * dst_stride_argb;
262    dst_stride_argb = -dst_stride_argb;
263  }
264  // Coalesce rows.
265  if (src_stride_y == width && src_stride_u * 2 == width &&
266      src_stride_v * 2 == width && dst_stride_argb == width * 4) {
267    width *= height;
268    height = 1;
269    src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
270  }
271#if defined(HAS_I422TOARGBROW_SSSE3)
272  if (TestCpuFlag(kCpuHasSSSE3)) {
273    I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
274    if (IS_ALIGNED(width, 8)) {
275      I422ToARGBRow = I422ToARGBRow_SSSE3;
276    }
277  }
278#endif
279#if defined(HAS_I422TOARGBROW_AVX2)
280  if (TestCpuFlag(kCpuHasAVX2)) {
281    I422ToARGBRow = I422ToARGBRow_Any_AVX2;
282    if (IS_ALIGNED(width, 16)) {
283      I422ToARGBRow = I422ToARGBRow_AVX2;
284    }
285  }
286#endif
287#if defined(HAS_I422TOARGBROW_NEON)
288  if (TestCpuFlag(kCpuHasNEON)) {
289    I422ToARGBRow = I422ToARGBRow_Any_NEON;
290    if (IS_ALIGNED(width, 8)) {
291      I422ToARGBRow = I422ToARGBRow_NEON;
292    }
293  }
294#endif
295#if defined(HAS_I422TOARGBROW_DSPR2)
296  if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 4) &&
297      IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
298      IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
299      IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
300      IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) {
301    I422ToARGBRow = I422ToARGBRow_DSPR2;
302  }
303#endif
304#if defined(HAS_I422TOARGBROW_MSA)
305  if (TestCpuFlag(kCpuHasMSA)) {
306    I422ToARGBRow = I422ToARGBRow_Any_MSA;
307    if (IS_ALIGNED(width, 8)) {
308      I422ToARGBRow = I422ToARGBRow_MSA;
309    }
310  }
311#endif
312
313  for (y = 0; y < height; ++y) {
314    I422ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
315    dst_argb += dst_stride_argb;
316    src_y += src_stride_y;
317    src_u += src_stride_u;
318    src_v += src_stride_v;
319  }
320  return 0;
321}
322
323// Convert I422 to ARGB.
324LIBYUV_API
325int I422ToARGB(const uint8* src_y,
326               int src_stride_y,
327               const uint8* src_u,
328               int src_stride_u,
329               const uint8* src_v,
330               int src_stride_v,
331               uint8* dst_argb,
332               int dst_stride_argb,
333               int width,
334               int height) {
335  return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
336                          src_stride_v, dst_argb, dst_stride_argb,
337                          &kYuvI601Constants, width, height);
338}
339
340// Convert I422 to ABGR.
341LIBYUV_API
342int I422ToABGR(const uint8* src_y,
343               int src_stride_y,
344               const uint8* src_u,
345               int src_stride_u,
346               const uint8* src_v,
347               int src_stride_v,
348               uint8* dst_abgr,
349               int dst_stride_abgr,
350               int width,
351               int height) {
352  return I422ToARGBMatrix(src_y, src_stride_y, src_v,
353                          src_stride_v,  // Swap U and V
354                          src_u, src_stride_u, dst_abgr, dst_stride_abgr,
355                          &kYvuI601Constants,  // Use Yvu matrix
356                          width, height);
357}
358
359// Convert J422 to ARGB.
360LIBYUV_API
361int J422ToARGB(const uint8* src_y,
362               int src_stride_y,
363               const uint8* src_u,
364               int src_stride_u,
365               const uint8* src_v,
366               int src_stride_v,
367               uint8* dst_argb,
368               int dst_stride_argb,
369               int width,
370               int height) {
371  return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
372                          src_stride_v, dst_argb, dst_stride_argb,
373                          &kYuvJPEGConstants, width, height);
374}
375
376// Convert J422 to ABGR.
377LIBYUV_API
378int J422ToABGR(const uint8* src_y,
379               int src_stride_y,
380               const uint8* src_u,
381               int src_stride_u,
382               const uint8* src_v,
383               int src_stride_v,
384               uint8* dst_abgr,
385               int dst_stride_abgr,
386               int width,
387               int height) {
388  return I422ToARGBMatrix(src_y, src_stride_y, src_v,
389                          src_stride_v,  // Swap U and V
390                          src_u, src_stride_u, dst_abgr, dst_stride_abgr,
391                          &kYvuJPEGConstants,  // Use Yvu matrix
392                          width, height);
393}
394
395// Convert H422 to ARGB.
396LIBYUV_API
397int H422ToARGB(const uint8* src_y,
398               int src_stride_y,
399               const uint8* src_u,
400               int src_stride_u,
401               const uint8* src_v,
402               int src_stride_v,
403               uint8* dst_argb,
404               int dst_stride_argb,
405               int width,
406               int height) {
407  return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
408                          src_stride_v, dst_argb, dst_stride_argb,
409                          &kYuvH709Constants, width, height);
410}
411
412// Convert H422 to ABGR.
413LIBYUV_API
414int H422ToABGR(const uint8* src_y,
415               int src_stride_y,
416               const uint8* src_u,
417               int src_stride_u,
418               const uint8* src_v,
419               int src_stride_v,
420               uint8* dst_abgr,
421               int dst_stride_abgr,
422               int width,
423               int height) {
424  return I422ToARGBMatrix(src_y, src_stride_y, src_v,
425                          src_stride_v,  // Swap U and V
426                          src_u, src_stride_u, dst_abgr, dst_stride_abgr,
427                          &kYvuH709Constants,  // Use Yvu matrix
428                          width, height);
429}
430
431// Convert I444 to ARGB with matrix
432static int I444ToARGBMatrix(const uint8* src_y,
433                            int src_stride_y,
434                            const uint8* src_u,
435                            int src_stride_u,
436                            const uint8* src_v,
437                            int src_stride_v,
438                            uint8* dst_argb,
439                            int dst_stride_argb,
440                            const struct YuvConstants* yuvconstants,
441                            int width,
442                            int height) {
443  int y;
444  void (*I444ToARGBRow)(const uint8* y_buf, const uint8* u_buf,
445                        const uint8* v_buf, uint8* rgb_buf,
446                        const struct YuvConstants* yuvconstants, int width) =
447      I444ToARGBRow_C;
448  if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
449    return -1;
450  }
451  // Negative height means invert the image.
452  if (height < 0) {
453    height = -height;
454    dst_argb = dst_argb + (height - 1) * dst_stride_argb;
455    dst_stride_argb = -dst_stride_argb;
456  }
457  // Coalesce rows.
458  if (src_stride_y == width && src_stride_u == width && src_stride_v == width &&
459      dst_stride_argb == width * 4) {
460    width *= height;
461    height = 1;
462    src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
463  }
464#if defined(HAS_I444TOARGBROW_SSSE3)
465  if (TestCpuFlag(kCpuHasSSSE3)) {
466    I444ToARGBRow = I444ToARGBRow_Any_SSSE3;
467    if (IS_ALIGNED(width, 8)) {
468      I444ToARGBRow = I444ToARGBRow_SSSE3;
469    }
470  }
471#endif
472#if defined(HAS_I444TOARGBROW_AVX2)
473  if (TestCpuFlag(kCpuHasAVX2)) {
474    I444ToARGBRow = I444ToARGBRow_Any_AVX2;
475    if (IS_ALIGNED(width, 16)) {
476      I444ToARGBRow = I444ToARGBRow_AVX2;
477    }
478  }
479#endif
480#if defined(HAS_I444TOARGBROW_NEON)
481  if (TestCpuFlag(kCpuHasNEON)) {
482    I444ToARGBRow = I444ToARGBRow_Any_NEON;
483    if (IS_ALIGNED(width, 8)) {
484      I444ToARGBRow = I444ToARGBRow_NEON;
485    }
486  }
487#endif
488#if defined(HAS_I444TOARGBROW_DSPR2)
489  if (TestCpuFlag(kCpuHasDSPR2)) {
490    I444ToARGBRow = I444ToARGBRow_Any_DSPR2;
491    if (IS_ALIGNED(width, 8)) {
492      I444ToARGBRow = I444ToARGBRow_DSPR2;
493    }
494  }
495#endif
496#if defined(HAS_I444TOARGBROW_MSA)
497  if (TestCpuFlag(kCpuHasMSA)) {
498    I444ToARGBRow = I444ToARGBRow_Any_MSA;
499    if (IS_ALIGNED(width, 8)) {
500      I444ToARGBRow = I444ToARGBRow_MSA;
501    }
502  }
503#endif
504
505  for (y = 0; y < height; ++y) {
506    I444ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
507    dst_argb += dst_stride_argb;
508    src_y += src_stride_y;
509    src_u += src_stride_u;
510    src_v += src_stride_v;
511  }
512  return 0;
513}
514
515// Convert I444 to ARGB.
516LIBYUV_API
517int I444ToARGB(const uint8* src_y,
518               int src_stride_y,
519               const uint8* src_u,
520               int src_stride_u,
521               const uint8* src_v,
522               int src_stride_v,
523               uint8* dst_argb,
524               int dst_stride_argb,
525               int width,
526               int height) {
527  return I444ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
528                          src_stride_v, dst_argb, dst_stride_argb,
529                          &kYuvI601Constants, width, height);
530}
531
532// Convert I444 to ABGR.
533LIBYUV_API
534int I444ToABGR(const uint8* src_y,
535               int src_stride_y,
536               const uint8* src_u,
537               int src_stride_u,
538               const uint8* src_v,
539               int src_stride_v,
540               uint8* dst_abgr,
541               int dst_stride_abgr,
542               int width,
543               int height) {
544  return I444ToARGBMatrix(src_y, src_stride_y, src_v,
545                          src_stride_v,  // Swap U and V
546                          src_u, src_stride_u, dst_abgr, dst_stride_abgr,
547                          &kYvuI601Constants,  // Use Yvu matrix
548                          width, height);
549}
550
551// Convert J444 to ARGB.
552LIBYUV_API
553int J444ToARGB(const uint8* src_y,
554               int src_stride_y,
555               const uint8* src_u,
556               int src_stride_u,
557               const uint8* src_v,
558               int src_stride_v,
559               uint8* dst_argb,
560               int dst_stride_argb,
561               int width,
562               int height) {
563  return I444ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
564                          src_stride_v, dst_argb, dst_stride_argb,
565                          &kYuvJPEGConstants, width, height);
566}
567
568// Convert I420 with Alpha to preattenuated ARGB.
569static int I420AlphaToARGBMatrix(const uint8* src_y,
570                                 int src_stride_y,
571                                 const uint8* src_u,
572                                 int src_stride_u,
573                                 const uint8* src_v,
574                                 int src_stride_v,
575                                 const uint8* src_a,
576                                 int src_stride_a,
577                                 uint8* dst_argb,
578                                 int dst_stride_argb,
579                                 const struct YuvConstants* yuvconstants,
580                                 int width,
581                                 int height,
582                                 int attenuate) {
583  int y;
584  void (*I422AlphaToARGBRow)(const uint8* y_buf, const uint8* u_buf,
585                             const uint8* v_buf, const uint8* a_buf,
586                             uint8* dst_argb,
587                             const struct YuvConstants* yuvconstants,
588                             int width) = I422AlphaToARGBRow_C;
589  void (*ARGBAttenuateRow)(const uint8* src_argb, uint8* dst_argb, int width) =
590      ARGBAttenuateRow_C;
591  if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
592    return -1;
593  }
594  // Negative height means invert the image.
595  if (height < 0) {
596    height = -height;
597    dst_argb = dst_argb + (height - 1) * dst_stride_argb;
598    dst_stride_argb = -dst_stride_argb;
599  }
600#if defined(HAS_I422ALPHATOARGBROW_SSSE3)
601  if (TestCpuFlag(kCpuHasSSSE3)) {
602    I422AlphaToARGBRow = I422AlphaToARGBRow_Any_SSSE3;
603    if (IS_ALIGNED(width, 8)) {
604      I422AlphaToARGBRow = I422AlphaToARGBRow_SSSE3;
605    }
606  }
607#endif
608#if defined(HAS_I422ALPHATOARGBROW_AVX2)
609  if (TestCpuFlag(kCpuHasAVX2)) {
610    I422AlphaToARGBRow = I422AlphaToARGBRow_Any_AVX2;
611    if (IS_ALIGNED(width, 16)) {
612      I422AlphaToARGBRow = I422AlphaToARGBRow_AVX2;
613    }
614  }
615#endif
616#if defined(HAS_I422ALPHATOARGBROW_NEON)
617  if (TestCpuFlag(kCpuHasNEON)) {
618    I422AlphaToARGBRow = I422AlphaToARGBRow_Any_NEON;
619    if (IS_ALIGNED(width, 8)) {
620      I422AlphaToARGBRow = I422AlphaToARGBRow_NEON;
621    }
622  }
623#endif
624#if defined(HAS_I422ALPHATOARGBROW_DSPR2)
625  if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 4) &&
626      IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
627      IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
628      IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
629      IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) {
630    I422AlphaToARGBRow = I422AlphaToARGBRow_DSPR2;
631  }
632#endif
633#if defined(HAS_I422ALPHATOARGBROW_MSA)
634  if (TestCpuFlag(kCpuHasMSA)) {
635    I422AlphaToARGBRow = I422AlphaToARGBRow_Any_MSA;
636    if (IS_ALIGNED(width, 8)) {
637      I422AlphaToARGBRow = I422AlphaToARGBRow_MSA;
638    }
639  }
640#endif
641#if defined(HAS_ARGBATTENUATEROW_SSSE3)
642  if (TestCpuFlag(kCpuHasSSSE3)) {
643    ARGBAttenuateRow = ARGBAttenuateRow_Any_SSSE3;
644    if (IS_ALIGNED(width, 4)) {
645      ARGBAttenuateRow = ARGBAttenuateRow_SSSE3;
646    }
647  }
648#endif
649#if defined(HAS_ARGBATTENUATEROW_AVX2)
650  if (TestCpuFlag(kCpuHasAVX2)) {
651    ARGBAttenuateRow = ARGBAttenuateRow_Any_AVX2;
652    if (IS_ALIGNED(width, 8)) {
653      ARGBAttenuateRow = ARGBAttenuateRow_AVX2;
654    }
655  }
656#endif
657#if defined(HAS_ARGBATTENUATEROW_NEON)
658  if (TestCpuFlag(kCpuHasNEON)) {
659    ARGBAttenuateRow = ARGBAttenuateRow_Any_NEON;
660    if (IS_ALIGNED(width, 8)) {
661      ARGBAttenuateRow = ARGBAttenuateRow_NEON;
662    }
663  }
664#endif
665#if defined(HAS_ARGBATTENUATEROW_MSA)
666  if (TestCpuFlag(kCpuHasMSA)) {
667    ARGBAttenuateRow = ARGBAttenuateRow_Any_MSA;
668    if (IS_ALIGNED(width, 8)) {
669      ARGBAttenuateRow = ARGBAttenuateRow_MSA;
670    }
671  }
672#endif
673
674  for (y = 0; y < height; ++y) {
675    I422AlphaToARGBRow(src_y, src_u, src_v, src_a, dst_argb, yuvconstants,
676                       width);
677    if (attenuate) {
678      ARGBAttenuateRow(dst_argb, dst_argb, width);
679    }
680    dst_argb += dst_stride_argb;
681    src_a += src_stride_a;
682    src_y += src_stride_y;
683    if (y & 1) {
684      src_u += src_stride_u;
685      src_v += src_stride_v;
686    }
687  }
688  return 0;
689}
690
691// Convert I420 with Alpha to ARGB.
692LIBYUV_API
693int I420AlphaToARGB(const uint8* src_y,
694                    int src_stride_y,
695                    const uint8* src_u,
696                    int src_stride_u,
697                    const uint8* src_v,
698                    int src_stride_v,
699                    const uint8* src_a,
700                    int src_stride_a,
701                    uint8* dst_argb,
702                    int dst_stride_argb,
703                    int width,
704                    int height,
705                    int attenuate) {
706  return I420AlphaToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
707                               src_stride_v, src_a, src_stride_a, dst_argb,
708                               dst_stride_argb, &kYuvI601Constants, width,
709                               height, attenuate);
710}
711
712// Convert I420 with Alpha to ABGR.
713LIBYUV_API
714int I420AlphaToABGR(const uint8* src_y,
715                    int src_stride_y,
716                    const uint8* src_u,
717                    int src_stride_u,
718                    const uint8* src_v,
719                    int src_stride_v,
720                    const uint8* src_a,
721                    int src_stride_a,
722                    uint8* dst_abgr,
723                    int dst_stride_abgr,
724                    int width,
725                    int height,
726                    int attenuate) {
727  return I420AlphaToARGBMatrix(
728      src_y, src_stride_y, src_v, src_stride_v,  // Swap U and V
729      src_u, src_stride_u, src_a, src_stride_a, dst_abgr, dst_stride_abgr,
730      &kYvuI601Constants,  // Use Yvu matrix
731      width, height, attenuate);
732}
733
734// Convert I400 to ARGB.
735LIBYUV_API
736int I400ToARGB(const uint8* src_y,
737               int src_stride_y,
738               uint8* dst_argb,
739               int dst_stride_argb,
740               int width,
741               int height) {
742  int y;
743  void (*I400ToARGBRow)(const uint8* y_buf, uint8* rgb_buf, int width) =
744      I400ToARGBRow_C;
745  if (!src_y || !dst_argb || width <= 0 || height == 0) {
746    return -1;
747  }
748  // Negative height means invert the image.
749  if (height < 0) {
750    height = -height;
751    dst_argb = dst_argb + (height - 1) * dst_stride_argb;
752    dst_stride_argb = -dst_stride_argb;
753  }
754  // Coalesce rows.
755  if (src_stride_y == width && dst_stride_argb == width * 4) {
756    width *= height;
757    height = 1;
758    src_stride_y = dst_stride_argb = 0;
759  }
760#if defined(HAS_I400TOARGBROW_SSE2)
761  if (TestCpuFlag(kCpuHasSSE2)) {
762    I400ToARGBRow = I400ToARGBRow_Any_SSE2;
763    if (IS_ALIGNED(width, 8)) {
764      I400ToARGBRow = I400ToARGBRow_SSE2;
765    }
766  }
767#endif
768#if defined(HAS_I400TOARGBROW_AVX2)
769  if (TestCpuFlag(kCpuHasAVX2)) {
770    I400ToARGBRow = I400ToARGBRow_Any_AVX2;
771    if (IS_ALIGNED(width, 16)) {
772      I400ToARGBRow = I400ToARGBRow_AVX2;
773    }
774  }
775#endif
776#if defined(HAS_I400TOARGBROW_NEON)
777  if (TestCpuFlag(kCpuHasNEON)) {
778    I400ToARGBRow = I400ToARGBRow_Any_NEON;
779    if (IS_ALIGNED(width, 8)) {
780      I400ToARGBRow = I400ToARGBRow_NEON;
781    }
782  }
783#endif
784#if defined(HAS_I400TOARGBROW_MSA)
785  if (TestCpuFlag(kCpuHasMSA)) {
786    I400ToARGBRow = I400ToARGBRow_Any_MSA;
787    if (IS_ALIGNED(width, 16)) {
788      I400ToARGBRow = I400ToARGBRow_MSA;
789    }
790  }
791#endif
792
793  for (y = 0; y < height; ++y) {
794    I400ToARGBRow(src_y, dst_argb, width);
795    dst_argb += dst_stride_argb;
796    src_y += src_stride_y;
797  }
798  return 0;
799}
800
801// Convert J400 to ARGB.
802LIBYUV_API
803int J400ToARGB(const uint8* src_y,
804               int src_stride_y,
805               uint8* dst_argb,
806               int dst_stride_argb,
807               int width,
808               int height) {
809  int y;
810  void (*J400ToARGBRow)(const uint8* src_y, uint8* dst_argb, int width) =
811      J400ToARGBRow_C;
812  if (!src_y || !dst_argb || width <= 0 || height == 0) {
813    return -1;
814  }
815  // Negative height means invert the image.
816  if (height < 0) {
817    height = -height;
818    src_y = src_y + (height - 1) * src_stride_y;
819    src_stride_y = -src_stride_y;
820  }
821  // Coalesce rows.
822  if (src_stride_y == width && dst_stride_argb == width * 4) {
823    width *= height;
824    height = 1;
825    src_stride_y = dst_stride_argb = 0;
826  }
827#if defined(HAS_J400TOARGBROW_SSE2)
828  if (TestCpuFlag(kCpuHasSSE2)) {
829    J400ToARGBRow = J400ToARGBRow_Any_SSE2;
830    if (IS_ALIGNED(width, 8)) {
831      J400ToARGBRow = J400ToARGBRow_SSE2;
832    }
833  }
834#endif
835#if defined(HAS_J400TOARGBROW_AVX2)
836  if (TestCpuFlag(kCpuHasAVX2)) {
837    J400ToARGBRow = J400ToARGBRow_Any_AVX2;
838    if (IS_ALIGNED(width, 16)) {
839      J400ToARGBRow = J400ToARGBRow_AVX2;
840    }
841  }
842#endif
843#if defined(HAS_J400TOARGBROW_NEON)
844  if (TestCpuFlag(kCpuHasNEON)) {
845    J400ToARGBRow = J400ToARGBRow_Any_NEON;
846    if (IS_ALIGNED(width, 8)) {
847      J400ToARGBRow = J400ToARGBRow_NEON;
848    }
849  }
850#endif
851#if defined(HAS_J400TOARGBROW_MSA)
852  if (TestCpuFlag(kCpuHasMSA)) {
853    J400ToARGBRow = J400ToARGBRow_Any_MSA;
854    if (IS_ALIGNED(width, 16)) {
855      J400ToARGBRow = J400ToARGBRow_MSA;
856    }
857  }
858#endif
859  for (y = 0; y < height; ++y) {
860    J400ToARGBRow(src_y, dst_argb, width);
861    src_y += src_stride_y;
862    dst_argb += dst_stride_argb;
863  }
864  return 0;
865}
866
867// Shuffle table for converting BGRA to ARGB.
868static uvec8 kShuffleMaskBGRAToARGB = {3u,  2u,  1u, 0u, 7u,  6u,  5u,  4u,
869                                       11u, 10u, 9u, 8u, 15u, 14u, 13u, 12u};
870
871// Shuffle table for converting ABGR to ARGB.
872static uvec8 kShuffleMaskABGRToARGB = {2u,  1u, 0u, 3u,  6u,  5u,  4u,  7u,
873                                       10u, 9u, 8u, 11u, 14u, 13u, 12u, 15u};
874
875// Shuffle table for converting RGBA to ARGB.
876static uvec8 kShuffleMaskRGBAToARGB = {1u, 2u,  3u,  0u, 5u,  6u,  7u,  4u,
877                                       9u, 10u, 11u, 8u, 13u, 14u, 15u, 12u};
878
879// Convert BGRA to ARGB.
880LIBYUV_API
881int BGRAToARGB(const uint8* src_bgra,
882               int src_stride_bgra,
883               uint8* dst_argb,
884               int dst_stride_argb,
885               int width,
886               int height) {
887  return ARGBShuffle(src_bgra, src_stride_bgra, dst_argb, dst_stride_argb,
888                     (const uint8*)(&kShuffleMaskBGRAToARGB), width, height);
889}
890
891// Convert ARGB to BGRA (same as BGRAToARGB).
892LIBYUV_API
893int ARGBToBGRA(const uint8* src_bgra,
894               int src_stride_bgra,
895               uint8* dst_argb,
896               int dst_stride_argb,
897               int width,
898               int height) {
899  return ARGBShuffle(src_bgra, src_stride_bgra, dst_argb, dst_stride_argb,
900                     (const uint8*)(&kShuffleMaskBGRAToARGB), width, height);
901}
902
903// Convert ABGR to ARGB.
904LIBYUV_API
905int ABGRToARGB(const uint8* src_abgr,
906               int src_stride_abgr,
907               uint8* dst_argb,
908               int dst_stride_argb,
909               int width,
910               int height) {
911  return ARGBShuffle(src_abgr, src_stride_abgr, dst_argb, dst_stride_argb,
912                     (const uint8*)(&kShuffleMaskABGRToARGB), width, height);
913}
914
915// Convert ARGB to ABGR to (same as ABGRToARGB).
916LIBYUV_API
917int ARGBToABGR(const uint8* src_abgr,
918               int src_stride_abgr,
919               uint8* dst_argb,
920               int dst_stride_argb,
921               int width,
922               int height) {
923  return ARGBShuffle(src_abgr, src_stride_abgr, dst_argb, dst_stride_argb,
924                     (const uint8*)(&kShuffleMaskABGRToARGB), width, height);
925}
926
927// Convert RGBA to ARGB.
928LIBYUV_API
929int RGBAToARGB(const uint8* src_rgba,
930               int src_stride_rgba,
931               uint8* dst_argb,
932               int dst_stride_argb,
933               int width,
934               int height) {
935  return ARGBShuffle(src_rgba, src_stride_rgba, dst_argb, dst_stride_argb,
936                     (const uint8*)(&kShuffleMaskRGBAToARGB), width, height);
937}
938
939// Convert RGB24 to ARGB.
940LIBYUV_API
941int RGB24ToARGB(const uint8* src_rgb24,
942                int src_stride_rgb24,
943                uint8* dst_argb,
944                int dst_stride_argb,
945                int width,
946                int height) {
947  int y;
948  void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) =
949      RGB24ToARGBRow_C;
950  if (!src_rgb24 || !dst_argb || width <= 0 || height == 0) {
951    return -1;
952  }
953  // Negative height means invert the image.
954  if (height < 0) {
955    height = -height;
956    src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
957    src_stride_rgb24 = -src_stride_rgb24;
958  }
959  // Coalesce rows.
960  if (src_stride_rgb24 == width * 3 && dst_stride_argb == width * 4) {
961    width *= height;
962    height = 1;
963    src_stride_rgb24 = dst_stride_argb = 0;
964  }
965#if defined(HAS_RGB24TOARGBROW_SSSE3)
966  if (TestCpuFlag(kCpuHasSSSE3)) {
967    RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
968    if (IS_ALIGNED(width, 16)) {
969      RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
970    }
971  }
972#endif
973#if defined(HAS_RGB24TOARGBROW_NEON)
974  if (TestCpuFlag(kCpuHasNEON)) {
975    RGB24ToARGBRow = RGB24ToARGBRow_Any_NEON;
976    if (IS_ALIGNED(width, 8)) {
977      RGB24ToARGBRow = RGB24ToARGBRow_NEON;
978    }
979  }
980#endif
981#if defined(HAS_RGB24TOARGBROW_DSPR2)
982  if (TestCpuFlag(kCpuHasDSPR2)) {
983    RGB24ToARGBRow = RGB24ToARGBRow_Any_DSPR2;
984    if (IS_ALIGNED(width, 8)) {
985      RGB24ToARGBRow = RGB24ToARGBRow_DSPR2;
986    }
987  }
988#endif
989#if defined(HAS_RGB24TOARGBROW_MSA)
990  if (TestCpuFlag(kCpuHasMSA)) {
991    RGB24ToARGBRow = RGB24ToARGBRow_Any_MSA;
992    if (IS_ALIGNED(width, 16)) {
993      RGB24ToARGBRow = RGB24ToARGBRow_MSA;
994    }
995  }
996#endif
997
998  for (y = 0; y < height; ++y) {
999    RGB24ToARGBRow(src_rgb24, dst_argb, width);
1000    src_rgb24 += src_stride_rgb24;
1001    dst_argb += dst_stride_argb;
1002  }
1003  return 0;
1004}
1005
1006// Convert RAW to ARGB.
1007LIBYUV_API
1008int RAWToARGB(const uint8* src_raw,
1009              int src_stride_raw,
1010              uint8* dst_argb,
1011              int dst_stride_argb,
1012              int width,
1013              int height) {
1014  int y;
1015  void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) =
1016      RAWToARGBRow_C;
1017  if (!src_raw || !dst_argb || width <= 0 || height == 0) {
1018    return -1;
1019  }
1020  // Negative height means invert the image.
1021  if (height < 0) {
1022    height = -height;
1023    src_raw = src_raw + (height - 1) * src_stride_raw;
1024    src_stride_raw = -src_stride_raw;
1025  }
1026  // Coalesce rows.
1027  if (src_stride_raw == width * 3 && dst_stride_argb == width * 4) {
1028    width *= height;
1029    height = 1;
1030    src_stride_raw = dst_stride_argb = 0;
1031  }
1032#if defined(HAS_RAWTOARGBROW_SSSE3)
1033  if (TestCpuFlag(kCpuHasSSSE3)) {
1034    RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
1035    if (IS_ALIGNED(width, 16)) {
1036      RAWToARGBRow = RAWToARGBRow_SSSE3;
1037    }
1038  }
1039#endif
1040#if defined(HAS_RAWTOARGBROW_NEON)
1041  if (TestCpuFlag(kCpuHasNEON)) {
1042    RAWToARGBRow = RAWToARGBRow_Any_NEON;
1043    if (IS_ALIGNED(width, 8)) {
1044      RAWToARGBRow = RAWToARGBRow_NEON;
1045    }
1046  }
1047#endif
1048#if defined(HAS_RAWTOARGBROW_DSPR2)
1049  if (TestCpuFlag(kCpuHasDSPR2)) {
1050    RAWToARGBRow = RAWToARGBRow_Any_DSPR2;
1051    if (IS_ALIGNED(width, 8)) {
1052      RAWToARGBRow = RAWToARGBRow_DSPR2;
1053    }
1054  }
1055#endif
1056#if defined(HAS_RAWTOARGBROW_MSA)
1057  if (TestCpuFlag(kCpuHasMSA)) {
1058    RAWToARGBRow = RAWToARGBRow_Any_MSA;
1059    if (IS_ALIGNED(width, 16)) {
1060      RAWToARGBRow = RAWToARGBRow_MSA;
1061    }
1062  }
1063#endif
1064
1065  for (y = 0; y < height; ++y) {
1066    RAWToARGBRow(src_raw, dst_argb, width);
1067    src_raw += src_stride_raw;
1068    dst_argb += dst_stride_argb;
1069  }
1070  return 0;
1071}
1072
1073// Convert RGB565 to ARGB.
1074LIBYUV_API
1075int RGB565ToARGB(const uint8* src_rgb565,
1076                 int src_stride_rgb565,
1077                 uint8* dst_argb,
1078                 int dst_stride_argb,
1079                 int width,
1080                 int height) {
1081  int y;
1082  void (*RGB565ToARGBRow)(const uint8* src_rgb565, uint8* dst_argb, int width) =
1083      RGB565ToARGBRow_C;
1084  if (!src_rgb565 || !dst_argb || width <= 0 || height == 0) {
1085    return -1;
1086  }
1087  // Negative height means invert the image.
1088  if (height < 0) {
1089    height = -height;
1090    src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
1091    src_stride_rgb565 = -src_stride_rgb565;
1092  }
1093  // Coalesce rows.
1094  if (src_stride_rgb565 == width * 2 && dst_stride_argb == width * 4) {
1095    width *= height;
1096    height = 1;
1097    src_stride_rgb565 = dst_stride_argb = 0;
1098  }
1099#if defined(HAS_RGB565TOARGBROW_SSE2)
1100  if (TestCpuFlag(kCpuHasSSE2)) {
1101    RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
1102    if (IS_ALIGNED(width, 8)) {
1103      RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
1104    }
1105  }
1106#endif
1107#if defined(HAS_RGB565TOARGBROW_AVX2)
1108  if (TestCpuFlag(kCpuHasAVX2)) {
1109    RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2;
1110    if (IS_ALIGNED(width, 16)) {
1111      RGB565ToARGBRow = RGB565ToARGBRow_AVX2;
1112    }
1113  }
1114#endif
1115#if defined(HAS_RGB565TOARGBROW_NEON)
1116  if (TestCpuFlag(kCpuHasNEON)) {
1117    RGB565ToARGBRow = RGB565ToARGBRow_Any_NEON;
1118    if (IS_ALIGNED(width, 8)) {
1119      RGB565ToARGBRow = RGB565ToARGBRow_NEON;
1120    }
1121  }
1122#endif
1123#if defined(HAS_RGB565TOARGBROW_DSPR2)
1124  if (TestCpuFlag(kCpuHasDSPR2)) {
1125    RGB565ToARGBRow = RGB565ToARGBRow_Any_DSPR2;
1126    if (IS_ALIGNED(width, 8)) {
1127      RGB565ToARGBRow = RGB565ToARGBRow_DSPR2;
1128    }
1129  }
1130#endif
1131#if defined(HAS_RGB565TOARGBROW_MSA)
1132  if (TestCpuFlag(kCpuHasMSA)) {
1133    RGB565ToARGBRow = RGB565ToARGBRow_Any_MSA;
1134    if (IS_ALIGNED(width, 16)) {
1135      RGB565ToARGBRow = RGB565ToARGBRow_MSA;
1136    }
1137  }
1138#endif
1139
1140  for (y = 0; y < height; ++y) {
1141    RGB565ToARGBRow(src_rgb565, dst_argb, width);
1142    src_rgb565 += src_stride_rgb565;
1143    dst_argb += dst_stride_argb;
1144  }
1145  return 0;
1146}
1147
1148// Convert ARGB1555 to ARGB.
1149LIBYUV_API
1150int ARGB1555ToARGB(const uint8* src_argb1555,
1151                   int src_stride_argb1555,
1152                   uint8* dst_argb,
1153                   int dst_stride_argb,
1154                   int width,
1155                   int height) {
1156  int y;
1157  void (*ARGB1555ToARGBRow)(const uint8* src_argb1555, uint8* dst_argb,
1158                            int width) = ARGB1555ToARGBRow_C;
1159  if (!src_argb1555 || !dst_argb || width <= 0 || height == 0) {
1160    return -1;
1161  }
1162  // Negative height means invert the image.
1163  if (height < 0) {
1164    height = -height;
1165    src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
1166    src_stride_argb1555 = -src_stride_argb1555;
1167  }
1168  // Coalesce rows.
1169  if (src_stride_argb1555 == width * 2 && dst_stride_argb == width * 4) {
1170    width *= height;
1171    height = 1;
1172    src_stride_argb1555 = dst_stride_argb = 0;
1173  }
1174#if defined(HAS_ARGB1555TOARGBROW_SSE2)
1175  if (TestCpuFlag(kCpuHasSSE2)) {
1176    ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
1177    if (IS_ALIGNED(width, 8)) {
1178      ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
1179    }
1180  }
1181#endif
1182#if defined(HAS_ARGB1555TOARGBROW_AVX2)
1183  if (TestCpuFlag(kCpuHasAVX2)) {
1184    ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2;
1185    if (IS_ALIGNED(width, 16)) {
1186      ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2;
1187    }
1188  }
1189#endif
1190#if defined(HAS_ARGB1555TOARGBROW_NEON)
1191  if (TestCpuFlag(kCpuHasNEON)) {
1192    ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_NEON;
1193    if (IS_ALIGNED(width, 8)) {
1194      ARGB1555ToARGBRow = ARGB1555ToARGBRow_NEON;
1195    }
1196  }
1197#endif
1198#if defined(HAS_ARGB1555TOARGBROW_DSPR2)
1199  if (TestCpuFlag(kCpuHasDSPR2)) {
1200    ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_DSPR2;
1201    if (IS_ALIGNED(width, 4)) {
1202      ARGB1555ToARGBRow = ARGB1555ToARGBRow_DSPR2;
1203    }
1204  }
1205#endif
1206#if defined(HAS_ARGB1555TOARGBROW_MSA)
1207  if (TestCpuFlag(kCpuHasMSA)) {
1208    ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_MSA;
1209    if (IS_ALIGNED(width, 16)) {
1210      ARGB1555ToARGBRow = ARGB1555ToARGBRow_MSA;
1211    }
1212  }
1213#endif
1214
1215  for (y = 0; y < height; ++y) {
1216    ARGB1555ToARGBRow(src_argb1555, dst_argb, width);
1217    src_argb1555 += src_stride_argb1555;
1218    dst_argb += dst_stride_argb;
1219  }
1220  return 0;
1221}
1222
1223// Convert ARGB4444 to ARGB.
1224LIBYUV_API
1225int ARGB4444ToARGB(const uint8* src_argb4444,
1226                   int src_stride_argb4444,
1227                   uint8* dst_argb,
1228                   int dst_stride_argb,
1229                   int width,
1230                   int height) {
1231  int y;
1232  void (*ARGB4444ToARGBRow)(const uint8* src_argb4444, uint8* dst_argb,
1233                            int width) = ARGB4444ToARGBRow_C;
1234  if (!src_argb4444 || !dst_argb || width <= 0 || height == 0) {
1235    return -1;
1236  }
1237  // Negative height means invert the image.
1238  if (height < 0) {
1239    height = -height;
1240    src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
1241    src_stride_argb4444 = -src_stride_argb4444;
1242  }
1243  // Coalesce rows.
1244  if (src_stride_argb4444 == width * 2 && dst_stride_argb == width * 4) {
1245    width *= height;
1246    height = 1;
1247    src_stride_argb4444 = dst_stride_argb = 0;
1248  }
1249#if defined(HAS_ARGB4444TOARGBROW_SSE2)
1250  if (TestCpuFlag(kCpuHasSSE2)) {
1251    ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
1252    if (IS_ALIGNED(width, 8)) {
1253      ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
1254    }
1255  }
1256#endif
1257#if defined(HAS_ARGB4444TOARGBROW_AVX2)
1258  if (TestCpuFlag(kCpuHasAVX2)) {
1259    ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2;
1260    if (IS_ALIGNED(width, 16)) {
1261      ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2;
1262    }
1263  }
1264#endif
1265#if defined(HAS_ARGB4444TOARGBROW_NEON)
1266  if (TestCpuFlag(kCpuHasNEON)) {
1267    ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_NEON;
1268    if (IS_ALIGNED(width, 8)) {
1269      ARGB4444ToARGBRow = ARGB4444ToARGBRow_NEON;
1270    }
1271  }
1272#endif
1273#if defined(HAS_ARGB4444TOARGBROW_DSPR2)
1274  if (TestCpuFlag(kCpuHasDSPR2)) {
1275    ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_DSPR2;
1276    if (IS_ALIGNED(width, 4)) {
1277      ARGB4444ToARGBRow = ARGB4444ToARGBRow_DSPR2;
1278    }
1279  }
1280#endif
1281#if defined(HAS_ARGB4444TOARGBROW_MSA)
1282  if (TestCpuFlag(kCpuHasMSA)) {
1283    ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MSA;
1284    if (IS_ALIGNED(width, 16)) {
1285      ARGB4444ToARGBRow = ARGB4444ToARGBRow_MSA;
1286    }
1287  }
1288#endif
1289
1290  for (y = 0; y < height; ++y) {
1291    ARGB4444ToARGBRow(src_argb4444, dst_argb, width);
1292    src_argb4444 += src_stride_argb4444;
1293    dst_argb += dst_stride_argb;
1294  }
1295  return 0;
1296}
1297
1298// Convert NV12 to ARGB.
1299LIBYUV_API
1300int NV12ToARGB(const uint8* src_y,
1301               int src_stride_y,
1302               const uint8* src_uv,
1303               int src_stride_uv,
1304               uint8* dst_argb,
1305               int dst_stride_argb,
1306               int width,
1307               int height) {
1308  int y;
1309  void (*NV12ToARGBRow)(const uint8* y_buf, const uint8* uv_buf, uint8* rgb_buf,
1310                        const struct YuvConstants* yuvconstants, int width) =
1311      NV12ToARGBRow_C;
1312  if (!src_y || !src_uv || !dst_argb || width <= 0 || height == 0) {
1313    return -1;
1314  }
1315  // Negative height means invert the image.
1316  if (height < 0) {
1317    height = -height;
1318    dst_argb = dst_argb + (height - 1) * dst_stride_argb;
1319    dst_stride_argb = -dst_stride_argb;
1320  }
1321#if defined(HAS_NV12TOARGBROW_SSSE3)
1322  if (TestCpuFlag(kCpuHasSSSE3)) {
1323    NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
1324    if (IS_ALIGNED(width, 8)) {
1325      NV12ToARGBRow = NV12ToARGBRow_SSSE3;
1326    }
1327  }
1328#endif
1329#if defined(HAS_NV12TOARGBROW_AVX2)
1330  if (TestCpuFlag(kCpuHasAVX2)) {
1331    NV12ToARGBRow = NV12ToARGBRow_Any_AVX2;
1332    if (IS_ALIGNED(width, 16)) {
1333      NV12ToARGBRow = NV12ToARGBRow_AVX2;
1334    }
1335  }
1336#endif
1337#if defined(HAS_NV12TOARGBROW_NEON)
1338  if (TestCpuFlag(kCpuHasNEON)) {
1339    NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
1340    if (IS_ALIGNED(width, 8)) {
1341      NV12ToARGBRow = NV12ToARGBRow_NEON;
1342    }
1343  }
1344#endif
1345#if defined(HAS_NV12TOARGBROW_DSPR2)
1346  if (TestCpuFlag(kCpuHasDSPR2)) {
1347    NV12ToARGBRow = NV12ToARGBRow_Any_DSPR2;
1348    if (IS_ALIGNED(width, 8)) {
1349      NV12ToARGBRow = NV12ToARGBRow_DSPR2;
1350    }
1351  }
1352#endif
1353#if defined(HAS_NV12TOARGBROW_MSA)
1354  if (TestCpuFlag(kCpuHasMSA)) {
1355    NV12ToARGBRow = NV12ToARGBRow_Any_MSA;
1356    if (IS_ALIGNED(width, 8)) {
1357      NV12ToARGBRow = NV12ToARGBRow_MSA;
1358    }
1359  }
1360#endif
1361
1362  for (y = 0; y < height; ++y) {
1363    NV12ToARGBRow(src_y, src_uv, dst_argb, &kYuvI601Constants, width);
1364    dst_argb += dst_stride_argb;
1365    src_y += src_stride_y;
1366    if (y & 1) {
1367      src_uv += src_stride_uv;
1368    }
1369  }
1370  return 0;
1371}
1372
1373// Convert NV21 to ARGB.
1374LIBYUV_API
1375int NV21ToARGB(const uint8* src_y,
1376               int src_stride_y,
1377               const uint8* src_uv,
1378               int src_stride_uv,
1379               uint8* dst_argb,
1380               int dst_stride_argb,
1381               int width,
1382               int height) {
1383  int y;
1384  void (*NV21ToARGBRow)(const uint8* y_buf, const uint8* uv_buf, uint8* rgb_buf,
1385                        const struct YuvConstants* yuvconstants, int width) =
1386      NV21ToARGBRow_C;
1387  if (!src_y || !src_uv || !dst_argb || width <= 0 || height == 0) {
1388    return -1;
1389  }
1390  // Negative height means invert the image.
1391  if (height < 0) {
1392    height = -height;
1393    dst_argb = dst_argb + (height - 1) * dst_stride_argb;
1394    dst_stride_argb = -dst_stride_argb;
1395  }
1396#if defined(HAS_NV21TOARGBROW_SSSE3)
1397  if (TestCpuFlag(kCpuHasSSSE3)) {
1398    NV21ToARGBRow = NV21ToARGBRow_Any_SSSE3;
1399    if (IS_ALIGNED(width, 8)) {
1400      NV21ToARGBRow = NV21ToARGBRow_SSSE3;
1401    }
1402  }
1403#endif
1404#if defined(HAS_NV21TOARGBROW_AVX2)
1405  if (TestCpuFlag(kCpuHasAVX2)) {
1406    NV21ToARGBRow = NV21ToARGBRow_Any_AVX2;
1407    if (IS_ALIGNED(width, 16)) {
1408      NV21ToARGBRow = NV21ToARGBRow_AVX2;
1409    }
1410  }
1411#endif
1412#if defined(HAS_NV21TOARGBROW_NEON)
1413  if (TestCpuFlag(kCpuHasNEON)) {
1414    NV21ToARGBRow = NV21ToARGBRow_Any_NEON;
1415    if (IS_ALIGNED(width, 8)) {
1416      NV21ToARGBRow = NV21ToARGBRow_NEON;
1417    }
1418  }
1419#endif
1420#if defined(HAS_NV21TOARGBROW_MSA)
1421  if (TestCpuFlag(kCpuHasMSA)) {
1422    NV21ToARGBRow = NV21ToARGBRow_Any_MSA;
1423    if (IS_ALIGNED(width, 8)) {
1424      NV21ToARGBRow = NV21ToARGBRow_MSA;
1425    }
1426  }
1427#endif
1428
1429  for (y = 0; y < height; ++y) {
1430    NV21ToARGBRow(src_y, src_uv, dst_argb, &kYuvI601Constants, width);
1431    dst_argb += dst_stride_argb;
1432    src_y += src_stride_y;
1433    if (y & 1) {
1434      src_uv += src_stride_uv;
1435    }
1436  }
1437  return 0;
1438}
1439
1440// Convert M420 to ARGB.
1441LIBYUV_API
1442int M420ToARGB(const uint8* src_m420,
1443               int src_stride_m420,
1444               uint8* dst_argb,
1445               int dst_stride_argb,
1446               int width,
1447               int height) {
1448  int y;
1449  void (*NV12ToARGBRow)(const uint8* y_buf, const uint8* uv_buf, uint8* rgb_buf,
1450                        const struct YuvConstants* yuvconstants, int width) =
1451      NV12ToARGBRow_C;
1452  if (!src_m420 || !dst_argb || width <= 0 || height == 0) {
1453    return -1;
1454  }
1455  // Negative height means invert the image.
1456  if (height < 0) {
1457    height = -height;
1458    dst_argb = dst_argb + (height - 1) * dst_stride_argb;
1459    dst_stride_argb = -dst_stride_argb;
1460  }
1461#if defined(HAS_NV12TOARGBROW_SSSE3)
1462  if (TestCpuFlag(kCpuHasSSSE3)) {
1463    NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
1464    if (IS_ALIGNED(width, 8)) {
1465      NV12ToARGBRow = NV12ToARGBRow_SSSE3;
1466    }
1467  }
1468#endif
1469#if defined(HAS_NV12TOARGBROW_AVX2)
1470  if (TestCpuFlag(kCpuHasAVX2)) {
1471    NV12ToARGBRow = NV12ToARGBRow_Any_AVX2;
1472    if (IS_ALIGNED(width, 16)) {
1473      NV12ToARGBRow = NV12ToARGBRow_AVX2;
1474    }
1475  }
1476#endif
1477#if defined(HAS_NV12TOARGBROW_NEON)
1478  if (TestCpuFlag(kCpuHasNEON)) {
1479    NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
1480    if (IS_ALIGNED(width, 8)) {
1481      NV12ToARGBRow = NV12ToARGBRow_NEON;
1482    }
1483  }
1484#endif
1485#if defined(HAS_NV12TOARGBROW_DSPR2)
1486  if (TestCpuFlag(kCpuHasDSPR2)) {
1487    NV12ToARGBRow = NV12ToARGBRow_Any_DSPR2;
1488    if (IS_ALIGNED(width, 8)) {
1489      NV12ToARGBRow = NV12ToARGBRow_DSPR2;
1490    }
1491  }
1492#endif
1493#if defined(HAS_NV12TOARGBROW_MSA)
1494  if (TestCpuFlag(kCpuHasMSA)) {
1495    NV12ToARGBRow = NV12ToARGBRow_Any_MSA;
1496    if (IS_ALIGNED(width, 8)) {
1497      NV12ToARGBRow = NV12ToARGBRow_MSA;
1498    }
1499  }
1500#endif
1501
1502  for (y = 0; y < height - 1; y += 2) {
1503    NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb,
1504                  &kYuvI601Constants, width);
1505    NV12ToARGBRow(src_m420 + src_stride_m420, src_m420 + src_stride_m420 * 2,
1506                  dst_argb + dst_stride_argb, &kYuvI601Constants, width);
1507    dst_argb += dst_stride_argb * 2;
1508    src_m420 += src_stride_m420 * 3;
1509  }
1510  if (height & 1) {
1511    NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb,
1512                  &kYuvI601Constants, width);
1513  }
1514  return 0;
1515}
1516
1517// Convert YUY2 to ARGB.
1518LIBYUV_API
1519int YUY2ToARGB(const uint8* src_yuy2,
1520               int src_stride_yuy2,
1521               uint8* dst_argb,
1522               int dst_stride_argb,
1523               int width,
1524               int height) {
1525  int y;
1526  void (*YUY2ToARGBRow)(const uint8* src_yuy2, uint8* dst_argb,
1527                        const struct YuvConstants* yuvconstants, int width) =
1528      YUY2ToARGBRow_C;
1529  if (!src_yuy2 || !dst_argb || width <= 0 || height == 0) {
1530    return -1;
1531  }
1532  // Negative height means invert the image.
1533  if (height < 0) {
1534    height = -height;
1535    src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
1536    src_stride_yuy2 = -src_stride_yuy2;
1537  }
1538  // Coalesce rows.
1539  if (src_stride_yuy2 == width * 2 && dst_stride_argb == width * 4) {
1540    width *= height;
1541    height = 1;
1542    src_stride_yuy2 = dst_stride_argb = 0;
1543  }
1544#if defined(HAS_YUY2TOARGBROW_SSSE3)
1545  if (TestCpuFlag(kCpuHasSSSE3)) {
1546    YUY2ToARGBRow = YUY2ToARGBRow_Any_SSSE3;
1547    if (IS_ALIGNED(width, 16)) {
1548      YUY2ToARGBRow = YUY2ToARGBRow_SSSE3;
1549    }
1550  }
1551#endif
1552#if defined(HAS_YUY2TOARGBROW_AVX2)
1553  if (TestCpuFlag(kCpuHasAVX2)) {
1554    YUY2ToARGBRow = YUY2ToARGBRow_Any_AVX2;
1555    if (IS_ALIGNED(width, 32)) {
1556      YUY2ToARGBRow = YUY2ToARGBRow_AVX2;
1557    }
1558  }
1559#endif
1560#if defined(HAS_YUY2TOARGBROW_NEON)
1561  if (TestCpuFlag(kCpuHasNEON)) {
1562    YUY2ToARGBRow = YUY2ToARGBRow_Any_NEON;
1563    if (IS_ALIGNED(width, 8)) {
1564      YUY2ToARGBRow = YUY2ToARGBRow_NEON;
1565    }
1566  }
1567#endif
1568#if defined(HAS_YUY2TOARGBROW_MSA)
1569  if (TestCpuFlag(kCpuHasMSA)) {
1570    YUY2ToARGBRow = YUY2ToARGBRow_Any_MSA;
1571    if (IS_ALIGNED(width, 8)) {
1572      YUY2ToARGBRow = YUY2ToARGBRow_MSA;
1573    }
1574  }
1575#endif
1576  for (y = 0; y < height; ++y) {
1577    YUY2ToARGBRow(src_yuy2, dst_argb, &kYuvI601Constants, width);
1578    src_yuy2 += src_stride_yuy2;
1579    dst_argb += dst_stride_argb;
1580  }
1581  return 0;
1582}
1583
1584// Convert UYVY to ARGB.
1585LIBYUV_API
1586int UYVYToARGB(const uint8* src_uyvy,
1587               int src_stride_uyvy,
1588               uint8* dst_argb,
1589               int dst_stride_argb,
1590               int width,
1591               int height) {
1592  int y;
1593  void (*UYVYToARGBRow)(const uint8* src_uyvy, uint8* dst_argb,
1594                        const struct YuvConstants* yuvconstants, int width) =
1595      UYVYToARGBRow_C;
1596  if (!src_uyvy || !dst_argb || width <= 0 || height == 0) {
1597    return -1;
1598  }
1599  // Negative height means invert the image.
1600  if (height < 0) {
1601    height = -height;
1602    src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
1603    src_stride_uyvy = -src_stride_uyvy;
1604  }
1605  // Coalesce rows.
1606  if (src_stride_uyvy == width * 2 && dst_stride_argb == width * 4) {
1607    width *= height;
1608    height = 1;
1609    src_stride_uyvy = dst_stride_argb = 0;
1610  }
1611#if defined(HAS_UYVYTOARGBROW_SSSE3)
1612  if (TestCpuFlag(kCpuHasSSSE3)) {
1613    UYVYToARGBRow = UYVYToARGBRow_Any_SSSE3;
1614    if (IS_ALIGNED(width, 16)) {
1615      UYVYToARGBRow = UYVYToARGBRow_SSSE3;
1616    }
1617  }
1618#endif
1619#if defined(HAS_UYVYTOARGBROW_AVX2)
1620  if (TestCpuFlag(kCpuHasAVX2)) {
1621    UYVYToARGBRow = UYVYToARGBRow_Any_AVX2;
1622    if (IS_ALIGNED(width, 32)) {
1623      UYVYToARGBRow = UYVYToARGBRow_AVX2;
1624    }
1625  }
1626#endif
1627#if defined(HAS_UYVYTOARGBROW_NEON)
1628  if (TestCpuFlag(kCpuHasNEON)) {
1629    UYVYToARGBRow = UYVYToARGBRow_Any_NEON;
1630    if (IS_ALIGNED(width, 8)) {
1631      UYVYToARGBRow = UYVYToARGBRow_NEON;
1632    }
1633  }
1634#endif
1635#if defined(HAS_UYVYTOARGBROW_MSA)
1636  if (TestCpuFlag(kCpuHasMSA)) {
1637    UYVYToARGBRow = UYVYToARGBRow_Any_MSA;
1638    if (IS_ALIGNED(width, 8)) {
1639      UYVYToARGBRow = UYVYToARGBRow_MSA;
1640    }
1641  }
1642#endif
1643  for (y = 0; y < height; ++y) {
1644    UYVYToARGBRow(src_uyvy, dst_argb, &kYuvI601Constants, width);
1645    src_uyvy += src_stride_uyvy;
1646    dst_argb += dst_stride_argb;
1647  }
1648  return 0;
1649}
1650
1651#ifdef __cplusplus
1652}  // extern "C"
1653}  // namespace libyuv
1654#endif
1655