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