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