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