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