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/video_common.h"
     20 #include "libyuv/row.h"
     21 
     22 #ifdef __cplusplus
     23 namespace libyuv {
     24 extern "C" {
     25 #endif
     26 
     27 LIBYUV_API
     28 int I420ToI422(const uint8* src_y, int src_stride_y,
     29                const uint8* src_u, int src_stride_u,
     30                const uint8* src_v, int src_stride_v,
     31                uint8* dst_y, int dst_stride_y,
     32                uint8* dst_u, int dst_stride_u,
     33                uint8* dst_v, int dst_stride_v,
     34                int width, int height) {
     35   if (!src_y || !src_u || !src_v ||
     36       !dst_y || !dst_u || !dst_v ||
     37       width <= 0 || height == 0) {
     38     return -1;
     39   }
     40   // Negative height means invert the image.
     41   if (height < 0) {
     42     height = -height;
     43     dst_y = dst_y + (height - 1) * dst_stride_y;
     44     dst_u = dst_u + (height - 1) * dst_stride_u;
     45     dst_v = dst_v + (height - 1) * dst_stride_v;
     46     dst_stride_y = -dst_stride_y;
     47     dst_stride_u = -dst_stride_u;
     48     dst_stride_v = -dst_stride_v;
     49   }
     50   int halfwidth = (width + 1) >> 1;
     51   void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
     52 #if defined(HAS_COPYROW_NEON)
     53   if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(halfwidth, 64)) {
     54     CopyRow = CopyRow_NEON;
     55   }
     56 #elif defined(HAS_COPYROW_X86)
     57   if (IS_ALIGNED(halfwidth, 4)) {
     58     CopyRow = CopyRow_X86;
     59 #if defined(HAS_COPYROW_SSE2)
     60     if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(halfwidth, 32) &&
     61         IS_ALIGNED(src_u, 16) && IS_ALIGNED(src_stride_u, 16) &&
     62         IS_ALIGNED(src_v, 16) && IS_ALIGNED(src_stride_v, 16) &&
     63         IS_ALIGNED(dst_u, 16) && IS_ALIGNED(dst_stride_u, 16) &&
     64         IS_ALIGNED(dst_v, 16) && IS_ALIGNED(dst_stride_v, 16)) {
     65       CopyRow = CopyRow_SSE2;
     66     }
     67 #endif
     68   }
     69 #endif
     70 
     71   // Copy Y plane
     72   if (dst_y) {
     73     CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
     74   }
     75 
     76   // UpSample U plane.
     77   int y;
     78   for (y = 0; y < height - 1; y += 2) {
     79     CopyRow(src_u, dst_u, halfwidth);
     80     CopyRow(src_u, dst_u + dst_stride_u, halfwidth);
     81     src_u += src_stride_u;
     82     dst_u += dst_stride_u * 2;
     83   }
     84   if (height & 1) {
     85     CopyRow(src_u, dst_u, halfwidth);
     86   }
     87 
     88   // UpSample V plane.
     89   for (y = 0; y < height - 1; y += 2) {
     90     CopyRow(src_v, dst_v, halfwidth);
     91     CopyRow(src_v, dst_v + dst_stride_v, halfwidth);
     92     src_v += src_stride_v;
     93     dst_v += dst_stride_v * 2;
     94   }
     95   if (height & 1) {
     96     CopyRow(src_v, dst_v, halfwidth);
     97   }
     98   return 0;
     99 }
    100 
    101 // use Bilinear for upsampling chroma
    102 void ScalePlaneBilinear(int src_width, int src_height,
    103                         int dst_width, int dst_height,
    104                         int src_stride, int dst_stride,
    105                         const uint8* src_ptr, uint8* dst_ptr);
    106 
    107 LIBYUV_API
    108 int I420ToI444(const uint8* src_y, int src_stride_y,
    109                const uint8* src_u, int src_stride_u,
    110                const uint8* src_v, int src_stride_v,
    111                uint8* dst_y, int dst_stride_y,
    112                uint8* dst_u, int dst_stride_u,
    113                uint8* dst_v, int dst_stride_v,
    114                int width, int height) {
    115   if (!src_y || !src_u|| !src_v ||
    116       !dst_y || !dst_u || !dst_v ||
    117       width <= 0 || height == 0) {
    118     return -1;
    119   }
    120   // Negative height means invert the image.
    121   if (height < 0) {
    122     height = -height;
    123     dst_y = dst_y + (height - 1) * dst_stride_y;
    124     dst_u = dst_u + (height - 1) * dst_stride_u;
    125     dst_v = dst_v + (height - 1) * dst_stride_v;
    126     dst_stride_y = -dst_stride_y;
    127     dst_stride_u = -dst_stride_u;
    128     dst_stride_v = -dst_stride_v;
    129   }
    130 
    131   // Copy Y plane
    132   if (dst_y) {
    133     CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
    134   }
    135 
    136   int halfwidth = (width + 1) >> 1;
    137   int halfheight = (height + 1) >> 1;
    138 
    139   // Upsample U plane.
    140   ScalePlaneBilinear(halfwidth, halfheight,
    141                      width, height,
    142                      src_stride_u,
    143                      dst_stride_u,
    144                      src_u, dst_u);
    145 
    146   // Upsample V plane.
    147   ScalePlaneBilinear(halfwidth, halfheight,
    148                      width, height,
    149                      src_stride_v,
    150                      dst_stride_v,
    151                      src_v, dst_v);
    152   return 0;
    153 }
    154 
    155 // 420 chroma is 1/2 width, 1/2 height
    156 // 411 chroma is 1/4 width, 1x height
    157 LIBYUV_API
    158 int I420ToI411(const uint8* src_y, int src_stride_y,
    159                const uint8* src_u, int src_stride_u,
    160                const uint8* src_v, int src_stride_v,
    161                uint8* dst_y, int dst_stride_y,
    162                uint8* dst_u, int dst_stride_u,
    163                uint8* dst_v, int dst_stride_v,
    164                int width, int height) {
    165   if (!src_y || !src_u || !src_v ||
    166       !dst_y || !dst_u || !dst_v ||
    167       width <= 0 || height == 0) {
    168     return -1;
    169   }
    170   // Negative height means invert the image.
    171   if (height < 0) {
    172     height = -height;
    173     dst_y = dst_y + (height - 1) * dst_stride_y;
    174     dst_u = dst_u + (height - 1) * dst_stride_u;
    175     dst_v = dst_v + (height - 1) * dst_stride_v;
    176     dst_stride_y = -dst_stride_y;
    177     dst_stride_u = -dst_stride_u;
    178     dst_stride_v = -dst_stride_v;
    179   }
    180 
    181   // Copy Y plane
    182   if (dst_y) {
    183     CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
    184   }
    185 
    186   int halfwidth = (width + 1) >> 1;
    187   int halfheight = (height + 1) >> 1;
    188   int quarterwidth = (width + 3) >> 2;
    189 
    190   // Resample U plane.
    191   ScalePlaneBilinear(halfwidth, halfheight,  // from 1/2 width, 1/2 height
    192                      quarterwidth, height,  // to 1/4 width, 1x height
    193                      src_stride_u,
    194                      dst_stride_u,
    195                      src_u, dst_u);
    196 
    197   // Resample V plane.
    198   ScalePlaneBilinear(halfwidth, halfheight,  // from 1/2 width, 1/2 height
    199                      quarterwidth, height,  // to 1/4 width, 1x height
    200                      src_stride_v,
    201                      dst_stride_v,
    202                      src_v, dst_v);
    203   return 0;
    204 }
    205 
    206 // Copy to I400. Source can be I420,422,444,400,NV12,NV21
    207 LIBYUV_API
    208 int I400Copy(const uint8* src_y, int src_stride_y,
    209              uint8* dst_y, int dst_stride_y,
    210              int width, int height) {
    211   if (!src_y || !dst_y ||
    212       width <= 0 || height == 0) {
    213     return -1;
    214   }
    215   // Negative height means invert the image.
    216   if (height < 0) {
    217     height = -height;
    218     src_y = src_y + (height - 1) * src_stride_y;
    219     src_stride_y = -src_stride_y;
    220   }
    221   CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
    222   return 0;
    223 }
    224 
    225 // YUY2 - Macro-pixel = 2 image pixels
    226 // Y0U0Y1V0....Y2U2Y3V2...Y4U4Y5V4....
    227 
    228 // UYVY - Macro-pixel = 2 image pixels
    229 // U0Y0V0Y1
    230 
    231 #if !defined(YUV_DISABLE_ASM) && defined(_M_IX86)
    232 #define HAS_I42XTOYUY2ROW_SSE2
    233 __declspec(naked) __declspec(align(16))
    234 static void I42xToYUY2Row_SSE2(const uint8* src_y,
    235                                const uint8* src_u,
    236                                const uint8* src_v,
    237                                uint8* dst_frame, int width) {
    238   __asm {
    239     push       esi
    240     push       edi
    241     mov        eax, [esp + 8 + 4]    // src_y
    242     mov        esi, [esp + 8 + 8]    // src_u
    243     mov        edx, [esp + 8 + 12]   // src_v
    244     mov        edi, [esp + 8 + 16]   // dst_frame
    245     mov        ecx, [esp + 8 + 20]   // width
    246     sub        edx, esi
    247 
    248     align      16
    249   convertloop:
    250     movq       xmm2, qword ptr [esi] // U
    251     movq       xmm3, qword ptr [esi + edx] // V
    252     lea        esi, [esi + 8]
    253     punpcklbw  xmm2, xmm3 // UV
    254     movdqa     xmm0, [eax] // Y
    255     lea        eax, [eax + 16]
    256     movdqa     xmm1, xmm0
    257     punpcklbw  xmm0, xmm2 // YUYV
    258     punpckhbw  xmm1, xmm2
    259     movdqa     [edi], xmm0
    260     movdqa     [edi + 16], xmm1
    261     lea        edi, [edi + 32]
    262     sub        ecx, 16
    263     jg         convertloop
    264 
    265     pop        edi
    266     pop        esi
    267     ret
    268   }
    269 }
    270 
    271 #define HAS_I42XTOUYVYROW_SSE2
    272 __declspec(naked) __declspec(align(16))
    273 static void I42xToUYVYRow_SSE2(const uint8* src_y,
    274                                const uint8* src_u,
    275                                const uint8* src_v,
    276                                uint8* dst_frame, int width) {
    277   __asm {
    278     push       esi
    279     push       edi
    280     mov        eax, [esp + 8 + 4]    // src_y
    281     mov        esi, [esp + 8 + 8]    // src_u
    282     mov        edx, [esp + 8 + 12]   // src_v
    283     mov        edi, [esp + 8 + 16]   // dst_frame
    284     mov        ecx, [esp + 8 + 20]   // width
    285     sub        edx, esi
    286 
    287     align      16
    288   convertloop:
    289     movq       xmm2, qword ptr [esi] // U
    290     movq       xmm3, qword ptr [esi + edx] // V
    291     lea        esi, [esi + 8]
    292     punpcklbw  xmm2, xmm3 // UV
    293     movdqa     xmm0, [eax] // Y
    294     movdqa     xmm1, xmm2
    295     lea        eax, [eax + 16]
    296     punpcklbw  xmm1, xmm0 // UYVY
    297     punpckhbw  xmm2, xmm0
    298     movdqa     [edi], xmm1
    299     movdqa     [edi + 16], xmm2
    300     lea        edi, [edi + 32]
    301     sub        ecx, 16
    302     jg         convertloop
    303 
    304     pop        edi
    305     pop        esi
    306     ret
    307   }
    308 }
    309 #elif !defined(YUV_DISABLE_ASM) && (defined(__x86_64__) || defined(__i386__))
    310 #define HAS_I42XTOYUY2ROW_SSE2
    311 static void I42xToYUY2Row_SSE2(const uint8* src_y,
    312                                const uint8* src_u,
    313                                const uint8* src_v,
    314                                uint8* dst_frame, int width) {
    315  asm volatile (
    316     "sub        %1,%2                            \n"
    317     ".p2align  4                                 \n"
    318   "1:                                            \n"
    319     "movq      (%1),%%xmm2                       \n"
    320     "movq      (%1,%2,1),%%xmm3                  \n"
    321     "lea       0x8(%1),%1                        \n"
    322     "punpcklbw %%xmm3,%%xmm2                     \n"
    323     "movdqa    (%0),%%xmm0                       \n"
    324     "lea       0x10(%0),%0                       \n"
    325     "movdqa    %%xmm0,%%xmm1                     \n"
    326     "punpcklbw %%xmm2,%%xmm0                     \n"
    327     "punpckhbw %%xmm2,%%xmm1                     \n"
    328     "movdqa    %%xmm0,(%3)                       \n"
    329     "movdqa    %%xmm1,0x10(%3)                   \n"
    330     "lea       0x20(%3),%3                       \n"
    331     "sub       $0x10,%4                          \n"
    332     "jg         1b                               \n"
    333     : "+r"(src_y),  // %0
    334       "+r"(src_u),  // %1
    335       "+r"(src_v),  // %2
    336       "+r"(dst_frame),  // %3
    337       "+rm"(width)  // %4
    338     :
    339     : "memory", "cc"
    340 #if defined(__SSE2__)
    341     , "xmm0", "xmm1", "xmm2", "xmm3"
    342 #endif
    343   );
    344 }
    345 
    346 #define HAS_I42XTOUYVYROW_SSE2
    347 static void I42xToUYVYRow_SSE2(const uint8* src_y,
    348                                const uint8* src_u,
    349                                const uint8* src_v,
    350                                uint8* dst_frame, int width) {
    351  asm volatile (
    352     "sub        %1,%2                            \n"
    353     ".p2align  4                                 \n"
    354   "1:                                            \n"
    355     "movq      (%1),%%xmm2                       \n"
    356     "movq      (%1,%2,1),%%xmm3                  \n"
    357     "lea       0x8(%1),%1                        \n"
    358     "punpcklbw %%xmm3,%%xmm2                     \n"
    359     "movdqa    (%0),%%xmm0                       \n"
    360     "movdqa    %%xmm2,%%xmm1                     \n"
    361     "lea       0x10(%0),%0                       \n"
    362     "punpcklbw %%xmm0,%%xmm1                     \n"
    363     "punpckhbw %%xmm0,%%xmm2                     \n"
    364     "movdqa    %%xmm1,(%3)                       \n"
    365     "movdqa    %%xmm2,0x10(%3)                   \n"
    366     "lea       0x20(%3),%3                       \n"
    367     "sub       $0x10,%4                          \n"
    368     "jg         1b                               \n"
    369     : "+r"(src_y),  // %0
    370       "+r"(src_u),  // %1
    371       "+r"(src_v),  // %2
    372       "+r"(dst_frame),  // %3
    373       "+rm"(width)  // %4
    374     :
    375     : "memory", "cc"
    376 #if defined(__SSE2__)
    377     , "xmm0", "xmm1", "xmm2", "xmm3"
    378 #endif
    379   );
    380 }
    381 #endif
    382 
    383 static void I42xToYUY2Row_C(const uint8* src_y,
    384                             const uint8* src_u,
    385                             const uint8* src_v,
    386                             uint8* dst_frame, int width) {
    387     for (int x = 0; x < width - 1; x += 2) {
    388       dst_frame[0] = src_y[0];
    389       dst_frame[1] = src_u[0];
    390       dst_frame[2] = src_y[1];
    391       dst_frame[3] = src_v[0];
    392       dst_frame += 4;
    393       src_y += 2;
    394       src_u += 1;
    395       src_v += 1;
    396     }
    397     if (width & 1) {
    398       dst_frame[0] = src_y[0];
    399       dst_frame[1] = src_u[0];
    400       dst_frame[2] = src_y[0];  // duplicate last y
    401       dst_frame[3] = src_v[0];
    402     }
    403 }
    404 
    405 static void I42xToUYVYRow_C(const uint8* src_y,
    406                             const uint8* src_u,
    407                             const uint8* src_v,
    408                             uint8* dst_frame, int width) {
    409     for (int x = 0; x < width - 1; x += 2) {
    410       dst_frame[0] = src_u[0];
    411       dst_frame[1] = src_y[0];
    412       dst_frame[2] = src_v[0];
    413       dst_frame[3] = src_y[1];
    414       dst_frame += 4;
    415       src_y += 2;
    416       src_u += 1;
    417       src_v += 1;
    418     }
    419     if (width & 1) {
    420       dst_frame[0] = src_u[0];
    421       dst_frame[1] = src_y[0];
    422       dst_frame[2] = src_v[0];
    423       dst_frame[3] = src_y[0];  // duplicate last y
    424     }
    425 }
    426 
    427 // Visual C x86 or GCC little endian.
    428 #if defined(__x86_64__) || defined(_M_X64) || \
    429   defined(__i386__) || defined(_M_IX86) || \
    430   defined(__arm__) || defined(_M_ARM) || \
    431   (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
    432 #define LIBYUV_LITTLE_ENDIAN
    433 #endif
    434 
    435 #ifdef LIBYUV_LITTLE_ENDIAN
    436 #define WRITEWORD(p, v) *reinterpret_cast<uint32*>(p) = v
    437 #else
    438 static inline void WRITEWORD(uint8* p, uint32 v) {
    439   p[0] = (uint8)(v & 255);
    440   p[1] = (uint8)((v >> 8) & 255);
    441   p[2] = (uint8)((v >> 16) & 255);
    442   p[3] = (uint8)((v >> 24) & 255);
    443 }
    444 #endif
    445 
    446 #define EIGHTTOTEN(x) (x << 2 | x >> 6)
    447 static void UYVYToV210Row_C(const uint8* src_uyvy, uint8* dst_v210, int width) {
    448   for (int x = 0; x < width; x += 6) {
    449     WRITEWORD(dst_v210 + 0, (EIGHTTOTEN(src_uyvy[0])) |
    450                             (EIGHTTOTEN(src_uyvy[1]) << 10) |
    451                             (EIGHTTOTEN(src_uyvy[2]) << 20));
    452     WRITEWORD(dst_v210 + 4, (EIGHTTOTEN(src_uyvy[3])) |
    453                             (EIGHTTOTEN(src_uyvy[4]) << 10) |
    454                             (EIGHTTOTEN(src_uyvy[5]) << 20));
    455     WRITEWORD(dst_v210 + 8, (EIGHTTOTEN(src_uyvy[6])) |
    456                             (EIGHTTOTEN(src_uyvy[7]) << 10) |
    457                             (EIGHTTOTEN(src_uyvy[8]) << 20));
    458     WRITEWORD(dst_v210 + 12, (EIGHTTOTEN(src_uyvy[9])) |
    459                              (EIGHTTOTEN(src_uyvy[10]) << 10) |
    460                              (EIGHTTOTEN(src_uyvy[11]) << 20));
    461     src_uyvy += 12;
    462     dst_v210 += 16;
    463   }
    464 }
    465 
    466 // TODO(fbarchard): Deprecate, move or expand 422 support?
    467 LIBYUV_API
    468 int I422ToYUY2(const uint8* src_y, int src_stride_y,
    469                const uint8* src_u, int src_stride_u,
    470                const uint8* src_v, int src_stride_v,
    471                uint8* dst_frame, int dst_stride_frame,
    472                int width, int height) {
    473   if (!src_y || !src_u || !src_v || !dst_frame ||
    474       width <= 0 || height == 0) {
    475     return -1;
    476   }
    477   // Negative height means invert the image.
    478   if (height < 0) {
    479     height = -height;
    480     dst_frame = dst_frame + (height - 1) * dst_stride_frame;
    481     dst_stride_frame = -dst_stride_frame;
    482   }
    483   void (*I42xToYUY2Row)(const uint8* src_y, const uint8* src_u,
    484                         const uint8* src_v, uint8* dst_frame, int width) =
    485       I42xToYUY2Row_C;
    486 #if defined(HAS_I42XTOYUY2ROW_SSE2)
    487   if (TestCpuFlag(kCpuHasSSE2) &&
    488       IS_ALIGNED(width, 16) &&
    489       IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
    490       IS_ALIGNED(dst_frame, 16) && IS_ALIGNED(dst_stride_frame, 16)) {
    491     I42xToYUY2Row = I42xToYUY2Row_SSE2;
    492   }
    493 #endif
    494 
    495   for (int y = 0; y < height; ++y) {
    496     I42xToYUY2Row(src_y, src_u, src_y, dst_frame, width);
    497     src_y += src_stride_y;
    498     src_u += src_stride_u;
    499     src_v += src_stride_v;
    500     dst_frame += dst_stride_frame;
    501   }
    502   return 0;
    503 }
    504 
    505 LIBYUV_API
    506 int I420ToYUY2(const uint8* src_y, int src_stride_y,
    507                const uint8* src_u, int src_stride_u,
    508                const uint8* src_v, int src_stride_v,
    509                uint8* dst_frame, int dst_stride_frame,
    510                int width, int height) {
    511   if (!src_y || !src_u || !src_v || !dst_frame ||
    512       width <= 0 || height == 0) {
    513     return -1;
    514   }
    515   // Negative height means invert the image.
    516   if (height < 0) {
    517     height = -height;
    518     dst_frame = dst_frame + (height - 1) * dst_stride_frame;
    519     dst_stride_frame = -dst_stride_frame;
    520   }
    521   void (*I42xToYUY2Row)(const uint8* src_y, const uint8* src_u,
    522                         const uint8* src_v, uint8* dst_frame, int width) =
    523       I42xToYUY2Row_C;
    524 #if defined(HAS_I42XTOYUY2ROW_SSE2)
    525   if (TestCpuFlag(kCpuHasSSE2) &&
    526       IS_ALIGNED(width, 16) &&
    527       IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
    528       IS_ALIGNED(dst_frame, 16) && IS_ALIGNED(dst_stride_frame, 16)) {
    529     I42xToYUY2Row = I42xToYUY2Row_SSE2;
    530   }
    531 #endif
    532 
    533   for (int y = 0; y < height - 1; y += 2) {
    534     I42xToYUY2Row(src_y, src_u, src_v, dst_frame, width);
    535     I42xToYUY2Row(src_y + src_stride_y, src_u, src_v,
    536                   dst_frame + dst_stride_frame, width);
    537     src_y += src_stride_y * 2;
    538     src_u += src_stride_u;
    539     src_v += src_stride_v;
    540     dst_frame += dst_stride_frame * 2;
    541   }
    542   if (height & 1) {
    543     I42xToYUY2Row(src_y, src_u, src_v, dst_frame, width);
    544   }
    545   return 0;
    546 }
    547 
    548 // TODO(fbarchard): Deprecate, move or expand 422 support?
    549 LIBYUV_API
    550 int I422ToUYVY(const uint8* src_y, int src_stride_y,
    551                const uint8* src_u, int src_stride_u,
    552                const uint8* src_v, int src_stride_v,
    553                uint8* dst_frame, int dst_stride_frame,
    554                int width, int height) {
    555   if (!src_y || !src_u || !src_v || !dst_frame ||
    556       width <= 0 || height == 0) {
    557     return -1;
    558   }
    559   // Negative height means invert the image.
    560   if (height < 0) {
    561     height = -height;
    562     dst_frame = dst_frame + (height - 1) * dst_stride_frame;
    563     dst_stride_frame = -dst_stride_frame;
    564   }
    565   void (*I42xToUYVYRow)(const uint8* src_y, const uint8* src_u,
    566                         const uint8* src_v, uint8* dst_frame, int width) =
    567       I42xToUYVYRow_C;
    568 #if defined(HAS_I42XTOUYVYROW_SSE2)
    569   if (TestCpuFlag(kCpuHasSSE2) &&
    570       IS_ALIGNED(width, 16) &&
    571       IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
    572       IS_ALIGNED(dst_frame, 16) && IS_ALIGNED(dst_stride_frame, 16)) {
    573     I42xToUYVYRow = I42xToUYVYRow_SSE2;
    574   }
    575 #endif
    576 
    577   for (int y = 0; y < height; ++y) {
    578     I42xToUYVYRow(src_y, src_u, src_y, dst_frame, width);
    579     src_y += src_stride_y;
    580     src_u += src_stride_u;
    581     src_v += src_stride_v;
    582     dst_frame += dst_stride_frame;
    583   }
    584   return 0;
    585 }
    586 
    587 LIBYUV_API
    588 int I420ToUYVY(const uint8* src_y, int src_stride_y,
    589                const uint8* src_u, int src_stride_u,
    590                const uint8* src_v, int src_stride_v,
    591                uint8* dst_frame, int dst_stride_frame,
    592                int width, int height) {
    593   if (!src_y || !src_u || !src_v || !dst_frame ||
    594       width <= 0 || height == 0) {
    595     return -1;
    596   }
    597   // Negative height means invert the image.
    598   if (height < 0) {
    599     height = -height;
    600     dst_frame = dst_frame + (height - 1) * dst_stride_frame;
    601     dst_stride_frame = -dst_stride_frame;
    602   }
    603   void (*I42xToUYVYRow)(const uint8* src_y, const uint8* src_u,
    604                         const uint8* src_v, uint8* dst_frame, int width) =
    605       I42xToUYVYRow_C;
    606 #if defined(HAS_I42XTOUYVYROW_SSE2)
    607   if (TestCpuFlag(kCpuHasSSE2) &&
    608       IS_ALIGNED(width, 16) &&
    609       IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
    610       IS_ALIGNED(dst_frame, 16) && IS_ALIGNED(dst_stride_frame, 16)) {
    611     I42xToUYVYRow = I42xToUYVYRow_SSE2;
    612   }
    613 #endif
    614 
    615   for (int y = 0; y < height - 1; y += 2) {
    616     I42xToUYVYRow(src_y, src_u, src_v, dst_frame, width);
    617     I42xToUYVYRow(src_y + src_stride_y, src_u, src_v,
    618                   dst_frame + dst_stride_frame, width);
    619     src_y += src_stride_y * 2;
    620     src_u += src_stride_u;
    621     src_v += src_stride_v;
    622     dst_frame += dst_stride_frame * 2;
    623   }
    624   if (height & 1) {
    625     I42xToUYVYRow(src_y, src_u, src_v, dst_frame, width);
    626   }
    627   return 0;
    628 }
    629 
    630 LIBYUV_API
    631 int I420ToV210(const uint8* src_y, int src_stride_y,
    632                const uint8* src_u, int src_stride_u,
    633                const uint8* src_v, int src_stride_v,
    634                uint8* dst_frame, int dst_stride_frame,
    635                int width, int height) {
    636   if (width * 16 / 6 > kMaxStride) {  // Row buffer of V210 is required.
    637     return -1;
    638   } else if (!src_y || !src_u || !src_v || !dst_frame ||
    639       width <= 0 || height == 0) {
    640     return -1;
    641   }
    642   // Negative height means invert the image.
    643   if (height < 0) {
    644     height = -height;
    645     dst_frame = dst_frame + (height - 1) * dst_stride_frame;
    646     dst_stride_frame = -dst_stride_frame;
    647   }
    648 
    649   SIMD_ALIGNED(uint8 row[kMaxStride]);
    650   void (*UYVYToV210Row)(const uint8* src_uyvy, uint8* dst_v210, int pix);
    651   UYVYToV210Row = UYVYToV210Row_C;
    652 
    653   void (*I42xToUYVYRow)(const uint8* src_y, const uint8* src_u,
    654                         const uint8* src_v, uint8* dst_frame, int width) =
    655       I42xToUYVYRow_C;
    656 #if defined(HAS_I42XTOUYVYROW_SSE2)
    657   if (TestCpuFlag(kCpuHasSSE2) &&
    658       IS_ALIGNED(width, 16) &&
    659       IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16)) {
    660     I42xToUYVYRow = I42xToUYVYRow_SSE2;
    661   }
    662 #endif
    663 
    664   for (int y = 0; y < height - 1; y += 2) {
    665     I42xToUYVYRow(src_y, src_u, src_v, row, width);
    666     UYVYToV210Row(row, dst_frame, width);
    667     I42xToUYVYRow(src_y + src_stride_y, src_u, src_v, row, width);
    668     UYVYToV210Row(row, dst_frame + dst_stride_frame, width);
    669 
    670     src_y += src_stride_y * 2;
    671     src_u += src_stride_u;
    672     src_v += src_stride_v;
    673     dst_frame += dst_stride_frame * 2;
    674   }
    675   if (height & 1) {
    676     I42xToUYVYRow(src_y, src_u, src_v, row, width);
    677     UYVYToV210Row(row, dst_frame, width);
    678   }
    679   return 0;
    680 }
    681 
    682 // Convert I420 to ARGB.
    683 LIBYUV_API
    684 int I420ToARGB(const uint8* src_y, int src_stride_y,
    685                const uint8* src_u, int src_stride_u,
    686                const uint8* src_v, int src_stride_v,
    687                uint8* dst_argb, int dst_stride_argb,
    688                int width, int height) {
    689   if (!src_y || !src_u || !src_v || !dst_argb ||
    690       width <= 0 || height == 0) {
    691     return -1;
    692   }
    693   // Negative height means invert the image.
    694   if (height < 0) {
    695     height = -height;
    696     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
    697     dst_stride_argb = -dst_stride_argb;
    698   }
    699   void (*I422ToARGBRow)(const uint8* y_buf,
    700                         const uint8* u_buf,
    701                         const uint8* v_buf,
    702                         uint8* rgb_buf,
    703                         int width) = I422ToARGBRow_C;
    704 #if defined(HAS_I422TOARGBROW_NEON)
    705   if (TestCpuFlag(kCpuHasNEON)) {
    706     I422ToARGBRow = I422ToARGBRow_Any_NEON;
    707     if (IS_ALIGNED(width, 16)) {
    708       I422ToARGBRow = I422ToARGBRow_NEON;
    709     }
    710   }
    711 #elif defined(HAS_I422TOARGBROW_SSSE3)
    712   if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
    713     I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
    714     if (IS_ALIGNED(width, 8)) {
    715       I422ToARGBRow = I422ToARGBRow_Unaligned_SSSE3;
    716       if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
    717         I422ToARGBRow = I422ToARGBRow_SSSE3;
    718       }
    719     }
    720   }
    721 #endif
    722 
    723   for (int y = 0; y < height; ++y) {
    724     I422ToARGBRow(src_y, src_u, src_v, dst_argb, width);
    725     dst_argb += dst_stride_argb;
    726     src_y += src_stride_y;
    727     if (y & 1) {
    728       src_u += src_stride_u;
    729       src_v += src_stride_v;
    730     }
    731   }
    732   return 0;
    733 }
    734 
    735 // Convert I420 to BGRA.
    736 LIBYUV_API
    737 int I420ToBGRA(const uint8* src_y, int src_stride_y,
    738                const uint8* src_u, int src_stride_u,
    739                const uint8* src_v, int src_stride_v,
    740                uint8* dst_bgra, int dst_stride_bgra,
    741                int width, int height) {
    742   if (!src_y || !src_u || !src_v ||
    743       !dst_bgra ||
    744       width <= 0 || height == 0) {
    745     return -1;
    746   }
    747   // Negative height means invert the image.
    748   if (height < 0) {
    749     height = -height;
    750     dst_bgra = dst_bgra + (height - 1) * dst_stride_bgra;
    751     dst_stride_bgra = -dst_stride_bgra;
    752   }
    753   void (*I422ToBGRARow)(const uint8* y_buf,
    754                         const uint8* u_buf,
    755                         const uint8* v_buf,
    756                         uint8* rgb_buf,
    757                         int width) = I422ToBGRARow_C;
    758 #if defined(HAS_I422TOBGRAROW_NEON)
    759   if (TestCpuFlag(kCpuHasNEON)) {
    760     I422ToBGRARow = I422ToBGRARow_Any_NEON;
    761     if (IS_ALIGNED(width, 16)) {
    762       I422ToBGRARow = I422ToBGRARow_NEON;
    763     }
    764   }
    765 #elif defined(HAS_I422TOBGRAROW_SSSE3)
    766   if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
    767     I422ToBGRARow = I422ToBGRARow_Any_SSSE3;
    768     if (IS_ALIGNED(width, 8)) {
    769       I422ToBGRARow = I422ToBGRARow_Unaligned_SSSE3;
    770       if (IS_ALIGNED(dst_bgra, 16) && IS_ALIGNED(dst_stride_bgra, 16)) {
    771         I422ToBGRARow = I422ToBGRARow_SSSE3;
    772       }
    773     }
    774   }
    775 #endif
    776 
    777   for (int y = 0; y < height; ++y) {
    778     I422ToBGRARow(src_y, src_u, src_v, dst_bgra, width);
    779     dst_bgra += dst_stride_bgra;
    780     src_y += src_stride_y;
    781     if (y & 1) {
    782       src_u += src_stride_u;
    783       src_v += src_stride_v;
    784     }
    785   }
    786   return 0;
    787 }
    788 
    789 // Convert I420 to ABGR.
    790 LIBYUV_API
    791 int I420ToABGR(const uint8* src_y, int src_stride_y,
    792                const uint8* src_u, int src_stride_u,
    793                const uint8* src_v, int src_stride_v,
    794                uint8* dst_abgr, int dst_stride_abgr,
    795                int width, int height) {
    796   if (!src_y || !src_u || !src_v ||
    797       !dst_abgr ||
    798       width <= 0 || height == 0) {
    799     return -1;
    800   }
    801   // Negative height means invert the image.
    802   if (height < 0) {
    803     height = -height;
    804     dst_abgr = dst_abgr + (height - 1) * dst_stride_abgr;
    805     dst_stride_abgr = -dst_stride_abgr;
    806   }
    807   void (*I422ToABGRRow)(const uint8* y_buf,
    808                         const uint8* u_buf,
    809                         const uint8* v_buf,
    810                         uint8* rgb_buf,
    811                         int width) = I422ToABGRRow_C;
    812 #if defined(HAS_I422TOABGRROW_NEON)
    813   if (TestCpuFlag(kCpuHasNEON)) {
    814     I422ToABGRRow = I422ToABGRRow_Any_NEON;
    815     if (IS_ALIGNED(width, 16)) {
    816       I422ToABGRRow = I422ToABGRRow_NEON;
    817     }
    818   }
    819 #elif defined(HAS_I422TOABGRROW_SSSE3)
    820   if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
    821     I422ToABGRRow = I422ToABGRRow_Any_SSSE3;
    822     if (IS_ALIGNED(width, 8)) {
    823       I422ToABGRRow = I422ToABGRRow_Unaligned_SSSE3;
    824       if (IS_ALIGNED(dst_abgr, 16) && IS_ALIGNED(dst_stride_abgr, 16)) {
    825         I422ToABGRRow = I422ToABGRRow_SSSE3;
    826       }
    827     }
    828   }
    829 #endif
    830 
    831   for (int y = 0; y < height; ++y) {
    832     I422ToABGRRow(src_y, src_u, src_v, dst_abgr, width);
    833     dst_abgr += dst_stride_abgr;
    834     src_y += src_stride_y;
    835     if (y & 1) {
    836       src_u += src_stride_u;
    837       src_v += src_stride_v;
    838     }
    839   }
    840   return 0;
    841 }
    842 
    843 // Convert I420 to RGBA.
    844 LIBYUV_API
    845 int I420ToRGBA(const uint8* src_y, int src_stride_y,
    846                const uint8* src_u, int src_stride_u,
    847                const uint8* src_v, int src_stride_v,
    848                uint8* dst_rgba, int dst_stride_rgba,
    849                int width, int height) {
    850   if (!src_y || !src_u || !src_v ||
    851       !dst_rgba ||
    852       width <= 0 || height == 0) {
    853     return -1;
    854   }
    855   // Negative height means invert the image.
    856   if (height < 0) {
    857     height = -height;
    858     dst_rgba = dst_rgba + (height - 1) * dst_stride_rgba;
    859     dst_stride_rgba = -dst_stride_rgba;
    860   }
    861   void (*I422ToRGBARow)(const uint8* y_buf,
    862                         const uint8* u_buf,
    863                         const uint8* v_buf,
    864                         uint8* rgb_buf,
    865                         int width) = I422ToRGBARow_C;
    866 #if defined(HAS_I422TORGBAROW_NEON)
    867   if (TestCpuFlag(kCpuHasNEON)) {
    868     I422ToRGBARow = I422ToRGBARow_Any_NEON;
    869     if (IS_ALIGNED(width, 16)) {
    870       I422ToRGBARow = I422ToRGBARow_NEON;
    871     }
    872   }
    873 #elif defined(HAS_I422TORGBAROW_SSSE3)
    874   if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
    875     I422ToRGBARow = I422ToRGBARow_Any_SSSE3;
    876     if (IS_ALIGNED(width, 8)) {
    877       I422ToRGBARow = I422ToRGBARow_Unaligned_SSSE3;
    878       if (IS_ALIGNED(dst_rgba, 16) && IS_ALIGNED(dst_stride_rgba, 16)) {
    879         I422ToRGBARow = I422ToRGBARow_SSSE3;
    880       }
    881     }
    882   }
    883 #endif
    884 
    885   for (int y = 0; y < height; ++y) {
    886     I422ToRGBARow(src_y, src_u, src_v, dst_rgba, width);
    887     dst_rgba += dst_stride_rgba;
    888     src_y += src_stride_y;
    889     if (y & 1) {
    890       src_u += src_stride_u;
    891       src_v += src_stride_v;
    892     }
    893   }
    894   return 0;
    895 }
    896 
    897 // Convert I420 to RGB24.
    898 LIBYUV_API
    899 int I420ToRGB24(const uint8* src_y, int src_stride_y,
    900                 const uint8* src_u, int src_stride_u,
    901                 const uint8* src_v, int src_stride_v,
    902                 uint8* dst_rgb24, int dst_stride_rgb24,
    903                 int width, int height) {
    904   if (!src_y || !src_u || !src_v ||
    905       !dst_rgb24 ||
    906       width <= 0 || height == 0) {
    907     return -1;
    908   }
    909   // Negative height means invert the image.
    910   if (height < 0) {
    911     height = -height;
    912     dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
    913     dst_stride_rgb24 = -dst_stride_rgb24;
    914   }
    915   void (*I422ToRGB24Row)(const uint8* y_buf,
    916                          const uint8* u_buf,
    917                          const uint8* v_buf,
    918                          uint8* rgb_buf,
    919                          int width) = I422ToRGB24Row_C;
    920 #if defined(HAS_I422TORGB24ROW_NEON)
    921   if (TestCpuFlag(kCpuHasNEON)) {
    922     I422ToRGB24Row = I422ToRGB24Row_Any_NEON;
    923     if (IS_ALIGNED(width, 16)) {
    924       I422ToRGB24Row = I422ToRGB24Row_NEON;
    925     }
    926   }
    927 #elif defined(HAS_I422TORGB24ROW_SSSE3)
    928   if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
    929     I422ToRGB24Row = I422ToRGB24Row_Any_SSSE3;
    930     if (IS_ALIGNED(width, 8)) {
    931       I422ToRGB24Row = I422ToRGB24Row_Unaligned_SSSE3;
    932       if (IS_ALIGNED(dst_rgb24, 16) && IS_ALIGNED(dst_stride_rgb24, 16)) {
    933         I422ToRGB24Row = I422ToRGB24Row_SSSE3;
    934       }
    935     }
    936   }
    937 #endif
    938 
    939   for (int y = 0; y < height; ++y) {
    940     I422ToRGB24Row(src_y, src_u, src_v, dst_rgb24, width);
    941     dst_rgb24 += dst_stride_rgb24;
    942     src_y += src_stride_y;
    943     if (y & 1) {
    944       src_u += src_stride_u;
    945       src_v += src_stride_v;
    946     }
    947   }
    948   return 0;
    949 }
    950 
    951 // Convert I420 to RAW.
    952 LIBYUV_API
    953 int I420ToRAW(const uint8* src_y, int src_stride_y,
    954               const uint8* src_u, int src_stride_u,
    955               const uint8* src_v, int src_stride_v,
    956               uint8* dst_raw, int dst_stride_raw,
    957               int width, int height) {
    958   if (!src_y || !src_u || !src_v ||
    959       !dst_raw ||
    960       width <= 0 || height == 0) {
    961     return -1;
    962   }
    963   // Negative height means invert the image.
    964   if (height < 0) {
    965     height = -height;
    966     dst_raw = dst_raw + (height - 1) * dst_stride_raw;
    967     dst_stride_raw = -dst_stride_raw;
    968   }
    969   void (*I422ToRAWRow)(const uint8* y_buf,
    970                        const uint8* u_buf,
    971                        const uint8* v_buf,
    972                        uint8* rgb_buf,
    973                        int width) = I422ToRAWRow_C;
    974 #if defined(HAS_I422TORAWROW_NEON)
    975   if (TestCpuFlag(kCpuHasNEON)) {
    976     I422ToRAWRow = I422ToRAWRow_Any_NEON;
    977     if (IS_ALIGNED(width, 16)) {
    978       I422ToRAWRow = I422ToRAWRow_NEON;
    979     }
    980   }
    981 #elif defined(HAS_I422TORAWROW_SSSE3)
    982   if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
    983     I422ToRAWRow = I422ToRAWRow_Any_SSSE3;
    984     if (IS_ALIGNED(width, 8)) {
    985       I422ToRAWRow = I422ToRAWRow_Unaligned_SSSE3;
    986       if (IS_ALIGNED(dst_raw, 16) && IS_ALIGNED(dst_stride_raw, 16)) {
    987         I422ToRAWRow = I422ToRAWRow_SSSE3;
    988       }
    989     }
    990   }
    991 #endif
    992 
    993   for (int y = 0; y < height; ++y) {
    994     I422ToRAWRow(src_y, src_u, src_v, dst_raw, width);
    995     dst_raw += dst_stride_raw;
    996     src_y += src_stride_y;
    997     if (y & 1) {
    998       src_u += src_stride_u;
    999       src_v += src_stride_v;
   1000     }
   1001   }
   1002   return 0;
   1003 }
   1004 
   1005 // Convert I420 to RGB565.
   1006 LIBYUV_API
   1007 int I420ToRGB565(const uint8* src_y, int src_stride_y,
   1008                  const uint8* src_u, int src_stride_u,
   1009                  const uint8* src_v, int src_stride_v,
   1010                  uint8* dst_rgb, int dst_stride_rgb,
   1011                  int width, int height) {
   1012   if (!src_y || !src_u || !src_v ||
   1013       !dst_rgb ||
   1014       width <= 0 || height == 0) {
   1015     return -1;
   1016   }
   1017   // Negative height means invert the image.
   1018   if (height < 0) {
   1019     height = -height;
   1020     dst_rgb = dst_rgb + (height - 1) * dst_stride_rgb;
   1021     dst_stride_rgb = -dst_stride_rgb;
   1022   }
   1023   void (*I422ToARGBRow)(const uint8* y_buf,
   1024                         const uint8* u_buf,
   1025                         const uint8* v_buf,
   1026                         uint8* rgb_buf,
   1027                         int width) = I422ToARGBRow_C;
   1028 #if defined(HAS_I422TOARGBROW_NEON)
   1029   if (TestCpuFlag(kCpuHasNEON)) {
   1030     I422ToARGBRow = I422ToARGBRow_NEON;
   1031   }
   1032 #elif defined(HAS_I422TOARGBROW_SSSE3)
   1033   if (TestCpuFlag(kCpuHasSSSE3)) {
   1034     I422ToARGBRow = I422ToARGBRow_SSSE3;
   1035   }
   1036 #endif
   1037 
   1038   SIMD_ALIGNED(uint8 row[kMaxStride]);
   1039   void (*ARGBToRGB565Row)(const uint8* src_rgb, uint8* dst_rgb, int pix) =
   1040       ARGBToRGB565Row_C;
   1041 #if defined(HAS_ARGBTORGB565ROW_SSE2)
   1042   if (TestCpuFlag(kCpuHasSSE2)) {
   1043     if (width * 2 <= kMaxStride) {
   1044       ARGBToRGB565Row = ARGBToRGB565Row_Any_SSE2;
   1045     }
   1046     if (IS_ALIGNED(width, 4)) {
   1047       ARGBToRGB565Row = ARGBToRGB565Row_SSE2;
   1048     }
   1049   }
   1050 #endif
   1051 
   1052   for (int y = 0; y < height; ++y) {
   1053     I422ToARGBRow(src_y, src_u, src_v, row, width);
   1054     ARGBToRGB565Row(row, dst_rgb, width);
   1055     dst_rgb += dst_stride_rgb;
   1056     src_y += src_stride_y;
   1057     if (y & 1) {
   1058       src_u += src_stride_u;
   1059       src_v += src_stride_v;
   1060     }
   1061   }
   1062   return 0;
   1063 }
   1064 
   1065 // Convert I420 to ARGB1555.
   1066 LIBYUV_API
   1067 int I420ToARGB1555(const uint8* src_y, int src_stride_y,
   1068                    const uint8* src_u, int src_stride_u,
   1069                    const uint8* src_v, int src_stride_v,
   1070                    uint8* dst_argb, int dst_stride_argb,
   1071                    int width, int height) {
   1072   if (!src_y || !src_u || !src_v ||
   1073       !dst_argb ||
   1074       width <= 0 || height == 0) {
   1075     return -1;
   1076   }
   1077   // Negative height means invert the image.
   1078   if (height < 0) {
   1079     height = -height;
   1080     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
   1081     dst_stride_argb = -dst_stride_argb;
   1082   }
   1083   void (*I422ToARGBRow)(const uint8* y_buf,
   1084                         const uint8* u_buf,
   1085                         const uint8* v_buf,
   1086                         uint8* rgb_buf,
   1087                         int width) = I422ToARGBRow_C;
   1088 #if defined(HAS_I422TOARGBROW_NEON)
   1089   if (TestCpuFlag(kCpuHasNEON)) {
   1090     I422ToARGBRow = I422ToARGBRow_NEON;
   1091   }
   1092 #elif defined(HAS_I422TOARGBROW_SSSE3)
   1093   if (TestCpuFlag(kCpuHasSSSE3)) {
   1094     I422ToARGBRow = I422ToARGBRow_SSSE3;
   1095   }
   1096 #endif
   1097 
   1098   SIMD_ALIGNED(uint8 row[kMaxStride]);
   1099   void (*ARGBToARGB1555Row)(const uint8* src_argb, uint8* dst_rgb, int pix) =
   1100       ARGBToARGB1555Row_C;
   1101 #if defined(HAS_ARGBTOARGB1555ROW_SSE2)
   1102   if (TestCpuFlag(kCpuHasSSE2)) {
   1103     if (width * 2 <= kMaxStride) {
   1104       ARGBToARGB1555Row = ARGBToARGB1555Row_Any_SSE2;
   1105     }
   1106     if (IS_ALIGNED(width, 4)) {
   1107       ARGBToARGB1555Row = ARGBToARGB1555Row_SSE2;
   1108     }
   1109   }
   1110 #endif
   1111 
   1112   for (int y = 0; y < height; ++y) {
   1113     I422ToARGBRow(src_y, src_u, src_v, row, width);
   1114     ARGBToARGB1555Row(row, dst_argb, width);
   1115     dst_argb += dst_stride_argb;
   1116     src_y += src_stride_y;
   1117     if (y & 1) {
   1118       src_u += src_stride_u;
   1119       src_v += src_stride_v;
   1120     }
   1121   }
   1122   return 0;
   1123 }
   1124 
   1125 // Convert I420 to ARGB4444.
   1126 LIBYUV_API
   1127 int I420ToARGB4444(const uint8* src_y, int src_stride_y,
   1128                    const uint8* src_u, int src_stride_u,
   1129                    const uint8* src_v, int src_stride_v,
   1130                    uint8* dst_argb, int dst_stride_argb,
   1131                    int width, int height) {
   1132   if (!src_y || !src_u || !src_v ||
   1133       !dst_argb ||
   1134       width <= 0 || height == 0) {
   1135     return -1;
   1136   }
   1137   // Negative height means invert the image.
   1138   if (height < 0) {
   1139     height = -height;
   1140     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
   1141     dst_stride_argb = -dst_stride_argb;
   1142   }
   1143   void (*I422ToARGBRow)(const uint8* y_buf,
   1144                         const uint8* u_buf,
   1145                         const uint8* v_buf,
   1146                         uint8* rgb_buf,
   1147                         int width) = I422ToARGBRow_C;
   1148 #if defined(HAS_I422TOARGBROW_NEON)
   1149   if (TestCpuFlag(kCpuHasNEON)) {
   1150     I422ToARGBRow = I422ToARGBRow_NEON;
   1151   }
   1152 #elif defined(HAS_I422TOARGBROW_SSSE3)
   1153   if (TestCpuFlag(kCpuHasSSSE3)) {
   1154     I422ToARGBRow = I422ToARGBRow_SSSE3;
   1155   }
   1156 #endif
   1157 
   1158   SIMD_ALIGNED(uint8 row[kMaxStride]);
   1159   void (*ARGBToARGB4444Row)(const uint8* src_argb, uint8* dst_rgb, int pix) =
   1160      ARGBToARGB4444Row_C;
   1161 #if defined(HAS_ARGBTOARGB4444ROW_SSE2)
   1162   if (TestCpuFlag(kCpuHasSSE2)) {
   1163     if (width * 2 <= kMaxStride) {
   1164       ARGBToARGB4444Row = ARGBToARGB4444Row_Any_SSE2;
   1165     }
   1166     if (IS_ALIGNED(width, 4)) {
   1167       ARGBToARGB4444Row = ARGBToARGB4444Row_SSE2;
   1168     }
   1169   }
   1170 #endif
   1171 
   1172   for (int y = 0; y < height; ++y) {
   1173     I422ToARGBRow(src_y, src_u, src_v, row, width);
   1174     ARGBToARGB4444Row(row, dst_argb, width);
   1175     dst_argb += dst_stride_argb;
   1176     src_y += src_stride_y;
   1177     if (y & 1) {
   1178       src_u += src_stride_u;
   1179       src_v += src_stride_v;
   1180     }
   1181   }
   1182   return 0;
   1183 }
   1184 
   1185 // Convert I420 to specified format
   1186 LIBYUV_API
   1187 int ConvertFromI420(const uint8* y, int y_stride,
   1188                     const uint8* u, int u_stride,
   1189                     const uint8* v, int v_stride,
   1190                     uint8* dst_sample, int dst_sample_stride,
   1191                     int width, int height,
   1192                     uint32 format) {
   1193   if (!y || !u|| !v || !dst_sample ||
   1194       width <= 0 || height == 0) {
   1195     return -1;
   1196   }
   1197   int r = 0;
   1198   switch (format) {
   1199     // Single plane formats
   1200     case FOURCC_YUY2:
   1201       r = I420ToYUY2(y, y_stride,
   1202                      u, u_stride,
   1203                      v, v_stride,
   1204                      dst_sample,
   1205                      dst_sample_stride ? dst_sample_stride : width * 2,
   1206                      width, height);
   1207       break;
   1208     case FOURCC_UYVY:
   1209       r = I420ToUYVY(y, y_stride,
   1210                      u, u_stride,
   1211                      v, v_stride,
   1212                      dst_sample,
   1213                      dst_sample_stride ? dst_sample_stride : width * 2,
   1214                      width, height);
   1215       break;
   1216     case FOURCC_V210:
   1217       r = I420ToV210(y, y_stride,
   1218                      u, u_stride,
   1219                      v, v_stride,
   1220                      dst_sample,
   1221                      dst_sample_stride ? dst_sample_stride :
   1222                          (width + 47) / 48 * 128,
   1223                      width, height);
   1224       break;
   1225     case FOURCC_RGBP:
   1226       r = I420ToRGB565(y, y_stride,
   1227                        u, u_stride,
   1228                        v, v_stride,
   1229                        dst_sample,
   1230                        dst_sample_stride ? dst_sample_stride : width * 2,
   1231                        width, height);
   1232       break;
   1233     case FOURCC_RGBO:
   1234       r = I420ToARGB1555(y, y_stride,
   1235                          u, u_stride,
   1236                          v, v_stride,
   1237                          dst_sample,
   1238                          dst_sample_stride ? dst_sample_stride : width * 2,
   1239                          width, height);
   1240       break;
   1241     case FOURCC_R444:
   1242       r = I420ToARGB4444(y, y_stride,
   1243                          u, u_stride,
   1244                          v, v_stride,
   1245                          dst_sample,
   1246                          dst_sample_stride ? dst_sample_stride : width * 2,
   1247                          width, height);
   1248       break;
   1249     case FOURCC_24BG:
   1250       r = I420ToRGB24(y, y_stride,
   1251                       u, u_stride,
   1252                       v, v_stride,
   1253                       dst_sample,
   1254                       dst_sample_stride ? dst_sample_stride : width * 3,
   1255                       width, height);
   1256       break;
   1257     case FOURCC_RAW:
   1258       r = I420ToRAW(y, y_stride,
   1259                     u, u_stride,
   1260                     v, v_stride,
   1261                     dst_sample,
   1262                     dst_sample_stride ? dst_sample_stride : width * 3,
   1263                     width, height);
   1264       break;
   1265     case FOURCC_ARGB:
   1266       r = I420ToARGB(y, y_stride,
   1267                      u, u_stride,
   1268                      v, v_stride,
   1269                      dst_sample,
   1270                      dst_sample_stride ? dst_sample_stride : width * 4,
   1271                      width, height);
   1272       break;
   1273     case FOURCC_BGRA:
   1274       r = I420ToBGRA(y, y_stride,
   1275                      u, u_stride,
   1276                      v, v_stride,
   1277                      dst_sample,
   1278                      dst_sample_stride ? dst_sample_stride : width * 4,
   1279                      width, height);
   1280       break;
   1281     case FOURCC_ABGR:
   1282       r = I420ToABGR(y, y_stride,
   1283                      u, u_stride,
   1284                      v, v_stride,
   1285                      dst_sample,
   1286                      dst_sample_stride ? dst_sample_stride : width * 4,
   1287                      width, height);
   1288       break;
   1289     case FOURCC_RGBA:
   1290       r = I420ToRGBA(y, y_stride,
   1291                      u, u_stride,
   1292                      v, v_stride,
   1293                      dst_sample,
   1294                      dst_sample_stride ? dst_sample_stride : width * 4,
   1295                      width, height);
   1296       break;
   1297     case FOURCC_BGGR:
   1298       r = I420ToBayerBGGR(y, y_stride,
   1299                           u, u_stride,
   1300                           v, v_stride,
   1301                           dst_sample,
   1302                           dst_sample_stride ? dst_sample_stride : width,
   1303                           width, height);
   1304       break;
   1305     case FOURCC_GBRG:
   1306       r = I420ToBayerGBRG(y, y_stride,
   1307                           u, u_stride,
   1308                           v, v_stride,
   1309                           dst_sample,
   1310                           dst_sample_stride ? dst_sample_stride : width,
   1311                           width, height);
   1312       break;
   1313     case FOURCC_GRBG:
   1314       r = I420ToBayerGRBG(y, y_stride,
   1315                           u, u_stride,
   1316                           v, v_stride,
   1317                           dst_sample,
   1318                           dst_sample_stride ? dst_sample_stride : width,
   1319                           width, height);
   1320       break;
   1321     case FOURCC_RGGB:
   1322       r = I420ToBayerRGGB(y, y_stride,
   1323                           u, u_stride,
   1324                           v, v_stride,
   1325                           dst_sample,
   1326                           dst_sample_stride ? dst_sample_stride : width,
   1327                           width, height);
   1328       break;
   1329     case FOURCC_I400:
   1330       r = I400Copy(y, y_stride,
   1331                    dst_sample,
   1332                    dst_sample_stride ? dst_sample_stride : width,
   1333                    width, height);
   1334       break;
   1335     // Triplanar formats
   1336     // TODO(fbarchard): halfstride instead of halfwidth
   1337     case FOURCC_I420:
   1338     case FOURCC_YU12:
   1339     case FOURCC_YV12: {
   1340       int halfwidth = (width + 1) / 2;
   1341       int halfheight = (height + 1) / 2;
   1342       uint8* dst_u;
   1343       uint8* dst_v;
   1344       if (format == FOURCC_YV12) {
   1345         dst_v = dst_sample + width * height;
   1346         dst_u = dst_v + halfwidth * halfheight;
   1347       } else {
   1348         dst_u = dst_sample + width * height;
   1349         dst_v = dst_u + halfwidth * halfheight;
   1350       }
   1351       r = I420Copy(y, y_stride,
   1352                    u, u_stride,
   1353                    v, v_stride,
   1354                    dst_sample, width,
   1355                    dst_u, halfwidth,
   1356                    dst_v, halfwidth,
   1357                    width, height);
   1358       break;
   1359     }
   1360     case FOURCC_I422:
   1361     case FOURCC_YV16: {
   1362       int halfwidth = (width + 1) / 2;
   1363       uint8* dst_u;
   1364       uint8* dst_v;
   1365       if (format == FOURCC_YV16) {
   1366         dst_v = dst_sample + width * height;
   1367         dst_u = dst_v + halfwidth * height;
   1368       } else {
   1369         dst_u = dst_sample + width * height;
   1370         dst_v = dst_u + halfwidth * height;
   1371       }
   1372       r = I420ToI422(y, y_stride,
   1373                      u, u_stride,
   1374                      v, v_stride,
   1375                      dst_sample, width,
   1376                      dst_u, halfwidth,
   1377                      dst_v, halfwidth,
   1378                      width, height);
   1379       break;
   1380     }
   1381     case FOURCC_I444:
   1382     case FOURCC_YV24: {
   1383       uint8* dst_u;
   1384       uint8* dst_v;
   1385       if (format == FOURCC_YV24) {
   1386         dst_v = dst_sample + width * height;
   1387         dst_u = dst_v + width * height;
   1388       } else {
   1389         dst_u = dst_sample + width * height;
   1390         dst_v = dst_u + width * height;
   1391       }
   1392       r = I420ToI444(y, y_stride,
   1393                      u, u_stride,
   1394                      v, v_stride,
   1395                      dst_sample, width,
   1396                      dst_u, width,
   1397                      dst_v, width,
   1398                      width, height);
   1399       break;
   1400     }
   1401     case FOURCC_I411: {
   1402       int quarterwidth = (width + 3) / 4;
   1403       uint8* dst_u = dst_sample + width * height;
   1404       uint8* dst_v = dst_u + quarterwidth * height;
   1405       r = I420ToI411(y, y_stride,
   1406                      u, u_stride,
   1407                      v, v_stride,
   1408                      dst_sample, width,
   1409                      dst_u, quarterwidth,
   1410                      dst_v, quarterwidth,
   1411                      width, height);
   1412       break;
   1413     }
   1414 
   1415     // Formats not supported - MJPG, biplanar, some rgb formats.
   1416     default:
   1417       return -1;  // unknown fourcc - return failure code.
   1418   }
   1419   return r;
   1420 }
   1421 
   1422 #ifdef __cplusplus
   1423 }  // extern "C"
   1424 }  // namespace libyuv
   1425 #endif
   1426