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