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* src_argb,
     30              int src_stride_argb,
     31              uint8* 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 I422 to ARGB with matrix
     51 static int I420ToARGBMatrix(const uint8* src_y,
     52                             int src_stride_y,
     53                             const uint8* src_u,
     54                             int src_stride_u,
     55                             const uint8* src_v,
     56                             int src_stride_v,
     57                             uint8* 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* y_buf, const uint8* u_buf,
     64                         const uint8* v_buf, uint8* 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_DSPR2)
    101   if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 4) &&
    102       IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
    103       IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
    104       IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
    105       IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) {
    106     I422ToARGBRow = I422ToARGBRow_DSPR2;
    107   }
    108 #endif
    109 #if defined(HAS_I422TOARGBROW_MSA)
    110   if (TestCpuFlag(kCpuHasMSA)) {
    111     I422ToARGBRow = I422ToARGBRow_Any_MSA;
    112     if (IS_ALIGNED(width, 8)) {
    113       I422ToARGBRow = I422ToARGBRow_MSA;
    114     }
    115   }
    116 #endif
    117 
    118   for (y = 0; y < height; ++y) {
    119     I422ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
    120     dst_argb += dst_stride_argb;
    121     src_y += src_stride_y;
    122     if (y & 1) {
    123       src_u += src_stride_u;
    124       src_v += src_stride_v;
    125     }
    126   }
    127   return 0;
    128 }
    129 
    130 // Convert I420 to ARGB.
    131 LIBYUV_API
    132 int I420ToARGB(const uint8* src_y,
    133                int src_stride_y,
    134                const uint8* src_u,
    135                int src_stride_u,
    136                const uint8* src_v,
    137                int src_stride_v,
    138                uint8* dst_argb,
    139                int dst_stride_argb,
    140                int width,
    141                int height) {
    142   return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
    143                           src_stride_v, dst_argb, dst_stride_argb,
    144                           &kYuvI601Constants, width, height);
    145 }
    146 
    147 // Convert I420 to ABGR.
    148 LIBYUV_API
    149 int I420ToABGR(const uint8* src_y,
    150                int src_stride_y,
    151                const uint8* src_u,
    152                int src_stride_u,
    153                const uint8* src_v,
    154                int src_stride_v,
    155                uint8* dst_abgr,
    156                int dst_stride_abgr,
    157                int width,
    158                int height) {
    159   return I420ToARGBMatrix(src_y, src_stride_y, src_v,
    160                           src_stride_v,  // Swap U and V
    161                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
    162                           &kYvuI601Constants,  // Use Yvu matrix
    163                           width, height);
    164 }
    165 
    166 // Convert J420 to ARGB.
    167 LIBYUV_API
    168 int J420ToARGB(const uint8* src_y,
    169                int src_stride_y,
    170                const uint8* src_u,
    171                int src_stride_u,
    172                const uint8* src_v,
    173                int src_stride_v,
    174                uint8* dst_argb,
    175                int dst_stride_argb,
    176                int width,
    177                int height) {
    178   return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
    179                           src_stride_v, dst_argb, dst_stride_argb,
    180                           &kYuvJPEGConstants, width, height);
    181 }
    182 
    183 // Convert J420 to ABGR.
    184 LIBYUV_API
    185 int J420ToABGR(const uint8* src_y,
    186                int src_stride_y,
    187                const uint8* src_u,
    188                int src_stride_u,
    189                const uint8* src_v,
    190                int src_stride_v,
    191                uint8* dst_abgr,
    192                int dst_stride_abgr,
    193                int width,
    194                int height) {
    195   return I420ToARGBMatrix(src_y, src_stride_y, src_v,
    196                           src_stride_v,  // Swap U and V
    197                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
    198                           &kYvuJPEGConstants,  // Use Yvu matrix
    199                           width, height);
    200 }
    201 
    202 // Convert H420 to ARGB.
    203 LIBYUV_API
    204 int H420ToARGB(const uint8* src_y,
    205                int src_stride_y,
    206                const uint8* src_u,
    207                int src_stride_u,
    208                const uint8* src_v,
    209                int src_stride_v,
    210                uint8* dst_argb,
    211                int dst_stride_argb,
    212                int width,
    213                int height) {
    214   return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
    215                           src_stride_v, dst_argb, dst_stride_argb,
    216                           &kYuvH709Constants, width, height);
    217 }
    218 
    219 // Convert H420 to ABGR.
    220 LIBYUV_API
    221 int H420ToABGR(const uint8* src_y,
    222                int src_stride_y,
    223                const uint8* src_u,
    224                int src_stride_u,
    225                const uint8* src_v,
    226                int src_stride_v,
    227                uint8* dst_abgr,
    228                int dst_stride_abgr,
    229                int width,
    230                int height) {
    231   return I420ToARGBMatrix(src_y, src_stride_y, src_v,
    232                           src_stride_v,  // Swap U and V
    233                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
    234                           &kYvuH709Constants,  // Use Yvu matrix
    235                           width, height);
    236 }
    237 
    238 // Convert I422 to ARGB with matrix
    239 static int I422ToARGBMatrix(const uint8* src_y,
    240                             int src_stride_y,
    241                             const uint8* src_u,
    242                             int src_stride_u,
    243                             const uint8* src_v,
    244                             int src_stride_v,
    245                             uint8* dst_argb,
    246                             int dst_stride_argb,
    247                             const struct YuvConstants* yuvconstants,
    248                             int width,
    249                             int height) {
    250   int y;
    251   void (*I422ToARGBRow)(const uint8* y_buf, const uint8* u_buf,
    252                         const uint8* v_buf, uint8* rgb_buf,
    253                         const struct YuvConstants* yuvconstants, int width) =
    254       I422ToARGBRow_C;
    255   if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
    256     return -1;
    257   }
    258   // Negative height means invert the image.
    259   if (height < 0) {
    260     height = -height;
    261     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
    262     dst_stride_argb = -dst_stride_argb;
    263   }
    264   // Coalesce rows.
    265   if (src_stride_y == width && src_stride_u * 2 == width &&
    266       src_stride_v * 2 == width && dst_stride_argb == width * 4) {
    267     width *= height;
    268     height = 1;
    269     src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
    270   }
    271 #if defined(HAS_I422TOARGBROW_SSSE3)
    272   if (TestCpuFlag(kCpuHasSSSE3)) {
    273     I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
    274     if (IS_ALIGNED(width, 8)) {
    275       I422ToARGBRow = I422ToARGBRow_SSSE3;
    276     }
    277   }
    278 #endif
    279 #if defined(HAS_I422TOARGBROW_AVX2)
    280   if (TestCpuFlag(kCpuHasAVX2)) {
    281     I422ToARGBRow = I422ToARGBRow_Any_AVX2;
    282     if (IS_ALIGNED(width, 16)) {
    283       I422ToARGBRow = I422ToARGBRow_AVX2;
    284     }
    285   }
    286 #endif
    287 #if defined(HAS_I422TOARGBROW_NEON)
    288   if (TestCpuFlag(kCpuHasNEON)) {
    289     I422ToARGBRow = I422ToARGBRow_Any_NEON;
    290     if (IS_ALIGNED(width, 8)) {
    291       I422ToARGBRow = I422ToARGBRow_NEON;
    292     }
    293   }
    294 #endif
    295 #if defined(HAS_I422TOARGBROW_DSPR2)
    296   if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 4) &&
    297       IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
    298       IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
    299       IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
    300       IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) {
    301     I422ToARGBRow = I422ToARGBRow_DSPR2;
    302   }
    303 #endif
    304 #if defined(HAS_I422TOARGBROW_MSA)
    305   if (TestCpuFlag(kCpuHasMSA)) {
    306     I422ToARGBRow = I422ToARGBRow_Any_MSA;
    307     if (IS_ALIGNED(width, 8)) {
    308       I422ToARGBRow = I422ToARGBRow_MSA;
    309     }
    310   }
    311 #endif
    312 
    313   for (y = 0; y < height; ++y) {
    314     I422ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
    315     dst_argb += dst_stride_argb;
    316     src_y += src_stride_y;
    317     src_u += src_stride_u;
    318     src_v += src_stride_v;
    319   }
    320   return 0;
    321 }
    322 
    323 // Convert I422 to ARGB.
    324 LIBYUV_API
    325 int I422ToARGB(const uint8* src_y,
    326                int src_stride_y,
    327                const uint8* src_u,
    328                int src_stride_u,
    329                const uint8* src_v,
    330                int src_stride_v,
    331                uint8* dst_argb,
    332                int dst_stride_argb,
    333                int width,
    334                int height) {
    335   return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
    336                           src_stride_v, dst_argb, dst_stride_argb,
    337                           &kYuvI601Constants, width, height);
    338 }
    339 
    340 // Convert I422 to ABGR.
    341 LIBYUV_API
    342 int I422ToABGR(const uint8* src_y,
    343                int src_stride_y,
    344                const uint8* src_u,
    345                int src_stride_u,
    346                const uint8* src_v,
    347                int src_stride_v,
    348                uint8* dst_abgr,
    349                int dst_stride_abgr,
    350                int width,
    351                int height) {
    352   return I422ToARGBMatrix(src_y, src_stride_y, src_v,
    353                           src_stride_v,  // Swap U and V
    354                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
    355                           &kYvuI601Constants,  // Use Yvu matrix
    356                           width, height);
    357 }
    358 
    359 // Convert J422 to ARGB.
    360 LIBYUV_API
    361 int J422ToARGB(const uint8* src_y,
    362                int src_stride_y,
    363                const uint8* src_u,
    364                int src_stride_u,
    365                const uint8* src_v,
    366                int src_stride_v,
    367                uint8* dst_argb,
    368                int dst_stride_argb,
    369                int width,
    370                int height) {
    371   return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
    372                           src_stride_v, dst_argb, dst_stride_argb,
    373                           &kYuvJPEGConstants, width, height);
    374 }
    375 
    376 // Convert J422 to ABGR.
    377 LIBYUV_API
    378 int J422ToABGR(const uint8* src_y,
    379                int src_stride_y,
    380                const uint8* src_u,
    381                int src_stride_u,
    382                const uint8* src_v,
    383                int src_stride_v,
    384                uint8* dst_abgr,
    385                int dst_stride_abgr,
    386                int width,
    387                int height) {
    388   return I422ToARGBMatrix(src_y, src_stride_y, src_v,
    389                           src_stride_v,  // Swap U and V
    390                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
    391                           &kYvuJPEGConstants,  // Use Yvu matrix
    392                           width, height);
    393 }
    394 
    395 // Convert H422 to ARGB.
    396 LIBYUV_API
    397 int H422ToARGB(const uint8* src_y,
    398                int src_stride_y,
    399                const uint8* src_u,
    400                int src_stride_u,
    401                const uint8* src_v,
    402                int src_stride_v,
    403                uint8* dst_argb,
    404                int dst_stride_argb,
    405                int width,
    406                int height) {
    407   return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
    408                           src_stride_v, dst_argb, dst_stride_argb,
    409                           &kYuvH709Constants, width, height);
    410 }
    411 
    412 // Convert H422 to ABGR.
    413 LIBYUV_API
    414 int H422ToABGR(const uint8* src_y,
    415                int src_stride_y,
    416                const uint8* src_u,
    417                int src_stride_u,
    418                const uint8* src_v,
    419                int src_stride_v,
    420                uint8* dst_abgr,
    421                int dst_stride_abgr,
    422                int width,
    423                int height) {
    424   return I422ToARGBMatrix(src_y, src_stride_y, src_v,
    425                           src_stride_v,  // Swap U and V
    426                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
    427                           &kYvuH709Constants,  // Use Yvu matrix
    428                           width, height);
    429 }
    430 
    431 // Convert I444 to ARGB with matrix
    432 static int I444ToARGBMatrix(const uint8* src_y,
    433                             int src_stride_y,
    434                             const uint8* src_u,
    435                             int src_stride_u,
    436                             const uint8* src_v,
    437                             int src_stride_v,
    438                             uint8* dst_argb,
    439                             int dst_stride_argb,
    440                             const struct YuvConstants* yuvconstants,
    441                             int width,
    442                             int height) {
    443   int y;
    444   void (*I444ToARGBRow)(const uint8* y_buf, const uint8* u_buf,
    445                         const uint8* v_buf, uint8* rgb_buf,
    446                         const struct YuvConstants* yuvconstants, int width) =
    447       I444ToARGBRow_C;
    448   if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
    449     return -1;
    450   }
    451   // Negative height means invert the image.
    452   if (height < 0) {
    453     height = -height;
    454     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
    455     dst_stride_argb = -dst_stride_argb;
    456   }
    457   // Coalesce rows.
    458   if (src_stride_y == width && src_stride_u == width && src_stride_v == width &&
    459       dst_stride_argb == width * 4) {
    460     width *= height;
    461     height = 1;
    462     src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
    463   }
    464 #if defined(HAS_I444TOARGBROW_SSSE3)
    465   if (TestCpuFlag(kCpuHasSSSE3)) {
    466     I444ToARGBRow = I444ToARGBRow_Any_SSSE3;
    467     if (IS_ALIGNED(width, 8)) {
    468       I444ToARGBRow = I444ToARGBRow_SSSE3;
    469     }
    470   }
    471 #endif
    472 #if defined(HAS_I444TOARGBROW_AVX2)
    473   if (TestCpuFlag(kCpuHasAVX2)) {
    474     I444ToARGBRow = I444ToARGBRow_Any_AVX2;
    475     if (IS_ALIGNED(width, 16)) {
    476       I444ToARGBRow = I444ToARGBRow_AVX2;
    477     }
    478   }
    479 #endif
    480 #if defined(HAS_I444TOARGBROW_NEON)
    481   if (TestCpuFlag(kCpuHasNEON)) {
    482     I444ToARGBRow = I444ToARGBRow_Any_NEON;
    483     if (IS_ALIGNED(width, 8)) {
    484       I444ToARGBRow = I444ToARGBRow_NEON;
    485     }
    486   }
    487 #endif
    488 #if defined(HAS_I444TOARGBROW_DSPR2)
    489   if (TestCpuFlag(kCpuHasDSPR2)) {
    490     I444ToARGBRow = I444ToARGBRow_Any_DSPR2;
    491     if (IS_ALIGNED(width, 8)) {
    492       I444ToARGBRow = I444ToARGBRow_DSPR2;
    493     }
    494   }
    495 #endif
    496 #if defined(HAS_I444TOARGBROW_MSA)
    497   if (TestCpuFlag(kCpuHasMSA)) {
    498     I444ToARGBRow = I444ToARGBRow_Any_MSA;
    499     if (IS_ALIGNED(width, 8)) {
    500       I444ToARGBRow = I444ToARGBRow_MSA;
    501     }
    502   }
    503 #endif
    504 
    505   for (y = 0; y < height; ++y) {
    506     I444ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
    507     dst_argb += dst_stride_argb;
    508     src_y += src_stride_y;
    509     src_u += src_stride_u;
    510     src_v += src_stride_v;
    511   }
    512   return 0;
    513 }
    514 
    515 // Convert I444 to ARGB.
    516 LIBYUV_API
    517 int I444ToARGB(const uint8* src_y,
    518                int src_stride_y,
    519                const uint8* src_u,
    520                int src_stride_u,
    521                const uint8* src_v,
    522                int src_stride_v,
    523                uint8* dst_argb,
    524                int dst_stride_argb,
    525                int width,
    526                int height) {
    527   return I444ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
    528                           src_stride_v, dst_argb, dst_stride_argb,
    529                           &kYuvI601Constants, width, height);
    530 }
    531 
    532 // Convert I444 to ABGR.
    533 LIBYUV_API
    534 int I444ToABGR(const uint8* src_y,
    535                int src_stride_y,
    536                const uint8* src_u,
    537                int src_stride_u,
    538                const uint8* src_v,
    539                int src_stride_v,
    540                uint8* dst_abgr,
    541                int dst_stride_abgr,
    542                int width,
    543                int height) {
    544   return I444ToARGBMatrix(src_y, src_stride_y, src_v,
    545                           src_stride_v,  // Swap U and V
    546                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
    547                           &kYvuI601Constants,  // Use Yvu matrix
    548                           width, height);
    549 }
    550 
    551 // Convert J444 to ARGB.
    552 LIBYUV_API
    553 int J444ToARGB(const uint8* src_y,
    554                int src_stride_y,
    555                const uint8* src_u,
    556                int src_stride_u,
    557                const uint8* src_v,
    558                int src_stride_v,
    559                uint8* dst_argb,
    560                int dst_stride_argb,
    561                int width,
    562                int height) {
    563   return I444ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
    564                           src_stride_v, dst_argb, dst_stride_argb,
    565                           &kYuvJPEGConstants, width, height);
    566 }
    567 
    568 // Convert I420 with Alpha to preattenuated ARGB.
    569 static int I420AlphaToARGBMatrix(const uint8* src_y,
    570                                  int src_stride_y,
    571                                  const uint8* src_u,
    572                                  int src_stride_u,
    573                                  const uint8* src_v,
    574                                  int src_stride_v,
    575                                  const uint8* src_a,
    576                                  int src_stride_a,
    577                                  uint8* dst_argb,
    578                                  int dst_stride_argb,
    579                                  const struct YuvConstants* yuvconstants,
    580                                  int width,
    581                                  int height,
    582                                  int attenuate) {
    583   int y;
    584   void (*I422AlphaToARGBRow)(const uint8* y_buf, const uint8* u_buf,
    585                              const uint8* v_buf, const uint8* a_buf,
    586                              uint8* dst_argb,
    587                              const struct YuvConstants* yuvconstants,
    588                              int width) = I422AlphaToARGBRow_C;
    589   void (*ARGBAttenuateRow)(const uint8* src_argb, uint8* dst_argb, int width) =
    590       ARGBAttenuateRow_C;
    591   if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
    592     return -1;
    593   }
    594   // Negative height means invert the image.
    595   if (height < 0) {
    596     height = -height;
    597     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
    598     dst_stride_argb = -dst_stride_argb;
    599   }
    600 #if defined(HAS_I422ALPHATOARGBROW_SSSE3)
    601   if (TestCpuFlag(kCpuHasSSSE3)) {
    602     I422AlphaToARGBRow = I422AlphaToARGBRow_Any_SSSE3;
    603     if (IS_ALIGNED(width, 8)) {
    604       I422AlphaToARGBRow = I422AlphaToARGBRow_SSSE3;
    605     }
    606   }
    607 #endif
    608 #if defined(HAS_I422ALPHATOARGBROW_AVX2)
    609   if (TestCpuFlag(kCpuHasAVX2)) {
    610     I422AlphaToARGBRow = I422AlphaToARGBRow_Any_AVX2;
    611     if (IS_ALIGNED(width, 16)) {
    612       I422AlphaToARGBRow = I422AlphaToARGBRow_AVX2;
    613     }
    614   }
    615 #endif
    616 #if defined(HAS_I422ALPHATOARGBROW_NEON)
    617   if (TestCpuFlag(kCpuHasNEON)) {
    618     I422AlphaToARGBRow = I422AlphaToARGBRow_Any_NEON;
    619     if (IS_ALIGNED(width, 8)) {
    620       I422AlphaToARGBRow = I422AlphaToARGBRow_NEON;
    621     }
    622   }
    623 #endif
    624 #if defined(HAS_I422ALPHATOARGBROW_DSPR2)
    625   if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 4) &&
    626       IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
    627       IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
    628       IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
    629       IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) {
    630     I422AlphaToARGBRow = I422AlphaToARGBRow_DSPR2;
    631   }
    632 #endif
    633 #if defined(HAS_I422ALPHATOARGBROW_MSA)
    634   if (TestCpuFlag(kCpuHasMSA)) {
    635     I422AlphaToARGBRow = I422AlphaToARGBRow_Any_MSA;
    636     if (IS_ALIGNED(width, 8)) {
    637       I422AlphaToARGBRow = I422AlphaToARGBRow_MSA;
    638     }
    639   }
    640 #endif
    641 #if defined(HAS_ARGBATTENUATEROW_SSSE3)
    642   if (TestCpuFlag(kCpuHasSSSE3)) {
    643     ARGBAttenuateRow = ARGBAttenuateRow_Any_SSSE3;
    644     if (IS_ALIGNED(width, 4)) {
    645       ARGBAttenuateRow = ARGBAttenuateRow_SSSE3;
    646     }
    647   }
    648 #endif
    649 #if defined(HAS_ARGBATTENUATEROW_AVX2)
    650   if (TestCpuFlag(kCpuHasAVX2)) {
    651     ARGBAttenuateRow = ARGBAttenuateRow_Any_AVX2;
    652     if (IS_ALIGNED(width, 8)) {
    653       ARGBAttenuateRow = ARGBAttenuateRow_AVX2;
    654     }
    655   }
    656 #endif
    657 #if defined(HAS_ARGBATTENUATEROW_NEON)
    658   if (TestCpuFlag(kCpuHasNEON)) {
    659     ARGBAttenuateRow = ARGBAttenuateRow_Any_NEON;
    660     if (IS_ALIGNED(width, 8)) {
    661       ARGBAttenuateRow = ARGBAttenuateRow_NEON;
    662     }
    663   }
    664 #endif
    665 #if defined(HAS_ARGBATTENUATEROW_MSA)
    666   if (TestCpuFlag(kCpuHasMSA)) {
    667     ARGBAttenuateRow = ARGBAttenuateRow_Any_MSA;
    668     if (IS_ALIGNED(width, 8)) {
    669       ARGBAttenuateRow = ARGBAttenuateRow_MSA;
    670     }
    671   }
    672 #endif
    673 
    674   for (y = 0; y < height; ++y) {
    675     I422AlphaToARGBRow(src_y, src_u, src_v, src_a, dst_argb, yuvconstants,
    676                        width);
    677     if (attenuate) {
    678       ARGBAttenuateRow(dst_argb, dst_argb, width);
    679     }
    680     dst_argb += dst_stride_argb;
    681     src_a += src_stride_a;
    682     src_y += src_stride_y;
    683     if (y & 1) {
    684       src_u += src_stride_u;
    685       src_v += src_stride_v;
    686     }
    687   }
    688   return 0;
    689 }
    690 
    691 // Convert I420 with Alpha to ARGB.
    692 LIBYUV_API
    693 int I420AlphaToARGB(const uint8* src_y,
    694                     int src_stride_y,
    695                     const uint8* src_u,
    696                     int src_stride_u,
    697                     const uint8* src_v,
    698                     int src_stride_v,
    699                     const uint8* src_a,
    700                     int src_stride_a,
    701                     uint8* dst_argb,
    702                     int dst_stride_argb,
    703                     int width,
    704                     int height,
    705                     int attenuate) {
    706   return I420AlphaToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
    707                                src_stride_v, src_a, src_stride_a, dst_argb,
    708                                dst_stride_argb, &kYuvI601Constants, width,
    709                                height, attenuate);
    710 }
    711 
    712 // Convert I420 with Alpha to ABGR.
    713 LIBYUV_API
    714 int I420AlphaToABGR(const uint8* src_y,
    715                     int src_stride_y,
    716                     const uint8* src_u,
    717                     int src_stride_u,
    718                     const uint8* src_v,
    719                     int src_stride_v,
    720                     const uint8* src_a,
    721                     int src_stride_a,
    722                     uint8* dst_abgr,
    723                     int dst_stride_abgr,
    724                     int width,
    725                     int height,
    726                     int attenuate) {
    727   return I420AlphaToARGBMatrix(
    728       src_y, src_stride_y, src_v, src_stride_v,  // Swap U and V
    729       src_u, src_stride_u, src_a, src_stride_a, dst_abgr, dst_stride_abgr,
    730       &kYvuI601Constants,  // Use Yvu matrix
    731       width, height, attenuate);
    732 }
    733 
    734 // Convert I400 to ARGB.
    735 LIBYUV_API
    736 int I400ToARGB(const uint8* src_y,
    737                int src_stride_y,
    738                uint8* dst_argb,
    739                int dst_stride_argb,
    740                int width,
    741                int height) {
    742   int y;
    743   void (*I400ToARGBRow)(const uint8* y_buf, uint8* rgb_buf, int width) =
    744       I400ToARGBRow_C;
    745   if (!src_y || !dst_argb || width <= 0 || height == 0) {
    746     return -1;
    747   }
    748   // Negative height means invert the image.
    749   if (height < 0) {
    750     height = -height;
    751     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
    752     dst_stride_argb = -dst_stride_argb;
    753   }
    754   // Coalesce rows.
    755   if (src_stride_y == width && dst_stride_argb == width * 4) {
    756     width *= height;
    757     height = 1;
    758     src_stride_y = dst_stride_argb = 0;
    759   }
    760 #if defined(HAS_I400TOARGBROW_SSE2)
    761   if (TestCpuFlag(kCpuHasSSE2)) {
    762     I400ToARGBRow = I400ToARGBRow_Any_SSE2;
    763     if (IS_ALIGNED(width, 8)) {
    764       I400ToARGBRow = I400ToARGBRow_SSE2;
    765     }
    766   }
    767 #endif
    768 #if defined(HAS_I400TOARGBROW_AVX2)
    769   if (TestCpuFlag(kCpuHasAVX2)) {
    770     I400ToARGBRow = I400ToARGBRow_Any_AVX2;
    771     if (IS_ALIGNED(width, 16)) {
    772       I400ToARGBRow = I400ToARGBRow_AVX2;
    773     }
    774   }
    775 #endif
    776 #if defined(HAS_I400TOARGBROW_NEON)
    777   if (TestCpuFlag(kCpuHasNEON)) {
    778     I400ToARGBRow = I400ToARGBRow_Any_NEON;
    779     if (IS_ALIGNED(width, 8)) {
    780       I400ToARGBRow = I400ToARGBRow_NEON;
    781     }
    782   }
    783 #endif
    784 #if defined(HAS_I400TOARGBROW_MSA)
    785   if (TestCpuFlag(kCpuHasMSA)) {
    786     I400ToARGBRow = I400ToARGBRow_Any_MSA;
    787     if (IS_ALIGNED(width, 16)) {
    788       I400ToARGBRow = I400ToARGBRow_MSA;
    789     }
    790   }
    791 #endif
    792 
    793   for (y = 0; y < height; ++y) {
    794     I400ToARGBRow(src_y, dst_argb, width);
    795     dst_argb += dst_stride_argb;
    796     src_y += src_stride_y;
    797   }
    798   return 0;
    799 }
    800 
    801 // Convert J400 to ARGB.
    802 LIBYUV_API
    803 int J400ToARGB(const uint8* src_y,
    804                int src_stride_y,
    805                uint8* dst_argb,
    806                int dst_stride_argb,
    807                int width,
    808                int height) {
    809   int y;
    810   void (*J400ToARGBRow)(const uint8* src_y, uint8* dst_argb, int width) =
    811       J400ToARGBRow_C;
    812   if (!src_y || !dst_argb || width <= 0 || height == 0) {
    813     return -1;
    814   }
    815   // Negative height means invert the image.
    816   if (height < 0) {
    817     height = -height;
    818     src_y = src_y + (height - 1) * src_stride_y;
    819     src_stride_y = -src_stride_y;
    820   }
    821   // Coalesce rows.
    822   if (src_stride_y == width && dst_stride_argb == width * 4) {
    823     width *= height;
    824     height = 1;
    825     src_stride_y = dst_stride_argb = 0;
    826   }
    827 #if defined(HAS_J400TOARGBROW_SSE2)
    828   if (TestCpuFlag(kCpuHasSSE2)) {
    829     J400ToARGBRow = J400ToARGBRow_Any_SSE2;
    830     if (IS_ALIGNED(width, 8)) {
    831       J400ToARGBRow = J400ToARGBRow_SSE2;
    832     }
    833   }
    834 #endif
    835 #if defined(HAS_J400TOARGBROW_AVX2)
    836   if (TestCpuFlag(kCpuHasAVX2)) {
    837     J400ToARGBRow = J400ToARGBRow_Any_AVX2;
    838     if (IS_ALIGNED(width, 16)) {
    839       J400ToARGBRow = J400ToARGBRow_AVX2;
    840     }
    841   }
    842 #endif
    843 #if defined(HAS_J400TOARGBROW_NEON)
    844   if (TestCpuFlag(kCpuHasNEON)) {
    845     J400ToARGBRow = J400ToARGBRow_Any_NEON;
    846     if (IS_ALIGNED(width, 8)) {
    847       J400ToARGBRow = J400ToARGBRow_NEON;
    848     }
    849   }
    850 #endif
    851 #if defined(HAS_J400TOARGBROW_MSA)
    852   if (TestCpuFlag(kCpuHasMSA)) {
    853     J400ToARGBRow = J400ToARGBRow_Any_MSA;
    854     if (IS_ALIGNED(width, 16)) {
    855       J400ToARGBRow = J400ToARGBRow_MSA;
    856     }
    857   }
    858 #endif
    859   for (y = 0; y < height; ++y) {
    860     J400ToARGBRow(src_y, dst_argb, width);
    861     src_y += src_stride_y;
    862     dst_argb += dst_stride_argb;
    863   }
    864   return 0;
    865 }
    866 
    867 // Shuffle table for converting BGRA to ARGB.
    868 static uvec8 kShuffleMaskBGRAToARGB = {3u,  2u,  1u, 0u, 7u,  6u,  5u,  4u,
    869                                        11u, 10u, 9u, 8u, 15u, 14u, 13u, 12u};
    870 
    871 // Shuffle table for converting ABGR to ARGB.
    872 static uvec8 kShuffleMaskABGRToARGB = {2u,  1u, 0u, 3u,  6u,  5u,  4u,  7u,
    873                                        10u, 9u, 8u, 11u, 14u, 13u, 12u, 15u};
    874 
    875 // Shuffle table for converting RGBA to ARGB.
    876 static uvec8 kShuffleMaskRGBAToARGB = {1u, 2u,  3u,  0u, 5u,  6u,  7u,  4u,
    877                                        9u, 10u, 11u, 8u, 13u, 14u, 15u, 12u};
    878 
    879 // Convert BGRA to ARGB.
    880 LIBYUV_API
    881 int BGRAToARGB(const uint8* src_bgra,
    882                int src_stride_bgra,
    883                uint8* dst_argb,
    884                int dst_stride_argb,
    885                int width,
    886                int height) {
    887   return ARGBShuffle(src_bgra, src_stride_bgra, dst_argb, dst_stride_argb,
    888                      (const uint8*)(&kShuffleMaskBGRAToARGB), width, height);
    889 }
    890 
    891 // Convert ARGB to BGRA (same as BGRAToARGB).
    892 LIBYUV_API
    893 int ARGBToBGRA(const uint8* src_bgra,
    894                int src_stride_bgra,
    895                uint8* dst_argb,
    896                int dst_stride_argb,
    897                int width,
    898                int height) {
    899   return ARGBShuffle(src_bgra, src_stride_bgra, dst_argb, dst_stride_argb,
    900                      (const uint8*)(&kShuffleMaskBGRAToARGB), width, height);
    901 }
    902 
    903 // Convert ABGR to ARGB.
    904 LIBYUV_API
    905 int ABGRToARGB(const uint8* src_abgr,
    906                int src_stride_abgr,
    907                uint8* dst_argb,
    908                int dst_stride_argb,
    909                int width,
    910                int height) {
    911   return ARGBShuffle(src_abgr, src_stride_abgr, dst_argb, dst_stride_argb,
    912                      (const uint8*)(&kShuffleMaskABGRToARGB), width, height);
    913 }
    914 
    915 // Convert ARGB to ABGR to (same as ABGRToARGB).
    916 LIBYUV_API
    917 int ARGBToABGR(const uint8* src_abgr,
    918                int src_stride_abgr,
    919                uint8* dst_argb,
    920                int dst_stride_argb,
    921                int width,
    922                int height) {
    923   return ARGBShuffle(src_abgr, src_stride_abgr, dst_argb, dst_stride_argb,
    924                      (const uint8*)(&kShuffleMaskABGRToARGB), width, height);
    925 }
    926 
    927 // Convert RGBA to ARGB.
    928 LIBYUV_API
    929 int RGBAToARGB(const uint8* src_rgba,
    930                int src_stride_rgba,
    931                uint8* dst_argb,
    932                int dst_stride_argb,
    933                int width,
    934                int height) {
    935   return ARGBShuffle(src_rgba, src_stride_rgba, dst_argb, dst_stride_argb,
    936                      (const uint8*)(&kShuffleMaskRGBAToARGB), width, height);
    937 }
    938 
    939 // Convert RGB24 to ARGB.
    940 LIBYUV_API
    941 int RGB24ToARGB(const uint8* src_rgb24,
    942                 int src_stride_rgb24,
    943                 uint8* dst_argb,
    944                 int dst_stride_argb,
    945                 int width,
    946                 int height) {
    947   int y;
    948   void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) =
    949       RGB24ToARGBRow_C;
    950   if (!src_rgb24 || !dst_argb || width <= 0 || height == 0) {
    951     return -1;
    952   }
    953   // Negative height means invert the image.
    954   if (height < 0) {
    955     height = -height;
    956     src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
    957     src_stride_rgb24 = -src_stride_rgb24;
    958   }
    959   // Coalesce rows.
    960   if (src_stride_rgb24 == width * 3 && dst_stride_argb == width * 4) {
    961     width *= height;
    962     height = 1;
    963     src_stride_rgb24 = dst_stride_argb = 0;
    964   }
    965 #if defined(HAS_RGB24TOARGBROW_SSSE3)
    966   if (TestCpuFlag(kCpuHasSSSE3)) {
    967     RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
    968     if (IS_ALIGNED(width, 16)) {
    969       RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
    970     }
    971   }
    972 #endif
    973 #if defined(HAS_RGB24TOARGBROW_NEON)
    974   if (TestCpuFlag(kCpuHasNEON)) {
    975     RGB24ToARGBRow = RGB24ToARGBRow_Any_NEON;
    976     if (IS_ALIGNED(width, 8)) {
    977       RGB24ToARGBRow = RGB24ToARGBRow_NEON;
    978     }
    979   }
    980 #endif
    981 #if defined(HAS_RGB24TOARGBROW_DSPR2)
    982   if (TestCpuFlag(kCpuHasDSPR2)) {
    983     RGB24ToARGBRow = RGB24ToARGBRow_Any_DSPR2;
    984     if (IS_ALIGNED(width, 8)) {
    985       RGB24ToARGBRow = RGB24ToARGBRow_DSPR2;
    986     }
    987   }
    988 #endif
    989 #if defined(HAS_RGB24TOARGBROW_MSA)
    990   if (TestCpuFlag(kCpuHasMSA)) {
    991     RGB24ToARGBRow = RGB24ToARGBRow_Any_MSA;
    992     if (IS_ALIGNED(width, 16)) {
    993       RGB24ToARGBRow = RGB24ToARGBRow_MSA;
    994     }
    995   }
    996 #endif
    997 
    998   for (y = 0; y < height; ++y) {
    999     RGB24ToARGBRow(src_rgb24, dst_argb, width);
   1000     src_rgb24 += src_stride_rgb24;
   1001     dst_argb += dst_stride_argb;
   1002   }
   1003   return 0;
   1004 }
   1005 
   1006 // Convert RAW to ARGB.
   1007 LIBYUV_API
   1008 int RAWToARGB(const uint8* src_raw,
   1009               int src_stride_raw,
   1010               uint8* dst_argb,
   1011               int dst_stride_argb,
   1012               int width,
   1013               int height) {
   1014   int y;
   1015   void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) =
   1016       RAWToARGBRow_C;
   1017   if (!src_raw || !dst_argb || width <= 0 || height == 0) {
   1018     return -1;
   1019   }
   1020   // Negative height means invert the image.
   1021   if (height < 0) {
   1022     height = -height;
   1023     src_raw = src_raw + (height - 1) * src_stride_raw;
   1024     src_stride_raw = -src_stride_raw;
   1025   }
   1026   // Coalesce rows.
   1027   if (src_stride_raw == width * 3 && dst_stride_argb == width * 4) {
   1028     width *= height;
   1029     height = 1;
   1030     src_stride_raw = dst_stride_argb = 0;
   1031   }
   1032 #if defined(HAS_RAWTOARGBROW_SSSE3)
   1033   if (TestCpuFlag(kCpuHasSSSE3)) {
   1034     RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
   1035     if (IS_ALIGNED(width, 16)) {
   1036       RAWToARGBRow = RAWToARGBRow_SSSE3;
   1037     }
   1038   }
   1039 #endif
   1040 #if defined(HAS_RAWTOARGBROW_NEON)
   1041   if (TestCpuFlag(kCpuHasNEON)) {
   1042     RAWToARGBRow = RAWToARGBRow_Any_NEON;
   1043     if (IS_ALIGNED(width, 8)) {
   1044       RAWToARGBRow = RAWToARGBRow_NEON;
   1045     }
   1046   }
   1047 #endif
   1048 #if defined(HAS_RAWTOARGBROW_DSPR2)
   1049   if (TestCpuFlag(kCpuHasDSPR2)) {
   1050     RAWToARGBRow = RAWToARGBRow_Any_DSPR2;
   1051     if (IS_ALIGNED(width, 8)) {
   1052       RAWToARGBRow = RAWToARGBRow_DSPR2;
   1053     }
   1054   }
   1055 #endif
   1056 #if defined(HAS_RAWTOARGBROW_MSA)
   1057   if (TestCpuFlag(kCpuHasMSA)) {
   1058     RAWToARGBRow = RAWToARGBRow_Any_MSA;
   1059     if (IS_ALIGNED(width, 16)) {
   1060       RAWToARGBRow = RAWToARGBRow_MSA;
   1061     }
   1062   }
   1063 #endif
   1064 
   1065   for (y = 0; y < height; ++y) {
   1066     RAWToARGBRow(src_raw, dst_argb, width);
   1067     src_raw += src_stride_raw;
   1068     dst_argb += dst_stride_argb;
   1069   }
   1070   return 0;
   1071 }
   1072 
   1073 // Convert RGB565 to ARGB.
   1074 LIBYUV_API
   1075 int RGB565ToARGB(const uint8* src_rgb565,
   1076                  int src_stride_rgb565,
   1077                  uint8* dst_argb,
   1078                  int dst_stride_argb,
   1079                  int width,
   1080                  int height) {
   1081   int y;
   1082   void (*RGB565ToARGBRow)(const uint8* src_rgb565, uint8* dst_argb, int width) =
   1083       RGB565ToARGBRow_C;
   1084   if (!src_rgb565 || !dst_argb || width <= 0 || height == 0) {
   1085     return -1;
   1086   }
   1087   // Negative height means invert the image.
   1088   if (height < 0) {
   1089     height = -height;
   1090     src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
   1091     src_stride_rgb565 = -src_stride_rgb565;
   1092   }
   1093   // Coalesce rows.
   1094   if (src_stride_rgb565 == width * 2 && dst_stride_argb == width * 4) {
   1095     width *= height;
   1096     height = 1;
   1097     src_stride_rgb565 = dst_stride_argb = 0;
   1098   }
   1099 #if defined(HAS_RGB565TOARGBROW_SSE2)
   1100   if (TestCpuFlag(kCpuHasSSE2)) {
   1101     RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
   1102     if (IS_ALIGNED(width, 8)) {
   1103       RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
   1104     }
   1105   }
   1106 #endif
   1107 #if defined(HAS_RGB565TOARGBROW_AVX2)
   1108   if (TestCpuFlag(kCpuHasAVX2)) {
   1109     RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2;
   1110     if (IS_ALIGNED(width, 16)) {
   1111       RGB565ToARGBRow = RGB565ToARGBRow_AVX2;
   1112     }
   1113   }
   1114 #endif
   1115 #if defined(HAS_RGB565TOARGBROW_NEON)
   1116   if (TestCpuFlag(kCpuHasNEON)) {
   1117     RGB565ToARGBRow = RGB565ToARGBRow_Any_NEON;
   1118     if (IS_ALIGNED(width, 8)) {
   1119       RGB565ToARGBRow = RGB565ToARGBRow_NEON;
   1120     }
   1121   }
   1122 #endif
   1123 #if defined(HAS_RGB565TOARGBROW_DSPR2)
   1124   if (TestCpuFlag(kCpuHasDSPR2)) {
   1125     RGB565ToARGBRow = RGB565ToARGBRow_Any_DSPR2;
   1126     if (IS_ALIGNED(width, 8)) {
   1127       RGB565ToARGBRow = RGB565ToARGBRow_DSPR2;
   1128     }
   1129   }
   1130 #endif
   1131 #if defined(HAS_RGB565TOARGBROW_MSA)
   1132   if (TestCpuFlag(kCpuHasMSA)) {
   1133     RGB565ToARGBRow = RGB565ToARGBRow_Any_MSA;
   1134     if (IS_ALIGNED(width, 16)) {
   1135       RGB565ToARGBRow = RGB565ToARGBRow_MSA;
   1136     }
   1137   }
   1138 #endif
   1139 
   1140   for (y = 0; y < height; ++y) {
   1141     RGB565ToARGBRow(src_rgb565, dst_argb, width);
   1142     src_rgb565 += src_stride_rgb565;
   1143     dst_argb += dst_stride_argb;
   1144   }
   1145   return 0;
   1146 }
   1147 
   1148 // Convert ARGB1555 to ARGB.
   1149 LIBYUV_API
   1150 int ARGB1555ToARGB(const uint8* src_argb1555,
   1151                    int src_stride_argb1555,
   1152                    uint8* dst_argb,
   1153                    int dst_stride_argb,
   1154                    int width,
   1155                    int height) {
   1156   int y;
   1157   void (*ARGB1555ToARGBRow)(const uint8* src_argb1555, uint8* dst_argb,
   1158                             int width) = ARGB1555ToARGBRow_C;
   1159   if (!src_argb1555 || !dst_argb || width <= 0 || height == 0) {
   1160     return -1;
   1161   }
   1162   // Negative height means invert the image.
   1163   if (height < 0) {
   1164     height = -height;
   1165     src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
   1166     src_stride_argb1555 = -src_stride_argb1555;
   1167   }
   1168   // Coalesce rows.
   1169   if (src_stride_argb1555 == width * 2 && dst_stride_argb == width * 4) {
   1170     width *= height;
   1171     height = 1;
   1172     src_stride_argb1555 = dst_stride_argb = 0;
   1173   }
   1174 #if defined(HAS_ARGB1555TOARGBROW_SSE2)
   1175   if (TestCpuFlag(kCpuHasSSE2)) {
   1176     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
   1177     if (IS_ALIGNED(width, 8)) {
   1178       ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
   1179     }
   1180   }
   1181 #endif
   1182 #if defined(HAS_ARGB1555TOARGBROW_AVX2)
   1183   if (TestCpuFlag(kCpuHasAVX2)) {
   1184     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2;
   1185     if (IS_ALIGNED(width, 16)) {
   1186       ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2;
   1187     }
   1188   }
   1189 #endif
   1190 #if defined(HAS_ARGB1555TOARGBROW_NEON)
   1191   if (TestCpuFlag(kCpuHasNEON)) {
   1192     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_NEON;
   1193     if (IS_ALIGNED(width, 8)) {
   1194       ARGB1555ToARGBRow = ARGB1555ToARGBRow_NEON;
   1195     }
   1196   }
   1197 #endif
   1198 #if defined(HAS_ARGB1555TOARGBROW_DSPR2)
   1199   if (TestCpuFlag(kCpuHasDSPR2)) {
   1200     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_DSPR2;
   1201     if (IS_ALIGNED(width, 4)) {
   1202       ARGB1555ToARGBRow = ARGB1555ToARGBRow_DSPR2;
   1203     }
   1204   }
   1205 #endif
   1206 #if defined(HAS_ARGB1555TOARGBROW_MSA)
   1207   if (TestCpuFlag(kCpuHasMSA)) {
   1208     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_MSA;
   1209     if (IS_ALIGNED(width, 16)) {
   1210       ARGB1555ToARGBRow = ARGB1555ToARGBRow_MSA;
   1211     }
   1212   }
   1213 #endif
   1214 
   1215   for (y = 0; y < height; ++y) {
   1216     ARGB1555ToARGBRow(src_argb1555, dst_argb, width);
   1217     src_argb1555 += src_stride_argb1555;
   1218     dst_argb += dst_stride_argb;
   1219   }
   1220   return 0;
   1221 }
   1222 
   1223 // Convert ARGB4444 to ARGB.
   1224 LIBYUV_API
   1225 int ARGB4444ToARGB(const uint8* src_argb4444,
   1226                    int src_stride_argb4444,
   1227                    uint8* dst_argb,
   1228                    int dst_stride_argb,
   1229                    int width,
   1230                    int height) {
   1231   int y;
   1232   void (*ARGB4444ToARGBRow)(const uint8* src_argb4444, uint8* dst_argb,
   1233                             int width) = ARGB4444ToARGBRow_C;
   1234   if (!src_argb4444 || !dst_argb || width <= 0 || height == 0) {
   1235     return -1;
   1236   }
   1237   // Negative height means invert the image.
   1238   if (height < 0) {
   1239     height = -height;
   1240     src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
   1241     src_stride_argb4444 = -src_stride_argb4444;
   1242   }
   1243   // Coalesce rows.
   1244   if (src_stride_argb4444 == width * 2 && dst_stride_argb == width * 4) {
   1245     width *= height;
   1246     height = 1;
   1247     src_stride_argb4444 = dst_stride_argb = 0;
   1248   }
   1249 #if defined(HAS_ARGB4444TOARGBROW_SSE2)
   1250   if (TestCpuFlag(kCpuHasSSE2)) {
   1251     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
   1252     if (IS_ALIGNED(width, 8)) {
   1253       ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
   1254     }
   1255   }
   1256 #endif
   1257 #if defined(HAS_ARGB4444TOARGBROW_AVX2)
   1258   if (TestCpuFlag(kCpuHasAVX2)) {
   1259     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2;
   1260     if (IS_ALIGNED(width, 16)) {
   1261       ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2;
   1262     }
   1263   }
   1264 #endif
   1265 #if defined(HAS_ARGB4444TOARGBROW_NEON)
   1266   if (TestCpuFlag(kCpuHasNEON)) {
   1267     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_NEON;
   1268     if (IS_ALIGNED(width, 8)) {
   1269       ARGB4444ToARGBRow = ARGB4444ToARGBRow_NEON;
   1270     }
   1271   }
   1272 #endif
   1273 #if defined(HAS_ARGB4444TOARGBROW_DSPR2)
   1274   if (TestCpuFlag(kCpuHasDSPR2)) {
   1275     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_DSPR2;
   1276     if (IS_ALIGNED(width, 4)) {
   1277       ARGB4444ToARGBRow = ARGB4444ToARGBRow_DSPR2;
   1278     }
   1279   }
   1280 #endif
   1281 #if defined(HAS_ARGB4444TOARGBROW_MSA)
   1282   if (TestCpuFlag(kCpuHasMSA)) {
   1283     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MSA;
   1284     if (IS_ALIGNED(width, 16)) {
   1285       ARGB4444ToARGBRow = ARGB4444ToARGBRow_MSA;
   1286     }
   1287   }
   1288 #endif
   1289 
   1290   for (y = 0; y < height; ++y) {
   1291     ARGB4444ToARGBRow(src_argb4444, dst_argb, width);
   1292     src_argb4444 += src_stride_argb4444;
   1293     dst_argb += dst_stride_argb;
   1294   }
   1295   return 0;
   1296 }
   1297 
   1298 // Convert NV12 to ARGB with matrix
   1299 static int NV12ToARGBMatrix(const uint8* src_y,
   1300                             int src_stride_y,
   1301                             const uint8* src_uv,
   1302                             int src_stride_uv,
   1303                             uint8* dst_argb,
   1304                             int dst_stride_argb,
   1305                             const struct YuvConstants* yuvconstants,
   1306                             int width,
   1307                             int height) {
   1308   int y;
   1309   void (*NV12ToARGBRow)(const uint8* y_buf, const uint8* uv_buf, uint8* rgb_buf,
   1310                         const struct YuvConstants* yuvconstants, int width) =
   1311       NV12ToARGBRow_C;
   1312   if (!src_y || !src_uv || !dst_argb || width <= 0 || height == 0) {
   1313     return -1;
   1314   }
   1315   // Negative height means invert the image.
   1316   if (height < 0) {
   1317     height = -height;
   1318     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
   1319     dst_stride_argb = -dst_stride_argb;
   1320   }
   1321 #if defined(HAS_NV12TOARGBROW_SSSE3)
   1322   if (TestCpuFlag(kCpuHasSSSE3)) {
   1323     NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
   1324     if (IS_ALIGNED(width, 8)) {
   1325       NV12ToARGBRow = NV12ToARGBRow_SSSE3;
   1326     }
   1327   }
   1328 #endif
   1329 #if defined(HAS_NV12TOARGBROW_AVX2)
   1330   if (TestCpuFlag(kCpuHasAVX2)) {
   1331     NV12ToARGBRow = NV12ToARGBRow_Any_AVX2;
   1332     if (IS_ALIGNED(width, 16)) {
   1333       NV12ToARGBRow = NV12ToARGBRow_AVX2;
   1334     }
   1335   }
   1336 #endif
   1337 #if defined(HAS_NV12TOARGBROW_NEON)
   1338   if (TestCpuFlag(kCpuHasNEON)) {
   1339     NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
   1340     if (IS_ALIGNED(width, 8)) {
   1341       NV12ToARGBRow = NV12ToARGBRow_NEON;
   1342     }
   1343   }
   1344 #endif
   1345 #if defined(HAS_NV12TOARGBROW_DSPR2)
   1346   if (TestCpuFlag(kCpuHasDSPR2)) {
   1347     NV12ToARGBRow = NV12ToARGBRow_Any_DSPR2;
   1348     if (IS_ALIGNED(width, 8)) {
   1349       NV12ToARGBRow = NV12ToARGBRow_DSPR2;
   1350     }
   1351   }
   1352 #endif
   1353 #if defined(HAS_NV12TOARGBROW_MSA)
   1354   if (TestCpuFlag(kCpuHasMSA)) {
   1355     NV12ToARGBRow = NV12ToARGBRow_Any_MSA;
   1356     if (IS_ALIGNED(width, 8)) {
   1357       NV12ToARGBRow = NV12ToARGBRow_MSA;
   1358     }
   1359   }
   1360 #endif
   1361 
   1362   for (y = 0; y < height; ++y) {
   1363     NV12ToARGBRow(src_y, src_uv, dst_argb, yuvconstants, width);
   1364     dst_argb += dst_stride_argb;
   1365     src_y += src_stride_y;
   1366     if (y & 1) {
   1367       src_uv += src_stride_uv;
   1368     }
   1369   }
   1370   return 0;
   1371 }
   1372 
   1373 // Convert NV21 to ARGB with matrix
   1374 static int NV21ToARGBMatrix(const uint8* src_y,
   1375                             int src_stride_y,
   1376                             const uint8* src_uv,
   1377                             int src_stride_uv,
   1378                             uint8* dst_argb,
   1379                             int dst_stride_argb,
   1380                             const struct YuvConstants* yuvconstants,
   1381                             int width,
   1382                             int height) {
   1383   int y;
   1384   void (*NV21ToARGBRow)(const uint8* y_buf, const uint8* uv_buf, uint8* rgb_buf,
   1385                         const struct YuvConstants* yuvconstants, int width) =
   1386       NV21ToARGBRow_C;
   1387   if (!src_y || !src_uv || !dst_argb || width <= 0 || height == 0) {
   1388     return -1;
   1389   }
   1390   // Negative height means invert the image.
   1391   if (height < 0) {
   1392     height = -height;
   1393     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
   1394     dst_stride_argb = -dst_stride_argb;
   1395   }
   1396 #if defined(HAS_NV21TOARGBROW_SSSE3)
   1397   if (TestCpuFlag(kCpuHasSSSE3)) {
   1398     NV21ToARGBRow = NV21ToARGBRow_Any_SSSE3;
   1399     if (IS_ALIGNED(width, 8)) {
   1400       NV21ToARGBRow = NV21ToARGBRow_SSSE3;
   1401     }
   1402   }
   1403 #endif
   1404 #if defined(HAS_NV21TOARGBROW_AVX2)
   1405   if (TestCpuFlag(kCpuHasAVX2)) {
   1406     NV21ToARGBRow = NV21ToARGBRow_Any_AVX2;
   1407     if (IS_ALIGNED(width, 16)) {
   1408       NV21ToARGBRow = NV21ToARGBRow_AVX2;
   1409     }
   1410   }
   1411 #endif
   1412 #if defined(HAS_NV21TOARGBROW_NEON)
   1413   if (TestCpuFlag(kCpuHasNEON)) {
   1414     NV21ToARGBRow = NV21ToARGBRow_Any_NEON;
   1415     if (IS_ALIGNED(width, 8)) {
   1416       NV21ToARGBRow = NV21ToARGBRow_NEON;
   1417     }
   1418   }
   1419 #endif
   1420 #if defined(HAS_NV21TOARGBROW_MSA)
   1421   if (TestCpuFlag(kCpuHasMSA)) {
   1422     NV21ToARGBRow = NV21ToARGBRow_Any_MSA;
   1423     if (IS_ALIGNED(width, 8)) {
   1424       NV21ToARGBRow = NV21ToARGBRow_MSA;
   1425     }
   1426   }
   1427 #endif
   1428 
   1429   for (y = 0; y < height; ++y) {
   1430     NV21ToARGBRow(src_y, src_uv, dst_argb, yuvconstants, width);
   1431     dst_argb += dst_stride_argb;
   1432     src_y += src_stride_y;
   1433     if (y & 1) {
   1434       src_uv += src_stride_uv;
   1435     }
   1436   }
   1437   return 0;
   1438 }
   1439 
   1440 // Convert NV12 to ARGB.
   1441 LIBYUV_API
   1442 int NV12ToARGB(const uint8* src_y,
   1443                int src_stride_y,
   1444                const uint8* src_uv,
   1445                int src_stride_uv,
   1446                uint8* dst_argb,
   1447                int dst_stride_argb,
   1448                int width,
   1449                int height) {
   1450   return NV12ToARGBMatrix(src_y, src_stride_y, src_uv, src_stride_uv, dst_argb,
   1451                           dst_stride_argb, &kYuvI601Constants, width, height);
   1452 }
   1453 
   1454 // Convert NV21 to ARGB.
   1455 LIBYUV_API
   1456 int NV21ToARGB(const uint8* src_y,
   1457                int src_stride_y,
   1458                const uint8* src_uv,
   1459                int src_stride_uv,
   1460                uint8* dst_argb,
   1461                int dst_stride_argb,
   1462                int width,
   1463                int height) {
   1464   return NV21ToARGBMatrix(src_y, src_stride_y, src_uv, src_stride_uv, dst_argb,
   1465                           dst_stride_argb, &kYuvI601Constants, width, height);
   1466 }
   1467 
   1468 // Convert NV12 to ABGR.
   1469 // To output ABGR instead of ARGB swap the UV and use a mirrored yuv matrix.
   1470 // To swap the UV use NV12 instead of NV21.LIBYUV_API
   1471 LIBYUV_API
   1472 int NV12ToABGR(const uint8* src_y,
   1473                int src_stride_y,
   1474                const uint8* src_uv,
   1475                int src_stride_uv,
   1476                uint8* dst_abgr,
   1477                int dst_stride_abgr,
   1478                int width,
   1479                int height) {
   1480   return NV21ToARGBMatrix(src_y, src_stride_y, src_uv, src_stride_uv, dst_abgr,
   1481                           dst_stride_abgr, &kYvuI601Constants, width, height);
   1482 }
   1483 
   1484 // Convert NV21 to ABGR.
   1485 LIBYUV_API
   1486 int NV21ToABGR(const uint8* src_y,
   1487                int src_stride_y,
   1488                const uint8* src_vu,
   1489                int src_stride_vu,
   1490                uint8* dst_abgr,
   1491                int dst_stride_abgr,
   1492                int width,
   1493                int height) {
   1494   return NV12ToARGBMatrix(src_y, src_stride_y, src_vu, src_stride_vu, dst_abgr,
   1495                           dst_stride_abgr, &kYvuI601Constants, width, height);
   1496 }
   1497 
   1498 // Convert M420 to ARGB.
   1499 LIBYUV_API
   1500 int M420ToARGB(const uint8* src_m420,
   1501                int src_stride_m420,
   1502                uint8* dst_argb,
   1503                int dst_stride_argb,
   1504                int width,
   1505                int height) {
   1506   int y;
   1507   void (*NV12ToARGBRow)(const uint8* y_buf, const uint8* uv_buf, uint8* rgb_buf,
   1508                         const struct YuvConstants* yuvconstants, int width) =
   1509       NV12ToARGBRow_C;
   1510   if (!src_m420 || !dst_argb || width <= 0 || height == 0) {
   1511     return -1;
   1512   }
   1513   // Negative height means invert the image.
   1514   if (height < 0) {
   1515     height = -height;
   1516     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
   1517     dst_stride_argb = -dst_stride_argb;
   1518   }
   1519 #if defined(HAS_NV12TOARGBROW_SSSE3)
   1520   if (TestCpuFlag(kCpuHasSSSE3)) {
   1521     NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
   1522     if (IS_ALIGNED(width, 8)) {
   1523       NV12ToARGBRow = NV12ToARGBRow_SSSE3;
   1524     }
   1525   }
   1526 #endif
   1527 #if defined(HAS_NV12TOARGBROW_AVX2)
   1528   if (TestCpuFlag(kCpuHasAVX2)) {
   1529     NV12ToARGBRow = NV12ToARGBRow_Any_AVX2;
   1530     if (IS_ALIGNED(width, 16)) {
   1531       NV12ToARGBRow = NV12ToARGBRow_AVX2;
   1532     }
   1533   }
   1534 #endif
   1535 #if defined(HAS_NV12TOARGBROW_NEON)
   1536   if (TestCpuFlag(kCpuHasNEON)) {
   1537     NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
   1538     if (IS_ALIGNED(width, 8)) {
   1539       NV12ToARGBRow = NV12ToARGBRow_NEON;
   1540     }
   1541   }
   1542 #endif
   1543 #if defined(HAS_NV12TOARGBROW_DSPR2)
   1544   if (TestCpuFlag(kCpuHasDSPR2)) {
   1545     NV12ToARGBRow = NV12ToARGBRow_Any_DSPR2;
   1546     if (IS_ALIGNED(width, 8)) {
   1547       NV12ToARGBRow = NV12ToARGBRow_DSPR2;
   1548     }
   1549   }
   1550 #endif
   1551 #if defined(HAS_NV12TOARGBROW_MSA)
   1552   if (TestCpuFlag(kCpuHasMSA)) {
   1553     NV12ToARGBRow = NV12ToARGBRow_Any_MSA;
   1554     if (IS_ALIGNED(width, 8)) {
   1555       NV12ToARGBRow = NV12ToARGBRow_MSA;
   1556     }
   1557   }
   1558 #endif
   1559 
   1560   for (y = 0; y < height - 1; y += 2) {
   1561     NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb,
   1562                   &kYuvI601Constants, width);
   1563     NV12ToARGBRow(src_m420 + src_stride_m420, src_m420 + src_stride_m420 * 2,
   1564                   dst_argb + dst_stride_argb, &kYuvI601Constants, width);
   1565     dst_argb += dst_stride_argb * 2;
   1566     src_m420 += src_stride_m420 * 3;
   1567   }
   1568   if (height & 1) {
   1569     NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb,
   1570                   &kYuvI601Constants, width);
   1571   }
   1572   return 0;
   1573 }
   1574 
   1575 // Convert YUY2 to ARGB.
   1576 LIBYUV_API
   1577 int YUY2ToARGB(const uint8* src_yuy2,
   1578                int src_stride_yuy2,
   1579                uint8* dst_argb,
   1580                int dst_stride_argb,
   1581                int width,
   1582                int height) {
   1583   int y;
   1584   void (*YUY2ToARGBRow)(const uint8* src_yuy2, uint8* dst_argb,
   1585                         const struct YuvConstants* yuvconstants, int width) =
   1586       YUY2ToARGBRow_C;
   1587   if (!src_yuy2 || !dst_argb || width <= 0 || height == 0) {
   1588     return -1;
   1589   }
   1590   // Negative height means invert the image.
   1591   if (height < 0) {
   1592     height = -height;
   1593     src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
   1594     src_stride_yuy2 = -src_stride_yuy2;
   1595   }
   1596   // Coalesce rows.
   1597   if (src_stride_yuy2 == width * 2 && dst_stride_argb == width * 4) {
   1598     width *= height;
   1599     height = 1;
   1600     src_stride_yuy2 = dst_stride_argb = 0;
   1601   }
   1602 #if defined(HAS_YUY2TOARGBROW_SSSE3)
   1603   if (TestCpuFlag(kCpuHasSSSE3)) {
   1604     YUY2ToARGBRow = YUY2ToARGBRow_Any_SSSE3;
   1605     if (IS_ALIGNED(width, 16)) {
   1606       YUY2ToARGBRow = YUY2ToARGBRow_SSSE3;
   1607     }
   1608   }
   1609 #endif
   1610 #if defined(HAS_YUY2TOARGBROW_AVX2)
   1611   if (TestCpuFlag(kCpuHasAVX2)) {
   1612     YUY2ToARGBRow = YUY2ToARGBRow_Any_AVX2;
   1613     if (IS_ALIGNED(width, 32)) {
   1614       YUY2ToARGBRow = YUY2ToARGBRow_AVX2;
   1615     }
   1616   }
   1617 #endif
   1618 #if defined(HAS_YUY2TOARGBROW_NEON)
   1619   if (TestCpuFlag(kCpuHasNEON)) {
   1620     YUY2ToARGBRow = YUY2ToARGBRow_Any_NEON;
   1621     if (IS_ALIGNED(width, 8)) {
   1622       YUY2ToARGBRow = YUY2ToARGBRow_NEON;
   1623     }
   1624   }
   1625 #endif
   1626 #if defined(HAS_YUY2TOARGBROW_MSA)
   1627   if (TestCpuFlag(kCpuHasMSA)) {
   1628     YUY2ToARGBRow = YUY2ToARGBRow_Any_MSA;
   1629     if (IS_ALIGNED(width, 8)) {
   1630       YUY2ToARGBRow = YUY2ToARGBRow_MSA;
   1631     }
   1632   }
   1633 #endif
   1634   for (y = 0; y < height; ++y) {
   1635     YUY2ToARGBRow(src_yuy2, dst_argb, &kYuvI601Constants, width);
   1636     src_yuy2 += src_stride_yuy2;
   1637     dst_argb += dst_stride_argb;
   1638   }
   1639   return 0;
   1640 }
   1641 
   1642 // Convert UYVY to ARGB.
   1643 LIBYUV_API
   1644 int UYVYToARGB(const uint8* src_uyvy,
   1645                int src_stride_uyvy,
   1646                uint8* dst_argb,
   1647                int dst_stride_argb,
   1648                int width,
   1649                int height) {
   1650   int y;
   1651   void (*UYVYToARGBRow)(const uint8* src_uyvy, uint8* dst_argb,
   1652                         const struct YuvConstants* yuvconstants, int width) =
   1653       UYVYToARGBRow_C;
   1654   if (!src_uyvy || !dst_argb || width <= 0 || height == 0) {
   1655     return -1;
   1656   }
   1657   // Negative height means invert the image.
   1658   if (height < 0) {
   1659     height = -height;
   1660     src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
   1661     src_stride_uyvy = -src_stride_uyvy;
   1662   }
   1663   // Coalesce rows.
   1664   if (src_stride_uyvy == width * 2 && dst_stride_argb == width * 4) {
   1665     width *= height;
   1666     height = 1;
   1667     src_stride_uyvy = dst_stride_argb = 0;
   1668   }
   1669 #if defined(HAS_UYVYTOARGBROW_SSSE3)
   1670   if (TestCpuFlag(kCpuHasSSSE3)) {
   1671     UYVYToARGBRow = UYVYToARGBRow_Any_SSSE3;
   1672     if (IS_ALIGNED(width, 16)) {
   1673       UYVYToARGBRow = UYVYToARGBRow_SSSE3;
   1674     }
   1675   }
   1676 #endif
   1677 #if defined(HAS_UYVYTOARGBROW_AVX2)
   1678   if (TestCpuFlag(kCpuHasAVX2)) {
   1679     UYVYToARGBRow = UYVYToARGBRow_Any_AVX2;
   1680     if (IS_ALIGNED(width, 32)) {
   1681       UYVYToARGBRow = UYVYToARGBRow_AVX2;
   1682     }
   1683   }
   1684 #endif
   1685 #if defined(HAS_UYVYTOARGBROW_NEON)
   1686   if (TestCpuFlag(kCpuHasNEON)) {
   1687     UYVYToARGBRow = UYVYToARGBRow_Any_NEON;
   1688     if (IS_ALIGNED(width, 8)) {
   1689       UYVYToARGBRow = UYVYToARGBRow_NEON;
   1690     }
   1691   }
   1692 #endif
   1693 #if defined(HAS_UYVYTOARGBROW_MSA)
   1694   if (TestCpuFlag(kCpuHasMSA)) {
   1695     UYVYToARGBRow = UYVYToARGBRow_Any_MSA;
   1696     if (IS_ALIGNED(width, 8)) {
   1697       UYVYToARGBRow = UYVYToARGBRow_MSA;
   1698     }
   1699   }
   1700 #endif
   1701   for (y = 0; y < height; ++y) {
   1702     UYVYToARGBRow(src_uyvy, dst_argb, &kYuvI601Constants, width);
   1703     src_uyvy += src_stride_uyvy;
   1704     dst_argb += dst_stride_argb;
   1705   }
   1706   return 0;
   1707 }
   1708 static void WeavePixels(const uint8* src_u,
   1709                         const uint8* src_v,
   1710                         int src_pixel_stride_uv,
   1711                         uint8* dst_uv,
   1712                         int width) {
   1713   int i;
   1714   for (i = 0; i < width; ++i) {
   1715     dst_uv[0] = *src_u;
   1716     dst_uv[1] = *src_v;
   1717     dst_uv += 2;
   1718     src_u += src_pixel_stride_uv;
   1719     src_v += src_pixel_stride_uv;
   1720   }
   1721 }
   1722 
   1723 // Convert Android420 to ARGB.
   1724 LIBYUV_API
   1725 int Android420ToARGBMatrix(const uint8* src_y,
   1726                            int src_stride_y,
   1727                            const uint8* src_u,
   1728                            int src_stride_u,
   1729                            const uint8* src_v,
   1730                            int src_stride_v,
   1731                            int src_pixel_stride_uv,
   1732                            uint8* dst_argb,
   1733                            int dst_stride_argb,
   1734                            const struct YuvConstants* yuvconstants,
   1735                            int width,
   1736                            int height) {
   1737   int y;
   1738   uint8* dst_uv;
   1739   const ptrdiff_t vu_off = src_v - src_u;
   1740   int halfwidth = (width + 1) >> 1;
   1741   int halfheight = (height + 1) >> 1;
   1742   if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
   1743     return -1;
   1744   }
   1745   // Negative height means invert the image.
   1746   if (height < 0) {
   1747     height = -height;
   1748     halfheight = (height + 1) >> 1;
   1749     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
   1750     dst_stride_argb = -dst_stride_argb;
   1751   }
   1752 
   1753   // I420
   1754   if (src_pixel_stride_uv == 1) {
   1755     return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
   1756                             src_stride_v, dst_argb, dst_stride_argb,
   1757                             yuvconstants, width, height);
   1758     // NV21
   1759   } else if (src_pixel_stride_uv == 2 && vu_off == -1 &&
   1760              src_stride_u == src_stride_v) {
   1761     return NV21ToARGBMatrix(src_y, src_stride_y, src_v, src_stride_v, dst_argb,
   1762                             dst_stride_argb, yuvconstants, width, height);
   1763     // NV12
   1764   } else if (src_pixel_stride_uv == 2 && vu_off == 1 &&
   1765              src_stride_u == src_stride_v) {
   1766     return NV12ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, dst_argb,
   1767                             dst_stride_argb, yuvconstants, width, height);
   1768   }
   1769 
   1770   // General case fallback creates NV12
   1771   align_buffer_64(plane_uv, halfwidth * 2 * halfheight);
   1772   dst_uv = plane_uv;
   1773   for (y = 0; y < halfheight; ++y) {
   1774     WeavePixels(src_u, src_v, src_pixel_stride_uv, dst_uv, halfwidth);
   1775     src_u += src_stride_u;
   1776     src_v += src_stride_v;
   1777     dst_uv += halfwidth * 2;
   1778   }
   1779   NV12ToARGBMatrix(src_y, src_stride_y, plane_uv, halfwidth * 2, dst_argb,
   1780                    dst_stride_argb, yuvconstants, width, height);
   1781   free_aligned_buffer_64(plane_uv);
   1782   return 0;
   1783 }
   1784 
   1785 // Convert Android420 to ARGB.
   1786 LIBYUV_API
   1787 int Android420ToARGB(const uint8* src_y,
   1788                      int src_stride_y,
   1789                      const uint8* src_u,
   1790                      int src_stride_u,
   1791                      const uint8* src_v,
   1792                      int src_stride_v,
   1793                      int src_pixel_stride_uv,
   1794                      uint8* dst_argb,
   1795                      int dst_stride_argb,
   1796                      int width,
   1797                      int height) {
   1798   return Android420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
   1799                                 src_stride_v, src_pixel_stride_uv, dst_argb,
   1800                                 dst_stride_argb, &kYuvI601Constants, width,
   1801                                 height);
   1802 }
   1803 
   1804 // Convert Android420 to ABGR.
   1805 LIBYUV_API
   1806 int Android420ToABGR(const uint8* src_y,
   1807                      int src_stride_y,
   1808                      const uint8* src_u,
   1809                      int src_stride_u,
   1810                      const uint8* src_v,
   1811                      int src_stride_v,
   1812                      int src_pixel_stride_uv,
   1813                      uint8* dst_abgr,
   1814                      int dst_stride_abgr,
   1815                      int width,
   1816                      int height) {
   1817   return Android420ToARGBMatrix(src_y, src_stride_y, src_v, src_stride_v, src_u,
   1818                                 src_stride_u, src_pixel_stride_uv, dst_abgr,
   1819                                 dst_stride_abgr, &kYvuI601Constants, width,
   1820                                 height);
   1821 }
   1822 
   1823 #ifdef __cplusplus
   1824 }  // extern "C"
   1825 }  // namespace libyuv
   1826 #endif
   1827