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 #include "libyuv/format_conversion.h"
     15 #ifdef HAVE_JPEG
     16 #include "libyuv/mjpeg_decoder.h"
     17 #endif
     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, int src_stride_argb,
     30              uint8* dst_argb, int dst_stride_argb,
     31              int width, int height) {
     32   if (!src_argb || !dst_argb ||
     33       width <= 0 || height == 0) {
     34     return -1;
     35   }
     36   // Negative height means invert the image.
     37   if (height < 0) {
     38     height = -height;
     39     src_argb = src_argb + (height - 1) * src_stride_argb;
     40     src_stride_argb = -src_stride_argb;
     41   }
     42 
     43   CopyPlane(src_argb, src_stride_argb, dst_argb, dst_stride_argb,
     44             width * 4, height);
     45   return 0;
     46 }
     47 
     48 // Convert I444 to ARGB.
     49 LIBYUV_API
     50 int I444ToARGB(const uint8* src_y, int src_stride_y,
     51                const uint8* src_u, int src_stride_u,
     52                const uint8* src_v, int src_stride_v,
     53                uint8* dst_argb, int dst_stride_argb,
     54                int width, int height) {
     55   int y;
     56   void (*I444ToARGBRow)(const uint8* y_buf,
     57                         const uint8* u_buf,
     58                         const uint8* v_buf,
     59                         uint8* rgb_buf,
     60                         int width) = I444ToARGBRow_C;
     61   if (!src_y || !src_u || !src_v ||
     62       !dst_argb ||
     63       width <= 0 || height == 0) {
     64     return -1;
     65   }
     66   // Negative height means invert the image.
     67   if (height < 0) {
     68     height = -height;
     69     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
     70     dst_stride_argb = -dst_stride_argb;
     71   }
     72   // Coalesce rows.
     73   if (src_stride_y == width &&
     74       src_stride_u == width &&
     75       src_stride_v == width &&
     76       dst_stride_argb == width * 4) {
     77     width *= height;
     78     height = 1;
     79     src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
     80   }
     81 #if defined(HAS_I444TOARGBROW_SSSE3)
     82   if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
     83     I444ToARGBRow = I444ToARGBRow_Any_SSSE3;
     84     if (IS_ALIGNED(width, 8)) {
     85       I444ToARGBRow = I444ToARGBRow_Unaligned_SSSE3;
     86       if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
     87         I444ToARGBRow = I444ToARGBRow_SSSE3;
     88       }
     89     }
     90   }
     91 #elif defined(HAS_I444TOARGBROW_NEON)
     92   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
     93     I444ToARGBRow = I444ToARGBRow_Any_NEON;
     94     if (IS_ALIGNED(width, 8)) {
     95       I444ToARGBRow = I444ToARGBRow_NEON;
     96     }
     97   }
     98 #endif
     99 
    100   for (y = 0; y < height; ++y) {
    101     I444ToARGBRow(src_y, src_u, src_v, dst_argb, width);
    102     dst_argb += dst_stride_argb;
    103     src_y += src_stride_y;
    104     src_u += src_stride_u;
    105     src_v += src_stride_v;
    106   }
    107   return 0;
    108 }
    109 
    110 // Convert I422 to ARGB.
    111 LIBYUV_API
    112 int I422ToARGB(const uint8* src_y, int src_stride_y,
    113                const uint8* src_u, int src_stride_u,
    114                const uint8* src_v, int src_stride_v,
    115                uint8* dst_argb, int dst_stride_argb,
    116                int width, int height) {
    117   int y;
    118   void (*I422ToARGBRow)(const uint8* y_buf,
    119                         const uint8* u_buf,
    120                         const uint8* v_buf,
    121                         uint8* rgb_buf,
    122                         int width) = I422ToARGBRow_C;
    123   if (!src_y || !src_u || !src_v ||
    124       !dst_argb ||
    125       width <= 0 || height == 0) {
    126     return -1;
    127   }
    128   // Negative height means invert the image.
    129   if (height < 0) {
    130     height = -height;
    131     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
    132     dst_stride_argb = -dst_stride_argb;
    133   }
    134   // Coalesce rows.
    135   if (src_stride_y == width &&
    136       src_stride_u * 2 == width &&
    137       src_stride_v * 2 == width &&
    138       dst_stride_argb == width * 4) {
    139     width *= height;
    140     height = 1;
    141     src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
    142   }
    143 #if defined(HAS_I422TOARGBROW_SSSE3)
    144   if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
    145     I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
    146     if (IS_ALIGNED(width, 8)) {
    147       I422ToARGBRow = I422ToARGBRow_Unaligned_SSSE3;
    148       if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
    149         I422ToARGBRow = I422ToARGBRow_SSSE3;
    150       }
    151     }
    152   }
    153 #endif
    154 #if defined(HAS_I422TOARGBROW_AVX2)
    155   if (TestCpuFlag(kCpuHasAVX2) && width >= 16) {
    156     I422ToARGBRow = I422ToARGBRow_Any_AVX2;
    157     if (IS_ALIGNED(width, 16)) {
    158       I422ToARGBRow = I422ToARGBRow_AVX2;
    159     }
    160   }
    161 #endif
    162 #if defined(HAS_I422TOARGBROW_NEON)
    163   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
    164     I422ToARGBRow = I422ToARGBRow_Any_NEON;
    165     if (IS_ALIGNED(width, 8)) {
    166       I422ToARGBRow = I422ToARGBRow_NEON;
    167     }
    168   }
    169 #endif
    170 #if defined(HAS_I422TOARGBROW_MIPS_DSPR2)
    171   if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) &&
    172       IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
    173       IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
    174       IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
    175       IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) {
    176     I422ToARGBRow = I422ToARGBRow_MIPS_DSPR2;
    177   }
    178 #endif
    179 
    180   for (y = 0; y < height; ++y) {
    181     I422ToARGBRow(src_y, src_u, src_v, dst_argb, width);
    182     dst_argb += dst_stride_argb;
    183     src_y += src_stride_y;
    184     src_u += src_stride_u;
    185     src_v += src_stride_v;
    186   }
    187   return 0;
    188 }
    189 
    190 // Convert I411 to ARGB.
    191 LIBYUV_API
    192 int I411ToARGB(const uint8* src_y, int src_stride_y,
    193                const uint8* src_u, int src_stride_u,
    194                const uint8* src_v, int src_stride_v,
    195                uint8* dst_argb, int dst_stride_argb,
    196                int width, int height) {
    197   int y;
    198   void (*I411ToARGBRow)(const uint8* y_buf,
    199                         const uint8* u_buf,
    200                         const uint8* v_buf,
    201                         uint8* rgb_buf,
    202                         int width) = I411ToARGBRow_C;
    203   if (!src_y || !src_u || !src_v ||
    204       !dst_argb ||
    205       width <= 0 || height == 0) {
    206     return -1;
    207   }
    208   // Negative height means invert the image.
    209   if (height < 0) {
    210     height = -height;
    211     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
    212     dst_stride_argb = -dst_stride_argb;
    213   }
    214   // Coalesce rows.
    215   if (src_stride_y == width &&
    216       src_stride_u * 4 == width &&
    217       src_stride_v * 4 == width &&
    218       dst_stride_argb == width * 4) {
    219     width *= height;
    220     height = 1;
    221     src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
    222   }
    223 #if defined(HAS_I411TOARGBROW_SSSE3)
    224   if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
    225     I411ToARGBRow = I411ToARGBRow_Any_SSSE3;
    226     if (IS_ALIGNED(width, 8)) {
    227       I411ToARGBRow = I411ToARGBRow_Unaligned_SSSE3;
    228       if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
    229         I411ToARGBRow = I411ToARGBRow_SSSE3;
    230       }
    231     }
    232   }
    233 #elif defined(HAS_I411TOARGBROW_NEON)
    234   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
    235     I411ToARGBRow = I411ToARGBRow_Any_NEON;
    236     if (IS_ALIGNED(width, 8)) {
    237       I411ToARGBRow = I411ToARGBRow_NEON;
    238     }
    239   }
    240 #endif
    241 
    242   for (y = 0; y < height; ++y) {
    243     I411ToARGBRow(src_y, src_u, src_v, dst_argb, width);
    244     dst_argb += dst_stride_argb;
    245     src_y += src_stride_y;
    246     src_u += src_stride_u;
    247     src_v += src_stride_v;
    248   }
    249   return 0;
    250 }
    251 
    252 // Convert I400 to ARGB.
    253 LIBYUV_API
    254 int I400ToARGB_Reference(const uint8* src_y, int src_stride_y,
    255                          uint8* dst_argb, int dst_stride_argb,
    256                          int width, int height) {
    257   int y;
    258   void (*YToARGBRow)(const uint8* y_buf,
    259                      uint8* rgb_buf,
    260                      int width) = YToARGBRow_C;
    261   if (!src_y || !dst_argb ||
    262       width <= 0 || height == 0) {
    263     return -1;
    264   }
    265   // Negative height means invert the image.
    266   if (height < 0) {
    267     height = -height;
    268     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
    269     dst_stride_argb = -dst_stride_argb;
    270   }
    271   // Coalesce rows.
    272   if (src_stride_y == width &&
    273       dst_stride_argb == width * 4) {
    274     width *= height;
    275     height = 1;
    276     src_stride_y = dst_stride_argb = 0;
    277   }
    278 #if defined(HAS_YTOARGBROW_SSE2)
    279   if (TestCpuFlag(kCpuHasSSE2) && width >= 8 &&
    280       IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
    281     YToARGBRow = YToARGBRow_Any_SSE2;
    282     if (IS_ALIGNED(width, 8)) {
    283       YToARGBRow = YToARGBRow_SSE2;
    284     }
    285   }
    286 #elif defined(HAS_YTOARGBROW_NEON)
    287   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
    288     YToARGBRow = YToARGBRow_Any_NEON;
    289     if (IS_ALIGNED(width, 8)) {
    290       YToARGBRow = YToARGBRow_NEON;
    291     }
    292   }
    293 #endif
    294 
    295   for (y = 0; y < height; ++y) {
    296     YToARGBRow(src_y, dst_argb, width);
    297     dst_argb += dst_stride_argb;
    298     src_y += src_stride_y;
    299   }
    300   return 0;
    301 }
    302 
    303 // Convert I400 to ARGB.
    304 LIBYUV_API
    305 int I400ToARGB(const uint8* src_y, int src_stride_y,
    306                uint8* dst_argb, int dst_stride_argb,
    307                int width, int height) {
    308   int y;
    309   void (*I400ToARGBRow)(const uint8* src_y, uint8* dst_argb, int pix) =
    310       I400ToARGBRow_C;
    311   if (!src_y || !dst_argb ||
    312       width <= 0 || height == 0) {
    313     return -1;
    314   }
    315   // Negative height means invert the image.
    316   if (height < 0) {
    317     height = -height;
    318     src_y = src_y + (height - 1) * src_stride_y;
    319     src_stride_y = -src_stride_y;
    320   }
    321   // Coalesce rows.
    322   if (src_stride_y == width &&
    323       dst_stride_argb == width * 4) {
    324     width *= height;
    325     height = 1;
    326     src_stride_y = dst_stride_argb = 0;
    327   }
    328 #if defined(HAS_I400TOARGBROW_SSE2)
    329   if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
    330     I400ToARGBRow = I400ToARGBRow_Any_SSE2;
    331     if (IS_ALIGNED(width, 8)) {
    332       I400ToARGBRow = I400ToARGBRow_Unaligned_SSE2;
    333       if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
    334         I400ToARGBRow = I400ToARGBRow_SSE2;
    335       }
    336     }
    337   }
    338 #elif defined(HAS_I400TOARGBROW_NEON)
    339   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
    340     I400ToARGBRow = I400ToARGBRow_Any_NEON;
    341     if (IS_ALIGNED(width, 8)) {
    342       I400ToARGBRow = I400ToARGBRow_NEON;
    343     }
    344   }
    345 #endif
    346   for (y = 0; y < height; ++y) {
    347     I400ToARGBRow(src_y, dst_argb, width);
    348     src_y += src_stride_y;
    349     dst_argb += dst_stride_argb;
    350   }
    351   return 0;
    352 }
    353 
    354 // Shuffle table for converting BGRA to ARGB.
    355 static uvec8 kShuffleMaskBGRAToARGB = {
    356   3u, 2u, 1u, 0u, 7u, 6u, 5u, 4u, 11u, 10u, 9u, 8u, 15u, 14u, 13u, 12u
    357 };
    358 
    359 // Shuffle table for converting ABGR to ARGB.
    360 static uvec8 kShuffleMaskABGRToARGB = {
    361   2u, 1u, 0u, 3u, 6u, 5u, 4u, 7u, 10u, 9u, 8u, 11u, 14u, 13u, 12u, 15u
    362 };
    363 
    364 // Shuffle table for converting RGBA to ARGB.
    365 static uvec8 kShuffleMaskRGBAToARGB = {
    366   1u, 2u, 3u, 0u, 5u, 6u, 7u, 4u, 9u, 10u, 11u, 8u, 13u, 14u, 15u, 12u
    367 };
    368 
    369 // Convert BGRA to ARGB.
    370 LIBYUV_API
    371 int BGRAToARGB(const uint8* src_bgra, int src_stride_bgra,
    372                uint8* dst_argb, int dst_stride_argb,
    373                int width, int height) {
    374   return ARGBShuffle(src_bgra, src_stride_bgra,
    375                      dst_argb, dst_stride_argb,
    376                      (const uint8*)(&kShuffleMaskBGRAToARGB),
    377                      width, height);
    378 }
    379 
    380 // Convert ARGB to BGRA (same as BGRAToARGB).
    381 LIBYUV_API
    382 int ARGBToBGRA(const uint8* src_bgra, int src_stride_bgra,
    383                uint8* dst_argb, int dst_stride_argb,
    384                int width, int height) {
    385   return ARGBShuffle(src_bgra, src_stride_bgra,
    386                      dst_argb, dst_stride_argb,
    387                      (const uint8*)(&kShuffleMaskBGRAToARGB),
    388                      width, height);
    389 }
    390 
    391 // Convert ABGR to ARGB.
    392 LIBYUV_API
    393 int ABGRToARGB(const uint8* src_abgr, int src_stride_abgr,
    394                uint8* dst_argb, int dst_stride_argb,
    395                int width, int height) {
    396   return ARGBShuffle(src_abgr, src_stride_abgr,
    397                      dst_argb, dst_stride_argb,
    398                      (const uint8*)(&kShuffleMaskABGRToARGB),
    399                      width, height);
    400 }
    401 
    402 // Convert ARGB to ABGR to (same as ABGRToARGB).
    403 LIBYUV_API
    404 int ARGBToABGR(const uint8* src_abgr, int src_stride_abgr,
    405                uint8* dst_argb, int dst_stride_argb,
    406                int width, int height) {
    407   return ARGBShuffle(src_abgr, src_stride_abgr,
    408                      dst_argb, dst_stride_argb,
    409                      (const uint8*)(&kShuffleMaskABGRToARGB),
    410                      width, height);
    411 }
    412 
    413 // Convert RGBA to ARGB.
    414 LIBYUV_API
    415 int RGBAToARGB(const uint8* src_rgba, int src_stride_rgba,
    416                uint8* dst_argb, int dst_stride_argb,
    417                int width, int height) {
    418   return ARGBShuffle(src_rgba, src_stride_rgba,
    419                      dst_argb, dst_stride_argb,
    420                      (const uint8*)(&kShuffleMaskRGBAToARGB),
    421                      width, height);
    422 }
    423 
    424 // Convert RGB24 to ARGB.
    425 LIBYUV_API
    426 int RGB24ToARGB(const uint8* src_rgb24, int src_stride_rgb24,
    427                 uint8* dst_argb, int dst_stride_argb,
    428                 int width, int height) {
    429   int y;
    430   void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
    431       RGB24ToARGBRow_C;
    432   if (!src_rgb24 || !dst_argb ||
    433       width <= 0 || height == 0) {
    434     return -1;
    435   }
    436   // Negative height means invert the image.
    437   if (height < 0) {
    438     height = -height;
    439     src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
    440     src_stride_rgb24 = -src_stride_rgb24;
    441   }
    442   // Coalesce rows.
    443   if (src_stride_rgb24 == width * 3 &&
    444       dst_stride_argb == width * 4) {
    445     width *= height;
    446     height = 1;
    447     src_stride_rgb24 = dst_stride_argb = 0;
    448   }
    449 #if defined(HAS_RGB24TOARGBROW_SSSE3)
    450   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16 &&
    451       IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
    452     RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
    453     if (IS_ALIGNED(width, 16)) {
    454       RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
    455     }
    456   }
    457 #elif defined(HAS_RGB24TOARGBROW_NEON)
    458   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
    459     RGB24ToARGBRow = RGB24ToARGBRow_Any_NEON;
    460     if (IS_ALIGNED(width, 8)) {
    461       RGB24ToARGBRow = RGB24ToARGBRow_NEON;
    462     }
    463   }
    464 #endif
    465 
    466   for (y = 0; y < height; ++y) {
    467     RGB24ToARGBRow(src_rgb24, dst_argb, width);
    468     src_rgb24 += src_stride_rgb24;
    469     dst_argb += dst_stride_argb;
    470   }
    471   return 0;
    472 }
    473 
    474 // Convert RAW to ARGB.
    475 LIBYUV_API
    476 int RAWToARGB(const uint8* src_raw, int src_stride_raw,
    477               uint8* dst_argb, int dst_stride_argb,
    478               int width, int height) {
    479   int y;
    480   void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
    481       RAWToARGBRow_C;
    482   if (!src_raw || !dst_argb ||
    483       width <= 0 || height == 0) {
    484     return -1;
    485   }
    486   // Negative height means invert the image.
    487   if (height < 0) {
    488     height = -height;
    489     src_raw = src_raw + (height - 1) * src_stride_raw;
    490     src_stride_raw = -src_stride_raw;
    491   }
    492   // Coalesce rows.
    493   if (src_stride_raw == width * 3 &&
    494       dst_stride_argb == width * 4) {
    495     width *= height;
    496     height = 1;
    497     src_stride_raw = dst_stride_argb = 0;
    498   }
    499 #if defined(HAS_RAWTOARGBROW_SSSE3)
    500   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16 &&
    501       IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
    502     RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
    503     if (IS_ALIGNED(width, 16)) {
    504       RAWToARGBRow = RAWToARGBRow_SSSE3;
    505     }
    506   }
    507 #elif defined(HAS_RAWTOARGBROW_NEON)
    508   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
    509     RAWToARGBRow = RAWToARGBRow_Any_NEON;
    510     if (IS_ALIGNED(width, 8)) {
    511       RAWToARGBRow = RAWToARGBRow_NEON;
    512     }
    513   }
    514 #endif
    515 
    516   for (y = 0; y < height; ++y) {
    517     RAWToARGBRow(src_raw, dst_argb, width);
    518     src_raw += src_stride_raw;
    519     dst_argb += dst_stride_argb;
    520   }
    521   return 0;
    522 }
    523 
    524 // Convert RGB565 to ARGB.
    525 LIBYUV_API
    526 int RGB565ToARGB(const uint8* src_rgb565, int src_stride_rgb565,
    527                  uint8* dst_argb, int dst_stride_argb,
    528                  int width, int height) {
    529   int y;
    530   void (*RGB565ToARGBRow)(const uint8* src_rgb565, uint8* dst_argb, int pix) =
    531       RGB565ToARGBRow_C;
    532   if (!src_rgb565 || !dst_argb ||
    533       width <= 0 || height == 0) {
    534     return -1;
    535   }
    536   // Negative height means invert the image.
    537   if (height < 0) {
    538     height = -height;
    539     src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
    540     src_stride_rgb565 = -src_stride_rgb565;
    541   }
    542   // Coalesce rows.
    543   if (src_stride_rgb565 == width * 2 &&
    544       dst_stride_argb == width * 4) {
    545     width *= height;
    546     height = 1;
    547     src_stride_rgb565 = dst_stride_argb = 0;
    548   }
    549 #if defined(HAS_RGB565TOARGBROW_SSE2)
    550   if (TestCpuFlag(kCpuHasSSE2) && width >= 8 &&
    551       IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
    552     RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
    553     if (IS_ALIGNED(width, 8)) {
    554       RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
    555     }
    556   }
    557 #elif defined(HAS_RGB565TOARGBROW_NEON)
    558   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
    559     RGB565ToARGBRow = RGB565ToARGBRow_Any_NEON;
    560     if (IS_ALIGNED(width, 8)) {
    561       RGB565ToARGBRow = RGB565ToARGBRow_NEON;
    562     }
    563   }
    564 #endif
    565 
    566   for (y = 0; y < height; ++y) {
    567     RGB565ToARGBRow(src_rgb565, dst_argb, width);
    568     src_rgb565 += src_stride_rgb565;
    569     dst_argb += dst_stride_argb;
    570   }
    571   return 0;
    572 }
    573 
    574 // Convert ARGB1555 to ARGB.
    575 LIBYUV_API
    576 int ARGB1555ToARGB(const uint8* src_argb1555, int src_stride_argb1555,
    577                    uint8* dst_argb, int dst_stride_argb,
    578                    int width, int height) {
    579   int y;
    580   void (*ARGB1555ToARGBRow)(const uint8* src_argb1555, uint8* dst_argb,
    581       int pix) = ARGB1555ToARGBRow_C;
    582   if (!src_argb1555 || !dst_argb ||
    583       width <= 0 || height == 0) {
    584     return -1;
    585   }
    586   // Negative height means invert the image.
    587   if (height < 0) {
    588     height = -height;
    589     src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
    590     src_stride_argb1555 = -src_stride_argb1555;
    591   }
    592   // Coalesce rows.
    593   if (src_stride_argb1555 == width * 2 &&
    594       dst_stride_argb == width * 4) {
    595     width *= height;
    596     height = 1;
    597     src_stride_argb1555 = dst_stride_argb = 0;
    598   }
    599 #if defined(HAS_ARGB1555TOARGBROW_SSE2)
    600   if (TestCpuFlag(kCpuHasSSE2) && width >= 8 &&
    601       IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
    602     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
    603     if (IS_ALIGNED(width, 8)) {
    604       ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
    605     }
    606   }
    607 #elif defined(HAS_ARGB1555TOARGBROW_NEON)
    608   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
    609     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_NEON;
    610     if (IS_ALIGNED(width, 8)) {
    611       ARGB1555ToARGBRow = ARGB1555ToARGBRow_NEON;
    612     }
    613   }
    614 #endif
    615 
    616   for (y = 0; y < height; ++y) {
    617     ARGB1555ToARGBRow(src_argb1555, dst_argb, width);
    618     src_argb1555 += src_stride_argb1555;
    619     dst_argb += dst_stride_argb;
    620   }
    621   return 0;
    622 }
    623 
    624 // Convert ARGB4444 to ARGB.
    625 LIBYUV_API
    626 int ARGB4444ToARGB(const uint8* src_argb4444, int src_stride_argb4444,
    627                    uint8* dst_argb, int dst_stride_argb,
    628                    int width, int height) {
    629   int y;
    630   void (*ARGB4444ToARGBRow)(const uint8* src_argb4444, uint8* dst_argb,
    631       int pix) = ARGB4444ToARGBRow_C;
    632   if (!src_argb4444 || !dst_argb ||
    633       width <= 0 || height == 0) {
    634     return -1;
    635   }
    636   // Negative height means invert the image.
    637   if (height < 0) {
    638     height = -height;
    639     src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
    640     src_stride_argb4444 = -src_stride_argb4444;
    641   }
    642   // Coalesce rows.
    643   if (src_stride_argb4444 == width * 2 &&
    644       dst_stride_argb == width * 4) {
    645     width *= height;
    646     height = 1;
    647     src_stride_argb4444 = dst_stride_argb = 0;
    648   }
    649 #if defined(HAS_ARGB4444TOARGBROW_SSE2)
    650   if (TestCpuFlag(kCpuHasSSE2) && width >= 8 &&
    651       IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
    652     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
    653     if (IS_ALIGNED(width, 8)) {
    654       ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
    655     }
    656   }
    657 #elif defined(HAS_ARGB4444TOARGBROW_NEON)
    658   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
    659     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_NEON;
    660     if (IS_ALIGNED(width, 8)) {
    661       ARGB4444ToARGBRow = ARGB4444ToARGBRow_NEON;
    662     }
    663   }
    664 #endif
    665 
    666   for (y = 0; y < height; ++y) {
    667     ARGB4444ToARGBRow(src_argb4444, dst_argb, width);
    668     src_argb4444 += src_stride_argb4444;
    669     dst_argb += dst_stride_argb;
    670   }
    671   return 0;
    672 }
    673 
    674 // Convert NV12 to ARGB.
    675 LIBYUV_API
    676 int NV12ToARGB(const uint8* src_y, int src_stride_y,
    677                const uint8* src_uv, int src_stride_uv,
    678                uint8* dst_argb, int dst_stride_argb,
    679                int width, int height) {
    680   int y;
    681   void (*NV12ToARGBRow)(const uint8* y_buf,
    682                         const uint8* uv_buf,
    683                         uint8* rgb_buf,
    684                         int width) = NV12ToARGBRow_C;
    685   if (!src_y || !src_uv || !dst_argb ||
    686       width <= 0 || height == 0) {
    687     return -1;
    688   }
    689   // Negative height means invert the image.
    690   if (height < 0) {
    691     height = -height;
    692     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
    693     dst_stride_argb = -dst_stride_argb;
    694   }
    695 #if defined(HAS_NV12TOARGBROW_SSSE3)
    696   if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
    697     NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
    698     if (IS_ALIGNED(width, 8)) {
    699       NV12ToARGBRow = NV12ToARGBRow_Unaligned_SSSE3;
    700       if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
    701         NV12ToARGBRow = NV12ToARGBRow_SSSE3;
    702       }
    703     }
    704   }
    705 #elif defined(HAS_NV12TOARGBROW_NEON)
    706   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
    707     NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
    708     if (IS_ALIGNED(width, 8)) {
    709       NV12ToARGBRow = NV12ToARGBRow_NEON;
    710     }
    711   }
    712 #endif
    713 
    714   for (y = 0; y < height; ++y) {
    715     NV12ToARGBRow(src_y, src_uv, dst_argb, width);
    716     dst_argb += dst_stride_argb;
    717     src_y += src_stride_y;
    718     if (y & 1) {
    719       src_uv += src_stride_uv;
    720     }
    721   }
    722   return 0;
    723 }
    724 
    725 // Convert NV21 to ARGB.
    726 LIBYUV_API
    727 int NV21ToARGB(const uint8* src_y, int src_stride_y,
    728                const uint8* src_uv, int src_stride_uv,
    729                uint8* dst_argb, int dst_stride_argb,
    730                int width, int height) {
    731   int y;
    732   void (*NV21ToARGBRow)(const uint8* y_buf,
    733                         const uint8* uv_buf,
    734                         uint8* rgb_buf,
    735                         int width) = NV21ToARGBRow_C;
    736   if (!src_y || !src_uv || !dst_argb ||
    737       width <= 0 || height == 0) {
    738     return -1;
    739   }
    740   // Negative height means invert the image.
    741   if (height < 0) {
    742     height = -height;
    743     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
    744     dst_stride_argb = -dst_stride_argb;
    745   }
    746 #if defined(HAS_NV21TOARGBROW_SSSE3)
    747   if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
    748     NV21ToARGBRow = NV21ToARGBRow_Any_SSSE3;
    749     if (IS_ALIGNED(width, 8)) {
    750       NV21ToARGBRow = NV21ToARGBRow_Unaligned_SSSE3;
    751       if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
    752         NV21ToARGBRow = NV21ToARGBRow_SSSE3;
    753       }
    754     }
    755   }
    756 #endif
    757 #if defined(HAS_NV21TOARGBROW_NEON)
    758   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
    759     NV21ToARGBRow = NV21ToARGBRow_Any_NEON;
    760     if (IS_ALIGNED(width, 8)) {
    761       NV21ToARGBRow = NV21ToARGBRow_NEON;
    762     }
    763   }
    764 #endif
    765 
    766   for (y = 0; y < height; ++y) {
    767     NV21ToARGBRow(src_y, src_uv, dst_argb, width);
    768     dst_argb += dst_stride_argb;
    769     src_y += src_stride_y;
    770     if (y & 1) {
    771       src_uv += src_stride_uv;
    772     }
    773   }
    774   return 0;
    775 }
    776 
    777 // Convert M420 to ARGB.
    778 LIBYUV_API
    779 int M420ToARGB(const uint8* src_m420, int src_stride_m420,
    780                uint8* dst_argb, int dst_stride_argb,
    781                int width, int height) {
    782   int y;
    783   void (*NV12ToARGBRow)(const uint8* y_buf,
    784                         const uint8* uv_buf,
    785                         uint8* rgb_buf,
    786                         int width) = NV12ToARGBRow_C;
    787   if (!src_m420 || !dst_argb ||
    788       width <= 0 || height == 0) {
    789     return -1;
    790   }
    791   // Negative height means invert the image.
    792   if (height < 0) {
    793     height = -height;
    794     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
    795     dst_stride_argb = -dst_stride_argb;
    796   }
    797 #if defined(HAS_NV12TOARGBROW_SSSE3)
    798   if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
    799     NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
    800     if (IS_ALIGNED(width, 8)) {
    801       NV12ToARGBRow = NV12ToARGBRow_Unaligned_SSSE3;
    802       if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
    803         NV12ToARGBRow = NV12ToARGBRow_SSSE3;
    804       }
    805     }
    806   }
    807 #elif defined(HAS_NV12TOARGBROW_NEON)
    808   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
    809     NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
    810     if (IS_ALIGNED(width, 8)) {
    811       NV12ToARGBRow = NV12ToARGBRow_NEON;
    812     }
    813   }
    814 #endif
    815 
    816   for (y = 0; y < height - 1; y += 2) {
    817     NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb, width);
    818     NV12ToARGBRow(src_m420 + src_stride_m420, src_m420 + src_stride_m420 * 2,
    819                   dst_argb + dst_stride_argb, width);
    820     dst_argb += dst_stride_argb * 2;
    821     src_m420 += src_stride_m420 * 3;
    822   }
    823   if (height & 1) {
    824     NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb, width);
    825   }
    826   return 0;
    827 }
    828 
    829 // Convert YUY2 to ARGB.
    830 LIBYUV_API
    831 int YUY2ToARGB(const uint8* src_yuy2, int src_stride_yuy2,
    832                uint8* dst_argb, int dst_stride_argb,
    833                int width, int height) {
    834   int y;
    835   void (*YUY2ToARGBRow)(const uint8* src_yuy2, uint8* dst_argb, int pix) =
    836       YUY2ToARGBRow_C;
    837   if (!src_yuy2 || !dst_argb ||
    838       width <= 0 || height == 0) {
    839     return -1;
    840   }
    841   // Negative height means invert the image.
    842   if (height < 0) {
    843     height = -height;
    844     src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
    845     src_stride_yuy2 = -src_stride_yuy2;
    846   }
    847   // Coalesce rows.
    848   if (src_stride_yuy2 == width * 2 &&
    849       dst_stride_argb == width * 4) {
    850     width *= height;
    851     height = 1;
    852     src_stride_yuy2 = dst_stride_argb = 0;
    853   }
    854 #if defined(HAS_YUY2TOARGBROW_SSSE3)
    855   // Posix is 16, Windows is 8.
    856   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
    857     YUY2ToARGBRow = YUY2ToARGBRow_Any_SSSE3;
    858     if (IS_ALIGNED(width, 16)) {
    859       YUY2ToARGBRow = YUY2ToARGBRow_Unaligned_SSSE3;
    860       if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16) &&
    861           IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
    862         YUY2ToARGBRow = YUY2ToARGBRow_SSSE3;
    863       }
    864     }
    865   }
    866 #elif defined(HAS_YUY2TOARGBROW_NEON)
    867   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
    868     YUY2ToARGBRow = YUY2ToARGBRow_Any_NEON;
    869     if (IS_ALIGNED(width, 8)) {
    870       YUY2ToARGBRow = YUY2ToARGBRow_NEON;
    871     }
    872   }
    873 #endif
    874   for (y = 0; y < height; ++y) {
    875     YUY2ToARGBRow(src_yuy2, dst_argb, width);
    876     src_yuy2 += src_stride_yuy2;
    877     dst_argb += dst_stride_argb;
    878   }
    879   return 0;
    880 }
    881 
    882 // Convert UYVY to ARGB.
    883 LIBYUV_API
    884 int UYVYToARGB(const uint8* src_uyvy, int src_stride_uyvy,
    885                uint8* dst_argb, int dst_stride_argb,
    886                int width, int height) {
    887   int y;
    888   void (*UYVYToARGBRow)(const uint8* src_uyvy, uint8* dst_argb, int pix) =
    889       UYVYToARGBRow_C;
    890   if (!src_uyvy || !dst_argb ||
    891       width <= 0 || height == 0) {
    892     return -1;
    893   }
    894   // Negative height means invert the image.
    895   if (height < 0) {
    896     height = -height;
    897     src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
    898     src_stride_uyvy = -src_stride_uyvy;
    899   }
    900   // Coalesce rows.
    901   if (src_stride_uyvy == width * 2 &&
    902       dst_stride_argb == width * 4) {
    903     width *= height;
    904     height = 1;
    905     src_stride_uyvy = dst_stride_argb = 0;
    906   }
    907 #if defined(HAS_UYVYTOARGBROW_SSSE3)
    908   // Posix is 16, Windows is 8.
    909   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
    910     UYVYToARGBRow = UYVYToARGBRow_Any_SSSE3;
    911     if (IS_ALIGNED(width, 16)) {
    912       UYVYToARGBRow = UYVYToARGBRow_Unaligned_SSSE3;
    913       if (IS_ALIGNED(src_uyvy, 16) && IS_ALIGNED(src_stride_uyvy, 16) &&
    914           IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
    915         UYVYToARGBRow = UYVYToARGBRow_SSSE3;
    916       }
    917     }
    918   }
    919 #elif defined(HAS_UYVYTOARGBROW_NEON)
    920   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
    921     UYVYToARGBRow = UYVYToARGBRow_Any_NEON;
    922     if (IS_ALIGNED(width, 8)) {
    923       UYVYToARGBRow = UYVYToARGBRow_NEON;
    924     }
    925   }
    926 #endif
    927   for (y = 0; y < height; ++y) {
    928     UYVYToARGBRow(src_uyvy, dst_argb, width);
    929     src_uyvy += src_stride_uyvy;
    930     dst_argb += dst_stride_argb;
    931   }
    932   return 0;
    933 }
    934 
    935 #ifdef __cplusplus
    936 }  // extern "C"
    937 }  // namespace libyuv
    938 #endif
    939