Home | History | Annotate | Download | only in source
      1 /*
      2  *  Copyright 2012 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_from_argb.h"
     12 
     13 #include "libyuv/basic_types.h"
     14 #include "libyuv/cpu_id.h"
     15 #include "libyuv/planar_functions.h"
     16 #include "libyuv/row.h"
     17 
     18 #ifdef __cplusplus
     19 namespace libyuv {
     20 extern "C" {
     21 #endif
     22 
     23 // ARGB little endian (bgra in memory) to I444
     24 LIBYUV_API
     25 int ARGBToI444(const uint8* src_argb, int src_stride_argb,
     26                uint8* dst_y, int dst_stride_y,
     27                uint8* dst_u, int dst_stride_u,
     28                uint8* dst_v, int dst_stride_v,
     29                int width, int height) {
     30   int y;
     31   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
     32       ARGBToYRow_C;
     33   void (*ARGBToUV444Row)(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
     34       int pix) = ARGBToUV444Row_C;
     35   if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
     36     return -1;
     37   }
     38   if (height < 0) {
     39     height = -height;
     40     src_argb = src_argb + (height - 1) * src_stride_argb;
     41     src_stride_argb = -src_stride_argb;
     42   }
     43   // Coalesce rows.
     44   if (src_stride_argb == width * 4 &&
     45       dst_stride_y == width &&
     46       dst_stride_u == width &&
     47       dst_stride_v == width) {
     48     width *= height;
     49     height = 1;
     50     src_stride_argb = dst_stride_y = dst_stride_u = dst_stride_v = 0;
     51   }
     52 #if defined(HAS_ARGBTOUV444ROW_SSSE3)
     53     if (TestCpuFlag(kCpuHasSSSE3)) {
     54       ARGBToUV444Row = ARGBToUV444Row_Any_SSSE3;
     55       if (IS_ALIGNED(width, 16)) {
     56         ARGBToUV444Row = ARGBToUV444Row_SSSE3;
     57       }
     58   }
     59 #endif
     60 #if defined(HAS_ARGBTOUV444ROW_NEON)
     61   if (TestCpuFlag(kCpuHasNEON)) {
     62     ARGBToUV444Row = ARGBToUV444Row_Any_NEON;
     63     if (IS_ALIGNED(width, 8)) {
     64       ARGBToUV444Row = ARGBToUV444Row_NEON;
     65     }
     66   }
     67 #endif
     68 #if defined(HAS_ARGBTOYROW_SSSE3)
     69   if (TestCpuFlag(kCpuHasSSSE3)) {
     70     ARGBToYRow = ARGBToYRow_Any_SSSE3;
     71     if (IS_ALIGNED(width, 16)) {
     72       ARGBToYRow = ARGBToYRow_SSSE3;
     73     }
     74   }
     75 #endif
     76 #if defined(HAS_ARGBTOYROW_AVX2)
     77   if (TestCpuFlag(kCpuHasAVX2)) {
     78     ARGBToYRow = ARGBToYRow_Any_AVX2;
     79     if (IS_ALIGNED(width, 32)) {
     80       ARGBToYRow = ARGBToYRow_AVX2;
     81     }
     82   }
     83 #endif
     84 #if defined(HAS_ARGBTOYROW_NEON)
     85   if (TestCpuFlag(kCpuHasNEON)) {
     86     ARGBToYRow = ARGBToYRow_Any_NEON;
     87     if (IS_ALIGNED(width, 8)) {
     88       ARGBToYRow = ARGBToYRow_NEON;
     89     }
     90   }
     91 #endif
     92 
     93   for (y = 0; y < height; ++y) {
     94     ARGBToUV444Row(src_argb, dst_u, dst_v, width);
     95     ARGBToYRow(src_argb, dst_y, width);
     96     src_argb += src_stride_argb;
     97     dst_y += dst_stride_y;
     98     dst_u += dst_stride_u;
     99     dst_v += dst_stride_v;
    100   }
    101   return 0;
    102 }
    103 
    104 // ARGB little endian (bgra in memory) to I422
    105 LIBYUV_API
    106 int ARGBToI422(const uint8* src_argb, int src_stride_argb,
    107                uint8* dst_y, int dst_stride_y,
    108                uint8* dst_u, int dst_stride_u,
    109                uint8* dst_v, int dst_stride_v,
    110                int width, int height) {
    111   int y;
    112   void (*ARGBToUV422Row)(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
    113       int pix) = ARGBToUV422Row_C;
    114   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
    115       ARGBToYRow_C;
    116   if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
    117     return -1;
    118   }
    119   if (height < 0) {
    120     height = -height;
    121     src_argb = src_argb + (height - 1) * src_stride_argb;
    122     src_stride_argb = -src_stride_argb;
    123   }
    124   // Coalesce rows.
    125   if (src_stride_argb == width * 4 &&
    126       dst_stride_y == width &&
    127       dst_stride_u * 2 == width &&
    128       dst_stride_v * 2 == width) {
    129     width *= height;
    130     height = 1;
    131     src_stride_argb = dst_stride_y = dst_stride_u = dst_stride_v = 0;
    132   }
    133 #if defined(HAS_ARGBTOUV422ROW_SSSE3)
    134   if (TestCpuFlag(kCpuHasSSSE3)) {
    135     ARGBToUV422Row = ARGBToUV422Row_Any_SSSE3;
    136     if (IS_ALIGNED(width, 16)) {
    137       ARGBToUV422Row = ARGBToUV422Row_SSSE3;
    138     }
    139   }
    140 #endif
    141 #if defined(HAS_ARGBTOUV422ROW_NEON)
    142   if (TestCpuFlag(kCpuHasNEON)) {
    143     ARGBToUV422Row = ARGBToUV422Row_Any_NEON;
    144     if (IS_ALIGNED(width, 16)) {
    145       ARGBToUV422Row = ARGBToUV422Row_NEON;
    146     }
    147   }
    148 #endif
    149 #if defined(HAS_ARGBTOYROW_SSSE3)
    150   if (TestCpuFlag(kCpuHasSSSE3)) {
    151     ARGBToYRow = ARGBToYRow_Any_SSSE3;
    152     if (IS_ALIGNED(width, 16)) {
    153       ARGBToYRow = ARGBToYRow_SSSE3;
    154     }
    155   }
    156 #endif
    157 #if defined(HAS_ARGBTOYROW_AVX2)
    158   if (TestCpuFlag(kCpuHasAVX2)) {
    159     ARGBToYRow = ARGBToYRow_Any_AVX2;
    160     if (IS_ALIGNED(width, 32)) {
    161       ARGBToYRow = ARGBToYRow_AVX2;
    162     }
    163   }
    164 #endif
    165 #if defined(HAS_ARGBTOYROW_NEON)
    166   if (TestCpuFlag(kCpuHasNEON)) {
    167     ARGBToYRow = ARGBToYRow_Any_NEON;
    168     if (IS_ALIGNED(width, 8)) {
    169       ARGBToYRow = ARGBToYRow_NEON;
    170     }
    171   }
    172 #endif
    173 
    174   for (y = 0; y < height; ++y) {
    175     ARGBToUV422Row(src_argb, dst_u, dst_v, width);
    176     ARGBToYRow(src_argb, dst_y, width);
    177     src_argb += src_stride_argb;
    178     dst_y += dst_stride_y;
    179     dst_u += dst_stride_u;
    180     dst_v += dst_stride_v;
    181   }
    182   return 0;
    183 }
    184 
    185 // ARGB little endian (bgra in memory) to I411
    186 LIBYUV_API
    187 int ARGBToI411(const uint8* src_argb, int src_stride_argb,
    188                uint8* dst_y, int dst_stride_y,
    189                uint8* dst_u, int dst_stride_u,
    190                uint8* dst_v, int dst_stride_v,
    191                int width, int height) {
    192   int y;
    193   void (*ARGBToUV411Row)(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
    194       int pix) = ARGBToUV411Row_C;
    195   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
    196       ARGBToYRow_C;
    197   if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
    198     return -1;
    199   }
    200   if (height < 0) {
    201     height = -height;
    202     src_argb = src_argb + (height - 1) * src_stride_argb;
    203     src_stride_argb = -src_stride_argb;
    204   }
    205   // Coalesce rows.
    206   if (src_stride_argb == width * 4 &&
    207       dst_stride_y == width &&
    208       dst_stride_u * 4 == width &&
    209       dst_stride_v * 4 == width) {
    210     width *= height;
    211     height = 1;
    212     src_stride_argb = dst_stride_y = dst_stride_u = dst_stride_v = 0;
    213   }
    214 #if defined(HAS_ARGBTOYROW_SSSE3)
    215   if (TestCpuFlag(kCpuHasSSSE3)) {
    216     ARGBToYRow = ARGBToYRow_Any_SSSE3;
    217     if (IS_ALIGNED(width, 16)) {
    218       ARGBToYRow = ARGBToYRow_SSSE3;
    219     }
    220   }
    221 #endif
    222 #if defined(HAS_ARGBTOYROW_AVX2)
    223   if (TestCpuFlag(kCpuHasAVX2)) {
    224     ARGBToYRow = ARGBToYRow_Any_AVX2;
    225     if (IS_ALIGNED(width, 32)) {
    226       ARGBToYRow = ARGBToYRow_AVX2;
    227     }
    228   }
    229 #endif
    230 #if defined(HAS_ARGBTOYROW_NEON)
    231   if (TestCpuFlag(kCpuHasNEON)) {
    232     ARGBToYRow = ARGBToYRow_Any_NEON;
    233     if (IS_ALIGNED(width, 8)) {
    234       ARGBToYRow = ARGBToYRow_NEON;
    235     }
    236   }
    237 #endif
    238 #if defined(HAS_ARGBTOUV411ROW_NEON)
    239   if (TestCpuFlag(kCpuHasNEON)) {
    240     ARGBToUV411Row = ARGBToUV411Row_Any_NEON;
    241     if (IS_ALIGNED(width, 32)) {
    242       ARGBToUV411Row = ARGBToUV411Row_NEON;
    243     }
    244   }
    245 #endif
    246 
    247   for (y = 0; y < height; ++y) {
    248     ARGBToUV411Row(src_argb, dst_u, dst_v, width);
    249     ARGBToYRow(src_argb, dst_y, width);
    250     src_argb += src_stride_argb;
    251     dst_y += dst_stride_y;
    252     dst_u += dst_stride_u;
    253     dst_v += dst_stride_v;
    254   }
    255   return 0;
    256 }
    257 
    258 LIBYUV_API
    259 int ARGBToNV12(const uint8* src_argb, int src_stride_argb,
    260                uint8* dst_y, int dst_stride_y,
    261                uint8* dst_uv, int dst_stride_uv,
    262                int width, int height) {
    263   int y;
    264   int halfwidth = (width + 1) >> 1;
    265   void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
    266                       uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
    267   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
    268       ARGBToYRow_C;
    269   void (*MergeUVRow_)(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
    270                       int width) = MergeUVRow_C;
    271   if (!src_argb ||
    272       !dst_y || !dst_uv ||
    273       width <= 0 || height == 0) {
    274     return -1;
    275   }
    276   // Negative height means invert the image.
    277   if (height < 0) {
    278     height = -height;
    279     src_argb = src_argb + (height - 1) * src_stride_argb;
    280     src_stride_argb = -src_stride_argb;
    281   }
    282 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
    283   if (TestCpuFlag(kCpuHasSSSE3)) {
    284     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
    285     ARGBToYRow = ARGBToYRow_Any_SSSE3;
    286     if (IS_ALIGNED(width, 16)) {
    287       ARGBToUVRow = ARGBToUVRow_SSSE3;
    288       ARGBToYRow = ARGBToYRow_SSSE3;
    289     }
    290   }
    291 #endif
    292 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
    293   if (TestCpuFlag(kCpuHasAVX2)) {
    294     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
    295     ARGBToYRow = ARGBToYRow_Any_AVX2;
    296     if (IS_ALIGNED(width, 32)) {
    297       ARGBToUVRow = ARGBToUVRow_AVX2;
    298       ARGBToYRow = ARGBToYRow_AVX2;
    299     }
    300   }
    301 #endif
    302 #if defined(HAS_ARGBTOYROW_NEON)
    303   if (TestCpuFlag(kCpuHasNEON)) {
    304     ARGBToYRow = ARGBToYRow_Any_NEON;
    305     if (IS_ALIGNED(width, 8)) {
    306       ARGBToYRow = ARGBToYRow_NEON;
    307     }
    308   }
    309 #endif
    310 #if defined(HAS_ARGBTOUVROW_NEON)
    311   if (TestCpuFlag(kCpuHasNEON)) {
    312     ARGBToUVRow = ARGBToUVRow_Any_NEON;
    313     if (IS_ALIGNED(width, 16)) {
    314       ARGBToUVRow = ARGBToUVRow_NEON;
    315     }
    316   }
    317 #endif
    318 #if defined(HAS_MERGEUVROW_SSE2)
    319   if (TestCpuFlag(kCpuHasSSE2)) {
    320     MergeUVRow_ = MergeUVRow_Any_SSE2;
    321     if (IS_ALIGNED(halfwidth, 16)) {
    322       MergeUVRow_ = MergeUVRow_SSE2;
    323     }
    324   }
    325 #endif
    326 #if defined(HAS_MERGEUVROW_AVX2)
    327   if (TestCpuFlag(kCpuHasAVX2)) {
    328     MergeUVRow_ = MergeUVRow_Any_AVX2;
    329     if (IS_ALIGNED(halfwidth, 32)) {
    330       MergeUVRow_ = MergeUVRow_AVX2;
    331     }
    332   }
    333 #endif
    334 #if defined(HAS_MERGEUVROW_NEON)
    335   if (TestCpuFlag(kCpuHasNEON)) {
    336     MergeUVRow_ = MergeUVRow_Any_NEON;
    337     if (IS_ALIGNED(halfwidth, 16)) {
    338       MergeUVRow_ = MergeUVRow_NEON;
    339     }
    340   }
    341 #endif
    342   {
    343     // Allocate a rows of uv.
    344     align_buffer_64(row_u, ((halfwidth + 31) & ~31) * 2);
    345     uint8* row_v = row_u + ((halfwidth + 31) & ~31);
    346 
    347     for (y = 0; y < height - 1; y += 2) {
    348       ARGBToUVRow(src_argb, src_stride_argb, row_u, row_v, width);
    349       MergeUVRow_(row_u, row_v, dst_uv, halfwidth);
    350       ARGBToYRow(src_argb, dst_y, width);
    351       ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
    352       src_argb += src_stride_argb * 2;
    353       dst_y += dst_stride_y * 2;
    354       dst_uv += dst_stride_uv;
    355     }
    356     if (height & 1) {
    357       ARGBToUVRow(src_argb, 0, row_u, row_v, width);
    358       MergeUVRow_(row_u, row_v, dst_uv, halfwidth);
    359       ARGBToYRow(src_argb, dst_y, width);
    360     }
    361     free_aligned_buffer_64(row_u);
    362   }
    363   return 0;
    364 }
    365 
    366 // Same as NV12 but U and V swapped.
    367 LIBYUV_API
    368 int ARGBToNV21(const uint8* src_argb, int src_stride_argb,
    369                uint8* dst_y, int dst_stride_y,
    370                uint8* dst_uv, int dst_stride_uv,
    371                int width, int height) {
    372   int y;
    373   int halfwidth = (width + 1) >> 1;
    374   void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
    375                       uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
    376   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
    377       ARGBToYRow_C;
    378   void (*MergeUVRow_)(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
    379                       int width) = MergeUVRow_C;
    380   if (!src_argb ||
    381       !dst_y || !dst_uv ||
    382       width <= 0 || height == 0) {
    383     return -1;
    384   }
    385   // Negative height means invert the image.
    386   if (height < 0) {
    387     height = -height;
    388     src_argb = src_argb + (height - 1) * src_stride_argb;
    389     src_stride_argb = -src_stride_argb;
    390   }
    391 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
    392   if (TestCpuFlag(kCpuHasSSSE3)) {
    393     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
    394     ARGBToYRow = ARGBToYRow_Any_SSSE3;
    395     if (IS_ALIGNED(width, 16)) {
    396       ARGBToUVRow = ARGBToUVRow_SSSE3;
    397       ARGBToYRow = ARGBToYRow_SSSE3;
    398     }
    399   }
    400 #endif
    401 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
    402   if (TestCpuFlag(kCpuHasAVX2)) {
    403     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
    404     ARGBToYRow = ARGBToYRow_Any_AVX2;
    405     if (IS_ALIGNED(width, 32)) {
    406       ARGBToUVRow = ARGBToUVRow_AVX2;
    407       ARGBToYRow = ARGBToYRow_AVX2;
    408     }
    409   }
    410 #endif
    411 #if defined(HAS_ARGBTOYROW_NEON)
    412   if (TestCpuFlag(kCpuHasNEON)) {
    413     ARGBToYRow = ARGBToYRow_Any_NEON;
    414     if (IS_ALIGNED(width, 8)) {
    415       ARGBToYRow = ARGBToYRow_NEON;
    416     }
    417   }
    418 #endif
    419 #if defined(HAS_ARGBTOUVROW_NEON)
    420   if (TestCpuFlag(kCpuHasNEON)) {
    421     ARGBToUVRow = ARGBToUVRow_Any_NEON;
    422     if (IS_ALIGNED(width, 16)) {
    423       ARGBToUVRow = ARGBToUVRow_NEON;
    424     }
    425   }
    426 #endif
    427 #if defined(HAS_MERGEUVROW_SSE2)
    428   if (TestCpuFlag(kCpuHasSSE2)) {
    429     MergeUVRow_ = MergeUVRow_Any_SSE2;
    430     if (IS_ALIGNED(halfwidth, 16)) {
    431       MergeUVRow_ = MergeUVRow_SSE2;
    432     }
    433   }
    434 #endif
    435 #if defined(HAS_MERGEUVROW_AVX2)
    436   if (TestCpuFlag(kCpuHasAVX2)) {
    437     MergeUVRow_ = MergeUVRow_Any_AVX2;
    438     if (IS_ALIGNED(halfwidth, 32)) {
    439       MergeUVRow_ = MergeUVRow_AVX2;
    440     }
    441   }
    442 #endif
    443 #if defined(HAS_MERGEUVROW_NEON)
    444   if (TestCpuFlag(kCpuHasNEON)) {
    445     MergeUVRow_ = MergeUVRow_Any_NEON;
    446     if (IS_ALIGNED(halfwidth, 16)) {
    447       MergeUVRow_ = MergeUVRow_NEON;
    448     }
    449   }
    450 #endif
    451   {
    452     // Allocate a rows of uv.
    453     align_buffer_64(row_u, ((halfwidth + 31) & ~31) * 2);
    454     uint8* row_v = row_u + ((halfwidth + 31) & ~31);
    455 
    456     for (y = 0; y < height - 1; y += 2) {
    457       ARGBToUVRow(src_argb, src_stride_argb, row_u, row_v, width);
    458       MergeUVRow_(row_v, row_u, dst_uv, halfwidth);
    459       ARGBToYRow(src_argb, dst_y, width);
    460       ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
    461       src_argb += src_stride_argb * 2;
    462       dst_y += dst_stride_y * 2;
    463       dst_uv += dst_stride_uv;
    464     }
    465     if (height & 1) {
    466       ARGBToUVRow(src_argb, 0, row_u, row_v, width);
    467       MergeUVRow_(row_v, row_u, dst_uv, halfwidth);
    468       ARGBToYRow(src_argb, dst_y, width);
    469     }
    470     free_aligned_buffer_64(row_u);
    471   }
    472   return 0;
    473 }
    474 
    475 // Convert ARGB to YUY2.
    476 LIBYUV_API
    477 int ARGBToYUY2(const uint8* src_argb, int src_stride_argb,
    478                uint8* dst_yuy2, int dst_stride_yuy2,
    479                int width, int height) {
    480   int y;
    481   void (*ARGBToUV422Row)(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
    482       int pix) = ARGBToUV422Row_C;
    483   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
    484       ARGBToYRow_C;
    485   void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u,
    486       const uint8* src_v, uint8* dst_yuy2, int width) = I422ToYUY2Row_C;
    487 
    488   if (!src_argb || !dst_yuy2 ||
    489       width <= 0 || height == 0) {
    490     return -1;
    491   }
    492   // Negative height means invert the image.
    493   if (height < 0) {
    494     height = -height;
    495     dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
    496     dst_stride_yuy2 = -dst_stride_yuy2;
    497   }
    498   // Coalesce rows.
    499   if (src_stride_argb == width * 4 &&
    500       dst_stride_yuy2 == width * 2) {
    501     width *= height;
    502     height = 1;
    503     src_stride_argb = dst_stride_yuy2 = 0;
    504   }
    505 #if defined(HAS_ARGBTOUV422ROW_SSSE3)
    506   if (TestCpuFlag(kCpuHasSSSE3)) {
    507     ARGBToUV422Row = ARGBToUV422Row_Any_SSSE3;
    508     if (IS_ALIGNED(width, 16)) {
    509       ARGBToUV422Row = ARGBToUV422Row_SSSE3;
    510     }
    511   }
    512 #endif
    513 #if defined(HAS_ARGBTOUV422ROW_NEON)
    514   if (TestCpuFlag(kCpuHasNEON)) {
    515     ARGBToUV422Row = ARGBToUV422Row_Any_NEON;
    516     if (IS_ALIGNED(width, 16)) {
    517       ARGBToUV422Row = ARGBToUV422Row_NEON;
    518     }
    519   }
    520 #endif
    521 #if defined(HAS_ARGBTOYROW_SSSE3)
    522   if (TestCpuFlag(kCpuHasSSSE3)) {
    523     ARGBToYRow = ARGBToYRow_Any_SSSE3;
    524     if (IS_ALIGNED(width, 16)) {
    525       ARGBToYRow = ARGBToYRow_SSSE3;
    526     }
    527   }
    528 #endif
    529 #if defined(HAS_ARGBTOYROW_AVX2)
    530   if (TestCpuFlag(kCpuHasAVX2)) {
    531     ARGBToYRow = ARGBToYRow_Any_AVX2;
    532     if (IS_ALIGNED(width, 32)) {
    533       ARGBToYRow = ARGBToYRow_AVX2;
    534     }
    535   }
    536 #endif
    537 #if defined(HAS_ARGBTOYROW_NEON)
    538   if (TestCpuFlag(kCpuHasNEON)) {
    539     ARGBToYRow = ARGBToYRow_Any_NEON;
    540     if (IS_ALIGNED(width, 8)) {
    541       ARGBToYRow = ARGBToYRow_NEON;
    542     }
    543   }
    544 #endif
    545 
    546 #if defined(HAS_I422TOYUY2ROW_SSE2)
    547   if (TestCpuFlag(kCpuHasSSE2)) {
    548     I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
    549     if (IS_ALIGNED(width, 16)) {
    550       I422ToYUY2Row = I422ToYUY2Row_SSE2;
    551     }
    552   }
    553 #endif
    554 #if defined(HAS_I422TOYUY2ROW_NEON)
    555   if (TestCpuFlag(kCpuHasNEON)) {
    556     I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
    557     if (IS_ALIGNED(width, 16)) {
    558       I422ToYUY2Row = I422ToYUY2Row_NEON;
    559     }
    560   }
    561 #endif
    562 
    563   {
    564     // Allocate a rows of yuv.
    565     align_buffer_64(row_y, ((width + 63) & ~63) * 2);
    566     uint8* row_u = row_y + ((width + 63) & ~63);
    567     uint8* row_v = row_u + ((width + 63) & ~63) / 2;
    568 
    569     for (y = 0; y < height; ++y) {
    570       ARGBToUV422Row(src_argb, row_u, row_v, width);
    571       ARGBToYRow(src_argb, row_y, width);
    572       I422ToYUY2Row(row_y, row_u, row_v, dst_yuy2, width);
    573       src_argb += src_stride_argb;
    574       dst_yuy2 += dst_stride_yuy2;
    575     }
    576 
    577     free_aligned_buffer_64(row_y);
    578   }
    579   return 0;
    580 }
    581 
    582 // Convert ARGB to UYVY.
    583 LIBYUV_API
    584 int ARGBToUYVY(const uint8* src_argb, int src_stride_argb,
    585                uint8* dst_uyvy, int dst_stride_uyvy,
    586                int width, int height) {
    587   int y;
    588   void (*ARGBToUV422Row)(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
    589       int pix) = ARGBToUV422Row_C;
    590   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
    591       ARGBToYRow_C;
    592   void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u,
    593       const uint8* src_v, uint8* dst_uyvy, int width) = I422ToUYVYRow_C;
    594 
    595   if (!src_argb || !dst_uyvy ||
    596       width <= 0 || height == 0) {
    597     return -1;
    598   }
    599   // Negative height means invert the image.
    600   if (height < 0) {
    601     height = -height;
    602     dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
    603     dst_stride_uyvy = -dst_stride_uyvy;
    604   }
    605   // Coalesce rows.
    606   if (src_stride_argb == width * 4 &&
    607       dst_stride_uyvy == width * 2) {
    608     width *= height;
    609     height = 1;
    610     src_stride_argb = dst_stride_uyvy = 0;
    611   }
    612 #if defined(HAS_ARGBTOUV422ROW_SSSE3)
    613   if (TestCpuFlag(kCpuHasSSSE3)) {
    614     ARGBToUV422Row = ARGBToUV422Row_Any_SSSE3;
    615     if (IS_ALIGNED(width, 16)) {
    616       ARGBToUV422Row = ARGBToUV422Row_SSSE3;
    617     }
    618   }
    619 #endif
    620 #if defined(HAS_ARGBTOUV422ROW_NEON)
    621   if (TestCpuFlag(kCpuHasNEON)) {
    622     ARGBToUV422Row = ARGBToUV422Row_Any_NEON;
    623     if (IS_ALIGNED(width, 16)) {
    624       ARGBToUV422Row = ARGBToUV422Row_NEON;
    625     }
    626   }
    627 #endif
    628 #if defined(HAS_ARGBTOYROW_SSSE3)
    629   if (TestCpuFlag(kCpuHasSSSE3)) {
    630     ARGBToYRow = ARGBToYRow_Any_SSSE3;
    631     if (IS_ALIGNED(width, 16)) {
    632       ARGBToYRow = ARGBToYRow_SSSE3;
    633     }
    634   }
    635 #endif
    636 #if defined(HAS_ARGBTOYROW_AVX2)
    637   if (TestCpuFlag(kCpuHasAVX2)) {
    638     ARGBToYRow = ARGBToYRow_Any_AVX2;
    639     if (IS_ALIGNED(width, 32)) {
    640       ARGBToYRow = ARGBToYRow_AVX2;
    641     }
    642   }
    643 #endif
    644 #if defined(HAS_ARGBTOYROW_NEON)
    645   if (TestCpuFlag(kCpuHasNEON)) {
    646     ARGBToYRow = ARGBToYRow_Any_NEON;
    647     if (IS_ALIGNED(width, 8)) {
    648       ARGBToYRow = ARGBToYRow_NEON;
    649     }
    650   }
    651 #endif
    652 
    653 #if defined(HAS_I422TOUYVYROW_SSE2)
    654   if (TestCpuFlag(kCpuHasSSE2)) {
    655     I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
    656     if (IS_ALIGNED(width, 16)) {
    657       I422ToUYVYRow = I422ToUYVYRow_SSE2;
    658     }
    659   }
    660 #endif
    661 #if defined(HAS_I422TOUYVYROW_NEON)
    662   if (TestCpuFlag(kCpuHasNEON)) {
    663     I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
    664     if (IS_ALIGNED(width, 16)) {
    665       I422ToUYVYRow = I422ToUYVYRow_NEON;
    666     }
    667   }
    668 #endif
    669 
    670   {
    671     // Allocate a rows of yuv.
    672     align_buffer_64(row_y, ((width + 63) & ~63) * 2);
    673     uint8* row_u = row_y + ((width + 63) & ~63);
    674     uint8* row_v = row_u + ((width + 63) & ~63) / 2;
    675 
    676     for (y = 0; y < height; ++y) {
    677       ARGBToUV422Row(src_argb, row_u, row_v, width);
    678       ARGBToYRow(src_argb, row_y, width);
    679       I422ToUYVYRow(row_y, row_u, row_v, dst_uyvy, width);
    680       src_argb += src_stride_argb;
    681       dst_uyvy += dst_stride_uyvy;
    682     }
    683 
    684     free_aligned_buffer_64(row_y);
    685   }
    686   return 0;
    687 }
    688 
    689 // Convert ARGB to I400.
    690 LIBYUV_API
    691 int ARGBToI400(const uint8* src_argb, int src_stride_argb,
    692                uint8* dst_y, int dst_stride_y,
    693                int width, int height) {
    694   int y;
    695   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
    696       ARGBToYRow_C;
    697   if (!src_argb || !dst_y || width <= 0 || height == 0) {
    698     return -1;
    699   }
    700   if (height < 0) {
    701     height = -height;
    702     src_argb = src_argb + (height - 1) * src_stride_argb;
    703     src_stride_argb = -src_stride_argb;
    704   }
    705   // Coalesce rows.
    706   if (src_stride_argb == width * 4 &&
    707       dst_stride_y == width) {
    708     width *= height;
    709     height = 1;
    710     src_stride_argb = dst_stride_y = 0;
    711   }
    712 #if defined(HAS_ARGBTOYROW_SSSE3)
    713   if (TestCpuFlag(kCpuHasSSSE3)) {
    714     ARGBToYRow = ARGBToYRow_Any_SSSE3;
    715     if (IS_ALIGNED(width, 16)) {
    716       ARGBToYRow = ARGBToYRow_SSSE3;
    717     }
    718   }
    719 #endif
    720 #if defined(HAS_ARGBTOYROW_AVX2)
    721   if (TestCpuFlag(kCpuHasAVX2)) {
    722     ARGBToYRow = ARGBToYRow_Any_AVX2;
    723     if (IS_ALIGNED(width, 32)) {
    724       ARGBToYRow = ARGBToYRow_AVX2;
    725     }
    726   }
    727 #endif
    728 #if defined(HAS_ARGBTOYROW_NEON)
    729   if (TestCpuFlag(kCpuHasNEON)) {
    730     ARGBToYRow = ARGBToYRow_Any_NEON;
    731     if (IS_ALIGNED(width, 8)) {
    732       ARGBToYRow = ARGBToYRow_NEON;
    733     }
    734   }
    735 #endif
    736 
    737   for (y = 0; y < height; ++y) {
    738     ARGBToYRow(src_argb, dst_y, width);
    739     src_argb += src_stride_argb;
    740     dst_y += dst_stride_y;
    741   }
    742   return 0;
    743 }
    744 
    745 // Shuffle table for converting ARGB to RGBA.
    746 static uvec8 kShuffleMaskARGBToRGBA = {
    747   3u, 0u, 1u, 2u, 7u, 4u, 5u, 6u, 11u, 8u, 9u, 10u, 15u, 12u, 13u, 14u
    748 };
    749 
    750 // Convert ARGB to RGBA.
    751 LIBYUV_API
    752 int ARGBToRGBA(const uint8* src_argb, int src_stride_argb,
    753                uint8* dst_rgba, int dst_stride_rgba,
    754                int width, int height) {
    755   return ARGBShuffle(src_argb, src_stride_argb,
    756                      dst_rgba, dst_stride_rgba,
    757                      (const uint8*)(&kShuffleMaskARGBToRGBA),
    758                      width, height);
    759 }
    760 
    761 // Convert ARGB To RGB24.
    762 LIBYUV_API
    763 int ARGBToRGB24(const uint8* src_argb, int src_stride_argb,
    764                 uint8* dst_rgb24, int dst_stride_rgb24,
    765                 int width, int height) {
    766   int y;
    767   void (*ARGBToRGB24Row)(const uint8* src_argb, uint8* dst_rgb, int pix) =
    768       ARGBToRGB24Row_C;
    769   if (!src_argb || !dst_rgb24 || width <= 0 || height == 0) {
    770     return -1;
    771   }
    772   if (height < 0) {
    773     height = -height;
    774     src_argb = src_argb + (height - 1) * src_stride_argb;
    775     src_stride_argb = -src_stride_argb;
    776   }
    777   // Coalesce rows.
    778   if (src_stride_argb == width * 4 &&
    779       dst_stride_rgb24 == width * 3) {
    780     width *= height;
    781     height = 1;
    782     src_stride_argb = dst_stride_rgb24 = 0;
    783   }
    784 #if defined(HAS_ARGBTORGB24ROW_SSSE3)
    785   if (TestCpuFlag(kCpuHasSSSE3)) {
    786     ARGBToRGB24Row = ARGBToRGB24Row_Any_SSSE3;
    787     if (IS_ALIGNED(width, 16)) {
    788       ARGBToRGB24Row = ARGBToRGB24Row_SSSE3;
    789     }
    790   }
    791 #endif
    792 #if defined(HAS_ARGBTORGB24ROW_NEON)
    793   if (TestCpuFlag(kCpuHasNEON)) {
    794     ARGBToRGB24Row = ARGBToRGB24Row_Any_NEON;
    795     if (IS_ALIGNED(width, 8)) {
    796       ARGBToRGB24Row = ARGBToRGB24Row_NEON;
    797     }
    798   }
    799 #endif
    800 
    801   for (y = 0; y < height; ++y) {
    802     ARGBToRGB24Row(src_argb, dst_rgb24, width);
    803     src_argb += src_stride_argb;
    804     dst_rgb24 += dst_stride_rgb24;
    805   }
    806   return 0;
    807 }
    808 
    809 // Convert ARGB To RAW.
    810 LIBYUV_API
    811 int ARGBToRAW(const uint8* src_argb, int src_stride_argb,
    812               uint8* dst_raw, int dst_stride_raw,
    813               int width, int height) {
    814   int y;
    815   void (*ARGBToRAWRow)(const uint8* src_argb, uint8* dst_rgb, int pix) =
    816       ARGBToRAWRow_C;
    817   if (!src_argb || !dst_raw || width <= 0 || height == 0) {
    818     return -1;
    819   }
    820   if (height < 0) {
    821     height = -height;
    822     src_argb = src_argb + (height - 1) * src_stride_argb;
    823     src_stride_argb = -src_stride_argb;
    824   }
    825   // Coalesce rows.
    826   if (src_stride_argb == width * 4 &&
    827       dst_stride_raw == width * 3) {
    828     width *= height;
    829     height = 1;
    830     src_stride_argb = dst_stride_raw = 0;
    831   }
    832 #if defined(HAS_ARGBTORAWROW_SSSE3)
    833   if (TestCpuFlag(kCpuHasSSSE3)) {
    834     ARGBToRAWRow = ARGBToRAWRow_Any_SSSE3;
    835     if (IS_ALIGNED(width, 16)) {
    836       ARGBToRAWRow = ARGBToRAWRow_SSSE3;
    837     }
    838   }
    839 #endif
    840 #if defined(HAS_ARGBTORAWROW_NEON)
    841   if (TestCpuFlag(kCpuHasNEON)) {
    842     ARGBToRAWRow = ARGBToRAWRow_Any_NEON;
    843     if (IS_ALIGNED(width, 8)) {
    844       ARGBToRAWRow = ARGBToRAWRow_NEON;
    845     }
    846   }
    847 #endif
    848 
    849   for (y = 0; y < height; ++y) {
    850     ARGBToRAWRow(src_argb, dst_raw, width);
    851     src_argb += src_stride_argb;
    852     dst_raw += dst_stride_raw;
    853   }
    854   return 0;
    855 }
    856 
    857 // Ordered 8x8 dither for 888 to 565.  Values from 0 to 7.
    858 static const uint8 kDither565_4x4[16] = {
    859   0, 4, 1, 5,
    860   6, 2, 7, 3,
    861   1, 5, 0, 4,
    862   7, 3, 6, 2,
    863 };
    864 
    865 // Convert ARGB To RGB565 with 4x4 dither matrix (16 bytes).
    866 LIBYUV_API
    867 int ARGBToRGB565Dither(const uint8* src_argb, int src_stride_argb,
    868                        uint8* dst_rgb565, int dst_stride_rgb565,
    869                        const uint8* dither4x4, int width, int height) {
    870   int y;
    871   void (*ARGBToRGB565DitherRow)(const uint8* src_argb, uint8* dst_rgb,
    872       const uint32 dither4, int pix) = ARGBToRGB565DitherRow_C;
    873   if (!src_argb || !dst_rgb565 || width <= 0 || height == 0) {
    874     return -1;
    875   }
    876   if (height < 0) {
    877     height = -height;
    878     src_argb = src_argb + (height - 1) * src_stride_argb;
    879     src_stride_argb = -src_stride_argb;
    880   }
    881   if (!dither4x4) {
    882     dither4x4 = kDither565_4x4;
    883   }
    884 #if defined(HAS_ARGBTORGB565DITHERROW_SSE2)
    885   if (TestCpuFlag(kCpuHasSSE2)) {
    886     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_SSE2;
    887     if (IS_ALIGNED(width, 4)) {
    888       ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_SSE2;
    889     }
    890   }
    891 #endif
    892 #if defined(HAS_ARGBTORGB565DITHERROW_AVX2)
    893   if (TestCpuFlag(kCpuHasAVX2)) {
    894     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_AVX2;
    895     if (IS_ALIGNED(width, 8)) {
    896       ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_AVX2;
    897     }
    898   }
    899 #endif
    900 #if defined(HAS_ARGBTORGB565DITHERROW_NEON)
    901   if (TestCpuFlag(kCpuHasNEON)) {
    902     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_NEON;
    903     if (IS_ALIGNED(width, 8)) {
    904       ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_NEON;
    905     }
    906   }
    907 #endif
    908   for (y = 0; y < height; ++y) {
    909     ARGBToRGB565DitherRow(src_argb, dst_rgb565,
    910                           *(uint32*)(dither4x4 + ((y & 3) << 2)), width);
    911     src_argb += src_stride_argb;
    912     dst_rgb565 += dst_stride_rgb565;
    913   }
    914   return 0;
    915 }
    916 
    917 // Convert ARGB To RGB565.
    918 // TODO(fbarchard): Consider using dither function low level with zeros.
    919 LIBYUV_API
    920 int ARGBToRGB565(const uint8* src_argb, int src_stride_argb,
    921                  uint8* dst_rgb565, int dst_stride_rgb565,
    922                  int width, int height) {
    923   int y;
    924   void (*ARGBToRGB565Row)(const uint8* src_argb, uint8* dst_rgb, int pix) =
    925       ARGBToRGB565Row_C;
    926   if (!src_argb || !dst_rgb565 || width <= 0 || height == 0) {
    927     return -1;
    928   }
    929   if (height < 0) {
    930     height = -height;
    931     src_argb = src_argb + (height - 1) * src_stride_argb;
    932     src_stride_argb = -src_stride_argb;
    933   }
    934   // Coalesce rows.
    935   if (src_stride_argb == width * 4 &&
    936       dst_stride_rgb565 == width * 2) {
    937     width *= height;
    938     height = 1;
    939     src_stride_argb = dst_stride_rgb565 = 0;
    940   }
    941 #if defined(HAS_ARGBTORGB565ROW_SSE2)
    942   if (TestCpuFlag(kCpuHasSSE2)) {
    943     ARGBToRGB565Row = ARGBToRGB565Row_Any_SSE2;
    944     if (IS_ALIGNED(width, 4)) {
    945       ARGBToRGB565Row = ARGBToRGB565Row_SSE2;
    946     }
    947   }
    948 #endif
    949 #if defined(HAS_ARGBTORGB565ROW_AVX2)
    950   if (TestCpuFlag(kCpuHasAVX2)) {
    951     ARGBToRGB565Row = ARGBToRGB565Row_Any_AVX2;
    952     if (IS_ALIGNED(width, 8)) {
    953       ARGBToRGB565Row = ARGBToRGB565Row_AVX2;
    954     }
    955   }
    956 #endif
    957 #if defined(HAS_ARGBTORGB565ROW_NEON)
    958   if (TestCpuFlag(kCpuHasNEON)) {
    959     ARGBToRGB565Row = ARGBToRGB565Row_Any_NEON;
    960     if (IS_ALIGNED(width, 8)) {
    961       ARGBToRGB565Row = ARGBToRGB565Row_NEON;
    962     }
    963   }
    964 #endif
    965 
    966   for (y = 0; y < height; ++y) {
    967     ARGBToRGB565Row(src_argb, dst_rgb565, width);
    968     src_argb += src_stride_argb;
    969     dst_rgb565 += dst_stride_rgb565;
    970   }
    971   return 0;
    972 }
    973 
    974 // Convert ARGB To ARGB1555.
    975 LIBYUV_API
    976 int ARGBToARGB1555(const uint8* src_argb, int src_stride_argb,
    977                    uint8* dst_argb1555, int dst_stride_argb1555,
    978                    int width, int height) {
    979   int y;
    980   void (*ARGBToARGB1555Row)(const uint8* src_argb, uint8* dst_rgb, int pix) =
    981       ARGBToARGB1555Row_C;
    982   if (!src_argb || !dst_argb1555 || width <= 0 || height == 0) {
    983     return -1;
    984   }
    985   if (height < 0) {
    986     height = -height;
    987     src_argb = src_argb + (height - 1) * src_stride_argb;
    988     src_stride_argb = -src_stride_argb;
    989   }
    990   // Coalesce rows.
    991   if (src_stride_argb == width * 4 &&
    992       dst_stride_argb1555 == width * 2) {
    993     width *= height;
    994     height = 1;
    995     src_stride_argb = dst_stride_argb1555 = 0;
    996   }
    997 #if defined(HAS_ARGBTOARGB1555ROW_SSE2)
    998   if (TestCpuFlag(kCpuHasSSE2)) {
    999     ARGBToARGB1555Row = ARGBToARGB1555Row_Any_SSE2;
   1000     if (IS_ALIGNED(width, 4)) {
   1001       ARGBToARGB1555Row = ARGBToARGB1555Row_SSE2;
   1002     }
   1003   }
   1004 #endif
   1005 #if defined(HAS_ARGBTOARGB1555ROW_AVX2)
   1006   if (TestCpuFlag(kCpuHasAVX2)) {
   1007     ARGBToARGB1555Row = ARGBToARGB1555Row_Any_AVX2;
   1008     if (IS_ALIGNED(width, 8)) {
   1009       ARGBToARGB1555Row = ARGBToARGB1555Row_AVX2;
   1010     }
   1011   }
   1012 #endif
   1013 #if defined(HAS_ARGBTOARGB1555ROW_NEON)
   1014   if (TestCpuFlag(kCpuHasNEON)) {
   1015     ARGBToARGB1555Row = ARGBToARGB1555Row_Any_NEON;
   1016     if (IS_ALIGNED(width, 8)) {
   1017       ARGBToARGB1555Row = ARGBToARGB1555Row_NEON;
   1018     }
   1019   }
   1020 #endif
   1021 
   1022   for (y = 0; y < height; ++y) {
   1023     ARGBToARGB1555Row(src_argb, dst_argb1555, width);
   1024     src_argb += src_stride_argb;
   1025     dst_argb1555 += dst_stride_argb1555;
   1026   }
   1027   return 0;
   1028 }
   1029 
   1030 // Convert ARGB To ARGB4444.
   1031 LIBYUV_API
   1032 int ARGBToARGB4444(const uint8* src_argb, int src_stride_argb,
   1033                    uint8* dst_argb4444, int dst_stride_argb4444,
   1034                    int width, int height) {
   1035   int y;
   1036   void (*ARGBToARGB4444Row)(const uint8* src_argb, uint8* dst_rgb, int pix) =
   1037       ARGBToARGB4444Row_C;
   1038   if (!src_argb || !dst_argb4444 || width <= 0 || height == 0) {
   1039     return -1;
   1040   }
   1041   if (height < 0) {
   1042     height = -height;
   1043     src_argb = src_argb + (height - 1) * src_stride_argb;
   1044     src_stride_argb = -src_stride_argb;
   1045   }
   1046   // Coalesce rows.
   1047   if (src_stride_argb == width * 4 &&
   1048       dst_stride_argb4444 == width * 2) {
   1049     width *= height;
   1050     height = 1;
   1051     src_stride_argb = dst_stride_argb4444 = 0;
   1052   }
   1053 #if defined(HAS_ARGBTOARGB4444ROW_SSE2)
   1054   if (TestCpuFlag(kCpuHasSSE2)) {
   1055     ARGBToARGB4444Row = ARGBToARGB4444Row_Any_SSE2;
   1056     if (IS_ALIGNED(width, 4)) {
   1057       ARGBToARGB4444Row = ARGBToARGB4444Row_SSE2;
   1058     }
   1059   }
   1060 #endif
   1061 #if defined(HAS_ARGBTOARGB4444ROW_AVX2)
   1062   if (TestCpuFlag(kCpuHasAVX2)) {
   1063     ARGBToARGB4444Row = ARGBToARGB4444Row_Any_AVX2;
   1064     if (IS_ALIGNED(width, 8)) {
   1065       ARGBToARGB4444Row = ARGBToARGB4444Row_AVX2;
   1066     }
   1067   }
   1068 #endif
   1069 #if defined(HAS_ARGBTOARGB4444ROW_NEON)
   1070   if (TestCpuFlag(kCpuHasNEON)) {
   1071     ARGBToARGB4444Row = ARGBToARGB4444Row_Any_NEON;
   1072     if (IS_ALIGNED(width, 8)) {
   1073       ARGBToARGB4444Row = ARGBToARGB4444Row_NEON;
   1074     }
   1075   }
   1076 #endif
   1077 
   1078   for (y = 0; y < height; ++y) {
   1079     ARGBToARGB4444Row(src_argb, dst_argb4444, width);
   1080     src_argb += src_stride_argb;
   1081     dst_argb4444 += dst_stride_argb4444;
   1082   }
   1083   return 0;
   1084 }
   1085 
   1086 // Convert ARGB to J420. (JPeg full range I420).
   1087 LIBYUV_API
   1088 int ARGBToJ420(const uint8* src_argb, int src_stride_argb,
   1089                uint8* dst_yj, int dst_stride_yj,
   1090                uint8* dst_u, int dst_stride_u,
   1091                uint8* dst_v, int dst_stride_v,
   1092                int width, int height) {
   1093   int y;
   1094   void (*ARGBToUVJRow)(const uint8* src_argb0, int src_stride_argb,
   1095                        uint8* dst_u, uint8* dst_v, int width) = ARGBToUVJRow_C;
   1096   void (*ARGBToYJRow)(const uint8* src_argb, uint8* dst_yj, int pix) =
   1097       ARGBToYJRow_C;
   1098   if (!src_argb ||
   1099       !dst_yj || !dst_u || !dst_v ||
   1100       width <= 0 || height == 0) {
   1101     return -1;
   1102   }
   1103   // Negative height means invert the image.
   1104   if (height < 0) {
   1105     height = -height;
   1106     src_argb = src_argb + (height - 1) * src_stride_argb;
   1107     src_stride_argb = -src_stride_argb;
   1108   }
   1109 #if defined(HAS_ARGBTOYJROW_SSSE3) && defined(HAS_ARGBTOUVJROW_SSSE3)
   1110   if (TestCpuFlag(kCpuHasSSSE3)) {
   1111     ARGBToUVJRow = ARGBToUVJRow_Any_SSSE3;
   1112     ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
   1113     if (IS_ALIGNED(width, 16)) {
   1114       ARGBToUVJRow = ARGBToUVJRow_SSSE3;
   1115       ARGBToYJRow = ARGBToYJRow_SSSE3;
   1116     }
   1117   }
   1118 #endif
   1119 #if defined(HAS_ARGBTOYJROW_AVX2)
   1120   if (TestCpuFlag(kCpuHasAVX2)) {
   1121     ARGBToYJRow = ARGBToYJRow_Any_AVX2;
   1122     if (IS_ALIGNED(width, 32)) {
   1123       ARGBToYJRow = ARGBToYJRow_AVX2;
   1124     }
   1125   }
   1126 #endif
   1127 #if defined(HAS_ARGBTOYJROW_NEON)
   1128   if (TestCpuFlag(kCpuHasNEON)) {
   1129     ARGBToYJRow = ARGBToYJRow_Any_NEON;
   1130     if (IS_ALIGNED(width, 8)) {
   1131       ARGBToYJRow = ARGBToYJRow_NEON;
   1132     }
   1133   }
   1134 #endif
   1135 #if defined(HAS_ARGBTOUVJROW_NEON)
   1136   if (TestCpuFlag(kCpuHasNEON)) {
   1137     ARGBToUVJRow = ARGBToUVJRow_Any_NEON;
   1138     if (IS_ALIGNED(width, 16)) {
   1139       ARGBToUVJRow = ARGBToUVJRow_NEON;
   1140     }
   1141   }
   1142 #endif
   1143 
   1144   for (y = 0; y < height - 1; y += 2) {
   1145     ARGBToUVJRow(src_argb, src_stride_argb, dst_u, dst_v, width);
   1146     ARGBToYJRow(src_argb, dst_yj, width);
   1147     ARGBToYJRow(src_argb + src_stride_argb, dst_yj + dst_stride_yj, width);
   1148     src_argb += src_stride_argb * 2;
   1149     dst_yj += dst_stride_yj * 2;
   1150     dst_u += dst_stride_u;
   1151     dst_v += dst_stride_v;
   1152   }
   1153   if (height & 1) {
   1154     ARGBToUVJRow(src_argb, 0, dst_u, dst_v, width);
   1155     ARGBToYJRow(src_argb, dst_yj, width);
   1156   }
   1157   return 0;
   1158 }
   1159 
   1160 // ARGB little endian (bgra in memory) to J422
   1161 LIBYUV_API
   1162 int ARGBToJ422(const uint8* src_argb, int src_stride_argb,
   1163                uint8* dst_y, int dst_stride_y,
   1164                uint8* dst_u, int dst_stride_u,
   1165                uint8* dst_v, int dst_stride_v,
   1166                int width, int height) {
   1167   int y;
   1168   void (*ARGBToUVJ422Row)(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
   1169       int pix) = ARGBToUVJ422Row_C;
   1170   void (*ARGBToYJRow)(const uint8* src_argb, uint8* dst_y, int pix) =
   1171       ARGBToYJRow_C;
   1172   if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
   1173     return -1;
   1174   }
   1175   if (height < 0) {
   1176     height = -height;
   1177     src_argb = src_argb + (height - 1) * src_stride_argb;
   1178     src_stride_argb = -src_stride_argb;
   1179   }
   1180   // Coalesce rows.
   1181   if (src_stride_argb == width * 4 &&
   1182       dst_stride_y == width &&
   1183       dst_stride_u * 2 == width &&
   1184       dst_stride_v * 2 == width) {
   1185     width *= height;
   1186     height = 1;
   1187     src_stride_argb = dst_stride_y = dst_stride_u = dst_stride_v = 0;
   1188   }
   1189 #if defined(HAS_ARGBTOUVJ422ROW_SSSE3)
   1190   if (TestCpuFlag(kCpuHasSSSE3)) {
   1191     ARGBToUVJ422Row = ARGBToUVJ422Row_Any_SSSE3;
   1192     if (IS_ALIGNED(width, 16)) {
   1193       ARGBToUVJ422Row = ARGBToUVJ422Row_SSSE3;
   1194     }
   1195   }
   1196 #endif
   1197 #if defined(HAS_ARGBTOUVJ422ROW_NEON)
   1198   if (TestCpuFlag(kCpuHasNEON)) {
   1199     ARGBToUVJ422Row = ARGBToUVJ422Row_Any_NEON;
   1200     if (IS_ALIGNED(width, 16)) {
   1201       ARGBToUVJ422Row = ARGBToUVJ422Row_NEON;
   1202     }
   1203   }
   1204 #endif
   1205 
   1206 #if defined(HAS_ARGBTOYJROW_SSSE3)
   1207   if (TestCpuFlag(kCpuHasSSSE3)) {
   1208     ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
   1209     if (IS_ALIGNED(width, 16)) {
   1210       ARGBToYJRow = ARGBToYJRow_SSSE3;
   1211     }
   1212   }
   1213 #endif
   1214 #if defined(HAS_ARGBTOYJROW_AVX2)
   1215   if (TestCpuFlag(kCpuHasAVX2)) {
   1216     ARGBToYJRow = ARGBToYJRow_Any_AVX2;
   1217     if (IS_ALIGNED(width, 32)) {
   1218       ARGBToYJRow = ARGBToYJRow_AVX2;
   1219     }
   1220   }
   1221 #endif
   1222 #if defined(HAS_ARGBTOYJROW_NEON)
   1223   if (TestCpuFlag(kCpuHasNEON)) {
   1224     ARGBToYJRow = ARGBToYJRow_Any_NEON;
   1225     if (IS_ALIGNED(width, 8)) {
   1226       ARGBToYJRow = ARGBToYJRow_NEON;
   1227     }
   1228   }
   1229 #endif
   1230 
   1231   for (y = 0; y < height; ++y) {
   1232     ARGBToUVJ422Row(src_argb, dst_u, dst_v, width);
   1233     ARGBToYJRow(src_argb, dst_y, width);
   1234     src_argb += src_stride_argb;
   1235     dst_y += dst_stride_y;
   1236     dst_u += dst_stride_u;
   1237     dst_v += dst_stride_v;
   1238   }
   1239   return 0;
   1240 }
   1241 
   1242 // Convert ARGB to J400.
   1243 LIBYUV_API
   1244 int ARGBToJ400(const uint8* src_argb, int src_stride_argb,
   1245                uint8* dst_yj, int dst_stride_yj,
   1246                int width, int height) {
   1247   int y;
   1248   void (*ARGBToYJRow)(const uint8* src_argb, uint8* dst_yj, int pix) =
   1249       ARGBToYJRow_C;
   1250   if (!src_argb || !dst_yj || width <= 0 || height == 0) {
   1251     return -1;
   1252   }
   1253   if (height < 0) {
   1254     height = -height;
   1255     src_argb = src_argb + (height - 1) * src_stride_argb;
   1256     src_stride_argb = -src_stride_argb;
   1257   }
   1258   // Coalesce rows.
   1259   if (src_stride_argb == width * 4 &&
   1260       dst_stride_yj == width) {
   1261     width *= height;
   1262     height = 1;
   1263     src_stride_argb = dst_stride_yj = 0;
   1264   }
   1265 #if defined(HAS_ARGBTOYJROW_SSSE3)
   1266   if (TestCpuFlag(kCpuHasSSSE3)) {
   1267     ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
   1268     if (IS_ALIGNED(width, 16)) {
   1269       ARGBToYJRow = ARGBToYJRow_SSSE3;
   1270     }
   1271   }
   1272 #endif
   1273 #if defined(HAS_ARGBTOYJROW_AVX2)
   1274   if (TestCpuFlag(kCpuHasAVX2)) {
   1275     ARGBToYJRow = ARGBToYJRow_Any_AVX2;
   1276     if (IS_ALIGNED(width, 32)) {
   1277       ARGBToYJRow = ARGBToYJRow_AVX2;
   1278     }
   1279   }
   1280 #endif
   1281 #if defined(HAS_ARGBTOYJROW_NEON)
   1282   if (TestCpuFlag(kCpuHasNEON)) {
   1283     ARGBToYJRow = ARGBToYJRow_Any_NEON;
   1284     if (IS_ALIGNED(width, 8)) {
   1285       ARGBToYJRow = ARGBToYJRow_NEON;
   1286     }
   1287   }
   1288 #endif
   1289 
   1290   for (y = 0; y < height; ++y) {
   1291     ARGBToYJRow(src_argb, dst_yj, width);
   1292     src_argb += src_stride_argb;
   1293     dst_yj += dst_stride_yj;
   1294   }
   1295   return 0;
   1296 }
   1297 
   1298 #ifdef __cplusplus
   1299 }  // extern "C"
   1300 }  // namespace libyuv
   1301 #endif
   1302