Home | History | Annotate | Download | only in source
      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.h"
     12 
     13 #include "libyuv/basic_types.h"
     14 #include "libyuv/cpu_id.h"
     15 #include "libyuv/planar_functions.h"
     16 #include "libyuv/rotate.h"
     17 #include "libyuv/scale.h"  // For ScalePlane()
     18 #include "libyuv/row.h"
     19 
     20 #ifdef __cplusplus
     21 namespace libyuv {
     22 extern "C" {
     23 #endif
     24 
     25 #define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
     26 static __inline int Abs(int v) {
     27   return v >= 0 ? v : -v;
     28 }
     29 
     30 // Any I4xx To I420 format with mirroring.
     31 static int I4xxToI420(const uint8* src_y, int src_stride_y,
     32                       const uint8* src_u, int src_stride_u,
     33                       const uint8* src_v, int src_stride_v,
     34                       uint8* dst_y, int dst_stride_y,
     35                       uint8* dst_u, int dst_stride_u,
     36                       uint8* dst_v, int dst_stride_v,
     37                       int src_y_width, int src_y_height,
     38                       int src_uv_width, int src_uv_height) {
     39   if (src_y_width == 0 || src_y_height == 0 ||
     40       src_uv_width == 0 || src_uv_height == 0) {
     41     return -1;
     42   }
     43   const int dst_y_width = Abs(src_y_width);
     44   const int dst_y_height = Abs(src_y_height);
     45   const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1);
     46   const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1);
     47   ScalePlane(src_y, src_stride_y, src_y_width, src_y_height,
     48              dst_y, dst_stride_y, dst_y_width, dst_y_height,
     49              kFilterBilinear);
     50   ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height,
     51              dst_u, dst_stride_u, dst_uv_width, dst_uv_height,
     52              kFilterBilinear);
     53   ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height,
     54              dst_v, dst_stride_v, dst_uv_width, dst_uv_height,
     55              kFilterBilinear);
     56   return 0;
     57 }
     58 
     59 // Copy I420 with optional flipping
     60 // TODO(fbarchard): Use Scale plane which supports mirroring, but ensure
     61 // is does row coalescing.
     62 LIBYUV_API
     63 int I420Copy(const uint8* src_y, int src_stride_y,
     64              const uint8* src_u, int src_stride_u,
     65              const uint8* src_v, int src_stride_v,
     66              uint8* dst_y, int dst_stride_y,
     67              uint8* dst_u, int dst_stride_u,
     68              uint8* dst_v, int dst_stride_v,
     69              int width, int height) {
     70   if (!src_y || !src_u || !src_v ||
     71       !dst_y || !dst_u || !dst_v ||
     72       width <= 0 || height == 0) {
     73     return -1;
     74   }
     75   // Negative height means invert the image.
     76   if (height < 0) {
     77     height = -height;
     78     const int halfheight = (height + 1) >> 1;
     79     src_y = src_y + (height - 1) * src_stride_y;
     80     src_u = src_u + (halfheight - 1) * src_stride_u;
     81     src_v = src_v + (halfheight - 1) * src_stride_v;
     82     src_stride_y = -src_stride_y;
     83     src_stride_u = -src_stride_u;
     84     src_stride_v = -src_stride_v;
     85   }
     86 
     87   if (dst_y) {
     88     CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
     89   }
     90   // Copy UV planes.
     91   const int halfwidth = (width + 1) >> 1;
     92   const int halfheight = (height + 1) >> 1;
     93   CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
     94   CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
     95   return 0;
     96 }
     97 
     98 // 422 chroma is 1/2 width, 1x height
     99 // 420 chroma is 1/2 width, 1/2 height
    100 LIBYUV_API
    101 int I422ToI420(const uint8* src_y, int src_stride_y,
    102                const uint8* src_u, int src_stride_u,
    103                const uint8* src_v, int src_stride_v,
    104                uint8* dst_y, int dst_stride_y,
    105                uint8* dst_u, int dst_stride_u,
    106                uint8* dst_v, int dst_stride_v,
    107                int width, int height) {
    108   const int src_uv_width = SUBSAMPLE(width, 1, 1);
    109   return I4xxToI420(src_y, src_stride_y,
    110                     src_u, src_stride_u,
    111                     src_v, src_stride_v,
    112                     dst_y, dst_stride_y,
    113                     dst_u, dst_stride_u,
    114                     dst_v, dst_stride_v,
    115                     width, height,
    116                     src_uv_width, height);
    117 }
    118 
    119 // 444 chroma is 1x width, 1x height
    120 // 420 chroma is 1/2 width, 1/2 height
    121 LIBYUV_API
    122 int I444ToI420(const uint8* src_y, int src_stride_y,
    123                const uint8* src_u, int src_stride_u,
    124                const uint8* src_v, int src_stride_v,
    125                uint8* dst_y, int dst_stride_y,
    126                uint8* dst_u, int dst_stride_u,
    127                uint8* dst_v, int dst_stride_v,
    128                int width, int height) {
    129   return I4xxToI420(src_y, src_stride_y,
    130                     src_u, src_stride_u,
    131                     src_v, src_stride_v,
    132                     dst_y, dst_stride_y,
    133                     dst_u, dst_stride_u,
    134                     dst_v, dst_stride_v,
    135                     width, height,
    136                     width, height);
    137 }
    138 
    139 // 411 chroma is 1/4 width, 1x height
    140 // 420 chroma is 1/2 width, 1/2 height
    141 LIBYUV_API
    142 int I411ToI420(const uint8* src_y, int src_stride_y,
    143                const uint8* src_u, int src_stride_u,
    144                const uint8* src_v, int src_stride_v,
    145                uint8* dst_y, int dst_stride_y,
    146                uint8* dst_u, int dst_stride_u,
    147                uint8* dst_v, int dst_stride_v,
    148                int width, int height) {
    149   const int src_uv_width = SUBSAMPLE(width, 3, 2);
    150   return I4xxToI420(src_y, src_stride_y,
    151                     src_u, src_stride_u,
    152                     src_v, src_stride_v,
    153                     dst_y, dst_stride_y,
    154                     dst_u, dst_stride_u,
    155                     dst_v, dst_stride_v,
    156                     width, height,
    157                     src_uv_width, height);
    158 }
    159 
    160 // I400 is greyscale typically used in MJPG
    161 LIBYUV_API
    162 int I400ToI420(const uint8* src_y, int src_stride_y,
    163                uint8* dst_y, int dst_stride_y,
    164                uint8* dst_u, int dst_stride_u,
    165                uint8* dst_v, int dst_stride_v,
    166                int width, int height) {
    167   if (!src_y || !dst_y || !dst_u || !dst_v ||
    168       width <= 0 || height == 0) {
    169     return -1;
    170   }
    171   // Negative height means invert the image.
    172   if (height < 0) {
    173     height = -height;
    174     src_y = src_y + (height - 1) * src_stride_y;
    175     src_stride_y = -src_stride_y;
    176   }
    177   int halfwidth = (width + 1) >> 1;
    178   int halfheight = (height + 1) >> 1;
    179   CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
    180   SetPlane(dst_u, dst_stride_u, halfwidth, halfheight, 128);
    181   SetPlane(dst_v, dst_stride_v, halfwidth, halfheight, 128);
    182   return 0;
    183 }
    184 
    185 static void CopyPlane2(const uint8* src, int src_stride_0, int src_stride_1,
    186                        uint8* dst, int dst_stride,
    187                        int width, int height) {
    188   void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
    189 #if defined(HAS_COPYROW_X86)
    190   if (TestCpuFlag(kCpuHasX86) && IS_ALIGNED(width, 4)) {
    191     CopyRow = CopyRow_X86;
    192   }
    193 #endif
    194 #if defined(HAS_COPYROW_SSE2)
    195   if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32) &&
    196       IS_ALIGNED(src, 16) &&
    197       IS_ALIGNED(src_stride_0, 16) && IS_ALIGNED(src_stride_1, 16) &&
    198       IS_ALIGNED(dst, 16) && IS_ALIGNED(dst_stride, 16)) {
    199     CopyRow = CopyRow_SSE2;
    200   }
    201 #endif
    202 #if defined(HAS_COPYROW_ERMS)
    203   if (TestCpuFlag(kCpuHasERMS)) {
    204     CopyRow = CopyRow_ERMS;
    205   }
    206 #endif
    207 #if defined(HAS_COPYROW_NEON)
    208   if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) {
    209     CopyRow = CopyRow_NEON;
    210   }
    211 #endif
    212 #if defined(HAS_COPYROW_MIPS)
    213   if (TestCpuFlag(kCpuHasMIPS)) {
    214     CopyRow = CopyRow_MIPS;
    215   }
    216 #endif
    217 
    218   // Copy plane
    219   for (int y = 0; y < height - 1; y += 2) {
    220     CopyRow(src, dst, width);
    221     CopyRow(src + src_stride_0, dst + dst_stride, width);
    222     src += src_stride_0 + src_stride_1;
    223     dst += dst_stride * 2;
    224   }
    225   if (height & 1) {
    226     CopyRow(src, dst, width);
    227   }
    228 }
    229 
    230 // Support converting from FOURCC_M420
    231 // Useful for bandwidth constrained transports like USB 1.0 and 2.0 and for
    232 // easy conversion to I420.
    233 // M420 format description:
    234 // M420 is row biplanar 420: 2 rows of Y and 1 row of UV.
    235 // Chroma is half width / half height. (420)
    236 // src_stride_m420 is row planar. Normally this will be the width in pixels.
    237 //   The UV plane is half width, but 2 values, so src_stride_m420 applies to
    238 //   this as well as the two Y planes.
    239 static int X420ToI420(const uint8* src_y,
    240                       int src_stride_y0, int src_stride_y1,
    241                       const uint8* src_uv, int src_stride_uv,
    242                       uint8* dst_y, int dst_stride_y,
    243                       uint8* dst_u, int dst_stride_u,
    244                       uint8* dst_v, int dst_stride_v,
    245                       int width, int height) {
    246   if (!src_y || !src_uv ||
    247       !dst_y || !dst_u || !dst_v ||
    248       width <= 0 || height == 0) {
    249     return -1;
    250   }
    251   // Negative height means invert the image.
    252   if (height < 0) {
    253     height = -height;
    254     int halfheight = (height + 1) >> 1;
    255     dst_y = dst_y + (height - 1) * dst_stride_y;
    256     dst_u = dst_u + (halfheight - 1) * dst_stride_u;
    257     dst_v = dst_v + (halfheight - 1) * dst_stride_v;
    258     dst_stride_y = -dst_stride_y;
    259     dst_stride_u = -dst_stride_u;
    260     dst_stride_v = -dst_stride_v;
    261   }
    262   // Coalesce rows.
    263   int halfwidth = (width + 1) >> 1;
    264   int halfheight = (height + 1) >> 1;
    265   if (src_stride_y0 == width &&
    266       src_stride_y1 == width &&
    267       dst_stride_y == width) {
    268     width *= height;
    269     height = 1;
    270     src_stride_y0 = src_stride_y1 = dst_stride_y = 0;
    271   }
    272   // Coalesce rows.
    273   if (src_stride_uv == halfwidth * 2 &&
    274       dst_stride_u == halfwidth &&
    275       dst_stride_v == halfwidth) {
    276     halfwidth *= halfheight;
    277     halfheight = 1;
    278     src_stride_uv = dst_stride_u = dst_stride_v = 0;
    279   }
    280   void (*SplitUVRow)(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix) =
    281       SplitUVRow_C;
    282 #if defined(HAS_SPLITUVROW_SSE2)
    283   if (TestCpuFlag(kCpuHasSSE2) && halfwidth >= 16) {
    284     SplitUVRow = SplitUVRow_Any_SSE2;
    285     if (IS_ALIGNED(halfwidth, 16)) {
    286       SplitUVRow = SplitUVRow_Unaligned_SSE2;
    287       if (IS_ALIGNED(src_uv, 16) && IS_ALIGNED(src_stride_uv, 16) &&
    288           IS_ALIGNED(dst_u, 16) && IS_ALIGNED(dst_stride_u, 16) &&
    289           IS_ALIGNED(dst_v, 16) && IS_ALIGNED(dst_stride_v, 16)) {
    290         SplitUVRow = SplitUVRow_SSE2;
    291       }
    292     }
    293   }
    294 #endif
    295 #if defined(HAS_SPLITUVROW_AVX2)
    296   if (TestCpuFlag(kCpuHasAVX2) && halfwidth >= 32) {
    297     SplitUVRow = SplitUVRow_Any_AVX2;
    298     if (IS_ALIGNED(halfwidth, 32)) {
    299       SplitUVRow = SplitUVRow_AVX2;
    300     }
    301   }
    302 #endif
    303 #if defined(HAS_SPLITUVROW_NEON)
    304   if (TestCpuFlag(kCpuHasNEON) && halfwidth >= 16) {
    305     SplitUVRow = SplitUVRow_Any_NEON;
    306     if (IS_ALIGNED(halfwidth, 16)) {
    307       SplitUVRow = SplitUVRow_NEON;
    308     }
    309   }
    310 #endif
    311 #if defined(HAS_SPLITUVROW_MIPS_DSPR2)
    312   if (TestCpuFlag(kCpuHasMIPS_DSPR2) && halfwidth >= 16) {
    313     SplitUVRow = SplitUVRow_Any_MIPS_DSPR2;
    314     if (IS_ALIGNED(halfwidth, 16)) {
    315       SplitUVRow = SplitUVRow_Unaligned_MIPS_DSPR2;
    316       if (IS_ALIGNED(src_uv, 4) && IS_ALIGNED(src_stride_uv, 4) &&
    317           IS_ALIGNED(dst_u, 4) && IS_ALIGNED(dst_stride_u, 4) &&
    318           IS_ALIGNED(dst_v, 4) && IS_ALIGNED(dst_stride_v, 4)) {
    319         SplitUVRow = SplitUVRow_MIPS_DSPR2;
    320       }
    321     }
    322   }
    323 #endif
    324 
    325   if (dst_y) {
    326     if (src_stride_y0 == src_stride_y1) {
    327       CopyPlane(src_y, src_stride_y0, dst_y, dst_stride_y, width, height);
    328     } else {
    329       CopyPlane2(src_y, src_stride_y0, src_stride_y1, dst_y, dst_stride_y,
    330                  width, height);
    331     }
    332   }
    333 
    334   for (int y = 0; y < halfheight; ++y) {
    335     // Copy a row of UV.
    336     SplitUVRow(src_uv, dst_u, dst_v, halfwidth);
    337     dst_u += dst_stride_u;
    338     dst_v += dst_stride_v;
    339     src_uv += src_stride_uv;
    340   }
    341   return 0;
    342 }
    343 
    344 // Convert NV12 to I420.
    345 LIBYUV_API
    346 int NV12ToI420(const uint8* src_y, int src_stride_y,
    347                const uint8* src_uv, int src_stride_uv,
    348                uint8* dst_y, int dst_stride_y,
    349                uint8* dst_u, int dst_stride_u,
    350                uint8* dst_v, int dst_stride_v,
    351                int width, int height) {
    352   return X420ToI420(src_y, src_stride_y, src_stride_y,
    353                     src_uv, src_stride_uv,
    354                     dst_y, dst_stride_y,
    355                     dst_u, dst_stride_u,
    356                     dst_v, dst_stride_v,
    357                     width, height);
    358 }
    359 
    360 // Convert NV21 to I420.  Same as NV12 but u and v pointers swapped.
    361 LIBYUV_API
    362 int NV21ToI420(const uint8* src_y, int src_stride_y,
    363                const uint8* src_vu, int src_stride_vu,
    364                uint8* dst_y, int dst_stride_y,
    365                uint8* dst_u, int dst_stride_u,
    366                uint8* dst_v, int dst_stride_v,
    367                int width, int height) {
    368   return X420ToI420(src_y, src_stride_y, src_stride_y,
    369                     src_vu, src_stride_vu,
    370                     dst_y, dst_stride_y,
    371                     dst_v, dst_stride_v,
    372                     dst_u, dst_stride_u,
    373                     width, height);
    374 }
    375 
    376 // Convert M420 to I420.
    377 LIBYUV_API
    378 int M420ToI420(const uint8* src_m420, int src_stride_m420,
    379                uint8* dst_y, int dst_stride_y,
    380                uint8* dst_u, int dst_stride_u,
    381                uint8* dst_v, int dst_stride_v,
    382                int width, int height) {
    383   return X420ToI420(src_m420, src_stride_m420, src_stride_m420 * 2,
    384                     src_m420 + src_stride_m420 * 2, src_stride_m420 * 3,
    385                     dst_y, dst_stride_y,
    386                     dst_u, dst_stride_u,
    387                     dst_v, dst_stride_v,
    388                     width, height);
    389 }
    390 
    391 // Convert Q420 to I420.
    392 // Format is rows of YY/YUYV
    393 LIBYUV_API
    394 int Q420ToI420(const uint8* src_y, int src_stride_y,
    395                const uint8* src_yuy2, int src_stride_yuy2,
    396                uint8* dst_y, int dst_stride_y,
    397                uint8* dst_u, int dst_stride_u,
    398                uint8* dst_v, int dst_stride_v,
    399                int width, int height) {
    400   if (!src_y || !src_yuy2 ||
    401       !dst_y || !dst_u || !dst_v ||
    402       width <= 0 || height == 0) {
    403     return -1;
    404   }
    405   // Negative height means invert the image.
    406   if (height < 0) {
    407     height = -height;
    408     int halfheight = (height + 1) >> 1;
    409     dst_y = dst_y + (height - 1) * dst_stride_y;
    410     dst_u = dst_u + (halfheight - 1) * dst_stride_u;
    411     dst_v = dst_v + (halfheight - 1) * dst_stride_v;
    412     dst_stride_y = -dst_stride_y;
    413     dst_stride_u = -dst_stride_u;
    414     dst_stride_v = -dst_stride_v;
    415   }
    416   // CopyRow for rows of just Y in Q420 copied to Y plane of I420.
    417   void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
    418 #if defined(HAS_COPYROW_NEON)
    419   if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) {
    420     CopyRow = CopyRow_NEON;
    421   }
    422 #endif
    423 #if defined(HAS_COPYROW_X86)
    424   if (IS_ALIGNED(width, 4)) {
    425     CopyRow = CopyRow_X86;
    426   }
    427 #endif
    428 #if defined(HAS_COPYROW_SSE2)
    429   if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32) &&
    430       IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
    431       IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
    432     CopyRow = CopyRow_SSE2;
    433   }
    434 #endif
    435 #if defined(HAS_COPYROW_ERMS)
    436   if (TestCpuFlag(kCpuHasERMS)) {
    437     CopyRow = CopyRow_ERMS;
    438   }
    439 #endif
    440 #if defined(HAS_COPYROW_MIPS)
    441   if (TestCpuFlag(kCpuHasMIPS)) {
    442     CopyRow = CopyRow_MIPS;
    443   }
    444 #endif
    445 
    446   void (*YUY2ToUV422Row)(const uint8* src_yuy2, uint8* dst_u, uint8* dst_v,
    447       int pix) = YUY2ToUV422Row_C;
    448   void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int pix) =
    449       YUY2ToYRow_C;
    450 #if defined(HAS_YUY2TOYROW_SSE2)
    451   if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
    452     YUY2ToUV422Row = YUY2ToUV422Row_Any_SSE2;
    453     YUY2ToYRow = YUY2ToYRow_Any_SSE2;
    454     if (IS_ALIGNED(width, 16)) {
    455       YUY2ToUV422Row = YUY2ToUV422Row_Unaligned_SSE2;
    456       YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2;
    457       if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) {
    458         YUY2ToUV422Row = YUY2ToUV422Row_SSE2;
    459         if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
    460           YUY2ToYRow = YUY2ToYRow_SSE2;
    461         }
    462       }
    463     }
    464   }
    465 #endif
    466 #if defined(HAS_YUY2TOYROW_AVX2)
    467   if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
    468     YUY2ToUV422Row = YUY2ToUV422Row_Any_AVX2;
    469     YUY2ToYRow = YUY2ToYRow_Any_AVX2;
    470     if (IS_ALIGNED(width, 32)) {
    471       YUY2ToUV422Row = YUY2ToUV422Row_AVX2;
    472       YUY2ToYRow = YUY2ToYRow_AVX2;
    473     }
    474   }
    475 #endif
    476 #if defined(HAS_YUY2TOYROW_NEON)
    477   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
    478     YUY2ToYRow = YUY2ToYRow_Any_NEON;
    479     if (width >= 16) {
    480       YUY2ToUV422Row = YUY2ToUV422Row_Any_NEON;
    481     }
    482     if (IS_ALIGNED(width, 16)) {
    483       YUY2ToYRow = YUY2ToYRow_NEON;
    484       YUY2ToUV422Row = YUY2ToUV422Row_NEON;
    485     }
    486   }
    487 #endif
    488 
    489   for (int y = 0; y < height - 1; y += 2) {
    490     CopyRow(src_y, dst_y, width);
    491     src_y += src_stride_y;
    492     dst_y += dst_stride_y;
    493 
    494     YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width);
    495     YUY2ToYRow(src_yuy2, dst_y, width);
    496     src_yuy2 += src_stride_yuy2;
    497     dst_y += dst_stride_y;
    498     dst_u += dst_stride_u;
    499     dst_v += dst_stride_v;
    500   }
    501   if (height & 1) {
    502     CopyRow(src_y, dst_y, width);
    503     YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width);
    504   }
    505   return 0;
    506 }
    507 
    508 // Convert YUY2 to I420.
    509 LIBYUV_API
    510 int YUY2ToI420(const uint8* src_yuy2, int src_stride_yuy2,
    511                uint8* dst_y, int dst_stride_y,
    512                uint8* dst_u, int dst_stride_u,
    513                uint8* dst_v, int dst_stride_v,
    514                int width, int height) {
    515   // Negative height means invert the image.
    516   if (height < 0) {
    517     height = -height;
    518     src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
    519     src_stride_yuy2 = -src_stride_yuy2;
    520   }
    521   void (*YUY2ToUVRow)(const uint8* src_yuy2, int src_stride_yuy2,
    522                       uint8* dst_u, uint8* dst_v, int pix);
    523   void (*YUY2ToYRow)(const uint8* src_yuy2,
    524                      uint8* dst_y, int pix);
    525   YUY2ToYRow = YUY2ToYRow_C;
    526   YUY2ToUVRow = YUY2ToUVRow_C;
    527 #if defined(HAS_YUY2TOYROW_SSE2)
    528   if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
    529     YUY2ToUVRow = YUY2ToUVRow_Any_SSE2;
    530     YUY2ToYRow = YUY2ToYRow_Any_SSE2;
    531     if (IS_ALIGNED(width, 16)) {
    532       YUY2ToUVRow = YUY2ToUVRow_Unaligned_SSE2;
    533       YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2;
    534       if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) {
    535         YUY2ToUVRow = YUY2ToUVRow_SSE2;
    536         if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
    537           YUY2ToYRow = YUY2ToYRow_SSE2;
    538         }
    539       }
    540     }
    541   }
    542 #endif
    543 #if defined(HAS_YUY2TOYROW_AVX2)
    544   if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
    545     YUY2ToUVRow = YUY2ToUVRow_Any_AVX2;
    546     YUY2ToYRow = YUY2ToYRow_Any_AVX2;
    547     if (IS_ALIGNED(width, 32)) {
    548       YUY2ToUVRow = YUY2ToUVRow_AVX2;
    549       YUY2ToYRow = YUY2ToYRow_AVX2;
    550     }
    551   }
    552 #endif
    553 #if defined(HAS_YUY2TOYROW_NEON)
    554   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
    555     YUY2ToYRow = YUY2ToYRow_Any_NEON;
    556     if (width >= 16) {
    557       YUY2ToUVRow = YUY2ToUVRow_Any_NEON;
    558     }
    559     if (IS_ALIGNED(width, 16)) {
    560       YUY2ToYRow = YUY2ToYRow_NEON;
    561       YUY2ToUVRow = YUY2ToUVRow_NEON;
    562     }
    563   }
    564 #endif
    565 
    566   for (int y = 0; y < height - 1; y += 2) {
    567     YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width);
    568     YUY2ToYRow(src_yuy2, dst_y, width);
    569     YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width);
    570     src_yuy2 += src_stride_yuy2 * 2;
    571     dst_y += dst_stride_y * 2;
    572     dst_u += dst_stride_u;
    573     dst_v += dst_stride_v;
    574   }
    575   if (height & 1) {
    576     YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width);
    577     YUY2ToYRow(src_yuy2, dst_y, width);
    578   }
    579   return 0;
    580 }
    581 
    582 // Convert UYVY to I420.
    583 LIBYUV_API
    584 int UYVYToI420(const uint8* src_uyvy, int src_stride_uyvy,
    585                uint8* dst_y, int dst_stride_y,
    586                uint8* dst_u, int dst_stride_u,
    587                uint8* dst_v, int dst_stride_v,
    588                int width, int height) {
    589   // Negative height means invert the image.
    590   if (height < 0) {
    591     height = -height;
    592     src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
    593     src_stride_uyvy = -src_stride_uyvy;
    594   }
    595   void (*UYVYToUVRow)(const uint8* src_uyvy, int src_stride_uyvy,
    596                       uint8* dst_u, uint8* dst_v, int pix);
    597   void (*UYVYToYRow)(const uint8* src_uyvy,
    598                      uint8* dst_y, int pix);
    599   UYVYToYRow = UYVYToYRow_C;
    600   UYVYToUVRow = UYVYToUVRow_C;
    601 #if defined(HAS_UYVYTOYROW_SSE2)
    602   if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
    603     UYVYToUVRow = UYVYToUVRow_Any_SSE2;
    604     UYVYToYRow = UYVYToYRow_Any_SSE2;
    605     if (IS_ALIGNED(width, 16)) {
    606       UYVYToUVRow = UYVYToUVRow_Unaligned_SSE2;
    607       UYVYToYRow = UYVYToYRow_Unaligned_SSE2;
    608       if (IS_ALIGNED(src_uyvy, 16) && IS_ALIGNED(src_stride_uyvy, 16)) {
    609         UYVYToUVRow = UYVYToUVRow_SSE2;
    610         if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
    611           UYVYToYRow = UYVYToYRow_SSE2;
    612         }
    613       }
    614     }
    615   }
    616 #endif
    617 #if defined(HAS_UYVYTOYROW_AVX2)
    618   if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
    619     UYVYToUVRow = UYVYToUVRow_Any_AVX2;
    620     UYVYToYRow = UYVYToYRow_Any_AVX2;
    621     if (IS_ALIGNED(width, 32)) {
    622       UYVYToUVRow = UYVYToUVRow_AVX2;
    623       UYVYToYRow = UYVYToYRow_AVX2;
    624     }
    625   }
    626 #endif
    627 #if defined(HAS_UYVYTOYROW_NEON)
    628   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
    629     UYVYToYRow = UYVYToYRow_Any_NEON;
    630     if (width >= 16) {
    631       UYVYToUVRow = UYVYToUVRow_Any_NEON;
    632     }
    633     if (IS_ALIGNED(width, 16)) {
    634       UYVYToYRow = UYVYToYRow_NEON;
    635       UYVYToUVRow = UYVYToUVRow_NEON;
    636     }
    637   }
    638 #endif
    639 
    640   for (int y = 0; y < height - 1; y += 2) {
    641     UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width);
    642     UYVYToYRow(src_uyvy, dst_y, width);
    643     UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width);
    644     src_uyvy += src_stride_uyvy * 2;
    645     dst_y += dst_stride_y * 2;
    646     dst_u += dst_stride_u;
    647     dst_v += dst_stride_v;
    648   }
    649   if (height & 1) {
    650     UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width);
    651     UYVYToYRow(src_uyvy, dst_y, width);
    652   }
    653   return 0;
    654 }
    655 
    656 // Convert ARGB to I420.
    657 LIBYUV_API
    658 int ARGBToI420(const uint8* src_argb, int src_stride_argb,
    659                uint8* dst_y, int dst_stride_y,
    660                uint8* dst_u, int dst_stride_u,
    661                uint8* dst_v, int dst_stride_v,
    662                int width, int height) {
    663   if (!src_argb ||
    664       !dst_y || !dst_u || !dst_v ||
    665       width <= 0 || height == 0) {
    666     return -1;
    667   }
    668   // Negative height means invert the image.
    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   void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
    675                       uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
    676   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
    677       ARGBToYRow_C;
    678 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
    679   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
    680     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
    681     ARGBToYRow = ARGBToYRow_Any_SSSE3;
    682     if (IS_ALIGNED(width, 16)) {
    683       ARGBToUVRow = ARGBToUVRow_Unaligned_SSSE3;
    684       ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
    685       if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
    686         ARGBToUVRow = ARGBToUVRow_SSSE3;
    687         if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
    688           ARGBToYRow = ARGBToYRow_SSSE3;
    689         }
    690       }
    691     }
    692   }
    693 #endif
    694 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
    695   if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
    696     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
    697     ARGBToYRow = ARGBToYRow_Any_AVX2;
    698     if (IS_ALIGNED(width, 32)) {
    699       ARGBToUVRow = ARGBToUVRow_AVX2;
    700       ARGBToYRow = ARGBToYRow_AVX2;
    701     }
    702   }
    703 #endif
    704 #if defined(HAS_ARGBTOYROW_NEON)
    705   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
    706     ARGBToYRow = ARGBToYRow_Any_NEON;
    707     if (IS_ALIGNED(width, 8)) {
    708       ARGBToYRow = ARGBToYRow_NEON;
    709     }
    710     if (width >= 16) {
    711       ARGBToUVRow = ARGBToUVRow_Any_NEON;
    712       if (IS_ALIGNED(width, 16)) {
    713         ARGBToUVRow = ARGBToUVRow_NEON;
    714       }
    715     }
    716   }
    717 #endif
    718 
    719   for (int y = 0; y < height - 1; y += 2) {
    720     ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width);
    721     ARGBToYRow(src_argb, dst_y, width);
    722     ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
    723     src_argb += src_stride_argb * 2;
    724     dst_y += dst_stride_y * 2;
    725     dst_u += dst_stride_u;
    726     dst_v += dst_stride_v;
    727   }
    728   if (height & 1) {
    729     ARGBToUVRow(src_argb, 0, dst_u, dst_v, width);
    730     ARGBToYRow(src_argb, dst_y, width);
    731   }
    732   return 0;
    733 }
    734 
    735 // Convert BGRA to I420.
    736 LIBYUV_API
    737 int BGRAToI420(const uint8* src_bgra, int src_stride_bgra,
    738                uint8* dst_y, int dst_stride_y,
    739                uint8* dst_u, int dst_stride_u,
    740                uint8* dst_v, int dst_stride_v,
    741                int width, int height) {
    742   if (!src_bgra ||
    743       !dst_y || !dst_u || !dst_v ||
    744       width <= 0 || height == 0) {
    745     return -1;
    746   }
    747   // Negative height means invert the image.
    748   if (height < 0) {
    749     height = -height;
    750     src_bgra = src_bgra + (height - 1) * src_stride_bgra;
    751     src_stride_bgra = -src_stride_bgra;
    752   }
    753   void (*BGRAToUVRow)(const uint8* src_bgra0, int src_stride_bgra,
    754                       uint8* dst_u, uint8* dst_v, int width) = BGRAToUVRow_C;
    755   void (*BGRAToYRow)(const uint8* src_bgra, uint8* dst_y, int pix) =
    756       BGRAToYRow_C;
    757 #if defined(HAS_BGRATOYROW_SSSE3)
    758   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
    759     BGRAToUVRow = BGRAToUVRow_Any_SSSE3;
    760     BGRAToYRow = BGRAToYRow_Any_SSSE3;
    761     if (IS_ALIGNED(width, 16)) {
    762       BGRAToUVRow = BGRAToUVRow_Unaligned_SSSE3;
    763       BGRAToYRow = BGRAToYRow_Unaligned_SSSE3;
    764       if (IS_ALIGNED(src_bgra, 16) && IS_ALIGNED(src_stride_bgra, 16)) {
    765         BGRAToUVRow = BGRAToUVRow_SSSE3;
    766         if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
    767           BGRAToYRow = BGRAToYRow_SSSE3;
    768         }
    769       }
    770     }
    771   }
    772 #elif defined(HAS_BGRATOYROW_NEON)
    773   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
    774     BGRAToYRow = BGRAToYRow_Any_NEON;
    775     if (IS_ALIGNED(width, 8)) {
    776       BGRAToYRow = BGRAToYRow_NEON;
    777     }
    778     if (width >= 16) {
    779       BGRAToUVRow = BGRAToUVRow_Any_NEON;
    780       if (IS_ALIGNED(width, 16)) {
    781         BGRAToUVRow = BGRAToUVRow_NEON;
    782       }
    783     }
    784   }
    785 #endif
    786 
    787   for (int y = 0; y < height - 1; y += 2) {
    788     BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width);
    789     BGRAToYRow(src_bgra, dst_y, width);
    790     BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width);
    791     src_bgra += src_stride_bgra * 2;
    792     dst_y += dst_stride_y * 2;
    793     dst_u += dst_stride_u;
    794     dst_v += dst_stride_v;
    795   }
    796   if (height & 1) {
    797     BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width);
    798     BGRAToYRow(src_bgra, dst_y, width);
    799   }
    800   return 0;
    801 }
    802 
    803 // Convert ABGR to I420.
    804 LIBYUV_API
    805 int ABGRToI420(const uint8* src_abgr, int src_stride_abgr,
    806                uint8* dst_y, int dst_stride_y,
    807                uint8* dst_u, int dst_stride_u,
    808                uint8* dst_v, int dst_stride_v,
    809                int width, int height) {
    810   if (!src_abgr ||
    811       !dst_y || !dst_u || !dst_v ||
    812       width <= 0 || height == 0) {
    813     return -1;
    814   }
    815   // Negative height means invert the image.
    816   if (height < 0) {
    817     height = -height;
    818     src_abgr = src_abgr + (height - 1) * src_stride_abgr;
    819     src_stride_abgr = -src_stride_abgr;
    820   }
    821   void (*ABGRToUVRow)(const uint8* src_abgr0, int src_stride_abgr,
    822                       uint8* dst_u, uint8* dst_v, int width) = ABGRToUVRow_C;
    823   void (*ABGRToYRow)(const uint8* src_abgr, uint8* dst_y, int pix) =
    824       ABGRToYRow_C;
    825 #if defined(HAS_ABGRTOYROW_SSSE3)
    826   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
    827     ABGRToUVRow = ABGRToUVRow_Any_SSSE3;
    828     ABGRToYRow = ABGRToYRow_Any_SSSE3;
    829     if (IS_ALIGNED(width, 16)) {
    830       ABGRToUVRow = ABGRToUVRow_Unaligned_SSSE3;
    831       ABGRToYRow = ABGRToYRow_Unaligned_SSSE3;
    832       if (IS_ALIGNED(src_abgr, 16) && IS_ALIGNED(src_stride_abgr, 16)) {
    833         ABGRToUVRow = ABGRToUVRow_SSSE3;
    834         if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
    835           ABGRToYRow = ABGRToYRow_SSSE3;
    836         }
    837       }
    838     }
    839   }
    840 #elif defined(HAS_ABGRTOYROW_NEON)
    841   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
    842     ABGRToYRow = ABGRToYRow_Any_NEON;
    843     if (IS_ALIGNED(width, 8)) {
    844       ABGRToYRow = ABGRToYRow_NEON;
    845     }
    846     if (width >= 16) {
    847       ABGRToUVRow = ABGRToUVRow_Any_NEON;
    848       if (IS_ALIGNED(width, 16)) {
    849         ABGRToUVRow = ABGRToUVRow_NEON;
    850       }
    851     }
    852   }
    853 #endif
    854 
    855   for (int y = 0; y < height - 1; y += 2) {
    856     ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width);
    857     ABGRToYRow(src_abgr, dst_y, width);
    858     ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width);
    859     src_abgr += src_stride_abgr * 2;
    860     dst_y += dst_stride_y * 2;
    861     dst_u += dst_stride_u;
    862     dst_v += dst_stride_v;
    863   }
    864   if (height & 1) {
    865     ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width);
    866     ABGRToYRow(src_abgr, dst_y, width);
    867   }
    868   return 0;
    869 }
    870 
    871 // Convert RGBA to I420.
    872 LIBYUV_API
    873 int RGBAToI420(const uint8* src_rgba, int src_stride_rgba,
    874                uint8* dst_y, int dst_stride_y,
    875                uint8* dst_u, int dst_stride_u,
    876                uint8* dst_v, int dst_stride_v,
    877                int width, int height) {
    878   if (!src_rgba ||
    879       !dst_y || !dst_u || !dst_v ||
    880       width <= 0 || height == 0) {
    881     return -1;
    882   }
    883   // Negative height means invert the image.
    884   if (height < 0) {
    885     height = -height;
    886     src_rgba = src_rgba + (height - 1) * src_stride_rgba;
    887     src_stride_rgba = -src_stride_rgba;
    888   }
    889   void (*RGBAToUVRow)(const uint8* src_rgba0, int src_stride_rgba,
    890                       uint8* dst_u, uint8* dst_v, int width) = RGBAToUVRow_C;
    891   void (*RGBAToYRow)(const uint8* src_rgba, uint8* dst_y, int pix) =
    892       RGBAToYRow_C;
    893 #if defined(HAS_RGBATOYROW_SSSE3)
    894   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
    895     RGBAToUVRow = RGBAToUVRow_Any_SSSE3;
    896     RGBAToYRow = RGBAToYRow_Any_SSSE3;
    897     if (IS_ALIGNED(width, 16)) {
    898       RGBAToUVRow = RGBAToUVRow_Unaligned_SSSE3;
    899       RGBAToYRow = RGBAToYRow_Unaligned_SSSE3;
    900       if (IS_ALIGNED(src_rgba, 16) && IS_ALIGNED(src_stride_rgba, 16)) {
    901         RGBAToUVRow = RGBAToUVRow_SSSE3;
    902         if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
    903           RGBAToYRow = RGBAToYRow_SSSE3;
    904         }
    905       }
    906     }
    907   }
    908 #elif defined(HAS_RGBATOYROW_NEON)
    909   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
    910     RGBAToYRow = RGBAToYRow_Any_NEON;
    911     if (IS_ALIGNED(width, 8)) {
    912       RGBAToYRow = RGBAToYRow_NEON;
    913     }
    914     if (width >= 16) {
    915       RGBAToUVRow = RGBAToUVRow_Any_NEON;
    916       if (IS_ALIGNED(width, 16)) {
    917         RGBAToUVRow = RGBAToUVRow_NEON;
    918       }
    919     }
    920   }
    921 #endif
    922 
    923   for (int y = 0; y < height - 1; y += 2) {
    924     RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width);
    925     RGBAToYRow(src_rgba, dst_y, width);
    926     RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width);
    927     src_rgba += src_stride_rgba * 2;
    928     dst_y += dst_stride_y * 2;
    929     dst_u += dst_stride_u;
    930     dst_v += dst_stride_v;
    931   }
    932   if (height & 1) {
    933     RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width);
    934     RGBAToYRow(src_rgba, dst_y, width);
    935   }
    936   return 0;
    937 }
    938 
    939 // Convert RGB24 to I420.
    940 LIBYUV_API
    941 int RGB24ToI420(const uint8* src_rgb24, int src_stride_rgb24,
    942                 uint8* dst_y, int dst_stride_y,
    943                 uint8* dst_u, int dst_stride_u,
    944                 uint8* dst_v, int dst_stride_v,
    945                 int width, int height) {
    946   if (!src_rgb24 || !dst_y || !dst_u || !dst_v ||
    947       width <= 0 || height == 0) {
    948     return -1;
    949   }
    950   // Negative height means invert the image.
    951   if (height < 0) {
    952     height = -height;
    953     src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
    954     src_stride_rgb24 = -src_stride_rgb24;
    955   }
    956 
    957 #if defined(HAS_RGB24TOYROW_NEON)
    958   void (*RGB24ToUVRow)(const uint8* src_rgb24, int src_stride_rgb24,
    959       uint8* dst_u, uint8* dst_v, int width) = RGB24ToUVRow_C;
    960   void (*RGB24ToYRow)(const uint8* src_rgb24, uint8* dst_y, int pix) =
    961       RGB24ToYRow_C;
    962   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
    963     RGB24ToYRow = RGB24ToYRow_Any_NEON;
    964     if (IS_ALIGNED(width, 8)) {
    965       RGB24ToYRow = RGB24ToYRow_NEON;
    966     }
    967     if (width >= 16) {
    968       RGB24ToUVRow = RGB24ToUVRow_Any_NEON;
    969       if (IS_ALIGNED(width, 16)) {
    970         RGB24ToUVRow = RGB24ToUVRow_NEON;
    971       }
    972     }
    973   }
    974 #else  // HAS_RGB24TOYROW_NEON
    975 
    976   // Allocate 2 rows of ARGB.
    977   const int kRowSize = (width * 4 + 15) & ~15;
    978   align_buffer_64(row, kRowSize * 2);
    979 
    980   void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
    981       RGB24ToARGBRow_C;
    982 #if defined(HAS_RGB24TOARGBROW_SSSE3)
    983   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
    984     RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
    985     if (IS_ALIGNED(width, 16)) {
    986       RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
    987     }
    988   }
    989 #endif
    990   void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
    991                       uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
    992 #if defined(HAS_ARGBTOUVROW_SSSE3)
    993   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
    994     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
    995     if (IS_ALIGNED(width, 16)) {
    996       ARGBToUVRow = ARGBToUVRow_SSSE3;
    997     }
    998   }
    999 #endif
   1000   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
   1001       ARGBToYRow_C;
   1002 #if defined(HAS_ARGBTOUVROW_SSSE3)
   1003   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
   1004     ARGBToYRow = ARGBToYRow_Any_SSSE3;
   1005     if (IS_ALIGNED(width, 16)) {
   1006       ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
   1007       if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
   1008         ARGBToYRow = ARGBToYRow_SSSE3;
   1009       }
   1010     }
   1011   }
   1012 #endif  // HAS_ARGBTOUVROW_SSSE3
   1013 #endif  // HAS_RGB24TOYROW_NEON
   1014 
   1015   for (int y = 0; y < height - 1; y += 2) {
   1016 #if defined(HAS_RGB24TOYROW_NEON)
   1017     RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
   1018     RGB24ToYRow(src_rgb24, dst_y, width);
   1019     RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
   1020 #else
   1021     RGB24ToARGBRow(src_rgb24, row, width);
   1022     RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width);
   1023     ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
   1024     ARGBToYRow(row, dst_y, width);
   1025     ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
   1026 #endif
   1027     src_rgb24 += src_stride_rgb24 * 2;
   1028     dst_y += dst_stride_y * 2;
   1029     dst_u += dst_stride_u;
   1030     dst_v += dst_stride_v;
   1031   }
   1032   if (height & 1) {
   1033 #if defined(HAS_RGB24TOYROW_NEON)
   1034     RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width);
   1035     RGB24ToYRow(src_rgb24, dst_y, width);
   1036 #else
   1037     RGB24ToARGBRow(src_rgb24, row, width);
   1038     ARGBToUVRow(row, 0, dst_u, dst_v, width);
   1039     ARGBToYRow(row, dst_y, width);
   1040 #endif
   1041   }
   1042 #if !defined(HAS_RGB24TOYROW_NEON)
   1043   free_aligned_buffer_64(row);
   1044 #endif
   1045   return 0;
   1046 }
   1047 
   1048 // Convert RAW to I420.
   1049 LIBYUV_API
   1050 int RAWToI420(const uint8* src_raw, int src_stride_raw,
   1051               uint8* dst_y, int dst_stride_y,
   1052               uint8* dst_u, int dst_stride_u,
   1053               uint8* dst_v, int dst_stride_v,
   1054               int width, int height) {
   1055   if (!src_raw || !dst_y || !dst_u || !dst_v ||
   1056       width <= 0 || height == 0) {
   1057     return -1;
   1058   }
   1059   // Negative height means invert the image.
   1060   if (height < 0) {
   1061     height = -height;
   1062     src_raw = src_raw + (height - 1) * src_stride_raw;
   1063     src_stride_raw = -src_stride_raw;
   1064   }
   1065 
   1066 #if defined(HAS_RAWTOYROW_NEON)
   1067   void (*RAWToUVRow)(const uint8* src_raw, int src_stride_raw,
   1068       uint8* dst_u, uint8* dst_v, int width) = RAWToUVRow_C;
   1069   void (*RAWToYRow)(const uint8* src_raw, uint8* dst_y, int pix) =
   1070       RAWToYRow_C;
   1071   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
   1072     RAWToYRow = RAWToYRow_Any_NEON;
   1073     if (IS_ALIGNED(width, 8)) {
   1074       RAWToYRow = RAWToYRow_NEON;
   1075     }
   1076     if (width >= 16) {
   1077       RAWToUVRow = RAWToUVRow_Any_NEON;
   1078       if (IS_ALIGNED(width, 16)) {
   1079         RAWToUVRow = RAWToUVRow_NEON;
   1080       }
   1081     }
   1082   }
   1083 #else  // HAS_RAWTOYROW_NEON
   1084 
   1085   // Allocate 2 rows of ARGB.
   1086   const int kRowSize = (width * 4 + 15) & ~15;
   1087   align_buffer_64(row, kRowSize * 2);
   1088 
   1089   void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
   1090       RAWToARGBRow_C;
   1091 #if defined(HAS_RAWTOARGBROW_SSSE3)
   1092   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
   1093     RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
   1094     if (IS_ALIGNED(width, 16)) {
   1095       RAWToARGBRow = RAWToARGBRow_SSSE3;
   1096     }
   1097   }
   1098 #endif
   1099   void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
   1100                       uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
   1101 #if defined(HAS_ARGBTOUVROW_SSSE3)
   1102   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
   1103     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
   1104     if (IS_ALIGNED(width, 16)) {
   1105       ARGBToUVRow = ARGBToUVRow_SSSE3;
   1106     }
   1107   }
   1108 #endif
   1109   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
   1110       ARGBToYRow_C;
   1111 #if defined(HAS_ARGBTOUVROW_SSSE3)
   1112   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
   1113     ARGBToYRow = ARGBToYRow_Any_SSSE3;
   1114     if (IS_ALIGNED(width, 16)) {
   1115       ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
   1116       if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
   1117         ARGBToYRow = ARGBToYRow_SSSE3;
   1118       }
   1119     }
   1120   }
   1121 #endif  // HAS_ARGBTOUVROW_SSSE3
   1122 #endif  // HAS_RAWTOYROW_NEON
   1123 
   1124   for (int y = 0; y < height - 1; y += 2) {
   1125 #if defined(HAS_RAWTOYROW_NEON)
   1126     RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width);
   1127     RAWToYRow(src_raw, dst_y, width);
   1128     RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width);
   1129 #else
   1130     RAWToARGBRow(src_raw, row, width);
   1131     RAWToARGBRow(src_raw + src_stride_raw, row + kRowSize, width);
   1132     ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
   1133     ARGBToYRow(row, dst_y, width);
   1134     ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
   1135 #endif
   1136     src_raw += src_stride_raw * 2;
   1137     dst_y += dst_stride_y * 2;
   1138     dst_u += dst_stride_u;
   1139     dst_v += dst_stride_v;
   1140   }
   1141   if (height & 1) {
   1142 #if defined(HAS_RAWTOYROW_NEON)
   1143     RAWToUVRow(src_raw, 0, dst_u, dst_v, width);
   1144     RAWToYRow(src_raw, dst_y, width);
   1145 #else
   1146     RAWToARGBRow(src_raw, row, width);
   1147     ARGBToUVRow(row, 0, dst_u, dst_v, width);
   1148     ARGBToYRow(row, dst_y, width);
   1149 #endif
   1150   }
   1151 #if !defined(HAS_RAWTOYROW_NEON)
   1152   free_aligned_buffer_64(row);
   1153 #endif
   1154   return 0;
   1155 }
   1156 
   1157 // Convert RGB565 to I420.
   1158 LIBYUV_API
   1159 int RGB565ToI420(const uint8* src_rgb565, int src_stride_rgb565,
   1160                 uint8* dst_y, int dst_stride_y,
   1161                 uint8* dst_u, int dst_stride_u,
   1162                 uint8* dst_v, int dst_stride_v,
   1163                 int width, int height) {
   1164   if (!src_rgb565 || !dst_y || !dst_u || !dst_v ||
   1165       width <= 0 || height == 0) {
   1166     return -1;
   1167   }
   1168   // Negative height means invert the image.
   1169   if (height < 0) {
   1170     height = -height;
   1171     src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
   1172     src_stride_rgb565 = -src_stride_rgb565;
   1173   }
   1174 
   1175 #if defined(HAS_RGB565TOYROW_NEON)
   1176   void (*RGB565ToUVRow)(const uint8* src_rgb565, int src_stride_rgb565,
   1177       uint8* dst_u, uint8* dst_v, int width) = RGB565ToUVRow_C;
   1178   void (*RGB565ToYRow)(const uint8* src_rgb565, uint8* dst_y, int pix) =
   1179       RGB565ToYRow_C;
   1180   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
   1181     RGB565ToYRow = RGB565ToYRow_Any_NEON;
   1182     if (IS_ALIGNED(width, 8)) {
   1183       RGB565ToYRow = RGB565ToYRow_NEON;
   1184     }
   1185     if (width >= 16) {
   1186       RGB565ToUVRow = RGB565ToUVRow_Any_NEON;
   1187       if (IS_ALIGNED(width, 16)) {
   1188         RGB565ToUVRow = RGB565ToUVRow_NEON;
   1189       }
   1190     }
   1191   }
   1192 #else  // HAS_RGB565TOYROW_NEON
   1193 
   1194   // Allocate 2 rows of ARGB.
   1195   const int kRowSize = (width * 4 + 15) & ~15;
   1196   align_buffer_64(row, kRowSize * 2);
   1197 
   1198   void (*RGB565ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
   1199       RGB565ToARGBRow_C;
   1200 #if defined(HAS_RGB565TOARGBROW_SSE2)
   1201   if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
   1202     RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
   1203     if (IS_ALIGNED(width, 8)) {
   1204       RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
   1205     }
   1206   }
   1207 #endif
   1208   void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
   1209                       uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
   1210 #if defined(HAS_ARGBTOUVROW_SSSE3)
   1211   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
   1212     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
   1213     if (IS_ALIGNED(width, 16)) {
   1214       ARGBToUVRow = ARGBToUVRow_SSSE3;
   1215     }
   1216   }
   1217 #endif
   1218   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
   1219       ARGBToYRow_C;
   1220 #if defined(HAS_ARGBTOUVROW_SSSE3)
   1221   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
   1222     ARGBToYRow = ARGBToYRow_Any_SSSE3;
   1223     if (IS_ALIGNED(width, 16)) {
   1224       ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
   1225       if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
   1226         ARGBToYRow = ARGBToYRow_SSSE3;
   1227       }
   1228     }
   1229   }
   1230 #endif  // HAS_ARGBTOUVROW_SSSE3
   1231 #endif  // HAS_RGB565TOYROW_NEON
   1232 
   1233   for (int y = 0; y < height - 1; y += 2) {
   1234 #if defined(HAS_RGB565TOYROW_NEON)
   1235     RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width);
   1236     RGB565ToYRow(src_rgb565, dst_y, width);
   1237     RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width);
   1238 #else
   1239     RGB565ToARGBRow(src_rgb565, row, width);
   1240     RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kRowSize, width);
   1241     ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
   1242     ARGBToYRow(row, dst_y, width);
   1243     ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
   1244 #endif
   1245     src_rgb565 += src_stride_rgb565 * 2;
   1246     dst_y += dst_stride_y * 2;
   1247     dst_u += dst_stride_u;
   1248     dst_v += dst_stride_v;
   1249   }
   1250   if (height & 1) {
   1251 #if defined(HAS_RGB565TOYROW_NEON)
   1252     RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width);
   1253     RGB565ToYRow(src_rgb565, dst_y, width);
   1254 #else
   1255     RGB565ToARGBRow(src_rgb565, row, width);
   1256     ARGBToUVRow(row, 0, dst_u, dst_v, width);
   1257     ARGBToYRow(row, dst_y, width);
   1258 #endif
   1259   }
   1260 #if !defined(HAS_RGB565TOYROW_NEON)
   1261   free_aligned_buffer_64(row);
   1262 #endif
   1263   return 0;
   1264 }
   1265 
   1266 // Convert ARGB1555 to I420.
   1267 LIBYUV_API
   1268 int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555,
   1269                    uint8* dst_y, int dst_stride_y,
   1270                    uint8* dst_u, int dst_stride_u,
   1271                    uint8* dst_v, int dst_stride_v,
   1272                    int width, int height) {
   1273   if (!src_argb1555 || !dst_y || !dst_u || !dst_v ||
   1274       width <= 0 || height == 0) {
   1275     return -1;
   1276   }
   1277   // Negative height means invert the image.
   1278   if (height < 0) {
   1279     height = -height;
   1280     src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
   1281     src_stride_argb1555 = -src_stride_argb1555;
   1282   }
   1283 
   1284 #if defined(HAS_ARGB1555TOYROW_NEON)
   1285   void (*ARGB1555ToUVRow)(const uint8* src_argb1555, int src_stride_argb1555,
   1286       uint8* dst_u, uint8* dst_v, int width) = ARGB1555ToUVRow_C;
   1287   void (*ARGB1555ToYRow)(const uint8* src_argb1555, uint8* dst_y, int pix) =
   1288       ARGB1555ToYRow_C;
   1289   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
   1290     ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON;
   1291     if (IS_ALIGNED(width, 8)) {
   1292       ARGB1555ToYRow = ARGB1555ToYRow_NEON;
   1293     }
   1294     if (width >= 16) {
   1295       ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON;
   1296       if (IS_ALIGNED(width, 16)) {
   1297         ARGB1555ToUVRow = ARGB1555ToUVRow_NEON;
   1298       }
   1299     }
   1300   }
   1301 #else  // HAS_ARGB1555TOYROW_NEON
   1302 
   1303   // Allocate 2 rows of ARGB.
   1304   const int kRowSize = (width * 4 + 15) & ~15;
   1305   align_buffer_64(row, kRowSize * 2);
   1306 
   1307   void (*ARGB1555ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
   1308       ARGB1555ToARGBRow_C;
   1309 #if defined(HAS_ARGB1555TOARGBROW_SSE2)
   1310   if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
   1311     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
   1312     if (IS_ALIGNED(width, 8)) {
   1313       ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
   1314     }
   1315   }
   1316 #endif
   1317   void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
   1318                       uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
   1319 #if defined(HAS_ARGBTOUVROW_SSSE3)
   1320   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
   1321     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
   1322     if (IS_ALIGNED(width, 16)) {
   1323       ARGBToUVRow = ARGBToUVRow_SSSE3;
   1324     }
   1325   }
   1326 #endif
   1327   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
   1328       ARGBToYRow_C;
   1329 #if defined(HAS_ARGBTOUVROW_SSSE3)
   1330   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
   1331     ARGBToYRow = ARGBToYRow_Any_SSSE3;
   1332     if (IS_ALIGNED(width, 16)) {
   1333       ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
   1334       if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
   1335         ARGBToYRow = ARGBToYRow_SSSE3;
   1336       }
   1337     }
   1338   }
   1339 #endif  // HAS_ARGBTOUVROW_SSSE3
   1340 #endif  // HAS_ARGB1555TOYROW_NEON
   1341 
   1342   for (int y = 0; y < height - 1; y += 2) {
   1343 #if defined(HAS_ARGB1555TOYROW_NEON)
   1344     ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width);
   1345     ARGB1555ToYRow(src_argb1555, dst_y, width);
   1346     ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y,
   1347                    width);
   1348 #else
   1349     ARGB1555ToARGBRow(src_argb1555, row, width);
   1350     ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize,
   1351                       width);
   1352     ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
   1353     ARGBToYRow(row, dst_y, width);
   1354     ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
   1355 #endif
   1356     src_argb1555 += src_stride_argb1555 * 2;
   1357     dst_y += dst_stride_y * 2;
   1358     dst_u += dst_stride_u;
   1359     dst_v += dst_stride_v;
   1360   }
   1361   if (height & 1) {
   1362 #if defined(HAS_ARGB1555TOYROW_NEON)
   1363     ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width);
   1364     ARGB1555ToYRow(src_argb1555, dst_y, width);
   1365 #else
   1366     ARGB1555ToARGBRow(src_argb1555, row, width);
   1367     ARGBToUVRow(row, 0, dst_u, dst_v, width);
   1368     ARGBToYRow(row, dst_y, width);
   1369 #endif
   1370   }
   1371 #if !defined(HAS_ARGB1555TOYROW_NEON)
   1372   free_aligned_buffer_64(row);
   1373 #endif
   1374   return 0;
   1375 }
   1376 
   1377 // Convert ARGB4444 to I420.
   1378 LIBYUV_API
   1379 int ARGB4444ToI420(const uint8* src_argb4444, int src_stride_argb4444,
   1380                    uint8* dst_y, int dst_stride_y,
   1381                    uint8* dst_u, int dst_stride_u,
   1382                    uint8* dst_v, int dst_stride_v,
   1383                    int width, int height) {
   1384   if (!src_argb4444 || !dst_y || !dst_u || !dst_v ||
   1385       width <= 0 || height == 0) {
   1386     return -1;
   1387   }
   1388   // Negative height means invert the image.
   1389   if (height < 0) {
   1390     height = -height;
   1391     src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
   1392     src_stride_argb4444 = -src_stride_argb4444;
   1393   }
   1394 
   1395 #if defined(HAS_ARGB4444TOYROW_NEON)
   1396   void (*ARGB4444ToUVRow)(const uint8* src_argb4444, int src_stride_argb4444,
   1397       uint8* dst_u, uint8* dst_v, int width) = ARGB4444ToUVRow_C;
   1398   void (*ARGB4444ToYRow)(const uint8* src_argb4444, uint8* dst_y, int pix) =
   1399       ARGB4444ToYRow_C;
   1400   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
   1401     ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON;
   1402     if (IS_ALIGNED(width, 8)) {
   1403       ARGB4444ToYRow = ARGB4444ToYRow_NEON;
   1404     }
   1405     if (width >= 16) {
   1406       ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON;
   1407       if (IS_ALIGNED(width, 16)) {
   1408         ARGB4444ToUVRow = ARGB4444ToUVRow_NEON;
   1409       }
   1410     }
   1411   }
   1412 #else  // HAS_ARGB4444TOYROW_NEON
   1413 
   1414   // Allocate 2 rows of ARGB.
   1415   const int kRowSize = (width * 4 + 15) & ~15;
   1416   align_buffer_64(row, kRowSize * 2);
   1417 
   1418   void (*ARGB4444ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
   1419       ARGB4444ToARGBRow_C;
   1420 #if defined(HAS_ARGB4444TOARGBROW_SSE2)
   1421   if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
   1422     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
   1423     if (IS_ALIGNED(width, 8)) {
   1424       ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
   1425     }
   1426   }
   1427 #endif
   1428   void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
   1429                       uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
   1430 #if defined(HAS_ARGBTOUVROW_SSSE3)
   1431   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
   1432     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
   1433     if (IS_ALIGNED(width, 16)) {
   1434       ARGBToUVRow = ARGBToUVRow_SSSE3;
   1435     }
   1436   }
   1437 #endif
   1438   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
   1439       ARGBToYRow_C;
   1440 #if defined(HAS_ARGBTOUVROW_SSSE3)
   1441   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
   1442     ARGBToYRow = ARGBToYRow_Any_SSSE3;
   1443     if (IS_ALIGNED(width, 16)) {
   1444       ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
   1445       if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
   1446         ARGBToYRow = ARGBToYRow_SSSE3;
   1447       }
   1448     }
   1449   }
   1450 #endif  // HAS_ARGBTOUVROW_SSSE3
   1451 #endif  // HAS_ARGB4444TOYROW_NEON
   1452 
   1453   for (int y = 0; y < height - 1; y += 2) {
   1454 #if defined(HAS_ARGB4444TOYROW_NEON)
   1455     ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width);
   1456     ARGB4444ToYRow(src_argb4444, dst_y, width);
   1457     ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y,
   1458                    width);
   1459 #else
   1460     ARGB4444ToARGBRow(src_argb4444, row, width);
   1461     ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kRowSize,
   1462                       width);
   1463     ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
   1464     ARGBToYRow(row, dst_y, width);
   1465     ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
   1466 #endif
   1467     src_argb4444 += src_stride_argb4444 * 2;
   1468     dst_y += dst_stride_y * 2;
   1469     dst_u += dst_stride_u;
   1470     dst_v += dst_stride_v;
   1471   }
   1472   if (height & 1) {
   1473 #if defined(HAS_ARGB4444TOYROW_NEON)
   1474     ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width);
   1475     ARGB4444ToYRow(src_argb4444, dst_y, width);
   1476 #else
   1477     ARGB4444ToARGBRow(src_argb4444, row, width);
   1478     ARGBToUVRow(row, 0, dst_u, dst_v, width);
   1479     ARGBToYRow(row, dst_y, width);
   1480 #endif
   1481   }
   1482 #if !defined(HAS_ARGB4444TOYROW_NEON)
   1483   free_aligned_buffer_64(row);
   1484 #endif
   1485   return 0;
   1486 }
   1487 
   1488 #ifdef __cplusplus
   1489 }  // extern "C"
   1490 }  // namespace libyuv
   1491 #endif
   1492