media/libyuv/source/convert.cc

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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  */
    11 #include "libyuv/convert.h"
    13 #include "libyuv/basic_types.h"
    14 #include "libyuv/cpu_id.h"
    15 #include "libyuv/planar_functions.h"
    16 #include "libyuv/rotate.h"
    17 #include "libyuv/scale.h"  // For ScalePlane()
    18 #include "libyuv/row.h"
    20 #ifdef __cplusplus
    21 namespace libyuv {
    22 extern "C" {
    23 #endif
    25 #define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
    26 static __inline int Abs(int v) {
    27   return v >= 0 ? v : -v;
    28 }
    30 // Any I4xx To I420 format with mirroring.
    31 static int I4xxToI420(const uint8* src_y, int src_stride_y,
    32                       const uint8* src_u, int src_stride_u,
    33                       const uint8* src_v, int src_stride_v,
    34                       uint8* dst_y, int dst_stride_y,
    35                       uint8* dst_u, int dst_stride_u,
    36                       uint8* dst_v, int dst_stride_v,
    37                       int src_y_width, int src_y_height,
    38                       int src_uv_width, int src_uv_height) {
    39   if (src_y_width == 0 || src_y_height == 0 ||
    40       src_uv_width == 0 || src_uv_height == 0) {
    41     return -1;
    42   }
    43   const int dst_y_width = Abs(src_y_width);
    44   const int dst_y_height = Abs(src_y_height);
    45   const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1);
    46   const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1);
    47   ScalePlane(src_y, src_stride_y, src_y_width, src_y_height,
    48              dst_y, dst_stride_y, dst_y_width, dst_y_height,
    49              kFilterBilinear);
    50   ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height,
    51              dst_u, dst_stride_u, dst_uv_width, dst_uv_height,
    52              kFilterBilinear);
    53   ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height,
    54              dst_v, dst_stride_v, dst_uv_width, dst_uv_height,
    55              kFilterBilinear);
    56   return 0;
    57 }
    59 // Copy I420 with optional flipping
    60 // TODO(fbarchard): Use Scale plane which supports mirroring, but ensure
    61 // is does row coalescing.
    62 LIBYUV_API
    63 int I420Copy(const uint8* src_y, int src_stride_y,
    64              const uint8* src_u, int src_stride_u,
    65              const uint8* src_v, int src_stride_v,
    66              uint8* dst_y, int dst_stride_y,
    67              uint8* dst_u, int dst_stride_u,
    68              uint8* dst_v, int dst_stride_v,
    69              int width, int height) {
    70   if (!src_y || !src_u || !src_v ||
    71       !dst_y || !dst_u || !dst_v ||
    72       width <= 0 || height == 0) {
    73     return -1;
    74   }
    75   // Negative height means invert the image.
    76   if (height < 0) {
    77     height = -height;
    78     const int halfheight = (height + 1) >> 1;
    79     src_y = src_y + (height - 1) * src_stride_y;
    80     src_u = src_u + (halfheight - 1) * src_stride_u;
    81     src_v = src_v + (halfheight - 1) * src_stride_v;
    82     src_stride_y = -src_stride_y;
    83     src_stride_u = -src_stride_u;
    84     src_stride_v = -src_stride_v;
    85   }
    87   if (dst_y) {
    88     CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
    89   }
    90   // Copy UV planes.
    91   const int halfwidth = (width + 1) >> 1;
    92   const int halfheight = (height + 1) >> 1;
    93   CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
    94   CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
    95   return 0;
    96 }
    98 // 422 chroma is 1/2 width, 1x height
    99 // 420 chroma is 1/2 width, 1/2 height
   100 LIBYUV_API
   101 int I422ToI420(const uint8* src_y, int src_stride_y,
   102                const uint8* src_u, int src_stride_u,
   103                const uint8* src_v, int src_stride_v,
   104                uint8* dst_y, int dst_stride_y,
   105                uint8* dst_u, int dst_stride_u,
   106                uint8* dst_v, int dst_stride_v,
   107                int width, int height) {
   108   const int src_uv_width = SUBSAMPLE(width, 1, 1);
   109   return I4xxToI420(src_y, src_stride_y,
   110                     src_u, src_stride_u,
   111                     src_v, src_stride_v,
   112                     dst_y, dst_stride_y,
   113                     dst_u, dst_stride_u,
   114                     dst_v, dst_stride_v,
   115                     width, height,
   116                     src_uv_width, height);
   117 }
   119 // 444 chroma is 1x width, 1x height
   120 // 420 chroma is 1/2 width, 1/2 height
   121 LIBYUV_API
   122 int I444ToI420(const uint8* src_y, int src_stride_y,
   123                const uint8* src_u, int src_stride_u,
   124                const uint8* src_v, int src_stride_v,
   125                uint8* dst_y, int dst_stride_y,
   126                uint8* dst_u, int dst_stride_u,
   127                uint8* dst_v, int dst_stride_v,
   128                int width, int height) {
   129   return I4xxToI420(src_y, src_stride_y,
   130                     src_u, src_stride_u,
   131                     src_v, src_stride_v,
   132                     dst_y, dst_stride_y,
   133                     dst_u, dst_stride_u,
   134                     dst_v, dst_stride_v,
   135                     width, height,
   136                     width, height);
   137 }
   139 // 411 chroma is 1/4 width, 1x height
   140 // 420 chroma is 1/2 width, 1/2 height
   141 LIBYUV_API
   142 int I411ToI420(const uint8* src_y, int src_stride_y,
   143                const uint8* src_u, int src_stride_u,
   144                const uint8* src_v, int src_stride_v,
   145                uint8* dst_y, int dst_stride_y,
   146                uint8* dst_u, int dst_stride_u,
   147                uint8* dst_v, int dst_stride_v,
   148                int width, int height) {
   149   const int src_uv_width = SUBSAMPLE(width, 3, 2);
   150   return I4xxToI420(src_y, src_stride_y,
   151                     src_u, src_stride_u,
   152                     src_v, src_stride_v,
   153                     dst_y, dst_stride_y,
   154                     dst_u, dst_stride_u,
   155                     dst_v, dst_stride_v,
   156                     width, height,
   157                     src_uv_width, height);
   158 }
   160 // I400 is greyscale typically used in MJPG
   161 LIBYUV_API
   162 int I400ToI420(const uint8* src_y, int src_stride_y,
   163                uint8* dst_y, int dst_stride_y,
   164                uint8* dst_u, int dst_stride_u,
   165                uint8* dst_v, int dst_stride_v,
   166                int width, int height) {
   167   if (!src_y || !dst_y || !dst_u || !dst_v ||
   168       width <= 0 || height == 0) {
   169     return -1;
   170   }
   171   // Negative height means invert the image.
   172   if (height < 0) {
   173     height = -height;
   174     src_y = src_y + (height - 1) * src_stride_y;
   175     src_stride_y = -src_stride_y;
   176   }
   177   int halfwidth = (width + 1) >> 1;
   178   int halfheight = (height + 1) >> 1;
   179   CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
   180   SetPlane(dst_u, dst_stride_u, halfwidth, halfheight, 128);
   181   SetPlane(dst_v, dst_stride_v, halfwidth, halfheight, 128);
   182   return 0;
   183 }
   185 static void CopyPlane2(const uint8* src, int src_stride_0, int src_stride_1,
   186                        uint8* dst, int dst_stride,
   187                        int width, int height) {
   188   void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
   189 #if defined(HAS_COPYROW_X86)
   190   if (TestCpuFlag(kCpuHasX86) && IS_ALIGNED(width, 4)) {
   191     CopyRow = CopyRow_X86;
   192   }
   193 #endif
   194 #if defined(HAS_COPYROW_SSE2)
   195   if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32) &&
   196       IS_ALIGNED(src, 16) &&
   197       IS_ALIGNED(src_stride_0, 16) && IS_ALIGNED(src_stride_1, 16) &&
   198       IS_ALIGNED(dst, 16) && IS_ALIGNED(dst_stride, 16)) {
   199     CopyRow = CopyRow_SSE2;
   200   }
   201 #endif
   202 #if defined(HAS_COPYROW_ERMS)
   203   if (TestCpuFlag(kCpuHasERMS)) {
   204     CopyRow = CopyRow_ERMS;
   205   }
   206 #endif
   207 #if defined(HAS_COPYROW_NEON)
   208   if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) {
   209     CopyRow = CopyRow_NEON;
   210   }
   211 #endif
   212 #if defined(HAS_COPYROW_MIPS)
   213   if (TestCpuFlag(kCpuHasMIPS)) {
   214     CopyRow = CopyRow_MIPS;
   215   }
   216 #endif
   218   // Copy plane
   219   for (int y = 0; y < height - 1; y += 2) {
   220     CopyRow(src, dst, width);
   221     CopyRow(src + src_stride_0, dst + dst_stride, width);
   222     src += src_stride_0 + src_stride_1;
   223     dst += dst_stride * 2;
   224   }
   225   if (height & 1) {
   226     CopyRow(src, dst, width);
   227   }
   228 }
   230 // Support converting from FOURCC_M420
   231 // Useful for bandwidth constrained transports like USB 1.0 and 2.0 and for
   232 // easy conversion to I420.
   233 // M420 format description:
   234 // M420 is row biplanar 420: 2 rows of Y and 1 row of UV.
   235 // Chroma is half width / half height. (420)
   236 // src_stride_m420 is row planar. Normally this will be the width in pixels.
   237 //   The UV plane is half width, but 2 values, so src_stride_m420 applies to
   238 //   this as well as the two Y planes.
   239 static int X420ToI420(const uint8* src_y,
   240                       int src_stride_y0, int src_stride_y1,
   241                       const uint8* src_uv, int src_stride_uv,
   242                       uint8* dst_y, int dst_stride_y,
   243                       uint8* dst_u, int dst_stride_u,
   244                       uint8* dst_v, int dst_stride_v,
   245                       int width, int height) {
   246   if (!src_y || !src_uv ||
   247       !dst_y || !dst_u || !dst_v ||
   248       width <= 0 || height == 0) {
   249     return -1;
   250   }
   251   // Negative height means invert the image.
   252   if (height < 0) {
   253     height = -height;
   254     int halfheight = (height + 1) >> 1;
   255     dst_y = dst_y + (height - 1) * dst_stride_y;
   256     dst_u = dst_u + (halfheight - 1) * dst_stride_u;
   257     dst_v = dst_v + (halfheight - 1) * dst_stride_v;
   258     dst_stride_y = -dst_stride_y;
   259     dst_stride_u = -dst_stride_u;
   260     dst_stride_v = -dst_stride_v;
   261   }
   262   // Coalesce rows.
   263   int halfwidth = (width + 1) >> 1;
   264   int halfheight = (height + 1) >> 1;
   265   if (src_stride_y0 == width &&
   266       src_stride_y1 == width &&
   267       dst_stride_y == width) {
   268     width *= height;
   269     height = 1;
   270     src_stride_y0 = src_stride_y1 = dst_stride_y = 0;
   271   }
   272   // Coalesce rows.
   273   if (src_stride_uv == halfwidth * 2 &&
   274       dst_stride_u == halfwidth &&
   275       dst_stride_v == halfwidth) {
   276     halfwidth *= halfheight;
   277     halfheight = 1;
   278     src_stride_uv = dst_stride_u = dst_stride_v = 0;
   279   }
   280   void (*SplitUVRow)(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix) =
   281       SplitUVRow_C;
   282 #if defined(HAS_SPLITUVROW_SSE2)
   283   if (TestCpuFlag(kCpuHasSSE2) && halfwidth >= 16) {
   284     SplitUVRow = SplitUVRow_Any_SSE2;
   285     if (IS_ALIGNED(halfwidth, 16)) {
   286       SplitUVRow = SplitUVRow_Unaligned_SSE2;
   287       if (IS_ALIGNED(src_uv, 16) && IS_ALIGNED(src_stride_uv, 16) &&
   288           IS_ALIGNED(dst_u, 16) && IS_ALIGNED(dst_stride_u, 16) &&
   289           IS_ALIGNED(dst_v, 16) && IS_ALIGNED(dst_stride_v, 16)) {
   290         SplitUVRow = SplitUVRow_SSE2;
   291       }
   292     }
   293   }
   294 #endif
   295 #if defined(HAS_SPLITUVROW_AVX2)
   296   if (TestCpuFlag(kCpuHasAVX2) && halfwidth >= 32) {
   297     SplitUVRow = SplitUVRow_Any_AVX2;
   298     if (IS_ALIGNED(halfwidth, 32)) {
   299       SplitUVRow = SplitUVRow_AVX2;
   300     }
   301   }
   302 #endif
   303 #if defined(HAS_SPLITUVROW_NEON)
   304   if (TestCpuFlag(kCpuHasNEON) && halfwidth >= 16) {
   305     SplitUVRow = SplitUVRow_Any_NEON;
   306     if (IS_ALIGNED(halfwidth, 16)) {
   307       SplitUVRow = SplitUVRow_NEON;
   308     }
   309   }
   310 #endif
   311 #if defined(HAS_SPLITUVROW_MIPS_DSPR2)
   312   if (TestCpuFlag(kCpuHasMIPS_DSPR2) && halfwidth >= 16) {
   313     SplitUVRow = SplitUVRow_Any_MIPS_DSPR2;
   314     if (IS_ALIGNED(halfwidth, 16)) {
   315       SplitUVRow = SplitUVRow_Unaligned_MIPS_DSPR2;
   316       if (IS_ALIGNED(src_uv, 4) && IS_ALIGNED(src_stride_uv, 4) &&
   317           IS_ALIGNED(dst_u, 4) && IS_ALIGNED(dst_stride_u, 4) &&
   318           IS_ALIGNED(dst_v, 4) && IS_ALIGNED(dst_stride_v, 4)) {
   319         SplitUVRow = SplitUVRow_MIPS_DSPR2;
   320       }
   321     }
   322   }
   323 #endif
   325   if (dst_y) {
   326     if (src_stride_y0 == src_stride_y1) {
   327       CopyPlane(src_y, src_stride_y0, dst_y, dst_stride_y, width, height);
   328     } else {
   329       CopyPlane2(src_y, src_stride_y0, src_stride_y1, dst_y, dst_stride_y,
   330                  width, height);
   331     }
   332   }
   334   for (int y = 0; y < halfheight; ++y) {
   335     // Copy a row of UV.
   336     SplitUVRow(src_uv, dst_u, dst_v, halfwidth);
   337     dst_u += dst_stride_u;
   338     dst_v += dst_stride_v;
   339     src_uv += src_stride_uv;
   340   }
   341   return 0;
   342 }
   344 // Convert NV12 to I420.
   345 LIBYUV_API
   346 int NV12ToI420(const uint8* src_y, int src_stride_y,
   347                const uint8* src_uv, int src_stride_uv,
   348                uint8* dst_y, int dst_stride_y,
   349                uint8* dst_u, int dst_stride_u,
   350                uint8* dst_v, int dst_stride_v,
   351                int width, int height) {
   352   return X420ToI420(src_y, src_stride_y, src_stride_y,
   353                     src_uv, src_stride_uv,
   354                     dst_y, dst_stride_y,
   355                     dst_u, dst_stride_u,
   356                     dst_v, dst_stride_v,
   357                     width, height);
   358 }
   360 // Convert NV21 to I420.  Same as NV12 but u and v pointers swapped.
   361 LIBYUV_API
   362 int NV21ToI420(const uint8* src_y, int src_stride_y,
   363                const uint8* src_vu, int src_stride_vu,
   364                uint8* dst_y, int dst_stride_y,
   365                uint8* dst_u, int dst_stride_u,
   366                uint8* dst_v, int dst_stride_v,
   367                int width, int height) {
   368   return X420ToI420(src_y, src_stride_y, src_stride_y,
   369                     src_vu, src_stride_vu,
   370                     dst_y, dst_stride_y,
   371                     dst_v, dst_stride_v,
   372                     dst_u, dst_stride_u,
   373                     width, height);
   374 }
   376 // Convert M420 to I420.
   377 LIBYUV_API
   378 int M420ToI420(const uint8* src_m420, int src_stride_m420,
   379                uint8* dst_y, int dst_stride_y,
   380                uint8* dst_u, int dst_stride_u,
   381                uint8* dst_v, int dst_stride_v,
   382                int width, int height) {
   383   return X420ToI420(src_m420, src_stride_m420, src_stride_m420 * 2,
   384                     src_m420 + src_stride_m420 * 2, src_stride_m420 * 3,
   385                     dst_y, dst_stride_y,
   386                     dst_u, dst_stride_u,
   387                     dst_v, dst_stride_v,
   388                     width, height);
   389 }
   391 // Convert Q420 to I420.
   392 // Format is rows of YY/YUYV
   393 LIBYUV_API
   394 int Q420ToI420(const uint8* src_y, int src_stride_y,
   395                const uint8* src_yuy2, int src_stride_yuy2,
   396                uint8* dst_y, int dst_stride_y,
   397                uint8* dst_u, int dst_stride_u,
   398                uint8* dst_v, int dst_stride_v,
   399                int width, int height) {
   400   if (!src_y || !src_yuy2 ||
   401       !dst_y || !dst_u || !dst_v ||
   402       width <= 0 || height == 0) {
   403     return -1;
   404   }
   405   // Negative height means invert the image.
   406   if (height < 0) {
   407     height = -height;
   408     int halfheight = (height + 1) >> 1;
   409     dst_y = dst_y + (height - 1) * dst_stride_y;
   410     dst_u = dst_u + (halfheight - 1) * dst_stride_u;
   411     dst_v = dst_v + (halfheight - 1) * dst_stride_v;
   412     dst_stride_y = -dst_stride_y;
   413     dst_stride_u = -dst_stride_u;
   414     dst_stride_v = -dst_stride_v;
   415   }
   416   // CopyRow for rows of just Y in Q420 copied to Y plane of I420.
   417   void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
   418 #if defined(HAS_COPYROW_NEON)
   419   if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) {
   420     CopyRow = CopyRow_NEON;
   421   }
   422 #endif
   423 #if defined(HAS_COPYROW_X86)
   424   if (IS_ALIGNED(width, 4)) {
   425     CopyRow = CopyRow_X86;
   426   }
   427 #endif
   428 #if defined(HAS_COPYROW_SSE2)
   429   if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32) &&
   430       IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
   431       IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
   432     CopyRow = CopyRow_SSE2;
   433   }
   434 #endif
   435 #if defined(HAS_COPYROW_ERMS)
   436   if (TestCpuFlag(kCpuHasERMS)) {
   437     CopyRow = CopyRow_ERMS;
   438   }
   439 #endif
   440 #if defined(HAS_COPYROW_MIPS)
   441   if (TestCpuFlag(kCpuHasMIPS)) {
   442     CopyRow = CopyRow_MIPS;
   443   }
   444 #endif
   446   void (*YUY2ToUV422Row)(const uint8* src_yuy2, uint8* dst_u, uint8* dst_v,
   447       int pix) = YUY2ToUV422Row_C;
   448   void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int pix) =
   449       YUY2ToYRow_C;
   450 #if defined(HAS_YUY2TOYROW_SSE2)
   451   if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
   452     YUY2ToUV422Row = YUY2ToUV422Row_Any_SSE2;
   453     YUY2ToYRow = YUY2ToYRow_Any_SSE2;
   454     if (IS_ALIGNED(width, 16)) {
   455       YUY2ToUV422Row = YUY2ToUV422Row_Unaligned_SSE2;
   456       YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2;
   457       if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) {
   458         YUY2ToUV422Row = YUY2ToUV422Row_SSE2;
   459         if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
   460           YUY2ToYRow = YUY2ToYRow_SSE2;
   461         }
   462       }
   463     }
   464   }
   465 #endif
   466 #if defined(HAS_YUY2TOYROW_AVX2)
   467   if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
   468     YUY2ToUV422Row = YUY2ToUV422Row_Any_AVX2;
   469     YUY2ToYRow = YUY2ToYRow_Any_AVX2;
   470     if (IS_ALIGNED(width, 32)) {
   471       YUY2ToUV422Row = YUY2ToUV422Row_AVX2;
   472       YUY2ToYRow = YUY2ToYRow_AVX2;
   473     }
   474   }
   475 #endif
   476 #if defined(HAS_YUY2TOYROW_NEON)
   477   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
   478     YUY2ToYRow = YUY2ToYRow_Any_NEON;
   479     if (width >= 16) {
   480       YUY2ToUV422Row = YUY2ToUV422Row_Any_NEON;
   481     }
   482     if (IS_ALIGNED(width, 16)) {
   483       YUY2ToYRow = YUY2ToYRow_NEON;
   484       YUY2ToUV422Row = YUY2ToUV422Row_NEON;
   485     }
   486   }
   487 #endif
   489   for (int y = 0; y < height - 1; y += 2) {
   490     CopyRow(src_y, dst_y, width);
   491     src_y += src_stride_y;
   492     dst_y += dst_stride_y;
   494     YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width);
   495     YUY2ToYRow(src_yuy2, dst_y, width);
   496     src_yuy2 += src_stride_yuy2;
   497     dst_y += dst_stride_y;
   498     dst_u += dst_stride_u;
   499     dst_v += dst_stride_v;
   500   }
   501   if (height & 1) {
   502     CopyRow(src_y, dst_y, width);
   503     YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width);
   504   }
   505   return 0;
   506 }
   508 // Convert YUY2 to I420.
   509 LIBYUV_API
   510 int YUY2ToI420(const uint8* src_yuy2, int src_stride_yuy2,
   511                uint8* dst_y, int dst_stride_y,
   512                uint8* dst_u, int dst_stride_u,
   513                uint8* dst_v, int dst_stride_v,
   514                int width, int height) {
   515   // Negative height means invert the image.
   516   if (height < 0) {
   517     height = -height;
   518     src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
   519     src_stride_yuy2 = -src_stride_yuy2;
   520   }
   521   void (*YUY2ToUVRow)(const uint8* src_yuy2, int src_stride_yuy2,
   522                       uint8* dst_u, uint8* dst_v, int pix);
   523   void (*YUY2ToYRow)(const uint8* src_yuy2,
   524                      uint8* dst_y, int pix);
   525   YUY2ToYRow = YUY2ToYRow_C;
   526   YUY2ToUVRow = YUY2ToUVRow_C;
   527 #if defined(HAS_YUY2TOYROW_SSE2)
   528   if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
   529     YUY2ToUVRow = YUY2ToUVRow_Any_SSE2;
   530     YUY2ToYRow = YUY2ToYRow_Any_SSE2;
   531     if (IS_ALIGNED(width, 16)) {
   532       YUY2ToUVRow = YUY2ToUVRow_Unaligned_SSE2;
   533       YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2;
   534       if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) {
   535         YUY2ToUVRow = YUY2ToUVRow_SSE2;
   536         if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
   537           YUY2ToYRow = YUY2ToYRow_SSE2;
   538         }
   539       }
   540     }
   541   }
   542 #endif
   543 #if defined(HAS_YUY2TOYROW_AVX2)
   544   if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
   545     YUY2ToUVRow = YUY2ToUVRow_Any_AVX2;
   546     YUY2ToYRow = YUY2ToYRow_Any_AVX2;
   547     if (IS_ALIGNED(width, 32)) {
   548       YUY2ToUVRow = YUY2ToUVRow_AVX2;
   549       YUY2ToYRow = YUY2ToYRow_AVX2;
   550     }
   551   }
   552 #endif
   553 #if defined(HAS_YUY2TOYROW_NEON)
   554   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
   555     YUY2ToYRow = YUY2ToYRow_Any_NEON;
   556     if (width >= 16) {
   557       YUY2ToUVRow = YUY2ToUVRow_Any_NEON;
   558     }
   559     if (IS_ALIGNED(width, 16)) {
   560       YUY2ToYRow = YUY2ToYRow_NEON;
   561       YUY2ToUVRow = YUY2ToUVRow_NEON;
   562     }
   563   }
   564 #endif
   566   for (int y = 0; y < height - 1; y += 2) {
   567     YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width);
   568     YUY2ToYRow(src_yuy2, dst_y, width);
   569     YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width);
   570     src_yuy2 += src_stride_yuy2 * 2;
   571     dst_y += dst_stride_y * 2;
   572     dst_u += dst_stride_u;
   573     dst_v += dst_stride_v;
   574   }
   575   if (height & 1) {
   576     YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width);
   577     YUY2ToYRow(src_yuy2, dst_y, width);
   578   }
   579   return 0;
   580 }
   582 // Convert UYVY to I420.
   583 LIBYUV_API
   584 int UYVYToI420(const uint8* src_uyvy, int src_stride_uyvy,
   585                uint8* dst_y, int dst_stride_y,
   586                uint8* dst_u, int dst_stride_u,
   587                uint8* dst_v, int dst_stride_v,
   588                int width, int height) {
   589   // Negative height means invert the image.
   590   if (height < 0) {
   591     height = -height;
   592     src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
   593     src_stride_uyvy = -src_stride_uyvy;
   594   }
   595   void (*UYVYToUVRow)(const uint8* src_uyvy, int src_stride_uyvy,
   596                       uint8* dst_u, uint8* dst_v, int pix);
   597   void (*UYVYToYRow)(const uint8* src_uyvy,
   598                      uint8* dst_y, int pix);
   599   UYVYToYRow = UYVYToYRow_C;
   600   UYVYToUVRow = UYVYToUVRow_C;
   601 #if defined(HAS_UYVYTOYROW_SSE2)
   602   if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
   603     UYVYToUVRow = UYVYToUVRow_Any_SSE2;
   604     UYVYToYRow = UYVYToYRow_Any_SSE2;
   605     if (IS_ALIGNED(width, 16)) {
   606       UYVYToUVRow = UYVYToUVRow_Unaligned_SSE2;
   607       UYVYToYRow = UYVYToYRow_Unaligned_SSE2;
   608       if (IS_ALIGNED(src_uyvy, 16) && IS_ALIGNED(src_stride_uyvy, 16)) {
   609         UYVYToUVRow = UYVYToUVRow_SSE2;
   610         if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
   611           UYVYToYRow = UYVYToYRow_SSE2;
   612         }
   613       }
   614     }
   615   }
   616 #endif
   617 #if defined(HAS_UYVYTOYROW_AVX2)
   618   if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
   619     UYVYToUVRow = UYVYToUVRow_Any_AVX2;
   620     UYVYToYRow = UYVYToYRow_Any_AVX2;
   621     if (IS_ALIGNED(width, 32)) {
   622       UYVYToUVRow = UYVYToUVRow_AVX2;
   623       UYVYToYRow = UYVYToYRow_AVX2;
   624     }
   625   }
   626 #endif
   627 #if defined(HAS_UYVYTOYROW_NEON)
   628   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
   629     UYVYToYRow = UYVYToYRow_Any_NEON;
   630     if (width >= 16) {
   631       UYVYToUVRow = UYVYToUVRow_Any_NEON;
   632     }
   633     if (IS_ALIGNED(width, 16)) {
   634       UYVYToYRow = UYVYToYRow_NEON;
   635       UYVYToUVRow = UYVYToUVRow_NEON;
   636     }
   637   }
   638 #endif
   640   for (int y = 0; y < height - 1; y += 2) {
   641     UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width);
   642     UYVYToYRow(src_uyvy, dst_y, width);
   643     UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width);
   644     src_uyvy += src_stride_uyvy * 2;
   645     dst_y += dst_stride_y * 2;
   646     dst_u += dst_stride_u;
   647     dst_v += dst_stride_v;
   648   }
   649   if (height & 1) {
   650     UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width);
   651     UYVYToYRow(src_uyvy, dst_y, width);
   652   }
   653   return 0;
   654 }
   656 // Convert ARGB to I420.
   657 LIBYUV_API
   658 int ARGBToI420(const uint8* src_argb, int src_stride_argb,
   659                uint8* dst_y, int dst_stride_y,
   660                uint8* dst_u, int dst_stride_u,
   661                uint8* dst_v, int dst_stride_v,
   662                int width, int height) {
   663   if (!src_argb ||
   664       !dst_y || !dst_u || !dst_v ||
   665       width <= 0 || height == 0) {
   666     return -1;
   667   }
   668   // Negative height means invert the image.
   669   if (height < 0) {
   670     height = -height;
   671     src_argb = src_argb + (height - 1) * src_stride_argb;
   672     src_stride_argb = -src_stride_argb;
   673   }
   674   void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
   675                       uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
   676   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
   677       ARGBToYRow_C;
   678 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
   679   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
   680     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
   681     ARGBToYRow = ARGBToYRow_Any_SSSE3;
   682     if (IS_ALIGNED(width, 16)) {
   683       ARGBToUVRow = ARGBToUVRow_Unaligned_SSSE3;
   684       ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
   685       if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
   686         ARGBToUVRow = ARGBToUVRow_SSSE3;
   687         if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
   688           ARGBToYRow = ARGBToYRow_SSSE3;
   689         }
   690       }
   691     }
   692   }
   693 #endif
   694 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
   695   if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
   696     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
   697     ARGBToYRow = ARGBToYRow_Any_AVX2;
   698     if (IS_ALIGNED(width, 32)) {
   699       ARGBToUVRow = ARGBToUVRow_AVX2;
   700       ARGBToYRow = ARGBToYRow_AVX2;
   701     }
   702   }
   703 #endif
   704 #if defined(HAS_ARGBTOYROW_NEON)
   705   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
   706     ARGBToYRow = ARGBToYRow_Any_NEON;
   707     if (IS_ALIGNED(width, 8)) {
   708       ARGBToYRow = ARGBToYRow_NEON;
   709     }
   710     if (width >= 16) {
   711       ARGBToUVRow = ARGBToUVRow_Any_NEON;
   712       if (IS_ALIGNED(width, 16)) {
   713         ARGBToUVRow = ARGBToUVRow_NEON;
   714       }
   715     }
   716   }
   717 #endif
   719   for (int y = 0; y < height - 1; y += 2) {
   720     ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width);
   721     ARGBToYRow(src_argb, dst_y, width);
   722     ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
   723     src_argb += src_stride_argb * 2;
   724     dst_y += dst_stride_y * 2;
   725     dst_u += dst_stride_u;
   726     dst_v += dst_stride_v;
   727   }
   728   if (height & 1) {
   729     ARGBToUVRow(src_argb, 0, dst_u, dst_v, width);
   730     ARGBToYRow(src_argb, dst_y, width);
   731   }
   732   return 0;
   733 }
   735 // Convert BGRA to I420.
   736 LIBYUV_API
   737 int BGRAToI420(const uint8* src_bgra, int src_stride_bgra,
   738                uint8* dst_y, int dst_stride_y,
   739                uint8* dst_u, int dst_stride_u,
   740                uint8* dst_v, int dst_stride_v,
   741                int width, int height) {
   742   if (!src_bgra ||
   743       !dst_y || !dst_u || !dst_v ||
   744       width <= 0 || height == 0) {
   745     return -1;
   746   }
   747   // Negative height means invert the image.
   748   if (height < 0) {
   749     height = -height;
   750     src_bgra = src_bgra + (height - 1) * src_stride_bgra;
   751     src_stride_bgra = -src_stride_bgra;
   752   }
   753   void (*BGRAToUVRow)(const uint8* src_bgra0, int src_stride_bgra,
   754                       uint8* dst_u, uint8* dst_v, int width) = BGRAToUVRow_C;
   755   void (*BGRAToYRow)(const uint8* src_bgra, uint8* dst_y, int pix) =
   756       BGRAToYRow_C;
   757 #if defined(HAS_BGRATOYROW_SSSE3)
   758   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
   759     BGRAToUVRow = BGRAToUVRow_Any_SSSE3;
   760     BGRAToYRow = BGRAToYRow_Any_SSSE3;
   761     if (IS_ALIGNED(width, 16)) {
   762       BGRAToUVRow = BGRAToUVRow_Unaligned_SSSE3;
   763       BGRAToYRow = BGRAToYRow_Unaligned_SSSE3;
   764       if (IS_ALIGNED(src_bgra, 16) && IS_ALIGNED(src_stride_bgra, 16)) {
   765         BGRAToUVRow = BGRAToUVRow_SSSE3;
   766         if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
   767           BGRAToYRow = BGRAToYRow_SSSE3;
   768         }
   769       }
   770     }
   771   }
   772 #elif defined(HAS_BGRATOYROW_NEON)
   773   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
   774     BGRAToYRow = BGRAToYRow_Any_NEON;
   775     if (IS_ALIGNED(width, 8)) {
   776       BGRAToYRow = BGRAToYRow_NEON;
   777     }
   778     if (width >= 16) {
   779       BGRAToUVRow = BGRAToUVRow_Any_NEON;
   780       if (IS_ALIGNED(width, 16)) {
   781         BGRAToUVRow = BGRAToUVRow_NEON;
   782       }
   783     }
   784   }
   785 #endif
   787   for (int y = 0; y < height - 1; y += 2) {
   788     BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width);
   789     BGRAToYRow(src_bgra, dst_y, width);
   790     BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width);
   791     src_bgra += src_stride_bgra * 2;
   792     dst_y += dst_stride_y * 2;
   793     dst_u += dst_stride_u;
   794     dst_v += dst_stride_v;
   795   }
   796   if (height & 1) {
   797     BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width);
   798     BGRAToYRow(src_bgra, dst_y, width);
   799   }
   800   return 0;
   801 }
   803 // Convert ABGR to I420.
   804 LIBYUV_API
   805 int ABGRToI420(const uint8* src_abgr, int src_stride_abgr,
   806                uint8* dst_y, int dst_stride_y,
   807                uint8* dst_u, int dst_stride_u,
   808                uint8* dst_v, int dst_stride_v,
   809                int width, int height) {
   810   if (!src_abgr ||
   811       !dst_y || !dst_u || !dst_v ||
   812       width <= 0 || height == 0) {
   813     return -1;
   814   }
   815   // Negative height means invert the image.
   816   if (height < 0) {
   817     height = -height;
   818     src_abgr = src_abgr + (height - 1) * src_stride_abgr;
   819     src_stride_abgr = -src_stride_abgr;
   820   }
   821   void (*ABGRToUVRow)(const uint8* src_abgr0, int src_stride_abgr,
   822                       uint8* dst_u, uint8* dst_v, int width) = ABGRToUVRow_C;
   823   void (*ABGRToYRow)(const uint8* src_abgr, uint8* dst_y, int pix) =
   824       ABGRToYRow_C;
   825 #if defined(HAS_ABGRTOYROW_SSSE3)
   826   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
   827     ABGRToUVRow = ABGRToUVRow_Any_SSSE3;
   828     ABGRToYRow = ABGRToYRow_Any_SSSE3;
   829     if (IS_ALIGNED(width, 16)) {
   830       ABGRToUVRow = ABGRToUVRow_Unaligned_SSSE3;
   831       ABGRToYRow = ABGRToYRow_Unaligned_SSSE3;
   832       if (IS_ALIGNED(src_abgr, 16) && IS_ALIGNED(src_stride_abgr, 16)) {
   833         ABGRToUVRow = ABGRToUVRow_SSSE3;
   834         if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
   835           ABGRToYRow = ABGRToYRow_SSSE3;
   836         }
   837       }
   838     }
   839   }
   840 #elif defined(HAS_ABGRTOYROW_NEON)
   841   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
   842     ABGRToYRow = ABGRToYRow_Any_NEON;
   843     if (IS_ALIGNED(width, 8)) {
   844       ABGRToYRow = ABGRToYRow_NEON;
   845     }
   846     if (width >= 16) {
   847       ABGRToUVRow = ABGRToUVRow_Any_NEON;
   848       if (IS_ALIGNED(width, 16)) {
   849         ABGRToUVRow = ABGRToUVRow_NEON;
   850       }
   851     }
   852   }
   853 #endif
   855   for (int y = 0; y < height - 1; y += 2) {
   856     ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width);
   857     ABGRToYRow(src_abgr, dst_y, width);
   858     ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width);
   859     src_abgr += src_stride_abgr * 2;
   860     dst_y += dst_stride_y * 2;
   861     dst_u += dst_stride_u;
   862     dst_v += dst_stride_v;
   863   }
   864   if (height & 1) {
   865     ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width);
   866     ABGRToYRow(src_abgr, dst_y, width);
   867   }
   868   return 0;
   869 }
   871 // Convert RGBA to I420.
   872 LIBYUV_API
   873 int RGBAToI420(const uint8* src_rgba, int src_stride_rgba,
   874                uint8* dst_y, int dst_stride_y,
   875                uint8* dst_u, int dst_stride_u,
   876                uint8* dst_v, int dst_stride_v,
   877                int width, int height) {
   878   if (!src_rgba ||
   879       !dst_y || !dst_u || !dst_v ||
   880       width <= 0 || height == 0) {
   881     return -1;
   882   }
   883   // Negative height means invert the image.
   884   if (height < 0) {
   885     height = -height;
   886     src_rgba = src_rgba + (height - 1) * src_stride_rgba;
   887     src_stride_rgba = -src_stride_rgba;
   888   }
   889   void (*RGBAToUVRow)(const uint8* src_rgba0, int src_stride_rgba,
   890                       uint8* dst_u, uint8* dst_v, int width) = RGBAToUVRow_C;
   891   void (*RGBAToYRow)(const uint8* src_rgba, uint8* dst_y, int pix) =
   892       RGBAToYRow_C;
   893 #if defined(HAS_RGBATOYROW_SSSE3)
   894   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
   895     RGBAToUVRow = RGBAToUVRow_Any_SSSE3;
   896     RGBAToYRow = RGBAToYRow_Any_SSSE3;
   897     if (IS_ALIGNED(width, 16)) {
   898       RGBAToUVRow = RGBAToUVRow_Unaligned_SSSE3;
   899       RGBAToYRow = RGBAToYRow_Unaligned_SSSE3;
   900       if (IS_ALIGNED(src_rgba, 16) && IS_ALIGNED(src_stride_rgba, 16)) {
   901         RGBAToUVRow = RGBAToUVRow_SSSE3;
   902         if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
   903           RGBAToYRow = RGBAToYRow_SSSE3;
   904         }
   905       }
   906     }
   907   }
   908 #elif defined(HAS_RGBATOYROW_NEON)
   909   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
   910     RGBAToYRow = RGBAToYRow_Any_NEON;
   911     if (IS_ALIGNED(width, 8)) {
   912       RGBAToYRow = RGBAToYRow_NEON;
   913     }
   914     if (width >= 16) {
   915       RGBAToUVRow = RGBAToUVRow_Any_NEON;
   916       if (IS_ALIGNED(width, 16)) {
   917         RGBAToUVRow = RGBAToUVRow_NEON;
   918       }
   919     }
   920   }
   921 #endif
   923   for (int y = 0; y < height - 1; y += 2) {
   924     RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width);
   925     RGBAToYRow(src_rgba, dst_y, width);
   926     RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width);
   927     src_rgba += src_stride_rgba * 2;
   928     dst_y += dst_stride_y * 2;
   929     dst_u += dst_stride_u;
   930     dst_v += dst_stride_v;
   931   }
   932   if (height & 1) {
   933     RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width);
   934     RGBAToYRow(src_rgba, dst_y, width);
   935   }
   936   return 0;
   937 }
   939 // Convert RGB24 to I420.
   940 LIBYUV_API
   941 int RGB24ToI420(const uint8* src_rgb24, int src_stride_rgb24,
   942                 uint8* dst_y, int dst_stride_y,
   943                 uint8* dst_u, int dst_stride_u,
   944                 uint8* dst_v, int dst_stride_v,
   945                 int width, int height) {
   946   if (!src_rgb24 || !dst_y || !dst_u || !dst_v ||
   947       width <= 0 || height == 0) {
   948     return -1;
   949   }
   950   // Negative height means invert the image.
   951   if (height < 0) {
   952     height = -height;
   953     src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
   954     src_stride_rgb24 = -src_stride_rgb24;
   955   }
   957 #if defined(HAS_RGB24TOYROW_NEON)
   958   void (*RGB24ToUVRow)(const uint8* src_rgb24, int src_stride_rgb24,
   959       uint8* dst_u, uint8* dst_v, int width) = RGB24ToUVRow_C;
   960   void (*RGB24ToYRow)(const uint8* src_rgb24, uint8* dst_y, int pix) =
   961       RGB24ToYRow_C;
   962   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
   963     RGB24ToYRow = RGB24ToYRow_Any_NEON;
   964     if (IS_ALIGNED(width, 8)) {
   965       RGB24ToYRow = RGB24ToYRow_NEON;
   966     }
   967     if (width >= 16) {
   968       RGB24ToUVRow = RGB24ToUVRow_Any_NEON;
   969       if (IS_ALIGNED(width, 16)) {
   970         RGB24ToUVRow = RGB24ToUVRow_NEON;
   971       }
   972     }
   973   }
   974 #else  // HAS_RGB24TOYROW_NEON
   976   // Allocate 2 rows of ARGB.
   977   const int kRowSize = (width * 4 + 15) & ~15;
   978   align_buffer_64(row, kRowSize * 2);
   980   void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
   981       RGB24ToARGBRow_C;
   982 #if defined(HAS_RGB24TOARGBROW_SSSE3)
   983   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
   984     RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
   985     if (IS_ALIGNED(width, 16)) {
   986       RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
   987     }
   988   }
   989 #endif
   990   void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
   991                       uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
   992 #if defined(HAS_ARGBTOUVROW_SSSE3)
   993   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
   994     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
   995     if (IS_ALIGNED(width, 16)) {
   996       ARGBToUVRow = ARGBToUVRow_SSSE3;
   997     }
   998   }
   999 #endif
  1000   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
  1001       ARGBToYRow_C;
  1002 #if defined(HAS_ARGBTOUVROW_SSSE3)
  1003   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
  1004     ARGBToYRow = ARGBToYRow_Any_SSSE3;
  1005     if (IS_ALIGNED(width, 16)) {
  1006       ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
  1007       if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
  1008         ARGBToYRow = ARGBToYRow_SSSE3;
  1012 #endif  // HAS_ARGBTOUVROW_SSSE3
  1013 #endif  // HAS_RGB24TOYROW_NEON
  1015   for (int y = 0; y < height - 1; y += 2) {
  1016 #if defined(HAS_RGB24TOYROW_NEON)
  1017     RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
  1018     RGB24ToYRow(src_rgb24, dst_y, width);
  1019     RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
  1020 #else
  1021     RGB24ToARGBRow(src_rgb24, row, width);
  1022     RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width);
  1023     ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
  1024     ARGBToYRow(row, dst_y, width);
  1025     ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
  1026 #endif
  1027     src_rgb24 += src_stride_rgb24 * 2;
  1028     dst_y += dst_stride_y * 2;
  1029     dst_u += dst_stride_u;
  1030     dst_v += dst_stride_v;
  1032   if (height & 1) {
  1033 #if defined(HAS_RGB24TOYROW_NEON)
  1034     RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width);
  1035     RGB24ToYRow(src_rgb24, dst_y, width);
  1036 #else
  1037     RGB24ToARGBRow(src_rgb24, row, width);
  1038     ARGBToUVRow(row, 0, dst_u, dst_v, width);
  1039     ARGBToYRow(row, dst_y, width);
  1040 #endif
  1042 #if !defined(HAS_RGB24TOYROW_NEON)
  1043   free_aligned_buffer_64(row);
  1044 #endif
  1045   return 0;
  1048 // Convert RAW to I420.
  1049 LIBYUV_API
  1050 int RAWToI420(const uint8* src_raw, int src_stride_raw,
  1051               uint8* dst_y, int dst_stride_y,
  1052               uint8* dst_u, int dst_stride_u,
  1053               uint8* dst_v, int dst_stride_v,
  1054               int width, int height) {
  1055   if (!src_raw || !dst_y || !dst_u || !dst_v ||
  1056       width <= 0 || height == 0) {
  1057     return -1;
  1059   // Negative height means invert the image.
  1060   if (height < 0) {
  1061     height = -height;
  1062     src_raw = src_raw + (height - 1) * src_stride_raw;
  1063     src_stride_raw = -src_stride_raw;
  1066 #if defined(HAS_RAWTOYROW_NEON)
  1067   void (*RAWToUVRow)(const uint8* src_raw, int src_stride_raw,
  1068       uint8* dst_u, uint8* dst_v, int width) = RAWToUVRow_C;
  1069   void (*RAWToYRow)(const uint8* src_raw, uint8* dst_y, int pix) =
  1070       RAWToYRow_C;
  1071   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
  1072     RAWToYRow = RAWToYRow_Any_NEON;
  1073     if (IS_ALIGNED(width, 8)) {
  1074       RAWToYRow = RAWToYRow_NEON;
  1076     if (width >= 16) {
  1077       RAWToUVRow = RAWToUVRow_Any_NEON;
  1078       if (IS_ALIGNED(width, 16)) {
  1079         RAWToUVRow = RAWToUVRow_NEON;
  1083 #else  // HAS_RAWTOYROW_NEON
  1085   // Allocate 2 rows of ARGB.
  1086   const int kRowSize = (width * 4 + 15) & ~15;
  1087   align_buffer_64(row, kRowSize * 2);
  1089   void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
  1090       RAWToARGBRow_C;
  1091 #if defined(HAS_RAWTOARGBROW_SSSE3)
  1092   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
  1093     RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
  1094     if (IS_ALIGNED(width, 16)) {
  1095       RAWToARGBRow = RAWToARGBRow_SSSE3;
  1098 #endif
  1099   void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
  1100                       uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
  1101 #if defined(HAS_ARGBTOUVROW_SSSE3)
  1102   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
  1103     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
  1104     if (IS_ALIGNED(width, 16)) {
  1105       ARGBToUVRow = ARGBToUVRow_SSSE3;
  1108 #endif
  1109   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
  1110       ARGBToYRow_C;
  1111 #if defined(HAS_ARGBTOUVROW_SSSE3)
  1112   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
  1113     ARGBToYRow = ARGBToYRow_Any_SSSE3;
  1114     if (IS_ALIGNED(width, 16)) {
  1115       ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
  1116       if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
  1117         ARGBToYRow = ARGBToYRow_SSSE3;
  1121 #endif  // HAS_ARGBTOUVROW_SSSE3
  1122 #endif  // HAS_RAWTOYROW_NEON
  1124   for (int y = 0; y < height - 1; y += 2) {
  1125 #if defined(HAS_RAWTOYROW_NEON)
  1126     RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width);
  1127     RAWToYRow(src_raw, dst_y, width);
  1128     RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width);
  1129 #else
  1130     RAWToARGBRow(src_raw, row, width);
  1131     RAWToARGBRow(src_raw + src_stride_raw, row + kRowSize, width);
  1132     ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
  1133     ARGBToYRow(row, dst_y, width);
  1134     ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
  1135 #endif
  1136     src_raw += src_stride_raw * 2;
  1137     dst_y += dst_stride_y * 2;
  1138     dst_u += dst_stride_u;
  1139     dst_v += dst_stride_v;
  1141   if (height & 1) {
  1142 #if defined(HAS_RAWTOYROW_NEON)
  1143     RAWToUVRow(src_raw, 0, dst_u, dst_v, width);
  1144     RAWToYRow(src_raw, dst_y, width);
  1145 #else
  1146     RAWToARGBRow(src_raw, row, width);
  1147     ARGBToUVRow(row, 0, dst_u, dst_v, width);
  1148     ARGBToYRow(row, dst_y, width);
  1149 #endif
  1151 #if !defined(HAS_RAWTOYROW_NEON)
  1152   free_aligned_buffer_64(row);
  1153 #endif
  1154   return 0;
  1157 // Convert RGB565 to I420.
  1158 LIBYUV_API
  1159 int RGB565ToI420(const uint8* src_rgb565, int src_stride_rgb565,
  1160                 uint8* dst_y, int dst_stride_y,
  1161                 uint8* dst_u, int dst_stride_u,
  1162                 uint8* dst_v, int dst_stride_v,
  1163                 int width, int height) {
  1164   if (!src_rgb565 || !dst_y || !dst_u || !dst_v ||
  1165       width <= 0 || height == 0) {
  1166     return -1;
  1168   // Negative height means invert the image.
  1169   if (height < 0) {
  1170     height = -height;
  1171     src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
  1172     src_stride_rgb565 = -src_stride_rgb565;
  1175 #if defined(HAS_RGB565TOYROW_NEON)
  1176   void (*RGB565ToUVRow)(const uint8* src_rgb565, int src_stride_rgb565,
  1177       uint8* dst_u, uint8* dst_v, int width) = RGB565ToUVRow_C;
  1178   void (*RGB565ToYRow)(const uint8* src_rgb565, uint8* dst_y, int pix) =
  1179       RGB565ToYRow_C;
  1180   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
  1181     RGB565ToYRow = RGB565ToYRow_Any_NEON;
  1182     if (IS_ALIGNED(width, 8)) {
  1183       RGB565ToYRow = RGB565ToYRow_NEON;
  1185     if (width >= 16) {
  1186       RGB565ToUVRow = RGB565ToUVRow_Any_NEON;
  1187       if (IS_ALIGNED(width, 16)) {
  1188         RGB565ToUVRow = RGB565ToUVRow_NEON;
  1192 #else  // HAS_RGB565TOYROW_NEON
  1194   // Allocate 2 rows of ARGB.
  1195   const int kRowSize = (width * 4 + 15) & ~15;
  1196   align_buffer_64(row, kRowSize * 2);
  1198   void (*RGB565ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
  1199       RGB565ToARGBRow_C;
  1200 #if defined(HAS_RGB565TOARGBROW_SSE2)
  1201   if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
  1202     RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
  1203     if (IS_ALIGNED(width, 8)) {
  1204       RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
  1207 #endif
  1208   void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
  1209                       uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
  1210 #if defined(HAS_ARGBTOUVROW_SSSE3)
  1211   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
  1212     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
  1213     if (IS_ALIGNED(width, 16)) {
  1214       ARGBToUVRow = ARGBToUVRow_SSSE3;
  1217 #endif
  1218   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
  1219       ARGBToYRow_C;
  1220 #if defined(HAS_ARGBTOUVROW_SSSE3)
  1221   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
  1222     ARGBToYRow = ARGBToYRow_Any_SSSE3;
  1223     if (IS_ALIGNED(width, 16)) {
  1224       ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
  1225       if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
  1226         ARGBToYRow = ARGBToYRow_SSSE3;
  1230 #endif  // HAS_ARGBTOUVROW_SSSE3
  1231 #endif  // HAS_RGB565TOYROW_NEON
  1233   for (int y = 0; y < height - 1; y += 2) {
  1234 #if defined(HAS_RGB565TOYROW_NEON)
  1235     RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width);
  1236     RGB565ToYRow(src_rgb565, dst_y, width);
  1237     RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width);
  1238 #else
  1239     RGB565ToARGBRow(src_rgb565, row, width);
  1240     RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kRowSize, width);
  1241     ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
  1242     ARGBToYRow(row, dst_y, width);
  1243     ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
  1244 #endif
  1245     src_rgb565 += src_stride_rgb565 * 2;
  1246     dst_y += dst_stride_y * 2;
  1247     dst_u += dst_stride_u;
  1248     dst_v += dst_stride_v;
  1250   if (height & 1) {
  1251 #if defined(HAS_RGB565TOYROW_NEON)
  1252     RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width);
  1253     RGB565ToYRow(src_rgb565, dst_y, width);
  1254 #else
  1255     RGB565ToARGBRow(src_rgb565, row, width);
  1256     ARGBToUVRow(row, 0, dst_u, dst_v, width);
  1257     ARGBToYRow(row, dst_y, width);
  1258 #endif
  1260 #if !defined(HAS_RGB565TOYROW_NEON)
  1261   free_aligned_buffer_64(row);
  1262 #endif
  1263   return 0;
  1266 // Convert ARGB1555 to I420.
  1267 LIBYUV_API
  1268 int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555,
  1269                    uint8* dst_y, int dst_stride_y,
  1270                    uint8* dst_u, int dst_stride_u,
  1271                    uint8* dst_v, int dst_stride_v,
  1272                    int width, int height) {
  1273   if (!src_argb1555 || !dst_y || !dst_u || !dst_v ||
  1274       width <= 0 || height == 0) {
  1275     return -1;
  1277   // Negative height means invert the image.
  1278   if (height < 0) {
  1279     height = -height;
  1280     src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
  1281     src_stride_argb1555 = -src_stride_argb1555;
  1284 #if defined(HAS_ARGB1555TOYROW_NEON)
  1285   void (*ARGB1555ToUVRow)(const uint8* src_argb1555, int src_stride_argb1555,
  1286       uint8* dst_u, uint8* dst_v, int width) = ARGB1555ToUVRow_C;
  1287   void (*ARGB1555ToYRow)(const uint8* src_argb1555, uint8* dst_y, int pix) =
  1288       ARGB1555ToYRow_C;
  1289   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
  1290     ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON;
  1291     if (IS_ALIGNED(width, 8)) {
  1292       ARGB1555ToYRow = ARGB1555ToYRow_NEON;
  1294     if (width >= 16) {
  1295       ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON;
  1296       if (IS_ALIGNED(width, 16)) {
  1297         ARGB1555ToUVRow = ARGB1555ToUVRow_NEON;
  1301 #else  // HAS_ARGB1555TOYROW_NEON
  1303   // Allocate 2 rows of ARGB.
  1304   const int kRowSize = (width * 4 + 15) & ~15;
  1305   align_buffer_64(row, kRowSize * 2);
  1307   void (*ARGB1555ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
  1308       ARGB1555ToARGBRow_C;
  1309 #if defined(HAS_ARGB1555TOARGBROW_SSE2)
  1310   if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
  1311     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
  1312     if (IS_ALIGNED(width, 8)) {
  1313       ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
  1316 #endif
  1317   void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
  1318                       uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
  1319 #if defined(HAS_ARGBTOUVROW_SSSE3)
  1320   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
  1321     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
  1322     if (IS_ALIGNED(width, 16)) {
  1323       ARGBToUVRow = ARGBToUVRow_SSSE3;
  1326 #endif
  1327   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
  1328       ARGBToYRow_C;
  1329 #if defined(HAS_ARGBTOUVROW_SSSE3)
  1330   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
  1331     ARGBToYRow = ARGBToYRow_Any_SSSE3;
  1332     if (IS_ALIGNED(width, 16)) {
  1333       ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
  1334       if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
  1335         ARGBToYRow = ARGBToYRow_SSSE3;
  1339 #endif  // HAS_ARGBTOUVROW_SSSE3
  1340 #endif  // HAS_ARGB1555TOYROW_NEON
  1342   for (int y = 0; y < height - 1; y += 2) {
  1343 #if defined(HAS_ARGB1555TOYROW_NEON)
  1344     ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width);
  1345     ARGB1555ToYRow(src_argb1555, dst_y, width);
  1346     ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y,
  1347                    width);
  1348 #else
  1349     ARGB1555ToARGBRow(src_argb1555, row, width);
  1350     ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize,
  1351                       width);
  1352     ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
  1353     ARGBToYRow(row, dst_y, width);
  1354     ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
  1355 #endif
  1356     src_argb1555 += src_stride_argb1555 * 2;
  1357     dst_y += dst_stride_y * 2;
  1358     dst_u += dst_stride_u;
  1359     dst_v += dst_stride_v;
  1361   if (height & 1) {
  1362 #if defined(HAS_ARGB1555TOYROW_NEON)
  1363     ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width);
  1364     ARGB1555ToYRow(src_argb1555, dst_y, width);
  1365 #else
  1366     ARGB1555ToARGBRow(src_argb1555, row, width);
  1367     ARGBToUVRow(row, 0, dst_u, dst_v, width);
  1368     ARGBToYRow(row, dst_y, width);
  1369 #endif
  1371 #if !defined(HAS_ARGB1555TOYROW_NEON)
  1372   free_aligned_buffer_64(row);
  1373 #endif
  1374   return 0;
  1377 // Convert ARGB4444 to I420.
  1378 LIBYUV_API
  1379 int ARGB4444ToI420(const uint8* src_argb4444, int src_stride_argb4444,
  1380                    uint8* dst_y, int dst_stride_y,
  1381                    uint8* dst_u, int dst_stride_u,
  1382                    uint8* dst_v, int dst_stride_v,
  1383                    int width, int height) {
  1384   if (!src_argb4444 || !dst_y || !dst_u || !dst_v ||
  1385       width <= 0 || height == 0) {
  1386     return -1;
  1388   // Negative height means invert the image.
  1389   if (height < 0) {
  1390     height = -height;
  1391     src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
  1392     src_stride_argb4444 = -src_stride_argb4444;
  1395 #if defined(HAS_ARGB4444TOYROW_NEON)
  1396   void (*ARGB4444ToUVRow)(const uint8* src_argb4444, int src_stride_argb4444,
  1397       uint8* dst_u, uint8* dst_v, int width) = ARGB4444ToUVRow_C;
  1398   void (*ARGB4444ToYRow)(const uint8* src_argb4444, uint8* dst_y, int pix) =
  1399       ARGB4444ToYRow_C;
  1400   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
  1401     ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON;
  1402     if (IS_ALIGNED(width, 8)) {
  1403       ARGB4444ToYRow = ARGB4444ToYRow_NEON;
  1405     if (width >= 16) {
  1406       ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON;
  1407       if (IS_ALIGNED(width, 16)) {
  1408         ARGB4444ToUVRow = ARGB4444ToUVRow_NEON;
  1412 #else  // HAS_ARGB4444TOYROW_NEON
  1414   // Allocate 2 rows of ARGB.
  1415   const int kRowSize = (width * 4 + 15) & ~15;
  1416   align_buffer_64(row, kRowSize * 2);
  1418   void (*ARGB4444ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
  1419       ARGB4444ToARGBRow_C;
  1420 #if defined(HAS_ARGB4444TOARGBROW_SSE2)
  1421   if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
  1422     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
  1423     if (IS_ALIGNED(width, 8)) {
  1424       ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
  1427 #endif
  1428   void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
  1429                       uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
  1430 #if defined(HAS_ARGBTOUVROW_SSSE3)
  1431   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
  1432     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
  1433     if (IS_ALIGNED(width, 16)) {
  1434       ARGBToUVRow = ARGBToUVRow_SSSE3;
  1437 #endif
  1438   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
  1439       ARGBToYRow_C;
  1440 #if defined(HAS_ARGBTOUVROW_SSSE3)
  1441   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
  1442     ARGBToYRow = ARGBToYRow_Any_SSSE3;
  1443     if (IS_ALIGNED(width, 16)) {
  1444       ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
  1445       if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
  1446         ARGBToYRow = ARGBToYRow_SSSE3;
  1450 #endif  // HAS_ARGBTOUVROW_SSSE3
  1451 #endif  // HAS_ARGB4444TOYROW_NEON
  1453   for (int y = 0; y < height - 1; y += 2) {
  1454 #if defined(HAS_ARGB4444TOYROW_NEON)
  1455     ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width);
  1456     ARGB4444ToYRow(src_argb4444, dst_y, width);
  1457     ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y,
  1458                    width);
  1459 #else
  1460     ARGB4444ToARGBRow(src_argb4444, row, width);
  1461     ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kRowSize,
  1462                       width);
  1463     ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
  1464     ARGBToYRow(row, dst_y, width);
  1465     ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
  1466 #endif
  1467     src_argb4444 += src_stride_argb4444 * 2;
  1468     dst_y += dst_stride_y * 2;
  1469     dst_u += dst_stride_u;
  1470     dst_v += dst_stride_v;
  1472   if (height & 1) {
  1473 #if defined(HAS_ARGB4444TOYROW_NEON)
  1474     ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width);
  1475     ARGB4444ToYRow(src_argb4444, dst_y, width);
  1476 #else
  1477     ARGB4444ToARGBRow(src_argb4444, row, width);
  1478     ARGBToUVRow(row, 0, dst_u, dst_v, width);
  1479     ARGBToYRow(row, dst_y, width);
  1480 #endif
  1482 #if !defined(HAS_ARGB4444TOYROW_NEON)
  1483   free_aligned_buffer_64(row);
  1484 #endif
  1485   return 0;
  1488 #ifdef __cplusplus
  1489 }  // extern "C"
  1490 }  // namespace libyuv
  1491 #endif

mercurial