1/* 2 * Copyright 2011 The LibYuv Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#include "libyuv/convert.h" 12 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" 19 20#ifdef __cplusplus 21namespace libyuv { 22extern "C" { 23#endif 24 25#define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s) 26static __inline int Abs(int v) { 27 return v >= 0 ? v : -v; 28} 29 30// Any I4xx To I420 format with mirroring. 31static 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} 58 59// Copy I420 with optional flipping 60// TODO(fbarchard): Use Scale plane which supports mirroring, but ensure 61// is does row coalescing. 62LIBYUV_API 63int 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 } 86 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} 97 98// 422 chroma is 1/2 width, 1x height 99// 420 chroma is 1/2 width, 1/2 height 100LIBYUV_API 101int 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} 118 119// 444 chroma is 1x width, 1x height 120// 420 chroma is 1/2 width, 1/2 height 121LIBYUV_API 122int 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} 138 139// 411 chroma is 1/4 width, 1x height 140// 420 chroma is 1/2 width, 1/2 height 141LIBYUV_API 142int 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} 159 160// I400 is greyscale typically used in MJPG 161LIBYUV_API 162int 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} 184 185static 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 217 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} 229 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. 239static 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 324 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 } 333 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} 343 344// Convert NV12 to I420. 345LIBYUV_API 346int 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} 359 360// Convert NV21 to I420. Same as NV12 but u and v pointers swapped. 361LIBYUV_API 362int 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} 375 376// Convert M420 to I420. 377LIBYUV_API 378int 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} 390 391// Convert Q420 to I420. 392// Format is rows of YY/YUYV 393LIBYUV_API 394int 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 445 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 488 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; 493 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} 507 508// Convert YUY2 to I420. 509LIBYUV_API 510int 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 565 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} 581 582// Convert UYVY to I420. 583LIBYUV_API 584int 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 639 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} 655 656// Convert ARGB to I420. 657LIBYUV_API 658int 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 718 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} 734 735// Convert BGRA to I420. 736LIBYUV_API 737int 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 786 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} 802 803// Convert ABGR to I420. 804LIBYUV_API 805int 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 854 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} 870 871// Convert RGBA to I420. 872LIBYUV_API 873int 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 922 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} 938 939// Convert RGB24 to I420. 940LIBYUV_API 941int 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 } 956 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 975 976 // Allocate 2 rows of ARGB. 977 const int kRowSize = (width * 4 + 15) & ~15; 978 align_buffer_64(row, kRowSize * 2); 979 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; 1009 } 1010 } 1011 } 1012#endif // HAS_ARGBTOUVROW_SSSE3 1013#endif // HAS_RGB24TOYROW_NEON 1014 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; 1031 } 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 1041 } 1042#if !defined(HAS_RGB24TOYROW_NEON) 1043 free_aligned_buffer_64(row); 1044#endif 1045 return 0; 1046} 1047 1048// Convert RAW to I420. 1049LIBYUV_API 1050int 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; 1058 } 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; 1064 } 1065 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; 1075 } 1076 if (width >= 16) { 1077 RAWToUVRow = RAWToUVRow_Any_NEON; 1078 if (IS_ALIGNED(width, 16)) { 1079 RAWToUVRow = RAWToUVRow_NEON; 1080 } 1081 } 1082 } 1083#else // HAS_RAWTOYROW_NEON 1084 1085 // Allocate 2 rows of ARGB. 1086 const int kRowSize = (width * 4 + 15) & ~15; 1087 align_buffer_64(row, kRowSize * 2); 1088 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; 1096 } 1097 } 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; 1106 } 1107 } 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; 1118 } 1119 } 1120 } 1121#endif // HAS_ARGBTOUVROW_SSSE3 1122#endif // HAS_RAWTOYROW_NEON 1123 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; 1140 } 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 1150 } 1151#if !defined(HAS_RAWTOYROW_NEON) 1152 free_aligned_buffer_64(row); 1153#endif 1154 return 0; 1155} 1156 1157// Convert RGB565 to I420. 1158LIBYUV_API 1159int 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; 1167 } 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; 1173 } 1174 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; 1184 } 1185 if (width >= 16) { 1186 RGB565ToUVRow = RGB565ToUVRow_Any_NEON; 1187 if (IS_ALIGNED(width, 16)) { 1188 RGB565ToUVRow = RGB565ToUVRow_NEON; 1189 } 1190 } 1191 } 1192#else // HAS_RGB565TOYROW_NEON 1193 1194 // Allocate 2 rows of ARGB. 1195 const int kRowSize = (width * 4 + 15) & ~15; 1196 align_buffer_64(row, kRowSize * 2); 1197 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; 1205 } 1206 } 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; 1215 } 1216 } 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; 1227 } 1228 } 1229 } 1230#endif // HAS_ARGBTOUVROW_SSSE3 1231#endif // HAS_RGB565TOYROW_NEON 1232 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; 1249 } 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 1259 } 1260#if !defined(HAS_RGB565TOYROW_NEON) 1261 free_aligned_buffer_64(row); 1262#endif 1263 return 0; 1264} 1265 1266// Convert ARGB1555 to I420. 1267LIBYUV_API 1268int 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; 1276 } 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; 1282 } 1283 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; 1293 } 1294 if (width >= 16) { 1295 ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON; 1296 if (IS_ALIGNED(width, 16)) { 1297 ARGB1555ToUVRow = ARGB1555ToUVRow_NEON; 1298 } 1299 } 1300 } 1301#else // HAS_ARGB1555TOYROW_NEON 1302 1303 // Allocate 2 rows of ARGB. 1304 const int kRowSize = (width * 4 + 15) & ~15; 1305 align_buffer_64(row, kRowSize * 2); 1306 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; 1314 } 1315 } 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; 1324 } 1325 } 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; 1336 } 1337 } 1338 } 1339#endif // HAS_ARGBTOUVROW_SSSE3 1340#endif // HAS_ARGB1555TOYROW_NEON 1341 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; 1360 } 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 1370 } 1371#if !defined(HAS_ARGB1555TOYROW_NEON) 1372 free_aligned_buffer_64(row); 1373#endif 1374 return 0; 1375} 1376 1377// Convert ARGB4444 to I420. 1378LIBYUV_API 1379int 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; 1387 } 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; 1393 } 1394 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; 1404 } 1405 if (width >= 16) { 1406 ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON; 1407 if (IS_ALIGNED(width, 16)) { 1408 ARGB4444ToUVRow = ARGB4444ToUVRow_NEON; 1409 } 1410 } 1411 } 1412#else // HAS_ARGB4444TOYROW_NEON 1413 1414 // Allocate 2 rows of ARGB. 1415 const int kRowSize = (width * 4 + 15) & ~15; 1416 align_buffer_64(row, kRowSize * 2); 1417 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; 1425 } 1426 } 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; 1435 } 1436 } 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; 1447 } 1448 } 1449 } 1450#endif // HAS_ARGBTOUVROW_SSSE3 1451#endif // HAS_ARGB4444TOYROW_NEON 1452 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; 1471 } 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 1481 } 1482#if !defined(HAS_ARGB4444TOYROW_NEON) 1483 free_aligned_buffer_64(row); 1484#endif 1485 return 0; 1486} 1487 1488#ifdef __cplusplus 1489} // extern "C" 1490} // namespace libyuv 1491#endif 1492