Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / libyuv / source / convert_argb.cc
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
23 namespace libyuv {
24 extern "C" {
25 #endif
26
27 // Copy ARGB with optional flipping
28 LIBYUV_API
29 int 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.
49 LIBYUV_API
50 int 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.
111 LIBYUV_API
112 int 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.
191 LIBYUV_API
192 int 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.
253 LIBYUV_API
254 int 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.
304 LIBYUV_API
305 int 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.
355 static 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.
360 static 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.
365 static 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.
370 LIBYUV_API
371 int 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).
381 LIBYUV_API
382 int 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.
392 LIBYUV_API
393 int 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).
403 LIBYUV_API
404 int 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.
414 LIBYUV_API
415 int 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.
425 LIBYUV_API
426 int 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.
475 LIBYUV_API
476 int 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.
525 LIBYUV_API
526 int 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.
575 LIBYUV_API
576 int 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.
625 LIBYUV_API
626 int 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.
675 LIBYUV_API
676 int 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.
726 LIBYUV_API
727 int 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.
778 LIBYUV_API
779 int 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.
830 LIBYUV_API
831 int 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.
883 LIBYUV_API
884 int 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