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#include "libyuv/format_conversion.h"
15#ifdef HAVE_JPEG
16#include "libyuv/mjpeg_decoder.h"
17#endif
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 I444 to ARGB.
49LIBYUV_API
50int I444ToARGB(const uint8* src_y, int src_stride_y,
51               const uint8* src_u, int src_stride_u,
52               const uint8* src_v, int src_stride_v,
53               uint8* dst_argb, int dst_stride_argb,
54               int width, int height) {
55  int y;
56  void (*I444ToARGBRow)(const uint8* y_buf,
57                        const uint8* u_buf,
58                        const uint8* v_buf,
59                        uint8* rgb_buf,
60                        int width) = I444ToARGBRow_C;
61  if (!src_y || !src_u || !src_v ||
62      !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  // Coalesce rows.
73  if (src_stride_y == width &&
74      src_stride_u == width &&
75      src_stride_v == width &&
76      dst_stride_argb == width * 4) {
77    width *= height;
78    height = 1;
79    src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
80  }
81#if defined(HAS_I444TOARGBROW_SSSE3)
82  if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
83    I444ToARGBRow = I444ToARGBRow_Any_SSSE3;
84    if (IS_ALIGNED(width, 8)) {
85      I444ToARGBRow = I444ToARGBRow_Unaligned_SSSE3;
86      if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
87        I444ToARGBRow = I444ToARGBRow_SSSE3;
88      }
89    }
90  }
91#elif defined(HAS_I444TOARGBROW_NEON)
92  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
93    I444ToARGBRow = I444ToARGBRow_Any_NEON;
94    if (IS_ALIGNED(width, 8)) {
95      I444ToARGBRow = I444ToARGBRow_NEON;
96    }
97  }
98#endif
99
100  for (y = 0; y < height; ++y) {
101    I444ToARGBRow(src_y, src_u, src_v, dst_argb, width);
102    dst_argb += dst_stride_argb;
103    src_y += src_stride_y;
104    src_u += src_stride_u;
105    src_v += src_stride_v;
106  }
107  return 0;
108}
109
110// Convert I422 to ARGB.
111LIBYUV_API
112int I422ToARGB(const uint8* src_y, int src_stride_y,
113               const uint8* src_u, int src_stride_u,
114               const uint8* src_v, int src_stride_v,
115               uint8* dst_argb, int dst_stride_argb,
116               int width, int height) {
117  int y;
118  void (*I422ToARGBRow)(const uint8* y_buf,
119                        const uint8* u_buf,
120                        const uint8* v_buf,
121                        uint8* rgb_buf,
122                        int width) = I422ToARGBRow_C;
123  if (!src_y || !src_u || !src_v ||
124      !dst_argb ||
125      width <= 0 || height == 0) {
126    return -1;
127  }
128  // Negative height means invert the image.
129  if (height < 0) {
130    height = -height;
131    dst_argb = dst_argb + (height - 1) * dst_stride_argb;
132    dst_stride_argb = -dst_stride_argb;
133  }
134  // Coalesce rows.
135  if (src_stride_y == width &&
136      src_stride_u * 2 == width &&
137      src_stride_v * 2 == width &&
138      dst_stride_argb == width * 4) {
139    width *= height;
140    height = 1;
141    src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
142  }
143#if defined(HAS_I422TOARGBROW_SSSE3)
144  if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
145    I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
146    if (IS_ALIGNED(width, 8)) {
147      I422ToARGBRow = I422ToARGBRow_Unaligned_SSSE3;
148      if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
149        I422ToARGBRow = I422ToARGBRow_SSSE3;
150      }
151    }
152  }
153#endif
154#if defined(HAS_I422TOARGBROW_AVX2)
155  if (TestCpuFlag(kCpuHasAVX2) && width >= 16) {
156    I422ToARGBRow = I422ToARGBRow_Any_AVX2;
157    if (IS_ALIGNED(width, 16)) {
158      I422ToARGBRow = I422ToARGBRow_AVX2;
159    }
160  }
161#endif
162#if defined(HAS_I422TOARGBROW_NEON)
163  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
164    I422ToARGBRow = I422ToARGBRow_Any_NEON;
165    if (IS_ALIGNED(width, 8)) {
166      I422ToARGBRow = I422ToARGBRow_NEON;
167    }
168  }
169#endif
170#if defined(HAS_I422TOARGBROW_MIPS_DSPR2)
171  if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) &&
172      IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
173      IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
174      IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
175      IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) {
176    I422ToARGBRow = I422ToARGBRow_MIPS_DSPR2;
177  }
178#endif
179
180  for (y = 0; y < height; ++y) {
181    I422ToARGBRow(src_y, src_u, src_v, dst_argb, width);
182    dst_argb += dst_stride_argb;
183    src_y += src_stride_y;
184    src_u += src_stride_u;
185    src_v += src_stride_v;
186  }
187  return 0;
188}
189
190// Convert I411 to ARGB.
191LIBYUV_API
192int I411ToARGB(const uint8* src_y, int src_stride_y,
193               const uint8* src_u, int src_stride_u,
194               const uint8* src_v, int src_stride_v,
195               uint8* dst_argb, int dst_stride_argb,
196               int width, int height) {
197  int y;
198  void (*I411ToARGBRow)(const uint8* y_buf,
199                        const uint8* u_buf,
200                        const uint8* v_buf,
201                        uint8* rgb_buf,
202                        int width) = I411ToARGBRow_C;
203  if (!src_y || !src_u || !src_v ||
204      !dst_argb ||
205      width <= 0 || height == 0) {
206    return -1;
207  }
208  // Negative height means invert the image.
209  if (height < 0) {
210    height = -height;
211    dst_argb = dst_argb + (height - 1) * dst_stride_argb;
212    dst_stride_argb = -dst_stride_argb;
213  }
214  // Coalesce rows.
215  if (src_stride_y == width &&
216      src_stride_u * 4 == width &&
217      src_stride_v * 4 == width &&
218      dst_stride_argb == width * 4) {
219    width *= height;
220    height = 1;
221    src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
222  }
223#if defined(HAS_I411TOARGBROW_SSSE3)
224  if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
225    I411ToARGBRow = I411ToARGBRow_Any_SSSE3;
226    if (IS_ALIGNED(width, 8)) {
227      I411ToARGBRow = I411ToARGBRow_Unaligned_SSSE3;
228      if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
229        I411ToARGBRow = I411ToARGBRow_SSSE3;
230      }
231    }
232  }
233#elif defined(HAS_I411TOARGBROW_NEON)
234  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
235    I411ToARGBRow = I411ToARGBRow_Any_NEON;
236    if (IS_ALIGNED(width, 8)) {
237      I411ToARGBRow = I411ToARGBRow_NEON;
238    }
239  }
240#endif
241
242  for (y = 0; y < height; ++y) {
243    I411ToARGBRow(src_y, src_u, src_v, dst_argb, width);
244    dst_argb += dst_stride_argb;
245    src_y += src_stride_y;
246    src_u += src_stride_u;
247    src_v += src_stride_v;
248  }
249  return 0;
250}
251
252// Convert I400 to ARGB.
253LIBYUV_API
254int I400ToARGB_Reference(const uint8* src_y, int src_stride_y,
255                         uint8* dst_argb, int dst_stride_argb,
256                         int width, int height) {
257  int y;
258  void (*YToARGBRow)(const uint8* y_buf,
259                     uint8* rgb_buf,
260                     int width) = YToARGBRow_C;
261  if (!src_y || !dst_argb ||
262      width <= 0 || height == 0) {
263    return -1;
264  }
265  // Negative height means invert the image.
266  if (height < 0) {
267    height = -height;
268    dst_argb = dst_argb + (height - 1) * dst_stride_argb;
269    dst_stride_argb = -dst_stride_argb;
270  }
271  // Coalesce rows.
272  if (src_stride_y == width &&
273      dst_stride_argb == width * 4) {
274    width *= height;
275    height = 1;
276    src_stride_y = dst_stride_argb = 0;
277  }
278#if defined(HAS_YTOARGBROW_SSE2)
279  if (TestCpuFlag(kCpuHasSSE2) && width >= 8 &&
280      IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
281    YToARGBRow = YToARGBRow_Any_SSE2;
282    if (IS_ALIGNED(width, 8)) {
283      YToARGBRow = YToARGBRow_SSE2;
284    }
285  }
286#elif defined(HAS_YTOARGBROW_NEON)
287  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
288    YToARGBRow = YToARGBRow_Any_NEON;
289    if (IS_ALIGNED(width, 8)) {
290      YToARGBRow = YToARGBRow_NEON;
291    }
292  }
293#endif
294
295  for (y = 0; y < height; ++y) {
296    YToARGBRow(src_y, dst_argb, width);
297    dst_argb += dst_stride_argb;
298    src_y += src_stride_y;
299  }
300  return 0;
301}
302
303// Convert I400 to ARGB.
304LIBYUV_API
305int I400ToARGB(const uint8* src_y, int src_stride_y,
306               uint8* dst_argb, int dst_stride_argb,
307               int width, int height) {
308  int y;
309  void (*I400ToARGBRow)(const uint8* src_y, uint8* dst_argb, int pix) =
310      I400ToARGBRow_C;
311  if (!src_y || !dst_argb ||
312      width <= 0 || height == 0) {
313    return -1;
314  }
315  // Negative height means invert the image.
316  if (height < 0) {
317    height = -height;
318    src_y = src_y + (height - 1) * src_stride_y;
319    src_stride_y = -src_stride_y;
320  }
321  // Coalesce rows.
322  if (src_stride_y == width &&
323      dst_stride_argb == width * 4) {
324    width *= height;
325    height = 1;
326    src_stride_y = dst_stride_argb = 0;
327  }
328#if defined(HAS_I400TOARGBROW_SSE2)
329  if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
330    I400ToARGBRow = I400ToARGBRow_Any_SSE2;
331    if (IS_ALIGNED(width, 8)) {
332      I400ToARGBRow = I400ToARGBRow_Unaligned_SSE2;
333      if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
334        I400ToARGBRow = I400ToARGBRow_SSE2;
335      }
336    }
337  }
338#elif defined(HAS_I400TOARGBROW_NEON)
339  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
340    I400ToARGBRow = I400ToARGBRow_Any_NEON;
341    if (IS_ALIGNED(width, 8)) {
342      I400ToARGBRow = I400ToARGBRow_NEON;
343    }
344  }
345#endif
346  for (y = 0; y < height; ++y) {
347    I400ToARGBRow(src_y, dst_argb, width);
348    src_y += src_stride_y;
349    dst_argb += dst_stride_argb;
350  }
351  return 0;
352}
353
354// Shuffle table for converting BGRA to ARGB.
355static uvec8 kShuffleMaskBGRAToARGB = {
356  3u, 2u, 1u, 0u, 7u, 6u, 5u, 4u, 11u, 10u, 9u, 8u, 15u, 14u, 13u, 12u
357};
358
359// Shuffle table for converting ABGR to ARGB.
360static uvec8 kShuffleMaskABGRToARGB = {
361  2u, 1u, 0u, 3u, 6u, 5u, 4u, 7u, 10u, 9u, 8u, 11u, 14u, 13u, 12u, 15u
362};
363
364// Shuffle table for converting RGBA to ARGB.
365static uvec8 kShuffleMaskRGBAToARGB = {
366  1u, 2u, 3u, 0u, 5u, 6u, 7u, 4u, 9u, 10u, 11u, 8u, 13u, 14u, 15u, 12u
367};
368
369// Convert BGRA to ARGB.
370LIBYUV_API
371int BGRAToARGB(const uint8* src_bgra, int src_stride_bgra,
372               uint8* dst_argb, int dst_stride_argb,
373               int width, int height) {
374  return ARGBShuffle(src_bgra, src_stride_bgra,
375                     dst_argb, dst_stride_argb,
376                     (const uint8*)(&kShuffleMaskBGRAToARGB),
377                     width, height);
378}
379
380// Convert ARGB to BGRA (same as BGRAToARGB).
381LIBYUV_API
382int ARGBToBGRA(const uint8* src_bgra, int src_stride_bgra,
383               uint8* dst_argb, int dst_stride_argb,
384               int width, int height) {
385  return ARGBShuffle(src_bgra, src_stride_bgra,
386                     dst_argb, dst_stride_argb,
387                     (const uint8*)(&kShuffleMaskBGRAToARGB),
388                     width, height);
389}
390
391// Convert ABGR to ARGB.
392LIBYUV_API
393int ABGRToARGB(const uint8* src_abgr, int src_stride_abgr,
394               uint8* dst_argb, int dst_stride_argb,
395               int width, int height) {
396  return ARGBShuffle(src_abgr, src_stride_abgr,
397                     dst_argb, dst_stride_argb,
398                     (const uint8*)(&kShuffleMaskABGRToARGB),
399                     width, height);
400}
401
402// Convert ARGB to ABGR to (same as ABGRToARGB).
403LIBYUV_API
404int ARGBToABGR(const uint8* src_abgr, int src_stride_abgr,
405               uint8* dst_argb, int dst_stride_argb,
406               int width, int height) {
407  return ARGBShuffle(src_abgr, src_stride_abgr,
408                     dst_argb, dst_stride_argb,
409                     (const uint8*)(&kShuffleMaskABGRToARGB),
410                     width, height);
411}
412
413// Convert RGBA to ARGB.
414LIBYUV_API
415int RGBAToARGB(const uint8* src_rgba, int src_stride_rgba,
416               uint8* dst_argb, int dst_stride_argb,
417               int width, int height) {
418  return ARGBShuffle(src_rgba, src_stride_rgba,
419                     dst_argb, dst_stride_argb,
420                     (const uint8*)(&kShuffleMaskRGBAToARGB),
421                     width, height);
422}
423
424// Convert RGB24 to ARGB.
425LIBYUV_API
426int RGB24ToARGB(const uint8* src_rgb24, int src_stride_rgb24,
427                uint8* dst_argb, int dst_stride_argb,
428                int width, int height) {
429  int y;
430  void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
431      RGB24ToARGBRow_C;
432  if (!src_rgb24 || !dst_argb ||
433      width <= 0 || height == 0) {
434    return -1;
435  }
436  // Negative height means invert the image.
437  if (height < 0) {
438    height = -height;
439    src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
440    src_stride_rgb24 = -src_stride_rgb24;
441  }
442  // Coalesce rows.
443  if (src_stride_rgb24 == width * 3 &&
444      dst_stride_argb == width * 4) {
445    width *= height;
446    height = 1;
447    src_stride_rgb24 = dst_stride_argb = 0;
448  }
449#if defined(HAS_RGB24TOARGBROW_SSSE3)
450  if (TestCpuFlag(kCpuHasSSSE3) && width >= 16 &&
451      IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
452    RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
453    if (IS_ALIGNED(width, 16)) {
454      RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
455    }
456  }
457#elif defined(HAS_RGB24TOARGBROW_NEON)
458  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
459    RGB24ToARGBRow = RGB24ToARGBRow_Any_NEON;
460    if (IS_ALIGNED(width, 8)) {
461      RGB24ToARGBRow = RGB24ToARGBRow_NEON;
462    }
463  }
464#endif
465
466  for (y = 0; y < height; ++y) {
467    RGB24ToARGBRow(src_rgb24, dst_argb, width);
468    src_rgb24 += src_stride_rgb24;
469    dst_argb += dst_stride_argb;
470  }
471  return 0;
472}
473
474// Convert RAW to ARGB.
475LIBYUV_API
476int RAWToARGB(const uint8* src_raw, int src_stride_raw,
477              uint8* dst_argb, int dst_stride_argb,
478              int width, int height) {
479  int y;
480  void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
481      RAWToARGBRow_C;
482  if (!src_raw || !dst_argb ||
483      width <= 0 || height == 0) {
484    return -1;
485  }
486  // Negative height means invert the image.
487  if (height < 0) {
488    height = -height;
489    src_raw = src_raw + (height - 1) * src_stride_raw;
490    src_stride_raw = -src_stride_raw;
491  }
492  // Coalesce rows.
493  if (src_stride_raw == width * 3 &&
494      dst_stride_argb == width * 4) {
495    width *= height;
496    height = 1;
497    src_stride_raw = dst_stride_argb = 0;
498  }
499#if defined(HAS_RAWTOARGBROW_SSSE3)
500  if (TestCpuFlag(kCpuHasSSSE3) && width >= 16 &&
501      IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
502    RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
503    if (IS_ALIGNED(width, 16)) {
504      RAWToARGBRow = RAWToARGBRow_SSSE3;
505    }
506  }
507#elif defined(HAS_RAWTOARGBROW_NEON)
508  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
509    RAWToARGBRow = RAWToARGBRow_Any_NEON;
510    if (IS_ALIGNED(width, 8)) {
511      RAWToARGBRow = RAWToARGBRow_NEON;
512    }
513  }
514#endif
515
516  for (y = 0; y < height; ++y) {
517    RAWToARGBRow(src_raw, dst_argb, width);
518    src_raw += src_stride_raw;
519    dst_argb += dst_stride_argb;
520  }
521  return 0;
522}
523
524// Convert RGB565 to ARGB.
525LIBYUV_API
526int RGB565ToARGB(const uint8* src_rgb565, int src_stride_rgb565,
527                 uint8* dst_argb, int dst_stride_argb,
528                 int width, int height) {
529  int y;
530  void (*RGB565ToARGBRow)(const uint8* src_rgb565, uint8* dst_argb, int pix) =
531      RGB565ToARGBRow_C;
532  if (!src_rgb565 || !dst_argb ||
533      width <= 0 || height == 0) {
534    return -1;
535  }
536  // Negative height means invert the image.
537  if (height < 0) {
538    height = -height;
539    src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
540    src_stride_rgb565 = -src_stride_rgb565;
541  }
542  // Coalesce rows.
543  if (src_stride_rgb565 == width * 2 &&
544      dst_stride_argb == width * 4) {
545    width *= height;
546    height = 1;
547    src_stride_rgb565 = dst_stride_argb = 0;
548  }
549#if defined(HAS_RGB565TOARGBROW_SSE2)
550  if (TestCpuFlag(kCpuHasSSE2) && width >= 8 &&
551      IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
552    RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
553    if (IS_ALIGNED(width, 8)) {
554      RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
555    }
556  }
557#elif defined(HAS_RGB565TOARGBROW_NEON)
558  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
559    RGB565ToARGBRow = RGB565ToARGBRow_Any_NEON;
560    if (IS_ALIGNED(width, 8)) {
561      RGB565ToARGBRow = RGB565ToARGBRow_NEON;
562    }
563  }
564#endif
565
566  for (y = 0; y < height; ++y) {
567    RGB565ToARGBRow(src_rgb565, dst_argb, width);
568    src_rgb565 += src_stride_rgb565;
569    dst_argb += dst_stride_argb;
570  }
571  return 0;
572}
573
574// Convert ARGB1555 to ARGB.
575LIBYUV_API
576int ARGB1555ToARGB(const uint8* src_argb1555, int src_stride_argb1555,
577                   uint8* dst_argb, int dst_stride_argb,
578                   int width, int height) {
579  int y;
580  void (*ARGB1555ToARGBRow)(const uint8* src_argb1555, uint8* dst_argb,
581      int pix) = ARGB1555ToARGBRow_C;
582  if (!src_argb1555 || !dst_argb ||
583      width <= 0 || height == 0) {
584    return -1;
585  }
586  // Negative height means invert the image.
587  if (height < 0) {
588    height = -height;
589    src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
590    src_stride_argb1555 = -src_stride_argb1555;
591  }
592  // Coalesce rows.
593  if (src_stride_argb1555 == width * 2 &&
594      dst_stride_argb == width * 4) {
595    width *= height;
596    height = 1;
597    src_stride_argb1555 = dst_stride_argb = 0;
598  }
599#if defined(HAS_ARGB1555TOARGBROW_SSE2)
600  if (TestCpuFlag(kCpuHasSSE2) && width >= 8 &&
601      IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
602    ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
603    if (IS_ALIGNED(width, 8)) {
604      ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
605    }
606  }
607#elif defined(HAS_ARGB1555TOARGBROW_NEON)
608  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
609    ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_NEON;
610    if (IS_ALIGNED(width, 8)) {
611      ARGB1555ToARGBRow = ARGB1555ToARGBRow_NEON;
612    }
613  }
614#endif
615
616  for (y = 0; y < height; ++y) {
617    ARGB1555ToARGBRow(src_argb1555, dst_argb, width);
618    src_argb1555 += src_stride_argb1555;
619    dst_argb += dst_stride_argb;
620  }
621  return 0;
622}
623
624// Convert ARGB4444 to ARGB.
625LIBYUV_API
626int ARGB4444ToARGB(const uint8* src_argb4444, int src_stride_argb4444,
627                   uint8* dst_argb, int dst_stride_argb,
628                   int width, int height) {
629  int y;
630  void (*ARGB4444ToARGBRow)(const uint8* src_argb4444, uint8* dst_argb,
631      int pix) = ARGB4444ToARGBRow_C;
632  if (!src_argb4444 || !dst_argb ||
633      width <= 0 || height == 0) {
634    return -1;
635  }
636  // Negative height means invert the image.
637  if (height < 0) {
638    height = -height;
639    src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
640    src_stride_argb4444 = -src_stride_argb4444;
641  }
642  // Coalesce rows.
643  if (src_stride_argb4444 == width * 2 &&
644      dst_stride_argb == width * 4) {
645    width *= height;
646    height = 1;
647    src_stride_argb4444 = dst_stride_argb = 0;
648  }
649#if defined(HAS_ARGB4444TOARGBROW_SSE2)
650  if (TestCpuFlag(kCpuHasSSE2) && width >= 8 &&
651      IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
652    ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
653    if (IS_ALIGNED(width, 8)) {
654      ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
655    }
656  }
657#elif defined(HAS_ARGB4444TOARGBROW_NEON)
658  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
659    ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_NEON;
660    if (IS_ALIGNED(width, 8)) {
661      ARGB4444ToARGBRow = ARGB4444ToARGBRow_NEON;
662    }
663  }
664#endif
665
666  for (y = 0; y < height; ++y) {
667    ARGB4444ToARGBRow(src_argb4444, dst_argb, width);
668    src_argb4444 += src_stride_argb4444;
669    dst_argb += dst_stride_argb;
670  }
671  return 0;
672}
673
674// Convert NV12 to ARGB.
675LIBYUV_API
676int NV12ToARGB(const uint8* src_y, int src_stride_y,
677               const uint8* src_uv, int src_stride_uv,
678               uint8* dst_argb, int dst_stride_argb,
679               int width, int height) {
680  int y;
681  void (*NV12ToARGBRow)(const uint8* y_buf,
682                        const uint8* uv_buf,
683                        uint8* rgb_buf,
684                        int width) = NV12ToARGBRow_C;
685  if (!src_y || !src_uv || !dst_argb ||
686      width <= 0 || height == 0) {
687    return -1;
688  }
689  // Negative height means invert the image.
690  if (height < 0) {
691    height = -height;
692    dst_argb = dst_argb + (height - 1) * dst_stride_argb;
693    dst_stride_argb = -dst_stride_argb;
694  }
695#if defined(HAS_NV12TOARGBROW_SSSE3)
696  if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
697    NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
698    if (IS_ALIGNED(width, 8)) {
699      NV12ToARGBRow = NV12ToARGBRow_Unaligned_SSSE3;
700      if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
701        NV12ToARGBRow = NV12ToARGBRow_SSSE3;
702      }
703    }
704  }
705#elif defined(HAS_NV12TOARGBROW_NEON)
706  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
707    NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
708    if (IS_ALIGNED(width, 8)) {
709      NV12ToARGBRow = NV12ToARGBRow_NEON;
710    }
711  }
712#endif
713
714  for (y = 0; y < height; ++y) {
715    NV12ToARGBRow(src_y, src_uv, dst_argb, width);
716    dst_argb += dst_stride_argb;
717    src_y += src_stride_y;
718    if (y & 1) {
719      src_uv += src_stride_uv;
720    }
721  }
722  return 0;
723}
724
725// Convert NV21 to ARGB.
726LIBYUV_API
727int NV21ToARGB(const uint8* src_y, int src_stride_y,
728               const uint8* src_uv, int src_stride_uv,
729               uint8* dst_argb, int dst_stride_argb,
730               int width, int height) {
731  int y;
732  void (*NV21ToARGBRow)(const uint8* y_buf,
733                        const uint8* uv_buf,
734                        uint8* rgb_buf,
735                        int width) = NV21ToARGBRow_C;
736  if (!src_y || !src_uv || !dst_argb ||
737      width <= 0 || height == 0) {
738    return -1;
739  }
740  // Negative height means invert the image.
741  if (height < 0) {
742    height = -height;
743    dst_argb = dst_argb + (height - 1) * dst_stride_argb;
744    dst_stride_argb = -dst_stride_argb;
745  }
746#if defined(HAS_NV21TOARGBROW_SSSE3)
747  if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
748    NV21ToARGBRow = NV21ToARGBRow_Any_SSSE3;
749    if (IS_ALIGNED(width, 8)) {
750      NV21ToARGBRow = NV21ToARGBRow_Unaligned_SSSE3;
751      if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
752        NV21ToARGBRow = NV21ToARGBRow_SSSE3;
753      }
754    }
755  }
756#endif
757#if defined(HAS_NV21TOARGBROW_NEON)
758  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
759    NV21ToARGBRow = NV21ToARGBRow_Any_NEON;
760    if (IS_ALIGNED(width, 8)) {
761      NV21ToARGBRow = NV21ToARGBRow_NEON;
762    }
763  }
764#endif
765
766  for (y = 0; y < height; ++y) {
767    NV21ToARGBRow(src_y, src_uv, dst_argb, width);
768    dst_argb += dst_stride_argb;
769    src_y += src_stride_y;
770    if (y & 1) {
771      src_uv += src_stride_uv;
772    }
773  }
774  return 0;
775}
776
777// Convert M420 to ARGB.
778LIBYUV_API
779int M420ToARGB(const uint8* src_m420, int src_stride_m420,
780               uint8* dst_argb, int dst_stride_argb,
781               int width, int height) {
782  int y;
783  void (*NV12ToARGBRow)(const uint8* y_buf,
784                        const uint8* uv_buf,
785                        uint8* rgb_buf,
786                        int width) = NV12ToARGBRow_C;
787  if (!src_m420 || !dst_argb ||
788      width <= 0 || height == 0) {
789    return -1;
790  }
791  // Negative height means invert the image.
792  if (height < 0) {
793    height = -height;
794    dst_argb = dst_argb + (height - 1) * dst_stride_argb;
795    dst_stride_argb = -dst_stride_argb;
796  }
797#if defined(HAS_NV12TOARGBROW_SSSE3)
798  if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
799    NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
800    if (IS_ALIGNED(width, 8)) {
801      NV12ToARGBRow = NV12ToARGBRow_Unaligned_SSSE3;
802      if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
803        NV12ToARGBRow = NV12ToARGBRow_SSSE3;
804      }
805    }
806  }
807#elif defined(HAS_NV12TOARGBROW_NEON)
808  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
809    NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
810    if (IS_ALIGNED(width, 8)) {
811      NV12ToARGBRow = NV12ToARGBRow_NEON;
812    }
813  }
814#endif
815
816  for (y = 0; y < height - 1; y += 2) {
817    NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb, width);
818    NV12ToARGBRow(src_m420 + src_stride_m420, src_m420 + src_stride_m420 * 2,
819                  dst_argb + dst_stride_argb, width);
820    dst_argb += dst_stride_argb * 2;
821    src_m420 += src_stride_m420 * 3;
822  }
823  if (height & 1) {
824    NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb, width);
825  }
826  return 0;
827}
828
829// Convert YUY2 to ARGB.
830LIBYUV_API
831int YUY2ToARGB(const uint8* src_yuy2, int src_stride_yuy2,
832               uint8* dst_argb, int dst_stride_argb,
833               int width, int height) {
834  int y;
835  void (*YUY2ToARGBRow)(const uint8* src_yuy2, uint8* dst_argb, int pix) =
836      YUY2ToARGBRow_C;
837  if (!src_yuy2 || !dst_argb ||
838      width <= 0 || height == 0) {
839    return -1;
840  }
841  // Negative height means invert the image.
842  if (height < 0) {
843    height = -height;
844    src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
845    src_stride_yuy2 = -src_stride_yuy2;
846  }
847  // Coalesce rows.
848  if (src_stride_yuy2 == width * 2 &&
849      dst_stride_argb == width * 4) {
850    width *= height;
851    height = 1;
852    src_stride_yuy2 = dst_stride_argb = 0;
853  }
854#if defined(HAS_YUY2TOARGBROW_SSSE3)
855  // Posix is 16, Windows is 8.
856  if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
857    YUY2ToARGBRow = YUY2ToARGBRow_Any_SSSE3;
858    if (IS_ALIGNED(width, 16)) {
859      YUY2ToARGBRow = YUY2ToARGBRow_Unaligned_SSSE3;
860      if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16) &&
861          IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
862        YUY2ToARGBRow = YUY2ToARGBRow_SSSE3;
863      }
864    }
865  }
866#elif defined(HAS_YUY2TOARGBROW_NEON)
867  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
868    YUY2ToARGBRow = YUY2ToARGBRow_Any_NEON;
869    if (IS_ALIGNED(width, 8)) {
870      YUY2ToARGBRow = YUY2ToARGBRow_NEON;
871    }
872  }
873#endif
874  for (y = 0; y < height; ++y) {
875    YUY2ToARGBRow(src_yuy2, dst_argb, width);
876    src_yuy2 += src_stride_yuy2;
877    dst_argb += dst_stride_argb;
878  }
879  return 0;
880}
881
882// Convert UYVY to ARGB.
883LIBYUV_API
884int UYVYToARGB(const uint8* src_uyvy, int src_stride_uyvy,
885               uint8* dst_argb, int dst_stride_argb,
886               int width, int height) {
887  int y;
888  void (*UYVYToARGBRow)(const uint8* src_uyvy, uint8* dst_argb, int pix) =
889      UYVYToARGBRow_C;
890  if (!src_uyvy || !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_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
898    src_stride_uyvy = -src_stride_uyvy;
899  }
900  // Coalesce rows.
901  if (src_stride_uyvy == width * 2 &&
902      dst_stride_argb == width * 4) {
903    width *= height;
904    height = 1;
905    src_stride_uyvy = dst_stride_argb = 0;
906  }
907#if defined(HAS_UYVYTOARGBROW_SSSE3)
908  // Posix is 16, Windows is 8.
909  if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
910    UYVYToARGBRow = UYVYToARGBRow_Any_SSSE3;
911    if (IS_ALIGNED(width, 16)) {
912      UYVYToARGBRow = UYVYToARGBRow_Unaligned_SSSE3;
913      if (IS_ALIGNED(src_uyvy, 16) && IS_ALIGNED(src_stride_uyvy, 16) &&
914          IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
915        UYVYToARGBRow = UYVYToARGBRow_SSSE3;
916      }
917    }
918  }
919#elif defined(HAS_UYVYTOARGBROW_NEON)
920  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
921    UYVYToARGBRow = UYVYToARGBRow_Any_NEON;
922    if (IS_ALIGNED(width, 8)) {
923      UYVYToARGBRow = UYVYToARGBRow_NEON;
924    }
925  }
926#endif
927  for (y = 0; y < height; ++y) {
928    UYVYToARGBRow(src_uyvy, dst_argb, width);
929    src_uyvy += src_stride_uyvy;
930    dst_argb += dst_stride_argb;
931  }
932  return 0;
933}
934
935#ifdef __cplusplus
936}  // extern "C"
937}  // namespace libyuv
938#endif
939