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/row.h" 18 #include "libyuv/scale.h" // For ScalePlane() 19 20 #ifdef __cplusplus 21 namespace libyuv { 22 extern "C" { 23 #endif 24 25 #define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s) 26 static __inline int Abs(int v) { 27 return v >= 0 ? v : -v; 28 } 29 30 // Any I4xx To I420 format with mirroring. 31 static int I4xxToI420(const uint8* src_y, 32 int src_stride_y, 33 const uint8* src_u, 34 int src_stride_u, 35 const uint8* src_v, 36 int src_stride_v, 37 uint8* dst_y, 38 int dst_stride_y, 39 uint8* dst_u, 40 int dst_stride_u, 41 uint8* dst_v, 42 int dst_stride_v, 43 int src_y_width, 44 int src_y_height, 45 int src_uv_width, 46 int src_uv_height) { 47 const int dst_y_width = Abs(src_y_width); 48 const int dst_y_height = Abs(src_y_height); 49 const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1); 50 const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1); 51 if (src_uv_width == 0 || src_uv_height == 0) { 52 return -1; 53 } 54 if (dst_y) { 55 ScalePlane(src_y, src_stride_y, src_y_width, src_y_height, dst_y, 56 dst_stride_y, dst_y_width, dst_y_height, kFilterBilinear); 57 } 58 ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u, 59 dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear); 60 ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height, dst_v, 61 dst_stride_v, dst_uv_width, dst_uv_height, kFilterBilinear); 62 return 0; 63 } 64 65 // Copy I420 with optional flipping 66 // TODO(fbarchard): Use Scale plane which supports mirroring, but ensure 67 // is does row coalescing. 68 LIBYUV_API 69 int I420Copy(const uint8* src_y, 70 int src_stride_y, 71 const uint8* src_u, 72 int src_stride_u, 73 const uint8* src_v, 74 int src_stride_v, 75 uint8* dst_y, 76 int dst_stride_y, 77 uint8* dst_u, 78 int dst_stride_u, 79 uint8* dst_v, 80 int dst_stride_v, 81 int width, 82 int height) { 83 int halfwidth = (width + 1) >> 1; 84 int halfheight = (height + 1) >> 1; 85 if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) { 86 return -1; 87 } 88 // Negative height means invert the image. 89 if (height < 0) { 90 height = -height; 91 halfheight = (height + 1) >> 1; 92 src_y = src_y + (height - 1) * src_stride_y; 93 src_u = src_u + (halfheight - 1) * src_stride_u; 94 src_v = src_v + (halfheight - 1) * src_stride_v; 95 src_stride_y = -src_stride_y; 96 src_stride_u = -src_stride_u; 97 src_stride_v = -src_stride_v; 98 } 99 100 if (dst_y) { 101 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); 102 } 103 // Copy UV planes. 104 CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight); 105 CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight); 106 return 0; 107 } 108 109 // 422 chroma is 1/2 width, 1x height 110 // 420 chroma is 1/2 width, 1/2 height 111 LIBYUV_API 112 int I422ToI420(const uint8* src_y, 113 int src_stride_y, 114 const uint8* src_u, 115 int src_stride_u, 116 const uint8* src_v, 117 int src_stride_v, 118 uint8* dst_y, 119 int dst_stride_y, 120 uint8* dst_u, 121 int dst_stride_u, 122 uint8* dst_v, 123 int dst_stride_v, 124 int width, 125 int height) { 126 const int src_uv_width = SUBSAMPLE(width, 1, 1); 127 return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v, 128 src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u, 129 dst_v, dst_stride_v, width, height, src_uv_width, height); 130 } 131 132 // 444 chroma is 1x width, 1x height 133 // 420 chroma is 1/2 width, 1/2 height 134 LIBYUV_API 135 int I444ToI420(const uint8* src_y, 136 int src_stride_y, 137 const uint8* src_u, 138 int src_stride_u, 139 const uint8* src_v, 140 int src_stride_v, 141 uint8* dst_y, 142 int dst_stride_y, 143 uint8* dst_u, 144 int dst_stride_u, 145 uint8* dst_v, 146 int dst_stride_v, 147 int width, 148 int height) { 149 return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v, 150 src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u, 151 dst_v, dst_stride_v, width, height, width, height); 152 } 153 154 // I400 is greyscale typically used in MJPG 155 LIBYUV_API 156 int I400ToI420(const uint8* src_y, 157 int src_stride_y, 158 uint8* dst_y, 159 int dst_stride_y, 160 uint8* dst_u, 161 int dst_stride_u, 162 uint8* dst_v, 163 int dst_stride_v, 164 int width, 165 int height) { 166 int halfwidth = (width + 1) >> 1; 167 int halfheight = (height + 1) >> 1; 168 if (!dst_u || !dst_v || width <= 0 || height == 0) { 169 return -1; 170 } 171 // Negative height means invert the image. 172 if (height < 0) { 173 height = -height; 174 halfheight = (height + 1) >> 1; 175 src_y = src_y + (height - 1) * src_stride_y; 176 src_stride_y = -src_stride_y; 177 } 178 if (dst_y) { 179 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); 180 } 181 SetPlane(dst_u, dst_stride_u, halfwidth, halfheight, 128); 182 SetPlane(dst_v, dst_stride_v, halfwidth, halfheight, 128); 183 return 0; 184 } 185 186 static void CopyPlane2(const uint8* src, 187 int src_stride_0, 188 int src_stride_1, 189 uint8* dst, 190 int dst_stride, 191 int width, 192 int height) { 193 int y; 194 void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C; 195 #if defined(HAS_COPYROW_SSE2) 196 if (TestCpuFlag(kCpuHasSSE2)) { 197 CopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2; 198 } 199 #endif 200 #if defined(HAS_COPYROW_AVX) 201 if (TestCpuFlag(kCpuHasAVX)) { 202 CopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX; 203 } 204 #endif 205 #if defined(HAS_COPYROW_ERMS) 206 if (TestCpuFlag(kCpuHasERMS)) { 207 CopyRow = CopyRow_ERMS; 208 } 209 #endif 210 #if defined(HAS_COPYROW_NEON) 211 if (TestCpuFlag(kCpuHasNEON)) { 212 CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON; 213 } 214 #endif 215 #if defined(HAS_COPYROW_MIPS) 216 if (TestCpuFlag(kCpuHasMIPS)) { 217 CopyRow = CopyRow_MIPS; 218 } 219 #endif 220 221 // Copy plane 222 for (y = 0; y < height - 1; y += 2) { 223 CopyRow(src, dst, width); 224 CopyRow(src + src_stride_0, dst + dst_stride, width); 225 src += src_stride_0 + src_stride_1; 226 dst += dst_stride * 2; 227 } 228 if (height & 1) { 229 CopyRow(src, dst, width); 230 } 231 } 232 233 // Support converting from FOURCC_M420 234 // Useful for bandwidth constrained transports like USB 1.0 and 2.0 and for 235 // easy conversion to I420. 236 // M420 format description: 237 // M420 is row biplanar 420: 2 rows of Y and 1 row of UV. 238 // Chroma is half width / half height. (420) 239 // src_stride_m420 is row planar. Normally this will be the width in pixels. 240 // The UV plane is half width, but 2 values, so src_stride_m420 applies to 241 // this as well as the two Y planes. 242 static int X420ToI420(const uint8* src_y, 243 int src_stride_y0, 244 int src_stride_y1, 245 const uint8* src_uv, 246 int src_stride_uv, 247 uint8* dst_y, 248 int dst_stride_y, 249 uint8* dst_u, 250 int dst_stride_u, 251 uint8* dst_v, 252 int dst_stride_v, 253 int width, 254 int height) { 255 int halfwidth = (width + 1) >> 1; 256 int halfheight = (height + 1) >> 1; 257 if (!src_uv || !dst_u || !dst_v || width <= 0 || height == 0) { 258 return -1; 259 } 260 // Negative height means invert the image. 261 if (height < 0) { 262 height = -height; 263 halfheight = (height + 1) >> 1; 264 if (dst_y) { 265 dst_y = dst_y + (height - 1) * dst_stride_y; 266 } 267 dst_u = dst_u + (halfheight - 1) * dst_stride_u; 268 dst_v = dst_v + (halfheight - 1) * dst_stride_v; 269 dst_stride_y = -dst_stride_y; 270 dst_stride_u = -dst_stride_u; 271 dst_stride_v = -dst_stride_v; 272 } 273 // Coalesce rows. 274 if (src_stride_y0 == width && src_stride_y1 == width && 275 dst_stride_y == width) { 276 width *= height; 277 height = 1; 278 src_stride_y0 = src_stride_y1 = dst_stride_y = 0; 279 } 280 // Coalesce rows. 281 if (src_stride_uv == halfwidth * 2 && dst_stride_u == halfwidth && 282 dst_stride_v == halfwidth) { 283 halfwidth *= halfheight; 284 halfheight = 1; 285 src_stride_uv = dst_stride_u = dst_stride_v = 0; 286 } 287 288 if (dst_y) { 289 if (src_stride_y0 == src_stride_y1) { 290 CopyPlane(src_y, src_stride_y0, dst_y, dst_stride_y, width, height); 291 } else { 292 CopyPlane2(src_y, src_stride_y0, src_stride_y1, dst_y, dst_stride_y, 293 width, height); 294 } 295 } 296 297 // Split UV plane - NV12 / NV21 298 SplitUVPlane(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v, dst_stride_v, 299 halfwidth, halfheight); 300 301 return 0; 302 } 303 304 // Convert NV12 to I420. 305 LIBYUV_API 306 int NV12ToI420(const uint8* src_y, 307 int src_stride_y, 308 const uint8* src_uv, 309 int src_stride_uv, 310 uint8* dst_y, 311 int dst_stride_y, 312 uint8* dst_u, 313 int dst_stride_u, 314 uint8* dst_v, 315 int dst_stride_v, 316 int width, 317 int height) { 318 return X420ToI420(src_y, src_stride_y, src_stride_y, src_uv, src_stride_uv, 319 dst_y, dst_stride_y, dst_u, dst_stride_u, dst_v, 320 dst_stride_v, width, height); 321 } 322 323 // Convert NV21 to I420. Same as NV12 but u and v pointers swapped. 324 LIBYUV_API 325 int NV21ToI420(const uint8* src_y, 326 int src_stride_y, 327 const uint8* src_vu, 328 int src_stride_vu, 329 uint8* dst_y, 330 int dst_stride_y, 331 uint8* dst_u, 332 int dst_stride_u, 333 uint8* dst_v, 334 int dst_stride_v, 335 int width, 336 int height) { 337 return X420ToI420(src_y, src_stride_y, src_stride_y, src_vu, src_stride_vu, 338 dst_y, dst_stride_y, dst_v, dst_stride_v, dst_u, 339 dst_stride_u, width, height); 340 } 341 342 // Convert M420 to I420. 343 LIBYUV_API 344 int M420ToI420(const uint8* src_m420, 345 int src_stride_m420, 346 uint8* dst_y, 347 int dst_stride_y, 348 uint8* dst_u, 349 int dst_stride_u, 350 uint8* dst_v, 351 int dst_stride_v, 352 int width, 353 int height) { 354 return X420ToI420(src_m420, src_stride_m420, src_stride_m420 * 2, 355 src_m420 + src_stride_m420 * 2, src_stride_m420 * 3, dst_y, 356 dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v, 357 width, height); 358 } 359 360 // Convert YUY2 to I420. 361 LIBYUV_API 362 int YUY2ToI420(const uint8* src_yuy2, 363 int src_stride_yuy2, 364 uint8* dst_y, 365 int dst_stride_y, 366 uint8* dst_u, 367 int dst_stride_u, 368 uint8* dst_v, 369 int dst_stride_v, 370 int width, 371 int height) { 372 int y; 373 void (*YUY2ToUVRow)(const uint8* src_yuy2, int src_stride_yuy2, uint8* dst_u, 374 uint8* dst_v, int width) = YUY2ToUVRow_C; 375 void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int width) = 376 YUY2ToYRow_C; 377 // Negative height means invert the image. 378 if (height < 0) { 379 height = -height; 380 src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2; 381 src_stride_yuy2 = -src_stride_yuy2; 382 } 383 #if defined(HAS_YUY2TOYROW_SSE2) 384 if (TestCpuFlag(kCpuHasSSE2)) { 385 YUY2ToUVRow = YUY2ToUVRow_Any_SSE2; 386 YUY2ToYRow = YUY2ToYRow_Any_SSE2; 387 if (IS_ALIGNED(width, 16)) { 388 YUY2ToUVRow = YUY2ToUVRow_SSE2; 389 YUY2ToYRow = YUY2ToYRow_SSE2; 390 } 391 } 392 #endif 393 #if defined(HAS_YUY2TOYROW_AVX2) 394 if (TestCpuFlag(kCpuHasAVX2)) { 395 YUY2ToUVRow = YUY2ToUVRow_Any_AVX2; 396 YUY2ToYRow = YUY2ToYRow_Any_AVX2; 397 if (IS_ALIGNED(width, 32)) { 398 YUY2ToUVRow = YUY2ToUVRow_AVX2; 399 YUY2ToYRow = YUY2ToYRow_AVX2; 400 } 401 } 402 #endif 403 #if defined(HAS_YUY2TOYROW_NEON) 404 if (TestCpuFlag(kCpuHasNEON)) { 405 YUY2ToYRow = YUY2ToYRow_Any_NEON; 406 YUY2ToUVRow = YUY2ToUVRow_Any_NEON; 407 if (IS_ALIGNED(width, 16)) { 408 YUY2ToYRow = YUY2ToYRow_NEON; 409 YUY2ToUVRow = YUY2ToUVRow_NEON; 410 } 411 } 412 #endif 413 #if defined(HAS_YUY2TOYROW_MSA) 414 if (TestCpuFlag(kCpuHasMSA)) { 415 YUY2ToYRow = YUY2ToYRow_Any_MSA; 416 YUY2ToUVRow = YUY2ToUVRow_Any_MSA; 417 if (IS_ALIGNED(width, 32)) { 418 YUY2ToYRow = YUY2ToYRow_MSA; 419 YUY2ToUVRow = YUY2ToUVRow_MSA; 420 } 421 } 422 #endif 423 424 for (y = 0; y < height - 1; y += 2) { 425 YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width); 426 YUY2ToYRow(src_yuy2, dst_y, width); 427 YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width); 428 src_yuy2 += src_stride_yuy2 * 2; 429 dst_y += dst_stride_y * 2; 430 dst_u += dst_stride_u; 431 dst_v += dst_stride_v; 432 } 433 if (height & 1) { 434 YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width); 435 YUY2ToYRow(src_yuy2, dst_y, width); 436 } 437 return 0; 438 } 439 440 // Convert UYVY to I420. 441 LIBYUV_API 442 int UYVYToI420(const uint8* src_uyvy, 443 int src_stride_uyvy, 444 uint8* dst_y, 445 int dst_stride_y, 446 uint8* dst_u, 447 int dst_stride_u, 448 uint8* dst_v, 449 int dst_stride_v, 450 int width, 451 int height) { 452 int y; 453 void (*UYVYToUVRow)(const uint8* src_uyvy, int src_stride_uyvy, uint8* dst_u, 454 uint8* dst_v, int width) = UYVYToUVRow_C; 455 void (*UYVYToYRow)(const uint8* src_uyvy, uint8* dst_y, int width) = 456 UYVYToYRow_C; 457 // Negative height means invert the image. 458 if (height < 0) { 459 height = -height; 460 src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy; 461 src_stride_uyvy = -src_stride_uyvy; 462 } 463 #if defined(HAS_UYVYTOYROW_SSE2) 464 if (TestCpuFlag(kCpuHasSSE2)) { 465 UYVYToUVRow = UYVYToUVRow_Any_SSE2; 466 UYVYToYRow = UYVYToYRow_Any_SSE2; 467 if (IS_ALIGNED(width, 16)) { 468 UYVYToUVRow = UYVYToUVRow_SSE2; 469 UYVYToYRow = UYVYToYRow_SSE2; 470 } 471 } 472 #endif 473 #if defined(HAS_UYVYTOYROW_AVX2) 474 if (TestCpuFlag(kCpuHasAVX2)) { 475 UYVYToUVRow = UYVYToUVRow_Any_AVX2; 476 UYVYToYRow = UYVYToYRow_Any_AVX2; 477 if (IS_ALIGNED(width, 32)) { 478 UYVYToUVRow = UYVYToUVRow_AVX2; 479 UYVYToYRow = UYVYToYRow_AVX2; 480 } 481 } 482 #endif 483 #if defined(HAS_UYVYTOYROW_NEON) 484 if (TestCpuFlag(kCpuHasNEON)) { 485 UYVYToYRow = UYVYToYRow_Any_NEON; 486 UYVYToUVRow = UYVYToUVRow_Any_NEON; 487 if (IS_ALIGNED(width, 16)) { 488 UYVYToYRow = UYVYToYRow_NEON; 489 UYVYToUVRow = UYVYToUVRow_NEON; 490 } 491 } 492 #endif 493 #if defined(HAS_UYVYTOYROW_MSA) 494 if (TestCpuFlag(kCpuHasMSA)) { 495 UYVYToYRow = UYVYToYRow_Any_MSA; 496 UYVYToUVRow = UYVYToUVRow_Any_MSA; 497 if (IS_ALIGNED(width, 32)) { 498 UYVYToYRow = UYVYToYRow_MSA; 499 UYVYToUVRow = UYVYToUVRow_MSA; 500 } 501 } 502 #endif 503 504 for (y = 0; y < height - 1; y += 2) { 505 UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width); 506 UYVYToYRow(src_uyvy, dst_y, width); 507 UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width); 508 src_uyvy += src_stride_uyvy * 2; 509 dst_y += dst_stride_y * 2; 510 dst_u += dst_stride_u; 511 dst_v += dst_stride_v; 512 } 513 if (height & 1) { 514 UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width); 515 UYVYToYRow(src_uyvy, dst_y, width); 516 } 517 return 0; 518 } 519 520 // Convert ARGB to I420. 521 LIBYUV_API 522 int ARGBToI420(const uint8* src_argb, 523 int src_stride_argb, 524 uint8* dst_y, 525 int dst_stride_y, 526 uint8* dst_u, 527 int dst_stride_u, 528 uint8* dst_v, 529 int dst_stride_v, 530 int width, 531 int height) { 532 int y; 533 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u, 534 uint8* dst_v, int width) = ARGBToUVRow_C; 535 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = 536 ARGBToYRow_C; 537 if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { 538 return -1; 539 } 540 // Negative height means invert the image. 541 if (height < 0) { 542 height = -height; 543 src_argb = src_argb + (height - 1) * src_stride_argb; 544 src_stride_argb = -src_stride_argb; 545 } 546 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) 547 if (TestCpuFlag(kCpuHasSSSE3)) { 548 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 549 ARGBToYRow = ARGBToYRow_Any_SSSE3; 550 if (IS_ALIGNED(width, 16)) { 551 ARGBToUVRow = ARGBToUVRow_SSSE3; 552 ARGBToYRow = ARGBToYRow_SSSE3; 553 } 554 } 555 #endif 556 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) 557 if (TestCpuFlag(kCpuHasAVX2)) { 558 ARGBToUVRow = ARGBToUVRow_Any_AVX2; 559 ARGBToYRow = ARGBToYRow_Any_AVX2; 560 if (IS_ALIGNED(width, 32)) { 561 ARGBToUVRow = ARGBToUVRow_AVX2; 562 ARGBToYRow = ARGBToYRow_AVX2; 563 } 564 } 565 #endif 566 #if defined(HAS_ARGBTOYROW_NEON) 567 if (TestCpuFlag(kCpuHasNEON)) { 568 ARGBToYRow = ARGBToYRow_Any_NEON; 569 if (IS_ALIGNED(width, 8)) { 570 ARGBToYRow = ARGBToYRow_NEON; 571 } 572 } 573 #endif 574 #if defined(HAS_ARGBTOUVROW_NEON) 575 if (TestCpuFlag(kCpuHasNEON)) { 576 ARGBToUVRow = ARGBToUVRow_Any_NEON; 577 if (IS_ALIGNED(width, 16)) { 578 ARGBToUVRow = ARGBToUVRow_NEON; 579 } 580 } 581 #endif 582 #if defined(HAS_ARGBTOYROW_DSPR2) 583 if (TestCpuFlag(kCpuHasDSPR2)) { 584 ARGBToYRow = ARGBToYRow_Any_DSPR2; 585 if (IS_ALIGNED(width, 8)) { 586 ARGBToYRow = ARGBToYRow_DSPR2; 587 } 588 } 589 #endif 590 #if defined(HAS_ARGBTOYROW_MSA) 591 if (TestCpuFlag(kCpuHasMSA)) { 592 ARGBToYRow = ARGBToYRow_Any_MSA; 593 if (IS_ALIGNED(width, 16)) { 594 ARGBToYRow = ARGBToYRow_MSA; 595 } 596 } 597 #endif 598 #if defined(HAS_ARGBTOUVROW_DSPR2) 599 if (TestCpuFlag(kCpuHasDSPR2)) { 600 ARGBToUVRow = ARGBToUVRow_Any_DSPR2; 601 if (IS_ALIGNED(width, 16)) { 602 ARGBToUVRow = ARGBToUVRow_DSPR2; 603 } 604 } 605 #endif 606 #if defined(HAS_ARGBTOUVROW_MSA) 607 if (TestCpuFlag(kCpuHasMSA)) { 608 ARGBToUVRow = ARGBToUVRow_Any_MSA; 609 if (IS_ALIGNED(width, 32)) { 610 ARGBToUVRow = ARGBToUVRow_MSA; 611 } 612 } 613 #endif 614 615 for (y = 0; y < height - 1; y += 2) { 616 ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width); 617 ARGBToYRow(src_argb, dst_y, width); 618 ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width); 619 src_argb += src_stride_argb * 2; 620 dst_y += dst_stride_y * 2; 621 dst_u += dst_stride_u; 622 dst_v += dst_stride_v; 623 } 624 if (height & 1) { 625 ARGBToUVRow(src_argb, 0, dst_u, dst_v, width); 626 ARGBToYRow(src_argb, dst_y, width); 627 } 628 return 0; 629 } 630 631 // Convert BGRA to I420. 632 LIBYUV_API 633 int BGRAToI420(const uint8* src_bgra, 634 int src_stride_bgra, 635 uint8* dst_y, 636 int dst_stride_y, 637 uint8* dst_u, 638 int dst_stride_u, 639 uint8* dst_v, 640 int dst_stride_v, 641 int width, 642 int height) { 643 int y; 644 void (*BGRAToUVRow)(const uint8* src_bgra0, int src_stride_bgra, uint8* dst_u, 645 uint8* dst_v, int width) = BGRAToUVRow_C; 646 void (*BGRAToYRow)(const uint8* src_bgra, uint8* dst_y, int width) = 647 BGRAToYRow_C; 648 if (!src_bgra || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { 649 return -1; 650 } 651 // Negative height means invert the image. 652 if (height < 0) { 653 height = -height; 654 src_bgra = src_bgra + (height - 1) * src_stride_bgra; 655 src_stride_bgra = -src_stride_bgra; 656 } 657 #if defined(HAS_BGRATOYROW_SSSE3) && defined(HAS_BGRATOUVROW_SSSE3) 658 if (TestCpuFlag(kCpuHasSSSE3)) { 659 BGRAToUVRow = BGRAToUVRow_Any_SSSE3; 660 BGRAToYRow = BGRAToYRow_Any_SSSE3; 661 if (IS_ALIGNED(width, 16)) { 662 BGRAToUVRow = BGRAToUVRow_SSSE3; 663 BGRAToYRow = BGRAToYRow_SSSE3; 664 } 665 } 666 #endif 667 #if defined(HAS_BGRATOYROW_NEON) 668 if (TestCpuFlag(kCpuHasNEON)) { 669 BGRAToYRow = BGRAToYRow_Any_NEON; 670 if (IS_ALIGNED(width, 8)) { 671 BGRAToYRow = BGRAToYRow_NEON; 672 } 673 } 674 #endif 675 #if defined(HAS_BGRATOUVROW_NEON) 676 if (TestCpuFlag(kCpuHasNEON)) { 677 BGRAToUVRow = BGRAToUVRow_Any_NEON; 678 if (IS_ALIGNED(width, 16)) { 679 BGRAToUVRow = BGRAToUVRow_NEON; 680 } 681 } 682 #endif 683 #if defined(HAS_BGRATOYROW_DSPR2) 684 if (TestCpuFlag(kCpuHasDSPR2)) { 685 BGRAToYRow = BGRAToYRow_Any_DSPR2; 686 if (IS_ALIGNED(width, 8)) { 687 BGRAToYRow = BGRAToYRow_DSPR2; 688 } 689 } 690 #endif 691 #if defined(HAS_BGRATOUVROW_DSPR2) 692 if (TestCpuFlag(kCpuHasDSPR2)) { 693 BGRAToUVRow = BGRAToUVRow_Any_DSPR2; 694 if (IS_ALIGNED(width, 16)) { 695 BGRAToUVRow = BGRAToUVRow_DSPR2; 696 } 697 } 698 #endif 699 #if defined(HAS_BGRATOYROW_MSA) 700 if (TestCpuFlag(kCpuHasMSA)) { 701 BGRAToYRow = BGRAToYRow_Any_MSA; 702 if (IS_ALIGNED(width, 16)) { 703 BGRAToYRow = BGRAToYRow_MSA; 704 } 705 } 706 #endif 707 #if defined(HAS_BGRATOUVROW_MSA) 708 if (TestCpuFlag(kCpuHasMSA)) { 709 BGRAToUVRow = BGRAToUVRow_Any_MSA; 710 if (IS_ALIGNED(width, 16)) { 711 BGRAToUVRow = BGRAToUVRow_MSA; 712 } 713 } 714 #endif 715 716 for (y = 0; y < height - 1; y += 2) { 717 BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width); 718 BGRAToYRow(src_bgra, dst_y, width); 719 BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width); 720 src_bgra += src_stride_bgra * 2; 721 dst_y += dst_stride_y * 2; 722 dst_u += dst_stride_u; 723 dst_v += dst_stride_v; 724 } 725 if (height & 1) { 726 BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width); 727 BGRAToYRow(src_bgra, dst_y, width); 728 } 729 return 0; 730 } 731 732 // Convert ABGR to I420. 733 LIBYUV_API 734 int ABGRToI420(const uint8* src_abgr, 735 int src_stride_abgr, 736 uint8* dst_y, 737 int dst_stride_y, 738 uint8* dst_u, 739 int dst_stride_u, 740 uint8* dst_v, 741 int dst_stride_v, 742 int width, 743 int height) { 744 int y; 745 void (*ABGRToUVRow)(const uint8* src_abgr0, int src_stride_abgr, uint8* dst_u, 746 uint8* dst_v, int width) = ABGRToUVRow_C; 747 void (*ABGRToYRow)(const uint8* src_abgr, uint8* dst_y, int width) = 748 ABGRToYRow_C; 749 if (!src_abgr || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { 750 return -1; 751 } 752 // Negative height means invert the image. 753 if (height < 0) { 754 height = -height; 755 src_abgr = src_abgr + (height - 1) * src_stride_abgr; 756 src_stride_abgr = -src_stride_abgr; 757 } 758 #if defined(HAS_ABGRTOYROW_SSSE3) && defined(HAS_ABGRTOUVROW_SSSE3) 759 if (TestCpuFlag(kCpuHasSSSE3)) { 760 ABGRToUVRow = ABGRToUVRow_Any_SSSE3; 761 ABGRToYRow = ABGRToYRow_Any_SSSE3; 762 if (IS_ALIGNED(width, 16)) { 763 ABGRToUVRow = ABGRToUVRow_SSSE3; 764 ABGRToYRow = ABGRToYRow_SSSE3; 765 } 766 } 767 #endif 768 #if defined(HAS_ABGRTOYROW_NEON) 769 if (TestCpuFlag(kCpuHasNEON)) { 770 ABGRToYRow = ABGRToYRow_Any_NEON; 771 if (IS_ALIGNED(width, 8)) { 772 ABGRToYRow = ABGRToYRow_NEON; 773 } 774 } 775 #endif 776 #if defined(HAS_ABGRTOUVROW_NEON) 777 if (TestCpuFlag(kCpuHasNEON)) { 778 ABGRToUVRow = ABGRToUVRow_Any_NEON; 779 if (IS_ALIGNED(width, 16)) { 780 ABGRToUVRow = ABGRToUVRow_NEON; 781 } 782 } 783 #endif 784 #if defined(HAS_ABGRTOYROW_DSPR2) 785 if (TestCpuFlag(kCpuHasDSPR2)) { 786 ABGRToYRow = ABGRToYRow_Any_DSPR2; 787 if (IS_ALIGNED(width, 8)) { 788 ABGRToYRow = ABGRToYRow_DSPR2; 789 } 790 } 791 #endif 792 #if defined(HAS_ABGRTOUVROW_DSPR2) 793 if (TestCpuFlag(kCpuHasDSPR2)) { 794 ABGRToUVRow = ABGRToUVRow_Any_DSPR2; 795 if (IS_ALIGNED(width, 16)) { 796 ABGRToUVRow = ABGRToUVRow_DSPR2; 797 } 798 } 799 #endif 800 #if defined(HAS_ABGRTOYROW_MSA) 801 if (TestCpuFlag(kCpuHasMSA)) { 802 ABGRToYRow = ABGRToYRow_Any_MSA; 803 if (IS_ALIGNED(width, 16)) { 804 ABGRToYRow = ABGRToYRow_MSA; 805 } 806 } 807 #endif 808 #if defined(HAS_ABGRTOUVROW_MSA) 809 if (TestCpuFlag(kCpuHasMSA)) { 810 ABGRToUVRow = ABGRToUVRow_Any_MSA; 811 if (IS_ALIGNED(width, 16)) { 812 ABGRToUVRow = ABGRToUVRow_MSA; 813 } 814 } 815 #endif 816 817 for (y = 0; y < height - 1; y += 2) { 818 ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width); 819 ABGRToYRow(src_abgr, dst_y, width); 820 ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width); 821 src_abgr += src_stride_abgr * 2; 822 dst_y += dst_stride_y * 2; 823 dst_u += dst_stride_u; 824 dst_v += dst_stride_v; 825 } 826 if (height & 1) { 827 ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width); 828 ABGRToYRow(src_abgr, dst_y, width); 829 } 830 return 0; 831 } 832 833 // Convert RGBA to I420. 834 LIBYUV_API 835 int RGBAToI420(const uint8* src_rgba, 836 int src_stride_rgba, 837 uint8* dst_y, 838 int dst_stride_y, 839 uint8* dst_u, 840 int dst_stride_u, 841 uint8* dst_v, 842 int dst_stride_v, 843 int width, 844 int height) { 845 int y; 846 void (*RGBAToUVRow)(const uint8* src_rgba0, int src_stride_rgba, uint8* dst_u, 847 uint8* dst_v, int width) = RGBAToUVRow_C; 848 void (*RGBAToYRow)(const uint8* src_rgba, uint8* dst_y, int width) = 849 RGBAToYRow_C; 850 if (!src_rgba || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { 851 return -1; 852 } 853 // Negative height means invert the image. 854 if (height < 0) { 855 height = -height; 856 src_rgba = src_rgba + (height - 1) * src_stride_rgba; 857 src_stride_rgba = -src_stride_rgba; 858 } 859 #if defined(HAS_RGBATOYROW_SSSE3) && defined(HAS_RGBATOUVROW_SSSE3) 860 if (TestCpuFlag(kCpuHasSSSE3)) { 861 RGBAToUVRow = RGBAToUVRow_Any_SSSE3; 862 RGBAToYRow = RGBAToYRow_Any_SSSE3; 863 if (IS_ALIGNED(width, 16)) { 864 RGBAToUVRow = RGBAToUVRow_SSSE3; 865 RGBAToYRow = RGBAToYRow_SSSE3; 866 } 867 } 868 #endif 869 #if defined(HAS_RGBATOYROW_NEON) 870 if (TestCpuFlag(kCpuHasNEON)) { 871 RGBAToYRow = RGBAToYRow_Any_NEON; 872 if (IS_ALIGNED(width, 8)) { 873 RGBAToYRow = RGBAToYRow_NEON; 874 } 875 } 876 #endif 877 #if defined(HAS_RGBATOUVROW_NEON) 878 if (TestCpuFlag(kCpuHasNEON)) { 879 RGBAToUVRow = RGBAToUVRow_Any_NEON; 880 if (IS_ALIGNED(width, 16)) { 881 RGBAToUVRow = RGBAToUVRow_NEON; 882 } 883 } 884 #endif 885 #if defined(HAS_RGBATOYROW_DSPR2) 886 if (TestCpuFlag(kCpuHasDSPR2)) { 887 RGBAToYRow = RGBAToYRow_Any_DSPR2; 888 if (IS_ALIGNED(width, 8)) { 889 RGBAToYRow = RGBAToYRow_DSPR2; 890 } 891 } 892 #endif 893 #if defined(HAS_RGBATOUVROW_DSPR2) 894 if (TestCpuFlag(kCpuHasDSPR2)) { 895 RGBAToUVRow = RGBAToUVRow_Any_DSPR2; 896 if (IS_ALIGNED(width, 16)) { 897 RGBAToUVRow = RGBAToUVRow_DSPR2; 898 } 899 } 900 #endif 901 #if defined(HAS_RGBATOYROW_MSA) 902 if (TestCpuFlag(kCpuHasMSA)) { 903 RGBAToYRow = RGBAToYRow_Any_MSA; 904 if (IS_ALIGNED(width, 16)) { 905 RGBAToYRow = RGBAToYRow_MSA; 906 } 907 } 908 #endif 909 #if defined(HAS_RGBATOUVROW_MSA) 910 if (TestCpuFlag(kCpuHasMSA)) { 911 RGBAToUVRow = RGBAToUVRow_Any_MSA; 912 if (IS_ALIGNED(width, 16)) { 913 RGBAToUVRow = RGBAToUVRow_MSA; 914 } 915 } 916 #endif 917 918 for (y = 0; y < height - 1; y += 2) { 919 RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width); 920 RGBAToYRow(src_rgba, dst_y, width); 921 RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width); 922 src_rgba += src_stride_rgba * 2; 923 dst_y += dst_stride_y * 2; 924 dst_u += dst_stride_u; 925 dst_v += dst_stride_v; 926 } 927 if (height & 1) { 928 RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width); 929 RGBAToYRow(src_rgba, dst_y, width); 930 } 931 return 0; 932 } 933 934 // Convert RGB24 to I420. 935 LIBYUV_API 936 int RGB24ToI420(const uint8* src_rgb24, 937 int src_stride_rgb24, 938 uint8* dst_y, 939 int dst_stride_y, 940 uint8* dst_u, 941 int dst_stride_u, 942 uint8* dst_v, 943 int dst_stride_v, 944 int width, 945 int height) { 946 int y; 947 #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA)) 948 void (*RGB24ToUVRow)(const uint8* src_rgb24, int src_stride_rgb24, 949 uint8* dst_u, uint8* dst_v, int width) = RGB24ToUVRow_C; 950 void (*RGB24ToYRow)(const uint8* src_rgb24, uint8* dst_y, int width) = 951 RGB24ToYRow_C; 952 #else 953 void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) = 954 RGB24ToARGBRow_C; 955 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u, 956 uint8* dst_v, int width) = ARGBToUVRow_C; 957 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = 958 ARGBToYRow_C; 959 #endif 960 if (!src_rgb24 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { 961 return -1; 962 } 963 // Negative height means invert the image. 964 if (height < 0) { 965 height = -height; 966 src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24; 967 src_stride_rgb24 = -src_stride_rgb24; 968 } 969 970 // Neon version does direct RGB24 to YUV. 971 #if defined(HAS_RGB24TOYROW_NEON) 972 if (TestCpuFlag(kCpuHasNEON)) { 973 RGB24ToUVRow = RGB24ToUVRow_Any_NEON; 974 RGB24ToYRow = RGB24ToYRow_Any_NEON; 975 if (IS_ALIGNED(width, 8)) { 976 RGB24ToYRow = RGB24ToYRow_NEON; 977 if (IS_ALIGNED(width, 16)) { 978 RGB24ToUVRow = RGB24ToUVRow_NEON; 979 } 980 } 981 } 982 #elif defined(HAS_RGB24TOYROW_MSA) 983 if (TestCpuFlag(kCpuHasMSA)) { 984 RGB24ToUVRow = RGB24ToUVRow_Any_MSA; 985 RGB24ToYRow = RGB24ToYRow_Any_MSA; 986 if (IS_ALIGNED(width, 16)) { 987 RGB24ToYRow = RGB24ToYRow_MSA; 988 RGB24ToUVRow = RGB24ToUVRow_MSA; 989 } 990 } 991 // Other platforms do intermediate conversion from RGB24 to ARGB. 992 #else 993 #if defined(HAS_RGB24TOARGBROW_SSSE3) 994 if (TestCpuFlag(kCpuHasSSSE3)) { 995 RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3; 996 if (IS_ALIGNED(width, 16)) { 997 RGB24ToARGBRow = RGB24ToARGBRow_SSSE3; 998 } 999 } 1000 #endif 1001 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) 1002 if (TestCpuFlag(kCpuHasSSSE3)) { 1003 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1004 ARGBToYRow = ARGBToYRow_Any_SSSE3; 1005 if (IS_ALIGNED(width, 16)) { 1006 ARGBToUVRow = ARGBToUVRow_SSSE3; 1007 ARGBToYRow = ARGBToYRow_SSSE3; 1008 } 1009 } 1010 #endif 1011 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) 1012 if (TestCpuFlag(kCpuHasAVX2)) { 1013 ARGBToUVRow = ARGBToUVRow_Any_AVX2; 1014 ARGBToYRow = ARGBToYRow_Any_AVX2; 1015 if (IS_ALIGNED(width, 32)) { 1016 ARGBToUVRow = ARGBToUVRow_AVX2; 1017 ARGBToYRow = ARGBToYRow_AVX2; 1018 } 1019 } 1020 #endif 1021 #endif 1022 1023 { 1024 #if !(defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA)) 1025 // Allocate 2 rows of ARGB. 1026 const int kRowSize = (width * 4 + 31) & ~31; 1027 align_buffer_64(row, kRowSize * 2); 1028 #endif 1029 1030 for (y = 0; y < height - 1; y += 2) { 1031 #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA)) 1032 RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width); 1033 RGB24ToYRow(src_rgb24, dst_y, width); 1034 RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width); 1035 #else 1036 RGB24ToARGBRow(src_rgb24, row, width); 1037 RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width); 1038 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1039 ARGBToYRow(row, dst_y, width); 1040 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1041 #endif 1042 src_rgb24 += src_stride_rgb24 * 2; 1043 dst_y += dst_stride_y * 2; 1044 dst_u += dst_stride_u; 1045 dst_v += dst_stride_v; 1046 } 1047 if (height & 1) { 1048 #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA)) 1049 RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width); 1050 RGB24ToYRow(src_rgb24, dst_y, width); 1051 #else 1052 RGB24ToARGBRow(src_rgb24, row, width); 1053 ARGBToUVRow(row, 0, dst_u, dst_v, width); 1054 ARGBToYRow(row, dst_y, width); 1055 #endif 1056 } 1057 #if !(defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA)) 1058 free_aligned_buffer_64(row); 1059 #endif 1060 } 1061 return 0; 1062 } 1063 1064 // Convert RAW to I420. 1065 LIBYUV_API 1066 int RAWToI420(const uint8* src_raw, 1067 int src_stride_raw, 1068 uint8* dst_y, 1069 int dst_stride_y, 1070 uint8* dst_u, 1071 int dst_stride_u, 1072 uint8* dst_v, 1073 int dst_stride_v, 1074 int width, 1075 int height) { 1076 int y; 1077 #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA)) 1078 void (*RAWToUVRow)(const uint8* src_raw, int src_stride_raw, uint8* dst_u, 1079 uint8* dst_v, int width) = RAWToUVRow_C; 1080 void (*RAWToYRow)(const uint8* src_raw, uint8* dst_y, int width) = 1081 RAWToYRow_C; 1082 #else 1083 void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) = 1084 RAWToARGBRow_C; 1085 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u, 1086 uint8* dst_v, int width) = ARGBToUVRow_C; 1087 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = 1088 ARGBToYRow_C; 1089 #endif 1090 if (!src_raw || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { 1091 return -1; 1092 } 1093 // Negative height means invert the image. 1094 if (height < 0) { 1095 height = -height; 1096 src_raw = src_raw + (height - 1) * src_stride_raw; 1097 src_stride_raw = -src_stride_raw; 1098 } 1099 1100 // Neon version does direct RAW to YUV. 1101 #if defined(HAS_RAWTOYROW_NEON) 1102 if (TestCpuFlag(kCpuHasNEON)) { 1103 RAWToUVRow = RAWToUVRow_Any_NEON; 1104 RAWToYRow = RAWToYRow_Any_NEON; 1105 if (IS_ALIGNED(width, 8)) { 1106 RAWToYRow = RAWToYRow_NEON; 1107 if (IS_ALIGNED(width, 16)) { 1108 RAWToUVRow = RAWToUVRow_NEON; 1109 } 1110 } 1111 } 1112 #elif defined(HAS_RAWTOYROW_MSA) 1113 if (TestCpuFlag(kCpuHasMSA)) { 1114 RAWToUVRow = RAWToUVRow_Any_MSA; 1115 RAWToYRow = RAWToYRow_Any_MSA; 1116 if (IS_ALIGNED(width, 16)) { 1117 RAWToYRow = RAWToYRow_MSA; 1118 RAWToUVRow = RAWToUVRow_MSA; 1119 } 1120 } 1121 // Other platforms do intermediate conversion from RAW to ARGB. 1122 #else 1123 #if defined(HAS_RAWTOARGBROW_SSSE3) 1124 if (TestCpuFlag(kCpuHasSSSE3)) { 1125 RAWToARGBRow = RAWToARGBRow_Any_SSSE3; 1126 if (IS_ALIGNED(width, 16)) { 1127 RAWToARGBRow = RAWToARGBRow_SSSE3; 1128 } 1129 } 1130 #endif 1131 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) 1132 if (TestCpuFlag(kCpuHasSSSE3)) { 1133 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1134 ARGBToYRow = ARGBToYRow_Any_SSSE3; 1135 if (IS_ALIGNED(width, 16)) { 1136 ARGBToUVRow = ARGBToUVRow_SSSE3; 1137 ARGBToYRow = ARGBToYRow_SSSE3; 1138 } 1139 } 1140 #endif 1141 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) 1142 if (TestCpuFlag(kCpuHasAVX2)) { 1143 ARGBToUVRow = ARGBToUVRow_Any_AVX2; 1144 ARGBToYRow = ARGBToYRow_Any_AVX2; 1145 if (IS_ALIGNED(width, 32)) { 1146 ARGBToUVRow = ARGBToUVRow_AVX2; 1147 ARGBToYRow = ARGBToYRow_AVX2; 1148 } 1149 } 1150 #endif 1151 #endif 1152 1153 { 1154 #if !(defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA)) 1155 // Allocate 2 rows of ARGB. 1156 const int kRowSize = (width * 4 + 31) & ~31; 1157 align_buffer_64(row, kRowSize * 2); 1158 #endif 1159 1160 for (y = 0; y < height - 1; y += 2) { 1161 #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA)) 1162 RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width); 1163 RAWToYRow(src_raw, dst_y, width); 1164 RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width); 1165 #else 1166 RAWToARGBRow(src_raw, row, width); 1167 RAWToARGBRow(src_raw + src_stride_raw, row + kRowSize, width); 1168 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1169 ARGBToYRow(row, dst_y, width); 1170 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1171 #endif 1172 src_raw += src_stride_raw * 2; 1173 dst_y += dst_stride_y * 2; 1174 dst_u += dst_stride_u; 1175 dst_v += dst_stride_v; 1176 } 1177 if (height & 1) { 1178 #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA)) 1179 RAWToUVRow(src_raw, 0, dst_u, dst_v, width); 1180 RAWToYRow(src_raw, dst_y, width); 1181 #else 1182 RAWToARGBRow(src_raw, row, width); 1183 ARGBToUVRow(row, 0, dst_u, dst_v, width); 1184 ARGBToYRow(row, dst_y, width); 1185 #endif 1186 } 1187 #if !(defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA)) 1188 free_aligned_buffer_64(row); 1189 #endif 1190 } 1191 return 0; 1192 } 1193 1194 // Convert RGB565 to I420. 1195 LIBYUV_API 1196 int RGB565ToI420(const uint8* src_rgb565, 1197 int src_stride_rgb565, 1198 uint8* dst_y, 1199 int dst_stride_y, 1200 uint8* dst_u, 1201 int dst_stride_u, 1202 uint8* dst_v, 1203 int dst_stride_v, 1204 int width, 1205 int height) { 1206 int y; 1207 #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA)) 1208 void (*RGB565ToUVRow)(const uint8* src_rgb565, int src_stride_rgb565, 1209 uint8* dst_u, uint8* dst_v, int width) = 1210 RGB565ToUVRow_C; 1211 void (*RGB565ToYRow)(const uint8* src_rgb565, uint8* dst_y, int width) = 1212 RGB565ToYRow_C; 1213 #else 1214 void (*RGB565ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) = 1215 RGB565ToARGBRow_C; 1216 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u, 1217 uint8* dst_v, int width) = ARGBToUVRow_C; 1218 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = 1219 ARGBToYRow_C; 1220 #endif 1221 if (!src_rgb565 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { 1222 return -1; 1223 } 1224 // Negative height means invert the image. 1225 if (height < 0) { 1226 height = -height; 1227 src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565; 1228 src_stride_rgb565 = -src_stride_rgb565; 1229 } 1230 1231 // Neon version does direct RGB565 to YUV. 1232 #if defined(HAS_RGB565TOYROW_NEON) 1233 if (TestCpuFlag(kCpuHasNEON)) { 1234 RGB565ToUVRow = RGB565ToUVRow_Any_NEON; 1235 RGB565ToYRow = RGB565ToYRow_Any_NEON; 1236 if (IS_ALIGNED(width, 8)) { 1237 RGB565ToYRow = RGB565ToYRow_NEON; 1238 if (IS_ALIGNED(width, 16)) { 1239 RGB565ToUVRow = RGB565ToUVRow_NEON; 1240 } 1241 } 1242 } 1243 #elif defined(HAS_RGB565TOYROW_MSA) 1244 if (TestCpuFlag(kCpuHasMSA)) { 1245 RGB565ToUVRow = RGB565ToUVRow_Any_MSA; 1246 RGB565ToYRow = RGB565ToYRow_Any_MSA; 1247 if (IS_ALIGNED(width, 16)) { 1248 RGB565ToYRow = RGB565ToYRow_MSA; 1249 RGB565ToUVRow = RGB565ToUVRow_MSA; 1250 } 1251 } 1252 // Other platforms do intermediate conversion from RGB565 to ARGB. 1253 #else 1254 #if defined(HAS_RGB565TOARGBROW_SSE2) 1255 if (TestCpuFlag(kCpuHasSSE2)) { 1256 RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2; 1257 if (IS_ALIGNED(width, 8)) { 1258 RGB565ToARGBRow = RGB565ToARGBRow_SSE2; 1259 } 1260 } 1261 #endif 1262 #if defined(HAS_RGB565TOARGBROW_AVX2) 1263 if (TestCpuFlag(kCpuHasAVX2)) { 1264 RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2; 1265 if (IS_ALIGNED(width, 16)) { 1266 RGB565ToARGBRow = RGB565ToARGBRow_AVX2; 1267 } 1268 } 1269 #endif 1270 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) 1271 if (TestCpuFlag(kCpuHasSSSE3)) { 1272 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1273 ARGBToYRow = ARGBToYRow_Any_SSSE3; 1274 if (IS_ALIGNED(width, 16)) { 1275 ARGBToUVRow = ARGBToUVRow_SSSE3; 1276 ARGBToYRow = ARGBToYRow_SSSE3; 1277 } 1278 } 1279 #endif 1280 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) 1281 if (TestCpuFlag(kCpuHasAVX2)) { 1282 ARGBToUVRow = ARGBToUVRow_Any_AVX2; 1283 ARGBToYRow = ARGBToYRow_Any_AVX2; 1284 if (IS_ALIGNED(width, 32)) { 1285 ARGBToUVRow = ARGBToUVRow_AVX2; 1286 ARGBToYRow = ARGBToYRow_AVX2; 1287 } 1288 } 1289 #endif 1290 #if defined(HAS_RGB565TOARGBROW_DSPR2) 1291 if (TestCpuFlag(kCpuHasDSPR2)) { 1292 RGB565ToARGBRow = RGB565ToARGBRow_Any_DSPR2; 1293 if (IS_ALIGNED(width, 8)) { 1294 RGB565ToARGBRow = RGB565ToARGBRow_DSPR2; 1295 } 1296 } 1297 #endif 1298 #endif 1299 { 1300 #if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA)) 1301 // Allocate 2 rows of ARGB. 1302 const int kRowSize = (width * 4 + 31) & ~31; 1303 align_buffer_64(row, kRowSize * 2); 1304 #endif 1305 for (y = 0; y < height - 1; y += 2) { 1306 #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA)) 1307 RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width); 1308 RGB565ToYRow(src_rgb565, dst_y, width); 1309 RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width); 1310 #else 1311 RGB565ToARGBRow(src_rgb565, row, width); 1312 RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kRowSize, width); 1313 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1314 ARGBToYRow(row, dst_y, width); 1315 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1316 #endif 1317 src_rgb565 += src_stride_rgb565 * 2; 1318 dst_y += dst_stride_y * 2; 1319 dst_u += dst_stride_u; 1320 dst_v += dst_stride_v; 1321 } 1322 if (height & 1) { 1323 #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA)) 1324 RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width); 1325 RGB565ToYRow(src_rgb565, dst_y, width); 1326 #else 1327 RGB565ToARGBRow(src_rgb565, row, width); 1328 ARGBToUVRow(row, 0, dst_u, dst_v, width); 1329 ARGBToYRow(row, dst_y, width); 1330 #endif 1331 } 1332 #if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA)) 1333 free_aligned_buffer_64(row); 1334 #endif 1335 } 1336 return 0; 1337 } 1338 1339 // Convert ARGB1555 to I420. 1340 LIBYUV_API 1341 int ARGB1555ToI420(const uint8* src_argb1555, 1342 int src_stride_argb1555, 1343 uint8* dst_y, 1344 int dst_stride_y, 1345 uint8* dst_u, 1346 int dst_stride_u, 1347 uint8* dst_v, 1348 int dst_stride_v, 1349 int width, 1350 int height) { 1351 int y; 1352 #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA)) 1353 void (*ARGB1555ToUVRow)(const uint8* src_argb1555, int src_stride_argb1555, 1354 uint8* dst_u, uint8* dst_v, int width) = 1355 ARGB1555ToUVRow_C; 1356 void (*ARGB1555ToYRow)(const uint8* src_argb1555, uint8* dst_y, int width) = 1357 ARGB1555ToYRow_C; 1358 #else 1359 void (*ARGB1555ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) = 1360 ARGB1555ToARGBRow_C; 1361 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u, 1362 uint8* dst_v, int width) = ARGBToUVRow_C; 1363 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = 1364 ARGBToYRow_C; 1365 #endif 1366 if (!src_argb1555 || !dst_y || !dst_u || !dst_v || width <= 0 || 1367 height == 0) { 1368 return -1; 1369 } 1370 // Negative height means invert the image. 1371 if (height < 0) { 1372 height = -height; 1373 src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555; 1374 src_stride_argb1555 = -src_stride_argb1555; 1375 } 1376 1377 // Neon version does direct ARGB1555 to YUV. 1378 #if defined(HAS_ARGB1555TOYROW_NEON) 1379 if (TestCpuFlag(kCpuHasNEON)) { 1380 ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON; 1381 ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON; 1382 if (IS_ALIGNED(width, 8)) { 1383 ARGB1555ToYRow = ARGB1555ToYRow_NEON; 1384 if (IS_ALIGNED(width, 16)) { 1385 ARGB1555ToUVRow = ARGB1555ToUVRow_NEON; 1386 } 1387 } 1388 } 1389 #elif defined(HAS_ARGB1555TOYROW_MSA) 1390 if (TestCpuFlag(kCpuHasMSA)) { 1391 ARGB1555ToUVRow = ARGB1555ToUVRow_Any_MSA; 1392 ARGB1555ToYRow = ARGB1555ToYRow_Any_MSA; 1393 if (IS_ALIGNED(width, 16)) { 1394 ARGB1555ToYRow = ARGB1555ToYRow_MSA; 1395 ARGB1555ToUVRow = ARGB1555ToUVRow_MSA; 1396 } 1397 } 1398 // Other platforms do intermediate conversion from ARGB1555 to ARGB. 1399 #else 1400 #if defined(HAS_ARGB1555TOARGBROW_SSE2) 1401 if (TestCpuFlag(kCpuHasSSE2)) { 1402 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2; 1403 if (IS_ALIGNED(width, 8)) { 1404 ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2; 1405 } 1406 } 1407 #endif 1408 #if defined(HAS_ARGB1555TOARGBROW_AVX2) 1409 if (TestCpuFlag(kCpuHasAVX2)) { 1410 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2; 1411 if (IS_ALIGNED(width, 16)) { 1412 ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2; 1413 } 1414 } 1415 #endif 1416 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) 1417 if (TestCpuFlag(kCpuHasSSSE3)) { 1418 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1419 ARGBToYRow = ARGBToYRow_Any_SSSE3; 1420 if (IS_ALIGNED(width, 16)) { 1421 ARGBToUVRow = ARGBToUVRow_SSSE3; 1422 ARGBToYRow = ARGBToYRow_SSSE3; 1423 } 1424 } 1425 #endif 1426 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) 1427 if (TestCpuFlag(kCpuHasAVX2)) { 1428 ARGBToUVRow = ARGBToUVRow_Any_AVX2; 1429 ARGBToYRow = ARGBToYRow_Any_AVX2; 1430 if (IS_ALIGNED(width, 32)) { 1431 ARGBToUVRow = ARGBToUVRow_AVX2; 1432 ARGBToYRow = ARGBToYRow_AVX2; 1433 } 1434 } 1435 #endif 1436 #endif 1437 { 1438 #if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA)) 1439 // Allocate 2 rows of ARGB. 1440 const int kRowSize = (width * 4 + 31) & ~31; 1441 align_buffer_64(row, kRowSize * 2); 1442 #endif 1443 1444 for (y = 0; y < height - 1; y += 2) { 1445 #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA)) 1446 ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width); 1447 ARGB1555ToYRow(src_argb1555, dst_y, width); 1448 ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y, 1449 width); 1450 #else 1451 ARGB1555ToARGBRow(src_argb1555, row, width); 1452 ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize, 1453 width); 1454 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1455 ARGBToYRow(row, dst_y, width); 1456 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1457 #endif 1458 src_argb1555 += src_stride_argb1555 * 2; 1459 dst_y += dst_stride_y * 2; 1460 dst_u += dst_stride_u; 1461 dst_v += dst_stride_v; 1462 } 1463 if (height & 1) { 1464 #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA)) 1465 ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width); 1466 ARGB1555ToYRow(src_argb1555, dst_y, width); 1467 #else 1468 ARGB1555ToARGBRow(src_argb1555, row, width); 1469 ARGBToUVRow(row, 0, dst_u, dst_v, width); 1470 ARGBToYRow(row, dst_y, width); 1471 #endif 1472 } 1473 #if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA)) 1474 free_aligned_buffer_64(row); 1475 #endif 1476 } 1477 return 0; 1478 } 1479 1480 // Convert ARGB4444 to I420. 1481 LIBYUV_API 1482 int ARGB4444ToI420(const uint8* src_argb4444, 1483 int src_stride_argb4444, 1484 uint8* dst_y, 1485 int dst_stride_y, 1486 uint8* dst_u, 1487 int dst_stride_u, 1488 uint8* dst_v, 1489 int dst_stride_v, 1490 int width, 1491 int height) { 1492 int y; 1493 #if defined(HAS_ARGB4444TOYROW_NEON) 1494 void (*ARGB4444ToUVRow)(const uint8* src_argb4444, int src_stride_argb4444, 1495 uint8* dst_u, uint8* dst_v, int width) = 1496 ARGB4444ToUVRow_C; 1497 void (*ARGB4444ToYRow)(const uint8* src_argb4444, uint8* dst_y, int width) = 1498 ARGB4444ToYRow_C; 1499 #else 1500 void (*ARGB4444ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) = 1501 ARGB4444ToARGBRow_C; 1502 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u, 1503 uint8* dst_v, int width) = ARGBToUVRow_C; 1504 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = 1505 ARGBToYRow_C; 1506 #endif 1507 if (!src_argb4444 || !dst_y || !dst_u || !dst_v || width <= 0 || 1508 height == 0) { 1509 return -1; 1510 } 1511 // Negative height means invert the image. 1512 if (height < 0) { 1513 height = -height; 1514 src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444; 1515 src_stride_argb4444 = -src_stride_argb4444; 1516 } 1517 1518 // Neon version does direct ARGB4444 to YUV. 1519 #if defined(HAS_ARGB4444TOYROW_NEON) 1520 if (TestCpuFlag(kCpuHasNEON)) { 1521 ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON; 1522 ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON; 1523 if (IS_ALIGNED(width, 8)) { 1524 ARGB4444ToYRow = ARGB4444ToYRow_NEON; 1525 if (IS_ALIGNED(width, 16)) { 1526 ARGB4444ToUVRow = ARGB4444ToUVRow_NEON; 1527 } 1528 } 1529 } 1530 // Other platforms do intermediate conversion from ARGB4444 to ARGB. 1531 #else 1532 #if defined(HAS_ARGB4444TOARGBROW_SSE2) 1533 if (TestCpuFlag(kCpuHasSSE2)) { 1534 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2; 1535 if (IS_ALIGNED(width, 8)) { 1536 ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2; 1537 } 1538 } 1539 #endif 1540 #if defined(HAS_ARGB4444TOARGBROW_AVX2) 1541 if (TestCpuFlag(kCpuHasAVX2)) { 1542 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2; 1543 if (IS_ALIGNED(width, 16)) { 1544 ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2; 1545 } 1546 } 1547 #endif 1548 #if defined(HAS_ARGB4444TOARGBROW_MSA) 1549 if (TestCpuFlag(kCpuHasMSA)) { 1550 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MSA; 1551 if (IS_ALIGNED(width, 16)) { 1552 ARGB4444ToARGBRow = ARGB4444ToARGBRow_MSA; 1553 } 1554 } 1555 #endif 1556 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) 1557 if (TestCpuFlag(kCpuHasSSSE3)) { 1558 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1559 ARGBToYRow = ARGBToYRow_Any_SSSE3; 1560 if (IS_ALIGNED(width, 16)) { 1561 ARGBToUVRow = ARGBToUVRow_SSSE3; 1562 ARGBToYRow = ARGBToYRow_SSSE3; 1563 } 1564 } 1565 #endif 1566 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) 1567 if (TestCpuFlag(kCpuHasAVX2)) { 1568 ARGBToUVRow = ARGBToUVRow_Any_AVX2; 1569 ARGBToYRow = ARGBToYRow_Any_AVX2; 1570 if (IS_ALIGNED(width, 32)) { 1571 ARGBToUVRow = ARGBToUVRow_AVX2; 1572 ARGBToYRow = ARGBToYRow_AVX2; 1573 } 1574 } 1575 #endif 1576 #if defined(HAS_ARGBTOYROW_MSA) 1577 if (TestCpuFlag(kCpuHasMSA)) { 1578 ARGBToUVRow = ARGBToUVRow_Any_MSA; 1579 ARGBToYRow = ARGBToYRow_Any_MSA; 1580 if (IS_ALIGNED(width, 16)) { 1581 ARGBToYRow = ARGBToYRow_MSA; 1582 if (IS_ALIGNED(width, 32)) { 1583 ARGBToUVRow = ARGBToUVRow_MSA; 1584 } 1585 } 1586 } 1587 #endif 1588 #endif 1589 1590 { 1591 #if !defined(HAS_ARGB4444TOYROW_NEON) 1592 // Allocate 2 rows of ARGB. 1593 const int kRowSize = (width * 4 + 31) & ~31; 1594 align_buffer_64(row, kRowSize * 2); 1595 #endif 1596 1597 for (y = 0; y < height - 1; y += 2) { 1598 #if defined(HAS_ARGB4444TOYROW_NEON) 1599 ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width); 1600 ARGB4444ToYRow(src_argb4444, dst_y, width); 1601 ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y, 1602 width); 1603 #else 1604 ARGB4444ToARGBRow(src_argb4444, row, width); 1605 ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kRowSize, 1606 width); 1607 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1608 ARGBToYRow(row, dst_y, width); 1609 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1610 #endif 1611 src_argb4444 += src_stride_argb4444 * 2; 1612 dst_y += dst_stride_y * 2; 1613 dst_u += dst_stride_u; 1614 dst_v += dst_stride_v; 1615 } 1616 if (height & 1) { 1617 #if defined(HAS_ARGB4444TOYROW_NEON) 1618 ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width); 1619 ARGB4444ToYRow(src_argb4444, dst_y, width); 1620 #else 1621 ARGB4444ToARGBRow(src_argb4444, row, width); 1622 ARGBToUVRow(row, 0, dst_u, dst_v, width); 1623 ARGBToYRow(row, dst_y, width); 1624 #endif 1625 } 1626 #if !defined(HAS_ARGB4444TOYROW_NEON) 1627 free_aligned_buffer_64(row); 1628 #endif 1629 } 1630 return 0; 1631 } 1632 1633 static void SplitPixels(const uint8* src_u, 1634 int src_pixel_stride_uv, 1635 uint8* dst_u, 1636 int width) { 1637 int i; 1638 for (i = 0; i < width; ++i) { 1639 *dst_u = *src_u; 1640 ++dst_u; 1641 src_u += src_pixel_stride_uv; 1642 } 1643 } 1644 1645 // Convert Android420 to I420. 1646 LIBYUV_API 1647 int Android420ToI420(const uint8* src_y, 1648 int src_stride_y, 1649 const uint8* src_u, 1650 int src_stride_u, 1651 const uint8* src_v, 1652 int src_stride_v, 1653 int src_pixel_stride_uv, 1654 uint8* dst_y, 1655 int dst_stride_y, 1656 uint8* dst_u, 1657 int dst_stride_u, 1658 uint8* dst_v, 1659 int dst_stride_v, 1660 int width, 1661 int height) { 1662 int y; 1663 const ptrdiff_t vu_off = src_v - src_u; 1664 int halfwidth = (width + 1) >> 1; 1665 int halfheight = (height + 1) >> 1; 1666 if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) { 1667 return -1; 1668 } 1669 // Negative height means invert the image. 1670 if (height < 0) { 1671 height = -height; 1672 halfheight = (height + 1) >> 1; 1673 src_y = src_y + (height - 1) * src_stride_y; 1674 src_u = src_u + (halfheight - 1) * src_stride_u; 1675 src_v = src_v + (halfheight - 1) * src_stride_v; 1676 src_stride_y = -src_stride_y; 1677 src_stride_u = -src_stride_u; 1678 src_stride_v = -src_stride_v; 1679 } 1680 1681 if (dst_y) { 1682 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); 1683 } 1684 1685 // Copy UV planes as is - I420 1686 if (src_pixel_stride_uv == 1) { 1687 CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight); 1688 CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight); 1689 return 0; 1690 // Split UV planes - NV21 1691 } else if (src_pixel_stride_uv == 2 && vu_off == -1 && 1692 src_stride_u == src_stride_v) { 1693 SplitUVPlane(src_v, src_stride_v, dst_v, dst_stride_v, dst_u, dst_stride_u, 1694 halfwidth, halfheight); 1695 return 0; 1696 // Split UV planes - NV12 1697 } else if (src_pixel_stride_uv == 2 && vu_off == 1 && 1698 src_stride_u == src_stride_v) { 1699 SplitUVPlane(src_u, src_stride_u, dst_u, dst_stride_u, dst_v, dst_stride_v, 1700 halfwidth, halfheight); 1701 return 0; 1702 } 1703 1704 for (y = 0; y < halfheight; ++y) { 1705 SplitPixels(src_u, src_pixel_stride_uv, dst_u, halfwidth); 1706 SplitPixels(src_v, src_pixel_stride_uv, dst_v, halfwidth); 1707 src_u += src_stride_u; 1708 src_v += src_stride_v; 1709 dst_u += dst_stride_u; 1710 dst_v += dst_stride_v; 1711 } 1712 return 0; 1713 } 1714 1715 #ifdef __cplusplus 1716 } // extern "C" 1717 } // namespace libyuv 1718 #endif 1719