1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/libyuv/source/convert_argb.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,901 @@ 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_argb.h" 1.15 + 1.16 +#include "libyuv/cpu_id.h" 1.17 +#include "libyuv/format_conversion.h" 1.18 +#ifdef HAVE_JPEG 1.19 +#include "libyuv/mjpeg_decoder.h" 1.20 +#endif 1.21 +#include "libyuv/rotate_argb.h" 1.22 +#include "libyuv/row.h" 1.23 +#include "libyuv/video_common.h" 1.24 + 1.25 +#ifdef __cplusplus 1.26 +namespace libyuv { 1.27 +extern "C" { 1.28 +#endif 1.29 + 1.30 +// Copy ARGB with optional flipping 1.31 +LIBYUV_API 1.32 +int ARGBCopy(const uint8* src_argb, int src_stride_argb, 1.33 + uint8* dst_argb, int dst_stride_argb, 1.34 + int width, int height) { 1.35 + if (!src_argb || !dst_argb || 1.36 + width <= 0 || height == 0) { 1.37 + return -1; 1.38 + } 1.39 + // Negative height means invert the image. 1.40 + if (height < 0) { 1.41 + height = -height; 1.42 + src_argb = src_argb + (height - 1) * src_stride_argb; 1.43 + src_stride_argb = -src_stride_argb; 1.44 + } 1.45 + 1.46 + CopyPlane(src_argb, src_stride_argb, dst_argb, dst_stride_argb, 1.47 + width * 4, height); 1.48 + return 0; 1.49 +} 1.50 + 1.51 +// Convert I444 to ARGB. 1.52 +LIBYUV_API 1.53 +int I444ToARGB(const uint8* src_y, int src_stride_y, 1.54 + const uint8* src_u, int src_stride_u, 1.55 + const uint8* src_v, int src_stride_v, 1.56 + uint8* dst_argb, int dst_stride_argb, 1.57 + int width, int height) { 1.58 + if (!src_y || !src_u || !src_v || 1.59 + !dst_argb || 1.60 + width <= 0 || height == 0) { 1.61 + return -1; 1.62 + } 1.63 + // Negative height means invert the image. 1.64 + if (height < 0) { 1.65 + height = -height; 1.66 + dst_argb = dst_argb + (height - 1) * dst_stride_argb; 1.67 + dst_stride_argb = -dst_stride_argb; 1.68 + } 1.69 + // Coalesce rows. 1.70 + if (src_stride_y == width && 1.71 + src_stride_u == width && 1.72 + src_stride_v == width && 1.73 + dst_stride_argb == width * 4) { 1.74 + width *= height; 1.75 + height = 1; 1.76 + src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0; 1.77 + } 1.78 + void (*I444ToARGBRow)(const uint8* y_buf, 1.79 + const uint8* u_buf, 1.80 + const uint8* v_buf, 1.81 + uint8* rgb_buf, 1.82 + int width) = I444ToARGBRow_C; 1.83 +#if defined(HAS_I444TOARGBROW_SSSE3) 1.84 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 1.85 + I444ToARGBRow = I444ToARGBRow_Any_SSSE3; 1.86 + if (IS_ALIGNED(width, 8)) { 1.87 + I444ToARGBRow = I444ToARGBRow_Unaligned_SSSE3; 1.88 + if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 1.89 + I444ToARGBRow = I444ToARGBRow_SSSE3; 1.90 + } 1.91 + } 1.92 + } 1.93 +#elif defined(HAS_I444TOARGBROW_NEON) 1.94 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.95 + I444ToARGBRow = I444ToARGBRow_Any_NEON; 1.96 + if (IS_ALIGNED(width, 8)) { 1.97 + I444ToARGBRow = I444ToARGBRow_NEON; 1.98 + } 1.99 + } 1.100 +#endif 1.101 + 1.102 + for (int y = 0; y < height; ++y) { 1.103 + I444ToARGBRow(src_y, src_u, src_v, dst_argb, width); 1.104 + dst_argb += dst_stride_argb; 1.105 + src_y += src_stride_y; 1.106 + src_u += src_stride_u; 1.107 + src_v += src_stride_v; 1.108 + } 1.109 + return 0; 1.110 +} 1.111 + 1.112 +// Convert I422 to ARGB. 1.113 +LIBYUV_API 1.114 +int I422ToARGB(const uint8* src_y, int src_stride_y, 1.115 + const uint8* src_u, int src_stride_u, 1.116 + const uint8* src_v, int src_stride_v, 1.117 + uint8* dst_argb, int dst_stride_argb, 1.118 + int width, int height) { 1.119 + if (!src_y || !src_u || !src_v || 1.120 + !dst_argb || 1.121 + width <= 0 || height == 0) { 1.122 + return -1; 1.123 + } 1.124 + // Negative height means invert the image. 1.125 + if (height < 0) { 1.126 + height = -height; 1.127 + dst_argb = dst_argb + (height - 1) * dst_stride_argb; 1.128 + dst_stride_argb = -dst_stride_argb; 1.129 + } 1.130 + // Coalesce rows. 1.131 + if (src_stride_y == width && 1.132 + src_stride_u * 2 == width && 1.133 + src_stride_v * 2 == width && 1.134 + dst_stride_argb == width * 4) { 1.135 + width *= height; 1.136 + height = 1; 1.137 + src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0; 1.138 + } 1.139 + void (*I422ToARGBRow)(const uint8* y_buf, 1.140 + const uint8* u_buf, 1.141 + const uint8* v_buf, 1.142 + uint8* rgb_buf, 1.143 + int width) = I422ToARGBRow_C; 1.144 +#if defined(HAS_I422TOARGBROW_SSSE3) 1.145 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 1.146 + I422ToARGBRow = I422ToARGBRow_Any_SSSE3; 1.147 + if (IS_ALIGNED(width, 8)) { 1.148 + I422ToARGBRow = I422ToARGBRow_Unaligned_SSSE3; 1.149 + if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 1.150 + I422ToARGBRow = I422ToARGBRow_SSSE3; 1.151 + } 1.152 + } 1.153 + } 1.154 +#endif 1.155 +#if defined(HAS_I422TOARGBROW_AVX2) 1.156 + if (TestCpuFlag(kCpuHasAVX2) && width >= 16) { 1.157 + I422ToARGBRow = I422ToARGBRow_Any_AVX2; 1.158 + if (IS_ALIGNED(width, 16)) { 1.159 + I422ToARGBRow = I422ToARGBRow_AVX2; 1.160 + } 1.161 + } 1.162 +#endif 1.163 +#if defined(HAS_I422TOARGBROW_NEON) 1.164 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.165 + I422ToARGBRow = I422ToARGBRow_Any_NEON; 1.166 + if (IS_ALIGNED(width, 8)) { 1.167 + I422ToARGBRow = I422ToARGBRow_NEON; 1.168 + } 1.169 + } 1.170 +#endif 1.171 +#if defined(HAS_I422TOARGBROW_MIPS_DSPR2) 1.172 + if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) && 1.173 + IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) && 1.174 + IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) && 1.175 + IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) && 1.176 + IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) { 1.177 + I422ToARGBRow = I422ToARGBRow_MIPS_DSPR2; 1.178 + } 1.179 +#endif 1.180 + 1.181 + for (int y = 0; y < height; ++y) { 1.182 + I422ToARGBRow(src_y, src_u, src_v, dst_argb, width); 1.183 + dst_argb += dst_stride_argb; 1.184 + src_y += src_stride_y; 1.185 + src_u += src_stride_u; 1.186 + src_v += src_stride_v; 1.187 + } 1.188 + return 0; 1.189 +} 1.190 + 1.191 +// Convert I411 to ARGB. 1.192 +LIBYUV_API 1.193 +int I411ToARGB(const uint8* src_y, int src_stride_y, 1.194 + const uint8* src_u, int src_stride_u, 1.195 + const uint8* src_v, int src_stride_v, 1.196 + uint8* dst_argb, int dst_stride_argb, 1.197 + int width, int height) { 1.198 + if (!src_y || !src_u || !src_v || 1.199 + !dst_argb || 1.200 + width <= 0 || height == 0) { 1.201 + return -1; 1.202 + } 1.203 + // Negative height means invert the image. 1.204 + if (height < 0) { 1.205 + height = -height; 1.206 + dst_argb = dst_argb + (height - 1) * dst_stride_argb; 1.207 + dst_stride_argb = -dst_stride_argb; 1.208 + } 1.209 + // Coalesce rows. 1.210 + if (src_stride_y == width && 1.211 + src_stride_u * 4 == width && 1.212 + src_stride_v * 4 == width && 1.213 + dst_stride_argb == width * 4) { 1.214 + width *= height; 1.215 + height = 1; 1.216 + src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0; 1.217 + } 1.218 + void (*I411ToARGBRow)(const uint8* y_buf, 1.219 + const uint8* u_buf, 1.220 + const uint8* v_buf, 1.221 + uint8* rgb_buf, 1.222 + int width) = I411ToARGBRow_C; 1.223 +#if defined(HAS_I411TOARGBROW_SSSE3) 1.224 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 1.225 + I411ToARGBRow = I411ToARGBRow_Any_SSSE3; 1.226 + if (IS_ALIGNED(width, 8)) { 1.227 + I411ToARGBRow = I411ToARGBRow_Unaligned_SSSE3; 1.228 + if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 1.229 + I411ToARGBRow = I411ToARGBRow_SSSE3; 1.230 + } 1.231 + } 1.232 + } 1.233 +#elif defined(HAS_I411TOARGBROW_NEON) 1.234 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.235 + I411ToARGBRow = I411ToARGBRow_Any_NEON; 1.236 + if (IS_ALIGNED(width, 8)) { 1.237 + I411ToARGBRow = I411ToARGBRow_NEON; 1.238 + } 1.239 + } 1.240 +#endif 1.241 + 1.242 + for (int y = 0; y < height; ++y) { 1.243 + I411ToARGBRow(src_y, src_u, src_v, dst_argb, width); 1.244 + dst_argb += dst_stride_argb; 1.245 + src_y += src_stride_y; 1.246 + src_u += src_stride_u; 1.247 + src_v += src_stride_v; 1.248 + } 1.249 + return 0; 1.250 +} 1.251 + 1.252 +// Convert I400 to ARGB. 1.253 +LIBYUV_API 1.254 +int I400ToARGB_Reference(const uint8* src_y, int src_stride_y, 1.255 + uint8* dst_argb, int dst_stride_argb, 1.256 + int width, int height) { 1.257 + if (!src_y || !dst_argb || 1.258 + width <= 0 || height == 0) { 1.259 + return -1; 1.260 + } 1.261 + // Negative height means invert the image. 1.262 + if (height < 0) { 1.263 + height = -height; 1.264 + dst_argb = dst_argb + (height - 1) * dst_stride_argb; 1.265 + dst_stride_argb = -dst_stride_argb; 1.266 + } 1.267 + // Coalesce rows. 1.268 + if (src_stride_y == width && 1.269 + dst_stride_argb == width * 4) { 1.270 + width *= height; 1.271 + height = 1; 1.272 + src_stride_y = dst_stride_argb = 0; 1.273 + } 1.274 + void (*YToARGBRow)(const uint8* y_buf, 1.275 + uint8* rgb_buf, 1.276 + int width) = YToARGBRow_C; 1.277 +#if defined(HAS_YTOARGBROW_SSE2) 1.278 + if (TestCpuFlag(kCpuHasSSE2) && width >= 8 && 1.279 + IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 1.280 + YToARGBRow = YToARGBRow_Any_SSE2; 1.281 + if (IS_ALIGNED(width, 8)) { 1.282 + YToARGBRow = YToARGBRow_SSE2; 1.283 + } 1.284 + } 1.285 +#elif defined(HAS_YTOARGBROW_NEON) 1.286 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.287 + YToARGBRow = YToARGBRow_Any_NEON; 1.288 + if (IS_ALIGNED(width, 8)) { 1.289 + YToARGBRow = YToARGBRow_NEON; 1.290 + } 1.291 + } 1.292 +#endif 1.293 + 1.294 + for (int y = 0; y < height; ++y) { 1.295 + YToARGBRow(src_y, dst_argb, width); 1.296 + dst_argb += dst_stride_argb; 1.297 + src_y += src_stride_y; 1.298 + } 1.299 + return 0; 1.300 +} 1.301 + 1.302 +// Convert I400 to ARGB. 1.303 +LIBYUV_API 1.304 +int I400ToARGB(const uint8* src_y, int src_stride_y, 1.305 + uint8* dst_argb, int dst_stride_argb, 1.306 + int width, int height) { 1.307 + if (!src_y || !dst_argb || 1.308 + width <= 0 || height == 0) { 1.309 + return -1; 1.310 + } 1.311 + // Negative height means invert the image. 1.312 + if (height < 0) { 1.313 + height = -height; 1.314 + src_y = src_y + (height - 1) * src_stride_y; 1.315 + src_stride_y = -src_stride_y; 1.316 + } 1.317 + // Coalesce rows. 1.318 + if (src_stride_y == width && 1.319 + dst_stride_argb == width * 4) { 1.320 + width *= height; 1.321 + height = 1; 1.322 + src_stride_y = dst_stride_argb = 0; 1.323 + } 1.324 + void (*I400ToARGBRow)(const uint8* src_y, uint8* dst_argb, int pix) = 1.325 + I400ToARGBRow_C; 1.326 +#if defined(HAS_I400TOARGBROW_SSE2) 1.327 + if (TestCpuFlag(kCpuHasSSE2) && width >= 8) { 1.328 + I400ToARGBRow = I400ToARGBRow_Any_SSE2; 1.329 + if (IS_ALIGNED(width, 8)) { 1.330 + I400ToARGBRow = I400ToARGBRow_Unaligned_SSE2; 1.331 + if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 1.332 + I400ToARGBRow = I400ToARGBRow_SSE2; 1.333 + } 1.334 + } 1.335 + } 1.336 +#elif defined(HAS_I400TOARGBROW_NEON) 1.337 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.338 + I400ToARGBRow = I400ToARGBRow_Any_NEON; 1.339 + if (IS_ALIGNED(width, 8)) { 1.340 + I400ToARGBRow = I400ToARGBRow_NEON; 1.341 + } 1.342 + } 1.343 +#endif 1.344 + for (int y = 0; y < height; ++y) { 1.345 + I400ToARGBRow(src_y, dst_argb, width); 1.346 + src_y += src_stride_y; 1.347 + dst_argb += dst_stride_argb; 1.348 + } 1.349 + return 0; 1.350 +} 1.351 + 1.352 +// Shuffle table for converting BGRA to ARGB. 1.353 +static uvec8 kShuffleMaskBGRAToARGB = { 1.354 + 3u, 2u, 1u, 0u, 7u, 6u, 5u, 4u, 11u, 10u, 9u, 8u, 15u, 14u, 13u, 12u 1.355 +}; 1.356 + 1.357 +// Shuffle table for converting ABGR to ARGB. 1.358 +static uvec8 kShuffleMaskABGRToARGB = { 1.359 + 2u, 1u, 0u, 3u, 6u, 5u, 4u, 7u, 10u, 9u, 8u, 11u, 14u, 13u, 12u, 15u 1.360 +}; 1.361 + 1.362 +// Shuffle table for converting RGBA to ARGB. 1.363 +static uvec8 kShuffleMaskRGBAToARGB = { 1.364 + 1u, 2u, 3u, 0u, 5u, 6u, 7u, 4u, 9u, 10u, 11u, 8u, 13u, 14u, 15u, 12u 1.365 +}; 1.366 + 1.367 +// Convert BGRA to ARGB. 1.368 +LIBYUV_API 1.369 +int BGRAToARGB(const uint8* src_bgra, int src_stride_bgra, 1.370 + uint8* dst_argb, int dst_stride_argb, 1.371 + int width, int height) { 1.372 + return ARGBShuffle(src_bgra, src_stride_bgra, 1.373 + dst_argb, dst_stride_argb, 1.374 + (const uint8*)(&kShuffleMaskBGRAToARGB), 1.375 + width, height); 1.376 +} 1.377 + 1.378 +// Convert ABGR to ARGB. 1.379 +LIBYUV_API 1.380 +int ABGRToARGB(const uint8* src_abgr, int src_stride_abgr, 1.381 + uint8* dst_argb, int dst_stride_argb, 1.382 + int width, int height) { 1.383 + return ARGBShuffle(src_abgr, src_stride_abgr, 1.384 + dst_argb, dst_stride_argb, 1.385 + (const uint8*)(&kShuffleMaskABGRToARGB), 1.386 + width, height); 1.387 +} 1.388 + 1.389 +// Convert RGBA to ARGB. 1.390 +LIBYUV_API 1.391 +int RGBAToARGB(const uint8* src_rgba, int src_stride_rgba, 1.392 + uint8* dst_argb, int dst_stride_argb, 1.393 + int width, int height) { 1.394 + return ARGBShuffle(src_rgba, src_stride_rgba, 1.395 + dst_argb, dst_stride_argb, 1.396 + (const uint8*)(&kShuffleMaskRGBAToARGB), 1.397 + width, height); 1.398 +} 1.399 + 1.400 +// Convert RGB24 to ARGB. 1.401 +LIBYUV_API 1.402 +int RGB24ToARGB(const uint8* src_rgb24, int src_stride_rgb24, 1.403 + uint8* dst_argb, int dst_stride_argb, 1.404 + int width, int height) { 1.405 + if (!src_rgb24 || !dst_argb || 1.406 + width <= 0 || height == 0) { 1.407 + return -1; 1.408 + } 1.409 + // Negative height means invert the image. 1.410 + if (height < 0) { 1.411 + height = -height; 1.412 + src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24; 1.413 + src_stride_rgb24 = -src_stride_rgb24; 1.414 + } 1.415 + // Coalesce rows. 1.416 + if (src_stride_rgb24 == width * 3 && 1.417 + dst_stride_argb == width * 4) { 1.418 + width *= height; 1.419 + height = 1; 1.420 + src_stride_rgb24 = dst_stride_argb = 0; 1.421 + } 1.422 + void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = 1.423 + RGB24ToARGBRow_C; 1.424 +#if defined(HAS_RGB24TOARGBROW_SSSE3) 1.425 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 16 && 1.426 + IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 1.427 + RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3; 1.428 + if (IS_ALIGNED(width, 16)) { 1.429 + RGB24ToARGBRow = RGB24ToARGBRow_SSSE3; 1.430 + } 1.431 + } 1.432 +#elif defined(HAS_RGB24TOARGBROW_NEON) 1.433 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.434 + RGB24ToARGBRow = RGB24ToARGBRow_Any_NEON; 1.435 + if (IS_ALIGNED(width, 8)) { 1.436 + RGB24ToARGBRow = RGB24ToARGBRow_NEON; 1.437 + } 1.438 + } 1.439 +#endif 1.440 + 1.441 + for (int y = 0; y < height; ++y) { 1.442 + RGB24ToARGBRow(src_rgb24, dst_argb, width); 1.443 + src_rgb24 += src_stride_rgb24; 1.444 + dst_argb += dst_stride_argb; 1.445 + } 1.446 + return 0; 1.447 +} 1.448 + 1.449 +// Convert RAW to ARGB. 1.450 +LIBYUV_API 1.451 +int RAWToARGB(const uint8* src_raw, int src_stride_raw, 1.452 + uint8* dst_argb, int dst_stride_argb, 1.453 + int width, int height) { 1.454 + if (!src_raw || !dst_argb || 1.455 + width <= 0 || height == 0) { 1.456 + return -1; 1.457 + } 1.458 + // Negative height means invert the image. 1.459 + if (height < 0) { 1.460 + height = -height; 1.461 + src_raw = src_raw + (height - 1) * src_stride_raw; 1.462 + src_stride_raw = -src_stride_raw; 1.463 + } 1.464 + // Coalesce rows. 1.465 + if (src_stride_raw == width * 3 && 1.466 + dst_stride_argb == width * 4) { 1.467 + width *= height; 1.468 + height = 1; 1.469 + src_stride_raw = dst_stride_argb = 0; 1.470 + } 1.471 + void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = 1.472 + RAWToARGBRow_C; 1.473 +#if defined(HAS_RAWTOARGBROW_SSSE3) 1.474 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 16 && 1.475 + IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 1.476 + RAWToARGBRow = RAWToARGBRow_Any_SSSE3; 1.477 + if (IS_ALIGNED(width, 16)) { 1.478 + RAWToARGBRow = RAWToARGBRow_SSSE3; 1.479 + } 1.480 + } 1.481 +#elif defined(HAS_RAWTOARGBROW_NEON) 1.482 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.483 + RAWToARGBRow = RAWToARGBRow_Any_NEON; 1.484 + if (IS_ALIGNED(width, 8)) { 1.485 + RAWToARGBRow = RAWToARGBRow_NEON; 1.486 + } 1.487 + } 1.488 +#endif 1.489 + 1.490 + for (int y = 0; y < height; ++y) { 1.491 + RAWToARGBRow(src_raw, dst_argb, width); 1.492 + src_raw += src_stride_raw; 1.493 + dst_argb += dst_stride_argb; 1.494 + } 1.495 + return 0; 1.496 +} 1.497 + 1.498 +// Convert RGB565 to ARGB. 1.499 +LIBYUV_API 1.500 +int RGB565ToARGB(const uint8* src_rgb565, int src_stride_rgb565, 1.501 + uint8* dst_argb, int dst_stride_argb, 1.502 + int width, int height) { 1.503 + if (!src_rgb565 || !dst_argb || 1.504 + width <= 0 || height == 0) { 1.505 + return -1; 1.506 + } 1.507 + // Negative height means invert the image. 1.508 + if (height < 0) { 1.509 + height = -height; 1.510 + src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565; 1.511 + src_stride_rgb565 = -src_stride_rgb565; 1.512 + } 1.513 + // Coalesce rows. 1.514 + if (src_stride_rgb565 == width * 2 && 1.515 + dst_stride_argb == width * 4) { 1.516 + width *= height; 1.517 + height = 1; 1.518 + src_stride_rgb565 = dst_stride_argb = 0; 1.519 + } 1.520 + void (*RGB565ToARGBRow)(const uint8* src_rgb565, uint8* dst_argb, int pix) = 1.521 + RGB565ToARGBRow_C; 1.522 +#if defined(HAS_RGB565TOARGBROW_SSE2) 1.523 + if (TestCpuFlag(kCpuHasSSE2) && width >= 8 && 1.524 + IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 1.525 + RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2; 1.526 + if (IS_ALIGNED(width, 8)) { 1.527 + RGB565ToARGBRow = RGB565ToARGBRow_SSE2; 1.528 + } 1.529 + } 1.530 +#elif defined(HAS_RGB565TOARGBROW_NEON) 1.531 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.532 + RGB565ToARGBRow = RGB565ToARGBRow_Any_NEON; 1.533 + if (IS_ALIGNED(width, 8)) { 1.534 + RGB565ToARGBRow = RGB565ToARGBRow_NEON; 1.535 + } 1.536 + } 1.537 +#endif 1.538 + 1.539 + for (int y = 0; y < height; ++y) { 1.540 + RGB565ToARGBRow(src_rgb565, dst_argb, width); 1.541 + src_rgb565 += src_stride_rgb565; 1.542 + dst_argb += dst_stride_argb; 1.543 + } 1.544 + return 0; 1.545 +} 1.546 + 1.547 +// Convert ARGB1555 to ARGB. 1.548 +LIBYUV_API 1.549 +int ARGB1555ToARGB(const uint8* src_argb1555, int src_stride_argb1555, 1.550 + uint8* dst_argb, int dst_stride_argb, 1.551 + int width, int height) { 1.552 + if (!src_argb1555 || !dst_argb || 1.553 + width <= 0 || height == 0) { 1.554 + return -1; 1.555 + } 1.556 + // Negative height means invert the image. 1.557 + if (height < 0) { 1.558 + height = -height; 1.559 + src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555; 1.560 + src_stride_argb1555 = -src_stride_argb1555; 1.561 + } 1.562 + // Coalesce rows. 1.563 + if (src_stride_argb1555 == width * 2 && 1.564 + dst_stride_argb == width * 4) { 1.565 + width *= height; 1.566 + height = 1; 1.567 + src_stride_argb1555 = dst_stride_argb = 0; 1.568 + } 1.569 + void (*ARGB1555ToARGBRow)(const uint8* src_argb1555, uint8* dst_argb, 1.570 + int pix) = ARGB1555ToARGBRow_C; 1.571 +#if defined(HAS_ARGB1555TOARGBROW_SSE2) 1.572 + if (TestCpuFlag(kCpuHasSSE2) && width >= 8 && 1.573 + IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 1.574 + ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2; 1.575 + if (IS_ALIGNED(width, 8)) { 1.576 + ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2; 1.577 + } 1.578 + } 1.579 +#elif defined(HAS_ARGB1555TOARGBROW_NEON) 1.580 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.581 + ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_NEON; 1.582 + if (IS_ALIGNED(width, 8)) { 1.583 + ARGB1555ToARGBRow = ARGB1555ToARGBRow_NEON; 1.584 + } 1.585 + } 1.586 +#endif 1.587 + 1.588 + for (int y = 0; y < height; ++y) { 1.589 + ARGB1555ToARGBRow(src_argb1555, dst_argb, width); 1.590 + src_argb1555 += src_stride_argb1555; 1.591 + dst_argb += dst_stride_argb; 1.592 + } 1.593 + return 0; 1.594 +} 1.595 + 1.596 +// Convert ARGB4444 to ARGB. 1.597 +LIBYUV_API 1.598 +int ARGB4444ToARGB(const uint8* src_argb4444, int src_stride_argb4444, 1.599 + uint8* dst_argb, int dst_stride_argb, 1.600 + int width, int height) { 1.601 + if (!src_argb4444 || !dst_argb || 1.602 + width <= 0 || height == 0) { 1.603 + return -1; 1.604 + } 1.605 + // Negative height means invert the image. 1.606 + if (height < 0) { 1.607 + height = -height; 1.608 + src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444; 1.609 + src_stride_argb4444 = -src_stride_argb4444; 1.610 + } 1.611 + // Coalesce rows. 1.612 + if (src_stride_argb4444 == width * 2 && 1.613 + dst_stride_argb == width * 4) { 1.614 + width *= height; 1.615 + height = 1; 1.616 + src_stride_argb4444 = dst_stride_argb = 0; 1.617 + } 1.618 + void (*ARGB4444ToARGBRow)(const uint8* src_argb4444, uint8* dst_argb, 1.619 + int pix) = ARGB4444ToARGBRow_C; 1.620 +#if defined(HAS_ARGB4444TOARGBROW_SSE2) 1.621 + if (TestCpuFlag(kCpuHasSSE2) && width >= 8 && 1.622 + IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 1.623 + ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2; 1.624 + if (IS_ALIGNED(width, 8)) { 1.625 + ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2; 1.626 + } 1.627 + } 1.628 +#elif defined(HAS_ARGB4444TOARGBROW_NEON) 1.629 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.630 + ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_NEON; 1.631 + if (IS_ALIGNED(width, 8)) { 1.632 + ARGB4444ToARGBRow = ARGB4444ToARGBRow_NEON; 1.633 + } 1.634 + } 1.635 +#endif 1.636 + 1.637 + for (int y = 0; y < height; ++y) { 1.638 + ARGB4444ToARGBRow(src_argb4444, dst_argb, width); 1.639 + src_argb4444 += src_stride_argb4444; 1.640 + dst_argb += dst_stride_argb; 1.641 + } 1.642 + return 0; 1.643 +} 1.644 + 1.645 +// Convert NV12 to ARGB. 1.646 +LIBYUV_API 1.647 +int NV12ToARGB(const uint8* src_y, int src_stride_y, 1.648 + const uint8* src_uv, int src_stride_uv, 1.649 + uint8* dst_argb, int dst_stride_argb, 1.650 + int width, int height) { 1.651 + if (!src_y || !src_uv || !dst_argb || 1.652 + width <= 0 || height == 0) { 1.653 + return -1; 1.654 + } 1.655 + // Negative height means invert the image. 1.656 + if (height < 0) { 1.657 + height = -height; 1.658 + dst_argb = dst_argb + (height - 1) * dst_stride_argb; 1.659 + dst_stride_argb = -dst_stride_argb; 1.660 + } 1.661 + void (*NV12ToARGBRow)(const uint8* y_buf, 1.662 + const uint8* uv_buf, 1.663 + uint8* rgb_buf, 1.664 + int width) = NV12ToARGBRow_C; 1.665 +#if defined(HAS_NV12TOARGBROW_SSSE3) 1.666 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 1.667 + NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3; 1.668 + if (IS_ALIGNED(width, 8)) { 1.669 + NV12ToARGBRow = NV12ToARGBRow_Unaligned_SSSE3; 1.670 + if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 1.671 + NV12ToARGBRow = NV12ToARGBRow_SSSE3; 1.672 + } 1.673 + } 1.674 + } 1.675 +#elif defined(HAS_NV12TOARGBROW_NEON) 1.676 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.677 + NV12ToARGBRow = NV12ToARGBRow_Any_NEON; 1.678 + if (IS_ALIGNED(width, 8)) { 1.679 + NV12ToARGBRow = NV12ToARGBRow_NEON; 1.680 + } 1.681 + } 1.682 +#endif 1.683 + 1.684 + for (int y = 0; y < height; ++y) { 1.685 + NV12ToARGBRow(src_y, src_uv, dst_argb, width); 1.686 + dst_argb += dst_stride_argb; 1.687 + src_y += src_stride_y; 1.688 + if (y & 1) { 1.689 + src_uv += src_stride_uv; 1.690 + } 1.691 + } 1.692 + return 0; 1.693 +} 1.694 + 1.695 +// Convert NV21 to ARGB. 1.696 +LIBYUV_API 1.697 +int NV21ToARGB(const uint8* src_y, int src_stride_y, 1.698 + const uint8* src_uv, int src_stride_uv, 1.699 + uint8* dst_argb, int dst_stride_argb, 1.700 + int width, int height) { 1.701 + if (!src_y || !src_uv || !dst_argb || 1.702 + width <= 0 || height == 0) { 1.703 + return -1; 1.704 + } 1.705 + // Negative height means invert the image. 1.706 + if (height < 0) { 1.707 + height = -height; 1.708 + dst_argb = dst_argb + (height - 1) * dst_stride_argb; 1.709 + dst_stride_argb = -dst_stride_argb; 1.710 + } 1.711 + void (*NV21ToARGBRow)(const uint8* y_buf, 1.712 + const uint8* uv_buf, 1.713 + uint8* rgb_buf, 1.714 + int width) = NV21ToARGBRow_C; 1.715 +#if defined(HAS_NV21TOARGBROW_SSSE3) 1.716 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 1.717 + NV21ToARGBRow = NV21ToARGBRow_Any_SSSE3; 1.718 + if (IS_ALIGNED(width, 8)) { 1.719 + NV21ToARGBRow = NV21ToARGBRow_Unaligned_SSSE3; 1.720 + if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 1.721 + NV21ToARGBRow = NV21ToARGBRow_SSSE3; 1.722 + } 1.723 + } 1.724 + } 1.725 +#endif 1.726 +#if defined(HAS_NV21TOARGBROW_NEON) 1.727 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.728 + NV21ToARGBRow = NV21ToARGBRow_Any_NEON; 1.729 + if (IS_ALIGNED(width, 8)) { 1.730 + NV21ToARGBRow = NV21ToARGBRow_NEON; 1.731 + } 1.732 + } 1.733 +#endif 1.734 + 1.735 + for (int y = 0; y < height; ++y) { 1.736 + NV21ToARGBRow(src_y, src_uv, dst_argb, width); 1.737 + dst_argb += dst_stride_argb; 1.738 + src_y += src_stride_y; 1.739 + if (y & 1) { 1.740 + src_uv += src_stride_uv; 1.741 + } 1.742 + } 1.743 + return 0; 1.744 +} 1.745 + 1.746 +// Convert M420 to ARGB. 1.747 +LIBYUV_API 1.748 +int M420ToARGB(const uint8* src_m420, int src_stride_m420, 1.749 + uint8* dst_argb, int dst_stride_argb, 1.750 + int width, int height) { 1.751 + if (!src_m420 || !dst_argb || 1.752 + width <= 0 || height == 0) { 1.753 + return -1; 1.754 + } 1.755 + // Negative height means invert the image. 1.756 + if (height < 0) { 1.757 + height = -height; 1.758 + dst_argb = dst_argb + (height - 1) * dst_stride_argb; 1.759 + dst_stride_argb = -dst_stride_argb; 1.760 + } 1.761 + void (*NV12ToARGBRow)(const uint8* y_buf, 1.762 + const uint8* uv_buf, 1.763 + uint8* rgb_buf, 1.764 + int width) = NV12ToARGBRow_C; 1.765 +#if defined(HAS_NV12TOARGBROW_SSSE3) 1.766 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 1.767 + NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3; 1.768 + if (IS_ALIGNED(width, 8)) { 1.769 + NV12ToARGBRow = NV12ToARGBRow_Unaligned_SSSE3; 1.770 + if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 1.771 + NV12ToARGBRow = NV12ToARGBRow_SSSE3; 1.772 + } 1.773 + } 1.774 + } 1.775 +#elif defined(HAS_NV12TOARGBROW_NEON) 1.776 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.777 + NV12ToARGBRow = NV12ToARGBRow_Any_NEON; 1.778 + if (IS_ALIGNED(width, 8)) { 1.779 + NV12ToARGBRow = NV12ToARGBRow_NEON; 1.780 + } 1.781 + } 1.782 +#endif 1.783 + 1.784 + for (int y = 0; y < height - 1; y += 2) { 1.785 + NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb, width); 1.786 + NV12ToARGBRow(src_m420 + src_stride_m420, src_m420 + src_stride_m420 * 2, 1.787 + dst_argb + dst_stride_argb, width); 1.788 + dst_argb += dst_stride_argb * 2; 1.789 + src_m420 += src_stride_m420 * 3; 1.790 + } 1.791 + if (height & 1) { 1.792 + NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb, width); 1.793 + } 1.794 + return 0; 1.795 +} 1.796 + 1.797 +// Convert YUY2 to ARGB. 1.798 +LIBYUV_API 1.799 +int YUY2ToARGB(const uint8* src_yuy2, int src_stride_yuy2, 1.800 + uint8* dst_argb, int dst_stride_argb, 1.801 + int width, int height) { 1.802 + if (!src_yuy2 || !dst_argb || 1.803 + width <= 0 || height == 0) { 1.804 + return -1; 1.805 + } 1.806 + // Negative height means invert the image. 1.807 + if (height < 0) { 1.808 + height = -height; 1.809 + src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2; 1.810 + src_stride_yuy2 = -src_stride_yuy2; 1.811 + } 1.812 + // Coalesce rows. 1.813 + if (src_stride_yuy2 == width * 2 && 1.814 + dst_stride_argb == width * 4) { 1.815 + width *= height; 1.816 + height = 1; 1.817 + src_stride_yuy2 = dst_stride_argb = 0; 1.818 + } 1.819 + void (*YUY2ToARGBRow)(const uint8* src_yuy2, uint8* dst_argb, int pix) = 1.820 + YUY2ToARGBRow_C; 1.821 +#if defined(HAS_YUY2TOARGBROW_SSSE3) 1.822 + // Posix is 16, Windows is 8. 1.823 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1.824 + YUY2ToARGBRow = YUY2ToARGBRow_Any_SSSE3; 1.825 + if (IS_ALIGNED(width, 16)) { 1.826 + YUY2ToARGBRow = YUY2ToARGBRow_Unaligned_SSSE3; 1.827 + if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16) && 1.828 + IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 1.829 + YUY2ToARGBRow = YUY2ToARGBRow_SSSE3; 1.830 + } 1.831 + } 1.832 + } 1.833 +#elif defined(HAS_YUY2TOARGBROW_NEON) 1.834 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.835 + YUY2ToARGBRow = YUY2ToARGBRow_Any_NEON; 1.836 + if (IS_ALIGNED(width, 8)) { 1.837 + YUY2ToARGBRow = YUY2ToARGBRow_NEON; 1.838 + } 1.839 + } 1.840 +#endif 1.841 + for (int y = 0; y < height; ++y) { 1.842 + YUY2ToARGBRow(src_yuy2, dst_argb, width); 1.843 + src_yuy2 += src_stride_yuy2; 1.844 + dst_argb += dst_stride_argb; 1.845 + } 1.846 + return 0; 1.847 +} 1.848 + 1.849 +// Convert UYVY to ARGB. 1.850 +LIBYUV_API 1.851 +int UYVYToARGB(const uint8* src_uyvy, int src_stride_uyvy, 1.852 + uint8* dst_argb, int dst_stride_argb, 1.853 + int width, int height) { 1.854 + if (!src_uyvy || !dst_argb || 1.855 + width <= 0 || height == 0) { 1.856 + return -1; 1.857 + } 1.858 + // Negative height means invert the image. 1.859 + if (height < 0) { 1.860 + height = -height; 1.861 + src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy; 1.862 + src_stride_uyvy = -src_stride_uyvy; 1.863 + } 1.864 + // Coalesce rows. 1.865 + if (src_stride_uyvy == width * 2 && 1.866 + dst_stride_argb == width * 4) { 1.867 + width *= height; 1.868 + height = 1; 1.869 + src_stride_uyvy = dst_stride_argb = 0; 1.870 + } 1.871 + void (*UYVYToARGBRow)(const uint8* src_uyvy, uint8* dst_argb, int pix) = 1.872 + UYVYToARGBRow_C; 1.873 +#if defined(HAS_UYVYTOARGBROW_SSSE3) 1.874 + // Posix is 16, Windows is 8. 1.875 + if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1.876 + UYVYToARGBRow = UYVYToARGBRow_Any_SSSE3; 1.877 + if (IS_ALIGNED(width, 16)) { 1.878 + UYVYToARGBRow = UYVYToARGBRow_Unaligned_SSSE3; 1.879 + if (IS_ALIGNED(src_uyvy, 16) && IS_ALIGNED(src_stride_uyvy, 16) && 1.880 + IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 1.881 + UYVYToARGBRow = UYVYToARGBRow_SSSE3; 1.882 + } 1.883 + } 1.884 + } 1.885 +#elif defined(HAS_UYVYTOARGBROW_NEON) 1.886 + if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1.887 + UYVYToARGBRow = UYVYToARGBRow_Any_NEON; 1.888 + if (IS_ALIGNED(width, 8)) { 1.889 + UYVYToARGBRow = UYVYToARGBRow_NEON; 1.890 + } 1.891 + } 1.892 +#endif 1.893 + for (int y = 0; y < height; ++y) { 1.894 + UYVYToARGBRow(src_uyvy, dst_argb, width); 1.895 + src_uyvy += src_stride_uyvy; 1.896 + dst_argb += dst_stride_argb; 1.897 + } 1.898 + return 0; 1.899 +} 1.900 + 1.901 +#ifdef __cplusplus 1.902 +} // extern "C" 1.903 +} // namespace libyuv 1.904 +#endif