Home | History | Annotate | Download | only in source
      1 /*
      2  *  Copyright 2012 The LibYuv Project Authors. All rights reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS. All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include "libyuv/convert_from.h"
     12 
     13 #include "libyuv/basic_types.h"
     14 #include "libyuv/convert.h"  // For I420Copy
     15 #include "libyuv/cpu_id.h"
     16 #include "libyuv/planar_functions.h"
     17 #include "libyuv/rotate.h"
     18 #include "libyuv/scale.h"  // For ScalePlane()
     19 #include "libyuv/video_common.h"
     20 #include "libyuv/row.h"
     21 
     22 #ifdef __cplusplus
     23 namespace libyuv {
     24 extern "C" {
     25 #endif
     26 
     27 #define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
     28 static __inline int Abs(int v) {
     29   return v >= 0 ? v : -v;
     30 }
     31 
     32 // I420 To any I4xx YUV format with mirroring.
     33 static int I420ToI4xx(const uint8* src_y, int src_stride_y,
     34                       const uint8* src_u, int src_stride_u,
     35                       const uint8* src_v, int src_stride_v,
     36                       uint8* dst_y, int dst_stride_y,
     37                       uint8* dst_u, int dst_stride_u,
     38                       uint8* dst_v, int dst_stride_v,
     39                       int src_y_width, int src_y_height,
     40                       int dst_uv_width, int dst_uv_height) {
     41   const int dst_y_width = Abs(src_y_width);
     42   const int dst_y_height = Abs(src_y_height);
     43   const int src_uv_width = SUBSAMPLE(src_y_width, 1, 1);
     44   const int src_uv_height = SUBSAMPLE(src_y_height, 1, 1);
     45   if (src_y_width == 0 || src_y_height == 0 ||
     46       dst_uv_width <= 0 || dst_uv_height <= 0) {
     47     return -1;
     48   }
     49   ScalePlane(src_y, src_stride_y, src_y_width, src_y_height,
     50              dst_y, dst_stride_y, dst_y_width, dst_y_height,
     51              kFilterBilinear);
     52   ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height,
     53              dst_u, dst_stride_u, dst_uv_width, dst_uv_height,
     54              kFilterBilinear);
     55   ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height,
     56              dst_v, dst_stride_v, dst_uv_width, dst_uv_height,
     57              kFilterBilinear);
     58   return 0;
     59 }
     60 
     61 // 420 chroma is 1/2 width, 1/2 height
     62 // 422 chroma is 1/2 width, 1x height
     63 LIBYUV_API
     64 int I420ToI422(const uint8* src_y, int src_stride_y,
     65                const uint8* src_u, int src_stride_u,
     66                const uint8* src_v, int src_stride_v,
     67                uint8* dst_y, int dst_stride_y,
     68                uint8* dst_u, int dst_stride_u,
     69                uint8* dst_v, int dst_stride_v,
     70                int width, int height) {
     71   const int dst_uv_width = (Abs(width) + 1) >> 1;
     72   const int dst_uv_height = Abs(height);
     73   return I420ToI4xx(src_y, src_stride_y,
     74                     src_u, src_stride_u,
     75                     src_v, src_stride_v,
     76                     dst_y, dst_stride_y,
     77                     dst_u, dst_stride_u,
     78                     dst_v, dst_stride_v,
     79                     width, height,
     80                     dst_uv_width, dst_uv_height);
     81 }
     82 
     83 // 420 chroma is 1/2 width, 1/2 height
     84 // 444 chroma is 1x width, 1x height
     85 LIBYUV_API
     86 int I420ToI444(const uint8* src_y, int src_stride_y,
     87                const uint8* src_u, int src_stride_u,
     88                const uint8* src_v, int src_stride_v,
     89                uint8* dst_y, int dst_stride_y,
     90                uint8* dst_u, int dst_stride_u,
     91                uint8* dst_v, int dst_stride_v,
     92                int width, int height) {
     93   const int dst_uv_width = Abs(width);
     94   const int dst_uv_height = Abs(height);
     95   return I420ToI4xx(src_y, src_stride_y,
     96                     src_u, src_stride_u,
     97                     src_v, src_stride_v,
     98                     dst_y, dst_stride_y,
     99                     dst_u, dst_stride_u,
    100                     dst_v, dst_stride_v,
    101                     width, height,
    102                     dst_uv_width, dst_uv_height);
    103 }
    104 
    105 // 420 chroma is 1/2 width, 1/2 height
    106 // 411 chroma is 1/4 width, 1x height
    107 LIBYUV_API
    108 int I420ToI411(const uint8* src_y, int src_stride_y,
    109                const uint8* src_u, int src_stride_u,
    110                const uint8* src_v, int src_stride_v,
    111                uint8* dst_y, int dst_stride_y,
    112                uint8* dst_u, int dst_stride_u,
    113                uint8* dst_v, int dst_stride_v,
    114                int width, int height) {
    115   const int dst_uv_width = (Abs(width) + 3) >> 2;
    116   const int dst_uv_height = Abs(height);
    117   return I420ToI4xx(src_y, src_stride_y,
    118                     src_u, src_stride_u,
    119                     src_v, src_stride_v,
    120                     dst_y, dst_stride_y,
    121                     dst_u, dst_stride_u,
    122                     dst_v, dst_stride_v,
    123                     width, height,
    124                     dst_uv_width, dst_uv_height);
    125 }
    126 
    127 // Copy to I400. Source can be I420,422,444,400,NV12,NV21
    128 LIBYUV_API
    129 int I400Copy(const uint8* src_y, int src_stride_y,
    130              uint8* dst_y, int dst_stride_y,
    131              int width, int height) {
    132   if (!src_y || !dst_y ||
    133       width <= 0 || height == 0) {
    134     return -1;
    135   }
    136   // Negative height means invert the image.
    137   if (height < 0) {
    138     height = -height;
    139     src_y = src_y + (height - 1) * src_stride_y;
    140     src_stride_y = -src_stride_y;
    141   }
    142   CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
    143   return 0;
    144 }
    145 
    146 LIBYUV_API
    147 int I422ToYUY2(const uint8* src_y, int src_stride_y,
    148                const uint8* src_u, int src_stride_u,
    149                const uint8* src_v, int src_stride_v,
    150                uint8* dst_yuy2, int dst_stride_yuy2,
    151                int width, int height) {
    152   int y;
    153   void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u,
    154                         const uint8* src_v, uint8* dst_yuy2, int width) =
    155       I422ToYUY2Row_C;
    156   if (!src_y || !src_u || !src_v || !dst_yuy2 ||
    157       width <= 0 || height == 0) {
    158     return -1;
    159   }
    160   // Negative height means invert the image.
    161   if (height < 0) {
    162     height = -height;
    163     dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
    164     dst_stride_yuy2 = -dst_stride_yuy2;
    165   }
    166   // Coalesce rows.
    167   if (src_stride_y == width &&
    168       src_stride_u * 2 == width &&
    169       src_stride_v * 2 == width &&
    170       dst_stride_yuy2 == width * 2) {
    171     width *= height;
    172     height = 1;
    173     src_stride_y = src_stride_u = src_stride_v = dst_stride_yuy2 = 0;
    174   }
    175 #if defined(HAS_I422TOYUY2ROW_SSE2)
    176   if (TestCpuFlag(kCpuHasSSE2)) {
    177     I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
    178     if (IS_ALIGNED(width, 16)) {
    179       I422ToYUY2Row = I422ToYUY2Row_SSE2;
    180     }
    181   }
    182 #endif
    183 #if defined(HAS_I422TOYUY2ROW_NEON)
    184   if (TestCpuFlag(kCpuHasNEON)) {
    185     I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
    186     if (IS_ALIGNED(width, 16)) {
    187       I422ToYUY2Row = I422ToYUY2Row_NEON;
    188     }
    189   }
    190 #endif
    191 
    192   for (y = 0; y < height; ++y) {
    193     I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
    194     src_y += src_stride_y;
    195     src_u += src_stride_u;
    196     src_v += src_stride_v;
    197     dst_yuy2 += dst_stride_yuy2;
    198   }
    199   return 0;
    200 }
    201 
    202 LIBYUV_API
    203 int I420ToYUY2(const uint8* src_y, int src_stride_y,
    204                const uint8* src_u, int src_stride_u,
    205                const uint8* src_v, int src_stride_v,
    206                uint8* dst_yuy2, int dst_stride_yuy2,
    207                int width, int height) {
    208   int y;
    209   void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u,
    210                         const uint8* src_v, uint8* dst_yuy2, int width) =
    211       I422ToYUY2Row_C;
    212   if (!src_y || !src_u || !src_v || !dst_yuy2 ||
    213       width <= 0 || height == 0) {
    214     return -1;
    215   }
    216   // Negative height means invert the image.
    217   if (height < 0) {
    218     height = -height;
    219     dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
    220     dst_stride_yuy2 = -dst_stride_yuy2;
    221   }
    222 #if defined(HAS_I422TOYUY2ROW_SSE2)
    223   if (TestCpuFlag(kCpuHasSSE2)) {
    224     I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
    225     if (IS_ALIGNED(width, 16)) {
    226       I422ToYUY2Row = I422ToYUY2Row_SSE2;
    227     }
    228   }
    229 #endif
    230 #if defined(HAS_I422TOYUY2ROW_NEON)
    231   if (TestCpuFlag(kCpuHasNEON)) {
    232     I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
    233     if (IS_ALIGNED(width, 16)) {
    234       I422ToYUY2Row = I422ToYUY2Row_NEON;
    235     }
    236   }
    237 #endif
    238 
    239   for (y = 0; y < height - 1; y += 2) {
    240     I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
    241     I422ToYUY2Row(src_y + src_stride_y, src_u, src_v,
    242                   dst_yuy2 + dst_stride_yuy2, width);
    243     src_y += src_stride_y * 2;
    244     src_u += src_stride_u;
    245     src_v += src_stride_v;
    246     dst_yuy2 += dst_stride_yuy2 * 2;
    247   }
    248   if (height & 1) {
    249     I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
    250   }
    251   return 0;
    252 }
    253 
    254 LIBYUV_API
    255 int I422ToUYVY(const uint8* src_y, int src_stride_y,
    256                const uint8* src_u, int src_stride_u,
    257                const uint8* src_v, int src_stride_v,
    258                uint8* dst_uyvy, int dst_stride_uyvy,
    259                int width, int height) {
    260   int y;
    261   void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u,
    262                         const uint8* src_v, uint8* dst_uyvy, int width) =
    263       I422ToUYVYRow_C;
    264   if (!src_y || !src_u || !src_v || !dst_uyvy ||
    265       width <= 0 || height == 0) {
    266     return -1;
    267   }
    268   // Negative height means invert the image.
    269   if (height < 0) {
    270     height = -height;
    271     dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
    272     dst_stride_uyvy = -dst_stride_uyvy;
    273   }
    274   // Coalesce rows.
    275   if (src_stride_y == width &&
    276       src_stride_u * 2 == width &&
    277       src_stride_v * 2 == width &&
    278       dst_stride_uyvy == width * 2) {
    279     width *= height;
    280     height = 1;
    281     src_stride_y = src_stride_u = src_stride_v = dst_stride_uyvy = 0;
    282   }
    283 #if defined(HAS_I422TOUYVYROW_SSE2)
    284   if (TestCpuFlag(kCpuHasSSE2)) {
    285     I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
    286     if (IS_ALIGNED(width, 16)) {
    287       I422ToUYVYRow = I422ToUYVYRow_SSE2;
    288     }
    289   }
    290 #endif
    291 #if defined(HAS_I422TOUYVYROW_NEON)
    292   if (TestCpuFlag(kCpuHasNEON)) {
    293     I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
    294     if (IS_ALIGNED(width, 16)) {
    295       I422ToUYVYRow = I422ToUYVYRow_NEON;
    296     }
    297   }
    298 #endif
    299 
    300   for (y = 0; y < height; ++y) {
    301     I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
    302     src_y += src_stride_y;
    303     src_u += src_stride_u;
    304     src_v += src_stride_v;
    305     dst_uyvy += dst_stride_uyvy;
    306   }
    307   return 0;
    308 }
    309 
    310 LIBYUV_API
    311 int I420ToUYVY(const uint8* src_y, int src_stride_y,
    312                const uint8* src_u, int src_stride_u,
    313                const uint8* src_v, int src_stride_v,
    314                uint8* dst_uyvy, int dst_stride_uyvy,
    315                int width, int height) {
    316   int y;
    317   void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u,
    318                         const uint8* src_v, uint8* dst_uyvy, int width) =
    319       I422ToUYVYRow_C;
    320   if (!src_y || !src_u || !src_v || !dst_uyvy ||
    321       width <= 0 || height == 0) {
    322     return -1;
    323   }
    324   // Negative height means invert the image.
    325   if (height < 0) {
    326     height = -height;
    327     dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
    328     dst_stride_uyvy = -dst_stride_uyvy;
    329   }
    330 #if defined(HAS_I422TOUYVYROW_SSE2)
    331   if (TestCpuFlag(kCpuHasSSE2)) {
    332     I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
    333     if (IS_ALIGNED(width, 16)) {
    334       I422ToUYVYRow = I422ToUYVYRow_SSE2;
    335     }
    336   }
    337 #endif
    338 #if defined(HAS_I422TOUYVYROW_NEON)
    339   if (TestCpuFlag(kCpuHasNEON)) {
    340     I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
    341     if (IS_ALIGNED(width, 16)) {
    342       I422ToUYVYRow = I422ToUYVYRow_NEON;
    343     }
    344   }
    345 #endif
    346 
    347   for (y = 0; y < height - 1; y += 2) {
    348     I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
    349     I422ToUYVYRow(src_y + src_stride_y, src_u, src_v,
    350                   dst_uyvy + dst_stride_uyvy, width);
    351     src_y += src_stride_y * 2;
    352     src_u += src_stride_u;
    353     src_v += src_stride_v;
    354     dst_uyvy += dst_stride_uyvy * 2;
    355   }
    356   if (height & 1) {
    357     I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
    358   }
    359   return 0;
    360 }
    361 
    362 LIBYUV_API
    363 int I420ToNV12(const uint8* src_y, int src_stride_y,
    364                const uint8* src_u, int src_stride_u,
    365                const uint8* src_v, int src_stride_v,
    366                uint8* dst_y, int dst_stride_y,
    367                uint8* dst_uv, int dst_stride_uv,
    368                int width, int height) {
    369   int y;
    370   void (*MergeUVRow_)(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
    371       int width) = MergeUVRow_C;
    372   // Coalesce rows.
    373   int halfwidth = (width + 1) >> 1;
    374   int halfheight = (height + 1) >> 1;
    375   if (!src_y || !src_u || !src_v || !dst_y || !dst_uv ||
    376       width <= 0 || height == 0) {
    377     return -1;
    378   }
    379   // Negative height means invert the image.
    380   if (height < 0) {
    381     height = -height;
    382     halfheight = (height + 1) >> 1;
    383     dst_y = dst_y + (height - 1) * dst_stride_y;
    384     dst_uv = dst_uv + (halfheight - 1) * dst_stride_uv;
    385     dst_stride_y = -dst_stride_y;
    386     dst_stride_uv = -dst_stride_uv;
    387   }
    388   if (src_stride_y == width &&
    389       dst_stride_y == width) {
    390     width *= height;
    391     height = 1;
    392     src_stride_y = dst_stride_y = 0;
    393   }
    394   // Coalesce rows.
    395   if (src_stride_u == halfwidth &&
    396       src_stride_v == halfwidth &&
    397       dst_stride_uv == halfwidth * 2) {
    398     halfwidth *= halfheight;
    399     halfheight = 1;
    400     src_stride_u = src_stride_v = dst_stride_uv = 0;
    401   }
    402 #if defined(HAS_MERGEUVROW_SSE2)
    403   if (TestCpuFlag(kCpuHasSSE2)) {
    404     MergeUVRow_ = MergeUVRow_Any_SSE2;
    405     if (IS_ALIGNED(halfwidth, 16)) {
    406       MergeUVRow_ = MergeUVRow_SSE2;
    407     }
    408   }
    409 #endif
    410 #if defined(HAS_MERGEUVROW_AVX2)
    411   if (TestCpuFlag(kCpuHasAVX2)) {
    412     MergeUVRow_ = MergeUVRow_Any_AVX2;
    413     if (IS_ALIGNED(halfwidth, 32)) {
    414       MergeUVRow_ = MergeUVRow_AVX2;
    415     }
    416   }
    417 #endif
    418 #if defined(HAS_MERGEUVROW_NEON)
    419   if (TestCpuFlag(kCpuHasNEON)) {
    420     MergeUVRow_ = MergeUVRow_Any_NEON;
    421     if (IS_ALIGNED(halfwidth, 16)) {
    422       MergeUVRow_ = MergeUVRow_NEON;
    423     }
    424   }
    425 #endif
    426 
    427   CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
    428   for (y = 0; y < halfheight; ++y) {
    429     // Merge a row of U and V into a row of UV.
    430     MergeUVRow_(src_u, src_v, dst_uv, halfwidth);
    431     src_u += src_stride_u;
    432     src_v += src_stride_v;
    433     dst_uv += dst_stride_uv;
    434   }
    435   return 0;
    436 }
    437 
    438 LIBYUV_API
    439 int I420ToNV21(const uint8* src_y, int src_stride_y,
    440                const uint8* src_u, int src_stride_u,
    441                const uint8* src_v, int src_stride_v,
    442                uint8* dst_y, int dst_stride_y,
    443                uint8* dst_vu, int dst_stride_vu,
    444                int width, int height) {
    445   return I420ToNV12(src_y, src_stride_y,
    446                     src_v, src_stride_v,
    447                     src_u, src_stride_u,
    448                     dst_y, src_stride_y,
    449                     dst_vu, dst_stride_vu,
    450                     width, height);
    451 }
    452 
    453 // Convert I420 to ARGB.
    454 LIBYUV_API
    455 int I420ToARGB(const uint8* src_y, int src_stride_y,
    456                const uint8* src_u, int src_stride_u,
    457                const uint8* src_v, int src_stride_v,
    458                uint8* dst_argb, int dst_stride_argb,
    459                int width, int height) {
    460   int y;
    461   void (*I422ToARGBRow)(const uint8* y_buf,
    462                         const uint8* u_buf,
    463                         const uint8* v_buf,
    464                         uint8* rgb_buf,
    465                         int width) = I422ToARGBRow_C;
    466   if (!src_y || !src_u || !src_v || !dst_argb ||
    467       width <= 0 || height == 0) {
    468     return -1;
    469   }
    470   // Negative height means invert the image.
    471   if (height < 0) {
    472     height = -height;
    473     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
    474     dst_stride_argb = -dst_stride_argb;
    475   }
    476 #if defined(HAS_I422TOARGBROW_SSSE3)
    477   if (TestCpuFlag(kCpuHasSSSE3)) {
    478     I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
    479     if (IS_ALIGNED(width, 8)) {
    480       I422ToARGBRow = I422ToARGBRow_SSSE3;
    481     }
    482   }
    483 #endif
    484 #if defined(HAS_I422TOARGBROW_AVX2)
    485   if (TestCpuFlag(kCpuHasAVX2)) {
    486     I422ToARGBRow = I422ToARGBRow_Any_AVX2;
    487     if (IS_ALIGNED(width, 16)) {
    488       I422ToARGBRow = I422ToARGBRow_AVX2;
    489     }
    490   }
    491 #endif
    492 #if defined(HAS_I422TOARGBROW_NEON)
    493   if (TestCpuFlag(kCpuHasNEON)) {
    494     I422ToARGBRow = I422ToARGBRow_Any_NEON;
    495     if (IS_ALIGNED(width, 8)) {
    496       I422ToARGBRow = I422ToARGBRow_NEON;
    497     }
    498   }
    499 #endif
    500 #if defined(HAS_I422TOARGBROW_MIPS_DSPR2)
    501   if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) &&
    502       IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
    503       IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
    504       IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
    505       IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) {
    506     I422ToARGBRow = I422ToARGBRow_MIPS_DSPR2;
    507   }
    508 #endif
    509 
    510   for (y = 0; y < height; ++y) {
    511     I422ToARGBRow(src_y, src_u, src_v, dst_argb, width);
    512     dst_argb += dst_stride_argb;
    513     src_y += src_stride_y;
    514     if (y & 1) {
    515       src_u += src_stride_u;
    516       src_v += src_stride_v;
    517     }
    518   }
    519   return 0;
    520 }
    521 
    522 // Convert I420 to BGRA.
    523 LIBYUV_API
    524 int I420ToBGRA(const uint8* src_y, int src_stride_y,
    525                const uint8* src_u, int src_stride_u,
    526                const uint8* src_v, int src_stride_v,
    527                uint8* dst_bgra, int dst_stride_bgra,
    528                int width, int height) {
    529   int y;
    530   void (*I422ToBGRARow)(const uint8* y_buf,
    531                         const uint8* u_buf,
    532                         const uint8* v_buf,
    533                         uint8* rgb_buf,
    534                         int width) = I422ToBGRARow_C;
    535   if (!src_y || !src_u || !src_v || !dst_bgra ||
    536       width <= 0 || height == 0) {
    537     return -1;
    538   }
    539   // Negative height means invert the image.
    540   if (height < 0) {
    541     height = -height;
    542     dst_bgra = dst_bgra + (height - 1) * dst_stride_bgra;
    543     dst_stride_bgra = -dst_stride_bgra;
    544   }
    545 #if defined(HAS_I422TOBGRAROW_SSSE3)
    546   if (TestCpuFlag(kCpuHasSSSE3)) {
    547     I422ToBGRARow = I422ToBGRARow_Any_SSSE3;
    548     if (IS_ALIGNED(width, 8)) {
    549       I422ToBGRARow = I422ToBGRARow_SSSE3;
    550     }
    551   }
    552 #endif
    553 #if defined(HAS_I422TOBGRAROW_AVX2)
    554   if (TestCpuFlag(kCpuHasAVX2)) {
    555     I422ToBGRARow = I422ToBGRARow_Any_AVX2;
    556     if (IS_ALIGNED(width, 16)) {
    557       I422ToBGRARow = I422ToBGRARow_AVX2;
    558     }
    559   }
    560 #endif
    561 #if defined(HAS_I422TOBGRAROW_NEON)
    562   if (TestCpuFlag(kCpuHasNEON)) {
    563     I422ToBGRARow = I422ToBGRARow_Any_NEON;
    564     if (IS_ALIGNED(width, 8)) {
    565       I422ToBGRARow = I422ToBGRARow_NEON;
    566     }
    567   }
    568 #endif
    569 #if defined(HAS_I422TOBGRAROW_MIPS_DSPR2)
    570   if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) &&
    571       IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
    572       IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
    573       IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
    574       IS_ALIGNED(dst_bgra, 4) && IS_ALIGNED(dst_stride_bgra, 4)) {
    575     I422ToBGRARow = I422ToBGRARow_MIPS_DSPR2;
    576   }
    577 #endif
    578 
    579   for (y = 0; y < height; ++y) {
    580     I422ToBGRARow(src_y, src_u, src_v, dst_bgra, width);
    581     dst_bgra += dst_stride_bgra;
    582     src_y += src_stride_y;
    583     if (y & 1) {
    584       src_u += src_stride_u;
    585       src_v += src_stride_v;
    586     }
    587   }
    588   return 0;
    589 }
    590 
    591 // Convert I420 to ABGR.
    592 LIBYUV_API
    593 int I420ToABGR(const uint8* src_y, int src_stride_y,
    594                const uint8* src_u, int src_stride_u,
    595                const uint8* src_v, int src_stride_v,
    596                uint8* dst_abgr, int dst_stride_abgr,
    597                int width, int height) {
    598   int y;
    599   void (*I422ToABGRRow)(const uint8* y_buf,
    600                         const uint8* u_buf,
    601                         const uint8* v_buf,
    602                         uint8* rgb_buf,
    603                         int width) = I422ToABGRRow_C;
    604   if (!src_y || !src_u || !src_v || !dst_abgr ||
    605       width <= 0 || height == 0) {
    606     return -1;
    607   }
    608   // Negative height means invert the image.
    609   if (height < 0) {
    610     height = -height;
    611     dst_abgr = dst_abgr + (height - 1) * dst_stride_abgr;
    612     dst_stride_abgr = -dst_stride_abgr;
    613   }
    614 #if defined(HAS_I422TOABGRROW_SSSE3)
    615   if (TestCpuFlag(kCpuHasSSSE3)) {
    616     I422ToABGRRow = I422ToABGRRow_Any_SSSE3;
    617     if (IS_ALIGNED(width, 8)) {
    618       I422ToABGRRow = I422ToABGRRow_SSSE3;
    619     }
    620   }
    621 #endif
    622 #if defined(HAS_I422TOABGRROW_AVX2)
    623   if (TestCpuFlag(kCpuHasAVX2)) {
    624     I422ToABGRRow = I422ToABGRRow_Any_AVX2;
    625     if (IS_ALIGNED(width, 16)) {
    626       I422ToABGRRow = I422ToABGRRow_AVX2;
    627     }
    628   }
    629 #endif
    630 #if defined(HAS_I422TOABGRROW_NEON)
    631   if (TestCpuFlag(kCpuHasNEON)) {
    632     I422ToABGRRow = I422ToABGRRow_Any_NEON;
    633     if (IS_ALIGNED(width, 8)) {
    634       I422ToABGRRow = I422ToABGRRow_NEON;
    635     }
    636   }
    637 #endif
    638 
    639   for (y = 0; y < height; ++y) {
    640     I422ToABGRRow(src_y, src_u, src_v, dst_abgr, width);
    641     dst_abgr += dst_stride_abgr;
    642     src_y += src_stride_y;
    643     if (y & 1) {
    644       src_u += src_stride_u;
    645       src_v += src_stride_v;
    646     }
    647   }
    648   return 0;
    649 }
    650 
    651 // Convert I420 to RGBA.
    652 LIBYUV_API
    653 int I420ToRGBA(const uint8* src_y, int src_stride_y,
    654                const uint8* src_u, int src_stride_u,
    655                const uint8* src_v, int src_stride_v,
    656                uint8* dst_rgba, int dst_stride_rgba,
    657                int width, int height) {
    658   int y;
    659   void (*I422ToRGBARow)(const uint8* y_buf,
    660                         const uint8* u_buf,
    661                         const uint8* v_buf,
    662                         uint8* rgb_buf,
    663                         int width) = I422ToRGBARow_C;
    664   if (!src_y || !src_u || !src_v || !dst_rgba ||
    665       width <= 0 || height == 0) {
    666     return -1;
    667   }
    668   // Negative height means invert the image.
    669   if (height < 0) {
    670     height = -height;
    671     dst_rgba = dst_rgba + (height - 1) * dst_stride_rgba;
    672     dst_stride_rgba = -dst_stride_rgba;
    673   }
    674 #if defined(HAS_I422TORGBAROW_SSSE3)
    675   if (TestCpuFlag(kCpuHasSSSE3)) {
    676     I422ToRGBARow = I422ToRGBARow_Any_SSSE3;
    677     if (IS_ALIGNED(width, 8)) {
    678       I422ToRGBARow = I422ToRGBARow_SSSE3;
    679     }
    680   }
    681 #endif
    682 #if defined(HAS_I422TORGBAROW_AVX2)
    683   if (TestCpuFlag(kCpuHasAVX2)) {
    684     I422ToRGBARow = I422ToRGBARow_Any_AVX2;
    685     if (IS_ALIGNED(width, 16)) {
    686       I422ToRGBARow = I422ToRGBARow_AVX2;
    687     }
    688   }
    689 #endif
    690 #if defined(HAS_I422TORGBAROW_NEON)
    691   if (TestCpuFlag(kCpuHasNEON)) {
    692     I422ToRGBARow = I422ToRGBARow_Any_NEON;
    693     if (IS_ALIGNED(width, 8)) {
    694       I422ToRGBARow = I422ToRGBARow_NEON;
    695     }
    696   }
    697 #endif
    698 
    699   for (y = 0; y < height; ++y) {
    700     I422ToRGBARow(src_y, src_u, src_v, dst_rgba, width);
    701     dst_rgba += dst_stride_rgba;
    702     src_y += src_stride_y;
    703     if (y & 1) {
    704       src_u += src_stride_u;
    705       src_v += src_stride_v;
    706     }
    707   }
    708   return 0;
    709 }
    710 
    711 // Convert I420 to RGB24.
    712 LIBYUV_API
    713 int I420ToRGB24(const uint8* src_y, int src_stride_y,
    714                 const uint8* src_u, int src_stride_u,
    715                 const uint8* src_v, int src_stride_v,
    716                 uint8* dst_rgb24, int dst_stride_rgb24,
    717                 int width, int height) {
    718   int y;
    719   void (*I422ToRGB24Row)(const uint8* y_buf,
    720                          const uint8* u_buf,
    721                          const uint8* v_buf,
    722                          uint8* rgb_buf,
    723                          int width) = I422ToRGB24Row_C;
    724   if (!src_y || !src_u || !src_v || !dst_rgb24 ||
    725       width <= 0 || height == 0) {
    726     return -1;
    727   }
    728   // Negative height means invert the image.
    729   if (height < 0) {
    730     height = -height;
    731     dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
    732     dst_stride_rgb24 = -dst_stride_rgb24;
    733   }
    734 #if defined(HAS_I422TORGB24ROW_SSSE3)
    735   if (TestCpuFlag(kCpuHasSSSE3)) {
    736     I422ToRGB24Row = I422ToRGB24Row_Any_SSSE3;
    737     if (IS_ALIGNED(width, 8)) {
    738       I422ToRGB24Row = I422ToRGB24Row_SSSE3;
    739     }
    740   }
    741 #endif
    742 #if defined(HAS_I422TORGB24ROW_AVX2)
    743   if (TestCpuFlag(kCpuHasAVX2)) {
    744     I422ToRGB24Row = I422ToRGB24Row_Any_AVX2;
    745     if (IS_ALIGNED(width, 16)) {
    746       I422ToRGB24Row = I422ToRGB24Row_AVX2;
    747     }
    748   }
    749 #endif
    750 #if defined(HAS_I422TORGB24ROW_NEON)
    751   if (TestCpuFlag(kCpuHasNEON)) {
    752     I422ToRGB24Row = I422ToRGB24Row_Any_NEON;
    753     if (IS_ALIGNED(width, 8)) {
    754       I422ToRGB24Row = I422ToRGB24Row_NEON;
    755     }
    756   }
    757 #endif
    758 
    759   for (y = 0; y < height; ++y) {
    760     I422ToRGB24Row(src_y, src_u, src_v, dst_rgb24, width);
    761     dst_rgb24 += dst_stride_rgb24;
    762     src_y += src_stride_y;
    763     if (y & 1) {
    764       src_u += src_stride_u;
    765       src_v += src_stride_v;
    766     }
    767   }
    768   return 0;
    769 }
    770 
    771 // Convert I420 to RAW.
    772 LIBYUV_API
    773 int I420ToRAW(const uint8* src_y, int src_stride_y,
    774                 const uint8* src_u, int src_stride_u,
    775                 const uint8* src_v, int src_stride_v,
    776                 uint8* dst_raw, int dst_stride_raw,
    777                 int width, int height) {
    778   int y;
    779   void (*I422ToRAWRow)(const uint8* y_buf,
    780                        const uint8* u_buf,
    781                        const uint8* v_buf,
    782                        uint8* rgb_buf,
    783                        int width) = I422ToRAWRow_C;
    784   if (!src_y || !src_u || !src_v || !dst_raw ||
    785       width <= 0 || height == 0) {
    786     return -1;
    787   }
    788   // Negative height means invert the image.
    789   if (height < 0) {
    790     height = -height;
    791     dst_raw = dst_raw + (height - 1) * dst_stride_raw;
    792     dst_stride_raw = -dst_stride_raw;
    793   }
    794 #if defined(HAS_I422TORAWROW_SSSE3)
    795   if (TestCpuFlag(kCpuHasSSSE3)) {
    796     I422ToRAWRow = I422ToRAWRow_Any_SSSE3;
    797     if (IS_ALIGNED(width, 8)) {
    798       I422ToRAWRow = I422ToRAWRow_SSSE3;
    799     }
    800   }
    801 #endif
    802 #if defined(HAS_I422TORAWROW_AVX2)
    803   if (TestCpuFlag(kCpuHasAVX2)) {
    804     I422ToRAWRow = I422ToRAWRow_Any_AVX2;
    805     if (IS_ALIGNED(width, 16)) {
    806       I422ToRAWRow = I422ToRAWRow_AVX2;
    807     }
    808   }
    809 #endif
    810 #if defined(HAS_I422TORAWROW_NEON)
    811   if (TestCpuFlag(kCpuHasNEON)) {
    812     I422ToRAWRow = I422ToRAWRow_Any_NEON;
    813     if (IS_ALIGNED(width, 8)) {
    814       I422ToRAWRow = I422ToRAWRow_NEON;
    815     }
    816   }
    817 #endif
    818 
    819   for (y = 0; y < height; ++y) {
    820     I422ToRAWRow(src_y, src_u, src_v, dst_raw, width);
    821     dst_raw += dst_stride_raw;
    822     src_y += src_stride_y;
    823     if (y & 1) {
    824       src_u += src_stride_u;
    825       src_v += src_stride_v;
    826     }
    827   }
    828   return 0;
    829 }
    830 
    831 // Convert I420 to ARGB1555.
    832 LIBYUV_API
    833 int I420ToARGB1555(const uint8* src_y, int src_stride_y,
    834                    const uint8* src_u, int src_stride_u,
    835                    const uint8* src_v, int src_stride_v,
    836                    uint8* dst_argb1555, int dst_stride_argb1555,
    837                    int width, int height) {
    838   int y;
    839   void (*I422ToARGB1555Row)(const uint8* y_buf,
    840                             const uint8* u_buf,
    841                             const uint8* v_buf,
    842                             uint8* rgb_buf,
    843                             int width) = I422ToARGB1555Row_C;
    844   if (!src_y || !src_u || !src_v || !dst_argb1555 ||
    845       width <= 0 || height == 0) {
    846     return -1;
    847   }
    848   // Negative height means invert the image.
    849   if (height < 0) {
    850     height = -height;
    851     dst_argb1555 = dst_argb1555 + (height - 1) * dst_stride_argb1555;
    852     dst_stride_argb1555 = -dst_stride_argb1555;
    853   }
    854 #if defined(HAS_I422TOARGB1555ROW_SSSE3)
    855   if (TestCpuFlag(kCpuHasSSSE3)) {
    856     I422ToARGB1555Row = I422ToARGB1555Row_Any_SSSE3;
    857     if (IS_ALIGNED(width, 8)) {
    858       I422ToARGB1555Row = I422ToARGB1555Row_SSSE3;
    859     }
    860   }
    861 #endif
    862 #if defined(HAS_I422TOARGB1555ROW_AVX2)
    863   if (TestCpuFlag(kCpuHasAVX2)) {
    864     I422ToARGB1555Row = I422ToARGB1555Row_Any_AVX2;
    865     if (IS_ALIGNED(width, 16)) {
    866       I422ToARGB1555Row = I422ToARGB1555Row_AVX2;
    867     }
    868   }
    869 #endif
    870 #if defined(HAS_I422TOARGB1555ROW_NEON)
    871   if (TestCpuFlag(kCpuHasNEON)) {
    872     I422ToARGB1555Row = I422ToARGB1555Row_Any_NEON;
    873     if (IS_ALIGNED(width, 8)) {
    874       I422ToARGB1555Row = I422ToARGB1555Row_NEON;
    875     }
    876   }
    877 #endif
    878 
    879   for (y = 0; y < height; ++y) {
    880     I422ToARGB1555Row(src_y, src_u, src_v, dst_argb1555, width);
    881     dst_argb1555 += dst_stride_argb1555;
    882     src_y += src_stride_y;
    883     if (y & 1) {
    884       src_u += src_stride_u;
    885       src_v += src_stride_v;
    886     }
    887   }
    888   return 0;
    889 }
    890 
    891 
    892 // Convert I420 to ARGB4444.
    893 LIBYUV_API
    894 int I420ToARGB4444(const uint8* src_y, int src_stride_y,
    895                    const uint8* src_u, int src_stride_u,
    896                    const uint8* src_v, int src_stride_v,
    897                    uint8* dst_argb4444, int dst_stride_argb4444,
    898                    int width, int height) {
    899   int y;
    900   void (*I422ToARGB4444Row)(const uint8* y_buf,
    901                             const uint8* u_buf,
    902                             const uint8* v_buf,
    903                             uint8* rgb_buf,
    904                             int width) = I422ToARGB4444Row_C;
    905   if (!src_y || !src_u || !src_v || !dst_argb4444 ||
    906       width <= 0 || height == 0) {
    907     return -1;
    908   }
    909   // Negative height means invert the image.
    910   if (height < 0) {
    911     height = -height;
    912     dst_argb4444 = dst_argb4444 + (height - 1) * dst_stride_argb4444;
    913     dst_stride_argb4444 = -dst_stride_argb4444;
    914   }
    915 #if defined(HAS_I422TOARGB4444ROW_SSSE3)
    916   if (TestCpuFlag(kCpuHasSSSE3)) {
    917     I422ToARGB4444Row = I422ToARGB4444Row_Any_SSSE3;
    918     if (IS_ALIGNED(width, 8)) {
    919       I422ToARGB4444Row = I422ToARGB4444Row_SSSE3;
    920     }
    921   }
    922 #endif
    923 #if defined(HAS_I422TOARGB4444ROW_AVX2)
    924   if (TestCpuFlag(kCpuHasAVX2)) {
    925     I422ToARGB4444Row = I422ToARGB4444Row_Any_AVX2;
    926     if (IS_ALIGNED(width, 16)) {
    927       I422ToARGB4444Row = I422ToARGB4444Row_AVX2;
    928     }
    929   }
    930 #endif
    931 #if defined(HAS_I422TOARGB4444ROW_NEON)
    932   if (TestCpuFlag(kCpuHasNEON)) {
    933     I422ToARGB4444Row = I422ToARGB4444Row_Any_NEON;
    934     if (IS_ALIGNED(width, 8)) {
    935       I422ToARGB4444Row = I422ToARGB4444Row_NEON;
    936     }
    937   }
    938 #endif
    939 
    940   for (y = 0; y < height; ++y) {
    941     I422ToARGB4444Row(src_y, src_u, src_v, dst_argb4444, width);
    942     dst_argb4444 += dst_stride_argb4444;
    943     src_y += src_stride_y;
    944     if (y & 1) {
    945       src_u += src_stride_u;
    946       src_v += src_stride_v;
    947     }
    948   }
    949   return 0;
    950 }
    951 
    952 // Convert I420 to RGB565.
    953 LIBYUV_API
    954 int I420ToRGB565(const uint8* src_y, int src_stride_y,
    955                  const uint8* src_u, int src_stride_u,
    956                  const uint8* src_v, int src_stride_v,
    957                  uint8* dst_rgb565, int dst_stride_rgb565,
    958                  int width, int height) {
    959   int y;
    960   void (*I422ToRGB565Row)(const uint8* y_buf,
    961                           const uint8* u_buf,
    962                           const uint8* v_buf,
    963                           uint8* rgb_buf,
    964                           int width) = I422ToRGB565Row_C;
    965   if (!src_y || !src_u || !src_v || !dst_rgb565 ||
    966       width <= 0 || height == 0) {
    967     return -1;
    968   }
    969   // Negative height means invert the image.
    970   if (height < 0) {
    971     height = -height;
    972     dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
    973     dst_stride_rgb565 = -dst_stride_rgb565;
    974   }
    975 #if defined(HAS_I422TORGB565ROW_SSSE3)
    976   if (TestCpuFlag(kCpuHasSSSE3)) {
    977     I422ToRGB565Row = I422ToRGB565Row_Any_SSSE3;
    978     if (IS_ALIGNED(width, 8)) {
    979       I422ToRGB565Row = I422ToRGB565Row_SSSE3;
    980     }
    981   }
    982 #endif
    983 #if defined(HAS_I422TORGB565ROW_AVX2)
    984   if (TestCpuFlag(kCpuHasAVX2)) {
    985     I422ToRGB565Row = I422ToRGB565Row_Any_AVX2;
    986     if (IS_ALIGNED(width, 16)) {
    987       I422ToRGB565Row = I422ToRGB565Row_AVX2;
    988     }
    989   }
    990 #endif
    991 #if defined(HAS_I422TORGB565ROW_NEON)
    992   if (TestCpuFlag(kCpuHasNEON)) {
    993     I422ToRGB565Row = I422ToRGB565Row_Any_NEON;
    994     if (IS_ALIGNED(width, 8)) {
    995       I422ToRGB565Row = I422ToRGB565Row_NEON;
    996     }
    997   }
    998 #endif
    999 
   1000   for (y = 0; y < height; ++y) {
   1001     I422ToRGB565Row(src_y, src_u, src_v, dst_rgb565, width);
   1002     dst_rgb565 += dst_stride_rgb565;
   1003     src_y += src_stride_y;
   1004     if (y & 1) {
   1005       src_u += src_stride_u;
   1006       src_v += src_stride_v;
   1007     }
   1008   }
   1009   return 0;
   1010 }
   1011 
   1012 // Ordered 8x8 dither for 888 to 565.  Values from 0 to 7.
   1013 static const uint8 kDither565_4x4[16] = {
   1014   0, 4, 1, 5,
   1015   6, 2, 7, 3,
   1016   1, 5, 0, 4,
   1017   7, 3, 6, 2,
   1018 };
   1019 
   1020 // Convert I420 to RGB565 with dithering.
   1021 LIBYUV_API
   1022 int I420ToRGB565Dither(const uint8* src_y, int src_stride_y,
   1023                        const uint8* src_u, int src_stride_u,
   1024                        const uint8* src_v, int src_stride_v,
   1025                        uint8* dst_rgb565, int dst_stride_rgb565,
   1026                        const uint8* dither4x4, int width, int height) {
   1027   int y;
   1028   void (*I422ToARGBRow)(const uint8* y_buf,
   1029                         const uint8* u_buf,
   1030                         const uint8* v_buf,
   1031                         uint8* rgb_buf,
   1032                         int width) = I422ToARGBRow_C;
   1033   void (*ARGBToRGB565DitherRow)(const uint8* src_argb, uint8* dst_rgb,
   1034       const uint32 dither4, int pix) = ARGBToRGB565DitherRow_C;
   1035   if (!src_y || !src_u || !src_v || !dst_rgb565 ||
   1036       width <= 0 || height == 0) {
   1037     return -1;
   1038   }
   1039   // Negative height means invert the image.
   1040   if (height < 0) {
   1041     height = -height;
   1042     dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
   1043     dst_stride_rgb565 = -dst_stride_rgb565;
   1044   }
   1045   if (!dither4x4) {
   1046     dither4x4 = kDither565_4x4;
   1047   }
   1048 #if defined(HAS_I422TOARGBROW_SSSE3)
   1049   if (TestCpuFlag(kCpuHasSSSE3)) {
   1050     I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
   1051     if (IS_ALIGNED(width, 8)) {
   1052       I422ToARGBRow = I422ToARGBRow_SSSE3;
   1053     }
   1054   }
   1055 #endif
   1056 #if defined(HAS_I422TOARGBROW_AVX2)
   1057   if (TestCpuFlag(kCpuHasAVX2)) {
   1058     I422ToARGBRow = I422ToARGBRow_Any_AVX2;
   1059     if (IS_ALIGNED(width, 16)) {
   1060       I422ToARGBRow = I422ToARGBRow_AVX2;
   1061     }
   1062   }
   1063 #endif
   1064 #if defined(HAS_I422TOARGBROW_NEON)
   1065   if (TestCpuFlag(kCpuHasNEON)) {
   1066     I422ToARGBRow = I422ToARGBRow_Any_NEON;
   1067     if (IS_ALIGNED(width, 8)) {
   1068       I422ToARGBRow = I422ToARGBRow_NEON;
   1069     }
   1070   }
   1071 #endif
   1072 #if defined(HAS_I422TOARGBROW_MIPS_DSPR2)
   1073   if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) &&
   1074       IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
   1075       IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
   1076       IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2)) {
   1077     I422ToARGBRow = I422ToARGBRow_MIPS_DSPR2;
   1078   }
   1079 #endif
   1080 #if defined(HAS_ARGBTORGB565DITHERROW_SSE2)
   1081   if (TestCpuFlag(kCpuHasSSE2)) {
   1082     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_SSE2;
   1083     if (IS_ALIGNED(width, 4)) {
   1084       ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_SSE2;
   1085     }
   1086   }
   1087 #endif
   1088 #if defined(HAS_ARGBTORGB565DITHERROW_AVX2)
   1089   if (TestCpuFlag(kCpuHasAVX2)) {
   1090     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_AVX2;
   1091     if (IS_ALIGNED(width, 8)) {
   1092       ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_AVX2;
   1093     }
   1094   }
   1095 #endif
   1096 #if defined(HAS_ARGBTORGB565DITHERROW_NEON)
   1097   if (TestCpuFlag(kCpuHasNEON)) {
   1098     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_NEON;
   1099     if (IS_ALIGNED(width, 8)) {
   1100       ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_NEON;
   1101     }
   1102   }
   1103 #endif
   1104   {
   1105     // Allocate a row of argb.
   1106     align_buffer_64(row_argb, width * 4);
   1107     for (y = 0; y < height; ++y) {
   1108       I422ToARGBRow(src_y, src_u, src_v, row_argb, width);
   1109       ARGBToRGB565DitherRow(row_argb, dst_rgb565,
   1110                             *(uint32*)(dither4x4 + ((y & 3) << 2)), width);
   1111       dst_rgb565 += dst_stride_rgb565;
   1112       src_y += src_stride_y;
   1113       if (y & 1) {
   1114         src_u += src_stride_u;
   1115         src_v += src_stride_v;
   1116       }
   1117     }
   1118     free_aligned_buffer_64(row_argb);
   1119   }
   1120   return 0;
   1121 }
   1122 
   1123 // Convert I420 to specified format
   1124 LIBYUV_API
   1125 int ConvertFromI420(const uint8* y, int y_stride,
   1126                     const uint8* u, int u_stride,
   1127                     const uint8* v, int v_stride,
   1128                     uint8* dst_sample, int dst_sample_stride,
   1129                     int width, int height,
   1130                     uint32 fourcc) {
   1131   uint32 format = CanonicalFourCC(fourcc);
   1132   int r = 0;
   1133   if (!y || !u|| !v || !dst_sample ||
   1134       width <= 0 || height == 0) {
   1135     return -1;
   1136   }
   1137   switch (format) {
   1138     // Single plane formats
   1139     case FOURCC_YUY2:
   1140       r = I420ToYUY2(y, y_stride,
   1141                      u, u_stride,
   1142                      v, v_stride,
   1143                      dst_sample,
   1144                      dst_sample_stride ? dst_sample_stride : width * 2,
   1145                      width, height);
   1146       break;
   1147     case FOURCC_UYVY:
   1148       r = I420ToUYVY(y, y_stride,
   1149                      u, u_stride,
   1150                      v, v_stride,
   1151                      dst_sample,
   1152                      dst_sample_stride ? dst_sample_stride : width * 2,
   1153                      width, height);
   1154       break;
   1155     case FOURCC_RGBP:
   1156       r = I420ToRGB565(y, y_stride,
   1157                        u, u_stride,
   1158                        v, v_stride,
   1159                        dst_sample,
   1160                        dst_sample_stride ? dst_sample_stride : width * 2,
   1161                        width, height);
   1162       break;
   1163     case FOURCC_RGBO:
   1164       r = I420ToARGB1555(y, y_stride,
   1165                          u, u_stride,
   1166                          v, v_stride,
   1167                          dst_sample,
   1168                          dst_sample_stride ? dst_sample_stride : width * 2,
   1169                          width, height);
   1170       break;
   1171     case FOURCC_R444:
   1172       r = I420ToARGB4444(y, y_stride,
   1173                          u, u_stride,
   1174                          v, v_stride,
   1175                          dst_sample,
   1176                          dst_sample_stride ? dst_sample_stride : width * 2,
   1177                          width, height);
   1178       break;
   1179     case FOURCC_24BG:
   1180       r = I420ToRGB24(y, y_stride,
   1181                       u, u_stride,
   1182                       v, v_stride,
   1183                       dst_sample,
   1184                       dst_sample_stride ? dst_sample_stride : width * 3,
   1185                       width, height);
   1186       break;
   1187     case FOURCC_RAW:
   1188       r = I420ToRAW(y, y_stride,
   1189                     u, u_stride,
   1190                     v, v_stride,
   1191                     dst_sample,
   1192                     dst_sample_stride ? dst_sample_stride : width * 3,
   1193                     width, height);
   1194       break;
   1195     case FOURCC_ARGB:
   1196       r = I420ToARGB(y, y_stride,
   1197                      u, u_stride,
   1198                      v, v_stride,
   1199                      dst_sample,
   1200                      dst_sample_stride ? dst_sample_stride : width * 4,
   1201                      width, height);
   1202       break;
   1203     case FOURCC_BGRA:
   1204       r = I420ToBGRA(y, y_stride,
   1205                      u, u_stride,
   1206                      v, v_stride,
   1207                      dst_sample,
   1208                      dst_sample_stride ? dst_sample_stride : width * 4,
   1209                      width, height);
   1210       break;
   1211     case FOURCC_ABGR:
   1212       r = I420ToABGR(y, y_stride,
   1213                      u, u_stride,
   1214                      v, v_stride,
   1215                      dst_sample,
   1216                      dst_sample_stride ? dst_sample_stride : width * 4,
   1217                      width, height);
   1218       break;
   1219     case FOURCC_RGBA:
   1220       r = I420ToRGBA(y, y_stride,
   1221                      u, u_stride,
   1222                      v, v_stride,
   1223                      dst_sample,
   1224                      dst_sample_stride ? dst_sample_stride : width * 4,
   1225                      width, height);
   1226       break;
   1227     case FOURCC_I400:
   1228       r = I400Copy(y, y_stride,
   1229                    dst_sample,
   1230                    dst_sample_stride ? dst_sample_stride : width,
   1231                    width, height);
   1232       break;
   1233     case FOURCC_NV12: {
   1234       uint8* dst_uv = dst_sample + width * height;
   1235       r = I420ToNV12(y, y_stride,
   1236                      u, u_stride,
   1237                      v, v_stride,
   1238                      dst_sample,
   1239                      dst_sample_stride ? dst_sample_stride : width,
   1240                      dst_uv,
   1241                      dst_sample_stride ? dst_sample_stride : width,
   1242                      width, height);
   1243       break;
   1244     }
   1245     case FOURCC_NV21: {
   1246       uint8* dst_vu = dst_sample + width * height;
   1247       r = I420ToNV21(y, y_stride,
   1248                      u, u_stride,
   1249                      v, v_stride,
   1250                      dst_sample,
   1251                      dst_sample_stride ? dst_sample_stride : width,
   1252                      dst_vu,
   1253                      dst_sample_stride ? dst_sample_stride : width,
   1254                      width, height);
   1255       break;
   1256     }
   1257     // TODO(fbarchard): Add M420.
   1258     // Triplanar formats
   1259     // TODO(fbarchard): halfstride instead of halfwidth
   1260     case FOURCC_I420:
   1261     case FOURCC_YU12:
   1262     case FOURCC_YV12: {
   1263       int halfwidth = (width + 1) / 2;
   1264       int halfheight = (height + 1) / 2;
   1265       uint8* dst_u;
   1266       uint8* dst_v;
   1267       if (format == FOURCC_YV12) {
   1268         dst_v = dst_sample + width * height;
   1269         dst_u = dst_v + halfwidth * halfheight;
   1270       } else {
   1271         dst_u = dst_sample + width * height;
   1272         dst_v = dst_u + halfwidth * halfheight;
   1273       }
   1274       r = I420Copy(y, y_stride,
   1275                    u, u_stride,
   1276                    v, v_stride,
   1277                    dst_sample, width,
   1278                    dst_u, halfwidth,
   1279                    dst_v, halfwidth,
   1280                    width, height);
   1281       break;
   1282     }
   1283     case FOURCC_I422:
   1284     case FOURCC_YV16: {
   1285       int halfwidth = (width + 1) / 2;
   1286       uint8* dst_u;
   1287       uint8* dst_v;
   1288       if (format == FOURCC_YV16) {
   1289         dst_v = dst_sample + width * height;
   1290         dst_u = dst_v + halfwidth * height;
   1291       } else {
   1292         dst_u = dst_sample + width * height;
   1293         dst_v = dst_u + halfwidth * height;
   1294       }
   1295       r = I420ToI422(y, y_stride,
   1296                      u, u_stride,
   1297                      v, v_stride,
   1298                      dst_sample, width,
   1299                      dst_u, halfwidth,
   1300                      dst_v, halfwidth,
   1301                      width, height);
   1302       break;
   1303     }
   1304     case FOURCC_I444:
   1305     case FOURCC_YV24: {
   1306       uint8* dst_u;
   1307       uint8* dst_v;
   1308       if (format == FOURCC_YV24) {
   1309         dst_v = dst_sample + width * height;
   1310         dst_u = dst_v + width * height;
   1311       } else {
   1312         dst_u = dst_sample + width * height;
   1313         dst_v = dst_u + width * height;
   1314       }
   1315       r = I420ToI444(y, y_stride,
   1316                      u, u_stride,
   1317                      v, v_stride,
   1318                      dst_sample, width,
   1319                      dst_u, width,
   1320                      dst_v, width,
   1321                      width, height);
   1322       break;
   1323     }
   1324     case FOURCC_I411: {
   1325       int quarterwidth = (width + 3) / 4;
   1326       uint8* dst_u = dst_sample + width * height;
   1327       uint8* dst_v = dst_u + quarterwidth * height;
   1328       r = I420ToI411(y, y_stride,
   1329                      u, u_stride,
   1330                      v, v_stride,
   1331                      dst_sample, width,
   1332                      dst_u, quarterwidth,
   1333                      dst_v, quarterwidth,
   1334                      width, height);
   1335       break;
   1336     }
   1337 
   1338     // Formats not supported - MJPG, biplanar, some rgb formats.
   1339     default:
   1340       return -1;  // unknown fourcc - return failure code.
   1341   }
   1342   return r;
   1343 }
   1344 
   1345 #ifdef __cplusplus
   1346 }  // extern "C"
   1347 }  // namespace libyuv
   1348 #endif
   1349