1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/libyuv/source/convert.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1491 @@ 1.4 +/* 1.5 + * Copyright 2011 The LibYuv Project Authors. All rights reserved. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license 1.8 + * that can be found in the LICENSE file in the root of the source 1.9 + * tree. An additional intellectual property rights grant can be found 1.10 + * in the file PATENTS. All contributing project authors may 1.11 + * be found in the AUTHORS file in the root of the source tree. 1.12 + */ 1.13 + 1.14 +#include "libyuv/convert.h" 1.15 + 1.16 +#include "libyuv/basic_types.h" 1.17 +#include "libyuv/cpu_id.h" 1.18 +#include "libyuv/planar_functions.h" 1.19 +#include "libyuv/rotate.h" 1.20 +#include "libyuv/scale.h" // For ScalePlane() 1.21 +#include "libyuv/row.h" 1.22 + 1.23 +#ifdef __cplusplus 1.24 +namespace libyuv { 1.25 +extern "C" { 1.26 +#endif 1.27 + 1.28 +#define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s) 1.29 +static __inline int Abs(int v) { 1.30 + return v >= 0 ? v : -v; 1.31 +} 1.32 + 1.33 +// Any I4xx To I420 format with mirroring. 1.34 +static int I4xxToI420(const uint8* src_y, int src_stride_y, 1.35 + const uint8* src_u, int src_stride_u, 1.36 + const uint8* src_v, int src_stride_v, 1.37 + uint8* dst_y, int dst_stride_y, 1.38 + uint8* dst_u, int dst_stride_u, 1.39 + uint8* dst_v, int dst_stride_v, 1.40 + int src_y_width, int src_y_height, 1.41 + int src_uv_width, int src_uv_height) { 1.42 + if (src_y_width == 0 || src_y_height == 0 || 1.43 + src_uv_width == 0 || src_uv_height == 0) { 1.44 + return -1; 1.45 + } 1.46 + const int dst_y_width = Abs(src_y_width); 1.47 + const int dst_y_height = Abs(src_y_height); 1.48 + const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1); 1.49 + const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1); 1.50 + ScalePlane(src_y, src_stride_y, src_y_width, src_y_height, 1.51 + dst_y, dst_stride_y, dst_y_width, dst_y_height, 1.52 + kFilterBilinear); 1.53 + ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height, 1.54 + dst_u, dst_stride_u, dst_uv_width, dst_uv_height, 1.55 + kFilterBilinear); 1.56 + ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height, 1.57 + dst_v, dst_stride_v, dst_uv_width, dst_uv_height, 1.58 + kFilterBilinear); 1.59 + return 0; 1.60 +} 1.61 + 1.62 +// Copy I420 with optional flipping 1.63 +// TODO(fbarchard): Use Scale plane which supports mirroring, but ensure 1.64 +// is does row coalescing. 1.65 +LIBYUV_API 1.66 +int I420Copy(const uint8* src_y, int src_stride_y, 1.67 + const uint8* src_u, int src_stride_u, 1.68 + const uint8* src_v, int src_stride_v, 1.69 + uint8* dst_y, int dst_stride_y, 1.70 + uint8* dst_u, int dst_stride_u, 1.71 + uint8* dst_v, int dst_stride_v, 1.72 + int width, int height) { 1.73 + if (!src_y || !src_u || !src_v || 1.74 + !dst_y || !dst_u || !dst_v || 1.75 + width <= 0 || height == 0) { 1.76 + return -1; 1.77 + } 1.78 + // Negative height means invert the image. 1.79 + if (height < 0) { 1.80 + height = -height; 1.81 + const int halfheight = (height + 1) >> 1; 1.82 + src_y = src_y + (height - 1) * src_stride_y; 1.83 + src_u = src_u + (halfheight - 1) * src_stride_u; 1.84 + src_v = src_v + (halfheight - 1) * src_stride_v; 1.85 + src_stride_y = -src_stride_y; 1.86 + src_stride_u = -src_stride_u; 1.87 + src_stride_v = -src_stride_v; 1.88 + } 1.89 + 1.90 + if (dst_y) { 1.91 + CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); 1.92 + } 1.93 + // Copy UV planes. 1.94 + const int halfwidth = (width + 1) >> 1; 1.95 + const int halfheight = (height + 1) >> 1; 1.96 + CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight); 1.97 + CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight); 1.98 + return 0; 1.99 +} 1.100 + 1.101 +// 422 chroma is 1/2 width, 1x height 1.102 +// 420 chroma is 1/2 width, 1/2 height 1.103 +LIBYUV_API 1.104 +int I422ToI420(const uint8* src_y, int src_stride_y, 1.105 + const uint8* src_u, int src_stride_u, 1.106 + const uint8* src_v, int src_stride_v, 1.107 + uint8* dst_y, int dst_stride_y, 1.108 + uint8* dst_u, int dst_stride_u, 1.109 + uint8* dst_v, int dst_stride_v, 1.110 + int width, int height) { 1.111 + const int src_uv_width = SUBSAMPLE(width, 1, 1); 1.112 + return I4xxToI420(src_y, src_stride_y, 1.113 + src_u, src_stride_u, 1.114 + src_v, src_stride_v, 1.115 + dst_y, dst_stride_y, 1.116 + dst_u, dst_stride_u, 1.117 + dst_v, dst_stride_v, 1.118 + width, height, 1.119 + src_uv_width, height); 1.120 +} 1.121 + 1.122 +// 444 chroma is 1x width, 1x height 1.123 +// 420 chroma is 1/2 width, 1/2 height 1.124 +LIBYUV_API 1.125 +int I444ToI420(const uint8* src_y, int src_stride_y, 1.126 + const uint8* src_u, int src_stride_u, 1.127 + const uint8* src_v, int src_stride_v, 1.128 + uint8* dst_y, int dst_stride_y, 1.129 + uint8* dst_u, int dst_stride_u, 1.130 + uint8* dst_v, int dst_stride_v, 1.131 + int width, int height) { 1.132 + return I4xxToI420(src_y, src_stride_y, 1.133 + src_u, src_stride_u, 1.134 + src_v, src_stride_v, 1.135 + dst_y, dst_stride_y, 1.136 + dst_u, dst_stride_u, 1.137 + dst_v, dst_stride_v, 1.138 + width, height, 1.139 + width, height); 1.140 +} 1.141 + 1.142 +// 411 chroma is 1/4 width, 1x height 1.143 +// 420 chroma is 1/2 width, 1/2 height 1.144 +LIBYUV_API 1.145 +int I411ToI420(const uint8* src_y, int src_stride_y, 1.146 + const uint8* src_u, int src_stride_u, 1.147 + const uint8* src_v, int src_stride_v, 1.148 + uint8* dst_y, int dst_stride_y, 1.149 + uint8* dst_u, int dst_stride_u, 1.150 + uint8* dst_v, int dst_stride_v, 1.151 + int width, int height) { 1.152 + const int src_uv_width = SUBSAMPLE(width, 3, 2); 1.153 + return I4xxToI420(src_y, src_stride_y, 1.154 + src_u, src_stride_u, 1.155 + src_v, src_stride_v, 1.156 + dst_y, dst_stride_y, 1.157 + dst_u, dst_stride_u, 1.158 + dst_v, dst_stride_v, 1.159 + width, height, 1.160 + src_uv_width, height); 1.161 +} 1.162 + 1.163 +// I400 is greyscale typically used in MJPG 1.164 +LIBYUV_API 1.165 +int I400ToI420(const uint8* src_y, int src_stride_y, 1.166 + uint8* dst_y, int dst_stride_y, 1.167 + uint8* dst_u, int dst_stride_u, 1.168 + uint8* dst_v, int dst_stride_v, 1.169 + int width, int height) { 1.170 + if (!src_y || !dst_y || !dst_u || !dst_v || 1.171 + width <= 0 || height == 0) { 1.172 + return -1; 1.173 + } 1.174 + // Negative height means invert the image. 1.175 + if (height < 0) { 1.176 + height = -height; 1.177 + src_y = src_y + (height - 1) * src_stride_y; 1.178 + src_stride_y = -src_stride_y; 1.179 + } 1.180 + int halfwidth = (width + 1) >> 1; 1.181 + int halfheight = (height + 1) >> 1; 1.182 + CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); 1.183 + SetPlane(dst_u, dst_stride_u, halfwidth, halfheight, 128); 1.184 + SetPlane(dst_v, dst_stride_v, halfwidth, halfheight, 128); 1.185 + return 0; 1.186 +} 1.187 + 1.188 +static void CopyPlane2(const uint8* src, int src_stride_0, int src_stride_1, 1.189 + uint8* dst, int dst_stride, 1.190 + int width, int height) { 1.191 + void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C; 1.192 +#if defined(HAS_COPYROW_X86) 1.193 + if (TestCpuFlag(kCpuHasX86) && IS_ALIGNED(width, 4)) { 1.194 + CopyRow = CopyRow_X86; 1.195 + } 1.196 +#endif 1.197 +#if defined(HAS_COPYROW_SSE2) 1.198 + if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32) && 1.199 + IS_ALIGNED(src, 16) && 1.200 + IS_ALIGNED(src_stride_0, 16) && IS_ALIGNED(src_stride_1, 16) && 1.201 + IS_ALIGNED(dst, 16) && IS_ALIGNED(dst_stride, 16)) { 1.202 + CopyRow = CopyRow_SSE2; 1.203 + } 1.204 +#endif 1.205 +#if defined(HAS_COPYROW_ERMS) 1.206 + if (TestCpuFlag(kCpuHasERMS)) { 1.207 + CopyRow = CopyRow_ERMS; 1.208 + } 1.209 +#endif 1.210 +#if defined(HAS_COPYROW_NEON) 1.211 + if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) { 1.212 + CopyRow = CopyRow_NEON; 1.213 + } 1.214 +#endif 1.215 +#if defined(HAS_COPYROW_MIPS) 1.216 + if (TestCpuFlag(kCpuHasMIPS)) { 1.217 + CopyRow = CopyRow_MIPS; 1.218 + } 1.219 +#endif 1.220 + 1.221 + // Copy plane 1.222 + for (int y = 0; y < height - 1; y += 2) { 1.223 + CopyRow(src, dst, width); 1.224 + CopyRow(src + src_stride_0, dst + dst_stride, width); 1.225 + src += src_stride_0 + src_stride_1; 1.226 + dst += dst_stride * 2; 1.227 + } 1.228 + if (height & 1) { 1.229 + CopyRow(src, dst, width); 1.230 + } 1.231 +} 1.232 + 1.233 +// Support converting from FOURCC_M420 1.234 +// Useful for bandwidth constrained transports like USB 1.0 and 2.0 and for 1.235 +// easy conversion to I420. 1.236 +// M420 format description: 1.237 +// M420 is row biplanar 420: 2 rows of Y and 1 row of UV. 1.238 +// Chroma is half width / half height. (420) 1.239 +// src_stride_m420 is row planar. Normally this will be the width in pixels. 1.240 +// The UV plane is half width, but 2 values, so src_stride_m420 applies to 1.241 +// this as well as the two Y planes. 1.242 +static int X420ToI420(const uint8* src_y, 1.243 + int src_stride_y0, int src_stride_y1, 1.244 + const uint8* src_uv, int src_stride_uv, 1.245 + uint8* dst_y, int dst_stride_y, 1.246 + uint8* dst_u, int dst_stride_u, 1.247 + uint8* dst_v, int dst_stride_v, 1.248 + int width, int height) { 1.249 + if (!src_y || !src_uv || 1.250 + !dst_y || !dst_u || !dst_v || 1.251 + width <= 0 || height == 0) { 1.252 + return -1; 1.253 + } 1.254 + // Negative height means invert the image. 1.255 + if (height < 0) { 1.256 + height = -height; 1.257 + int halfheight = (height + 1) >> 1; 1.258 + dst_y = dst_y + (height - 1) * dst_stride_y; 1.259 + dst_u = dst_u + (halfheight - 1) * dst_stride_u; 1.260 + dst_v = dst_v + (halfheight - 1) * dst_stride_v; 1.261 + dst_stride_y = -dst_stride_y; 1.262 + dst_stride_u = -dst_stride_u; 1.263 + dst_stride_v = -dst_stride_v; 1.264 + } 1.265 + // Coalesce rows. 1.266 + int halfwidth = (width + 1) >> 1; 1.267 + int halfheight = (height + 1) >> 1; 1.268 + if (src_stride_y0 == width && 1.269 + src_stride_y1 == width && 1.270 + dst_stride_y == width) { 1.271 + width *= height; 1.272 + height = 1; 1.273 + src_stride_y0 = src_stride_y1 = dst_stride_y = 0; 1.274 + } 1.275 + // Coalesce rows. 1.276 + if (src_stride_uv == halfwidth * 2 && 1.277 + dst_stride_u == halfwidth && 1.278 + dst_stride_v == halfwidth) { 1.279 + halfwidth *= halfheight; 1.280 + halfheight = 1; 1.281 + src_stride_uv = dst_stride_u = dst_stride_v = 0; 1.282 + } 1.283 + void (*SplitUVRow)(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix) = 1.284 + SplitUVRow_C; 1.285 +#if defined(HAS_SPLITUVROW_SSE2) 1.286 + if (TestCpuFlag(kCpuHasSSE2) && halfwidth >= 16) { 1.287 + SplitUVRow = SplitUVRow_Any_SSE2; 1.288 + if (IS_ALIGNED(halfwidth, 16)) { 1.289 + SplitUVRow = SplitUVRow_Unaligned_SSE2; 1.290 + if (IS_ALIGNED(src_uv, 16) && IS_ALIGNED(src_stride_uv, 16) && 1.291 + IS_ALIGNED(dst_u, 16) && IS_ALIGNED(dst_stride_u, 16) && 1.292 + IS_ALIGNED(dst_v, 16) && IS_ALIGNED(dst_stride_v, 16)) { 1.293 + SplitUVRow = SplitUVRow_SSE2; 1.294 + } 1.295 + } 1.296 + } 1.297 +#endif 1.298 +#if defined(HAS_SPLITUVROW_AVX2) 1.299 + if (TestCpuFlag(kCpuHasAVX2) && halfwidth >= 32) { 1.300 + SplitUVRow = SplitUVRow_Any_AVX2; 1.301 + if (IS_ALIGNED(halfwidth, 32)) { 1.302 + SplitUVRow = SplitUVRow_AVX2; 1.303 + } 1.304 + } 1.305 +#endif 1.306 +#if defined(HAS_SPLITUVROW_NEON) 1.307 + if (TestCpuFlag(kCpuHasNEON) && halfwidth >= 16) { 1.308 + SplitUVRow = SplitUVRow_Any_NEON; 1.309 + if (IS_ALIGNED(halfwidth, 16)) { 1.310 + SplitUVRow = SplitUVRow_NEON; 1.311 + } 1.312 + } 1.313 +#endif 1.314 +#if defined(HAS_SPLITUVROW_MIPS_DSPR2) 1.315 + if (TestCpuFlag(kCpuHasMIPS_DSPR2) && halfwidth >= 16) { 1.316 + SplitUVRow = SplitUVRow_Any_MIPS_DSPR2; 1.317 + if (IS_ALIGNED(halfwidth, 16)) { 1.318 + SplitUVRow = SplitUVRow_Unaligned_MIPS_DSPR2; 1.319 + if (IS_ALIGNED(src_uv, 4) && IS_ALIGNED(src_stride_uv, 4) && 1.320 + IS_ALIGNED(dst_u, 4) && IS_ALIGNED(dst_stride_u, 4) && 1.321 + IS_ALIGNED(dst_v, 4) && IS_ALIGNED(dst_stride_v, 4)) { 1.322 + SplitUVRow = SplitUVRow_MIPS_DSPR2; 1.323 + } 1.324 + } 1.325 + } 1.326 +#endif 1.327 + 1.328 + if (dst_y) { 1.329 + if (src_stride_y0 == src_stride_y1) { 1.330 + CopyPlane(src_y, src_stride_y0, dst_y, dst_stride_y, width, height); 1.331 + } else { 1.332 + CopyPlane2(src_y, src_stride_y0, src_stride_y1, dst_y, dst_stride_y, 1.333 + width, height); 1.334 + } 1.335 + } 1.336 + 1.337 + for (int y = 0; y < halfheight; ++y) { 1.338 + // Copy a row of UV. 1.339 + SplitUVRow(src_uv, dst_u, dst_v, halfwidth); 1.340 + dst_u += dst_stride_u; 1.341 + dst_v += dst_stride_v; 1.342 + src_uv += src_stride_uv; 1.343 + } 1.344 + return 0; 1.345 +} 1.346 + 1.347 +// Convert NV12 to I420. 1.348 +LIBYUV_API 1.349 +int NV12ToI420(const uint8* src_y, int src_stride_y, 1.350 + const uint8* src_uv, int src_stride_uv, 1.351 + uint8* dst_y, int dst_stride_y, 1.352 + uint8* dst_u, int dst_stride_u, 1.353 + uint8* dst_v, int dst_stride_v, 1.354 + int width, int height) { 1.355 + return X420ToI420(src_y, src_stride_y, src_stride_y, 1.356 + src_uv, src_stride_uv, 1.357 + dst_y, dst_stride_y, 1.358 + dst_u, dst_stride_u, 1.359 + dst_v, dst_stride_v, 1.360 + width, height); 1.361 +} 1.362 + 1.363 +// Convert NV21 to I420. Same as NV12 but u and v pointers swapped. 1.364 +LIBYUV_API 1.365 +int NV21ToI420(const uint8* src_y, int src_stride_y, 1.366 + const uint8* src_vu, int src_stride_vu, 1.367 + uint8* dst_y, int dst_stride_y, 1.368 + uint8* dst_u, int dst_stride_u, 1.369 + uint8* dst_v, int dst_stride_v, 1.370 + int width, int height) { 1.371 + return X420ToI420(src_y, src_stride_y, src_stride_y, 1.372 + src_vu, src_stride_vu, 1.373 + dst_y, dst_stride_y, 1.374 + dst_v, dst_stride_v, 1.375 + dst_u, dst_stride_u, 1.376 + width, height); 1.377 +} 1.378 + 1.379 +// Convert M420 to I420. 1.380 +LIBYUV_API 1.381 +int M420ToI420(const uint8* src_m420, int src_stride_m420, 1.382 + uint8* dst_y, int dst_stride_y, 1.383 + uint8* dst_u, int dst_stride_u, 1.384 + uint8* dst_v, int dst_stride_v, 1.385 + int width, int height) { 1.386 + return X420ToI420(src_m420, src_stride_m420, src_stride_m420 * 2, 1.387 + src_m420 + src_stride_m420 * 2, src_stride_m420 * 3, 1.388 + dst_y, dst_stride_y, 1.389 + dst_u, dst_stride_u, 1.390 + dst_v, dst_stride_v, 1.391 + width, height); 1.392 +} 1.393 + 1.394 +// Convert Q420 to I420. 1.395 +// Format is rows of YY/YUYV 1.396 +LIBYUV_API 1.397 +int Q420ToI420(const uint8* src_y, int src_stride_y, 1.398 + const uint8* src_yuy2, int src_stride_yuy2, 1.399 + uint8* dst_y, int dst_stride_y, 1.400 + uint8* dst_u, int dst_stride_u, 1.401 + uint8* dst_v, int dst_stride_v, 1.402 + int width, int height) { 1.403 + if (!src_y || !src_yuy2 || 1.404 + !dst_y || !dst_u || !dst_v || 1.405 + width <= 0 || height == 0) { 1.406 + return -1; 1.407 + } 1.408 + // Negative height means invert the image. 1.409 + if (height < 0) { 1.410 + height = -height; 1.411 + int halfheight = (height + 1) >> 1; 1.412 + dst_y = dst_y + (height - 1) * dst_stride_y; 1.413 + dst_u = dst_u + (halfheight - 1) * dst_stride_u; 1.414 + dst_v = dst_v + (halfheight - 1) * dst_stride_v; 1.415 + dst_stride_y = -dst_stride_y; 1.416 + dst_stride_u = -dst_stride_u; 1.417 + dst_stride_v = -dst_stride_v; 1.418 + } 1.419 + // CopyRow for rows of just Y in Q420 copied to Y plane of I420. 1.420 + void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C; 1.421 +#if defined(HAS_COPYROW_NEON) 1.422 + if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) { 1.423 + CopyRow = CopyRow_NEON; 1.424 + } 1.425 +#endif 1.426 +#if defined(HAS_COPYROW_X86) 1.427 + if (IS_ALIGNED(width, 4)) { 1.428 + CopyRow = CopyRow_X86; 1.429 + } 1.430 +#endif 1.431 +#if defined(HAS_COPYROW_SSE2) 1.432 + if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32) && 1.433 + IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) && 1.434 + IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 1.435 + CopyRow = CopyRow_SSE2; 1.436 + } 1.437 +#endif 1.438 +#if defined(HAS_COPYROW_ERMS) 1.439 + if (TestCpuFlag(kCpuHasERMS)) { 1.440 + CopyRow = CopyRow_ERMS; 1.441 + } 1.442 +#endif 1.443 +#if defined(HAS_COPYROW_MIPS) 1.444 + if (TestCpuFlag(kCpuHasMIPS)) { 1.445 + CopyRow = CopyRow_MIPS; 1.446 + } 1.447 +#endif 1.448 + 1.449 + void (*YUY2ToUV422Row)(const uint8* src_yuy2, uint8* dst_u, uint8* dst_v, 1.450 + int pix) = YUY2ToUV422Row_C; 1.451 + void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int pix) = 1.452 + YUY2ToYRow_C; 1.453 +#if defined(HAS_YUY2TOYROW_SSE2) 1.454 + if (TestCpuFlag(kCpuHasSSE2) && width >= 16) { 1.455 + YUY2ToUV422Row = YUY2ToUV422Row_Any_SSE2; 1.456 + YUY2ToYRow = YUY2ToYRow_Any_SSE2; 1.457 + if (IS_ALIGNED(width, 16)) { 1.458 + YUY2ToUV422Row = YUY2ToUV422Row_Unaligned_SSE2; 1.459 + YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2; 1.460 + if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) { 1.461 + YUY2ToUV422Row = YUY2ToUV422Row_SSE2; 1.462 + if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 1.463 + YUY2ToYRow = YUY2ToYRow_SSE2; 1.464 + } 1.465 + } 1.466 + } 1.467 + } 1.468 +#endif 1.469 +#if defined(HAS_YUY2TOYROW_AVX2) 1.470 + if (TestCpuFlag(kCpuHasAVX2) && width >= 32) { 1.471 + YUY2ToUV422Row = YUY2ToUV422Row_Any_AVX2; 1.472 + YUY2ToYRow = YUY2ToYRow_Any_AVX2; 1.473 + if (IS_ALIGNED(width, 32)) { 1.474 + YUY2ToUV422Row = YUY2ToUV422Row_AVX2; 1.475 + YUY2ToYRow = YUY2ToYRow_AVX2; 1.476 + } 1.477 + } 1.478 +#endif 1.479 +#if defined(HAS_YUY2TOYROW_NEON) 1.480 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.481 + YUY2ToYRow = YUY2ToYRow_Any_NEON; 1.482 + if (width >= 16) { 1.483 + YUY2ToUV422Row = YUY2ToUV422Row_Any_NEON; 1.484 + } 1.485 + if (IS_ALIGNED(width, 16)) { 1.486 + YUY2ToYRow = YUY2ToYRow_NEON; 1.487 + YUY2ToUV422Row = YUY2ToUV422Row_NEON; 1.488 + } 1.489 + } 1.490 +#endif 1.491 + 1.492 + for (int y = 0; y < height - 1; y += 2) { 1.493 + CopyRow(src_y, dst_y, width); 1.494 + src_y += src_stride_y; 1.495 + dst_y += dst_stride_y; 1.496 + 1.497 + YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width); 1.498 + YUY2ToYRow(src_yuy2, dst_y, width); 1.499 + src_yuy2 += src_stride_yuy2; 1.500 + dst_y += dst_stride_y; 1.501 + dst_u += dst_stride_u; 1.502 + dst_v += dst_stride_v; 1.503 + } 1.504 + if (height & 1) { 1.505 + CopyRow(src_y, dst_y, width); 1.506 + YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width); 1.507 + } 1.508 + return 0; 1.509 +} 1.510 + 1.511 +// Convert YUY2 to I420. 1.512 +LIBYUV_API 1.513 +int YUY2ToI420(const uint8* src_yuy2, int src_stride_yuy2, 1.514 + uint8* dst_y, int dst_stride_y, 1.515 + uint8* dst_u, int dst_stride_u, 1.516 + uint8* dst_v, int dst_stride_v, 1.517 + int width, int height) { 1.518 + // Negative height means invert the image. 1.519 + if (height < 0) { 1.520 + height = -height; 1.521 + src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2; 1.522 + src_stride_yuy2 = -src_stride_yuy2; 1.523 + } 1.524 + void (*YUY2ToUVRow)(const uint8* src_yuy2, int src_stride_yuy2, 1.525 + uint8* dst_u, uint8* dst_v, int pix); 1.526 + void (*YUY2ToYRow)(const uint8* src_yuy2, 1.527 + uint8* dst_y, int pix); 1.528 + YUY2ToYRow = YUY2ToYRow_C; 1.529 + YUY2ToUVRow = YUY2ToUVRow_C; 1.530 +#if defined(HAS_YUY2TOYROW_SSE2) 1.531 + if (TestCpuFlag(kCpuHasSSE2) && width >= 16) { 1.532 + YUY2ToUVRow = YUY2ToUVRow_Any_SSE2; 1.533 + YUY2ToYRow = YUY2ToYRow_Any_SSE2; 1.534 + if (IS_ALIGNED(width, 16)) { 1.535 + YUY2ToUVRow = YUY2ToUVRow_Unaligned_SSE2; 1.536 + YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2; 1.537 + if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) { 1.538 + YUY2ToUVRow = YUY2ToUVRow_SSE2; 1.539 + if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 1.540 + YUY2ToYRow = YUY2ToYRow_SSE2; 1.541 + } 1.542 + } 1.543 + } 1.544 + } 1.545 +#endif 1.546 +#if defined(HAS_YUY2TOYROW_AVX2) 1.547 + if (TestCpuFlag(kCpuHasAVX2) && width >= 32) { 1.548 + YUY2ToUVRow = YUY2ToUVRow_Any_AVX2; 1.549 + YUY2ToYRow = YUY2ToYRow_Any_AVX2; 1.550 + if (IS_ALIGNED(width, 32)) { 1.551 + YUY2ToUVRow = YUY2ToUVRow_AVX2; 1.552 + YUY2ToYRow = YUY2ToYRow_AVX2; 1.553 + } 1.554 + } 1.555 +#endif 1.556 +#if defined(HAS_YUY2TOYROW_NEON) 1.557 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.558 + YUY2ToYRow = YUY2ToYRow_Any_NEON; 1.559 + if (width >= 16) { 1.560 + YUY2ToUVRow = YUY2ToUVRow_Any_NEON; 1.561 + } 1.562 + if (IS_ALIGNED(width, 16)) { 1.563 + YUY2ToYRow = YUY2ToYRow_NEON; 1.564 + YUY2ToUVRow = YUY2ToUVRow_NEON; 1.565 + } 1.566 + } 1.567 +#endif 1.568 + 1.569 + for (int y = 0; y < height - 1; y += 2) { 1.570 + YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width); 1.571 + YUY2ToYRow(src_yuy2, dst_y, width); 1.572 + YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width); 1.573 + src_yuy2 += src_stride_yuy2 * 2; 1.574 + dst_y += dst_stride_y * 2; 1.575 + dst_u += dst_stride_u; 1.576 + dst_v += dst_stride_v; 1.577 + } 1.578 + if (height & 1) { 1.579 + YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width); 1.580 + YUY2ToYRow(src_yuy2, dst_y, width); 1.581 + } 1.582 + return 0; 1.583 +} 1.584 + 1.585 +// Convert UYVY to I420. 1.586 +LIBYUV_API 1.587 +int UYVYToI420(const uint8* src_uyvy, int src_stride_uyvy, 1.588 + uint8* dst_y, int dst_stride_y, 1.589 + uint8* dst_u, int dst_stride_u, 1.590 + uint8* dst_v, int dst_stride_v, 1.591 + int width, int height) { 1.592 + // Negative height means invert the image. 1.593 + if (height < 0) { 1.594 + height = -height; 1.595 + src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy; 1.596 + src_stride_uyvy = -src_stride_uyvy; 1.597 + } 1.598 + void (*UYVYToUVRow)(const uint8* src_uyvy, int src_stride_uyvy, 1.599 + uint8* dst_u, uint8* dst_v, int pix); 1.600 + void (*UYVYToYRow)(const uint8* src_uyvy, 1.601 + uint8* dst_y, int pix); 1.602 + UYVYToYRow = UYVYToYRow_C; 1.603 + UYVYToUVRow = UYVYToUVRow_C; 1.604 +#if defined(HAS_UYVYTOYROW_SSE2) 1.605 + if (TestCpuFlag(kCpuHasSSE2) && width >= 16) { 1.606 + UYVYToUVRow = UYVYToUVRow_Any_SSE2; 1.607 + UYVYToYRow = UYVYToYRow_Any_SSE2; 1.608 + if (IS_ALIGNED(width, 16)) { 1.609 + UYVYToUVRow = UYVYToUVRow_Unaligned_SSE2; 1.610 + UYVYToYRow = UYVYToYRow_Unaligned_SSE2; 1.611 + if (IS_ALIGNED(src_uyvy, 16) && IS_ALIGNED(src_stride_uyvy, 16)) { 1.612 + UYVYToUVRow = UYVYToUVRow_SSE2; 1.613 + if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 1.614 + UYVYToYRow = UYVYToYRow_SSE2; 1.615 + } 1.616 + } 1.617 + } 1.618 + } 1.619 +#endif 1.620 +#if defined(HAS_UYVYTOYROW_AVX2) 1.621 + if (TestCpuFlag(kCpuHasAVX2) && width >= 32) { 1.622 + UYVYToUVRow = UYVYToUVRow_Any_AVX2; 1.623 + UYVYToYRow = UYVYToYRow_Any_AVX2; 1.624 + if (IS_ALIGNED(width, 32)) { 1.625 + UYVYToUVRow = UYVYToUVRow_AVX2; 1.626 + UYVYToYRow = UYVYToYRow_AVX2; 1.627 + } 1.628 + } 1.629 +#endif 1.630 +#if defined(HAS_UYVYTOYROW_NEON) 1.631 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.632 + UYVYToYRow = UYVYToYRow_Any_NEON; 1.633 + if (width >= 16) { 1.634 + UYVYToUVRow = UYVYToUVRow_Any_NEON; 1.635 + } 1.636 + if (IS_ALIGNED(width, 16)) { 1.637 + UYVYToYRow = UYVYToYRow_NEON; 1.638 + UYVYToUVRow = UYVYToUVRow_NEON; 1.639 + } 1.640 + } 1.641 +#endif 1.642 + 1.643 + for (int y = 0; y < height - 1; y += 2) { 1.644 + UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width); 1.645 + UYVYToYRow(src_uyvy, dst_y, width); 1.646 + UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width); 1.647 + src_uyvy += src_stride_uyvy * 2; 1.648 + dst_y += dst_stride_y * 2; 1.649 + dst_u += dst_stride_u; 1.650 + dst_v += dst_stride_v; 1.651 + } 1.652 + if (height & 1) { 1.653 + UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width); 1.654 + UYVYToYRow(src_uyvy, dst_y, width); 1.655 + } 1.656 + return 0; 1.657 +} 1.658 + 1.659 +// Convert ARGB to I420. 1.660 +LIBYUV_API 1.661 +int ARGBToI420(const uint8* src_argb, int src_stride_argb, 1.662 + uint8* dst_y, int dst_stride_y, 1.663 + uint8* dst_u, int dst_stride_u, 1.664 + uint8* dst_v, int dst_stride_v, 1.665 + int width, int height) { 1.666 + if (!src_argb || 1.667 + !dst_y || !dst_u || !dst_v || 1.668 + width <= 0 || height == 0) { 1.669 + return -1; 1.670 + } 1.671 + // Negative height means invert the image. 1.672 + if (height < 0) { 1.673 + height = -height; 1.674 + src_argb = src_argb + (height - 1) * src_stride_argb; 1.675 + src_stride_argb = -src_stride_argb; 1.676 + } 1.677 + void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, 1.678 + uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; 1.679 + void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) = 1.680 + ARGBToYRow_C; 1.681 +#if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) 1.682 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1.683 + ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1.684 + ARGBToYRow = ARGBToYRow_Any_SSSE3; 1.685 + if (IS_ALIGNED(width, 16)) { 1.686 + ARGBToUVRow = ARGBToUVRow_Unaligned_SSSE3; 1.687 + ARGBToYRow = ARGBToYRow_Unaligned_SSSE3; 1.688 + if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) { 1.689 + ARGBToUVRow = ARGBToUVRow_SSSE3; 1.690 + if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 1.691 + ARGBToYRow = ARGBToYRow_SSSE3; 1.692 + } 1.693 + } 1.694 + } 1.695 + } 1.696 +#endif 1.697 +#if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) 1.698 + if (TestCpuFlag(kCpuHasAVX2) && width >= 32) { 1.699 + ARGBToUVRow = ARGBToUVRow_Any_AVX2; 1.700 + ARGBToYRow = ARGBToYRow_Any_AVX2; 1.701 + if (IS_ALIGNED(width, 32)) { 1.702 + ARGBToUVRow = ARGBToUVRow_AVX2; 1.703 + ARGBToYRow = ARGBToYRow_AVX2; 1.704 + } 1.705 + } 1.706 +#endif 1.707 +#if defined(HAS_ARGBTOYROW_NEON) 1.708 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.709 + ARGBToYRow = ARGBToYRow_Any_NEON; 1.710 + if (IS_ALIGNED(width, 8)) { 1.711 + ARGBToYRow = ARGBToYRow_NEON; 1.712 + } 1.713 + if (width >= 16) { 1.714 + ARGBToUVRow = ARGBToUVRow_Any_NEON; 1.715 + if (IS_ALIGNED(width, 16)) { 1.716 + ARGBToUVRow = ARGBToUVRow_NEON; 1.717 + } 1.718 + } 1.719 + } 1.720 +#endif 1.721 + 1.722 + for (int y = 0; y < height - 1; y += 2) { 1.723 + ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width); 1.724 + ARGBToYRow(src_argb, dst_y, width); 1.725 + ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width); 1.726 + src_argb += src_stride_argb * 2; 1.727 + dst_y += dst_stride_y * 2; 1.728 + dst_u += dst_stride_u; 1.729 + dst_v += dst_stride_v; 1.730 + } 1.731 + if (height & 1) { 1.732 + ARGBToUVRow(src_argb, 0, dst_u, dst_v, width); 1.733 + ARGBToYRow(src_argb, dst_y, width); 1.734 + } 1.735 + return 0; 1.736 +} 1.737 + 1.738 +// Convert BGRA to I420. 1.739 +LIBYUV_API 1.740 +int BGRAToI420(const uint8* src_bgra, int src_stride_bgra, 1.741 + uint8* dst_y, int dst_stride_y, 1.742 + uint8* dst_u, int dst_stride_u, 1.743 + uint8* dst_v, int dst_stride_v, 1.744 + int width, int height) { 1.745 + if (!src_bgra || 1.746 + !dst_y || !dst_u || !dst_v || 1.747 + width <= 0 || height == 0) { 1.748 + return -1; 1.749 + } 1.750 + // Negative height means invert the image. 1.751 + if (height < 0) { 1.752 + height = -height; 1.753 + src_bgra = src_bgra + (height - 1) * src_stride_bgra; 1.754 + src_stride_bgra = -src_stride_bgra; 1.755 + } 1.756 + void (*BGRAToUVRow)(const uint8* src_bgra0, int src_stride_bgra, 1.757 + uint8* dst_u, uint8* dst_v, int width) = BGRAToUVRow_C; 1.758 + void (*BGRAToYRow)(const uint8* src_bgra, uint8* dst_y, int pix) = 1.759 + BGRAToYRow_C; 1.760 +#if defined(HAS_BGRATOYROW_SSSE3) 1.761 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1.762 + BGRAToUVRow = BGRAToUVRow_Any_SSSE3; 1.763 + BGRAToYRow = BGRAToYRow_Any_SSSE3; 1.764 + if (IS_ALIGNED(width, 16)) { 1.765 + BGRAToUVRow = BGRAToUVRow_Unaligned_SSSE3; 1.766 + BGRAToYRow = BGRAToYRow_Unaligned_SSSE3; 1.767 + if (IS_ALIGNED(src_bgra, 16) && IS_ALIGNED(src_stride_bgra, 16)) { 1.768 + BGRAToUVRow = BGRAToUVRow_SSSE3; 1.769 + if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 1.770 + BGRAToYRow = BGRAToYRow_SSSE3; 1.771 + } 1.772 + } 1.773 + } 1.774 + } 1.775 +#elif defined(HAS_BGRATOYROW_NEON) 1.776 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.777 + BGRAToYRow = BGRAToYRow_Any_NEON; 1.778 + if (IS_ALIGNED(width, 8)) { 1.779 + BGRAToYRow = BGRAToYRow_NEON; 1.780 + } 1.781 + if (width >= 16) { 1.782 + BGRAToUVRow = BGRAToUVRow_Any_NEON; 1.783 + if (IS_ALIGNED(width, 16)) { 1.784 + BGRAToUVRow = BGRAToUVRow_NEON; 1.785 + } 1.786 + } 1.787 + } 1.788 +#endif 1.789 + 1.790 + for (int y = 0; y < height - 1; y += 2) { 1.791 + BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width); 1.792 + BGRAToYRow(src_bgra, dst_y, width); 1.793 + BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width); 1.794 + src_bgra += src_stride_bgra * 2; 1.795 + dst_y += dst_stride_y * 2; 1.796 + dst_u += dst_stride_u; 1.797 + dst_v += dst_stride_v; 1.798 + } 1.799 + if (height & 1) { 1.800 + BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width); 1.801 + BGRAToYRow(src_bgra, dst_y, width); 1.802 + } 1.803 + return 0; 1.804 +} 1.805 + 1.806 +// Convert ABGR to I420. 1.807 +LIBYUV_API 1.808 +int ABGRToI420(const uint8* src_abgr, int src_stride_abgr, 1.809 + uint8* dst_y, int dst_stride_y, 1.810 + uint8* dst_u, int dst_stride_u, 1.811 + uint8* dst_v, int dst_stride_v, 1.812 + int width, int height) { 1.813 + if (!src_abgr || 1.814 + !dst_y || !dst_u || !dst_v || 1.815 + width <= 0 || height == 0) { 1.816 + return -1; 1.817 + } 1.818 + // Negative height means invert the image. 1.819 + if (height < 0) { 1.820 + height = -height; 1.821 + src_abgr = src_abgr + (height - 1) * src_stride_abgr; 1.822 + src_stride_abgr = -src_stride_abgr; 1.823 + } 1.824 + void (*ABGRToUVRow)(const uint8* src_abgr0, int src_stride_abgr, 1.825 + uint8* dst_u, uint8* dst_v, int width) = ABGRToUVRow_C; 1.826 + void (*ABGRToYRow)(const uint8* src_abgr, uint8* dst_y, int pix) = 1.827 + ABGRToYRow_C; 1.828 +#if defined(HAS_ABGRTOYROW_SSSE3) 1.829 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1.830 + ABGRToUVRow = ABGRToUVRow_Any_SSSE3; 1.831 + ABGRToYRow = ABGRToYRow_Any_SSSE3; 1.832 + if (IS_ALIGNED(width, 16)) { 1.833 + ABGRToUVRow = ABGRToUVRow_Unaligned_SSSE3; 1.834 + ABGRToYRow = ABGRToYRow_Unaligned_SSSE3; 1.835 + if (IS_ALIGNED(src_abgr, 16) && IS_ALIGNED(src_stride_abgr, 16)) { 1.836 + ABGRToUVRow = ABGRToUVRow_SSSE3; 1.837 + if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 1.838 + ABGRToYRow = ABGRToYRow_SSSE3; 1.839 + } 1.840 + } 1.841 + } 1.842 + } 1.843 +#elif defined(HAS_ABGRTOYROW_NEON) 1.844 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.845 + ABGRToYRow = ABGRToYRow_Any_NEON; 1.846 + if (IS_ALIGNED(width, 8)) { 1.847 + ABGRToYRow = ABGRToYRow_NEON; 1.848 + } 1.849 + if (width >= 16) { 1.850 + ABGRToUVRow = ABGRToUVRow_Any_NEON; 1.851 + if (IS_ALIGNED(width, 16)) { 1.852 + ABGRToUVRow = ABGRToUVRow_NEON; 1.853 + } 1.854 + } 1.855 + } 1.856 +#endif 1.857 + 1.858 + for (int y = 0; y < height - 1; y += 2) { 1.859 + ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width); 1.860 + ABGRToYRow(src_abgr, dst_y, width); 1.861 + ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width); 1.862 + src_abgr += src_stride_abgr * 2; 1.863 + dst_y += dst_stride_y * 2; 1.864 + dst_u += dst_stride_u; 1.865 + dst_v += dst_stride_v; 1.866 + } 1.867 + if (height & 1) { 1.868 + ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width); 1.869 + ABGRToYRow(src_abgr, dst_y, width); 1.870 + } 1.871 + return 0; 1.872 +} 1.873 + 1.874 +// Convert RGBA to I420. 1.875 +LIBYUV_API 1.876 +int RGBAToI420(const uint8* src_rgba, int src_stride_rgba, 1.877 + uint8* dst_y, int dst_stride_y, 1.878 + uint8* dst_u, int dst_stride_u, 1.879 + uint8* dst_v, int dst_stride_v, 1.880 + int width, int height) { 1.881 + if (!src_rgba || 1.882 + !dst_y || !dst_u || !dst_v || 1.883 + width <= 0 || height == 0) { 1.884 + return -1; 1.885 + } 1.886 + // Negative height means invert the image. 1.887 + if (height < 0) { 1.888 + height = -height; 1.889 + src_rgba = src_rgba + (height - 1) * src_stride_rgba; 1.890 + src_stride_rgba = -src_stride_rgba; 1.891 + } 1.892 + void (*RGBAToUVRow)(const uint8* src_rgba0, int src_stride_rgba, 1.893 + uint8* dst_u, uint8* dst_v, int width) = RGBAToUVRow_C; 1.894 + void (*RGBAToYRow)(const uint8* src_rgba, uint8* dst_y, int pix) = 1.895 + RGBAToYRow_C; 1.896 +#if defined(HAS_RGBATOYROW_SSSE3) 1.897 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1.898 + RGBAToUVRow = RGBAToUVRow_Any_SSSE3; 1.899 + RGBAToYRow = RGBAToYRow_Any_SSSE3; 1.900 + if (IS_ALIGNED(width, 16)) { 1.901 + RGBAToUVRow = RGBAToUVRow_Unaligned_SSSE3; 1.902 + RGBAToYRow = RGBAToYRow_Unaligned_SSSE3; 1.903 + if (IS_ALIGNED(src_rgba, 16) && IS_ALIGNED(src_stride_rgba, 16)) { 1.904 + RGBAToUVRow = RGBAToUVRow_SSSE3; 1.905 + if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 1.906 + RGBAToYRow = RGBAToYRow_SSSE3; 1.907 + } 1.908 + } 1.909 + } 1.910 + } 1.911 +#elif defined(HAS_RGBATOYROW_NEON) 1.912 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.913 + RGBAToYRow = RGBAToYRow_Any_NEON; 1.914 + if (IS_ALIGNED(width, 8)) { 1.915 + RGBAToYRow = RGBAToYRow_NEON; 1.916 + } 1.917 + if (width >= 16) { 1.918 + RGBAToUVRow = RGBAToUVRow_Any_NEON; 1.919 + if (IS_ALIGNED(width, 16)) { 1.920 + RGBAToUVRow = RGBAToUVRow_NEON; 1.921 + } 1.922 + } 1.923 + } 1.924 +#endif 1.925 + 1.926 + for (int y = 0; y < height - 1; y += 2) { 1.927 + RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width); 1.928 + RGBAToYRow(src_rgba, dst_y, width); 1.929 + RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width); 1.930 + src_rgba += src_stride_rgba * 2; 1.931 + dst_y += dst_stride_y * 2; 1.932 + dst_u += dst_stride_u; 1.933 + dst_v += dst_stride_v; 1.934 + } 1.935 + if (height & 1) { 1.936 + RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width); 1.937 + RGBAToYRow(src_rgba, dst_y, width); 1.938 + } 1.939 + return 0; 1.940 +} 1.941 + 1.942 +// Convert RGB24 to I420. 1.943 +LIBYUV_API 1.944 +int RGB24ToI420(const uint8* src_rgb24, int src_stride_rgb24, 1.945 + uint8* dst_y, int dst_stride_y, 1.946 + uint8* dst_u, int dst_stride_u, 1.947 + uint8* dst_v, int dst_stride_v, 1.948 + int width, int height) { 1.949 + if (!src_rgb24 || !dst_y || !dst_u || !dst_v || 1.950 + width <= 0 || height == 0) { 1.951 + return -1; 1.952 + } 1.953 + // Negative height means invert the image. 1.954 + if (height < 0) { 1.955 + height = -height; 1.956 + src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24; 1.957 + src_stride_rgb24 = -src_stride_rgb24; 1.958 + } 1.959 + 1.960 +#if defined(HAS_RGB24TOYROW_NEON) 1.961 + void (*RGB24ToUVRow)(const uint8* src_rgb24, int src_stride_rgb24, 1.962 + uint8* dst_u, uint8* dst_v, int width) = RGB24ToUVRow_C; 1.963 + void (*RGB24ToYRow)(const uint8* src_rgb24, uint8* dst_y, int pix) = 1.964 + RGB24ToYRow_C; 1.965 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.966 + RGB24ToYRow = RGB24ToYRow_Any_NEON; 1.967 + if (IS_ALIGNED(width, 8)) { 1.968 + RGB24ToYRow = RGB24ToYRow_NEON; 1.969 + } 1.970 + if (width >= 16) { 1.971 + RGB24ToUVRow = RGB24ToUVRow_Any_NEON; 1.972 + if (IS_ALIGNED(width, 16)) { 1.973 + RGB24ToUVRow = RGB24ToUVRow_NEON; 1.974 + } 1.975 + } 1.976 + } 1.977 +#else // HAS_RGB24TOYROW_NEON 1.978 + 1.979 + // Allocate 2 rows of ARGB. 1.980 + const int kRowSize = (width * 4 + 15) & ~15; 1.981 + align_buffer_64(row, kRowSize * 2); 1.982 + 1.983 + void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = 1.984 + RGB24ToARGBRow_C; 1.985 +#if defined(HAS_RGB24TOARGBROW_SSSE3) 1.986 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1.987 + RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3; 1.988 + if (IS_ALIGNED(width, 16)) { 1.989 + RGB24ToARGBRow = RGB24ToARGBRow_SSSE3; 1.990 + } 1.991 + } 1.992 +#endif 1.993 + void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, 1.994 + uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; 1.995 +#if defined(HAS_ARGBTOUVROW_SSSE3) 1.996 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1.997 + ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1.998 + if (IS_ALIGNED(width, 16)) { 1.999 + ARGBToUVRow = ARGBToUVRow_SSSE3; 1.1000 + } 1.1001 + } 1.1002 +#endif 1.1003 + void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) = 1.1004 + ARGBToYRow_C; 1.1005 +#if defined(HAS_ARGBTOUVROW_SSSE3) 1.1006 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1.1007 + ARGBToYRow = ARGBToYRow_Any_SSSE3; 1.1008 + if (IS_ALIGNED(width, 16)) { 1.1009 + ARGBToYRow = ARGBToYRow_Unaligned_SSSE3; 1.1010 + if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 1.1011 + ARGBToYRow = ARGBToYRow_SSSE3; 1.1012 + } 1.1013 + } 1.1014 + } 1.1015 +#endif // HAS_ARGBTOUVROW_SSSE3 1.1016 +#endif // HAS_RGB24TOYROW_NEON 1.1017 + 1.1018 + for (int y = 0; y < height - 1; y += 2) { 1.1019 +#if defined(HAS_RGB24TOYROW_NEON) 1.1020 + RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width); 1.1021 + RGB24ToYRow(src_rgb24, dst_y, width); 1.1022 + RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width); 1.1023 +#else 1.1024 + RGB24ToARGBRow(src_rgb24, row, width); 1.1025 + RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width); 1.1026 + ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1.1027 + ARGBToYRow(row, dst_y, width); 1.1028 + ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1.1029 +#endif 1.1030 + src_rgb24 += src_stride_rgb24 * 2; 1.1031 + dst_y += dst_stride_y * 2; 1.1032 + dst_u += dst_stride_u; 1.1033 + dst_v += dst_stride_v; 1.1034 + } 1.1035 + if (height & 1) { 1.1036 +#if defined(HAS_RGB24TOYROW_NEON) 1.1037 + RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width); 1.1038 + RGB24ToYRow(src_rgb24, dst_y, width); 1.1039 +#else 1.1040 + RGB24ToARGBRow(src_rgb24, row, width); 1.1041 + ARGBToUVRow(row, 0, dst_u, dst_v, width); 1.1042 + ARGBToYRow(row, dst_y, width); 1.1043 +#endif 1.1044 + } 1.1045 +#if !defined(HAS_RGB24TOYROW_NEON) 1.1046 + free_aligned_buffer_64(row); 1.1047 +#endif 1.1048 + return 0; 1.1049 +} 1.1050 + 1.1051 +// Convert RAW to I420. 1.1052 +LIBYUV_API 1.1053 +int RAWToI420(const uint8* src_raw, int src_stride_raw, 1.1054 + uint8* dst_y, int dst_stride_y, 1.1055 + uint8* dst_u, int dst_stride_u, 1.1056 + uint8* dst_v, int dst_stride_v, 1.1057 + int width, int height) { 1.1058 + if (!src_raw || !dst_y || !dst_u || !dst_v || 1.1059 + width <= 0 || height == 0) { 1.1060 + return -1; 1.1061 + } 1.1062 + // Negative height means invert the image. 1.1063 + if (height < 0) { 1.1064 + height = -height; 1.1065 + src_raw = src_raw + (height - 1) * src_stride_raw; 1.1066 + src_stride_raw = -src_stride_raw; 1.1067 + } 1.1068 + 1.1069 +#if defined(HAS_RAWTOYROW_NEON) 1.1070 + void (*RAWToUVRow)(const uint8* src_raw, int src_stride_raw, 1.1071 + uint8* dst_u, uint8* dst_v, int width) = RAWToUVRow_C; 1.1072 + void (*RAWToYRow)(const uint8* src_raw, uint8* dst_y, int pix) = 1.1073 + RAWToYRow_C; 1.1074 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.1075 + RAWToYRow = RAWToYRow_Any_NEON; 1.1076 + if (IS_ALIGNED(width, 8)) { 1.1077 + RAWToYRow = RAWToYRow_NEON; 1.1078 + } 1.1079 + if (width >= 16) { 1.1080 + RAWToUVRow = RAWToUVRow_Any_NEON; 1.1081 + if (IS_ALIGNED(width, 16)) { 1.1082 + RAWToUVRow = RAWToUVRow_NEON; 1.1083 + } 1.1084 + } 1.1085 + } 1.1086 +#else // HAS_RAWTOYROW_NEON 1.1087 + 1.1088 + // Allocate 2 rows of ARGB. 1.1089 + const int kRowSize = (width * 4 + 15) & ~15; 1.1090 + align_buffer_64(row, kRowSize * 2); 1.1091 + 1.1092 + void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = 1.1093 + RAWToARGBRow_C; 1.1094 +#if defined(HAS_RAWTOARGBROW_SSSE3) 1.1095 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1.1096 + RAWToARGBRow = RAWToARGBRow_Any_SSSE3; 1.1097 + if (IS_ALIGNED(width, 16)) { 1.1098 + RAWToARGBRow = RAWToARGBRow_SSSE3; 1.1099 + } 1.1100 + } 1.1101 +#endif 1.1102 + void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, 1.1103 + uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; 1.1104 +#if defined(HAS_ARGBTOUVROW_SSSE3) 1.1105 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1.1106 + ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1.1107 + if (IS_ALIGNED(width, 16)) { 1.1108 + ARGBToUVRow = ARGBToUVRow_SSSE3; 1.1109 + } 1.1110 + } 1.1111 +#endif 1.1112 + void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) = 1.1113 + ARGBToYRow_C; 1.1114 +#if defined(HAS_ARGBTOUVROW_SSSE3) 1.1115 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1.1116 + ARGBToYRow = ARGBToYRow_Any_SSSE3; 1.1117 + if (IS_ALIGNED(width, 16)) { 1.1118 + ARGBToYRow = ARGBToYRow_Unaligned_SSSE3; 1.1119 + if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 1.1120 + ARGBToYRow = ARGBToYRow_SSSE3; 1.1121 + } 1.1122 + } 1.1123 + } 1.1124 +#endif // HAS_ARGBTOUVROW_SSSE3 1.1125 +#endif // HAS_RAWTOYROW_NEON 1.1126 + 1.1127 + for (int y = 0; y < height - 1; y += 2) { 1.1128 +#if defined(HAS_RAWTOYROW_NEON) 1.1129 + RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width); 1.1130 + RAWToYRow(src_raw, dst_y, width); 1.1131 + RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width); 1.1132 +#else 1.1133 + RAWToARGBRow(src_raw, row, width); 1.1134 + RAWToARGBRow(src_raw + src_stride_raw, row + kRowSize, width); 1.1135 + ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1.1136 + ARGBToYRow(row, dst_y, width); 1.1137 + ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1.1138 +#endif 1.1139 + src_raw += src_stride_raw * 2; 1.1140 + dst_y += dst_stride_y * 2; 1.1141 + dst_u += dst_stride_u; 1.1142 + dst_v += dst_stride_v; 1.1143 + } 1.1144 + if (height & 1) { 1.1145 +#if defined(HAS_RAWTOYROW_NEON) 1.1146 + RAWToUVRow(src_raw, 0, dst_u, dst_v, width); 1.1147 + RAWToYRow(src_raw, dst_y, width); 1.1148 +#else 1.1149 + RAWToARGBRow(src_raw, row, width); 1.1150 + ARGBToUVRow(row, 0, dst_u, dst_v, width); 1.1151 + ARGBToYRow(row, dst_y, width); 1.1152 +#endif 1.1153 + } 1.1154 +#if !defined(HAS_RAWTOYROW_NEON) 1.1155 + free_aligned_buffer_64(row); 1.1156 +#endif 1.1157 + return 0; 1.1158 +} 1.1159 + 1.1160 +// Convert RGB565 to I420. 1.1161 +LIBYUV_API 1.1162 +int RGB565ToI420(const uint8* src_rgb565, int src_stride_rgb565, 1.1163 + uint8* dst_y, int dst_stride_y, 1.1164 + uint8* dst_u, int dst_stride_u, 1.1165 + uint8* dst_v, int dst_stride_v, 1.1166 + int width, int height) { 1.1167 + if (!src_rgb565 || !dst_y || !dst_u || !dst_v || 1.1168 + width <= 0 || height == 0) { 1.1169 + return -1; 1.1170 + } 1.1171 + // Negative height means invert the image. 1.1172 + if (height < 0) { 1.1173 + height = -height; 1.1174 + src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565; 1.1175 + src_stride_rgb565 = -src_stride_rgb565; 1.1176 + } 1.1177 + 1.1178 +#if defined(HAS_RGB565TOYROW_NEON) 1.1179 + void (*RGB565ToUVRow)(const uint8* src_rgb565, int src_stride_rgb565, 1.1180 + uint8* dst_u, uint8* dst_v, int width) = RGB565ToUVRow_C; 1.1181 + void (*RGB565ToYRow)(const uint8* src_rgb565, uint8* dst_y, int pix) = 1.1182 + RGB565ToYRow_C; 1.1183 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.1184 + RGB565ToYRow = RGB565ToYRow_Any_NEON; 1.1185 + if (IS_ALIGNED(width, 8)) { 1.1186 + RGB565ToYRow = RGB565ToYRow_NEON; 1.1187 + } 1.1188 + if (width >= 16) { 1.1189 + RGB565ToUVRow = RGB565ToUVRow_Any_NEON; 1.1190 + if (IS_ALIGNED(width, 16)) { 1.1191 + RGB565ToUVRow = RGB565ToUVRow_NEON; 1.1192 + } 1.1193 + } 1.1194 + } 1.1195 +#else // HAS_RGB565TOYROW_NEON 1.1196 + 1.1197 + // Allocate 2 rows of ARGB. 1.1198 + const int kRowSize = (width * 4 + 15) & ~15; 1.1199 + align_buffer_64(row, kRowSize * 2); 1.1200 + 1.1201 + void (*RGB565ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = 1.1202 + RGB565ToARGBRow_C; 1.1203 +#if defined(HAS_RGB565TOARGBROW_SSE2) 1.1204 + if (TestCpuFlag(kCpuHasSSE2) && width >= 8) { 1.1205 + RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2; 1.1206 + if (IS_ALIGNED(width, 8)) { 1.1207 + RGB565ToARGBRow = RGB565ToARGBRow_SSE2; 1.1208 + } 1.1209 + } 1.1210 +#endif 1.1211 + void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, 1.1212 + uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; 1.1213 +#if defined(HAS_ARGBTOUVROW_SSSE3) 1.1214 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1.1215 + ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1.1216 + if (IS_ALIGNED(width, 16)) { 1.1217 + ARGBToUVRow = ARGBToUVRow_SSSE3; 1.1218 + } 1.1219 + } 1.1220 +#endif 1.1221 + void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) = 1.1222 + ARGBToYRow_C; 1.1223 +#if defined(HAS_ARGBTOUVROW_SSSE3) 1.1224 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1.1225 + ARGBToYRow = ARGBToYRow_Any_SSSE3; 1.1226 + if (IS_ALIGNED(width, 16)) { 1.1227 + ARGBToYRow = ARGBToYRow_Unaligned_SSSE3; 1.1228 + if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 1.1229 + ARGBToYRow = ARGBToYRow_SSSE3; 1.1230 + } 1.1231 + } 1.1232 + } 1.1233 +#endif // HAS_ARGBTOUVROW_SSSE3 1.1234 +#endif // HAS_RGB565TOYROW_NEON 1.1235 + 1.1236 + for (int y = 0; y < height - 1; y += 2) { 1.1237 +#if defined(HAS_RGB565TOYROW_NEON) 1.1238 + RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width); 1.1239 + RGB565ToYRow(src_rgb565, dst_y, width); 1.1240 + RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width); 1.1241 +#else 1.1242 + RGB565ToARGBRow(src_rgb565, row, width); 1.1243 + RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kRowSize, width); 1.1244 + ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1.1245 + ARGBToYRow(row, dst_y, width); 1.1246 + ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1.1247 +#endif 1.1248 + src_rgb565 += src_stride_rgb565 * 2; 1.1249 + dst_y += dst_stride_y * 2; 1.1250 + dst_u += dst_stride_u; 1.1251 + dst_v += dst_stride_v; 1.1252 + } 1.1253 + if (height & 1) { 1.1254 +#if defined(HAS_RGB565TOYROW_NEON) 1.1255 + RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width); 1.1256 + RGB565ToYRow(src_rgb565, dst_y, width); 1.1257 +#else 1.1258 + RGB565ToARGBRow(src_rgb565, row, width); 1.1259 + ARGBToUVRow(row, 0, dst_u, dst_v, width); 1.1260 + ARGBToYRow(row, dst_y, width); 1.1261 +#endif 1.1262 + } 1.1263 +#if !defined(HAS_RGB565TOYROW_NEON) 1.1264 + free_aligned_buffer_64(row); 1.1265 +#endif 1.1266 + return 0; 1.1267 +} 1.1268 + 1.1269 +// Convert ARGB1555 to I420. 1.1270 +LIBYUV_API 1.1271 +int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555, 1.1272 + uint8* dst_y, int dst_stride_y, 1.1273 + uint8* dst_u, int dst_stride_u, 1.1274 + uint8* dst_v, int dst_stride_v, 1.1275 + int width, int height) { 1.1276 + if (!src_argb1555 || !dst_y || !dst_u || !dst_v || 1.1277 + width <= 0 || height == 0) { 1.1278 + return -1; 1.1279 + } 1.1280 + // Negative height means invert the image. 1.1281 + if (height < 0) { 1.1282 + height = -height; 1.1283 + src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555; 1.1284 + src_stride_argb1555 = -src_stride_argb1555; 1.1285 + } 1.1286 + 1.1287 +#if defined(HAS_ARGB1555TOYROW_NEON) 1.1288 + void (*ARGB1555ToUVRow)(const uint8* src_argb1555, int src_stride_argb1555, 1.1289 + uint8* dst_u, uint8* dst_v, int width) = ARGB1555ToUVRow_C; 1.1290 + void (*ARGB1555ToYRow)(const uint8* src_argb1555, uint8* dst_y, int pix) = 1.1291 + ARGB1555ToYRow_C; 1.1292 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.1293 + ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON; 1.1294 + if (IS_ALIGNED(width, 8)) { 1.1295 + ARGB1555ToYRow = ARGB1555ToYRow_NEON; 1.1296 + } 1.1297 + if (width >= 16) { 1.1298 + ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON; 1.1299 + if (IS_ALIGNED(width, 16)) { 1.1300 + ARGB1555ToUVRow = ARGB1555ToUVRow_NEON; 1.1301 + } 1.1302 + } 1.1303 + } 1.1304 +#else // HAS_ARGB1555TOYROW_NEON 1.1305 + 1.1306 + // Allocate 2 rows of ARGB. 1.1307 + const int kRowSize = (width * 4 + 15) & ~15; 1.1308 + align_buffer_64(row, kRowSize * 2); 1.1309 + 1.1310 + void (*ARGB1555ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = 1.1311 + ARGB1555ToARGBRow_C; 1.1312 +#if defined(HAS_ARGB1555TOARGBROW_SSE2) 1.1313 + if (TestCpuFlag(kCpuHasSSE2) && width >= 8) { 1.1314 + ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2; 1.1315 + if (IS_ALIGNED(width, 8)) { 1.1316 + ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2; 1.1317 + } 1.1318 + } 1.1319 +#endif 1.1320 + void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, 1.1321 + uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; 1.1322 +#if defined(HAS_ARGBTOUVROW_SSSE3) 1.1323 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1.1324 + ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1.1325 + if (IS_ALIGNED(width, 16)) { 1.1326 + ARGBToUVRow = ARGBToUVRow_SSSE3; 1.1327 + } 1.1328 + } 1.1329 +#endif 1.1330 + void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) = 1.1331 + ARGBToYRow_C; 1.1332 +#if defined(HAS_ARGBTOUVROW_SSSE3) 1.1333 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1.1334 + ARGBToYRow = ARGBToYRow_Any_SSSE3; 1.1335 + if (IS_ALIGNED(width, 16)) { 1.1336 + ARGBToYRow = ARGBToYRow_Unaligned_SSSE3; 1.1337 + if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 1.1338 + ARGBToYRow = ARGBToYRow_SSSE3; 1.1339 + } 1.1340 + } 1.1341 + } 1.1342 +#endif // HAS_ARGBTOUVROW_SSSE3 1.1343 +#endif // HAS_ARGB1555TOYROW_NEON 1.1344 + 1.1345 + for (int y = 0; y < height - 1; y += 2) { 1.1346 +#if defined(HAS_ARGB1555TOYROW_NEON) 1.1347 + ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width); 1.1348 + ARGB1555ToYRow(src_argb1555, dst_y, width); 1.1349 + ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y, 1.1350 + width); 1.1351 +#else 1.1352 + ARGB1555ToARGBRow(src_argb1555, row, width); 1.1353 + ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize, 1.1354 + width); 1.1355 + ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1.1356 + ARGBToYRow(row, dst_y, width); 1.1357 + ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1.1358 +#endif 1.1359 + src_argb1555 += src_stride_argb1555 * 2; 1.1360 + dst_y += dst_stride_y * 2; 1.1361 + dst_u += dst_stride_u; 1.1362 + dst_v += dst_stride_v; 1.1363 + } 1.1364 + if (height & 1) { 1.1365 +#if defined(HAS_ARGB1555TOYROW_NEON) 1.1366 + ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width); 1.1367 + ARGB1555ToYRow(src_argb1555, dst_y, width); 1.1368 +#else 1.1369 + ARGB1555ToARGBRow(src_argb1555, row, width); 1.1370 + ARGBToUVRow(row, 0, dst_u, dst_v, width); 1.1371 + ARGBToYRow(row, dst_y, width); 1.1372 +#endif 1.1373 + } 1.1374 +#if !defined(HAS_ARGB1555TOYROW_NEON) 1.1375 + free_aligned_buffer_64(row); 1.1376 +#endif 1.1377 + return 0; 1.1378 +} 1.1379 + 1.1380 +// Convert ARGB4444 to I420. 1.1381 +LIBYUV_API 1.1382 +int ARGB4444ToI420(const uint8* src_argb4444, int src_stride_argb4444, 1.1383 + uint8* dst_y, int dst_stride_y, 1.1384 + uint8* dst_u, int dst_stride_u, 1.1385 + uint8* dst_v, int dst_stride_v, 1.1386 + int width, int height) { 1.1387 + if (!src_argb4444 || !dst_y || !dst_u || !dst_v || 1.1388 + width <= 0 || height == 0) { 1.1389 + return -1; 1.1390 + } 1.1391 + // Negative height means invert the image. 1.1392 + if (height < 0) { 1.1393 + height = -height; 1.1394 + src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444; 1.1395 + src_stride_argb4444 = -src_stride_argb4444; 1.1396 + } 1.1397 + 1.1398 +#if defined(HAS_ARGB4444TOYROW_NEON) 1.1399 + void (*ARGB4444ToUVRow)(const uint8* src_argb4444, int src_stride_argb4444, 1.1400 + uint8* dst_u, uint8* dst_v, int width) = ARGB4444ToUVRow_C; 1.1401 + void (*ARGB4444ToYRow)(const uint8* src_argb4444, uint8* dst_y, int pix) = 1.1402 + ARGB4444ToYRow_C; 1.1403 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.1404 + ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON; 1.1405 + if (IS_ALIGNED(width, 8)) { 1.1406 + ARGB4444ToYRow = ARGB4444ToYRow_NEON; 1.1407 + } 1.1408 + if (width >= 16) { 1.1409 + ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON; 1.1410 + if (IS_ALIGNED(width, 16)) { 1.1411 + ARGB4444ToUVRow = ARGB4444ToUVRow_NEON; 1.1412 + } 1.1413 + } 1.1414 + } 1.1415 +#else // HAS_ARGB4444TOYROW_NEON 1.1416 + 1.1417 + // Allocate 2 rows of ARGB. 1.1418 + const int kRowSize = (width * 4 + 15) & ~15; 1.1419 + align_buffer_64(row, kRowSize * 2); 1.1420 + 1.1421 + void (*ARGB4444ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = 1.1422 + ARGB4444ToARGBRow_C; 1.1423 +#if defined(HAS_ARGB4444TOARGBROW_SSE2) 1.1424 + if (TestCpuFlag(kCpuHasSSE2) && width >= 8) { 1.1425 + ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2; 1.1426 + if (IS_ALIGNED(width, 8)) { 1.1427 + ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2; 1.1428 + } 1.1429 + } 1.1430 +#endif 1.1431 + void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, 1.1432 + uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; 1.1433 +#if defined(HAS_ARGBTOUVROW_SSSE3) 1.1434 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1.1435 + ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1.1436 + if (IS_ALIGNED(width, 16)) { 1.1437 + ARGBToUVRow = ARGBToUVRow_SSSE3; 1.1438 + } 1.1439 + } 1.1440 +#endif 1.1441 + void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) = 1.1442 + ARGBToYRow_C; 1.1443 +#if defined(HAS_ARGBTOUVROW_SSSE3) 1.1444 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1.1445 + ARGBToYRow = ARGBToYRow_Any_SSSE3; 1.1446 + if (IS_ALIGNED(width, 16)) { 1.1447 + ARGBToYRow = ARGBToYRow_Unaligned_SSSE3; 1.1448 + if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 1.1449 + ARGBToYRow = ARGBToYRow_SSSE3; 1.1450 + } 1.1451 + } 1.1452 + } 1.1453 +#endif // HAS_ARGBTOUVROW_SSSE3 1.1454 +#endif // HAS_ARGB4444TOYROW_NEON 1.1455 + 1.1456 + for (int y = 0; y < height - 1; y += 2) { 1.1457 +#if defined(HAS_ARGB4444TOYROW_NEON) 1.1458 + ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width); 1.1459 + ARGB4444ToYRow(src_argb4444, dst_y, width); 1.1460 + ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y, 1.1461 + width); 1.1462 +#else 1.1463 + ARGB4444ToARGBRow(src_argb4444, row, width); 1.1464 + ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kRowSize, 1.1465 + width); 1.1466 + ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1.1467 + ARGBToYRow(row, dst_y, width); 1.1468 + ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1.1469 +#endif 1.1470 + src_argb4444 += src_stride_argb4444 * 2; 1.1471 + dst_y += dst_stride_y * 2; 1.1472 + dst_u += dst_stride_u; 1.1473 + dst_v += dst_stride_v; 1.1474 + } 1.1475 + if (height & 1) { 1.1476 +#if defined(HAS_ARGB4444TOYROW_NEON) 1.1477 + ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width); 1.1478 + ARGB4444ToYRow(src_argb4444, dst_y, width); 1.1479 +#else 1.1480 + ARGB4444ToARGBRow(src_argb4444, row, width); 1.1481 + ARGBToUVRow(row, 0, dst_u, dst_v, width); 1.1482 + ARGBToYRow(row, dst_y, width); 1.1483 +#endif 1.1484 + } 1.1485 +#if !defined(HAS_ARGB4444TOYROW_NEON) 1.1486 + free_aligned_buffer_64(row); 1.1487 +#endif 1.1488 + return 0; 1.1489 +} 1.1490 + 1.1491 +#ifdef __cplusplus 1.1492 +} // extern "C" 1.1493 +} // namespace libyuv 1.1494 +#endif