LCOV - code coverage report
Current view: top level - media/libyuv/libyuv/source - planar_functions.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 15 1243 1.2 %
Date: 2017-07-14 16:53:18 Functions: 1 59 1.7 %
Legend: Lines: hit not hit

          Line data    Source code
       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/planar_functions.h"
      12             : 
      13             : #include <string.h>  // for memset()
      14             : 
      15             : #include "libyuv/cpu_id.h"
      16             : #ifdef HAVE_JPEG
      17             : #include "libyuv/mjpeg_decoder.h"
      18             : #endif
      19             : #include "libyuv/row.h"
      20             : #include "libyuv/scale_row.h"  // for ScaleRowDown2
      21             : 
      22             : #ifdef __cplusplus
      23             : namespace libyuv {
      24             : extern "C" {
      25             : #endif
      26             : 
      27             : // Copy a plane of data
      28             : LIBYUV_API
      29           0 : void CopyPlane(const uint8* src_y,
      30             :                int src_stride_y,
      31             :                uint8* dst_y,
      32             :                int dst_stride_y,
      33             :                int width,
      34             :                int height) {
      35             :   int y;
      36           0 :   void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
      37             :   // Negative height means invert the image.
      38           0 :   if (height < 0) {
      39           0 :     height = -height;
      40           0 :     dst_y = dst_y + (height - 1) * dst_stride_y;
      41           0 :     dst_stride_y = -dst_stride_y;
      42             :   }
      43             :   // Coalesce rows.
      44           0 :   if (src_stride_y == width && dst_stride_y == width) {
      45           0 :     width *= height;
      46           0 :     height = 1;
      47           0 :     src_stride_y = dst_stride_y = 0;
      48             :   }
      49             :   // Nothing to do.
      50           0 :   if (src_y == dst_y && src_stride_y == dst_stride_y) {
      51           0 :     return;
      52             :   }
      53             : #if defined(HAS_COPYROW_SSE2)
      54           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
      55           0 :     CopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2;
      56             :   }
      57             : #endif
      58             : #if defined(HAS_COPYROW_AVX)
      59           0 :   if (TestCpuFlag(kCpuHasAVX)) {
      60           0 :     CopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX;
      61             :   }
      62             : #endif
      63             : #if defined(HAS_COPYROW_ERMS)
      64           0 :   if (TestCpuFlag(kCpuHasERMS)) {
      65           0 :     CopyRow = CopyRow_ERMS;
      66             :   }
      67             : #endif
      68             : #if defined(HAS_COPYROW_NEON)
      69             :   if (TestCpuFlag(kCpuHasNEON)) {
      70             :     CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON;
      71             :   }
      72             : #endif
      73             : #if defined(HAS_COPYROW_MIPS)
      74             :   if (TestCpuFlag(kCpuHasMIPS)) {
      75             :     CopyRow = CopyRow_MIPS;
      76             :   }
      77             : #endif
      78             : 
      79             :   // Copy plane
      80           0 :   for (y = 0; y < height; ++y) {
      81           0 :     CopyRow(src_y, dst_y, width);
      82           0 :     src_y += src_stride_y;
      83           0 :     dst_y += dst_stride_y;
      84             :   }
      85             : }
      86             : 
      87             : // TODO(fbarchard): Consider support for negative height.
      88             : // TODO(fbarchard): Consider stride measured in bytes.
      89             : LIBYUV_API
      90           0 : void CopyPlane_16(const uint16* src_y,
      91             :                   int src_stride_y,
      92             :                   uint16* dst_y,
      93             :                   int dst_stride_y,
      94             :                   int width,
      95             :                   int height) {
      96             :   int y;
      97           0 :   void (*CopyRow)(const uint16* src, uint16* dst, int width) = CopyRow_16_C;
      98             :   // Coalesce rows.
      99           0 :   if (src_stride_y == width && dst_stride_y == width) {
     100           0 :     width *= height;
     101           0 :     height = 1;
     102           0 :     src_stride_y = dst_stride_y = 0;
     103             :   }
     104             : #if defined(HAS_COPYROW_16_SSE2)
     105             :   if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32)) {
     106             :     CopyRow = CopyRow_16_SSE2;
     107             :   }
     108             : #endif
     109             : #if defined(HAS_COPYROW_16_ERMS)
     110             :   if (TestCpuFlag(kCpuHasERMS)) {
     111             :     CopyRow = CopyRow_16_ERMS;
     112             :   }
     113             : #endif
     114             : #if defined(HAS_COPYROW_16_NEON)
     115             :   if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) {
     116             :     CopyRow = CopyRow_16_NEON;
     117             :   }
     118             : #endif
     119             : #if defined(HAS_COPYROW_16_MIPS)
     120             :   if (TestCpuFlag(kCpuHasMIPS)) {
     121             :     CopyRow = CopyRow_16_MIPS;
     122             :   }
     123             : #endif
     124             : 
     125             :   // Copy plane
     126           0 :   for (y = 0; y < height; ++y) {
     127           0 :     CopyRow(src_y, dst_y, width);
     128           0 :     src_y += src_stride_y;
     129           0 :     dst_y += dst_stride_y;
     130             :   }
     131           0 : }
     132             : 
     133             : // Copy I422.
     134             : LIBYUV_API
     135           0 : int I422Copy(const uint8* src_y,
     136             :              int src_stride_y,
     137             :              const uint8* src_u,
     138             :              int src_stride_u,
     139             :              const uint8* src_v,
     140             :              int src_stride_v,
     141             :              uint8* dst_y,
     142             :              int dst_stride_y,
     143             :              uint8* dst_u,
     144             :              int dst_stride_u,
     145             :              uint8* dst_v,
     146             :              int dst_stride_v,
     147             :              int width,
     148             :              int height) {
     149           0 :   int halfwidth = (width + 1) >> 1;
     150           0 :   if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
     151           0 :     return -1;
     152             :   }
     153             :   // Negative height means invert the image.
     154           0 :   if (height < 0) {
     155           0 :     height = -height;
     156           0 :     src_y = src_y + (height - 1) * src_stride_y;
     157           0 :     src_u = src_u + (height - 1) * src_stride_u;
     158           0 :     src_v = src_v + (height - 1) * src_stride_v;
     159           0 :     src_stride_y = -src_stride_y;
     160           0 :     src_stride_u = -src_stride_u;
     161           0 :     src_stride_v = -src_stride_v;
     162             :   }
     163             : 
     164           0 :   if (dst_y) {
     165           0 :     CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
     166             :   }
     167           0 :   CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, height);
     168           0 :   CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, height);
     169           0 :   return 0;
     170             : }
     171             : 
     172             : // Copy I444.
     173             : LIBYUV_API
     174           0 : int I444Copy(const uint8* src_y,
     175             :              int src_stride_y,
     176             :              const uint8* src_u,
     177             :              int src_stride_u,
     178             :              const uint8* src_v,
     179             :              int src_stride_v,
     180             :              uint8* dst_y,
     181             :              int dst_stride_y,
     182             :              uint8* dst_u,
     183             :              int dst_stride_u,
     184             :              uint8* dst_v,
     185             :              int dst_stride_v,
     186             :              int width,
     187             :              int height) {
     188           0 :   if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
     189           0 :     return -1;
     190             :   }
     191             :   // Negative height means invert the image.
     192           0 :   if (height < 0) {
     193           0 :     height = -height;
     194           0 :     src_y = src_y + (height - 1) * src_stride_y;
     195           0 :     src_u = src_u + (height - 1) * src_stride_u;
     196           0 :     src_v = src_v + (height - 1) * src_stride_v;
     197           0 :     src_stride_y = -src_stride_y;
     198           0 :     src_stride_u = -src_stride_u;
     199           0 :     src_stride_v = -src_stride_v;
     200             :   }
     201             : 
     202           0 :   if (dst_y) {
     203           0 :     CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
     204             :   }
     205           0 :   CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, width, height);
     206           0 :   CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, width, height);
     207           0 :   return 0;
     208             : }
     209             : 
     210             : // Copy I400.
     211             : LIBYUV_API
     212           0 : int I400ToI400(const uint8* src_y,
     213             :                int src_stride_y,
     214             :                uint8* dst_y,
     215             :                int dst_stride_y,
     216             :                int width,
     217             :                int height) {
     218           0 :   if (!src_y || !dst_y || width <= 0 || height == 0) {
     219           0 :     return -1;
     220             :   }
     221             :   // Negative height means invert the image.
     222           0 :   if (height < 0) {
     223           0 :     height = -height;
     224           0 :     src_y = src_y + (height - 1) * src_stride_y;
     225           0 :     src_stride_y = -src_stride_y;
     226             :   }
     227           0 :   CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
     228           0 :   return 0;
     229             : }
     230             : 
     231             : // Convert I420 to I400.
     232             : LIBYUV_API
     233           0 : int I420ToI400(const uint8* src_y,
     234             :                int src_stride_y,
     235             :                const uint8* src_u,
     236             :                int src_stride_u,
     237             :                const uint8* src_v,
     238             :                int src_stride_v,
     239             :                uint8* dst_y,
     240             :                int dst_stride_y,
     241             :                int width,
     242             :                int height) {
     243             :   (void)src_u;
     244             :   (void)src_stride_u;
     245             :   (void)src_v;
     246             :   (void)src_stride_v;
     247           0 :   if (!src_y || !dst_y || width <= 0 || height == 0) {
     248           0 :     return -1;
     249             :   }
     250             :   // Negative height means invert the image.
     251           0 :   if (height < 0) {
     252           0 :     height = -height;
     253           0 :     src_y = src_y + (height - 1) * src_stride_y;
     254           0 :     src_stride_y = -src_stride_y;
     255             :   }
     256             : 
     257           0 :   CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
     258           0 :   return 0;
     259             : }
     260             : 
     261             : // Support function for NV12 etc UV channels.
     262             : // Width and height are plane sizes (typically half pixel width).
     263             : LIBYUV_API
     264           0 : void SplitUVPlane(const uint8* src_uv,
     265             :                   int src_stride_uv,
     266             :                   uint8* dst_u,
     267             :                   int dst_stride_u,
     268             :                   uint8* dst_v,
     269             :                   int dst_stride_v,
     270             :                   int width,
     271             :                   int height) {
     272             :   int y;
     273             :   void (*SplitUVRow)(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
     274           0 :                      int width) = SplitUVRow_C;
     275             :   // Negative height means invert the image.
     276           0 :   if (height < 0) {
     277           0 :     height = -height;
     278           0 :     dst_u = dst_u + (height - 1) * dst_stride_u;
     279           0 :     dst_v = dst_v + (height - 1) * dst_stride_v;
     280           0 :     dst_stride_u = -dst_stride_u;
     281           0 :     dst_stride_v = -dst_stride_v;
     282             :   }
     283             :   // Coalesce rows.
     284           0 :   if (src_stride_uv == width * 2 && dst_stride_u == width &&
     285             :       dst_stride_v == width) {
     286           0 :     width *= height;
     287           0 :     height = 1;
     288           0 :     src_stride_uv = dst_stride_u = dst_stride_v = 0;
     289             :   }
     290             : #if defined(HAS_SPLITUVROW_SSE2)
     291           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
     292           0 :     SplitUVRow = SplitUVRow_Any_SSE2;
     293           0 :     if (IS_ALIGNED(width, 16)) {
     294           0 :       SplitUVRow = SplitUVRow_SSE2;
     295             :     }
     296             :   }
     297             : #endif
     298             : #if defined(HAS_SPLITUVROW_AVX2)
     299           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
     300           0 :     SplitUVRow = SplitUVRow_Any_AVX2;
     301           0 :     if (IS_ALIGNED(width, 32)) {
     302           0 :       SplitUVRow = SplitUVRow_AVX2;
     303             :     }
     304             :   }
     305             : #endif
     306             : #if defined(HAS_SPLITUVROW_NEON)
     307             :   if (TestCpuFlag(kCpuHasNEON)) {
     308             :     SplitUVRow = SplitUVRow_Any_NEON;
     309             :     if (IS_ALIGNED(width, 16)) {
     310             :       SplitUVRow = SplitUVRow_NEON;
     311             :     }
     312             :   }
     313             : #endif
     314             : #if defined(HAS_SPLITUVROW_DSPR2)
     315             :   if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(dst_u, 4) &&
     316             :       IS_ALIGNED(dst_stride_u, 4) && IS_ALIGNED(dst_v, 4) &&
     317             :       IS_ALIGNED(dst_stride_v, 4)) {
     318             :     SplitUVRow = SplitUVRow_Any_DSPR2;
     319             :     if (IS_ALIGNED(width, 16)) {
     320             :       SplitUVRow = SplitUVRow_DSPR2;
     321             :     }
     322             :   }
     323             : #endif
     324             : 
     325           0 :   for (y = 0; y < height; ++y) {
     326             :     // Copy a row of UV.
     327           0 :     SplitUVRow(src_uv, dst_u, dst_v, width);
     328           0 :     dst_u += dst_stride_u;
     329           0 :     dst_v += dst_stride_v;
     330           0 :     src_uv += src_stride_uv;
     331             :   }
     332           0 : }
     333             : 
     334             : LIBYUV_API
     335           0 : void MergeUVPlane(const uint8* src_u,
     336             :                   int src_stride_u,
     337             :                   const uint8* src_v,
     338             :                   int src_stride_v,
     339             :                   uint8* dst_uv,
     340             :                   int dst_stride_uv,
     341             :                   int width,
     342             :                   int height) {
     343             :   int y;
     344             :   void (*MergeUVRow)(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
     345           0 :                      int width) = MergeUVRow_C;
     346             :   // Coalesce rows.
     347             :   // Negative height means invert the image.
     348           0 :   if (height < 0) {
     349           0 :     height = -height;
     350           0 :     dst_uv = dst_uv + (height - 1) * dst_stride_uv;
     351           0 :     dst_stride_uv = -dst_stride_uv;
     352             :   }
     353             :   // Coalesce rows.
     354           0 :   if (src_stride_u == width && src_stride_v == width &&
     355           0 :       dst_stride_uv == width * 2) {
     356           0 :     width *= height;
     357           0 :     height = 1;
     358           0 :     src_stride_u = src_stride_v = dst_stride_uv = 0;
     359             :   }
     360             : #if defined(HAS_MERGEUVROW_SSE2)
     361           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
     362           0 :     MergeUVRow = MergeUVRow_Any_SSE2;
     363           0 :     if (IS_ALIGNED(width, 16)) {
     364           0 :       MergeUVRow = MergeUVRow_SSE2;
     365             :     }
     366             :   }
     367             : #endif
     368             : #if defined(HAS_MERGEUVROW_AVX2)
     369           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
     370           0 :     MergeUVRow = MergeUVRow_Any_AVX2;
     371           0 :     if (IS_ALIGNED(width, 32)) {
     372           0 :       MergeUVRow = MergeUVRow_AVX2;
     373             :     }
     374             :   }
     375             : #endif
     376             : #if defined(HAS_MERGEUVROW_NEON)
     377             :   if (TestCpuFlag(kCpuHasNEON)) {
     378             :     MergeUVRow = MergeUVRow_Any_NEON;
     379             :     if (IS_ALIGNED(width, 16)) {
     380             :       MergeUVRow = MergeUVRow_NEON;
     381             :     }
     382             :   }
     383             : #endif
     384             : 
     385           0 :   for (y = 0; y < height; ++y) {
     386             :     // Merge a row of U and V into a row of UV.
     387           0 :     MergeUVRow(src_u, src_v, dst_uv, width);
     388           0 :     src_u += src_stride_u;
     389           0 :     src_v += src_stride_v;
     390           0 :     dst_uv += dst_stride_uv;
     391             :   }
     392           0 : }
     393             : 
     394             : // Mirror a plane of data.
     395           0 : void MirrorPlane(const uint8* src_y,
     396             :                  int src_stride_y,
     397             :                  uint8* dst_y,
     398             :                  int dst_stride_y,
     399             :                  int width,
     400             :                  int height) {
     401             :   int y;
     402           0 :   void (*MirrorRow)(const uint8* src, uint8* dst, int width) = MirrorRow_C;
     403             :   // Negative height means invert the image.
     404           0 :   if (height < 0) {
     405           0 :     height = -height;
     406           0 :     src_y = src_y + (height - 1) * src_stride_y;
     407           0 :     src_stride_y = -src_stride_y;
     408             :   }
     409             : #if defined(HAS_MIRRORROW_NEON)
     410             :   if (TestCpuFlag(kCpuHasNEON)) {
     411             :     MirrorRow = MirrorRow_Any_NEON;
     412             :     if (IS_ALIGNED(width, 16)) {
     413             :       MirrorRow = MirrorRow_NEON;
     414             :     }
     415             :   }
     416             : #endif
     417             : #if defined(HAS_MIRRORROW_SSSE3)
     418           0 :   if (TestCpuFlag(kCpuHasSSSE3)) {
     419           0 :     MirrorRow = MirrorRow_Any_SSSE3;
     420           0 :     if (IS_ALIGNED(width, 16)) {
     421           0 :       MirrorRow = MirrorRow_SSSE3;
     422             :     }
     423             :   }
     424             : #endif
     425             : #if defined(HAS_MIRRORROW_AVX2)
     426           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
     427           0 :     MirrorRow = MirrorRow_Any_AVX2;
     428           0 :     if (IS_ALIGNED(width, 32)) {
     429           0 :       MirrorRow = MirrorRow_AVX2;
     430             :     }
     431             :   }
     432             : #endif
     433             : // TODO(fbarchard): Mirror on mips handle unaligned memory.
     434             : #if defined(HAS_MIRRORROW_DSPR2)
     435             :   if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(src_y, 4) &&
     436             :       IS_ALIGNED(src_stride_y, 4) && IS_ALIGNED(dst_y, 4) &&
     437             :       IS_ALIGNED(dst_stride_y, 4)) {
     438             :     MirrorRow = MirrorRow_DSPR2;
     439             :   }
     440             : #endif
     441             : #if defined(HAS_MIRRORROW_MSA)
     442             :   if (TestCpuFlag(kCpuHasMSA)) {
     443             :     MirrorRow = MirrorRow_Any_MSA;
     444             :     if (IS_ALIGNED(width, 64)) {
     445             :       MirrorRow = MirrorRow_MSA;
     446             :     }
     447             :   }
     448             : #endif
     449             : 
     450             :   // Mirror plane
     451           0 :   for (y = 0; y < height; ++y) {
     452           0 :     MirrorRow(src_y, dst_y, width);
     453           0 :     src_y += src_stride_y;
     454           0 :     dst_y += dst_stride_y;
     455             :   }
     456           0 : }
     457             : 
     458             : // Convert YUY2 to I422.
     459             : LIBYUV_API
     460           0 : int YUY2ToI422(const uint8* src_yuy2,
     461             :                int src_stride_yuy2,
     462             :                uint8* dst_y,
     463             :                int dst_stride_y,
     464             :                uint8* dst_u,
     465             :                int dst_stride_u,
     466             :                uint8* dst_v,
     467             :                int dst_stride_v,
     468             :                int width,
     469             :                int height) {
     470             :   int y;
     471             :   void (*YUY2ToUV422Row)(const uint8* src_yuy2, uint8* dst_u, uint8* dst_v,
     472           0 :                          int width) = YUY2ToUV422Row_C;
     473             :   void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int width) =
     474           0 :       YUY2ToYRow_C;
     475           0 :   if (!src_yuy2 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
     476           0 :     return -1;
     477             :   }
     478             :   // Negative height means invert the image.
     479           0 :   if (height < 0) {
     480           0 :     height = -height;
     481           0 :     src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
     482           0 :     src_stride_yuy2 = -src_stride_yuy2;
     483             :   }
     484             :   // Coalesce rows.
     485           0 :   if (src_stride_yuy2 == width * 2 && dst_stride_y == width &&
     486           0 :       dst_stride_u * 2 == width && dst_stride_v * 2 == width &&
     487           0 :       width * height <= 32768) {
     488           0 :     width *= height;
     489           0 :     height = 1;
     490           0 :     src_stride_yuy2 = dst_stride_y = dst_stride_u = dst_stride_v = 0;
     491             :   }
     492             : #if defined(HAS_YUY2TOYROW_SSE2)
     493           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
     494           0 :     YUY2ToUV422Row = YUY2ToUV422Row_Any_SSE2;
     495           0 :     YUY2ToYRow = YUY2ToYRow_Any_SSE2;
     496           0 :     if (IS_ALIGNED(width, 16)) {
     497           0 :       YUY2ToUV422Row = YUY2ToUV422Row_SSE2;
     498           0 :       YUY2ToYRow = YUY2ToYRow_SSE2;
     499             :     }
     500             :   }
     501             : #endif
     502             : #if defined(HAS_YUY2TOYROW_AVX2)
     503           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
     504           0 :     YUY2ToUV422Row = YUY2ToUV422Row_Any_AVX2;
     505           0 :     YUY2ToYRow = YUY2ToYRow_Any_AVX2;
     506           0 :     if (IS_ALIGNED(width, 32)) {
     507           0 :       YUY2ToUV422Row = YUY2ToUV422Row_AVX2;
     508           0 :       YUY2ToYRow = YUY2ToYRow_AVX2;
     509             :     }
     510             :   }
     511             : #endif
     512             : #if defined(HAS_YUY2TOYROW_NEON)
     513             :   if (TestCpuFlag(kCpuHasNEON)) {
     514             :     YUY2ToYRow = YUY2ToYRow_Any_NEON;
     515             :     YUY2ToUV422Row = YUY2ToUV422Row_Any_NEON;
     516             :     if (IS_ALIGNED(width, 16)) {
     517             :       YUY2ToYRow = YUY2ToYRow_NEON;
     518             :       YUY2ToUV422Row = YUY2ToUV422Row_NEON;
     519             :     }
     520             :   }
     521             : #endif
     522             : #if defined(HAS_YUY2TOYROW_MSA)
     523             :   if (TestCpuFlag(kCpuHasMSA)) {
     524             :     YUY2ToYRow = YUY2ToYRow_Any_MSA;
     525             :     YUY2ToUV422Row = YUY2ToUV422Row_Any_MSA;
     526             :     if (IS_ALIGNED(width, 32)) {
     527             :       YUY2ToYRow = YUY2ToYRow_MSA;
     528             :       YUY2ToUV422Row = YUY2ToUV422Row_MSA;
     529             :     }
     530             :   }
     531             : #endif
     532             : 
     533           0 :   for (y = 0; y < height; ++y) {
     534           0 :     YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width);
     535           0 :     YUY2ToYRow(src_yuy2, dst_y, width);
     536           0 :     src_yuy2 += src_stride_yuy2;
     537           0 :     dst_y += dst_stride_y;
     538           0 :     dst_u += dst_stride_u;
     539           0 :     dst_v += dst_stride_v;
     540             :   }
     541           0 :   return 0;
     542             : }
     543             : 
     544             : // Convert UYVY to I422.
     545             : LIBYUV_API
     546           0 : int UYVYToI422(const uint8* src_uyvy,
     547             :                int src_stride_uyvy,
     548             :                uint8* dst_y,
     549             :                int dst_stride_y,
     550             :                uint8* dst_u,
     551             :                int dst_stride_u,
     552             :                uint8* dst_v,
     553             :                int dst_stride_v,
     554             :                int width,
     555             :                int height) {
     556             :   int y;
     557             :   void (*UYVYToUV422Row)(const uint8* src_uyvy, uint8* dst_u, uint8* dst_v,
     558           0 :                          int width) = UYVYToUV422Row_C;
     559             :   void (*UYVYToYRow)(const uint8* src_uyvy, uint8* dst_y, int width) =
     560           0 :       UYVYToYRow_C;
     561           0 :   if (!src_uyvy || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
     562           0 :     return -1;
     563             :   }
     564             :   // Negative height means invert the image.
     565           0 :   if (height < 0) {
     566           0 :     height = -height;
     567           0 :     src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
     568           0 :     src_stride_uyvy = -src_stride_uyvy;
     569             :   }
     570             :   // Coalesce rows.
     571           0 :   if (src_stride_uyvy == width * 2 && dst_stride_y == width &&
     572           0 :       dst_stride_u * 2 == width && dst_stride_v * 2 == width &&
     573           0 :       width * height <= 32768) {
     574           0 :     width *= height;
     575           0 :     height = 1;
     576           0 :     src_stride_uyvy = dst_stride_y = dst_stride_u = dst_stride_v = 0;
     577             :   }
     578             : #if defined(HAS_UYVYTOYROW_SSE2)
     579           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
     580           0 :     UYVYToUV422Row = UYVYToUV422Row_Any_SSE2;
     581           0 :     UYVYToYRow = UYVYToYRow_Any_SSE2;
     582           0 :     if (IS_ALIGNED(width, 16)) {
     583           0 :       UYVYToUV422Row = UYVYToUV422Row_SSE2;
     584           0 :       UYVYToYRow = UYVYToYRow_SSE2;
     585             :     }
     586             :   }
     587             : #endif
     588             : #if defined(HAS_UYVYTOYROW_AVX2)
     589           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
     590           0 :     UYVYToUV422Row = UYVYToUV422Row_Any_AVX2;
     591           0 :     UYVYToYRow = UYVYToYRow_Any_AVX2;
     592           0 :     if (IS_ALIGNED(width, 32)) {
     593           0 :       UYVYToUV422Row = UYVYToUV422Row_AVX2;
     594           0 :       UYVYToYRow = UYVYToYRow_AVX2;
     595             :     }
     596             :   }
     597             : #endif
     598             : #if defined(HAS_UYVYTOYROW_NEON)
     599             :   if (TestCpuFlag(kCpuHasNEON)) {
     600             :     UYVYToYRow = UYVYToYRow_Any_NEON;
     601             :     UYVYToUV422Row = UYVYToUV422Row_Any_NEON;
     602             :     if (IS_ALIGNED(width, 16)) {
     603             :       UYVYToYRow = UYVYToYRow_NEON;
     604             :       UYVYToUV422Row = UYVYToUV422Row_NEON;
     605             :     }
     606             :   }
     607             : #endif
     608             : #if defined(HAS_UYVYTOYROW_MSA)
     609             :   if (TestCpuFlag(kCpuHasMSA)) {
     610             :     UYVYToYRow = UYVYToYRow_Any_MSA;
     611             :     UYVYToUV422Row = UYVYToUV422Row_Any_MSA;
     612             :     if (IS_ALIGNED(width, 32)) {
     613             :       UYVYToYRow = UYVYToYRow_MSA;
     614             :       UYVYToUV422Row = UYVYToUV422Row_MSA;
     615             :     }
     616             :   }
     617             : #endif
     618             : 
     619           0 :   for (y = 0; y < height; ++y) {
     620           0 :     UYVYToUV422Row(src_uyvy, dst_u, dst_v, width);
     621           0 :     UYVYToYRow(src_uyvy, dst_y, width);
     622           0 :     src_uyvy += src_stride_uyvy;
     623           0 :     dst_y += dst_stride_y;
     624           0 :     dst_u += dst_stride_u;
     625           0 :     dst_v += dst_stride_v;
     626             :   }
     627           0 :   return 0;
     628             : }
     629             : 
     630             : // Convert YUY2 to Y.
     631             : LIBYUV_API
     632           0 : int YUY2ToY(const uint8* src_yuy2,
     633             :             int src_stride_yuy2,
     634             :             uint8* dst_y,
     635             :             int dst_stride_y,
     636             :             int width,
     637             :             int height) {
     638             :   int y;
     639             :   void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int width) =
     640           0 :       YUY2ToYRow_C;
     641           0 :   if (!src_yuy2 || !dst_y || width <= 0 || height == 0) {
     642           0 :     return -1;
     643             :   }
     644             :   // Negative height means invert the image.
     645           0 :   if (height < 0) {
     646           0 :     height = -height;
     647           0 :     src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
     648           0 :     src_stride_yuy2 = -src_stride_yuy2;
     649             :   }
     650             :   // Coalesce rows.
     651           0 :   if (src_stride_yuy2 == width * 2 && dst_stride_y == width) {
     652           0 :     width *= height;
     653           0 :     height = 1;
     654           0 :     src_stride_yuy2 = dst_stride_y = 0;
     655             :   }
     656             : #if defined(HAS_YUY2TOYROW_SSE2)
     657           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
     658           0 :     YUY2ToYRow = YUY2ToYRow_Any_SSE2;
     659           0 :     if (IS_ALIGNED(width, 16)) {
     660           0 :       YUY2ToYRow = YUY2ToYRow_SSE2;
     661             :     }
     662             :   }
     663             : #endif
     664             : #if defined(HAS_YUY2TOYROW_AVX2)
     665           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
     666           0 :     YUY2ToYRow = YUY2ToYRow_Any_AVX2;
     667           0 :     if (IS_ALIGNED(width, 32)) {
     668           0 :       YUY2ToYRow = YUY2ToYRow_AVX2;
     669             :     }
     670             :   }
     671             : #endif
     672             : #if defined(HAS_YUY2TOYROW_NEON)
     673             :   if (TestCpuFlag(kCpuHasNEON)) {
     674             :     YUY2ToYRow = YUY2ToYRow_Any_NEON;
     675             :     if (IS_ALIGNED(width, 16)) {
     676             :       YUY2ToYRow = YUY2ToYRow_NEON;
     677             :     }
     678             :   }
     679             : #endif
     680             : #if defined(HAS_YUY2TOYROW_MSA)
     681             :   if (TestCpuFlag(kCpuHasMSA)) {
     682             :     YUY2ToYRow = YUY2ToYRow_Any_MSA;
     683             :     if (IS_ALIGNED(width, 32)) {
     684             :       YUY2ToYRow = YUY2ToYRow_MSA;
     685             :     }
     686             :   }
     687             : #endif
     688             : 
     689           0 :   for (y = 0; y < height; ++y) {
     690           0 :     YUY2ToYRow(src_yuy2, dst_y, width);
     691           0 :     src_yuy2 += src_stride_yuy2;
     692           0 :     dst_y += dst_stride_y;
     693             :   }
     694           0 :   return 0;
     695             : }
     696             : 
     697             : // Mirror I400 with optional flipping
     698             : LIBYUV_API
     699           0 : int I400Mirror(const uint8* src_y,
     700             :                int src_stride_y,
     701             :                uint8* dst_y,
     702             :                int dst_stride_y,
     703             :                int width,
     704             :                int height) {
     705           0 :   if (!src_y || !dst_y || width <= 0 || height == 0) {
     706           0 :     return -1;
     707             :   }
     708             :   // Negative height means invert the image.
     709           0 :   if (height < 0) {
     710           0 :     height = -height;
     711           0 :     src_y = src_y + (height - 1) * src_stride_y;
     712           0 :     src_stride_y = -src_stride_y;
     713             :   }
     714             : 
     715           0 :   MirrorPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
     716           0 :   return 0;
     717             : }
     718             : 
     719             : // Mirror I420 with optional flipping
     720             : LIBYUV_API
     721           0 : int I420Mirror(const uint8* src_y,
     722             :                int src_stride_y,
     723             :                const uint8* src_u,
     724             :                int src_stride_u,
     725             :                const uint8* src_v,
     726             :                int src_stride_v,
     727             :                uint8* dst_y,
     728             :                int dst_stride_y,
     729             :                uint8* dst_u,
     730             :                int dst_stride_u,
     731             :                uint8* dst_v,
     732             :                int dst_stride_v,
     733             :                int width,
     734             :                int height) {
     735           0 :   int halfwidth = (width + 1) >> 1;
     736           0 :   int halfheight = (height + 1) >> 1;
     737           0 :   if (!src_y || !src_u || !src_v || !dst_y || !dst_u || !dst_v || width <= 0 ||
     738             :       height == 0) {
     739           0 :     return -1;
     740             :   }
     741             :   // Negative height means invert the image.
     742           0 :   if (height < 0) {
     743           0 :     height = -height;
     744           0 :     halfheight = (height + 1) >> 1;
     745           0 :     src_y = src_y + (height - 1) * src_stride_y;
     746           0 :     src_u = src_u + (halfheight - 1) * src_stride_u;
     747           0 :     src_v = src_v + (halfheight - 1) * src_stride_v;
     748           0 :     src_stride_y = -src_stride_y;
     749           0 :     src_stride_u = -src_stride_u;
     750           0 :     src_stride_v = -src_stride_v;
     751             :   }
     752             : 
     753           0 :   if (dst_y) {
     754           0 :     MirrorPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
     755             :   }
     756           0 :   MirrorPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
     757           0 :   MirrorPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
     758           0 :   return 0;
     759             : }
     760             : 
     761             : // ARGB mirror.
     762             : LIBYUV_API
     763           0 : int ARGBMirror(const uint8* src_argb,
     764             :                int src_stride_argb,
     765             :                uint8* dst_argb,
     766             :                int dst_stride_argb,
     767             :                int width,
     768             :                int height) {
     769             :   int y;
     770             :   void (*ARGBMirrorRow)(const uint8* src, uint8* dst, int width) =
     771           0 :       ARGBMirrorRow_C;
     772           0 :   if (!src_argb || !dst_argb || width <= 0 || height == 0) {
     773           0 :     return -1;
     774             :   }
     775             :   // Negative height means invert the image.
     776           0 :   if (height < 0) {
     777           0 :     height = -height;
     778           0 :     src_argb = src_argb + (height - 1) * src_stride_argb;
     779           0 :     src_stride_argb = -src_stride_argb;
     780             :   }
     781             : #if defined(HAS_ARGBMIRRORROW_NEON)
     782             :   if (TestCpuFlag(kCpuHasNEON)) {
     783             :     ARGBMirrorRow = ARGBMirrorRow_Any_NEON;
     784             :     if (IS_ALIGNED(width, 4)) {
     785             :       ARGBMirrorRow = ARGBMirrorRow_NEON;
     786             :     }
     787             :   }
     788             : #endif
     789             : #if defined(HAS_ARGBMIRRORROW_SSE2)
     790           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
     791           0 :     ARGBMirrorRow = ARGBMirrorRow_Any_SSE2;
     792           0 :     if (IS_ALIGNED(width, 4)) {
     793           0 :       ARGBMirrorRow = ARGBMirrorRow_SSE2;
     794             :     }
     795             :   }
     796             : #endif
     797             : #if defined(HAS_ARGBMIRRORROW_AVX2)
     798           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
     799           0 :     ARGBMirrorRow = ARGBMirrorRow_Any_AVX2;
     800           0 :     if (IS_ALIGNED(width, 8)) {
     801           0 :       ARGBMirrorRow = ARGBMirrorRow_AVX2;
     802             :     }
     803             :   }
     804             : #endif
     805             : #if defined(HAS_ARGBMIRRORROW_MSA)
     806             :   if (TestCpuFlag(kCpuHasMSA)) {
     807             :     ARGBMirrorRow = ARGBMirrorRow_Any_MSA;
     808             :     if (IS_ALIGNED(width, 16)) {
     809             :       ARGBMirrorRow = ARGBMirrorRow_MSA;
     810             :     }
     811             :   }
     812             : #endif
     813             : 
     814             :   // Mirror plane
     815           0 :   for (y = 0; y < height; ++y) {
     816           0 :     ARGBMirrorRow(src_argb, dst_argb, width);
     817           0 :     src_argb += src_stride_argb;
     818           0 :     dst_argb += dst_stride_argb;
     819             :   }
     820           0 :   return 0;
     821             : }
     822             : 
     823             : // Get a blender that optimized for the CPU and pixel count.
     824             : // As there are 6 blenders to choose from, the caller should try to use
     825             : // the same blend function for all pixels if possible.
     826             : LIBYUV_API
     827           0 : ARGBBlendRow GetARGBBlend() {
     828             :   void (*ARGBBlendRow)(const uint8* src_argb, const uint8* src_argb1,
     829           0 :                        uint8* dst_argb, int width) = ARGBBlendRow_C;
     830             : #if defined(HAS_ARGBBLENDROW_SSSE3)
     831           0 :   if (TestCpuFlag(kCpuHasSSSE3)) {
     832           0 :     ARGBBlendRow = ARGBBlendRow_SSSE3;
     833           0 :     return ARGBBlendRow;
     834             :   }
     835             : #endif
     836             : #if defined(HAS_ARGBBLENDROW_NEON)
     837             :   if (TestCpuFlag(kCpuHasNEON)) {
     838             :     ARGBBlendRow = ARGBBlendRow_NEON;
     839             :   }
     840             : #endif
     841           0 :   return ARGBBlendRow;
     842             : }
     843             : 
     844             : // Alpha Blend 2 ARGB images and store to destination.
     845             : LIBYUV_API
     846           0 : int ARGBBlend(const uint8* src_argb0,
     847             :               int src_stride_argb0,
     848             :               const uint8* src_argb1,
     849             :               int src_stride_argb1,
     850             :               uint8* dst_argb,
     851             :               int dst_stride_argb,
     852             :               int width,
     853             :               int height) {
     854             :   int y;
     855             :   void (*ARGBBlendRow)(const uint8* src_argb, const uint8* src_argb1,
     856           0 :                        uint8* dst_argb, int width) = GetARGBBlend();
     857           0 :   if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
     858           0 :     return -1;
     859             :   }
     860             :   // Negative height means invert the image.
     861           0 :   if (height < 0) {
     862           0 :     height = -height;
     863           0 :     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
     864           0 :     dst_stride_argb = -dst_stride_argb;
     865             :   }
     866             :   // Coalesce rows.
     867           0 :   if (src_stride_argb0 == width * 4 && src_stride_argb1 == width * 4 &&
     868           0 :       dst_stride_argb == width * 4) {
     869           0 :     width *= height;
     870           0 :     height = 1;
     871           0 :     src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
     872             :   }
     873             : 
     874           0 :   for (y = 0; y < height; ++y) {
     875           0 :     ARGBBlendRow(src_argb0, src_argb1, dst_argb, width);
     876           0 :     src_argb0 += src_stride_argb0;
     877           0 :     src_argb1 += src_stride_argb1;
     878           0 :     dst_argb += dst_stride_argb;
     879             :   }
     880           0 :   return 0;
     881             : }
     882             : 
     883             : // Alpha Blend plane and store to destination.
     884             : LIBYUV_API
     885           0 : int BlendPlane(const uint8* src_y0,
     886             :                int src_stride_y0,
     887             :                const uint8* src_y1,
     888             :                int src_stride_y1,
     889             :                const uint8* alpha,
     890             :                int alpha_stride,
     891             :                uint8* dst_y,
     892             :                int dst_stride_y,
     893             :                int width,
     894             :                int height) {
     895             :   int y;
     896             :   void (*BlendPlaneRow)(const uint8* src0, const uint8* src1,
     897             :                         const uint8* alpha, uint8* dst, int width) =
     898           0 :       BlendPlaneRow_C;
     899           0 :   if (!src_y0 || !src_y1 || !alpha || !dst_y || width <= 0 || height == 0) {
     900           0 :     return -1;
     901             :   }
     902             :   // Negative height means invert the image.
     903           0 :   if (height < 0) {
     904           0 :     height = -height;
     905           0 :     dst_y = dst_y + (height - 1) * dst_stride_y;
     906           0 :     dst_stride_y = -dst_stride_y;
     907             :   }
     908             : 
     909             :   // Coalesce rows for Y plane.
     910           0 :   if (src_stride_y0 == width && src_stride_y1 == width &&
     911           0 :       alpha_stride == width && dst_stride_y == width) {
     912           0 :     width *= height;
     913           0 :     height = 1;
     914           0 :     src_stride_y0 = src_stride_y1 = alpha_stride = dst_stride_y = 0;
     915             :   }
     916             : 
     917             : #if defined(HAS_BLENDPLANEROW_SSSE3)
     918           0 :   if (TestCpuFlag(kCpuHasSSSE3)) {
     919           0 :     BlendPlaneRow = BlendPlaneRow_Any_SSSE3;
     920           0 :     if (IS_ALIGNED(width, 8)) {
     921           0 :       BlendPlaneRow = BlendPlaneRow_SSSE3;
     922             :     }
     923             :   }
     924             : #endif
     925             : #if defined(HAS_BLENDPLANEROW_AVX2)
     926           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
     927           0 :     BlendPlaneRow = BlendPlaneRow_Any_AVX2;
     928           0 :     if (IS_ALIGNED(width, 32)) {
     929           0 :       BlendPlaneRow = BlendPlaneRow_AVX2;
     930             :     }
     931             :   }
     932             : #endif
     933             : 
     934           0 :   for (y = 0; y < height; ++y) {
     935           0 :     BlendPlaneRow(src_y0, src_y1, alpha, dst_y, width);
     936           0 :     src_y0 += src_stride_y0;
     937           0 :     src_y1 += src_stride_y1;
     938           0 :     alpha += alpha_stride;
     939           0 :     dst_y += dst_stride_y;
     940             :   }
     941           0 :   return 0;
     942             : }
     943             : 
     944             : #define MAXTWIDTH 2048
     945             : // Alpha Blend YUV images and store to destination.
     946             : LIBYUV_API
     947           0 : int I420Blend(const uint8* src_y0,
     948             :               int src_stride_y0,
     949             :               const uint8* src_u0,
     950             :               int src_stride_u0,
     951             :               const uint8* src_v0,
     952             :               int src_stride_v0,
     953             :               const uint8* src_y1,
     954             :               int src_stride_y1,
     955             :               const uint8* src_u1,
     956             :               int src_stride_u1,
     957             :               const uint8* src_v1,
     958             :               int src_stride_v1,
     959             :               const uint8* alpha,
     960             :               int alpha_stride,
     961             :               uint8* dst_y,
     962             :               int dst_stride_y,
     963             :               uint8* dst_u,
     964             :               int dst_stride_u,
     965             :               uint8* dst_v,
     966             :               int dst_stride_v,
     967             :               int width,
     968             :               int height) {
     969             :   int y;
     970             :   // Half width/height for UV.
     971           0 :   int halfwidth = (width + 1) >> 1;
     972             :   void (*BlendPlaneRow)(const uint8* src0, const uint8* src1,
     973             :                         const uint8* alpha, uint8* dst, int width) =
     974           0 :       BlendPlaneRow_C;
     975             :   void (*ScaleRowDown2)(const uint8* src_ptr, ptrdiff_t src_stride,
     976           0 :                         uint8* dst_ptr, int dst_width) = ScaleRowDown2Box_C;
     977           0 :   if (!src_y0 || !src_u0 || !src_v0 || !src_y1 || !src_u1 || !src_v1 ||
     978           0 :       !alpha || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
     979           0 :     return -1;
     980             :   }
     981             : 
     982             :   // Negative height means invert the image.
     983           0 :   if (height < 0) {
     984           0 :     height = -height;
     985           0 :     dst_y = dst_y + (height - 1) * dst_stride_y;
     986           0 :     dst_stride_y = -dst_stride_y;
     987             :   }
     988             : 
     989             :   // Blend Y plane.
     990             :   BlendPlane(src_y0, src_stride_y0, src_y1, src_stride_y1, alpha, alpha_stride,
     991           0 :              dst_y, dst_stride_y, width, height);
     992             : 
     993             : #if defined(HAS_BLENDPLANEROW_SSSE3)
     994           0 :   if (TestCpuFlag(kCpuHasSSSE3)) {
     995           0 :     BlendPlaneRow = BlendPlaneRow_Any_SSSE3;
     996           0 :     if (IS_ALIGNED(halfwidth, 8)) {
     997           0 :       BlendPlaneRow = BlendPlaneRow_SSSE3;
     998             :     }
     999             :   }
    1000             : #endif
    1001             : #if defined(HAS_BLENDPLANEROW_AVX2)
    1002           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
    1003           0 :     BlendPlaneRow = BlendPlaneRow_Any_AVX2;
    1004           0 :     if (IS_ALIGNED(halfwidth, 32)) {
    1005           0 :       BlendPlaneRow = BlendPlaneRow_AVX2;
    1006             :     }
    1007             :   }
    1008             : #endif
    1009           0 :   if (!IS_ALIGNED(width, 2)) {
    1010           0 :     ScaleRowDown2 = ScaleRowDown2Box_Odd_C;
    1011             :   }
    1012             : #if defined(HAS_SCALEROWDOWN2_NEON)
    1013             :   if (TestCpuFlag(kCpuHasNEON)) {
    1014             :     ScaleRowDown2 = ScaleRowDown2Box_Odd_NEON;
    1015             :     if (IS_ALIGNED(width, 2)) {
    1016             :       ScaleRowDown2 = ScaleRowDown2Box_Any_NEON;
    1017             :       if (IS_ALIGNED(halfwidth, 16)) {
    1018             :         ScaleRowDown2 = ScaleRowDown2Box_NEON;
    1019             :       }
    1020             :     }
    1021             :   }
    1022             : #endif
    1023             : #if defined(HAS_SCALEROWDOWN2_SSSE3)
    1024           0 :   if (TestCpuFlag(kCpuHasSSSE3)) {
    1025           0 :     ScaleRowDown2 = ScaleRowDown2Box_Odd_SSSE3;
    1026           0 :     if (IS_ALIGNED(width, 2)) {
    1027           0 :       ScaleRowDown2 = ScaleRowDown2Box_Any_SSSE3;
    1028           0 :       if (IS_ALIGNED(halfwidth, 16)) {
    1029           0 :         ScaleRowDown2 = ScaleRowDown2Box_SSSE3;
    1030             :       }
    1031             :     }
    1032             :   }
    1033             : #endif
    1034             : #if defined(HAS_SCALEROWDOWN2_AVX2)
    1035           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
    1036           0 :     ScaleRowDown2 = ScaleRowDown2Box_Odd_AVX2;
    1037           0 :     if (IS_ALIGNED(width, 2)) {
    1038           0 :       ScaleRowDown2 = ScaleRowDown2Box_Any_AVX2;
    1039           0 :       if (IS_ALIGNED(halfwidth, 32)) {
    1040           0 :         ScaleRowDown2 = ScaleRowDown2Box_AVX2;
    1041             :       }
    1042             :     }
    1043             :   }
    1044             : #endif
    1045             : 
    1046             :   // Row buffer for intermediate alpha pixels.
    1047           0 :   align_buffer_64(halfalpha, halfwidth);
    1048           0 :   for (y = 0; y < height; y += 2) {
    1049             :     // last row of odd height image use 1 row of alpha instead of 2.
    1050           0 :     if (y == (height - 1)) {
    1051           0 :       alpha_stride = 0;
    1052             :     }
    1053             :     // Subsample 2 rows of UV to half width and half height.
    1054           0 :     ScaleRowDown2(alpha, alpha_stride, halfalpha, halfwidth);
    1055           0 :     alpha += alpha_stride * 2;
    1056           0 :     BlendPlaneRow(src_u0, src_u1, halfalpha, dst_u, halfwidth);
    1057           0 :     BlendPlaneRow(src_v0, src_v1, halfalpha, dst_v, halfwidth);
    1058           0 :     src_u0 += src_stride_u0;
    1059           0 :     src_u1 += src_stride_u1;
    1060           0 :     dst_u += dst_stride_u;
    1061           0 :     src_v0 += src_stride_v0;
    1062           0 :     src_v1 += src_stride_v1;
    1063           0 :     dst_v += dst_stride_v;
    1064             :   }
    1065           0 :   free_aligned_buffer_64(halfalpha);
    1066           0 :   return 0;
    1067             : }
    1068             : 
    1069             : // Multiply 2 ARGB images and store to destination.
    1070             : LIBYUV_API
    1071           0 : int ARGBMultiply(const uint8* src_argb0,
    1072             :                  int src_stride_argb0,
    1073             :                  const uint8* src_argb1,
    1074             :                  int src_stride_argb1,
    1075             :                  uint8* dst_argb,
    1076             :                  int dst_stride_argb,
    1077             :                  int width,
    1078             :                  int height) {
    1079             :   int y;
    1080             :   void (*ARGBMultiplyRow)(const uint8* src0, const uint8* src1, uint8* dst,
    1081           0 :                           int width) = ARGBMultiplyRow_C;
    1082           0 :   if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
    1083           0 :     return -1;
    1084             :   }
    1085             :   // Negative height means invert the image.
    1086           0 :   if (height < 0) {
    1087           0 :     height = -height;
    1088           0 :     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
    1089           0 :     dst_stride_argb = -dst_stride_argb;
    1090             :   }
    1091             :   // Coalesce rows.
    1092           0 :   if (src_stride_argb0 == width * 4 && src_stride_argb1 == width * 4 &&
    1093           0 :       dst_stride_argb == width * 4) {
    1094           0 :     width *= height;
    1095           0 :     height = 1;
    1096           0 :     src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
    1097             :   }
    1098             : #if defined(HAS_ARGBMULTIPLYROW_SSE2)
    1099           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
    1100           0 :     ARGBMultiplyRow = ARGBMultiplyRow_Any_SSE2;
    1101           0 :     if (IS_ALIGNED(width, 4)) {
    1102           0 :       ARGBMultiplyRow = ARGBMultiplyRow_SSE2;
    1103             :     }
    1104             :   }
    1105             : #endif
    1106             : #if defined(HAS_ARGBMULTIPLYROW_AVX2)
    1107           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
    1108           0 :     ARGBMultiplyRow = ARGBMultiplyRow_Any_AVX2;
    1109           0 :     if (IS_ALIGNED(width, 8)) {
    1110           0 :       ARGBMultiplyRow = ARGBMultiplyRow_AVX2;
    1111             :     }
    1112             :   }
    1113             : #endif
    1114             : #if defined(HAS_ARGBMULTIPLYROW_NEON)
    1115             :   if (TestCpuFlag(kCpuHasNEON)) {
    1116             :     ARGBMultiplyRow = ARGBMultiplyRow_Any_NEON;
    1117             :     if (IS_ALIGNED(width, 8)) {
    1118             :       ARGBMultiplyRow = ARGBMultiplyRow_NEON;
    1119             :     }
    1120             :   }
    1121             : #endif
    1122             : #if defined(HAS_ARGBMULTIPLYROW_MSA)
    1123             :   if (TestCpuFlag(kCpuHasMSA)) {
    1124             :     ARGBMultiplyRow = ARGBMultiplyRow_Any_MSA;
    1125             :     if (IS_ALIGNED(width, 4)) {
    1126             :       ARGBMultiplyRow = ARGBMultiplyRow_MSA;
    1127             :     }
    1128             :   }
    1129             : #endif
    1130             : 
    1131             :   // Multiply plane
    1132           0 :   for (y = 0; y < height; ++y) {
    1133           0 :     ARGBMultiplyRow(src_argb0, src_argb1, dst_argb, width);
    1134           0 :     src_argb0 += src_stride_argb0;
    1135           0 :     src_argb1 += src_stride_argb1;
    1136           0 :     dst_argb += dst_stride_argb;
    1137             :   }
    1138           0 :   return 0;
    1139             : }
    1140             : 
    1141             : // Add 2 ARGB images and store to destination.
    1142             : LIBYUV_API
    1143           0 : int ARGBAdd(const uint8* src_argb0,
    1144             :             int src_stride_argb0,
    1145             :             const uint8* src_argb1,
    1146             :             int src_stride_argb1,
    1147             :             uint8* dst_argb,
    1148             :             int dst_stride_argb,
    1149             :             int width,
    1150             :             int height) {
    1151             :   int y;
    1152             :   void (*ARGBAddRow)(const uint8* src0, const uint8* src1, uint8* dst,
    1153           0 :                      int width) = ARGBAddRow_C;
    1154           0 :   if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
    1155           0 :     return -1;
    1156             :   }
    1157             :   // Negative height means invert the image.
    1158           0 :   if (height < 0) {
    1159           0 :     height = -height;
    1160           0 :     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
    1161           0 :     dst_stride_argb = -dst_stride_argb;
    1162             :   }
    1163             :   // Coalesce rows.
    1164           0 :   if (src_stride_argb0 == width * 4 && src_stride_argb1 == width * 4 &&
    1165           0 :       dst_stride_argb == width * 4) {
    1166           0 :     width *= height;
    1167           0 :     height = 1;
    1168           0 :     src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
    1169             :   }
    1170             : #if defined(HAS_ARGBADDROW_SSE2) && (defined(_MSC_VER) && !defined(__clang__))
    1171             :   if (TestCpuFlag(kCpuHasSSE2)) {
    1172             :     ARGBAddRow = ARGBAddRow_SSE2;
    1173             :   }
    1174             : #endif
    1175             : #if defined(HAS_ARGBADDROW_SSE2) && !(defined(_MSC_VER) && !defined(__clang__))
    1176           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
    1177           0 :     ARGBAddRow = ARGBAddRow_Any_SSE2;
    1178           0 :     if (IS_ALIGNED(width, 4)) {
    1179           0 :       ARGBAddRow = ARGBAddRow_SSE2;
    1180             :     }
    1181             :   }
    1182             : #endif
    1183             : #if defined(HAS_ARGBADDROW_AVX2)
    1184           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
    1185           0 :     ARGBAddRow = ARGBAddRow_Any_AVX2;
    1186           0 :     if (IS_ALIGNED(width, 8)) {
    1187           0 :       ARGBAddRow = ARGBAddRow_AVX2;
    1188             :     }
    1189             :   }
    1190             : #endif
    1191             : #if defined(HAS_ARGBADDROW_NEON)
    1192             :   if (TestCpuFlag(kCpuHasNEON)) {
    1193             :     ARGBAddRow = ARGBAddRow_Any_NEON;
    1194             :     if (IS_ALIGNED(width, 8)) {
    1195             :       ARGBAddRow = ARGBAddRow_NEON;
    1196             :     }
    1197             :   }
    1198             : #endif
    1199             : #if defined(HAS_ARGBADDROW_MSA)
    1200             :   if (TestCpuFlag(kCpuHasMSA)) {
    1201             :     ARGBAddRow = ARGBAddRow_Any_MSA;
    1202             :     if (IS_ALIGNED(width, 8)) {
    1203             :       ARGBAddRow = ARGBAddRow_MSA;
    1204             :     }
    1205             :   }
    1206             : #endif
    1207             : 
    1208             :   // Add plane
    1209           0 :   for (y = 0; y < height; ++y) {
    1210           0 :     ARGBAddRow(src_argb0, src_argb1, dst_argb, width);
    1211           0 :     src_argb0 += src_stride_argb0;
    1212           0 :     src_argb1 += src_stride_argb1;
    1213           0 :     dst_argb += dst_stride_argb;
    1214             :   }
    1215           0 :   return 0;
    1216             : }
    1217             : 
    1218             : // Subtract 2 ARGB images and store to destination.
    1219             : LIBYUV_API
    1220           0 : int ARGBSubtract(const uint8* src_argb0,
    1221             :                  int src_stride_argb0,
    1222             :                  const uint8* src_argb1,
    1223             :                  int src_stride_argb1,
    1224             :                  uint8* dst_argb,
    1225             :                  int dst_stride_argb,
    1226             :                  int width,
    1227             :                  int height) {
    1228             :   int y;
    1229             :   void (*ARGBSubtractRow)(const uint8* src0, const uint8* src1, uint8* dst,
    1230           0 :                           int width) = ARGBSubtractRow_C;
    1231           0 :   if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
    1232           0 :     return -1;
    1233             :   }
    1234             :   // Negative height means invert the image.
    1235           0 :   if (height < 0) {
    1236           0 :     height = -height;
    1237           0 :     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
    1238           0 :     dst_stride_argb = -dst_stride_argb;
    1239             :   }
    1240             :   // Coalesce rows.
    1241           0 :   if (src_stride_argb0 == width * 4 && src_stride_argb1 == width * 4 &&
    1242           0 :       dst_stride_argb == width * 4) {
    1243           0 :     width *= height;
    1244           0 :     height = 1;
    1245           0 :     src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
    1246             :   }
    1247             : #if defined(HAS_ARGBSUBTRACTROW_SSE2)
    1248           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
    1249           0 :     ARGBSubtractRow = ARGBSubtractRow_Any_SSE2;
    1250           0 :     if (IS_ALIGNED(width, 4)) {
    1251           0 :       ARGBSubtractRow = ARGBSubtractRow_SSE2;
    1252             :     }
    1253             :   }
    1254             : #endif
    1255             : #if defined(HAS_ARGBSUBTRACTROW_AVX2)
    1256           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
    1257           0 :     ARGBSubtractRow = ARGBSubtractRow_Any_AVX2;
    1258           0 :     if (IS_ALIGNED(width, 8)) {
    1259           0 :       ARGBSubtractRow = ARGBSubtractRow_AVX2;
    1260             :     }
    1261             :   }
    1262             : #endif
    1263             : #if defined(HAS_ARGBSUBTRACTROW_NEON)
    1264             :   if (TestCpuFlag(kCpuHasNEON)) {
    1265             :     ARGBSubtractRow = ARGBSubtractRow_Any_NEON;
    1266             :     if (IS_ALIGNED(width, 8)) {
    1267             :       ARGBSubtractRow = ARGBSubtractRow_NEON;
    1268             :     }
    1269             :   }
    1270             : #endif
    1271             : #if defined(HAS_ARGBSUBTRACTROW_MSA)
    1272             :   if (TestCpuFlag(kCpuHasMSA)) {
    1273             :     ARGBSubtractRow = ARGBSubtractRow_Any_MSA;
    1274             :     if (IS_ALIGNED(width, 8)) {
    1275             :       ARGBSubtractRow = ARGBSubtractRow_MSA;
    1276             :     }
    1277             :   }
    1278             : #endif
    1279             : 
    1280             :   // Subtract plane
    1281           0 :   for (y = 0; y < height; ++y) {
    1282           0 :     ARGBSubtractRow(src_argb0, src_argb1, dst_argb, width);
    1283           0 :     src_argb0 += src_stride_argb0;
    1284           0 :     src_argb1 += src_stride_argb1;
    1285           0 :     dst_argb += dst_stride_argb;
    1286             :   }
    1287           0 :   return 0;
    1288             : }
    1289             : // Convert I422 to RGBA with matrix
    1290           0 : static int I422ToRGBAMatrix(const uint8* src_y,
    1291             :                             int src_stride_y,
    1292             :                             const uint8* src_u,
    1293             :                             int src_stride_u,
    1294             :                             const uint8* src_v,
    1295             :                             int src_stride_v,
    1296             :                             uint8* dst_rgba,
    1297             :                             int dst_stride_rgba,
    1298             :                             const struct YuvConstants* yuvconstants,
    1299             :                             int width,
    1300             :                             int height) {
    1301             :   int y;
    1302             :   void (*I422ToRGBARow)(const uint8* y_buf, const uint8* u_buf,
    1303             :                         const uint8* v_buf, uint8* rgb_buf,
    1304             :                         const struct YuvConstants* yuvconstants, int width) =
    1305           0 :       I422ToRGBARow_C;
    1306           0 :   if (!src_y || !src_u || !src_v || !dst_rgba || width <= 0 || height == 0) {
    1307           0 :     return -1;
    1308             :   }
    1309             :   // Negative height means invert the image.
    1310           0 :   if (height < 0) {
    1311           0 :     height = -height;
    1312           0 :     dst_rgba = dst_rgba + (height - 1) * dst_stride_rgba;
    1313           0 :     dst_stride_rgba = -dst_stride_rgba;
    1314             :   }
    1315             : #if defined(HAS_I422TORGBAROW_SSSE3)
    1316           0 :   if (TestCpuFlag(kCpuHasSSSE3)) {
    1317           0 :     I422ToRGBARow = I422ToRGBARow_Any_SSSE3;
    1318           0 :     if (IS_ALIGNED(width, 8)) {
    1319           0 :       I422ToRGBARow = I422ToRGBARow_SSSE3;
    1320             :     }
    1321             :   }
    1322             : #endif
    1323             : #if defined(HAS_I422TORGBAROW_AVX2)
    1324           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
    1325           0 :     I422ToRGBARow = I422ToRGBARow_Any_AVX2;
    1326           0 :     if (IS_ALIGNED(width, 16)) {
    1327           0 :       I422ToRGBARow = I422ToRGBARow_AVX2;
    1328             :     }
    1329             :   }
    1330             : #endif
    1331             : #if defined(HAS_I422TORGBAROW_NEON)
    1332             :   if (TestCpuFlag(kCpuHasNEON)) {
    1333             :     I422ToRGBARow = I422ToRGBARow_Any_NEON;
    1334             :     if (IS_ALIGNED(width, 8)) {
    1335             :       I422ToRGBARow = I422ToRGBARow_NEON;
    1336             :     }
    1337             :   }
    1338             : #endif
    1339             : #if defined(HAS_I422TORGBAROW_DSPR2)
    1340             :   if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 4) &&
    1341             :       IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
    1342             :       IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
    1343             :       IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
    1344             :       IS_ALIGNED(dst_rgba, 4) && IS_ALIGNED(dst_stride_rgba, 4)) {
    1345             :     I422ToRGBARow = I422ToRGBARow_DSPR2;
    1346             :   }
    1347             : #endif
    1348             : #if defined(HAS_I422TORGBAROW_MSA)
    1349             :   if (TestCpuFlag(kCpuHasMSA)) {
    1350             :     I422ToRGBARow = I422ToRGBARow_Any_MSA;
    1351             :     if (IS_ALIGNED(width, 8)) {
    1352             :       I422ToRGBARow = I422ToRGBARow_MSA;
    1353             :     }
    1354             :   }
    1355             : #endif
    1356             : 
    1357           0 :   for (y = 0; y < height; ++y) {
    1358           0 :     I422ToRGBARow(src_y, src_u, src_v, dst_rgba, yuvconstants, width);
    1359           0 :     dst_rgba += dst_stride_rgba;
    1360           0 :     src_y += src_stride_y;
    1361           0 :     src_u += src_stride_u;
    1362           0 :     src_v += src_stride_v;
    1363             :   }
    1364           0 :   return 0;
    1365             : }
    1366             : 
    1367             : // Convert I422 to RGBA.
    1368             : LIBYUV_API
    1369           0 : int I422ToRGBA(const uint8* src_y,
    1370             :                int src_stride_y,
    1371             :                const uint8* src_u,
    1372             :                int src_stride_u,
    1373             :                const uint8* src_v,
    1374             :                int src_stride_v,
    1375             :                uint8* dst_rgba,
    1376             :                int dst_stride_rgba,
    1377             :                int width,
    1378             :                int height) {
    1379             :   return I422ToRGBAMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
    1380             :                           src_stride_v, dst_rgba, dst_stride_rgba,
    1381           0 :                           &kYuvI601Constants, width, height);
    1382             : }
    1383             : 
    1384             : // Convert I422 to BGRA.
    1385             : LIBYUV_API
    1386           0 : int I422ToBGRA(const uint8* src_y,
    1387             :                int src_stride_y,
    1388             :                const uint8* src_u,
    1389             :                int src_stride_u,
    1390             :                const uint8* src_v,
    1391             :                int src_stride_v,
    1392             :                uint8* dst_bgra,
    1393             :                int dst_stride_bgra,
    1394             :                int width,
    1395             :                int height) {
    1396             :   return I422ToRGBAMatrix(src_y, src_stride_y, src_v,
    1397             :                           src_stride_v,  // Swap U and V
    1398             :                           src_u, src_stride_u, dst_bgra, dst_stride_bgra,
    1399             :                           &kYvuI601Constants,  // Use Yvu matrix
    1400           0 :                           width, height);
    1401             : }
    1402             : 
    1403             : // Convert NV12 to RGB565.
    1404             : LIBYUV_API
    1405           0 : int NV12ToRGB565(const uint8* src_y,
    1406             :                  int src_stride_y,
    1407             :                  const uint8* src_uv,
    1408             :                  int src_stride_uv,
    1409             :                  uint8* dst_rgb565,
    1410             :                  int dst_stride_rgb565,
    1411             :                  int width,
    1412             :                  int height) {
    1413             :   int y;
    1414             :   void (*NV12ToRGB565Row)(
    1415             :       const uint8* y_buf, const uint8* uv_buf, uint8* rgb_buf,
    1416           0 :       const struct YuvConstants* yuvconstants, int width) = NV12ToRGB565Row_C;
    1417           0 :   if (!src_y || !src_uv || !dst_rgb565 || width <= 0 || height == 0) {
    1418           0 :     return -1;
    1419             :   }
    1420             :   // Negative height means invert the image.
    1421           0 :   if (height < 0) {
    1422           0 :     height = -height;
    1423           0 :     dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
    1424           0 :     dst_stride_rgb565 = -dst_stride_rgb565;
    1425             :   }
    1426             : #if defined(HAS_NV12TORGB565ROW_SSSE3)
    1427           0 :   if (TestCpuFlag(kCpuHasSSSE3)) {
    1428           0 :     NV12ToRGB565Row = NV12ToRGB565Row_Any_SSSE3;
    1429           0 :     if (IS_ALIGNED(width, 8)) {
    1430           0 :       NV12ToRGB565Row = NV12ToRGB565Row_SSSE3;
    1431             :     }
    1432             :   }
    1433             : #endif
    1434             : #if defined(HAS_NV12TORGB565ROW_AVX2)
    1435           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
    1436           0 :     NV12ToRGB565Row = NV12ToRGB565Row_Any_AVX2;
    1437           0 :     if (IS_ALIGNED(width, 16)) {
    1438           0 :       NV12ToRGB565Row = NV12ToRGB565Row_AVX2;
    1439             :     }
    1440             :   }
    1441             : #endif
    1442             : #if defined(HAS_NV12TORGB565ROW_NEON)
    1443             :   if (TestCpuFlag(kCpuHasNEON)) {
    1444             :     NV12ToRGB565Row = NV12ToRGB565Row_Any_NEON;
    1445             :     if (IS_ALIGNED(width, 8)) {
    1446             :       NV12ToRGB565Row = NV12ToRGB565Row_NEON;
    1447             :     }
    1448             :   }
    1449             : #endif
    1450             : #if defined(HAS_NV12TORGB565ROW_MSA)
    1451             :   if (TestCpuFlag(kCpuHasMSA)) {
    1452             :     NV12ToRGB565Row = NV12ToRGB565Row_Any_MSA;
    1453             :     if (IS_ALIGNED(width, 8)) {
    1454             :       NV12ToRGB565Row = NV12ToRGB565Row_MSA;
    1455             :     }
    1456             :   }
    1457             : #endif
    1458             : 
    1459           0 :   for (y = 0; y < height; ++y) {
    1460           0 :     NV12ToRGB565Row(src_y, src_uv, dst_rgb565, &kYuvI601Constants, width);
    1461           0 :     dst_rgb565 += dst_stride_rgb565;
    1462           0 :     src_y += src_stride_y;
    1463           0 :     if (y & 1) {
    1464           0 :       src_uv += src_stride_uv;
    1465             :     }
    1466             :   }
    1467           0 :   return 0;
    1468             : }
    1469             : 
    1470             : // Convert RAW to RGB24.
    1471             : LIBYUV_API
    1472           0 : int RAWToRGB24(const uint8* src_raw,
    1473             :                int src_stride_raw,
    1474             :                uint8* dst_rgb24,
    1475             :                int dst_stride_rgb24,
    1476             :                int width,
    1477             :                int height) {
    1478             :   int y;
    1479             :   void (*RAWToRGB24Row)(const uint8* src_rgb, uint8* dst_rgb24, int width) =
    1480           0 :       RAWToRGB24Row_C;
    1481           0 :   if (!src_raw || !dst_rgb24 || width <= 0 || height == 0) {
    1482           0 :     return -1;
    1483             :   }
    1484             :   // Negative height means invert the image.
    1485           0 :   if (height < 0) {
    1486           0 :     height = -height;
    1487           0 :     src_raw = src_raw + (height - 1) * src_stride_raw;
    1488           0 :     src_stride_raw = -src_stride_raw;
    1489             :   }
    1490             :   // Coalesce rows.
    1491           0 :   if (src_stride_raw == width * 3 && dst_stride_rgb24 == width * 3) {
    1492           0 :     width *= height;
    1493           0 :     height = 1;
    1494           0 :     src_stride_raw = dst_stride_rgb24 = 0;
    1495             :   }
    1496             : #if defined(HAS_RAWTORGB24ROW_SSSE3)
    1497           0 :   if (TestCpuFlag(kCpuHasSSSE3)) {
    1498           0 :     RAWToRGB24Row = RAWToRGB24Row_Any_SSSE3;
    1499           0 :     if (IS_ALIGNED(width, 8)) {
    1500           0 :       RAWToRGB24Row = RAWToRGB24Row_SSSE3;
    1501             :     }
    1502             :   }
    1503             : #endif
    1504             : #if defined(HAS_RAWTORGB24ROW_NEON)
    1505             :   if (TestCpuFlag(kCpuHasNEON)) {
    1506             :     RAWToRGB24Row = RAWToRGB24Row_Any_NEON;
    1507             :     if (IS_ALIGNED(width, 8)) {
    1508             :       RAWToRGB24Row = RAWToRGB24Row_NEON;
    1509             :     }
    1510             :   }
    1511             : #endif
    1512             : 
    1513           0 :   for (y = 0; y < height; ++y) {
    1514           0 :     RAWToRGB24Row(src_raw, dst_rgb24, width);
    1515           0 :     src_raw += src_stride_raw;
    1516           0 :     dst_rgb24 += dst_stride_rgb24;
    1517             :   }
    1518           0 :   return 0;
    1519             : }
    1520             : 
    1521             : LIBYUV_API
    1522           0 : void SetPlane(uint8* dst_y,
    1523             :               int dst_stride_y,
    1524             :               int width,
    1525             :               int height,
    1526             :               uint32 value) {
    1527             :   int y;
    1528           0 :   void (*SetRow)(uint8 * dst, uint8 value, int width) = SetRow_C;
    1529           0 :   if (height < 0) {
    1530           0 :     height = -height;
    1531           0 :     dst_y = dst_y + (height - 1) * dst_stride_y;
    1532           0 :     dst_stride_y = -dst_stride_y;
    1533             :   }
    1534             :   // Coalesce rows.
    1535           0 :   if (dst_stride_y == width) {
    1536           0 :     width *= height;
    1537           0 :     height = 1;
    1538           0 :     dst_stride_y = 0;
    1539             :   }
    1540             : #if defined(HAS_SETROW_NEON)
    1541             :   if (TestCpuFlag(kCpuHasNEON)) {
    1542             :     SetRow = SetRow_Any_NEON;
    1543             :     if (IS_ALIGNED(width, 16)) {
    1544             :       SetRow = SetRow_NEON;
    1545             :     }
    1546             :   }
    1547             : #endif
    1548             : #if defined(HAS_SETROW_X86)
    1549           0 :   if (TestCpuFlag(kCpuHasX86)) {
    1550           0 :     SetRow = SetRow_Any_X86;
    1551           0 :     if (IS_ALIGNED(width, 4)) {
    1552           0 :       SetRow = SetRow_X86;
    1553             :     }
    1554             :   }
    1555             : #endif
    1556             : #if defined(HAS_SETROW_ERMS)
    1557           0 :   if (TestCpuFlag(kCpuHasERMS)) {
    1558           0 :     SetRow = SetRow_ERMS;
    1559             :   }
    1560             : #endif
    1561             : 
    1562             :   // Set plane
    1563           0 :   for (y = 0; y < height; ++y) {
    1564           0 :     SetRow(dst_y, value, width);
    1565           0 :     dst_y += dst_stride_y;
    1566             :   }
    1567           0 : }
    1568             : 
    1569             : // Draw a rectangle into I420
    1570             : LIBYUV_API
    1571           0 : int I420Rect(uint8* dst_y,
    1572             :              int dst_stride_y,
    1573             :              uint8* dst_u,
    1574             :              int dst_stride_u,
    1575             :              uint8* dst_v,
    1576             :              int dst_stride_v,
    1577             :              int x,
    1578             :              int y,
    1579             :              int width,
    1580             :              int height,
    1581             :              int value_y,
    1582             :              int value_u,
    1583             :              int value_v) {
    1584           0 :   int halfwidth = (width + 1) >> 1;
    1585           0 :   int halfheight = (height + 1) >> 1;
    1586           0 :   uint8* start_y = dst_y + y * dst_stride_y + x;
    1587           0 :   uint8* start_u = dst_u + (y / 2) * dst_stride_u + (x / 2);
    1588           0 :   uint8* start_v = dst_v + (y / 2) * dst_stride_v + (x / 2);
    1589           0 :   if (!dst_y || !dst_u || !dst_v || width <= 0 || height == 0 || x < 0 ||
    1590           0 :       y < 0 || value_y < 0 || value_y > 255 || value_u < 0 || value_u > 255 ||
    1591           0 :       value_v < 0 || value_v > 255) {
    1592           0 :     return -1;
    1593             :   }
    1594             : 
    1595           0 :   SetPlane(start_y, dst_stride_y, width, height, value_y);
    1596           0 :   SetPlane(start_u, dst_stride_u, halfwidth, halfheight, value_u);
    1597           0 :   SetPlane(start_v, dst_stride_v, halfwidth, halfheight, value_v);
    1598           0 :   return 0;
    1599             : }
    1600             : 
    1601             : // Draw a rectangle into ARGB
    1602             : LIBYUV_API
    1603           5 : int ARGBRect(uint8* dst_argb,
    1604             :              int dst_stride_argb,
    1605             :              int dst_x,
    1606             :              int dst_y,
    1607             :              int width,
    1608             :              int height,
    1609             :              uint32 value) {
    1610             :   int y;
    1611           5 :   void (*ARGBSetRow)(uint8 * dst_argb, uint32 value, int width) = ARGBSetRow_C;
    1612           5 :   if (!dst_argb || width <= 0 || height == 0 || dst_x < 0 || dst_y < 0) {
    1613           0 :     return -1;
    1614             :   }
    1615           5 :   if (height < 0) {
    1616           0 :     height = -height;
    1617           0 :     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
    1618           0 :     dst_stride_argb = -dst_stride_argb;
    1619             :   }
    1620           5 :   dst_argb += dst_y * dst_stride_argb + dst_x * 4;
    1621             :   // Coalesce rows.
    1622           5 :   if (dst_stride_argb == width * 4) {
    1623           5 :     width *= height;
    1624           5 :     height = 1;
    1625           5 :     dst_stride_argb = 0;
    1626             :   }
    1627             : 
    1628             : #if defined(HAS_ARGBSETROW_NEON)
    1629             :   if (TestCpuFlag(kCpuHasNEON)) {
    1630             :     ARGBSetRow = ARGBSetRow_Any_NEON;
    1631             :     if (IS_ALIGNED(width, 4)) {
    1632             :       ARGBSetRow = ARGBSetRow_NEON;
    1633             :     }
    1634             :   }
    1635             : #endif
    1636             : #if defined(HAS_ARGBSETROW_X86)
    1637           5 :   if (TestCpuFlag(kCpuHasX86)) {
    1638           5 :     ARGBSetRow = ARGBSetRow_X86;
    1639             :   }
    1640             : #endif
    1641             : 
    1642             :   // Set plane
    1643          10 :   for (y = 0; y < height; ++y) {
    1644           5 :     ARGBSetRow(dst_argb, value, width);
    1645           5 :     dst_argb += dst_stride_argb;
    1646             :   }
    1647           5 :   return 0;
    1648             : }
    1649             : 
    1650             : // Convert unattentuated ARGB to preattenuated ARGB.
    1651             : // An unattenutated ARGB alpha blend uses the formula
    1652             : // p = a * f + (1 - a) * b
    1653             : // where
    1654             : //   p is output pixel
    1655             : //   f is foreground pixel
    1656             : //   b is background pixel
    1657             : //   a is alpha value from foreground pixel
    1658             : // An preattenutated ARGB alpha blend uses the formula
    1659             : // p = f + (1 - a) * b
    1660             : // where
    1661             : //   f is foreground pixel premultiplied by alpha
    1662             : 
    1663             : LIBYUV_API
    1664           0 : int ARGBAttenuate(const uint8* src_argb,
    1665             :                   int src_stride_argb,
    1666             :                   uint8* dst_argb,
    1667             :                   int dst_stride_argb,
    1668             :                   int width,
    1669             :                   int height) {
    1670             :   int y;
    1671             :   void (*ARGBAttenuateRow)(const uint8* src_argb, uint8* dst_argb, int width) =
    1672           0 :       ARGBAttenuateRow_C;
    1673           0 :   if (!src_argb || !dst_argb || width <= 0 || height == 0) {
    1674           0 :     return -1;
    1675             :   }
    1676           0 :   if (height < 0) {
    1677           0 :     height = -height;
    1678           0 :     src_argb = src_argb + (height - 1) * src_stride_argb;
    1679           0 :     src_stride_argb = -src_stride_argb;
    1680             :   }
    1681             :   // Coalesce rows.
    1682           0 :   if (src_stride_argb == width * 4 && dst_stride_argb == width * 4) {
    1683           0 :     width *= height;
    1684           0 :     height = 1;
    1685           0 :     src_stride_argb = dst_stride_argb = 0;
    1686             :   }
    1687             : #if defined(HAS_ARGBATTENUATEROW_SSSE3)
    1688           0 :   if (TestCpuFlag(kCpuHasSSSE3)) {
    1689           0 :     ARGBAttenuateRow = ARGBAttenuateRow_Any_SSSE3;
    1690           0 :     if (IS_ALIGNED(width, 4)) {
    1691           0 :       ARGBAttenuateRow = ARGBAttenuateRow_SSSE3;
    1692             :     }
    1693             :   }
    1694             : #endif
    1695             : #if defined(HAS_ARGBATTENUATEROW_AVX2)
    1696           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
    1697           0 :     ARGBAttenuateRow = ARGBAttenuateRow_Any_AVX2;
    1698           0 :     if (IS_ALIGNED(width, 8)) {
    1699           0 :       ARGBAttenuateRow = ARGBAttenuateRow_AVX2;
    1700             :     }
    1701             :   }
    1702             : #endif
    1703             : #if defined(HAS_ARGBATTENUATEROW_NEON)
    1704             :   if (TestCpuFlag(kCpuHasNEON)) {
    1705             :     ARGBAttenuateRow = ARGBAttenuateRow_Any_NEON;
    1706             :     if (IS_ALIGNED(width, 8)) {
    1707             :       ARGBAttenuateRow = ARGBAttenuateRow_NEON;
    1708             :     }
    1709             :   }
    1710             : #endif
    1711             : #if defined(HAS_ARGBATTENUATEROW_MSA)
    1712             :   if (TestCpuFlag(kCpuHasMSA)) {
    1713             :     ARGBAttenuateRow = ARGBAttenuateRow_Any_MSA;
    1714             :     if (IS_ALIGNED(width, 8)) {
    1715             :       ARGBAttenuateRow = ARGBAttenuateRow_MSA;
    1716             :     }
    1717             :   }
    1718             : #endif
    1719             : 
    1720           0 :   for (y = 0; y < height; ++y) {
    1721           0 :     ARGBAttenuateRow(src_argb, dst_argb, width);
    1722           0 :     src_argb += src_stride_argb;
    1723           0 :     dst_argb += dst_stride_argb;
    1724             :   }
    1725           0 :   return 0;
    1726             : }
    1727             : 
    1728             : // Convert preattentuated ARGB to unattenuated ARGB.
    1729             : LIBYUV_API
    1730           0 : int ARGBUnattenuate(const uint8* src_argb,
    1731             :                     int src_stride_argb,
    1732             :                     uint8* dst_argb,
    1733             :                     int dst_stride_argb,
    1734             :                     int width,
    1735             :                     int height) {
    1736             :   int y;
    1737             :   void (*ARGBUnattenuateRow)(const uint8* src_argb, uint8* dst_argb,
    1738           0 :                              int width) = ARGBUnattenuateRow_C;
    1739           0 :   if (!src_argb || !dst_argb || width <= 0 || height == 0) {
    1740           0 :     return -1;
    1741             :   }
    1742           0 :   if (height < 0) {
    1743           0 :     height = -height;
    1744           0 :     src_argb = src_argb + (height - 1) * src_stride_argb;
    1745           0 :     src_stride_argb = -src_stride_argb;
    1746             :   }
    1747             :   // Coalesce rows.
    1748           0 :   if (src_stride_argb == width * 4 && dst_stride_argb == width * 4) {
    1749           0 :     width *= height;
    1750           0 :     height = 1;
    1751           0 :     src_stride_argb = dst_stride_argb = 0;
    1752             :   }
    1753             : #if defined(HAS_ARGBUNATTENUATEROW_SSE2)
    1754           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
    1755           0 :     ARGBUnattenuateRow = ARGBUnattenuateRow_Any_SSE2;
    1756           0 :     if (IS_ALIGNED(width, 4)) {
    1757           0 :       ARGBUnattenuateRow = ARGBUnattenuateRow_SSE2;
    1758             :     }
    1759             :   }
    1760             : #endif
    1761             : #if defined(HAS_ARGBUNATTENUATEROW_AVX2)
    1762           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
    1763           0 :     ARGBUnattenuateRow = ARGBUnattenuateRow_Any_AVX2;
    1764           0 :     if (IS_ALIGNED(width, 8)) {
    1765           0 :       ARGBUnattenuateRow = ARGBUnattenuateRow_AVX2;
    1766             :     }
    1767             :   }
    1768             : #endif
    1769             :   // TODO(fbarchard): Neon version.
    1770             : 
    1771           0 :   for (y = 0; y < height; ++y) {
    1772           0 :     ARGBUnattenuateRow(src_argb, dst_argb, width);
    1773           0 :     src_argb += src_stride_argb;
    1774           0 :     dst_argb += dst_stride_argb;
    1775             :   }
    1776           0 :   return 0;
    1777             : }
    1778             : 
    1779             : // Convert ARGB to Grayed ARGB.
    1780             : LIBYUV_API
    1781           0 : int ARGBGrayTo(const uint8* src_argb,
    1782             :                int src_stride_argb,
    1783             :                uint8* dst_argb,
    1784             :                int dst_stride_argb,
    1785             :                int width,
    1786             :                int height) {
    1787             :   int y;
    1788             :   void (*ARGBGrayRow)(const uint8* src_argb, uint8* dst_argb, int width) =
    1789           0 :       ARGBGrayRow_C;
    1790           0 :   if (!src_argb || !dst_argb || width <= 0 || height == 0) {
    1791           0 :     return -1;
    1792             :   }
    1793           0 :   if (height < 0) {
    1794           0 :     height = -height;
    1795           0 :     src_argb = src_argb + (height - 1) * src_stride_argb;
    1796           0 :     src_stride_argb = -src_stride_argb;
    1797             :   }
    1798             :   // Coalesce rows.
    1799           0 :   if (src_stride_argb == width * 4 && dst_stride_argb == width * 4) {
    1800           0 :     width *= height;
    1801           0 :     height = 1;
    1802           0 :     src_stride_argb = dst_stride_argb = 0;
    1803             :   }
    1804             : #if defined(HAS_ARGBGRAYROW_SSSE3)
    1805           0 :   if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 8)) {
    1806           0 :     ARGBGrayRow = ARGBGrayRow_SSSE3;
    1807             :   }
    1808             : #endif
    1809             : #if defined(HAS_ARGBGRAYROW_NEON)
    1810             :   if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
    1811             :     ARGBGrayRow = ARGBGrayRow_NEON;
    1812             :   }
    1813             : #endif
    1814             : #if defined(HAS_ARGBGRAYROW_MSA)
    1815             :   if (TestCpuFlag(kCpuHasMSA) && IS_ALIGNED(width, 8)) {
    1816             :     ARGBGrayRow = ARGBGrayRow_MSA;
    1817             :   }
    1818             : #endif
    1819             : 
    1820           0 :   for (y = 0; y < height; ++y) {
    1821           0 :     ARGBGrayRow(src_argb, dst_argb, width);
    1822           0 :     src_argb += src_stride_argb;
    1823           0 :     dst_argb += dst_stride_argb;
    1824             :   }
    1825           0 :   return 0;
    1826             : }
    1827             : 
    1828             : // Make a rectangle of ARGB gray scale.
    1829             : LIBYUV_API
    1830           0 : int ARGBGray(uint8* dst_argb,
    1831             :              int dst_stride_argb,
    1832             :              int dst_x,
    1833             :              int dst_y,
    1834             :              int width,
    1835             :              int height) {
    1836             :   int y;
    1837             :   void (*ARGBGrayRow)(const uint8* src_argb, uint8* dst_argb, int width) =
    1838           0 :       ARGBGrayRow_C;
    1839           0 :   uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
    1840           0 :   if (!dst_argb || width <= 0 || height <= 0 || dst_x < 0 || dst_y < 0) {
    1841           0 :     return -1;
    1842             :   }
    1843             :   // Coalesce rows.
    1844           0 :   if (dst_stride_argb == width * 4) {
    1845           0 :     width *= height;
    1846           0 :     height = 1;
    1847           0 :     dst_stride_argb = 0;
    1848             :   }
    1849             : #if defined(HAS_ARGBGRAYROW_SSSE3)
    1850           0 :   if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 8)) {
    1851           0 :     ARGBGrayRow = ARGBGrayRow_SSSE3;
    1852             :   }
    1853             : #endif
    1854             : #if defined(HAS_ARGBGRAYROW_NEON)
    1855             :   if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
    1856             :     ARGBGrayRow = ARGBGrayRow_NEON;
    1857             :   }
    1858             : #endif
    1859             : #if defined(HAS_ARGBGRAYROW_MSA)
    1860             :   if (TestCpuFlag(kCpuHasMSA) && IS_ALIGNED(width, 8)) {
    1861             :     ARGBGrayRow = ARGBGrayRow_MSA;
    1862             :   }
    1863             : #endif
    1864             : 
    1865           0 :   for (y = 0; y < height; ++y) {
    1866           0 :     ARGBGrayRow(dst, dst, width);
    1867           0 :     dst += dst_stride_argb;
    1868             :   }
    1869           0 :   return 0;
    1870             : }
    1871             : 
    1872             : // Make a rectangle of ARGB Sepia tone.
    1873             : LIBYUV_API
    1874           0 : int ARGBSepia(uint8* dst_argb,
    1875             :               int dst_stride_argb,
    1876             :               int dst_x,
    1877             :               int dst_y,
    1878             :               int width,
    1879             :               int height) {
    1880             :   int y;
    1881           0 :   void (*ARGBSepiaRow)(uint8 * dst_argb, int width) = ARGBSepiaRow_C;
    1882           0 :   uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
    1883           0 :   if (!dst_argb || width <= 0 || height <= 0 || dst_x < 0 || dst_y < 0) {
    1884           0 :     return -1;
    1885             :   }
    1886             :   // Coalesce rows.
    1887           0 :   if (dst_stride_argb == width * 4) {
    1888           0 :     width *= height;
    1889           0 :     height = 1;
    1890           0 :     dst_stride_argb = 0;
    1891             :   }
    1892             : #if defined(HAS_ARGBSEPIAROW_SSSE3)
    1893           0 :   if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 8)) {
    1894           0 :     ARGBSepiaRow = ARGBSepiaRow_SSSE3;
    1895             :   }
    1896             : #endif
    1897             : #if defined(HAS_ARGBSEPIAROW_NEON)
    1898             :   if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
    1899             :     ARGBSepiaRow = ARGBSepiaRow_NEON;
    1900             :   }
    1901             : #endif
    1902             : #if defined(HAS_ARGBSEPIAROW_MSA)
    1903             :   if (TestCpuFlag(kCpuHasMSA) && IS_ALIGNED(width, 8)) {
    1904             :     ARGBSepiaRow = ARGBSepiaRow_MSA;
    1905             :   }
    1906             : #endif
    1907             : 
    1908           0 :   for (y = 0; y < height; ++y) {
    1909           0 :     ARGBSepiaRow(dst, width);
    1910           0 :     dst += dst_stride_argb;
    1911             :   }
    1912           0 :   return 0;
    1913             : }
    1914             : 
    1915             : // Apply a 4x4 matrix to each ARGB pixel.
    1916             : // Note: Normally for shading, but can be used to swizzle or invert.
    1917             : LIBYUV_API
    1918           0 : int ARGBColorMatrix(const uint8* src_argb,
    1919             :                     int src_stride_argb,
    1920             :                     uint8* dst_argb,
    1921             :                     int dst_stride_argb,
    1922             :                     const int8* matrix_argb,
    1923             :                     int width,
    1924             :                     int height) {
    1925             :   int y;
    1926             :   void (*ARGBColorMatrixRow)(const uint8* src_argb, uint8* dst_argb,
    1927             :                              const int8* matrix_argb, int width) =
    1928           0 :       ARGBColorMatrixRow_C;
    1929           0 :   if (!src_argb || !dst_argb || !matrix_argb || width <= 0 || height == 0) {
    1930           0 :     return -1;
    1931             :   }
    1932           0 :   if (height < 0) {
    1933           0 :     height = -height;
    1934           0 :     src_argb = src_argb + (height - 1) * src_stride_argb;
    1935           0 :     src_stride_argb = -src_stride_argb;
    1936             :   }
    1937             :   // Coalesce rows.
    1938           0 :   if (src_stride_argb == width * 4 && dst_stride_argb == width * 4) {
    1939           0 :     width *= height;
    1940           0 :     height = 1;
    1941           0 :     src_stride_argb = dst_stride_argb = 0;
    1942             :   }
    1943             : #if defined(HAS_ARGBCOLORMATRIXROW_SSSE3)
    1944           0 :   if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 8)) {
    1945           0 :     ARGBColorMatrixRow = ARGBColorMatrixRow_SSSE3;
    1946             :   }
    1947             : #endif
    1948             : #if defined(HAS_ARGBCOLORMATRIXROW_NEON)
    1949             :   if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
    1950             :     ARGBColorMatrixRow = ARGBColorMatrixRow_NEON;
    1951             :   }
    1952             : #endif
    1953           0 :   for (y = 0; y < height; ++y) {
    1954           0 :     ARGBColorMatrixRow(src_argb, dst_argb, matrix_argb, width);
    1955           0 :     src_argb += src_stride_argb;
    1956           0 :     dst_argb += dst_stride_argb;
    1957             :   }
    1958           0 :   return 0;
    1959             : }
    1960             : 
    1961             : // Apply a 4x3 matrix to each ARGB pixel.
    1962             : // Deprecated.
    1963             : LIBYUV_API
    1964           0 : int RGBColorMatrix(uint8* dst_argb,
    1965             :                    int dst_stride_argb,
    1966             :                    const int8* matrix_rgb,
    1967             :                    int dst_x,
    1968             :                    int dst_y,
    1969             :                    int width,
    1970             :                    int height) {
    1971             :   SIMD_ALIGNED(int8 matrix_argb[16]);
    1972           0 :   uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
    1973           0 :   if (!dst_argb || !matrix_rgb || width <= 0 || height <= 0 || dst_x < 0 ||
    1974             :       dst_y < 0) {
    1975           0 :     return -1;
    1976             :   }
    1977             : 
    1978             :   // Convert 4x3 7 bit matrix to 4x4 6 bit matrix.
    1979           0 :   matrix_argb[0] = matrix_rgb[0] / 2;
    1980           0 :   matrix_argb[1] = matrix_rgb[1] / 2;
    1981           0 :   matrix_argb[2] = matrix_rgb[2] / 2;
    1982           0 :   matrix_argb[3] = matrix_rgb[3] / 2;
    1983           0 :   matrix_argb[4] = matrix_rgb[4] / 2;
    1984           0 :   matrix_argb[5] = matrix_rgb[5] / 2;
    1985           0 :   matrix_argb[6] = matrix_rgb[6] / 2;
    1986           0 :   matrix_argb[7] = matrix_rgb[7] / 2;
    1987           0 :   matrix_argb[8] = matrix_rgb[8] / 2;
    1988           0 :   matrix_argb[9] = matrix_rgb[9] / 2;
    1989           0 :   matrix_argb[10] = matrix_rgb[10] / 2;
    1990           0 :   matrix_argb[11] = matrix_rgb[11] / 2;
    1991           0 :   matrix_argb[14] = matrix_argb[13] = matrix_argb[12] = 0;
    1992           0 :   matrix_argb[15] = 64;  // 1.0
    1993             : 
    1994             :   return ARGBColorMatrix((const uint8*)(dst), dst_stride_argb, dst,
    1995           0 :                          dst_stride_argb, &matrix_argb[0], width, height);
    1996             : }
    1997             : 
    1998             : // Apply a color table each ARGB pixel.
    1999             : // Table contains 256 ARGB values.
    2000             : LIBYUV_API
    2001           0 : int ARGBColorTable(uint8* dst_argb,
    2002             :                    int dst_stride_argb,
    2003             :                    const uint8* table_argb,
    2004             :                    int dst_x,
    2005             :                    int dst_y,
    2006             :                    int width,
    2007             :                    int height) {
    2008             :   int y;
    2009             :   void (*ARGBColorTableRow)(uint8 * dst_argb, const uint8* table_argb,
    2010           0 :                             int width) = ARGBColorTableRow_C;
    2011           0 :   uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
    2012           0 :   if (!dst_argb || !table_argb || width <= 0 || height <= 0 || dst_x < 0 ||
    2013             :       dst_y < 0) {
    2014           0 :     return -1;
    2015             :   }
    2016             :   // Coalesce rows.
    2017           0 :   if (dst_stride_argb == width * 4) {
    2018           0 :     width *= height;
    2019           0 :     height = 1;
    2020           0 :     dst_stride_argb = 0;
    2021             :   }
    2022             : #if defined(HAS_ARGBCOLORTABLEROW_X86)
    2023           0 :   if (TestCpuFlag(kCpuHasX86)) {
    2024           0 :     ARGBColorTableRow = ARGBColorTableRow_X86;
    2025             :   }
    2026             : #endif
    2027           0 :   for (y = 0; y < height; ++y) {
    2028           0 :     ARGBColorTableRow(dst, table_argb, width);
    2029           0 :     dst += dst_stride_argb;
    2030             :   }
    2031           0 :   return 0;
    2032             : }
    2033             : 
    2034             : // Apply a color table each ARGB pixel but preserve destination alpha.
    2035             : // Table contains 256 ARGB values.
    2036             : LIBYUV_API
    2037           0 : int RGBColorTable(uint8* dst_argb,
    2038             :                   int dst_stride_argb,
    2039             :                   const uint8* table_argb,
    2040             :                   int dst_x,
    2041             :                   int dst_y,
    2042             :                   int width,
    2043             :                   int height) {
    2044             :   int y;
    2045             :   void (*RGBColorTableRow)(uint8 * dst_argb, const uint8* table_argb,
    2046           0 :                            int width) = RGBColorTableRow_C;
    2047           0 :   uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
    2048           0 :   if (!dst_argb || !table_argb || width <= 0 || height <= 0 || dst_x < 0 ||
    2049             :       dst_y < 0) {
    2050           0 :     return -1;
    2051             :   }
    2052             :   // Coalesce rows.
    2053           0 :   if (dst_stride_argb == width * 4) {
    2054           0 :     width *= height;
    2055           0 :     height = 1;
    2056           0 :     dst_stride_argb = 0;
    2057             :   }
    2058             : #if defined(HAS_RGBCOLORTABLEROW_X86)
    2059           0 :   if (TestCpuFlag(kCpuHasX86)) {
    2060           0 :     RGBColorTableRow = RGBColorTableRow_X86;
    2061             :   }
    2062             : #endif
    2063           0 :   for (y = 0; y < height; ++y) {
    2064           0 :     RGBColorTableRow(dst, table_argb, width);
    2065           0 :     dst += dst_stride_argb;
    2066             :   }
    2067           0 :   return 0;
    2068             : }
    2069             : 
    2070             : // ARGBQuantize is used to posterize art.
    2071             : // e.g. rgb / qvalue * qvalue + qvalue / 2
    2072             : // But the low levels implement efficiently with 3 parameters, and could be
    2073             : // used for other high level operations.
    2074             : // dst_argb[0] = (b * scale >> 16) * interval_size + interval_offset;
    2075             : // where scale is 1 / interval_size as a fixed point value.
    2076             : // The divide is replaces with a multiply by reciprocal fixed point multiply.
    2077             : // Caveat - although SSE2 saturates, the C function does not and should be used
    2078             : // with care if doing anything but quantization.
    2079             : LIBYUV_API
    2080           0 : int ARGBQuantize(uint8* dst_argb,
    2081             :                  int dst_stride_argb,
    2082             :                  int scale,
    2083             :                  int interval_size,
    2084             :                  int interval_offset,
    2085             :                  int dst_x,
    2086             :                  int dst_y,
    2087             :                  int width,
    2088             :                  int height) {
    2089             :   int y;
    2090             :   void (*ARGBQuantizeRow)(uint8 * dst_argb, int scale, int interval_size,
    2091           0 :                           int interval_offset, int width) = ARGBQuantizeRow_C;
    2092           0 :   uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
    2093           0 :   if (!dst_argb || width <= 0 || height <= 0 || dst_x < 0 || dst_y < 0 ||
    2094           0 :       interval_size < 1 || interval_size > 255) {
    2095           0 :     return -1;
    2096             :   }
    2097             :   // Coalesce rows.
    2098           0 :   if (dst_stride_argb == width * 4) {
    2099           0 :     width *= height;
    2100           0 :     height = 1;
    2101           0 :     dst_stride_argb = 0;
    2102             :   }
    2103             : #if defined(HAS_ARGBQUANTIZEROW_SSE2)
    2104           0 :   if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 4)) {
    2105           0 :     ARGBQuantizeRow = ARGBQuantizeRow_SSE2;
    2106             :   }
    2107             : #endif
    2108             : #if defined(HAS_ARGBQUANTIZEROW_NEON)
    2109             :   if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
    2110             :     ARGBQuantizeRow = ARGBQuantizeRow_NEON;
    2111             :   }
    2112             : #endif
    2113           0 :   for (y = 0; y < height; ++y) {
    2114           0 :     ARGBQuantizeRow(dst, scale, interval_size, interval_offset, width);
    2115           0 :     dst += dst_stride_argb;
    2116             :   }
    2117           0 :   return 0;
    2118             : }
    2119             : 
    2120             : // Computes table of cumulative sum for image where the value is the sum
    2121             : // of all values above and to the left of the entry. Used by ARGBBlur.
    2122             : LIBYUV_API
    2123           0 : int ARGBComputeCumulativeSum(const uint8* src_argb,
    2124             :                              int src_stride_argb,
    2125             :                              int32* dst_cumsum,
    2126             :                              int dst_stride32_cumsum,
    2127             :                              int width,
    2128             :                              int height) {
    2129             :   int y;
    2130             :   void (*ComputeCumulativeSumRow)(const uint8* row, int32* cumsum,
    2131             :                                   const int32* previous_cumsum, int width) =
    2132           0 :       ComputeCumulativeSumRow_C;
    2133           0 :   int32* previous_cumsum = dst_cumsum;
    2134           0 :   if (!dst_cumsum || !src_argb || width <= 0 || height <= 0) {
    2135           0 :     return -1;
    2136             :   }
    2137             : #if defined(HAS_CUMULATIVESUMTOAVERAGEROW_SSE2)
    2138           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
    2139           0 :     ComputeCumulativeSumRow = ComputeCumulativeSumRow_SSE2;
    2140             :   }
    2141             : #endif
    2142           0 :   memset(dst_cumsum, 0, width * sizeof(dst_cumsum[0]) * 4);  // 4 int per pixel.
    2143           0 :   for (y = 0; y < height; ++y) {
    2144           0 :     ComputeCumulativeSumRow(src_argb, dst_cumsum, previous_cumsum, width);
    2145           0 :     previous_cumsum = dst_cumsum;
    2146           0 :     dst_cumsum += dst_stride32_cumsum;
    2147           0 :     src_argb += src_stride_argb;
    2148             :   }
    2149           0 :   return 0;
    2150             : }
    2151             : 
    2152             : // Blur ARGB image.
    2153             : // Caller should allocate CumulativeSum table of width * height * 16 bytes
    2154             : // aligned to 16 byte boundary. height can be radius * 2 + 2 to save memory
    2155             : // as the buffer is treated as circular.
    2156             : LIBYUV_API
    2157           0 : int ARGBBlur(const uint8* src_argb,
    2158             :              int src_stride_argb,
    2159             :              uint8* dst_argb,
    2160             :              int dst_stride_argb,
    2161             :              int32* dst_cumsum,
    2162             :              int dst_stride32_cumsum,
    2163             :              int width,
    2164             :              int height,
    2165             :              int radius) {
    2166             :   int y;
    2167             :   void (*ComputeCumulativeSumRow)(const uint8* row, int32* cumsum,
    2168             :                                   const int32* previous_cumsum, int width) =
    2169           0 :       ComputeCumulativeSumRow_C;
    2170             :   void (*CumulativeSumToAverageRow)(const int32* topleft, const int32* botleft,
    2171             :                                     int width, int area, uint8* dst,
    2172           0 :                                     int count) = CumulativeSumToAverageRow_C;
    2173             :   int32* cumsum_bot_row;
    2174             :   int32* max_cumsum_bot_row;
    2175             :   int32* cumsum_top_row;
    2176             : 
    2177           0 :   if (!src_argb || !dst_argb || width <= 0 || height == 0) {
    2178           0 :     return -1;
    2179             :   }
    2180           0 :   if (height < 0) {
    2181           0 :     height = -height;
    2182           0 :     src_argb = src_argb + (height - 1) * src_stride_argb;
    2183           0 :     src_stride_argb = -src_stride_argb;
    2184             :   }
    2185           0 :   if (radius > height) {
    2186           0 :     radius = height;
    2187             :   }
    2188           0 :   if (radius > (width / 2 - 1)) {
    2189           0 :     radius = width / 2 - 1;
    2190             :   }
    2191           0 :   if (radius <= 0) {
    2192           0 :     return -1;
    2193             :   }
    2194             : #if defined(HAS_CUMULATIVESUMTOAVERAGEROW_SSE2)
    2195           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
    2196           0 :     ComputeCumulativeSumRow = ComputeCumulativeSumRow_SSE2;
    2197           0 :     CumulativeSumToAverageRow = CumulativeSumToAverageRow_SSE2;
    2198             :   }
    2199             : #endif
    2200             :   // Compute enough CumulativeSum for first row to be blurred. After this
    2201             :   // one row of CumulativeSum is updated at a time.
    2202             :   ARGBComputeCumulativeSum(src_argb, src_stride_argb, dst_cumsum,
    2203           0 :                            dst_stride32_cumsum, width, radius);
    2204             : 
    2205           0 :   src_argb = src_argb + radius * src_stride_argb;
    2206           0 :   cumsum_bot_row = &dst_cumsum[(radius - 1) * dst_stride32_cumsum];
    2207             : 
    2208           0 :   max_cumsum_bot_row = &dst_cumsum[(radius * 2 + 2) * dst_stride32_cumsum];
    2209           0 :   cumsum_top_row = &dst_cumsum[0];
    2210             : 
    2211           0 :   for (y = 0; y < height; ++y) {
    2212           0 :     int top_y = ((y - radius - 1) >= 0) ? (y - radius - 1) : 0;
    2213           0 :     int bot_y = ((y + radius) < height) ? (y + radius) : (height - 1);
    2214           0 :     int area = radius * (bot_y - top_y);
    2215           0 :     int boxwidth = radius * 4;
    2216             :     int x;
    2217             :     int n;
    2218             : 
    2219             :     // Increment cumsum_top_row pointer with circular buffer wrap around.
    2220           0 :     if (top_y) {
    2221           0 :       cumsum_top_row += dst_stride32_cumsum;
    2222           0 :       if (cumsum_top_row >= max_cumsum_bot_row) {
    2223           0 :         cumsum_top_row = dst_cumsum;
    2224             :       }
    2225             :     }
    2226             :     // Increment cumsum_bot_row pointer with circular buffer wrap around and
    2227             :     // then fill in a row of CumulativeSum.
    2228           0 :     if ((y + radius) < height) {
    2229           0 :       const int32* prev_cumsum_bot_row = cumsum_bot_row;
    2230           0 :       cumsum_bot_row += dst_stride32_cumsum;
    2231           0 :       if (cumsum_bot_row >= max_cumsum_bot_row) {
    2232           0 :         cumsum_bot_row = dst_cumsum;
    2233             :       }
    2234             :       ComputeCumulativeSumRow(src_argb, cumsum_bot_row, prev_cumsum_bot_row,
    2235           0 :                               width);
    2236           0 :       src_argb += src_stride_argb;
    2237             :     }
    2238             : 
    2239             :     // Left clipped.
    2240           0 :     for (x = 0; x < radius + 1; ++x) {
    2241           0 :       CumulativeSumToAverageRow(cumsum_top_row, cumsum_bot_row, boxwidth, area,
    2242           0 :                                 &dst_argb[x * 4], 1);
    2243           0 :       area += (bot_y - top_y);
    2244           0 :       boxwidth += 4;
    2245             :     }
    2246             : 
    2247             :     // Middle unclipped.
    2248           0 :     n = (width - 1) - radius - x + 1;
    2249           0 :     CumulativeSumToAverageRow(cumsum_top_row, cumsum_bot_row, boxwidth, area,
    2250           0 :                               &dst_argb[x * 4], n);
    2251             : 
    2252             :     // Right clipped.
    2253           0 :     for (x += n; x <= width - 1; ++x) {
    2254           0 :       area -= (bot_y - top_y);
    2255           0 :       boxwidth -= 4;
    2256           0 :       CumulativeSumToAverageRow(cumsum_top_row + (x - radius - 1) * 4,
    2257           0 :                                 cumsum_bot_row + (x - radius - 1) * 4, boxwidth,
    2258           0 :                                 area, &dst_argb[x * 4], 1);
    2259             :     }
    2260           0 :     dst_argb += dst_stride_argb;
    2261             :   }
    2262           0 :   return 0;
    2263             : }
    2264             : 
    2265             : // Multiply ARGB image by a specified ARGB value.
    2266             : LIBYUV_API
    2267           0 : int ARGBShade(const uint8* src_argb,
    2268             :               int src_stride_argb,
    2269             :               uint8* dst_argb,
    2270             :               int dst_stride_argb,
    2271             :               int width,
    2272             :               int height,
    2273             :               uint32 value) {
    2274             :   int y;
    2275             :   void (*ARGBShadeRow)(const uint8* src_argb, uint8* dst_argb, int width,
    2276           0 :                        uint32 value) = ARGBShadeRow_C;
    2277           0 :   if (!src_argb || !dst_argb || width <= 0 || height == 0 || value == 0u) {
    2278           0 :     return -1;
    2279             :   }
    2280           0 :   if (height < 0) {
    2281           0 :     height = -height;
    2282           0 :     src_argb = src_argb + (height - 1) * src_stride_argb;
    2283           0 :     src_stride_argb = -src_stride_argb;
    2284             :   }
    2285             :   // Coalesce rows.
    2286           0 :   if (src_stride_argb == width * 4 && dst_stride_argb == width * 4) {
    2287           0 :     width *= height;
    2288           0 :     height = 1;
    2289           0 :     src_stride_argb = dst_stride_argb = 0;
    2290             :   }
    2291             : #if defined(HAS_ARGBSHADEROW_SSE2)
    2292           0 :   if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 4)) {
    2293           0 :     ARGBShadeRow = ARGBShadeRow_SSE2;
    2294             :   }
    2295             : #endif
    2296             : #if defined(HAS_ARGBSHADEROW_NEON)
    2297             :   if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
    2298             :     ARGBShadeRow = ARGBShadeRow_NEON;
    2299             :   }
    2300             : #endif
    2301             : #if defined(HAS_ARGBSHADEROW_MSA)
    2302             :   if (TestCpuFlag(kCpuHasMSA) && IS_ALIGNED(width, 4)) {
    2303             :     ARGBShadeRow = ARGBShadeRow_MSA;
    2304             :   }
    2305             : #endif
    2306             : 
    2307           0 :   for (y = 0; y < height; ++y) {
    2308           0 :     ARGBShadeRow(src_argb, dst_argb, width, value);
    2309           0 :     src_argb += src_stride_argb;
    2310           0 :     dst_argb += dst_stride_argb;
    2311             :   }
    2312           0 :   return 0;
    2313             : }
    2314             : 
    2315             : // Interpolate 2 planes by specified amount (0 to 255).
    2316             : LIBYUV_API
    2317           0 : int InterpolatePlane(const uint8* src0,
    2318             :                      int src_stride0,
    2319             :                      const uint8* src1,
    2320             :                      int src_stride1,
    2321             :                      uint8* dst,
    2322             :                      int dst_stride,
    2323             :                      int width,
    2324             :                      int height,
    2325             :                      int interpolation) {
    2326             :   int y;
    2327             :   void (*InterpolateRow)(uint8 * dst_ptr, const uint8* src_ptr,
    2328             :                          ptrdiff_t src_stride, int dst_width,
    2329           0 :                          int source_y_fraction) = InterpolateRow_C;
    2330           0 :   if (!src0 || !src1 || !dst || width <= 0 || height == 0) {
    2331           0 :     return -1;
    2332             :   }
    2333             :   // Negative height means invert the image.
    2334           0 :   if (height < 0) {
    2335           0 :     height = -height;
    2336           0 :     dst = dst + (height - 1) * dst_stride;
    2337           0 :     dst_stride = -dst_stride;
    2338             :   }
    2339             :   // Coalesce rows.
    2340           0 :   if (src_stride0 == width && src_stride1 == width && dst_stride == width) {
    2341           0 :     width *= height;
    2342           0 :     height = 1;
    2343           0 :     src_stride0 = src_stride1 = dst_stride = 0;
    2344             :   }
    2345             : #if defined(HAS_INTERPOLATEROW_SSSE3)
    2346           0 :   if (TestCpuFlag(kCpuHasSSSE3)) {
    2347           0 :     InterpolateRow = InterpolateRow_Any_SSSE3;
    2348           0 :     if (IS_ALIGNED(width, 16)) {
    2349           0 :       InterpolateRow = InterpolateRow_SSSE3;
    2350             :     }
    2351             :   }
    2352             : #endif
    2353             : #if defined(HAS_INTERPOLATEROW_AVX2)
    2354           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
    2355           0 :     InterpolateRow = InterpolateRow_Any_AVX2;
    2356           0 :     if (IS_ALIGNED(width, 32)) {
    2357           0 :       InterpolateRow = InterpolateRow_AVX2;
    2358             :     }
    2359             :   }
    2360             : #endif
    2361             : #if defined(HAS_INTERPOLATEROW_NEON)
    2362             :   if (TestCpuFlag(kCpuHasNEON)) {
    2363             :     InterpolateRow = InterpolateRow_Any_NEON;
    2364             :     if (IS_ALIGNED(width, 16)) {
    2365             :       InterpolateRow = InterpolateRow_NEON;
    2366             :     }
    2367             :   }
    2368             : #endif
    2369             : #if defined(HAS_INTERPOLATEROW_DSPR2)
    2370             :   if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(src0, 4) &&
    2371             :       IS_ALIGNED(src_stride0, 4) && IS_ALIGNED(src1, 4) &&
    2372             :       IS_ALIGNED(src_stride1, 4) && IS_ALIGNED(dst, 4) &&
    2373             :       IS_ALIGNED(dst_stride, 4) && IS_ALIGNED(width, 4)) {
    2374             :     InterpolateRow = InterpolateRow_DSPR2;
    2375             :   }
    2376             : #endif
    2377             : 
    2378           0 :   for (y = 0; y < height; ++y) {
    2379           0 :     InterpolateRow(dst, src0, src1 - src0, width, interpolation);
    2380           0 :     src0 += src_stride0;
    2381           0 :     src1 += src_stride1;
    2382           0 :     dst += dst_stride;
    2383             :   }
    2384           0 :   return 0;
    2385             : }
    2386             : 
    2387             : // Interpolate 2 ARGB images by specified amount (0 to 255).
    2388             : LIBYUV_API
    2389           0 : int ARGBInterpolate(const uint8* src_argb0,
    2390             :                     int src_stride_argb0,
    2391             :                     const uint8* src_argb1,
    2392             :                     int src_stride_argb1,
    2393             :                     uint8* dst_argb,
    2394             :                     int dst_stride_argb,
    2395             :                     int width,
    2396             :                     int height,
    2397             :                     int interpolation) {
    2398           0 :   return InterpolatePlane(src_argb0, src_stride_argb0, src_argb1,
    2399             :                           src_stride_argb1, dst_argb, dst_stride_argb,
    2400           0 :                           width * 4, height, interpolation);
    2401             : }
    2402             : 
    2403             : // Interpolate 2 YUV images by specified amount (0 to 255).
    2404             : LIBYUV_API
    2405           0 : int I420Interpolate(const uint8* src0_y,
    2406             :                     int src0_stride_y,
    2407             :                     const uint8* src0_u,
    2408             :                     int src0_stride_u,
    2409             :                     const uint8* src0_v,
    2410             :                     int src0_stride_v,
    2411             :                     const uint8* src1_y,
    2412             :                     int src1_stride_y,
    2413             :                     const uint8* src1_u,
    2414             :                     int src1_stride_u,
    2415             :                     const uint8* src1_v,
    2416             :                     int src1_stride_v,
    2417             :                     uint8* dst_y,
    2418             :                     int dst_stride_y,
    2419             :                     uint8* dst_u,
    2420             :                     int dst_stride_u,
    2421             :                     uint8* dst_v,
    2422             :                     int dst_stride_v,
    2423             :                     int width,
    2424             :                     int height,
    2425             :                     int interpolation) {
    2426           0 :   int halfwidth = (width + 1) >> 1;
    2427           0 :   int halfheight = (height + 1) >> 1;
    2428           0 :   if (!src0_y || !src0_u || !src0_v || !src1_y || !src1_u || !src1_v ||
    2429           0 :       !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
    2430           0 :     return -1;
    2431             :   }
    2432             :   InterpolatePlane(src0_y, src0_stride_y, src1_y, src1_stride_y, dst_y,
    2433           0 :                    dst_stride_y, width, height, interpolation);
    2434             :   InterpolatePlane(src0_u, src0_stride_u, src1_u, src1_stride_u, dst_u,
    2435           0 :                    dst_stride_u, halfwidth, halfheight, interpolation);
    2436             :   InterpolatePlane(src0_v, src0_stride_v, src1_v, src1_stride_v, dst_v,
    2437           0 :                    dst_stride_v, halfwidth, halfheight, interpolation);
    2438           0 :   return 0;
    2439             : }
    2440             : 
    2441             : // Shuffle ARGB channel order.  e.g. BGRA to ARGB.
    2442             : LIBYUV_API
    2443           0 : int ARGBShuffle(const uint8* src_bgra,
    2444             :                 int src_stride_bgra,
    2445             :                 uint8* dst_argb,
    2446             :                 int dst_stride_argb,
    2447             :                 const uint8* shuffler,
    2448             :                 int width,
    2449             :                 int height) {
    2450             :   int y;
    2451             :   void (*ARGBShuffleRow)(const uint8* src_bgra, uint8* dst_argb,
    2452           0 :                          const uint8* shuffler, int width) = ARGBShuffleRow_C;
    2453           0 :   if (!src_bgra || !dst_argb || width <= 0 || height == 0) {
    2454           0 :     return -1;
    2455             :   }
    2456             :   // Negative height means invert the image.
    2457           0 :   if (height < 0) {
    2458           0 :     height = -height;
    2459           0 :     src_bgra = src_bgra + (height - 1) * src_stride_bgra;
    2460           0 :     src_stride_bgra = -src_stride_bgra;
    2461             :   }
    2462             :   // Coalesce rows.
    2463           0 :   if (src_stride_bgra == width * 4 && dst_stride_argb == width * 4) {
    2464           0 :     width *= height;
    2465           0 :     height = 1;
    2466           0 :     src_stride_bgra = dst_stride_argb = 0;
    2467             :   }
    2468             : #if defined(HAS_ARGBSHUFFLEROW_SSE2)
    2469           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
    2470           0 :     ARGBShuffleRow = ARGBShuffleRow_Any_SSE2;
    2471           0 :     if (IS_ALIGNED(width, 4)) {
    2472           0 :       ARGBShuffleRow = ARGBShuffleRow_SSE2;
    2473             :     }
    2474             :   }
    2475             : #endif
    2476             : #if defined(HAS_ARGBSHUFFLEROW_SSSE3)
    2477           0 :   if (TestCpuFlag(kCpuHasSSSE3)) {
    2478           0 :     ARGBShuffleRow = ARGBShuffleRow_Any_SSSE3;
    2479           0 :     if (IS_ALIGNED(width, 8)) {
    2480           0 :       ARGBShuffleRow = ARGBShuffleRow_SSSE3;
    2481             :     }
    2482             :   }
    2483             : #endif
    2484             : #if defined(HAS_ARGBSHUFFLEROW_AVX2)
    2485           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
    2486           0 :     ARGBShuffleRow = ARGBShuffleRow_Any_AVX2;
    2487           0 :     if (IS_ALIGNED(width, 16)) {
    2488           0 :       ARGBShuffleRow = ARGBShuffleRow_AVX2;
    2489             :     }
    2490             :   }
    2491             : #endif
    2492             : #if defined(HAS_ARGBSHUFFLEROW_NEON)
    2493             :   if (TestCpuFlag(kCpuHasNEON)) {
    2494             :     ARGBShuffleRow = ARGBShuffleRow_Any_NEON;
    2495             :     if (IS_ALIGNED(width, 4)) {
    2496             :       ARGBShuffleRow = ARGBShuffleRow_NEON;
    2497             :     }
    2498             :   }
    2499             : #endif
    2500             : #if defined(HAS_ARGBSHUFFLEROW_MSA)
    2501             :   if (TestCpuFlag(kCpuHasMSA)) {
    2502             :     ARGBShuffleRow = ARGBShuffleRow_Any_MSA;
    2503             :     if (IS_ALIGNED(width, 8)) {
    2504             :       ARGBShuffleRow = ARGBShuffleRow_MSA;
    2505             :     }
    2506             :   }
    2507             : #endif
    2508             : 
    2509           0 :   for (y = 0; y < height; ++y) {
    2510           0 :     ARGBShuffleRow(src_bgra, dst_argb, shuffler, width);
    2511           0 :     src_bgra += src_stride_bgra;
    2512           0 :     dst_argb += dst_stride_argb;
    2513             :   }
    2514           0 :   return 0;
    2515             : }
    2516             : 
    2517             : // Sobel ARGB effect.
    2518           0 : static int ARGBSobelize(const uint8* src_argb,
    2519             :                         int src_stride_argb,
    2520             :                         uint8* dst_argb,
    2521             :                         int dst_stride_argb,
    2522             :                         int width,
    2523             :                         int height,
    2524             :                         void (*SobelRow)(const uint8* src_sobelx,
    2525             :                                          const uint8* src_sobely,
    2526             :                                          uint8* dst,
    2527             :                                          int width)) {
    2528             :   int y;
    2529             :   void (*ARGBToYJRow)(const uint8* src_argb, uint8* dst_g, int width) =
    2530           0 :       ARGBToYJRow_C;
    2531             :   void (*SobelYRow)(const uint8* src_y0, const uint8* src_y1, uint8* dst_sobely,
    2532           0 :                     int width) = SobelYRow_C;
    2533             :   void (*SobelXRow)(const uint8* src_y0, const uint8* src_y1,
    2534             :                     const uint8* src_y2, uint8* dst_sobely, int width) =
    2535           0 :       SobelXRow_C;
    2536           0 :   const int kEdge = 16;  // Extra pixels at start of row for extrude/align.
    2537           0 :   if (!src_argb || !dst_argb || width <= 0 || height == 0) {
    2538           0 :     return -1;
    2539             :   }
    2540             :   // Negative height means invert the image.
    2541           0 :   if (height < 0) {
    2542           0 :     height = -height;
    2543           0 :     src_argb = src_argb + (height - 1) * src_stride_argb;
    2544           0 :     src_stride_argb = -src_stride_argb;
    2545             :   }
    2546             : 
    2547             : #if defined(HAS_ARGBTOYJROW_SSSE3)
    2548           0 :   if (TestCpuFlag(kCpuHasSSSE3)) {
    2549           0 :     ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
    2550           0 :     if (IS_ALIGNED(width, 16)) {
    2551           0 :       ARGBToYJRow = ARGBToYJRow_SSSE3;
    2552             :     }
    2553             :   }
    2554             : #endif
    2555             : #if defined(HAS_ARGBTOYJROW_AVX2)
    2556           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
    2557           0 :     ARGBToYJRow = ARGBToYJRow_Any_AVX2;
    2558           0 :     if (IS_ALIGNED(width, 32)) {
    2559           0 :       ARGBToYJRow = ARGBToYJRow_AVX2;
    2560             :     }
    2561             :   }
    2562             : #endif
    2563             : #if defined(HAS_ARGBTOYJROW_NEON)
    2564             :   if (TestCpuFlag(kCpuHasNEON)) {
    2565             :     ARGBToYJRow = ARGBToYJRow_Any_NEON;
    2566             :     if (IS_ALIGNED(width, 8)) {
    2567             :       ARGBToYJRow = ARGBToYJRow_NEON;
    2568             :     }
    2569             :   }
    2570             : #endif
    2571             : #if defined(HAS_ARGBTOYJROW_MSA)
    2572             :   if (TestCpuFlag(kCpuHasMSA)) {
    2573             :     ARGBToYJRow = ARGBToYJRow_Any_MSA;
    2574             :     if (IS_ALIGNED(width, 16)) {
    2575             :       ARGBToYJRow = ARGBToYJRow_MSA;
    2576             :     }
    2577             :   }
    2578             : #endif
    2579             : 
    2580             : #if defined(HAS_SOBELYROW_SSE2)
    2581           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
    2582           0 :     SobelYRow = SobelYRow_SSE2;
    2583             :   }
    2584             : #endif
    2585             : #if defined(HAS_SOBELYROW_NEON)
    2586             :   if (TestCpuFlag(kCpuHasNEON)) {
    2587             :     SobelYRow = SobelYRow_NEON;
    2588             :   }
    2589             : #endif
    2590             : #if defined(HAS_SOBELXROW_SSE2)
    2591           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
    2592           0 :     SobelXRow = SobelXRow_SSE2;
    2593             :   }
    2594             : #endif
    2595             : #if defined(HAS_SOBELXROW_NEON)
    2596             :   if (TestCpuFlag(kCpuHasNEON)) {
    2597             :     SobelXRow = SobelXRow_NEON;
    2598             :   }
    2599             : #endif
    2600             :   {
    2601             :     // 3 rows with edges before/after.
    2602           0 :     const int kRowSize = (width + kEdge + 31) & ~31;
    2603           0 :     align_buffer_64(rows, kRowSize * 2 + (kEdge + kRowSize * 3 + kEdge));
    2604           0 :     uint8* row_sobelx = rows;
    2605           0 :     uint8* row_sobely = rows + kRowSize;
    2606           0 :     uint8* row_y = rows + kRowSize * 2;
    2607             : 
    2608             :     // Convert first row.
    2609           0 :     uint8* row_y0 = row_y + kEdge;
    2610           0 :     uint8* row_y1 = row_y0 + kRowSize;
    2611           0 :     uint8* row_y2 = row_y1 + kRowSize;
    2612           0 :     ARGBToYJRow(src_argb, row_y0, width);
    2613           0 :     row_y0[-1] = row_y0[0];
    2614           0 :     memset(row_y0 + width, row_y0[width - 1], 16);  // Extrude 16 for valgrind.
    2615           0 :     ARGBToYJRow(src_argb, row_y1, width);
    2616           0 :     row_y1[-1] = row_y1[0];
    2617           0 :     memset(row_y1 + width, row_y1[width - 1], 16);
    2618           0 :     memset(row_y2 + width, 0, 16);
    2619             : 
    2620           0 :     for (y = 0; y < height; ++y) {
    2621             :       // Convert next row of ARGB to G.
    2622           0 :       if (y < (height - 1)) {
    2623           0 :         src_argb += src_stride_argb;
    2624             :       }
    2625           0 :       ARGBToYJRow(src_argb, row_y2, width);
    2626           0 :       row_y2[-1] = row_y2[0];
    2627           0 :       row_y2[width] = row_y2[width - 1];
    2628             : 
    2629           0 :       SobelXRow(row_y0 - 1, row_y1 - 1, row_y2 - 1, row_sobelx, width);
    2630           0 :       SobelYRow(row_y0 - 1, row_y2 - 1, row_sobely, width);
    2631           0 :       SobelRow(row_sobelx, row_sobely, dst_argb, width);
    2632             : 
    2633             :       // Cycle thru circular queue of 3 row_y buffers.
    2634             :       {
    2635           0 :         uint8* row_yt = row_y0;
    2636           0 :         row_y0 = row_y1;
    2637           0 :         row_y1 = row_y2;
    2638           0 :         row_y2 = row_yt;
    2639             :       }
    2640             : 
    2641           0 :       dst_argb += dst_stride_argb;
    2642             :     }
    2643           0 :     free_aligned_buffer_64(rows);
    2644             :   }
    2645           0 :   return 0;
    2646             : }
    2647             : 
    2648             : // Sobel ARGB effect.
    2649             : LIBYUV_API
    2650           0 : int ARGBSobel(const uint8* src_argb,
    2651             :               int src_stride_argb,
    2652             :               uint8* dst_argb,
    2653             :               int dst_stride_argb,
    2654             :               int width,
    2655             :               int height) {
    2656             :   void (*SobelRow)(const uint8* src_sobelx, const uint8* src_sobely,
    2657           0 :                    uint8* dst_argb, int width) = SobelRow_C;
    2658             : #if defined(HAS_SOBELROW_SSE2)
    2659           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
    2660           0 :     SobelRow = SobelRow_Any_SSE2;
    2661           0 :     if (IS_ALIGNED(width, 16)) {
    2662           0 :       SobelRow = SobelRow_SSE2;
    2663             :     }
    2664             :   }
    2665             : #endif
    2666             : #if defined(HAS_SOBELROW_NEON)
    2667             :   if (TestCpuFlag(kCpuHasNEON)) {
    2668             :     SobelRow = SobelRow_Any_NEON;
    2669             :     if (IS_ALIGNED(width, 8)) {
    2670             :       SobelRow = SobelRow_NEON;
    2671             :     }
    2672             :   }
    2673             : #endif
    2674             : #if defined(HAS_SOBELROW_MSA)
    2675             :   if (TestCpuFlag(kCpuHasMSA)) {
    2676             :     SobelRow = SobelRow_Any_MSA;
    2677             :     if (IS_ALIGNED(width, 16)) {
    2678             :       SobelRow = SobelRow_MSA;
    2679             :     }
    2680             :   }
    2681             : #endif
    2682             :   return ARGBSobelize(src_argb, src_stride_argb, dst_argb, dst_stride_argb,
    2683           0 :                       width, height, SobelRow);
    2684             : }
    2685             : 
    2686             : // Sobel ARGB effect with planar output.
    2687             : LIBYUV_API
    2688           0 : int ARGBSobelToPlane(const uint8* src_argb,
    2689             :                      int src_stride_argb,
    2690             :                      uint8* dst_y,
    2691             :                      int dst_stride_y,
    2692             :                      int width,
    2693             :                      int height) {
    2694             :   void (*SobelToPlaneRow)(const uint8* src_sobelx, const uint8* src_sobely,
    2695           0 :                           uint8* dst_, int width) = SobelToPlaneRow_C;
    2696             : #if defined(HAS_SOBELTOPLANEROW_SSE2)
    2697           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
    2698           0 :     SobelToPlaneRow = SobelToPlaneRow_Any_SSE2;
    2699           0 :     if (IS_ALIGNED(width, 16)) {
    2700           0 :       SobelToPlaneRow = SobelToPlaneRow_SSE2;
    2701             :     }
    2702             :   }
    2703             : #endif
    2704             : #if defined(HAS_SOBELTOPLANEROW_NEON)
    2705             :   if (TestCpuFlag(kCpuHasNEON)) {
    2706             :     SobelToPlaneRow = SobelToPlaneRow_Any_NEON;
    2707             :     if (IS_ALIGNED(width, 16)) {
    2708             :       SobelToPlaneRow = SobelToPlaneRow_NEON;
    2709             :     }
    2710             :   }
    2711             : #endif
    2712             : #if defined(HAS_SOBELTOPLANEROW_MSA)
    2713             :   if (TestCpuFlag(kCpuHasMSA)) {
    2714             :     SobelToPlaneRow = SobelToPlaneRow_Any_MSA;
    2715             :     if (IS_ALIGNED(width, 32)) {
    2716             :       SobelToPlaneRow = SobelToPlaneRow_MSA;
    2717             :     }
    2718             :   }
    2719             : #endif
    2720             :   return ARGBSobelize(src_argb, src_stride_argb, dst_y, dst_stride_y, width,
    2721           0 :                       height, SobelToPlaneRow);
    2722             : }
    2723             : 
    2724             : // SobelXY ARGB effect.
    2725             : // Similar to Sobel, but also stores Sobel X in R and Sobel Y in B.  G = Sobel.
    2726             : LIBYUV_API
    2727           0 : int ARGBSobelXY(const uint8* src_argb,
    2728             :                 int src_stride_argb,
    2729             :                 uint8* dst_argb,
    2730             :                 int dst_stride_argb,
    2731             :                 int width,
    2732             :                 int height) {
    2733             :   void (*SobelXYRow)(const uint8* src_sobelx, const uint8* src_sobely,
    2734           0 :                      uint8* dst_argb, int width) = SobelXYRow_C;
    2735             : #if defined(HAS_SOBELXYROW_SSE2)
    2736           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
    2737           0 :     SobelXYRow = SobelXYRow_Any_SSE2;
    2738           0 :     if (IS_ALIGNED(width, 16)) {
    2739           0 :       SobelXYRow = SobelXYRow_SSE2;
    2740             :     }
    2741             :   }
    2742             : #endif
    2743             : #if defined(HAS_SOBELXYROW_NEON)
    2744             :   if (TestCpuFlag(kCpuHasNEON)) {
    2745             :     SobelXYRow = SobelXYRow_Any_NEON;
    2746             :     if (IS_ALIGNED(width, 8)) {
    2747             :       SobelXYRow = SobelXYRow_NEON;
    2748             :     }
    2749             :   }
    2750             : #endif
    2751             : #if defined(HAS_SOBELXYROW_MSA)
    2752             :   if (TestCpuFlag(kCpuHasMSA)) {
    2753             :     SobelXYRow = SobelXYRow_Any_MSA;
    2754             :     if (IS_ALIGNED(width, 16)) {
    2755             :       SobelXYRow = SobelXYRow_MSA;
    2756             :     }
    2757             :   }
    2758             : #endif
    2759             :   return ARGBSobelize(src_argb, src_stride_argb, dst_argb, dst_stride_argb,
    2760           0 :                       width, height, SobelXYRow);
    2761             : }
    2762             : 
    2763             : // Apply a 4x4 polynomial to each ARGB pixel.
    2764             : LIBYUV_API
    2765           0 : int ARGBPolynomial(const uint8* src_argb,
    2766             :                    int src_stride_argb,
    2767             :                    uint8* dst_argb,
    2768             :                    int dst_stride_argb,
    2769             :                    const float* poly,
    2770             :                    int width,
    2771             :                    int height) {
    2772             :   int y;
    2773             :   void (*ARGBPolynomialRow)(const uint8* src_argb, uint8* dst_argb,
    2774           0 :                             const float* poly, int width) = ARGBPolynomialRow_C;
    2775           0 :   if (!src_argb || !dst_argb || !poly || width <= 0 || height == 0) {
    2776           0 :     return -1;
    2777             :   }
    2778             :   // Negative height means invert the image.
    2779           0 :   if (height < 0) {
    2780           0 :     height = -height;
    2781           0 :     src_argb = src_argb + (height - 1) * src_stride_argb;
    2782           0 :     src_stride_argb = -src_stride_argb;
    2783             :   }
    2784             :   // Coalesce rows.
    2785           0 :   if (src_stride_argb == width * 4 && dst_stride_argb == width * 4) {
    2786           0 :     width *= height;
    2787           0 :     height = 1;
    2788           0 :     src_stride_argb = dst_stride_argb = 0;
    2789             :   }
    2790             : #if defined(HAS_ARGBPOLYNOMIALROW_SSE2)
    2791           0 :   if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 2)) {
    2792           0 :     ARGBPolynomialRow = ARGBPolynomialRow_SSE2;
    2793             :   }
    2794             : #endif
    2795             : #if defined(HAS_ARGBPOLYNOMIALROW_AVX2)
    2796           0 :   if (TestCpuFlag(kCpuHasAVX2) && TestCpuFlag(kCpuHasFMA3) &&
    2797           0 :       IS_ALIGNED(width, 2)) {
    2798           0 :     ARGBPolynomialRow = ARGBPolynomialRow_AVX2;
    2799             :   }
    2800             : #endif
    2801             : 
    2802           0 :   for (y = 0; y < height; ++y) {
    2803           0 :     ARGBPolynomialRow(src_argb, dst_argb, poly, width);
    2804           0 :     src_argb += src_stride_argb;
    2805           0 :     dst_argb += dst_stride_argb;
    2806             :   }
    2807           0 :   return 0;
    2808             : }
    2809             : 
    2810             : // Convert plane of 16 bit shorts to half floats.
    2811             : // Source values are multiplied by scale before storing as half float.
    2812             : LIBYUV_API
    2813           0 : int HalfFloatPlane(const uint16* src_y,
    2814             :                    int src_stride_y,
    2815             :                    uint16* dst_y,
    2816             :                    int dst_stride_y,
    2817             :                    float scale,
    2818             :                    int width,
    2819             :                    int height) {
    2820             :   int y;
    2821             :   void (*HalfFloatRow)(const uint16* src, uint16* dst, float scale, int width) =
    2822           0 :       HalfFloatRow_C;
    2823           0 :   if (!src_y || !dst_y || width <= 0 || height == 0) {
    2824           0 :     return -1;
    2825             :   }
    2826           0 :   src_stride_y >>= 1;
    2827           0 :   dst_stride_y >>= 1;
    2828             :   // Negative height means invert the image.
    2829           0 :   if (height < 0) {
    2830           0 :     height = -height;
    2831           0 :     src_y = src_y + (height - 1) * src_stride_y;
    2832           0 :     src_stride_y = -src_stride_y;
    2833             :   }
    2834             :   // Coalesce rows.
    2835           0 :   if (src_stride_y == width && dst_stride_y == width) {
    2836           0 :     width *= height;
    2837           0 :     height = 1;
    2838           0 :     src_stride_y = dst_stride_y = 0;
    2839             :   }
    2840             : #if defined(HAS_HALFFLOATROW_SSE2)
    2841           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
    2842           0 :     HalfFloatRow = HalfFloatRow_Any_SSE2;
    2843           0 :     if (IS_ALIGNED(width, 8)) {
    2844           0 :       HalfFloatRow = HalfFloatRow_SSE2;
    2845             :     }
    2846             :   }
    2847             : #endif
    2848             : #if defined(HAS_HALFFLOATROW_AVX2)
    2849           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
    2850           0 :     HalfFloatRow = HalfFloatRow_Any_AVX2;
    2851           0 :     if (IS_ALIGNED(width, 16)) {
    2852           0 :       HalfFloatRow = HalfFloatRow_AVX2;
    2853             :     }
    2854             :   }
    2855             : #endif
    2856             : #if defined(HAS_HALFFLOATROW_F16C)
    2857             :   if (TestCpuFlag(kCpuHasAVX2) && TestCpuFlag(kCpuHasF16C)) {
    2858             :     HalfFloatRow =
    2859             :         (scale == 1.0f) ? HalfFloat1Row_Any_F16C : HalfFloatRow_Any_F16C;
    2860             :     if (IS_ALIGNED(width, 16)) {
    2861             :       HalfFloatRow = (scale == 1.0f) ? HalfFloat1Row_F16C : HalfFloatRow_F16C;
    2862             :     }
    2863             :   }
    2864             : #endif
    2865             : #if defined(HAS_HALFFLOATROW_NEON)
    2866             :   if (TestCpuFlag(kCpuHasNEON)) {
    2867             :     HalfFloatRow =
    2868             :         (scale == 1.0f) ? HalfFloat1Row_Any_NEON : HalfFloatRow_Any_NEON;
    2869             :     if (IS_ALIGNED(width, 8)) {
    2870             :       HalfFloatRow = (scale == 1.0f) ? HalfFloat1Row_NEON : HalfFloatRow_NEON;
    2871             :     }
    2872             :   }
    2873             : #endif
    2874             : 
    2875           0 :   for (y = 0; y < height; ++y) {
    2876           0 :     HalfFloatRow(src_y, dst_y, scale, width);
    2877           0 :     src_y += src_stride_y;
    2878           0 :     dst_y += dst_stride_y;
    2879             :   }
    2880           0 :   return 0;
    2881             : }
    2882             : 
    2883             : // Apply a lumacolortable to each ARGB pixel.
    2884             : LIBYUV_API
    2885           0 : int ARGBLumaColorTable(const uint8* src_argb,
    2886             :                        int src_stride_argb,
    2887             :                        uint8* dst_argb,
    2888             :                        int dst_stride_argb,
    2889             :                        const uint8* luma,
    2890             :                        int width,
    2891             :                        int height) {
    2892             :   int y;
    2893             :   void (*ARGBLumaColorTableRow)(
    2894             :       const uint8* src_argb, uint8* dst_argb, int width, const uint8* luma,
    2895           0 :       const uint32 lumacoeff) = ARGBLumaColorTableRow_C;
    2896           0 :   if (!src_argb || !dst_argb || !luma || width <= 0 || height == 0) {
    2897           0 :     return -1;
    2898             :   }
    2899             :   // Negative height means invert the image.
    2900           0 :   if (height < 0) {
    2901           0 :     height = -height;
    2902           0 :     src_argb = src_argb + (height - 1) * src_stride_argb;
    2903           0 :     src_stride_argb = -src_stride_argb;
    2904             :   }
    2905             :   // Coalesce rows.
    2906           0 :   if (src_stride_argb == width * 4 && dst_stride_argb == width * 4) {
    2907           0 :     width *= height;
    2908           0 :     height = 1;
    2909           0 :     src_stride_argb = dst_stride_argb = 0;
    2910             :   }
    2911             : #if defined(HAS_ARGBLUMACOLORTABLEROW_SSSE3)
    2912           0 :   if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 4)) {
    2913           0 :     ARGBLumaColorTableRow = ARGBLumaColorTableRow_SSSE3;
    2914             :   }
    2915             : #endif
    2916             : 
    2917           0 :   for (y = 0; y < height; ++y) {
    2918           0 :     ARGBLumaColorTableRow(src_argb, dst_argb, width, luma, 0x00264b0f);
    2919           0 :     src_argb += src_stride_argb;
    2920           0 :     dst_argb += dst_stride_argb;
    2921             :   }
    2922           0 :   return 0;
    2923             : }
    2924             : 
    2925             : // Copy Alpha from one ARGB image to another.
    2926             : LIBYUV_API
    2927           0 : int ARGBCopyAlpha(const uint8* src_argb,
    2928             :                   int src_stride_argb,
    2929             :                   uint8* dst_argb,
    2930             :                   int dst_stride_argb,
    2931             :                   int width,
    2932             :                   int height) {
    2933             :   int y;
    2934             :   void (*ARGBCopyAlphaRow)(const uint8* src_argb, uint8* dst_argb, int width) =
    2935           0 :       ARGBCopyAlphaRow_C;
    2936           0 :   if (!src_argb || !dst_argb || width <= 0 || height == 0) {
    2937           0 :     return -1;
    2938             :   }
    2939             :   // Negative height means invert the image.
    2940           0 :   if (height < 0) {
    2941           0 :     height = -height;
    2942           0 :     src_argb = src_argb + (height - 1) * src_stride_argb;
    2943           0 :     src_stride_argb = -src_stride_argb;
    2944             :   }
    2945             :   // Coalesce rows.
    2946           0 :   if (src_stride_argb == width * 4 && dst_stride_argb == width * 4) {
    2947           0 :     width *= height;
    2948           0 :     height = 1;
    2949           0 :     src_stride_argb = dst_stride_argb = 0;
    2950             :   }
    2951             : #if defined(HAS_ARGBCOPYALPHAROW_SSE2)
    2952           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
    2953           0 :     ARGBCopyAlphaRow = ARGBCopyAlphaRow_Any_SSE2;
    2954           0 :     if (IS_ALIGNED(width, 8)) {
    2955           0 :       ARGBCopyAlphaRow = ARGBCopyAlphaRow_SSE2;
    2956             :     }
    2957             :   }
    2958             : #endif
    2959             : #if defined(HAS_ARGBCOPYALPHAROW_AVX2)
    2960           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
    2961           0 :     ARGBCopyAlphaRow = ARGBCopyAlphaRow_Any_AVX2;
    2962           0 :     if (IS_ALIGNED(width, 16)) {
    2963           0 :       ARGBCopyAlphaRow = ARGBCopyAlphaRow_AVX2;
    2964             :     }
    2965             :   }
    2966             : #endif
    2967             : 
    2968           0 :   for (y = 0; y < height; ++y) {
    2969           0 :     ARGBCopyAlphaRow(src_argb, dst_argb, width);
    2970           0 :     src_argb += src_stride_argb;
    2971           0 :     dst_argb += dst_stride_argb;
    2972             :   }
    2973           0 :   return 0;
    2974             : }
    2975             : 
    2976             : // Extract just the alpha channel from ARGB.
    2977             : LIBYUV_API
    2978           0 : int ARGBExtractAlpha(const uint8* src_argb,
    2979             :                      int src_stride,
    2980             :                      uint8* dst_a,
    2981             :                      int dst_stride,
    2982             :                      int width,
    2983             :                      int height) {
    2984           0 :   if (!src_argb || !dst_a || width <= 0 || height == 0) {
    2985           0 :     return -1;
    2986             :   }
    2987             :   // Negative height means invert the image.
    2988           0 :   if (height < 0) {
    2989           0 :     height = -height;
    2990           0 :     src_argb += (height - 1) * src_stride;
    2991           0 :     src_stride = -src_stride;
    2992             :   }
    2993             :   // Coalesce rows.
    2994           0 :   if (src_stride == width * 4 && dst_stride == width) {
    2995           0 :     width *= height;
    2996           0 :     height = 1;
    2997           0 :     src_stride = dst_stride = 0;
    2998             :   }
    2999             :   void (*ARGBExtractAlphaRow)(const uint8* src_argb, uint8* dst_a, int width) =
    3000           0 :       ARGBExtractAlphaRow_C;
    3001             : #if defined(HAS_ARGBEXTRACTALPHAROW_SSE2)
    3002           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
    3003           0 :     ARGBExtractAlphaRow = IS_ALIGNED(width, 8) ? ARGBExtractAlphaRow_SSE2
    3004             :                                                : ARGBExtractAlphaRow_Any_SSE2;
    3005             :   }
    3006             : #endif
    3007             : #if defined(HAS_ARGBEXTRACTALPHAROW_AVX2)
    3008           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
    3009           0 :     ARGBExtractAlphaRow = IS_ALIGNED(width, 32) ? ARGBExtractAlphaRow_AVX2
    3010             :                                                 : ARGBExtractAlphaRow_Any_AVX2;
    3011             :   }
    3012             : #endif
    3013             : #if defined(HAS_ARGBEXTRACTALPHAROW_NEON)
    3014             :   if (TestCpuFlag(kCpuHasNEON)) {
    3015             :     ARGBExtractAlphaRow = IS_ALIGNED(width, 16) ? ARGBExtractAlphaRow_NEON
    3016             :                                                 : ARGBExtractAlphaRow_Any_NEON;
    3017             :   }
    3018             : #endif
    3019             : 
    3020           0 :   for (int y = 0; y < height; ++y) {
    3021           0 :     ARGBExtractAlphaRow(src_argb, dst_a, width);
    3022           0 :     src_argb += src_stride;
    3023           0 :     dst_a += dst_stride;
    3024             :   }
    3025           0 :   return 0;
    3026             : }
    3027             : 
    3028             : // Copy a planar Y channel to the alpha channel of a destination ARGB image.
    3029             : LIBYUV_API
    3030           0 : int ARGBCopyYToAlpha(const uint8* src_y,
    3031             :                      int src_stride_y,
    3032             :                      uint8* dst_argb,
    3033             :                      int dst_stride_argb,
    3034             :                      int width,
    3035             :                      int height) {
    3036             :   int y;
    3037             :   void (*ARGBCopyYToAlphaRow)(const uint8* src_y, uint8* dst_argb, int width) =
    3038           0 :       ARGBCopyYToAlphaRow_C;
    3039           0 :   if (!src_y || !dst_argb || width <= 0 || height == 0) {
    3040           0 :     return -1;
    3041             :   }
    3042             :   // Negative height means invert the image.
    3043           0 :   if (height < 0) {
    3044           0 :     height = -height;
    3045           0 :     src_y = src_y + (height - 1) * src_stride_y;
    3046           0 :     src_stride_y = -src_stride_y;
    3047             :   }
    3048             :   // Coalesce rows.
    3049           0 :   if (src_stride_y == width && dst_stride_argb == width * 4) {
    3050           0 :     width *= height;
    3051           0 :     height = 1;
    3052           0 :     src_stride_y = dst_stride_argb = 0;
    3053             :   }
    3054             : #if defined(HAS_ARGBCOPYYTOALPHAROW_SSE2)
    3055           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
    3056           0 :     ARGBCopyYToAlphaRow = ARGBCopyYToAlphaRow_Any_SSE2;
    3057           0 :     if (IS_ALIGNED(width, 8)) {
    3058           0 :       ARGBCopyYToAlphaRow = ARGBCopyYToAlphaRow_SSE2;
    3059             :     }
    3060             :   }
    3061             : #endif
    3062             : #if defined(HAS_ARGBCOPYYTOALPHAROW_AVX2)
    3063           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
    3064           0 :     ARGBCopyYToAlphaRow = ARGBCopyYToAlphaRow_Any_AVX2;
    3065           0 :     if (IS_ALIGNED(width, 16)) {
    3066           0 :       ARGBCopyYToAlphaRow = ARGBCopyYToAlphaRow_AVX2;
    3067             :     }
    3068             :   }
    3069             : #endif
    3070             : 
    3071           0 :   for (y = 0; y < height; ++y) {
    3072           0 :     ARGBCopyYToAlphaRow(src_y, dst_argb, width);
    3073           0 :     src_y += src_stride_y;
    3074           0 :     dst_argb += dst_stride_argb;
    3075             :   }
    3076           0 :   return 0;
    3077             : }
    3078             : 
    3079             : // TODO(fbarchard): Consider if width is even Y channel can be split
    3080             : // directly. A SplitUVRow_Odd function could copy the remaining chroma.
    3081             : 
    3082             : LIBYUV_API
    3083           0 : int YUY2ToNV12(const uint8* src_yuy2,
    3084             :                int src_stride_yuy2,
    3085             :                uint8* dst_y,
    3086             :                int dst_stride_y,
    3087             :                uint8* dst_uv,
    3088             :                int dst_stride_uv,
    3089             :                int width,
    3090             :                int height) {
    3091             :   int y;
    3092           0 :   int halfwidth = (width + 1) >> 1;
    3093             :   void (*SplitUVRow)(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
    3094           0 :                      int width) = SplitUVRow_C;
    3095             :   void (*InterpolateRow)(uint8 * dst_ptr, const uint8* src_ptr,
    3096             :                          ptrdiff_t src_stride, int dst_width,
    3097           0 :                          int source_y_fraction) = InterpolateRow_C;
    3098           0 :   if (!src_yuy2 || !dst_y || !dst_uv || width <= 0 || height == 0) {
    3099           0 :     return -1;
    3100             :   }
    3101             :   // Negative height means invert the image.
    3102           0 :   if (height < 0) {
    3103           0 :     height = -height;
    3104           0 :     src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
    3105           0 :     src_stride_yuy2 = -src_stride_yuy2;
    3106             :   }
    3107             : #if defined(HAS_SPLITUVROW_SSE2)
    3108           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
    3109           0 :     SplitUVRow = SplitUVRow_Any_SSE2;
    3110           0 :     if (IS_ALIGNED(width, 16)) {
    3111           0 :       SplitUVRow = SplitUVRow_SSE2;
    3112             :     }
    3113             :   }
    3114             : #endif
    3115             : #if defined(HAS_SPLITUVROW_AVX2)
    3116           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
    3117           0 :     SplitUVRow = SplitUVRow_Any_AVX2;
    3118           0 :     if (IS_ALIGNED(width, 32)) {
    3119           0 :       SplitUVRow = SplitUVRow_AVX2;
    3120             :     }
    3121             :   }
    3122             : #endif
    3123             : #if defined(HAS_SPLITUVROW_NEON)
    3124             :   if (TestCpuFlag(kCpuHasNEON)) {
    3125             :     SplitUVRow = SplitUVRow_Any_NEON;
    3126             :     if (IS_ALIGNED(width, 16)) {
    3127             :       SplitUVRow = SplitUVRow_NEON;
    3128             :     }
    3129             :   }
    3130             : #endif
    3131             : #if defined(HAS_INTERPOLATEROW_SSSE3)
    3132           0 :   if (TestCpuFlag(kCpuHasSSSE3)) {
    3133           0 :     InterpolateRow = InterpolateRow_Any_SSSE3;
    3134           0 :     if (IS_ALIGNED(width, 16)) {
    3135           0 :       InterpolateRow = InterpolateRow_SSSE3;
    3136             :     }
    3137             :   }
    3138             : #endif
    3139             : #if defined(HAS_INTERPOLATEROW_AVX2)
    3140           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
    3141           0 :     InterpolateRow = InterpolateRow_Any_AVX2;
    3142           0 :     if (IS_ALIGNED(width, 32)) {
    3143           0 :       InterpolateRow = InterpolateRow_AVX2;
    3144             :     }
    3145             :   }
    3146             : #endif
    3147             : #if defined(HAS_INTERPOLATEROW_NEON)
    3148             :   if (TestCpuFlag(kCpuHasNEON)) {
    3149             :     InterpolateRow = InterpolateRow_Any_NEON;
    3150             :     if (IS_ALIGNED(width, 16)) {
    3151             :       InterpolateRow = InterpolateRow_NEON;
    3152             :     }
    3153             :   }
    3154             : #endif
    3155             : 
    3156             :   {
    3157           0 :     int awidth = halfwidth * 2;
    3158             :     // row of y and 2 rows of uv
    3159           0 :     align_buffer_64(rows, awidth * 3);
    3160             : 
    3161           0 :     for (y = 0; y < height - 1; y += 2) {
    3162             :       // Split Y from UV.
    3163           0 :       SplitUVRow(src_yuy2, rows, rows + awidth, awidth);
    3164           0 :       memcpy(dst_y, rows, width);
    3165           0 :       SplitUVRow(src_yuy2 + src_stride_yuy2, rows, rows + awidth * 2, awidth);
    3166           0 :       memcpy(dst_y + dst_stride_y, rows, width);
    3167           0 :       InterpolateRow(dst_uv, rows + awidth, awidth, awidth, 128);
    3168           0 :       src_yuy2 += src_stride_yuy2 * 2;
    3169           0 :       dst_y += dst_stride_y * 2;
    3170           0 :       dst_uv += dst_stride_uv;
    3171             :     }
    3172           0 :     if (height & 1) {
    3173             :       // Split Y from UV.
    3174           0 :       SplitUVRow(src_yuy2, rows, dst_uv, awidth);
    3175           0 :       memcpy(dst_y, rows, width);
    3176             :     }
    3177           0 :     free_aligned_buffer_64(rows);
    3178             :   }
    3179           0 :   return 0;
    3180             : }
    3181             : 
    3182             : LIBYUV_API
    3183           0 : int UYVYToNV12(const uint8* src_uyvy,
    3184             :                int src_stride_uyvy,
    3185             :                uint8* dst_y,
    3186             :                int dst_stride_y,
    3187             :                uint8* dst_uv,
    3188             :                int dst_stride_uv,
    3189             :                int width,
    3190             :                int height) {
    3191             :   int y;
    3192           0 :   int halfwidth = (width + 1) >> 1;
    3193             :   void (*SplitUVRow)(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
    3194           0 :                      int width) = SplitUVRow_C;
    3195             :   void (*InterpolateRow)(uint8 * dst_ptr, const uint8* src_ptr,
    3196             :                          ptrdiff_t src_stride, int dst_width,
    3197           0 :                          int source_y_fraction) = InterpolateRow_C;
    3198           0 :   if (!src_uyvy || !dst_y || !dst_uv || width <= 0 || height == 0) {
    3199           0 :     return -1;
    3200             :   }
    3201             :   // Negative height means invert the image.
    3202           0 :   if (height < 0) {
    3203           0 :     height = -height;
    3204           0 :     src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
    3205           0 :     src_stride_uyvy = -src_stride_uyvy;
    3206             :   }
    3207             : #if defined(HAS_SPLITUVROW_SSE2)
    3208           0 :   if (TestCpuFlag(kCpuHasSSE2)) {
    3209           0 :     SplitUVRow = SplitUVRow_Any_SSE2;
    3210           0 :     if (IS_ALIGNED(width, 16)) {
    3211           0 :       SplitUVRow = SplitUVRow_SSE2;
    3212             :     }
    3213             :   }
    3214             : #endif
    3215             : #if defined(HAS_SPLITUVROW_AVX2)
    3216           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
    3217           0 :     SplitUVRow = SplitUVRow_Any_AVX2;
    3218           0 :     if (IS_ALIGNED(width, 32)) {
    3219           0 :       SplitUVRow = SplitUVRow_AVX2;
    3220             :     }
    3221             :   }
    3222             : #endif
    3223             : #if defined(HAS_SPLITUVROW_NEON)
    3224             :   if (TestCpuFlag(kCpuHasNEON)) {
    3225             :     SplitUVRow = SplitUVRow_Any_NEON;
    3226             :     if (IS_ALIGNED(width, 16)) {
    3227             :       SplitUVRow = SplitUVRow_NEON;
    3228             :     }
    3229             :   }
    3230             : #endif
    3231             : #if defined(HAS_INTERPOLATEROW_SSSE3)
    3232           0 :   if (TestCpuFlag(kCpuHasSSSE3)) {
    3233           0 :     InterpolateRow = InterpolateRow_Any_SSSE3;
    3234           0 :     if (IS_ALIGNED(width, 16)) {
    3235           0 :       InterpolateRow = InterpolateRow_SSSE3;
    3236             :     }
    3237             :   }
    3238             : #endif
    3239             : #if defined(HAS_INTERPOLATEROW_AVX2)
    3240           0 :   if (TestCpuFlag(kCpuHasAVX2)) {
    3241           0 :     InterpolateRow = InterpolateRow_Any_AVX2;
    3242           0 :     if (IS_ALIGNED(width, 32)) {
    3243           0 :       InterpolateRow = InterpolateRow_AVX2;
    3244             :     }
    3245             :   }
    3246             : #endif
    3247             : #if defined(HAS_INTERPOLATEROW_NEON)
    3248             :   if (TestCpuFlag(kCpuHasNEON)) {
    3249             :     InterpolateRow = InterpolateRow_Any_NEON;
    3250             :     if (IS_ALIGNED(width, 16)) {
    3251             :       InterpolateRow = InterpolateRow_NEON;
    3252             :     }
    3253             :   }
    3254             : #endif
    3255             : 
    3256             :   {
    3257           0 :     int awidth = halfwidth * 2;
    3258             :     // row of y and 2 rows of uv
    3259           0 :     align_buffer_64(rows, awidth * 3);
    3260             : 
    3261           0 :     for (y = 0; y < height - 1; y += 2) {
    3262             :       // Split Y from UV.
    3263           0 :       SplitUVRow(src_uyvy, rows + awidth, rows, awidth);
    3264           0 :       memcpy(dst_y, rows, width);
    3265           0 :       SplitUVRow(src_uyvy + src_stride_uyvy, rows + awidth * 2, rows, awidth);
    3266           0 :       memcpy(dst_y + dst_stride_y, rows, width);
    3267           0 :       InterpolateRow(dst_uv, rows + awidth, awidth, awidth, 128);
    3268           0 :       src_uyvy += src_stride_uyvy * 2;
    3269           0 :       dst_y += dst_stride_y * 2;
    3270           0 :       dst_uv += dst_stride_uv;
    3271             :     }
    3272           0 :     if (height & 1) {
    3273             :       // Split Y from UV.
    3274           0 :       SplitUVRow(src_uyvy, dst_uv, rows, awidth);
    3275           0 :       memcpy(dst_y, rows, width);
    3276             :     }
    3277           0 :     free_aligned_buffer_64(rows);
    3278             :   }
    3279           0 :   return 0;
    3280             : }
    3281             : 
    3282             : #ifdef __cplusplus
    3283             : }  // extern "C"
    3284             : }  // namespace libyuv
    3285             : #endif

Generated by: LCOV version 1.13