Home | History | Annotate | Download | only in source
      1 /*
      2  *  Copyright 2011 The LibYuv Project Authors. All rights reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS. All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include "libyuv/convert_argb.h"
     12 
     13 #include "libyuv/cpu_id.h"
     14 #ifdef HAVE_JPEG
     15 #include "libyuv/mjpeg_decoder.h"
     16 #endif
     17 #include "libyuv/planar_functions.h"  // For CopyPlane and ARGBShuffle.
     18 #include "libyuv/rotate_argb.h"
     19 #include "libyuv/row.h"
     20 #include "libyuv/video_common.h"
     21 
     22 #ifdef __cplusplus
     23 namespace libyuv {
     24 extern "C" {
     25 #endif
     26 
     27 // Copy ARGB with optional flipping
     28 LIBYUV_API
     29 int ARGBCopy(const uint8_t* src_argb,
     30              int src_stride_argb,
     31              uint8_t* dst_argb,
     32              int dst_stride_argb,
     33              int width,
     34              int height) {
     35   if (!src_argb || !dst_argb || width <= 0 || height == 0) {
     36     return -1;
     37   }
     38   // Negative height means invert the image.
     39   if (height < 0) {
     40     height = -height;
     41     src_argb = src_argb + (height - 1) * src_stride_argb;
     42     src_stride_argb = -src_stride_argb;
     43   }
     44 
     45   CopyPlane(src_argb, src_stride_argb, dst_argb, dst_stride_argb, width * 4,
     46             height);
     47   return 0;
     48 }
     49 
     50 // Convert I420 to ARGB with matrix
     51 static int I420ToARGBMatrix(const uint8_t* src_y,
     52                             int src_stride_y,
     53                             const uint8_t* src_u,
     54                             int src_stride_u,
     55                             const uint8_t* src_v,
     56                             int src_stride_v,
     57                             uint8_t* dst_argb,
     58                             int dst_stride_argb,
     59                             const struct YuvConstants* yuvconstants,
     60                             int width,
     61                             int height) {
     62   int y;
     63   void (*I422ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
     64                         const uint8_t* v_buf, uint8_t* rgb_buf,
     65                         const struct YuvConstants* yuvconstants, int width) =
     66       I422ToARGBRow_C;
     67   if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
     68     return -1;
     69   }
     70   // Negative height means invert the image.
     71   if (height < 0) {
     72     height = -height;
     73     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
     74     dst_stride_argb = -dst_stride_argb;
     75   }
     76 #if defined(HAS_I422TOARGBROW_SSSE3)
     77   if (TestCpuFlag(kCpuHasSSSE3)) {
     78     I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
     79     if (IS_ALIGNED(width, 8)) {
     80       I422ToARGBRow = I422ToARGBRow_SSSE3;
     81     }
     82   }
     83 #endif
     84 #if defined(HAS_I422TOARGBROW_AVX2)
     85   if (TestCpuFlag(kCpuHasAVX2)) {
     86     I422ToARGBRow = I422ToARGBRow_Any_AVX2;
     87     if (IS_ALIGNED(width, 16)) {
     88       I422ToARGBRow = I422ToARGBRow_AVX2;
     89     }
     90   }
     91 #endif
     92 #if defined(HAS_I422TOARGBROW_NEON)
     93   if (TestCpuFlag(kCpuHasNEON)) {
     94     I422ToARGBRow = I422ToARGBRow_Any_NEON;
     95     if (IS_ALIGNED(width, 8)) {
     96       I422ToARGBRow = I422ToARGBRow_NEON;
     97     }
     98   }
     99 #endif
    100 #if defined(HAS_I422TOARGBROW_MSA)
    101   if (TestCpuFlag(kCpuHasMSA)) {
    102     I422ToARGBRow = I422ToARGBRow_Any_MSA;
    103     if (IS_ALIGNED(width, 8)) {
    104       I422ToARGBRow = I422ToARGBRow_MSA;
    105     }
    106   }
    107 #endif
    108 
    109   for (y = 0; y < height; ++y) {
    110     I422ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
    111     dst_argb += dst_stride_argb;
    112     src_y += src_stride_y;
    113     if (y & 1) {
    114       src_u += src_stride_u;
    115       src_v += src_stride_v;
    116     }
    117   }
    118   return 0;
    119 }
    120 
    121 // Convert I420 to ARGB.
    122 LIBYUV_API
    123 int I420ToARGB(const uint8_t* src_y,
    124                int src_stride_y,
    125                const uint8_t* src_u,
    126                int src_stride_u,
    127                const uint8_t* src_v,
    128                int src_stride_v,
    129                uint8_t* dst_argb,
    130                int dst_stride_argb,
    131                int width,
    132                int height) {
    133   return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
    134                           src_stride_v, dst_argb, dst_stride_argb,
    135                           &kYuvI601Constants, width, height);
    136 }
    137 
    138 // Convert I420 to ABGR.
    139 LIBYUV_API
    140 int I420ToABGR(const uint8_t* src_y,
    141                int src_stride_y,
    142                const uint8_t* src_u,
    143                int src_stride_u,
    144                const uint8_t* src_v,
    145                int src_stride_v,
    146                uint8_t* dst_abgr,
    147                int dst_stride_abgr,
    148                int width,
    149                int height) {
    150   return I420ToARGBMatrix(src_y, src_stride_y, src_v,
    151                           src_stride_v,  // Swap U and V
    152                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
    153                           &kYvuI601Constants,  // Use Yvu matrix
    154                           width, height);
    155 }
    156 
    157 // Convert J420 to ARGB.
    158 LIBYUV_API
    159 int J420ToARGB(const uint8_t* src_y,
    160                int src_stride_y,
    161                const uint8_t* src_u,
    162                int src_stride_u,
    163                const uint8_t* src_v,
    164                int src_stride_v,
    165                uint8_t* dst_argb,
    166                int dst_stride_argb,
    167                int width,
    168                int height) {
    169   return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
    170                           src_stride_v, dst_argb, dst_stride_argb,
    171                           &kYuvJPEGConstants, width, height);
    172 }
    173 
    174 // Convert J420 to ABGR.
    175 LIBYUV_API
    176 int J420ToABGR(const uint8_t* src_y,
    177                int src_stride_y,
    178                const uint8_t* src_u,
    179                int src_stride_u,
    180                const uint8_t* src_v,
    181                int src_stride_v,
    182                uint8_t* dst_abgr,
    183                int dst_stride_abgr,
    184                int width,
    185                int height) {
    186   return I420ToARGBMatrix(src_y, src_stride_y, src_v,
    187                           src_stride_v,  // Swap U and V
    188                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
    189                           &kYvuJPEGConstants,  // Use Yvu matrix
    190                           width, height);
    191 }
    192 
    193 // Convert H420 to ARGB.
    194 LIBYUV_API
    195 int H420ToARGB(const uint8_t* src_y,
    196                int src_stride_y,
    197                const uint8_t* src_u,
    198                int src_stride_u,
    199                const uint8_t* src_v,
    200                int src_stride_v,
    201                uint8_t* dst_argb,
    202                int dst_stride_argb,
    203                int width,
    204                int height) {
    205   return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
    206                           src_stride_v, dst_argb, dst_stride_argb,
    207                           &kYuvH709Constants, width, height);
    208 }
    209 
    210 // Convert H420 to ABGR.
    211 LIBYUV_API
    212 int H420ToABGR(const uint8_t* src_y,
    213                int src_stride_y,
    214                const uint8_t* src_u,
    215                int src_stride_u,
    216                const uint8_t* src_v,
    217                int src_stride_v,
    218                uint8_t* dst_abgr,
    219                int dst_stride_abgr,
    220                int width,
    221                int height) {
    222   return I420ToARGBMatrix(src_y, src_stride_y, src_v,
    223                           src_stride_v,  // Swap U and V
    224                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
    225                           &kYvuH709Constants,  // Use Yvu matrix
    226                           width, height);
    227 }
    228 
    229 // Convert I422 to ARGB with matrix
    230 static int I422ToARGBMatrix(const uint8_t* src_y,
    231                             int src_stride_y,
    232                             const uint8_t* src_u,
    233                             int src_stride_u,
    234                             const uint8_t* src_v,
    235                             int src_stride_v,
    236                             uint8_t* dst_argb,
    237                             int dst_stride_argb,
    238                             const struct YuvConstants* yuvconstants,
    239                             int width,
    240                             int height) {
    241   int y;
    242   void (*I422ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
    243                         const uint8_t* v_buf, uint8_t* rgb_buf,
    244                         const struct YuvConstants* yuvconstants, int width) =
    245       I422ToARGBRow_C;
    246   if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
    247     return -1;
    248   }
    249   // Negative height means invert the image.
    250   if (height < 0) {
    251     height = -height;
    252     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
    253     dst_stride_argb = -dst_stride_argb;
    254   }
    255   // Coalesce rows.
    256   if (src_stride_y == width && src_stride_u * 2 == width &&
    257       src_stride_v * 2 == width && dst_stride_argb == width * 4) {
    258     width *= height;
    259     height = 1;
    260     src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
    261   }
    262 #if defined(HAS_I422TOARGBROW_SSSE3)
    263   if (TestCpuFlag(kCpuHasSSSE3)) {
    264     I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
    265     if (IS_ALIGNED(width, 8)) {
    266       I422ToARGBRow = I422ToARGBRow_SSSE3;
    267     }
    268   }
    269 #endif
    270 #if defined(HAS_I422TOARGBROW_AVX2)
    271   if (TestCpuFlag(kCpuHasAVX2)) {
    272     I422ToARGBRow = I422ToARGBRow_Any_AVX2;
    273     if (IS_ALIGNED(width, 16)) {
    274       I422ToARGBRow = I422ToARGBRow_AVX2;
    275     }
    276   }
    277 #endif
    278 #if defined(HAS_I422TOARGBROW_NEON)
    279   if (TestCpuFlag(kCpuHasNEON)) {
    280     I422ToARGBRow = I422ToARGBRow_Any_NEON;
    281     if (IS_ALIGNED(width, 8)) {
    282       I422ToARGBRow = I422ToARGBRow_NEON;
    283     }
    284   }
    285 #endif
    286 #if defined(HAS_I422TOARGBROW_MSA)
    287   if (TestCpuFlag(kCpuHasMSA)) {
    288     I422ToARGBRow = I422ToARGBRow_Any_MSA;
    289     if (IS_ALIGNED(width, 8)) {
    290       I422ToARGBRow = I422ToARGBRow_MSA;
    291     }
    292   }
    293 #endif
    294 
    295   for (y = 0; y < height; ++y) {
    296     I422ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
    297     dst_argb += dst_stride_argb;
    298     src_y += src_stride_y;
    299     src_u += src_stride_u;
    300     src_v += src_stride_v;
    301   }
    302   return 0;
    303 }
    304 
    305 // Convert I422 to ARGB.
    306 LIBYUV_API
    307 int I422ToARGB(const uint8_t* src_y,
    308                int src_stride_y,
    309                const uint8_t* src_u,
    310                int src_stride_u,
    311                const uint8_t* src_v,
    312                int src_stride_v,
    313                uint8_t* dst_argb,
    314                int dst_stride_argb,
    315                int width,
    316                int height) {
    317   return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
    318                           src_stride_v, dst_argb, dst_stride_argb,
    319                           &kYuvI601Constants, width, height);
    320 }
    321 
    322 // Convert I422 to ABGR.
    323 LIBYUV_API
    324 int I422ToABGR(const uint8_t* src_y,
    325                int src_stride_y,
    326                const uint8_t* src_u,
    327                int src_stride_u,
    328                const uint8_t* src_v,
    329                int src_stride_v,
    330                uint8_t* dst_abgr,
    331                int dst_stride_abgr,
    332                int width,
    333                int height) {
    334   return I422ToARGBMatrix(src_y, src_stride_y, src_v,
    335                           src_stride_v,  // Swap U and V
    336                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
    337                           &kYvuI601Constants,  // Use Yvu matrix
    338                           width, height);
    339 }
    340 
    341 // Convert J422 to ARGB.
    342 LIBYUV_API
    343 int J422ToARGB(const uint8_t* src_y,
    344                int src_stride_y,
    345                const uint8_t* src_u,
    346                int src_stride_u,
    347                const uint8_t* src_v,
    348                int src_stride_v,
    349                uint8_t* dst_argb,
    350                int dst_stride_argb,
    351                int width,
    352                int height) {
    353   return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
    354                           src_stride_v, dst_argb, dst_stride_argb,
    355                           &kYuvJPEGConstants, width, height);
    356 }
    357 
    358 // Convert J422 to ABGR.
    359 LIBYUV_API
    360 int J422ToABGR(const uint8_t* src_y,
    361                int src_stride_y,
    362                const uint8_t* src_u,
    363                int src_stride_u,
    364                const uint8_t* src_v,
    365                int src_stride_v,
    366                uint8_t* dst_abgr,
    367                int dst_stride_abgr,
    368                int width,
    369                int height) {
    370   return I422ToARGBMatrix(src_y, src_stride_y, src_v,
    371                           src_stride_v,  // Swap U and V
    372                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
    373                           &kYvuJPEGConstants,  // Use Yvu matrix
    374                           width, height);
    375 }
    376 
    377 // Convert H422 to ARGB.
    378 LIBYUV_API
    379 int H422ToARGB(const uint8_t* src_y,
    380                int src_stride_y,
    381                const uint8_t* src_u,
    382                int src_stride_u,
    383                const uint8_t* src_v,
    384                int src_stride_v,
    385                uint8_t* dst_argb,
    386                int dst_stride_argb,
    387                int width,
    388                int height) {
    389   return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
    390                           src_stride_v, dst_argb, dst_stride_argb,
    391                           &kYuvH709Constants, width, height);
    392 }
    393 
    394 // Convert H422 to ABGR.
    395 LIBYUV_API
    396 int H422ToABGR(const uint8_t* src_y,
    397                int src_stride_y,
    398                const uint8_t* src_u,
    399                int src_stride_u,
    400                const uint8_t* src_v,
    401                int src_stride_v,
    402                uint8_t* dst_abgr,
    403                int dst_stride_abgr,
    404                int width,
    405                int height) {
    406   return I422ToARGBMatrix(src_y, src_stride_y, src_v,
    407                           src_stride_v,  // Swap U and V
    408                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
    409                           &kYvuH709Constants,  // Use Yvu matrix
    410                           width, height);
    411 }
    412 
    413 // Convert 10 bit YUV to ARGB with matrix
    414 // TODO(fbarchard): Consider passing scale multiplier to I210ToARGB to
    415 // multiply 10 bit yuv into high bits to allow any number of bits.
    416 static int I010ToAR30Matrix(const uint16_t* src_y,
    417                             int src_stride_y,
    418                             const uint16_t* src_u,
    419                             int src_stride_u,
    420                             const uint16_t* src_v,
    421                             int src_stride_v,
    422                             uint8_t* dst_ar30,
    423                             int dst_stride_ar30,
    424                             const struct YuvConstants* yuvconstants,
    425                             int width,
    426                             int height) {
    427   int y;
    428   void (*I210ToAR30Row)(const uint16_t* y_buf, const uint16_t* u_buf,
    429                         const uint16_t* v_buf, uint8_t* rgb_buf,
    430                         const struct YuvConstants* yuvconstants, int width) =
    431       I210ToAR30Row_C;
    432   if (!src_y || !src_u || !src_v || !dst_ar30 || width <= 0 || height == 0) {
    433     return -1;
    434   }
    435   // Negative height means invert the image.
    436   if (height < 0) {
    437     height = -height;
    438     dst_ar30 = dst_ar30 + (height - 1) * dst_stride_ar30;
    439     dst_stride_ar30 = -dst_stride_ar30;
    440   }
    441 #if defined(HAS_I210TOAR30ROW_SSSE3)
    442   if (TestCpuFlag(kCpuHasSSSE3)) {
    443     I210ToAR30Row = I210ToAR30Row_Any_SSSE3;
    444     if (IS_ALIGNED(width, 8)) {
    445       I210ToAR30Row = I210ToAR30Row_SSSE3;
    446     }
    447   }
    448 #endif
    449 #if defined(HAS_I210TOAR30ROW_AVX2)
    450   if (TestCpuFlag(kCpuHasAVX2)) {
    451     I210ToAR30Row = I210ToAR30Row_Any_AVX2;
    452     if (IS_ALIGNED(width, 16)) {
    453       I210ToAR30Row = I210ToAR30Row_AVX2;
    454     }
    455   }
    456 #endif
    457   for (y = 0; y < height; ++y) {
    458     I210ToAR30Row(src_y, src_u, src_v, dst_ar30, yuvconstants, width);
    459     dst_ar30 += dst_stride_ar30;
    460     src_y += src_stride_y;
    461     if (y & 1) {
    462       src_u += src_stride_u;
    463       src_v += src_stride_v;
    464     }
    465   }
    466   return 0;
    467 }
    468 
    469 // Convert I010 to AR30.
    470 LIBYUV_API
    471 int I010ToAR30(const uint16_t* src_y,
    472                int src_stride_y,
    473                const uint16_t* src_u,
    474                int src_stride_u,
    475                const uint16_t* src_v,
    476                int src_stride_v,
    477                uint8_t* dst_ar30,
    478                int dst_stride_ar30,
    479                int width,
    480                int height) {
    481   return I010ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
    482                           src_stride_v, dst_ar30, dst_stride_ar30,
    483                           &kYuvI601Constants, width, height);
    484 }
    485 
    486 // Convert H010 to AR30.
    487 LIBYUV_API
    488 int H010ToAR30(const uint16_t* src_y,
    489                int src_stride_y,
    490                const uint16_t* src_u,
    491                int src_stride_u,
    492                const uint16_t* src_v,
    493                int src_stride_v,
    494                uint8_t* dst_ar30,
    495                int dst_stride_ar30,
    496                int width,
    497                int height) {
    498   return I010ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
    499                           src_stride_v, dst_ar30, dst_stride_ar30,
    500                           &kYuvH709Constants, width, height);
    501 }
    502 
    503 // Convert I010 to AB30.
    504 LIBYUV_API
    505 int I010ToAB30(const uint16_t* src_y,
    506                int src_stride_y,
    507                const uint16_t* src_u,
    508                int src_stride_u,
    509                const uint16_t* src_v,
    510                int src_stride_v,
    511                uint8_t* dst_ab30,
    512                int dst_stride_ab30,
    513                int width,
    514                int height) {
    515   return I010ToAR30Matrix(src_y, src_stride_y, src_v, src_stride_v, src_u,
    516                           src_stride_u, dst_ab30, dst_stride_ab30,
    517                           &kYvuI601Constants, width, height);
    518 }
    519 
    520 // Convert H010 to AB30.
    521 LIBYUV_API
    522 int H010ToAB30(const uint16_t* src_y,
    523                int src_stride_y,
    524                const uint16_t* src_u,
    525                int src_stride_u,
    526                const uint16_t* src_v,
    527                int src_stride_v,
    528                uint8_t* dst_ab30,
    529                int dst_stride_ab30,
    530                int width,
    531                int height) {
    532   return I010ToAR30Matrix(src_y, src_stride_y, src_v, src_stride_v, src_u,
    533                           src_stride_u, dst_ab30, dst_stride_ab30,
    534                           &kYvuH709Constants, width, height);
    535 }
    536 
    537 // Convert 10 bit YUV to ARGB with matrix
    538 static int I010ToARGBMatrix(const uint16_t* src_y,
    539                             int src_stride_y,
    540                             const uint16_t* src_u,
    541                             int src_stride_u,
    542                             const uint16_t* src_v,
    543                             int src_stride_v,
    544                             uint8_t* dst_argb,
    545                             int dst_stride_argb,
    546                             const struct YuvConstants* yuvconstants,
    547                             int width,
    548                             int height) {
    549   int y;
    550   void (*I210ToARGBRow)(const uint16_t* y_buf, const uint16_t* u_buf,
    551                         const uint16_t* v_buf, uint8_t* rgb_buf,
    552                         const struct YuvConstants* yuvconstants, int width) =
    553       I210ToARGBRow_C;
    554   if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
    555     return -1;
    556   }
    557   // Negative height means invert the image.
    558   if (height < 0) {
    559     height = -height;
    560     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
    561     dst_stride_argb = -dst_stride_argb;
    562   }
    563 #if defined(HAS_I210TOARGBROW_SSSE3)
    564   if (TestCpuFlag(kCpuHasSSSE3)) {
    565     I210ToARGBRow = I210ToARGBRow_Any_SSSE3;
    566     if (IS_ALIGNED(width, 8)) {
    567       I210ToARGBRow = I210ToARGBRow_SSSE3;
    568     }
    569   }
    570 #endif
    571 #if defined(HAS_I210TOARGBROW_AVX2)
    572   if (TestCpuFlag(kCpuHasAVX2)) {
    573     I210ToARGBRow = I210ToARGBRow_Any_AVX2;
    574     if (IS_ALIGNED(width, 16)) {
    575       I210ToARGBRow = I210ToARGBRow_AVX2;
    576     }
    577   }
    578 #endif
    579   for (y = 0; y < height; ++y) {
    580     I210ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
    581     dst_argb += dst_stride_argb;
    582     src_y += src_stride_y;
    583     if (y & 1) {
    584       src_u += src_stride_u;
    585       src_v += src_stride_v;
    586     }
    587   }
    588   return 0;
    589 }
    590 
    591 // Convert I010 to ARGB.
    592 LIBYUV_API
    593 int I010ToARGB(const uint16_t* src_y,
    594                int src_stride_y,
    595                const uint16_t* src_u,
    596                int src_stride_u,
    597                const uint16_t* src_v,
    598                int src_stride_v,
    599                uint8_t* dst_argb,
    600                int dst_stride_argb,
    601                int width,
    602                int height) {
    603   return I010ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
    604                           src_stride_v, dst_argb, dst_stride_argb,
    605                           &kYuvI601Constants, width, height);
    606 }
    607 
    608 // Convert I010 to ABGR.
    609 LIBYUV_API
    610 int I010ToABGR(const uint16_t* src_y,
    611                int src_stride_y,
    612                const uint16_t* src_u,
    613                int src_stride_u,
    614                const uint16_t* src_v,
    615                int src_stride_v,
    616                uint8_t* dst_abgr,
    617                int dst_stride_abgr,
    618                int width,
    619                int height) {
    620   return I010ToARGBMatrix(src_y, src_stride_y, src_v,
    621                           src_stride_v,  // Swap U and V
    622                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
    623                           &kYvuI601Constants,  // Use Yvu matrix
    624                           width, height);
    625 }
    626 
    627 // Convert H010 to ARGB.
    628 LIBYUV_API
    629 int H010ToARGB(const uint16_t* src_y,
    630                int src_stride_y,
    631                const uint16_t* src_u,
    632                int src_stride_u,
    633                const uint16_t* src_v,
    634                int src_stride_v,
    635                uint8_t* dst_argb,
    636                int dst_stride_argb,
    637                int width,
    638                int height) {
    639   return I010ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
    640                           src_stride_v, dst_argb, dst_stride_argb,
    641                           &kYuvH709Constants, width, height);
    642 }
    643 
    644 // Convert H010 to ABGR.
    645 LIBYUV_API
    646 int H010ToABGR(const uint16_t* src_y,
    647                int src_stride_y,
    648                const uint16_t* src_u,
    649                int src_stride_u,
    650                const uint16_t* src_v,
    651                int src_stride_v,
    652                uint8_t* dst_abgr,
    653                int dst_stride_abgr,
    654                int width,
    655                int height) {
    656   return I010ToARGBMatrix(src_y, src_stride_y, src_v,
    657                           src_stride_v,  // Swap U and V
    658                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
    659                           &kYvuH709Constants,  // Use Yvu matrix
    660                           width, height);
    661 }
    662 
    663 // Convert I444 to ARGB with matrix
    664 static int I444ToARGBMatrix(const uint8_t* src_y,
    665                             int src_stride_y,
    666                             const uint8_t* src_u,
    667                             int src_stride_u,
    668                             const uint8_t* src_v,
    669                             int src_stride_v,
    670                             uint8_t* dst_argb,
    671                             int dst_stride_argb,
    672                             const struct YuvConstants* yuvconstants,
    673                             int width,
    674                             int height) {
    675   int y;
    676   void (*I444ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
    677                         const uint8_t* v_buf, uint8_t* rgb_buf,
    678                         const struct YuvConstants* yuvconstants, int width) =
    679       I444ToARGBRow_C;
    680   if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
    681     return -1;
    682   }
    683   // Negative height means invert the image.
    684   if (height < 0) {
    685     height = -height;
    686     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
    687     dst_stride_argb = -dst_stride_argb;
    688   }
    689   // Coalesce rows.
    690   if (src_stride_y == width && src_stride_u == width && src_stride_v == width &&
    691       dst_stride_argb == width * 4) {
    692     width *= height;
    693     height = 1;
    694     src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
    695   }
    696 #if defined(HAS_I444TOARGBROW_SSSE3)
    697   if (TestCpuFlag(kCpuHasSSSE3)) {
    698     I444ToARGBRow = I444ToARGBRow_Any_SSSE3;
    699     if (IS_ALIGNED(width, 8)) {
    700       I444ToARGBRow = I444ToARGBRow_SSSE3;
    701     }
    702   }
    703 #endif
    704 #if defined(HAS_I444TOARGBROW_AVX2)
    705   if (TestCpuFlag(kCpuHasAVX2)) {
    706     I444ToARGBRow = I444ToARGBRow_Any_AVX2;
    707     if (IS_ALIGNED(width, 16)) {
    708       I444ToARGBRow = I444ToARGBRow_AVX2;
    709     }
    710   }
    711 #endif
    712 #if defined(HAS_I444TOARGBROW_NEON)
    713   if (TestCpuFlag(kCpuHasNEON)) {
    714     I444ToARGBRow = I444ToARGBRow_Any_NEON;
    715     if (IS_ALIGNED(width, 8)) {
    716       I444ToARGBRow = I444ToARGBRow_NEON;
    717     }
    718   }
    719 #endif
    720 #if defined(HAS_I444TOARGBROW_MSA)
    721   if (TestCpuFlag(kCpuHasMSA)) {
    722     I444ToARGBRow = I444ToARGBRow_Any_MSA;
    723     if (IS_ALIGNED(width, 8)) {
    724       I444ToARGBRow = I444ToARGBRow_MSA;
    725     }
    726   }
    727 #endif
    728 
    729   for (y = 0; y < height; ++y) {
    730     I444ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
    731     dst_argb += dst_stride_argb;
    732     src_y += src_stride_y;
    733     src_u += src_stride_u;
    734     src_v += src_stride_v;
    735   }
    736   return 0;
    737 }
    738 
    739 // Convert I444 to ARGB.
    740 LIBYUV_API
    741 int I444ToARGB(const uint8_t* src_y,
    742                int src_stride_y,
    743                const uint8_t* src_u,
    744                int src_stride_u,
    745                const uint8_t* src_v,
    746                int src_stride_v,
    747                uint8_t* dst_argb,
    748                int dst_stride_argb,
    749                int width,
    750                int height) {
    751   return I444ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
    752                           src_stride_v, dst_argb, dst_stride_argb,
    753                           &kYuvI601Constants, width, height);
    754 }
    755 
    756 // Convert I444 to ABGR.
    757 LIBYUV_API
    758 int I444ToABGR(const uint8_t* src_y,
    759                int src_stride_y,
    760                const uint8_t* src_u,
    761                int src_stride_u,
    762                const uint8_t* src_v,
    763                int src_stride_v,
    764                uint8_t* dst_abgr,
    765                int dst_stride_abgr,
    766                int width,
    767                int height) {
    768   return I444ToARGBMatrix(src_y, src_stride_y, src_v,
    769                           src_stride_v,  // Swap U and V
    770                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
    771                           &kYvuI601Constants,  // Use Yvu matrix
    772                           width, height);
    773 }
    774 
    775 // Convert J444 to ARGB.
    776 LIBYUV_API
    777 int J444ToARGB(const uint8_t* src_y,
    778                int src_stride_y,
    779                const uint8_t* src_u,
    780                int src_stride_u,
    781                const uint8_t* src_v,
    782                int src_stride_v,
    783                uint8_t* dst_argb,
    784                int dst_stride_argb,
    785                int width,
    786                int height) {
    787   return I444ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
    788                           src_stride_v, dst_argb, dst_stride_argb,
    789                           &kYuvJPEGConstants, width, height);
    790 }
    791 
    792 // Convert I420 with Alpha to preattenuated ARGB.
    793 static int I420AlphaToARGBMatrix(const uint8_t* src_y,
    794                                  int src_stride_y,
    795                                  const uint8_t* src_u,
    796                                  int src_stride_u,
    797                                  const uint8_t* src_v,
    798                                  int src_stride_v,
    799                                  const uint8_t* src_a,
    800                                  int src_stride_a,
    801                                  uint8_t* dst_argb,
    802                                  int dst_stride_argb,
    803                                  const struct YuvConstants* yuvconstants,
    804                                  int width,
    805                                  int height,
    806                                  int attenuate) {
    807   int y;
    808   void (*I422AlphaToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
    809                              const uint8_t* v_buf, const uint8_t* a_buf,
    810                              uint8_t* dst_argb,
    811                              const struct YuvConstants* yuvconstants,
    812                              int width) = I422AlphaToARGBRow_C;
    813   void (*ARGBAttenuateRow)(const uint8_t* src_argb, uint8_t* dst_argb,
    814                            int width) = ARGBAttenuateRow_C;
    815   if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
    816     return -1;
    817   }
    818   // Negative height means invert the image.
    819   if (height < 0) {
    820     height = -height;
    821     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
    822     dst_stride_argb = -dst_stride_argb;
    823   }
    824 #if defined(HAS_I422ALPHATOARGBROW_SSSE3)
    825   if (TestCpuFlag(kCpuHasSSSE3)) {
    826     I422AlphaToARGBRow = I422AlphaToARGBRow_Any_SSSE3;
    827     if (IS_ALIGNED(width, 8)) {
    828       I422AlphaToARGBRow = I422AlphaToARGBRow_SSSE3;
    829     }
    830   }
    831 #endif
    832 #if defined(HAS_I422ALPHATOARGBROW_AVX2)
    833   if (TestCpuFlag(kCpuHasAVX2)) {
    834     I422AlphaToARGBRow = I422AlphaToARGBRow_Any_AVX2;
    835     if (IS_ALIGNED(width, 16)) {
    836       I422AlphaToARGBRow = I422AlphaToARGBRow_AVX2;
    837     }
    838   }
    839 #endif
    840 #if defined(HAS_I422ALPHATOARGBROW_NEON)
    841   if (TestCpuFlag(kCpuHasNEON)) {
    842     I422AlphaToARGBRow = I422AlphaToARGBRow_Any_NEON;
    843     if (IS_ALIGNED(width, 8)) {
    844       I422AlphaToARGBRow = I422AlphaToARGBRow_NEON;
    845     }
    846   }
    847 #endif
    848 #if defined(HAS_I422ALPHATOARGBROW_MSA)
    849   if (TestCpuFlag(kCpuHasMSA)) {
    850     I422AlphaToARGBRow = I422AlphaToARGBRow_Any_MSA;
    851     if (IS_ALIGNED(width, 8)) {
    852       I422AlphaToARGBRow = I422AlphaToARGBRow_MSA;
    853     }
    854   }
    855 #endif
    856 #if defined(HAS_ARGBATTENUATEROW_SSSE3)
    857   if (TestCpuFlag(kCpuHasSSSE3)) {
    858     ARGBAttenuateRow = ARGBAttenuateRow_Any_SSSE3;
    859     if (IS_ALIGNED(width, 4)) {
    860       ARGBAttenuateRow = ARGBAttenuateRow_SSSE3;
    861     }
    862   }
    863 #endif
    864 #if defined(HAS_ARGBATTENUATEROW_AVX2)
    865   if (TestCpuFlag(kCpuHasAVX2)) {
    866     ARGBAttenuateRow = ARGBAttenuateRow_Any_AVX2;
    867     if (IS_ALIGNED(width, 8)) {
    868       ARGBAttenuateRow = ARGBAttenuateRow_AVX2;
    869     }
    870   }
    871 #endif
    872 #if defined(HAS_ARGBATTENUATEROW_NEON)
    873   if (TestCpuFlag(kCpuHasNEON)) {
    874     ARGBAttenuateRow = ARGBAttenuateRow_Any_NEON;
    875     if (IS_ALIGNED(width, 8)) {
    876       ARGBAttenuateRow = ARGBAttenuateRow_NEON;
    877     }
    878   }
    879 #endif
    880 #if defined(HAS_ARGBATTENUATEROW_MSA)
    881   if (TestCpuFlag(kCpuHasMSA)) {
    882     ARGBAttenuateRow = ARGBAttenuateRow_Any_MSA;
    883     if (IS_ALIGNED(width, 8)) {
    884       ARGBAttenuateRow = ARGBAttenuateRow_MSA;
    885     }
    886   }
    887 #endif
    888 
    889   for (y = 0; y < height; ++y) {
    890     I422AlphaToARGBRow(src_y, src_u, src_v, src_a, dst_argb, yuvconstants,
    891                        width);
    892     if (attenuate) {
    893       ARGBAttenuateRow(dst_argb, dst_argb, width);
    894     }
    895     dst_argb += dst_stride_argb;
    896     src_a += src_stride_a;
    897     src_y += src_stride_y;
    898     if (y & 1) {
    899       src_u += src_stride_u;
    900       src_v += src_stride_v;
    901     }
    902   }
    903   return 0;
    904 }
    905 
    906 // Convert I420 with Alpha to ARGB.
    907 LIBYUV_API
    908 int I420AlphaToARGB(const uint8_t* src_y,
    909                     int src_stride_y,
    910                     const uint8_t* src_u,
    911                     int src_stride_u,
    912                     const uint8_t* src_v,
    913                     int src_stride_v,
    914                     const uint8_t* src_a,
    915                     int src_stride_a,
    916                     uint8_t* dst_argb,
    917                     int dst_stride_argb,
    918                     int width,
    919                     int height,
    920                     int attenuate) {
    921   return I420AlphaToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
    922                                src_stride_v, src_a, src_stride_a, dst_argb,
    923                                dst_stride_argb, &kYuvI601Constants, width,
    924                                height, attenuate);
    925 }
    926 
    927 // Convert I420 with Alpha to ABGR.
    928 LIBYUV_API
    929 int I420AlphaToABGR(const uint8_t* src_y,
    930                     int src_stride_y,
    931                     const uint8_t* src_u,
    932                     int src_stride_u,
    933                     const uint8_t* src_v,
    934                     int src_stride_v,
    935                     const uint8_t* src_a,
    936                     int src_stride_a,
    937                     uint8_t* dst_abgr,
    938                     int dst_stride_abgr,
    939                     int width,
    940                     int height,
    941                     int attenuate) {
    942   return I420AlphaToARGBMatrix(
    943       src_y, src_stride_y, src_v, src_stride_v,  // Swap U and V
    944       src_u, src_stride_u, src_a, src_stride_a, dst_abgr, dst_stride_abgr,
    945       &kYvuI601Constants,  // Use Yvu matrix
    946       width, height, attenuate);
    947 }
    948 
    949 // Convert I400 to ARGB.
    950 LIBYUV_API
    951 int I400ToARGB(const uint8_t* src_y,
    952                int src_stride_y,
    953                uint8_t* dst_argb,
    954                int dst_stride_argb,
    955                int width,
    956                int height) {
    957   int y;
    958   void (*I400ToARGBRow)(const uint8_t* y_buf, uint8_t* rgb_buf, int width) =
    959       I400ToARGBRow_C;
    960   if (!src_y || !dst_argb || width <= 0 || height == 0) {
    961     return -1;
    962   }
    963   // Negative height means invert the image.
    964   if (height < 0) {
    965     height = -height;
    966     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
    967     dst_stride_argb = -dst_stride_argb;
    968   }
    969   // Coalesce rows.
    970   if (src_stride_y == width && dst_stride_argb == width * 4) {
    971     width *= height;
    972     height = 1;
    973     src_stride_y = dst_stride_argb = 0;
    974   }
    975 #if defined(HAS_I400TOARGBROW_SSE2)
    976   if (TestCpuFlag(kCpuHasSSE2)) {
    977     I400ToARGBRow = I400ToARGBRow_Any_SSE2;
    978     if (IS_ALIGNED(width, 8)) {
    979       I400ToARGBRow = I400ToARGBRow_SSE2;
    980     }
    981   }
    982 #endif
    983 #if defined(HAS_I400TOARGBROW_AVX2)
    984   if (TestCpuFlag(kCpuHasAVX2)) {
    985     I400ToARGBRow = I400ToARGBRow_Any_AVX2;
    986     if (IS_ALIGNED(width, 16)) {
    987       I400ToARGBRow = I400ToARGBRow_AVX2;
    988     }
    989   }
    990 #endif
    991 #if defined(HAS_I400TOARGBROW_NEON)
    992   if (TestCpuFlag(kCpuHasNEON)) {
    993     I400ToARGBRow = I400ToARGBRow_Any_NEON;
    994     if (IS_ALIGNED(width, 8)) {
    995       I400ToARGBRow = I400ToARGBRow_NEON;
    996     }
    997   }
    998 #endif
    999 #if defined(HAS_I400TOARGBROW_MSA)
   1000   if (TestCpuFlag(kCpuHasMSA)) {
   1001     I400ToARGBRow = I400ToARGBRow_Any_MSA;
   1002     if (IS_ALIGNED(width, 16)) {
   1003       I400ToARGBRow = I400ToARGBRow_MSA;
   1004     }
   1005   }
   1006 #endif
   1007 
   1008   for (y = 0; y < height; ++y) {
   1009     I400ToARGBRow(src_y, dst_argb, width);
   1010     dst_argb += dst_stride_argb;
   1011     src_y += src_stride_y;
   1012   }
   1013   return 0;
   1014 }
   1015 
   1016 // Convert J400 to ARGB.
   1017 LIBYUV_API
   1018 int J400ToARGB(const uint8_t* src_y,
   1019                int src_stride_y,
   1020                uint8_t* dst_argb,
   1021                int dst_stride_argb,
   1022                int width,
   1023                int height) {
   1024   int y;
   1025   void (*J400ToARGBRow)(const uint8_t* src_y, uint8_t* dst_argb, int width) =
   1026       J400ToARGBRow_C;
   1027   if (!src_y || !dst_argb || width <= 0 || height == 0) {
   1028     return -1;
   1029   }
   1030   // Negative height means invert the image.
   1031   if (height < 0) {
   1032     height = -height;
   1033     src_y = src_y + (height - 1) * src_stride_y;
   1034     src_stride_y = -src_stride_y;
   1035   }
   1036   // Coalesce rows.
   1037   if (src_stride_y == width && dst_stride_argb == width * 4) {
   1038     width *= height;
   1039     height = 1;
   1040     src_stride_y = dst_stride_argb = 0;
   1041   }
   1042 #if defined(HAS_J400TOARGBROW_SSE2)
   1043   if (TestCpuFlag(kCpuHasSSE2)) {
   1044     J400ToARGBRow = J400ToARGBRow_Any_SSE2;
   1045     if (IS_ALIGNED(width, 8)) {
   1046       J400ToARGBRow = J400ToARGBRow_SSE2;
   1047     }
   1048   }
   1049 #endif
   1050 #if defined(HAS_J400TOARGBROW_AVX2)
   1051   if (TestCpuFlag(kCpuHasAVX2)) {
   1052     J400ToARGBRow = J400ToARGBRow_Any_AVX2;
   1053     if (IS_ALIGNED(width, 16)) {
   1054       J400ToARGBRow = J400ToARGBRow_AVX2;
   1055     }
   1056   }
   1057 #endif
   1058 #if defined(HAS_J400TOARGBROW_NEON)
   1059   if (TestCpuFlag(kCpuHasNEON)) {
   1060     J400ToARGBRow = J400ToARGBRow_Any_NEON;
   1061     if (IS_ALIGNED(width, 8)) {
   1062       J400ToARGBRow = J400ToARGBRow_NEON;
   1063     }
   1064   }
   1065 #endif
   1066 #if defined(HAS_J400TOARGBROW_MSA)
   1067   if (TestCpuFlag(kCpuHasMSA)) {
   1068     J400ToARGBRow = J400ToARGBRow_Any_MSA;
   1069     if (IS_ALIGNED(width, 16)) {
   1070       J400ToARGBRow = J400ToARGBRow_MSA;
   1071     }
   1072   }
   1073 #endif
   1074   for (y = 0; y < height; ++y) {
   1075     J400ToARGBRow(src_y, dst_argb, width);
   1076     src_y += src_stride_y;
   1077     dst_argb += dst_stride_argb;
   1078   }
   1079   return 0;
   1080 }
   1081 
   1082 // Shuffle table for converting BGRA to ARGB.
   1083 static const uvec8 kShuffleMaskBGRAToARGB = {
   1084     3u, 2u, 1u, 0u, 7u, 6u, 5u, 4u, 11u, 10u, 9u, 8u, 15u, 14u, 13u, 12u};
   1085 
   1086 // Shuffle table for converting ABGR to ARGB.
   1087 static const uvec8 kShuffleMaskABGRToARGB = {
   1088     2u, 1u, 0u, 3u, 6u, 5u, 4u, 7u, 10u, 9u, 8u, 11u, 14u, 13u, 12u, 15u};
   1089 
   1090 // Shuffle table for converting RGBA to ARGB.
   1091 static const uvec8 kShuffleMaskRGBAToARGB = {
   1092     1u, 2u, 3u, 0u, 5u, 6u, 7u, 4u, 9u, 10u, 11u, 8u, 13u, 14u, 15u, 12u};
   1093 
   1094 // Convert BGRA to ARGB.
   1095 LIBYUV_API
   1096 int BGRAToARGB(const uint8_t* src_bgra,
   1097                int src_stride_bgra,
   1098                uint8_t* dst_argb,
   1099                int dst_stride_argb,
   1100                int width,
   1101                int height) {
   1102   return ARGBShuffle(src_bgra, src_stride_bgra, dst_argb, dst_stride_argb,
   1103                      (const uint8_t*)(&kShuffleMaskBGRAToARGB), width, height);
   1104 }
   1105 
   1106 // Convert ARGB to BGRA (same as BGRAToARGB).
   1107 LIBYUV_API
   1108 int ARGBToBGRA(const uint8_t* src_bgra,
   1109                int src_stride_bgra,
   1110                uint8_t* dst_argb,
   1111                int dst_stride_argb,
   1112                int width,
   1113                int height) {
   1114   return ARGBShuffle(src_bgra, src_stride_bgra, dst_argb, dst_stride_argb,
   1115                      (const uint8_t*)(&kShuffleMaskBGRAToARGB), width, height);
   1116 }
   1117 
   1118 // Convert ABGR to ARGB.
   1119 LIBYUV_API
   1120 int ABGRToARGB(const uint8_t* src_abgr,
   1121                int src_stride_abgr,
   1122                uint8_t* dst_argb,
   1123                int dst_stride_argb,
   1124                int width,
   1125                int height) {
   1126   return ARGBShuffle(src_abgr, src_stride_abgr, dst_argb, dst_stride_argb,
   1127                      (const uint8_t*)(&kShuffleMaskABGRToARGB), width, height);
   1128 }
   1129 
   1130 // Convert ARGB to ABGR to (same as ABGRToARGB).
   1131 LIBYUV_API
   1132 int ARGBToABGR(const uint8_t* src_abgr,
   1133                int src_stride_abgr,
   1134                uint8_t* dst_argb,
   1135                int dst_stride_argb,
   1136                int width,
   1137                int height) {
   1138   return ARGBShuffle(src_abgr, src_stride_abgr, dst_argb, dst_stride_argb,
   1139                      (const uint8_t*)(&kShuffleMaskABGRToARGB), width, height);
   1140 }
   1141 
   1142 // Convert RGBA to ARGB.
   1143 LIBYUV_API
   1144 int RGBAToARGB(const uint8_t* src_rgba,
   1145                int src_stride_rgba,
   1146                uint8_t* dst_argb,
   1147                int dst_stride_argb,
   1148                int width,
   1149                int height) {
   1150   return ARGBShuffle(src_rgba, src_stride_rgba, dst_argb, dst_stride_argb,
   1151                      (const uint8_t*)(&kShuffleMaskRGBAToARGB), width, height);
   1152 }
   1153 
   1154 // Convert RGB24 to ARGB.
   1155 LIBYUV_API
   1156 int RGB24ToARGB(const uint8_t* src_rgb24,
   1157                 int src_stride_rgb24,
   1158                 uint8_t* dst_argb,
   1159                 int dst_stride_argb,
   1160                 int width,
   1161                 int height) {
   1162   int y;
   1163   void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
   1164       RGB24ToARGBRow_C;
   1165   if (!src_rgb24 || !dst_argb || width <= 0 || height == 0) {
   1166     return -1;
   1167   }
   1168   // Negative height means invert the image.
   1169   if (height < 0) {
   1170     height = -height;
   1171     src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
   1172     src_stride_rgb24 = -src_stride_rgb24;
   1173   }
   1174   // Coalesce rows.
   1175   if (src_stride_rgb24 == width * 3 && dst_stride_argb == width * 4) {
   1176     width *= height;
   1177     height = 1;
   1178     src_stride_rgb24 = dst_stride_argb = 0;
   1179   }
   1180 #if defined(HAS_RGB24TOARGBROW_SSSE3)
   1181   if (TestCpuFlag(kCpuHasSSSE3)) {
   1182     RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
   1183     if (IS_ALIGNED(width, 16)) {
   1184       RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
   1185     }
   1186   }
   1187 #endif
   1188 #if defined(HAS_RGB24TOARGBROW_NEON)
   1189   if (TestCpuFlag(kCpuHasNEON)) {
   1190     RGB24ToARGBRow = RGB24ToARGBRow_Any_NEON;
   1191     if (IS_ALIGNED(width, 8)) {
   1192       RGB24ToARGBRow = RGB24ToARGBRow_NEON;
   1193     }
   1194   }
   1195 #endif
   1196 #if defined(HAS_RGB24TOARGBROW_MSA)
   1197   if (TestCpuFlag(kCpuHasMSA)) {
   1198     RGB24ToARGBRow = RGB24ToARGBRow_Any_MSA;
   1199     if (IS_ALIGNED(width, 16)) {
   1200       RGB24ToARGBRow = RGB24ToARGBRow_MSA;
   1201     }
   1202   }
   1203 #endif
   1204 
   1205   for (y = 0; y < height; ++y) {
   1206     RGB24ToARGBRow(src_rgb24, dst_argb, width);
   1207     src_rgb24 += src_stride_rgb24;
   1208     dst_argb += dst_stride_argb;
   1209   }
   1210   return 0;
   1211 }
   1212 
   1213 // Convert RAW to ARGB.
   1214 LIBYUV_API
   1215 int RAWToARGB(const uint8_t* src_raw,
   1216               int src_stride_raw,
   1217               uint8_t* dst_argb,
   1218               int dst_stride_argb,
   1219               int width,
   1220               int height) {
   1221   int y;
   1222   void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
   1223       RAWToARGBRow_C;
   1224   if (!src_raw || !dst_argb || width <= 0 || height == 0) {
   1225     return -1;
   1226   }
   1227   // Negative height means invert the image.
   1228   if (height < 0) {
   1229     height = -height;
   1230     src_raw = src_raw + (height - 1) * src_stride_raw;
   1231     src_stride_raw = -src_stride_raw;
   1232   }
   1233   // Coalesce rows.
   1234   if (src_stride_raw == width * 3 && dst_stride_argb == width * 4) {
   1235     width *= height;
   1236     height = 1;
   1237     src_stride_raw = dst_stride_argb = 0;
   1238   }
   1239 #if defined(HAS_RAWTOARGBROW_SSSE3)
   1240   if (TestCpuFlag(kCpuHasSSSE3)) {
   1241     RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
   1242     if (IS_ALIGNED(width, 16)) {
   1243       RAWToARGBRow = RAWToARGBRow_SSSE3;
   1244     }
   1245   }
   1246 #endif
   1247 #if defined(HAS_RAWTOARGBROW_NEON)
   1248   if (TestCpuFlag(kCpuHasNEON)) {
   1249     RAWToARGBRow = RAWToARGBRow_Any_NEON;
   1250     if (IS_ALIGNED(width, 8)) {
   1251       RAWToARGBRow = RAWToARGBRow_NEON;
   1252     }
   1253   }
   1254 #endif
   1255 #if defined(HAS_RAWTOARGBROW_MSA)
   1256   if (TestCpuFlag(kCpuHasMSA)) {
   1257     RAWToARGBRow = RAWToARGBRow_Any_MSA;
   1258     if (IS_ALIGNED(width, 16)) {
   1259       RAWToARGBRow = RAWToARGBRow_MSA;
   1260     }
   1261   }
   1262 #endif
   1263 
   1264   for (y = 0; y < height; ++y) {
   1265     RAWToARGBRow(src_raw, dst_argb, width);
   1266     src_raw += src_stride_raw;
   1267     dst_argb += dst_stride_argb;
   1268   }
   1269   return 0;
   1270 }
   1271 
   1272 // Convert RGB565 to ARGB.
   1273 LIBYUV_API
   1274 int RGB565ToARGB(const uint8_t* src_rgb565,
   1275                  int src_stride_rgb565,
   1276                  uint8_t* dst_argb,
   1277                  int dst_stride_argb,
   1278                  int width,
   1279                  int height) {
   1280   int y;
   1281   void (*RGB565ToARGBRow)(const uint8_t* src_rgb565, uint8_t* dst_argb,
   1282                           int width) = RGB565ToARGBRow_C;
   1283   if (!src_rgb565 || !dst_argb || width <= 0 || height == 0) {
   1284     return -1;
   1285   }
   1286   // Negative height means invert the image.
   1287   if (height < 0) {
   1288     height = -height;
   1289     src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
   1290     src_stride_rgb565 = -src_stride_rgb565;
   1291   }
   1292   // Coalesce rows.
   1293   if (src_stride_rgb565 == width * 2 && dst_stride_argb == width * 4) {
   1294     width *= height;
   1295     height = 1;
   1296     src_stride_rgb565 = dst_stride_argb = 0;
   1297   }
   1298 #if defined(HAS_RGB565TOARGBROW_SSE2)
   1299   if (TestCpuFlag(kCpuHasSSE2)) {
   1300     RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
   1301     if (IS_ALIGNED(width, 8)) {
   1302       RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
   1303     }
   1304   }
   1305 #endif
   1306 #if defined(HAS_RGB565TOARGBROW_AVX2)
   1307   if (TestCpuFlag(kCpuHasAVX2)) {
   1308     RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2;
   1309     if (IS_ALIGNED(width, 16)) {
   1310       RGB565ToARGBRow = RGB565ToARGBRow_AVX2;
   1311     }
   1312   }
   1313 #endif
   1314 #if defined(HAS_RGB565TOARGBROW_NEON)
   1315   if (TestCpuFlag(kCpuHasNEON)) {
   1316     RGB565ToARGBRow = RGB565ToARGBRow_Any_NEON;
   1317     if (IS_ALIGNED(width, 8)) {
   1318       RGB565ToARGBRow = RGB565ToARGBRow_NEON;
   1319     }
   1320   }
   1321 #endif
   1322 #if defined(HAS_RGB565TOARGBROW_MSA)
   1323   if (TestCpuFlag(kCpuHasMSA)) {
   1324     RGB565ToARGBRow = RGB565ToARGBRow_Any_MSA;
   1325     if (IS_ALIGNED(width, 16)) {
   1326       RGB565ToARGBRow = RGB565ToARGBRow_MSA;
   1327     }
   1328   }
   1329 #endif
   1330 
   1331   for (y = 0; y < height; ++y) {
   1332     RGB565ToARGBRow(src_rgb565, dst_argb, width);
   1333     src_rgb565 += src_stride_rgb565;
   1334     dst_argb += dst_stride_argb;
   1335   }
   1336   return 0;
   1337 }
   1338 
   1339 // Convert ARGB1555 to ARGB.
   1340 LIBYUV_API
   1341 int ARGB1555ToARGB(const uint8_t* src_argb1555,
   1342                    int src_stride_argb1555,
   1343                    uint8_t* dst_argb,
   1344                    int dst_stride_argb,
   1345                    int width,
   1346                    int height) {
   1347   int y;
   1348   void (*ARGB1555ToARGBRow)(const uint8_t* src_argb1555, uint8_t* dst_argb,
   1349                             int width) = ARGB1555ToARGBRow_C;
   1350   if (!src_argb1555 || !dst_argb || width <= 0 || height == 0) {
   1351     return -1;
   1352   }
   1353   // Negative height means invert the image.
   1354   if (height < 0) {
   1355     height = -height;
   1356     src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
   1357     src_stride_argb1555 = -src_stride_argb1555;
   1358   }
   1359   // Coalesce rows.
   1360   if (src_stride_argb1555 == width * 2 && dst_stride_argb == width * 4) {
   1361     width *= height;
   1362     height = 1;
   1363     src_stride_argb1555 = dst_stride_argb = 0;
   1364   }
   1365 #if defined(HAS_ARGB1555TOARGBROW_SSE2)
   1366   if (TestCpuFlag(kCpuHasSSE2)) {
   1367     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
   1368     if (IS_ALIGNED(width, 8)) {
   1369       ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
   1370     }
   1371   }
   1372 #endif
   1373 #if defined(HAS_ARGB1555TOARGBROW_AVX2)
   1374   if (TestCpuFlag(kCpuHasAVX2)) {
   1375     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2;
   1376     if (IS_ALIGNED(width, 16)) {
   1377       ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2;
   1378     }
   1379   }
   1380 #endif
   1381 #if defined(HAS_ARGB1555TOARGBROW_NEON)
   1382   if (TestCpuFlag(kCpuHasNEON)) {
   1383     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_NEON;
   1384     if (IS_ALIGNED(width, 8)) {
   1385       ARGB1555ToARGBRow = ARGB1555ToARGBRow_NEON;
   1386     }
   1387   }
   1388 #endif
   1389 #if defined(HAS_ARGB1555TOARGBROW_MSA)
   1390   if (TestCpuFlag(kCpuHasMSA)) {
   1391     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_MSA;
   1392     if (IS_ALIGNED(width, 16)) {
   1393       ARGB1555ToARGBRow = ARGB1555ToARGBRow_MSA;
   1394     }
   1395   }
   1396 #endif
   1397 
   1398   for (y = 0; y < height; ++y) {
   1399     ARGB1555ToARGBRow(src_argb1555, dst_argb, width);
   1400     src_argb1555 += src_stride_argb1555;
   1401     dst_argb += dst_stride_argb;
   1402   }
   1403   return 0;
   1404 }
   1405 
   1406 // Convert ARGB4444 to ARGB.
   1407 LIBYUV_API
   1408 int ARGB4444ToARGB(const uint8_t* src_argb4444,
   1409                    int src_stride_argb4444,
   1410                    uint8_t* dst_argb,
   1411                    int dst_stride_argb,
   1412                    int width,
   1413                    int height) {
   1414   int y;
   1415   void (*ARGB4444ToARGBRow)(const uint8_t* src_argb4444, uint8_t* dst_argb,
   1416                             int width) = ARGB4444ToARGBRow_C;
   1417   if (!src_argb4444 || !dst_argb || width <= 0 || height == 0) {
   1418     return -1;
   1419   }
   1420   // Negative height means invert the image.
   1421   if (height < 0) {
   1422     height = -height;
   1423     src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
   1424     src_stride_argb4444 = -src_stride_argb4444;
   1425   }
   1426   // Coalesce rows.
   1427   if (src_stride_argb4444 == width * 2 && dst_stride_argb == width * 4) {
   1428     width *= height;
   1429     height = 1;
   1430     src_stride_argb4444 = dst_stride_argb = 0;
   1431   }
   1432 #if defined(HAS_ARGB4444TOARGBROW_SSE2)
   1433   if (TestCpuFlag(kCpuHasSSE2)) {
   1434     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
   1435     if (IS_ALIGNED(width, 8)) {
   1436       ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
   1437     }
   1438   }
   1439 #endif
   1440 #if defined(HAS_ARGB4444TOARGBROW_AVX2)
   1441   if (TestCpuFlag(kCpuHasAVX2)) {
   1442     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2;
   1443     if (IS_ALIGNED(width, 16)) {
   1444       ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2;
   1445     }
   1446   }
   1447 #endif
   1448 #if defined(HAS_ARGB4444TOARGBROW_NEON)
   1449   if (TestCpuFlag(kCpuHasNEON)) {
   1450     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_NEON;
   1451     if (IS_ALIGNED(width, 8)) {
   1452       ARGB4444ToARGBRow = ARGB4444ToARGBRow_NEON;
   1453     }
   1454   }
   1455 #endif
   1456 #if defined(HAS_ARGB4444TOARGBROW_MSA)
   1457   if (TestCpuFlag(kCpuHasMSA)) {
   1458     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MSA;
   1459     if (IS_ALIGNED(width, 16)) {
   1460       ARGB4444ToARGBRow = ARGB4444ToARGBRow_MSA;
   1461     }
   1462   }
   1463 #endif
   1464 
   1465   for (y = 0; y < height; ++y) {
   1466     ARGB4444ToARGBRow(src_argb4444, dst_argb, width);
   1467     src_argb4444 += src_stride_argb4444;
   1468     dst_argb += dst_stride_argb;
   1469   }
   1470   return 0;
   1471 }
   1472 
   1473 // Convert AR30 to ARGB.
   1474 LIBYUV_API
   1475 int AR30ToARGB(const uint8_t* src_ar30,
   1476                int src_stride_ar30,
   1477                uint8_t* dst_argb,
   1478                int dst_stride_argb,
   1479                int width,
   1480                int height) {
   1481   int y;
   1482   if (!src_ar30 || !dst_argb || width <= 0 || height == 0) {
   1483     return -1;
   1484   }
   1485   // Negative height means invert the image.
   1486   if (height < 0) {
   1487     height = -height;
   1488     src_ar30 = src_ar30 + (height - 1) * src_stride_ar30;
   1489     src_stride_ar30 = -src_stride_ar30;
   1490   }
   1491   // Coalesce rows.
   1492   if (src_stride_ar30 == width * 4 && dst_stride_argb == width * 4) {
   1493     width *= height;
   1494     height = 1;
   1495     src_stride_ar30 = dst_stride_argb = 0;
   1496   }
   1497   for (y = 0; y < height; ++y) {
   1498     AR30ToARGBRow_C(src_ar30, dst_argb, width);
   1499     src_ar30 += src_stride_ar30;
   1500     dst_argb += dst_stride_argb;
   1501   }
   1502   return 0;
   1503 }
   1504 
   1505 // Convert AR30 to ABGR.
   1506 LIBYUV_API
   1507 int AR30ToABGR(const uint8_t* src_ar30,
   1508                int src_stride_ar30,
   1509                uint8_t* dst_abgr,
   1510                int dst_stride_abgr,
   1511                int width,
   1512                int height) {
   1513   int y;
   1514   if (!src_ar30 || !dst_abgr || width <= 0 || height == 0) {
   1515     return -1;
   1516   }
   1517   // Negative height means invert the image.
   1518   if (height < 0) {
   1519     height = -height;
   1520     src_ar30 = src_ar30 + (height - 1) * src_stride_ar30;
   1521     src_stride_ar30 = -src_stride_ar30;
   1522   }
   1523   // Coalesce rows.
   1524   if (src_stride_ar30 == width * 4 && dst_stride_abgr == width * 4) {
   1525     width *= height;
   1526     height = 1;
   1527     src_stride_ar30 = dst_stride_abgr = 0;
   1528   }
   1529   for (y = 0; y < height; ++y) {
   1530     AR30ToABGRRow_C(src_ar30, dst_abgr, width);
   1531     src_ar30 += src_stride_ar30;
   1532     dst_abgr += dst_stride_abgr;
   1533   }
   1534   return 0;
   1535 }
   1536 
   1537 // Convert AR30 to AB30.
   1538 LIBYUV_API
   1539 int AR30ToAB30(const uint8_t* src_ar30,
   1540                int src_stride_ar30,
   1541                uint8_t* dst_ab30,
   1542                int dst_stride_ab30,
   1543                int width,
   1544                int height) {
   1545   int y;
   1546   if (!src_ar30 || !dst_ab30 || width <= 0 || height == 0) {
   1547     return -1;
   1548   }
   1549   // Negative height means invert the image.
   1550   if (height < 0) {
   1551     height = -height;
   1552     src_ar30 = src_ar30 + (height - 1) * src_stride_ar30;
   1553     src_stride_ar30 = -src_stride_ar30;
   1554   }
   1555   // Coalesce rows.
   1556   if (src_stride_ar30 == width * 4 && dst_stride_ab30 == width * 4) {
   1557     width *= height;
   1558     height = 1;
   1559     src_stride_ar30 = dst_stride_ab30 = 0;
   1560   }
   1561   for (y = 0; y < height; ++y) {
   1562     AR30ToAB30Row_C(src_ar30, dst_ab30, width);
   1563     src_ar30 += src_stride_ar30;
   1564     dst_ab30 += dst_stride_ab30;
   1565   }
   1566   return 0;
   1567 }
   1568 
   1569 // Convert NV12 to ARGB with matrix
   1570 static int NV12ToARGBMatrix(const uint8_t* src_y,
   1571                             int src_stride_y,
   1572                             const uint8_t* src_uv,
   1573                             int src_stride_uv,
   1574                             uint8_t* dst_argb,
   1575                             int dst_stride_argb,
   1576                             const struct YuvConstants* yuvconstants,
   1577                             int width,
   1578                             int height) {
   1579   int y;
   1580   void (*NV12ToARGBRow)(
   1581       const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
   1582       const struct YuvConstants* yuvconstants, int width) = NV12ToARGBRow_C;
   1583   if (!src_y || !src_uv || !dst_argb || width <= 0 || height == 0) {
   1584     return -1;
   1585   }
   1586   // Negative height means invert the image.
   1587   if (height < 0) {
   1588     height = -height;
   1589     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
   1590     dst_stride_argb = -dst_stride_argb;
   1591   }
   1592 #if defined(HAS_NV12TOARGBROW_SSSE3)
   1593   if (TestCpuFlag(kCpuHasSSSE3)) {
   1594     NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
   1595     if (IS_ALIGNED(width, 8)) {
   1596       NV12ToARGBRow = NV12ToARGBRow_SSSE3;
   1597     }
   1598   }
   1599 #endif
   1600 #if defined(HAS_NV12TOARGBROW_AVX2)
   1601   if (TestCpuFlag(kCpuHasAVX2)) {
   1602     NV12ToARGBRow = NV12ToARGBRow_Any_AVX2;
   1603     if (IS_ALIGNED(width, 16)) {
   1604       NV12ToARGBRow = NV12ToARGBRow_AVX2;
   1605     }
   1606   }
   1607 #endif
   1608 #if defined(HAS_NV12TOARGBROW_NEON)
   1609   if (TestCpuFlag(kCpuHasNEON)) {
   1610     NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
   1611     if (IS_ALIGNED(width, 8)) {
   1612       NV12ToARGBRow = NV12ToARGBRow_NEON;
   1613     }
   1614   }
   1615 #endif
   1616 #if defined(HAS_NV12TOARGBROW_MSA)
   1617   if (TestCpuFlag(kCpuHasMSA)) {
   1618     NV12ToARGBRow = NV12ToARGBRow_Any_MSA;
   1619     if (IS_ALIGNED(width, 8)) {
   1620       NV12ToARGBRow = NV12ToARGBRow_MSA;
   1621     }
   1622   }
   1623 #endif
   1624 
   1625   for (y = 0; y < height; ++y) {
   1626     NV12ToARGBRow(src_y, src_uv, dst_argb, yuvconstants, width);
   1627     dst_argb += dst_stride_argb;
   1628     src_y += src_stride_y;
   1629     if (y & 1) {
   1630       src_uv += src_stride_uv;
   1631     }
   1632   }
   1633   return 0;
   1634 }
   1635 
   1636 // Convert NV21 to ARGB with matrix
   1637 static int NV21ToARGBMatrix(const uint8_t* src_y,
   1638                             int src_stride_y,
   1639                             const uint8_t* src_vu,
   1640                             int src_stride_vu,
   1641                             uint8_t* dst_argb,
   1642                             int dst_stride_argb,
   1643                             const struct YuvConstants* yuvconstants,
   1644                             int width,
   1645                             int height) {
   1646   int y;
   1647   void (*NV21ToARGBRow)(
   1648       const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
   1649       const struct YuvConstants* yuvconstants, int width) = NV21ToARGBRow_C;
   1650   if (!src_y || !src_vu || !dst_argb || width <= 0 || height == 0) {
   1651     return -1;
   1652   }
   1653   // Negative height means invert the image.
   1654   if (height < 0) {
   1655     height = -height;
   1656     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
   1657     dst_stride_argb = -dst_stride_argb;
   1658   }
   1659 #if defined(HAS_NV21TOARGBROW_SSSE3)
   1660   if (TestCpuFlag(kCpuHasSSSE3)) {
   1661     NV21ToARGBRow = NV21ToARGBRow_Any_SSSE3;
   1662     if (IS_ALIGNED(width, 8)) {
   1663       NV21ToARGBRow = NV21ToARGBRow_SSSE3;
   1664     }
   1665   }
   1666 #endif
   1667 #if defined(HAS_NV21TOARGBROW_AVX2)
   1668   if (TestCpuFlag(kCpuHasAVX2)) {
   1669     NV21ToARGBRow = NV21ToARGBRow_Any_AVX2;
   1670     if (IS_ALIGNED(width, 16)) {
   1671       NV21ToARGBRow = NV21ToARGBRow_AVX2;
   1672     }
   1673   }
   1674 #endif
   1675 #if defined(HAS_NV21TOARGBROW_NEON)
   1676   if (TestCpuFlag(kCpuHasNEON)) {
   1677     NV21ToARGBRow = NV21ToARGBRow_Any_NEON;
   1678     if (IS_ALIGNED(width, 8)) {
   1679       NV21ToARGBRow = NV21ToARGBRow_NEON;
   1680     }
   1681   }
   1682 #endif
   1683 #if defined(HAS_NV21TOARGBROW_MSA)
   1684   if (TestCpuFlag(kCpuHasMSA)) {
   1685     NV21ToARGBRow = NV21ToARGBRow_Any_MSA;
   1686     if (IS_ALIGNED(width, 8)) {
   1687       NV21ToARGBRow = NV21ToARGBRow_MSA;
   1688     }
   1689   }
   1690 #endif
   1691 
   1692   for (y = 0; y < height; ++y) {
   1693     NV21ToARGBRow(src_y, src_vu, dst_argb, yuvconstants, width);
   1694     dst_argb += dst_stride_argb;
   1695     src_y += src_stride_y;
   1696     if (y & 1) {
   1697       src_vu += src_stride_vu;
   1698     }
   1699   }
   1700   return 0;
   1701 }
   1702 
   1703 // Convert NV12 to ARGB.
   1704 LIBYUV_API
   1705 int NV12ToARGB(const uint8_t* src_y,
   1706                int src_stride_y,
   1707                const uint8_t* src_uv,
   1708                int src_stride_uv,
   1709                uint8_t* dst_argb,
   1710                int dst_stride_argb,
   1711                int width,
   1712                int height) {
   1713   return NV12ToARGBMatrix(src_y, src_stride_y, src_uv, src_stride_uv, dst_argb,
   1714                           dst_stride_argb, &kYuvI601Constants, width, height);
   1715 }
   1716 
   1717 // Convert NV21 to ARGB.
   1718 LIBYUV_API
   1719 int NV21ToARGB(const uint8_t* src_y,
   1720                int src_stride_y,
   1721                const uint8_t* src_vu,
   1722                int src_stride_vu,
   1723                uint8_t* dst_argb,
   1724                int dst_stride_argb,
   1725                int width,
   1726                int height) {
   1727   return NV21ToARGBMatrix(src_y, src_stride_y, src_vu, src_stride_vu, dst_argb,
   1728                           dst_stride_argb, &kYuvI601Constants, width, height);
   1729 }
   1730 
   1731 // Convert NV12 to ABGR.
   1732 // To output ABGR instead of ARGB swap the UV and use a mirrrored yuc matrix.
   1733 // To swap the UV use NV12 instead of NV21.LIBYUV_API
   1734 int NV12ToABGR(const uint8_t* src_y,
   1735                int src_stride_y,
   1736                const uint8_t* src_uv,
   1737                int src_stride_uv,
   1738                uint8_t* dst_abgr,
   1739                int dst_stride_abgr,
   1740                int width,
   1741                int height) {
   1742   return NV21ToARGBMatrix(src_y, src_stride_y, src_uv, src_stride_uv, dst_abgr,
   1743                           dst_stride_abgr, &kYvuI601Constants, width, height);
   1744 }
   1745 
   1746 // Convert NV21 to ABGR.
   1747 LIBYUV_API
   1748 int NV21ToABGR(const uint8_t* src_y,
   1749                int src_stride_y,
   1750                const uint8_t* src_vu,
   1751                int src_stride_vu,
   1752                uint8_t* dst_abgr,
   1753                int dst_stride_abgr,
   1754                int width,
   1755                int height) {
   1756   return NV12ToARGBMatrix(src_y, src_stride_y, src_vu, src_stride_vu, dst_abgr,
   1757                           dst_stride_abgr, &kYvuI601Constants, width, height);
   1758 }
   1759 
   1760 // TODO(fbarchard): Consider SSSE3 2 step conversion.
   1761 // Convert NV12 to RGB24 with matrix
   1762 static int NV12ToRGB24Matrix(const uint8_t* src_y,
   1763                              int src_stride_y,
   1764                              const uint8_t* src_uv,
   1765                              int src_stride_uv,
   1766                              uint8_t* dst_rgb24,
   1767                              int dst_stride_rgb24,
   1768                              const struct YuvConstants* yuvconstants,
   1769                              int width,
   1770                              int height) {
   1771   int y;
   1772   void (*NV12ToRGB24Row)(
   1773       const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
   1774       const struct YuvConstants* yuvconstants, int width) = NV12ToRGB24Row_C;
   1775   if (!src_y || !src_uv || !dst_rgb24 || width <= 0 || height == 0) {
   1776     return -1;
   1777   }
   1778   // Negative height means invert the image.
   1779   if (height < 0) {
   1780     height = -height;
   1781     dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
   1782     dst_stride_rgb24 = -dst_stride_rgb24;
   1783   }
   1784 #if defined(HAS_NV12TORGB24ROW_NEON)
   1785   if (TestCpuFlag(kCpuHasNEON)) {
   1786     NV12ToRGB24Row = NV12ToRGB24Row_Any_NEON;
   1787     if (IS_ALIGNED(width, 8)) {
   1788       NV12ToRGB24Row = NV12ToRGB24Row_NEON;
   1789     }
   1790   }
   1791 #endif
   1792 #if defined(HAS_NV12TORGB24ROW_SSSE3)
   1793   if (TestCpuFlag(kCpuHasSSSE3)) {
   1794     NV12ToRGB24Row = NV12ToRGB24Row_Any_SSSE3;
   1795     if (IS_ALIGNED(width, 16)) {
   1796       NV12ToRGB24Row = NV12ToRGB24Row_SSSE3;
   1797     }
   1798   }
   1799 #endif
   1800 #if defined(HAS_NV12TORGB24ROW_AVX2)
   1801   if (TestCpuFlag(kCpuHasAVX2)) {
   1802     NV12ToRGB24Row = NV12ToRGB24Row_Any_AVX2;
   1803     if (IS_ALIGNED(width, 32)) {
   1804       NV12ToRGB24Row = NV12ToRGB24Row_AVX2;
   1805     }
   1806   }
   1807 #endif
   1808 
   1809   for (y = 0; y < height; ++y) {
   1810     NV12ToRGB24Row(src_y, src_uv, dst_rgb24, yuvconstants, width);
   1811     dst_rgb24 += dst_stride_rgb24;
   1812     src_y += src_stride_y;
   1813     if (y & 1) {
   1814       src_uv += src_stride_uv;
   1815     }
   1816   }
   1817   return 0;
   1818 }
   1819 
   1820 // Convert NV21 to RGB24 with matrix
   1821 static int NV21ToRGB24Matrix(const uint8_t* src_y,
   1822                              int src_stride_y,
   1823                              const uint8_t* src_vu,
   1824                              int src_stride_vu,
   1825                              uint8_t* dst_rgb24,
   1826                              int dst_stride_rgb24,
   1827                              const struct YuvConstants* yuvconstants,
   1828                              int width,
   1829                              int height) {
   1830   int y;
   1831   void (*NV21ToRGB24Row)(
   1832       const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
   1833       const struct YuvConstants* yuvconstants, int width) = NV21ToRGB24Row_C;
   1834   if (!src_y || !src_vu || !dst_rgb24 || width <= 0 || height == 0) {
   1835     return -1;
   1836   }
   1837   // Negative height means invert the image.
   1838   if (height < 0) {
   1839     height = -height;
   1840     dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
   1841     dst_stride_rgb24 = -dst_stride_rgb24;
   1842   }
   1843 #if defined(HAS_NV21TORGB24ROW_NEON)
   1844   if (TestCpuFlag(kCpuHasNEON)) {
   1845     NV21ToRGB24Row = NV21ToRGB24Row_Any_NEON;
   1846     if (IS_ALIGNED(width, 8)) {
   1847       NV21ToRGB24Row = NV21ToRGB24Row_NEON;
   1848     }
   1849   }
   1850 #endif
   1851 #if defined(HAS_NV21TORGB24ROW_SSSE3)
   1852   if (TestCpuFlag(kCpuHasSSSE3)) {
   1853     NV21ToRGB24Row = NV21ToRGB24Row_Any_SSSE3;
   1854     if (IS_ALIGNED(width, 16)) {
   1855       NV21ToRGB24Row = NV21ToRGB24Row_SSSE3;
   1856     }
   1857   }
   1858 #endif
   1859 #if defined(HAS_NV21TORGB24ROW_AVX2)
   1860   if (TestCpuFlag(kCpuHasAVX2)) {
   1861     NV21ToRGB24Row = NV21ToRGB24Row_Any_AVX2;
   1862     if (IS_ALIGNED(width, 32)) {
   1863       NV21ToRGB24Row = NV21ToRGB24Row_AVX2;
   1864     }
   1865   }
   1866 #endif
   1867 
   1868   for (y = 0; y < height; ++y) {
   1869     NV21ToRGB24Row(src_y, src_vu, dst_rgb24, yuvconstants, width);
   1870     dst_rgb24 += dst_stride_rgb24;
   1871     src_y += src_stride_y;
   1872     if (y & 1) {
   1873       src_vu += src_stride_vu;
   1874     }
   1875   }
   1876   return 0;
   1877 }
   1878 
   1879 // TODO(fbarchard): NV12ToRAW can be implemented by mirrored matrix.
   1880 // Convert NV12 to RGB24.
   1881 LIBYUV_API
   1882 int NV12ToRGB24(const uint8_t* src_y,
   1883                 int src_stride_y,
   1884                 const uint8_t* src_uv,
   1885                 int src_stride_uv,
   1886                 uint8_t* dst_rgb24,
   1887                 int dst_stride_rgb24,
   1888                 int width,
   1889                 int height) {
   1890   return NV12ToRGB24Matrix(src_y, src_stride_y, src_uv, src_stride_uv,
   1891                            dst_rgb24, dst_stride_rgb24, &kYuvI601Constants,
   1892                            width, height);
   1893 }
   1894 
   1895 // Convert NV21 to RGB24.
   1896 LIBYUV_API
   1897 int NV21ToRGB24(const uint8_t* src_y,
   1898                 int src_stride_y,
   1899                 const uint8_t* src_vu,
   1900                 int src_stride_vu,
   1901                 uint8_t* dst_rgb24,
   1902                 int dst_stride_rgb24,
   1903                 int width,
   1904                 int height) {
   1905   return NV21ToRGB24Matrix(src_y, src_stride_y, src_vu, src_stride_vu,
   1906                            dst_rgb24, dst_stride_rgb24, &kYuvI601Constants,
   1907                            width, height);
   1908 }
   1909 
   1910 // Convert M420 to ARGB.
   1911 LIBYUV_API
   1912 int M420ToARGB(const uint8_t* src_m420,
   1913                int src_stride_m420,
   1914                uint8_t* dst_argb,
   1915                int dst_stride_argb,
   1916                int width,
   1917                int height) {
   1918   int y;
   1919   void (*NV12ToARGBRow)(
   1920       const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
   1921       const struct YuvConstants* yuvconstants, int width) = NV12ToARGBRow_C;
   1922   if (!src_m420 || !dst_argb || width <= 0 || height == 0) {
   1923     return -1;
   1924   }
   1925   // Negative height means invert the image.
   1926   if (height < 0) {
   1927     height = -height;
   1928     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
   1929     dst_stride_argb = -dst_stride_argb;
   1930   }
   1931 #if defined(HAS_NV12TOARGBROW_SSSE3)
   1932   if (TestCpuFlag(kCpuHasSSSE3)) {
   1933     NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
   1934     if (IS_ALIGNED(width, 8)) {
   1935       NV12ToARGBRow = NV12ToARGBRow_SSSE3;
   1936     }
   1937   }
   1938 #endif
   1939 #if defined(HAS_NV12TOARGBROW_AVX2)
   1940   if (TestCpuFlag(kCpuHasAVX2)) {
   1941     NV12ToARGBRow = NV12ToARGBRow_Any_AVX2;
   1942     if (IS_ALIGNED(width, 16)) {
   1943       NV12ToARGBRow = NV12ToARGBRow_AVX2;
   1944     }
   1945   }
   1946 #endif
   1947 #if defined(HAS_NV12TOARGBROW_NEON)
   1948   if (TestCpuFlag(kCpuHasNEON)) {
   1949     NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
   1950     if (IS_ALIGNED(width, 8)) {
   1951       NV12ToARGBRow = NV12ToARGBRow_NEON;
   1952     }
   1953   }
   1954 #endif
   1955 #if defined(HAS_NV12TOARGBROW_MSA)
   1956   if (TestCpuFlag(kCpuHasMSA)) {
   1957     NV12ToARGBRow = NV12ToARGBRow_Any_MSA;
   1958     if (IS_ALIGNED(width, 8)) {
   1959       NV12ToARGBRow = NV12ToARGBRow_MSA;
   1960     }
   1961   }
   1962 #endif
   1963 
   1964   for (y = 0; y < height - 1; y += 2) {
   1965     NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb,
   1966                   &kYuvI601Constants, width);
   1967     NV12ToARGBRow(src_m420 + src_stride_m420, src_m420 + src_stride_m420 * 2,
   1968                   dst_argb + dst_stride_argb, &kYuvI601Constants, width);
   1969     dst_argb += dst_stride_argb * 2;
   1970     src_m420 += src_stride_m420 * 3;
   1971   }
   1972   if (height & 1) {
   1973     NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb,
   1974                   &kYuvI601Constants, width);
   1975   }
   1976   return 0;
   1977 }
   1978 
   1979 // Convert YUY2 to ARGB.
   1980 LIBYUV_API
   1981 int YUY2ToARGB(const uint8_t* src_yuy2,
   1982                int src_stride_yuy2,
   1983                uint8_t* dst_argb,
   1984                int dst_stride_argb,
   1985                int width,
   1986                int height) {
   1987   int y;
   1988   void (*YUY2ToARGBRow)(const uint8_t* src_yuy2, uint8_t* dst_argb,
   1989                         const struct YuvConstants* yuvconstants, int width) =
   1990       YUY2ToARGBRow_C;
   1991   if (!src_yuy2 || !dst_argb || width <= 0 || height == 0) {
   1992     return -1;
   1993   }
   1994   // Negative height means invert the image.
   1995   if (height < 0) {
   1996     height = -height;
   1997     src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
   1998     src_stride_yuy2 = -src_stride_yuy2;
   1999   }
   2000   // Coalesce rows.
   2001   if (src_stride_yuy2 == width * 2 && dst_stride_argb == width * 4) {
   2002     width *= height;
   2003     height = 1;
   2004     src_stride_yuy2 = dst_stride_argb = 0;
   2005   }
   2006 #if defined(HAS_YUY2TOARGBROW_SSSE3)
   2007   if (TestCpuFlag(kCpuHasSSSE3)) {
   2008     YUY2ToARGBRow = YUY2ToARGBRow_Any_SSSE3;
   2009     if (IS_ALIGNED(width, 16)) {
   2010       YUY2ToARGBRow = YUY2ToARGBRow_SSSE3;
   2011     }
   2012   }
   2013 #endif
   2014 #if defined(HAS_YUY2TOARGBROW_AVX2)
   2015   if (TestCpuFlag(kCpuHasAVX2)) {
   2016     YUY2ToARGBRow = YUY2ToARGBRow_Any_AVX2;
   2017     if (IS_ALIGNED(width, 32)) {
   2018       YUY2ToARGBRow = YUY2ToARGBRow_AVX2;
   2019     }
   2020   }
   2021 #endif
   2022 #if defined(HAS_YUY2TOARGBROW_NEON)
   2023   if (TestCpuFlag(kCpuHasNEON)) {
   2024     YUY2ToARGBRow = YUY2ToARGBRow_Any_NEON;
   2025     if (IS_ALIGNED(width, 8)) {
   2026       YUY2ToARGBRow = YUY2ToARGBRow_NEON;
   2027     }
   2028   }
   2029 #endif
   2030 #if defined(HAS_YUY2TOARGBROW_MSA)
   2031   if (TestCpuFlag(kCpuHasMSA)) {
   2032     YUY2ToARGBRow = YUY2ToARGBRow_Any_MSA;
   2033     if (IS_ALIGNED(width, 8)) {
   2034       YUY2ToARGBRow = YUY2ToARGBRow_MSA;
   2035     }
   2036   }
   2037 #endif
   2038   for (y = 0; y < height; ++y) {
   2039     YUY2ToARGBRow(src_yuy2, dst_argb, &kYuvI601Constants, width);
   2040     src_yuy2 += src_stride_yuy2;
   2041     dst_argb += dst_stride_argb;
   2042   }
   2043   return 0;
   2044 }
   2045 
   2046 // Convert UYVY to ARGB.
   2047 LIBYUV_API
   2048 int UYVYToARGB(const uint8_t* src_uyvy,
   2049                int src_stride_uyvy,
   2050                uint8_t* dst_argb,
   2051                int dst_stride_argb,
   2052                int width,
   2053                int height) {
   2054   int y;
   2055   void (*UYVYToARGBRow)(const uint8_t* src_uyvy, uint8_t* dst_argb,
   2056                         const struct YuvConstants* yuvconstants, int width) =
   2057       UYVYToARGBRow_C;
   2058   if (!src_uyvy || !dst_argb || width <= 0 || height == 0) {
   2059     return -1;
   2060   }
   2061   // Negative height means invert the image.
   2062   if (height < 0) {
   2063     height = -height;
   2064     src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
   2065     src_stride_uyvy = -src_stride_uyvy;
   2066   }
   2067   // Coalesce rows.
   2068   if (src_stride_uyvy == width * 2 && dst_stride_argb == width * 4) {
   2069     width *= height;
   2070     height = 1;
   2071     src_stride_uyvy = dst_stride_argb = 0;
   2072   }
   2073 #if defined(HAS_UYVYTOARGBROW_SSSE3)
   2074   if (TestCpuFlag(kCpuHasSSSE3)) {
   2075     UYVYToARGBRow = UYVYToARGBRow_Any_SSSE3;
   2076     if (IS_ALIGNED(width, 16)) {
   2077       UYVYToARGBRow = UYVYToARGBRow_SSSE3;
   2078     }
   2079   }
   2080 #endif
   2081 #if defined(HAS_UYVYTOARGBROW_AVX2)
   2082   if (TestCpuFlag(kCpuHasAVX2)) {
   2083     UYVYToARGBRow = UYVYToARGBRow_Any_AVX2;
   2084     if (IS_ALIGNED(width, 32)) {
   2085       UYVYToARGBRow = UYVYToARGBRow_AVX2;
   2086     }
   2087   }
   2088 #endif
   2089 #if defined(HAS_UYVYTOARGBROW_NEON)
   2090   if (TestCpuFlag(kCpuHasNEON)) {
   2091     UYVYToARGBRow = UYVYToARGBRow_Any_NEON;
   2092     if (IS_ALIGNED(width, 8)) {
   2093       UYVYToARGBRow = UYVYToARGBRow_NEON;
   2094     }
   2095   }
   2096 #endif
   2097 #if defined(HAS_UYVYTOARGBROW_MSA)
   2098   if (TestCpuFlag(kCpuHasMSA)) {
   2099     UYVYToARGBRow = UYVYToARGBRow_Any_MSA;
   2100     if (IS_ALIGNED(width, 8)) {
   2101       UYVYToARGBRow = UYVYToARGBRow_MSA;
   2102     }
   2103   }
   2104 #endif
   2105   for (y = 0; y < height; ++y) {
   2106     UYVYToARGBRow(src_uyvy, dst_argb, &kYuvI601Constants, width);
   2107     src_uyvy += src_stride_uyvy;
   2108     dst_argb += dst_stride_argb;
   2109   }
   2110   return 0;
   2111 }
   2112 static void WeavePixels(const uint8_t* src_u,
   2113                         const uint8_t* src_v,
   2114                         int src_pixel_stride_uv,
   2115                         uint8_t* dst_uv,
   2116                         int width) {
   2117   int i;
   2118   for (i = 0; i < width; ++i) {
   2119     dst_uv[0] = *src_u;
   2120     dst_uv[1] = *src_v;
   2121     dst_uv += 2;
   2122     src_u += src_pixel_stride_uv;
   2123     src_v += src_pixel_stride_uv;
   2124   }
   2125 }
   2126 
   2127 // Convert Android420 to ARGB.
   2128 LIBYUV_API
   2129 int Android420ToARGBMatrix(const uint8_t* src_y,
   2130                            int src_stride_y,
   2131                            const uint8_t* src_u,
   2132                            int src_stride_u,
   2133                            const uint8_t* src_v,
   2134                            int src_stride_v,
   2135                            int src_pixel_stride_uv,
   2136                            uint8_t* dst_argb,
   2137                            int dst_stride_argb,
   2138                            const struct YuvConstants* yuvconstants,
   2139                            int width,
   2140                            int height) {
   2141   int y;
   2142   uint8_t* dst_uv;
   2143   const ptrdiff_t vu_off = src_v - src_u;
   2144   int halfwidth = (width + 1) >> 1;
   2145   int halfheight = (height + 1) >> 1;
   2146   if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
   2147     return -1;
   2148   }
   2149   // Negative height means invert the image.
   2150   if (height < 0) {
   2151     height = -height;
   2152     halfheight = (height + 1) >> 1;
   2153     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
   2154     dst_stride_argb = -dst_stride_argb;
   2155   }
   2156 
   2157   // I420
   2158   if (src_pixel_stride_uv == 1) {
   2159     return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
   2160                             src_stride_v, dst_argb, dst_stride_argb,
   2161                             yuvconstants, width, height);
   2162     // NV21
   2163   }
   2164   if (src_pixel_stride_uv == 2 && vu_off == -1 &&
   2165       src_stride_u == src_stride_v) {
   2166     return NV21ToARGBMatrix(src_y, src_stride_y, src_v, src_stride_v, dst_argb,
   2167                             dst_stride_argb, yuvconstants, width, height);
   2168     // NV12
   2169   }
   2170   if (src_pixel_stride_uv == 2 && vu_off == 1 && src_stride_u == src_stride_v) {
   2171     return NV12ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, dst_argb,
   2172                             dst_stride_argb, yuvconstants, width, height);
   2173   }
   2174 
   2175   // General case fallback creates NV12
   2176   align_buffer_64(plane_uv, halfwidth * 2 * halfheight);
   2177   dst_uv = plane_uv;
   2178   for (y = 0; y < halfheight; ++y) {
   2179     WeavePixels(src_u, src_v, src_pixel_stride_uv, dst_uv, halfwidth);
   2180     src_u += src_stride_u;
   2181     src_v += src_stride_v;
   2182     dst_uv += halfwidth * 2;
   2183   }
   2184   NV12ToARGBMatrix(src_y, src_stride_y, plane_uv, halfwidth * 2, dst_argb,
   2185                    dst_stride_argb, yuvconstants, width, height);
   2186   free_aligned_buffer_64(plane_uv);
   2187   return 0;
   2188 }
   2189 
   2190 // Convert Android420 to ARGB.
   2191 LIBYUV_API
   2192 int Android420ToARGB(const uint8_t* src_y,
   2193                      int src_stride_y,
   2194                      const uint8_t* src_u,
   2195                      int src_stride_u,
   2196                      const uint8_t* src_v,
   2197                      int src_stride_v,
   2198                      int src_pixel_stride_uv,
   2199                      uint8_t* dst_argb,
   2200                      int dst_stride_argb,
   2201                      int width,
   2202                      int height) {
   2203   return Android420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
   2204                                 src_stride_v, src_pixel_stride_uv, dst_argb,
   2205                                 dst_stride_argb, &kYuvI601Constants, width,
   2206                                 height);
   2207 }
   2208 
   2209 // Convert Android420 to ABGR.
   2210 LIBYUV_API
   2211 int Android420ToABGR(const uint8_t* src_y,
   2212                      int src_stride_y,
   2213                      const uint8_t* src_u,
   2214                      int src_stride_u,
   2215                      const uint8_t* src_v,
   2216                      int src_stride_v,
   2217                      int src_pixel_stride_uv,
   2218                      uint8_t* dst_abgr,
   2219                      int dst_stride_abgr,
   2220                      int width,
   2221                      int height) {
   2222   return Android420ToARGBMatrix(src_y, src_stride_y, src_v, src_stride_v, src_u,
   2223                                 src_stride_u, src_pixel_stride_uv, dst_abgr,
   2224                                 dst_stride_abgr, &kYvuI601Constants, width,
   2225                                 height);
   2226 }
   2227 
   2228 #ifdef __cplusplus
   2229 }  // extern "C"
   2230 }  // namespace libyuv
   2231 #endif
   2232