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_argb.h" 12 13 #include "libyuv/cpu_id.h" 14 #ifdef HAVE_JPEG 15 #include "libyuv/mjpeg_decoder.h" 16 #endif 17 #include "libyuv/planar_functions.h" // For CopyPlane and ARGBShuffle. 18 #include "libyuv/rotate_argb.h" 19 #include "libyuv/row.h" 20 #include "libyuv/video_common.h" 21 22 #ifdef __cplusplus 23 namespace libyuv { 24 extern "C" { 25 #endif 26 27 // Copy ARGB with optional flipping 28 LIBYUV_API 29 int ARGBCopy(const uint8_t* src_argb, 30 int src_stride_argb, 31 uint8_t* dst_argb, 32 int dst_stride_argb, 33 int width, 34 int height) { 35 if (!src_argb || !dst_argb || width <= 0 || height == 0) { 36 return -1; 37 } 38 // Negative height means invert the image. 39 if (height < 0) { 40 height = -height; 41 src_argb = src_argb + (height - 1) * src_stride_argb; 42 src_stride_argb = -src_stride_argb; 43 } 44 45 CopyPlane(src_argb, src_stride_argb, dst_argb, dst_stride_argb, width * 4, 46 height); 47 return 0; 48 } 49 50 // Convert I420 to ARGB with matrix 51 static int I420ToARGBMatrix(const uint8_t* src_y, 52 int src_stride_y, 53 const uint8_t* src_u, 54 int src_stride_u, 55 const uint8_t* src_v, 56 int src_stride_v, 57 uint8_t* dst_argb, 58 int dst_stride_argb, 59 const struct YuvConstants* yuvconstants, 60 int width, 61 int height) { 62 int y; 63 void (*I422ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf, 64 const uint8_t* v_buf, uint8_t* rgb_buf, 65 const struct YuvConstants* yuvconstants, int width) = 66 I422ToARGBRow_C; 67 if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) { 68 return -1; 69 } 70 // Negative height means invert the image. 71 if (height < 0) { 72 height = -height; 73 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 74 dst_stride_argb = -dst_stride_argb; 75 } 76 #if defined(HAS_I422TOARGBROW_SSSE3) 77 if (TestCpuFlag(kCpuHasSSSE3)) { 78 I422ToARGBRow = I422ToARGBRow_Any_SSSE3; 79 if (IS_ALIGNED(width, 8)) { 80 I422ToARGBRow = I422ToARGBRow_SSSE3; 81 } 82 } 83 #endif 84 #if defined(HAS_I422TOARGBROW_AVX2) 85 if (TestCpuFlag(kCpuHasAVX2)) { 86 I422ToARGBRow = I422ToARGBRow_Any_AVX2; 87 if (IS_ALIGNED(width, 16)) { 88 I422ToARGBRow = I422ToARGBRow_AVX2; 89 } 90 } 91 #endif 92 #if defined(HAS_I422TOARGBROW_NEON) 93 if (TestCpuFlag(kCpuHasNEON)) { 94 I422ToARGBRow = I422ToARGBRow_Any_NEON; 95 if (IS_ALIGNED(width, 8)) { 96 I422ToARGBRow = I422ToARGBRow_NEON; 97 } 98 } 99 #endif 100 #if defined(HAS_I422TOARGBROW_MSA) 101 if (TestCpuFlag(kCpuHasMSA)) { 102 I422ToARGBRow = I422ToARGBRow_Any_MSA; 103 if (IS_ALIGNED(width, 8)) { 104 I422ToARGBRow = I422ToARGBRow_MSA; 105 } 106 } 107 #endif 108 109 for (y = 0; y < height; ++y) { 110 I422ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width); 111 dst_argb += dst_stride_argb; 112 src_y += src_stride_y; 113 if (y & 1) { 114 src_u += src_stride_u; 115 src_v += src_stride_v; 116 } 117 } 118 return 0; 119 } 120 121 // Convert I420 to ARGB. 122 LIBYUV_API 123 int I420ToARGB(const uint8_t* src_y, 124 int src_stride_y, 125 const uint8_t* src_u, 126 int src_stride_u, 127 const uint8_t* src_v, 128 int src_stride_v, 129 uint8_t* dst_argb, 130 int dst_stride_argb, 131 int width, 132 int height) { 133 return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, 134 src_stride_v, dst_argb, dst_stride_argb, 135 &kYuvI601Constants, width, height); 136 } 137 138 // Convert I420 to ABGR. 139 LIBYUV_API 140 int I420ToABGR(const uint8_t* src_y, 141 int src_stride_y, 142 const uint8_t* src_u, 143 int src_stride_u, 144 const uint8_t* src_v, 145 int src_stride_v, 146 uint8_t* dst_abgr, 147 int dst_stride_abgr, 148 int width, 149 int height) { 150 return I420ToARGBMatrix(src_y, src_stride_y, src_v, 151 src_stride_v, // Swap U and V 152 src_u, src_stride_u, dst_abgr, dst_stride_abgr, 153 &kYvuI601Constants, // Use Yvu matrix 154 width, height); 155 } 156 157 // Convert J420 to ARGB. 158 LIBYUV_API 159 int J420ToARGB(const uint8_t* src_y, 160 int src_stride_y, 161 const uint8_t* src_u, 162 int src_stride_u, 163 const uint8_t* src_v, 164 int src_stride_v, 165 uint8_t* dst_argb, 166 int dst_stride_argb, 167 int width, 168 int height) { 169 return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, 170 src_stride_v, dst_argb, dst_stride_argb, 171 &kYuvJPEGConstants, width, height); 172 } 173 174 // Convert J420 to ABGR. 175 LIBYUV_API 176 int J420ToABGR(const uint8_t* src_y, 177 int src_stride_y, 178 const uint8_t* src_u, 179 int src_stride_u, 180 const uint8_t* src_v, 181 int src_stride_v, 182 uint8_t* dst_abgr, 183 int dst_stride_abgr, 184 int width, 185 int height) { 186 return I420ToARGBMatrix(src_y, src_stride_y, src_v, 187 src_stride_v, // Swap U and V 188 src_u, src_stride_u, dst_abgr, dst_stride_abgr, 189 &kYvuJPEGConstants, // Use Yvu matrix 190 width, height); 191 } 192 193 // Convert H420 to ARGB. 194 LIBYUV_API 195 int H420ToARGB(const uint8_t* src_y, 196 int src_stride_y, 197 const uint8_t* src_u, 198 int src_stride_u, 199 const uint8_t* src_v, 200 int src_stride_v, 201 uint8_t* dst_argb, 202 int dst_stride_argb, 203 int width, 204 int height) { 205 return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, 206 src_stride_v, dst_argb, dst_stride_argb, 207 &kYuvH709Constants, width, height); 208 } 209 210 // Convert H420 to ABGR. 211 LIBYUV_API 212 int H420ToABGR(const uint8_t* src_y, 213 int src_stride_y, 214 const uint8_t* src_u, 215 int src_stride_u, 216 const uint8_t* src_v, 217 int src_stride_v, 218 uint8_t* dst_abgr, 219 int dst_stride_abgr, 220 int width, 221 int height) { 222 return I420ToARGBMatrix(src_y, src_stride_y, src_v, 223 src_stride_v, // Swap U and V 224 src_u, src_stride_u, dst_abgr, dst_stride_abgr, 225 &kYvuH709Constants, // Use Yvu matrix 226 width, height); 227 } 228 229 // Convert I422 to ARGB with matrix 230 static int I422ToARGBMatrix(const uint8_t* src_y, 231 int src_stride_y, 232 const uint8_t* src_u, 233 int src_stride_u, 234 const uint8_t* src_v, 235 int src_stride_v, 236 uint8_t* dst_argb, 237 int dst_stride_argb, 238 const struct YuvConstants* yuvconstants, 239 int width, 240 int height) { 241 int y; 242 void (*I422ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf, 243 const uint8_t* v_buf, uint8_t* rgb_buf, 244 const struct YuvConstants* yuvconstants, int width) = 245 I422ToARGBRow_C; 246 if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) { 247 return -1; 248 } 249 // Negative height means invert the image. 250 if (height < 0) { 251 height = -height; 252 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 253 dst_stride_argb = -dst_stride_argb; 254 } 255 // Coalesce rows. 256 if (src_stride_y == width && src_stride_u * 2 == width && 257 src_stride_v * 2 == width && dst_stride_argb == width * 4) { 258 width *= height; 259 height = 1; 260 src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0; 261 } 262 #if defined(HAS_I422TOARGBROW_SSSE3) 263 if (TestCpuFlag(kCpuHasSSSE3)) { 264 I422ToARGBRow = I422ToARGBRow_Any_SSSE3; 265 if (IS_ALIGNED(width, 8)) { 266 I422ToARGBRow = I422ToARGBRow_SSSE3; 267 } 268 } 269 #endif 270 #if defined(HAS_I422TOARGBROW_AVX2) 271 if (TestCpuFlag(kCpuHasAVX2)) { 272 I422ToARGBRow = I422ToARGBRow_Any_AVX2; 273 if (IS_ALIGNED(width, 16)) { 274 I422ToARGBRow = I422ToARGBRow_AVX2; 275 } 276 } 277 #endif 278 #if defined(HAS_I422TOARGBROW_NEON) 279 if (TestCpuFlag(kCpuHasNEON)) { 280 I422ToARGBRow = I422ToARGBRow_Any_NEON; 281 if (IS_ALIGNED(width, 8)) { 282 I422ToARGBRow = I422ToARGBRow_NEON; 283 } 284 } 285 #endif 286 #if defined(HAS_I422TOARGBROW_MSA) 287 if (TestCpuFlag(kCpuHasMSA)) { 288 I422ToARGBRow = I422ToARGBRow_Any_MSA; 289 if (IS_ALIGNED(width, 8)) { 290 I422ToARGBRow = I422ToARGBRow_MSA; 291 } 292 } 293 #endif 294 295 for (y = 0; y < height; ++y) { 296 I422ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width); 297 dst_argb += dst_stride_argb; 298 src_y += src_stride_y; 299 src_u += src_stride_u; 300 src_v += src_stride_v; 301 } 302 return 0; 303 } 304 305 // Convert I422 to ARGB. 306 LIBYUV_API 307 int I422ToARGB(const uint8_t* src_y, 308 int src_stride_y, 309 const uint8_t* src_u, 310 int src_stride_u, 311 const uint8_t* src_v, 312 int src_stride_v, 313 uint8_t* dst_argb, 314 int dst_stride_argb, 315 int width, 316 int height) { 317 return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, 318 src_stride_v, dst_argb, dst_stride_argb, 319 &kYuvI601Constants, width, height); 320 } 321 322 // Convert I422 to ABGR. 323 LIBYUV_API 324 int I422ToABGR(const uint8_t* src_y, 325 int src_stride_y, 326 const uint8_t* src_u, 327 int src_stride_u, 328 const uint8_t* src_v, 329 int src_stride_v, 330 uint8_t* dst_abgr, 331 int dst_stride_abgr, 332 int width, 333 int height) { 334 return I422ToARGBMatrix(src_y, src_stride_y, src_v, 335 src_stride_v, // Swap U and V 336 src_u, src_stride_u, dst_abgr, dst_stride_abgr, 337 &kYvuI601Constants, // Use Yvu matrix 338 width, height); 339 } 340 341 // Convert J422 to ARGB. 342 LIBYUV_API 343 int J422ToARGB(const uint8_t* src_y, 344 int src_stride_y, 345 const uint8_t* src_u, 346 int src_stride_u, 347 const uint8_t* src_v, 348 int src_stride_v, 349 uint8_t* dst_argb, 350 int dst_stride_argb, 351 int width, 352 int height) { 353 return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, 354 src_stride_v, dst_argb, dst_stride_argb, 355 &kYuvJPEGConstants, width, height); 356 } 357 358 // Convert J422 to ABGR. 359 LIBYUV_API 360 int J422ToABGR(const uint8_t* src_y, 361 int src_stride_y, 362 const uint8_t* src_u, 363 int src_stride_u, 364 const uint8_t* src_v, 365 int src_stride_v, 366 uint8_t* dst_abgr, 367 int dst_stride_abgr, 368 int width, 369 int height) { 370 return I422ToARGBMatrix(src_y, src_stride_y, src_v, 371 src_stride_v, // Swap U and V 372 src_u, src_stride_u, dst_abgr, dst_stride_abgr, 373 &kYvuJPEGConstants, // Use Yvu matrix 374 width, height); 375 } 376 377 // Convert H422 to ARGB. 378 LIBYUV_API 379 int H422ToARGB(const uint8_t* src_y, 380 int src_stride_y, 381 const uint8_t* src_u, 382 int src_stride_u, 383 const uint8_t* src_v, 384 int src_stride_v, 385 uint8_t* dst_argb, 386 int dst_stride_argb, 387 int width, 388 int height) { 389 return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, 390 src_stride_v, dst_argb, dst_stride_argb, 391 &kYuvH709Constants, width, height); 392 } 393 394 // Convert H422 to ABGR. 395 LIBYUV_API 396 int H422ToABGR(const uint8_t* src_y, 397 int src_stride_y, 398 const uint8_t* src_u, 399 int src_stride_u, 400 const uint8_t* src_v, 401 int src_stride_v, 402 uint8_t* dst_abgr, 403 int dst_stride_abgr, 404 int width, 405 int height) { 406 return I422ToARGBMatrix(src_y, src_stride_y, src_v, 407 src_stride_v, // Swap U and V 408 src_u, src_stride_u, dst_abgr, dst_stride_abgr, 409 &kYvuH709Constants, // Use Yvu matrix 410 width, height); 411 } 412 413 // Convert 10 bit YUV to ARGB with matrix 414 // TODO(fbarchard): Consider passing scale multiplier to I210ToARGB to 415 // multiply 10 bit yuv into high bits to allow any number of bits. 416 static int I010ToAR30Matrix(const uint16_t* src_y, 417 int src_stride_y, 418 const uint16_t* src_u, 419 int src_stride_u, 420 const uint16_t* src_v, 421 int src_stride_v, 422 uint8_t* dst_ar30, 423 int dst_stride_ar30, 424 const struct YuvConstants* yuvconstants, 425 int width, 426 int height) { 427 int y; 428 void (*I210ToAR30Row)(const uint16_t* y_buf, const uint16_t* u_buf, 429 const uint16_t* v_buf, uint8_t* rgb_buf, 430 const struct YuvConstants* yuvconstants, int width) = 431 I210ToAR30Row_C; 432 if (!src_y || !src_u || !src_v || !dst_ar30 || width <= 0 || height == 0) { 433 return -1; 434 } 435 // Negative height means invert the image. 436 if (height < 0) { 437 height = -height; 438 dst_ar30 = dst_ar30 + (height - 1) * dst_stride_ar30; 439 dst_stride_ar30 = -dst_stride_ar30; 440 } 441 #if defined(HAS_I210TOAR30ROW_SSSE3) 442 if (TestCpuFlag(kCpuHasSSSE3)) { 443 I210ToAR30Row = I210ToAR30Row_Any_SSSE3; 444 if (IS_ALIGNED(width, 8)) { 445 I210ToAR30Row = I210ToAR30Row_SSSE3; 446 } 447 } 448 #endif 449 #if defined(HAS_I210TOAR30ROW_AVX2) 450 if (TestCpuFlag(kCpuHasAVX2)) { 451 I210ToAR30Row = I210ToAR30Row_Any_AVX2; 452 if (IS_ALIGNED(width, 16)) { 453 I210ToAR30Row = I210ToAR30Row_AVX2; 454 } 455 } 456 #endif 457 for (y = 0; y < height; ++y) { 458 I210ToAR30Row(src_y, src_u, src_v, dst_ar30, yuvconstants, width); 459 dst_ar30 += dst_stride_ar30; 460 src_y += src_stride_y; 461 if (y & 1) { 462 src_u += src_stride_u; 463 src_v += src_stride_v; 464 } 465 } 466 return 0; 467 } 468 469 // Convert I010 to AR30. 470 LIBYUV_API 471 int I010ToAR30(const uint16_t* src_y, 472 int src_stride_y, 473 const uint16_t* src_u, 474 int src_stride_u, 475 const uint16_t* src_v, 476 int src_stride_v, 477 uint8_t* dst_ar30, 478 int dst_stride_ar30, 479 int width, 480 int height) { 481 return I010ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v, 482 src_stride_v, dst_ar30, dst_stride_ar30, 483 &kYuvI601Constants, width, height); 484 } 485 486 // Convert H010 to AR30. 487 LIBYUV_API 488 int H010ToAR30(const uint16_t* src_y, 489 int src_stride_y, 490 const uint16_t* src_u, 491 int src_stride_u, 492 const uint16_t* src_v, 493 int src_stride_v, 494 uint8_t* dst_ar30, 495 int dst_stride_ar30, 496 int width, 497 int height) { 498 return I010ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v, 499 src_stride_v, dst_ar30, dst_stride_ar30, 500 &kYuvH709Constants, width, height); 501 } 502 503 // Convert I010 to AB30. 504 LIBYUV_API 505 int I010ToAB30(const uint16_t* src_y, 506 int src_stride_y, 507 const uint16_t* src_u, 508 int src_stride_u, 509 const uint16_t* src_v, 510 int src_stride_v, 511 uint8_t* dst_ab30, 512 int dst_stride_ab30, 513 int width, 514 int height) { 515 return I010ToAR30Matrix(src_y, src_stride_y, src_v, src_stride_v, src_u, 516 src_stride_u, dst_ab30, dst_stride_ab30, 517 &kYvuI601Constants, width, height); 518 } 519 520 // Convert H010 to AB30. 521 LIBYUV_API 522 int H010ToAB30(const uint16_t* src_y, 523 int src_stride_y, 524 const uint16_t* src_u, 525 int src_stride_u, 526 const uint16_t* src_v, 527 int src_stride_v, 528 uint8_t* dst_ab30, 529 int dst_stride_ab30, 530 int width, 531 int height) { 532 return I010ToAR30Matrix(src_y, src_stride_y, src_v, src_stride_v, src_u, 533 src_stride_u, dst_ab30, dst_stride_ab30, 534 &kYvuH709Constants, width, height); 535 } 536 537 // Convert 10 bit YUV to ARGB with matrix 538 static int I010ToARGBMatrix(const uint16_t* src_y, 539 int src_stride_y, 540 const uint16_t* src_u, 541 int src_stride_u, 542 const uint16_t* src_v, 543 int src_stride_v, 544 uint8_t* dst_argb, 545 int dst_stride_argb, 546 const struct YuvConstants* yuvconstants, 547 int width, 548 int height) { 549 int y; 550 void (*I210ToARGBRow)(const uint16_t* y_buf, const uint16_t* u_buf, 551 const uint16_t* v_buf, uint8_t* rgb_buf, 552 const struct YuvConstants* yuvconstants, int width) = 553 I210ToARGBRow_C; 554 if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) { 555 return -1; 556 } 557 // Negative height means invert the image. 558 if (height < 0) { 559 height = -height; 560 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 561 dst_stride_argb = -dst_stride_argb; 562 } 563 #if defined(HAS_I210TOARGBROW_SSSE3) 564 if (TestCpuFlag(kCpuHasSSSE3)) { 565 I210ToARGBRow = I210ToARGBRow_Any_SSSE3; 566 if (IS_ALIGNED(width, 8)) { 567 I210ToARGBRow = I210ToARGBRow_SSSE3; 568 } 569 } 570 #endif 571 #if defined(HAS_I210TOARGBROW_AVX2) 572 if (TestCpuFlag(kCpuHasAVX2)) { 573 I210ToARGBRow = I210ToARGBRow_Any_AVX2; 574 if (IS_ALIGNED(width, 16)) { 575 I210ToARGBRow = I210ToARGBRow_AVX2; 576 } 577 } 578 #endif 579 for (y = 0; y < height; ++y) { 580 I210ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width); 581 dst_argb += dst_stride_argb; 582 src_y += src_stride_y; 583 if (y & 1) { 584 src_u += src_stride_u; 585 src_v += src_stride_v; 586 } 587 } 588 return 0; 589 } 590 591 // Convert I010 to ARGB. 592 LIBYUV_API 593 int I010ToARGB(const uint16_t* src_y, 594 int src_stride_y, 595 const uint16_t* src_u, 596 int src_stride_u, 597 const uint16_t* src_v, 598 int src_stride_v, 599 uint8_t* dst_argb, 600 int dst_stride_argb, 601 int width, 602 int height) { 603 return I010ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, 604 src_stride_v, dst_argb, dst_stride_argb, 605 &kYuvI601Constants, width, height); 606 } 607 608 // Convert I010 to ABGR. 609 LIBYUV_API 610 int I010ToABGR(const uint16_t* src_y, 611 int src_stride_y, 612 const uint16_t* src_u, 613 int src_stride_u, 614 const uint16_t* src_v, 615 int src_stride_v, 616 uint8_t* dst_abgr, 617 int dst_stride_abgr, 618 int width, 619 int height) { 620 return I010ToARGBMatrix(src_y, src_stride_y, src_v, 621 src_stride_v, // Swap U and V 622 src_u, src_stride_u, dst_abgr, dst_stride_abgr, 623 &kYvuI601Constants, // Use Yvu matrix 624 width, height); 625 } 626 627 // Convert H010 to ARGB. 628 LIBYUV_API 629 int H010ToARGB(const uint16_t* src_y, 630 int src_stride_y, 631 const uint16_t* src_u, 632 int src_stride_u, 633 const uint16_t* src_v, 634 int src_stride_v, 635 uint8_t* dst_argb, 636 int dst_stride_argb, 637 int width, 638 int height) { 639 return I010ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, 640 src_stride_v, dst_argb, dst_stride_argb, 641 &kYuvH709Constants, width, height); 642 } 643 644 // Convert H010 to ABGR. 645 LIBYUV_API 646 int H010ToABGR(const uint16_t* src_y, 647 int src_stride_y, 648 const uint16_t* src_u, 649 int src_stride_u, 650 const uint16_t* src_v, 651 int src_stride_v, 652 uint8_t* dst_abgr, 653 int dst_stride_abgr, 654 int width, 655 int height) { 656 return I010ToARGBMatrix(src_y, src_stride_y, src_v, 657 src_stride_v, // Swap U and V 658 src_u, src_stride_u, dst_abgr, dst_stride_abgr, 659 &kYvuH709Constants, // Use Yvu matrix 660 width, height); 661 } 662 663 // Convert I444 to ARGB with matrix 664 static int I444ToARGBMatrix(const uint8_t* src_y, 665 int src_stride_y, 666 const uint8_t* src_u, 667 int src_stride_u, 668 const uint8_t* src_v, 669 int src_stride_v, 670 uint8_t* dst_argb, 671 int dst_stride_argb, 672 const struct YuvConstants* yuvconstants, 673 int width, 674 int height) { 675 int y; 676 void (*I444ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf, 677 const uint8_t* v_buf, uint8_t* rgb_buf, 678 const struct YuvConstants* yuvconstants, int width) = 679 I444ToARGBRow_C; 680 if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) { 681 return -1; 682 } 683 // Negative height means invert the image. 684 if (height < 0) { 685 height = -height; 686 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 687 dst_stride_argb = -dst_stride_argb; 688 } 689 // Coalesce rows. 690 if (src_stride_y == width && src_stride_u == width && src_stride_v == width && 691 dst_stride_argb == width * 4) { 692 width *= height; 693 height = 1; 694 src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0; 695 } 696 #if defined(HAS_I444TOARGBROW_SSSE3) 697 if (TestCpuFlag(kCpuHasSSSE3)) { 698 I444ToARGBRow = I444ToARGBRow_Any_SSSE3; 699 if (IS_ALIGNED(width, 8)) { 700 I444ToARGBRow = I444ToARGBRow_SSSE3; 701 } 702 } 703 #endif 704 #if defined(HAS_I444TOARGBROW_AVX2) 705 if (TestCpuFlag(kCpuHasAVX2)) { 706 I444ToARGBRow = I444ToARGBRow_Any_AVX2; 707 if (IS_ALIGNED(width, 16)) { 708 I444ToARGBRow = I444ToARGBRow_AVX2; 709 } 710 } 711 #endif 712 #if defined(HAS_I444TOARGBROW_NEON) 713 if (TestCpuFlag(kCpuHasNEON)) { 714 I444ToARGBRow = I444ToARGBRow_Any_NEON; 715 if (IS_ALIGNED(width, 8)) { 716 I444ToARGBRow = I444ToARGBRow_NEON; 717 } 718 } 719 #endif 720 #if defined(HAS_I444TOARGBROW_MSA) 721 if (TestCpuFlag(kCpuHasMSA)) { 722 I444ToARGBRow = I444ToARGBRow_Any_MSA; 723 if (IS_ALIGNED(width, 8)) { 724 I444ToARGBRow = I444ToARGBRow_MSA; 725 } 726 } 727 #endif 728 729 for (y = 0; y < height; ++y) { 730 I444ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width); 731 dst_argb += dst_stride_argb; 732 src_y += src_stride_y; 733 src_u += src_stride_u; 734 src_v += src_stride_v; 735 } 736 return 0; 737 } 738 739 // Convert I444 to ARGB. 740 LIBYUV_API 741 int I444ToARGB(const uint8_t* src_y, 742 int src_stride_y, 743 const uint8_t* src_u, 744 int src_stride_u, 745 const uint8_t* src_v, 746 int src_stride_v, 747 uint8_t* dst_argb, 748 int dst_stride_argb, 749 int width, 750 int height) { 751 return I444ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, 752 src_stride_v, dst_argb, dst_stride_argb, 753 &kYuvI601Constants, width, height); 754 } 755 756 // Convert I444 to ABGR. 757 LIBYUV_API 758 int I444ToABGR(const uint8_t* src_y, 759 int src_stride_y, 760 const uint8_t* src_u, 761 int src_stride_u, 762 const uint8_t* src_v, 763 int src_stride_v, 764 uint8_t* dst_abgr, 765 int dst_stride_abgr, 766 int width, 767 int height) { 768 return I444ToARGBMatrix(src_y, src_stride_y, src_v, 769 src_stride_v, // Swap U and V 770 src_u, src_stride_u, dst_abgr, dst_stride_abgr, 771 &kYvuI601Constants, // Use Yvu matrix 772 width, height); 773 } 774 775 // Convert J444 to ARGB. 776 LIBYUV_API 777 int J444ToARGB(const uint8_t* src_y, 778 int src_stride_y, 779 const uint8_t* src_u, 780 int src_stride_u, 781 const uint8_t* src_v, 782 int src_stride_v, 783 uint8_t* dst_argb, 784 int dst_stride_argb, 785 int width, 786 int height) { 787 return I444ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, 788 src_stride_v, dst_argb, dst_stride_argb, 789 &kYuvJPEGConstants, width, height); 790 } 791 792 // Convert I420 with Alpha to preattenuated ARGB. 793 static int I420AlphaToARGBMatrix(const uint8_t* src_y, 794 int src_stride_y, 795 const uint8_t* src_u, 796 int src_stride_u, 797 const uint8_t* src_v, 798 int src_stride_v, 799 const uint8_t* src_a, 800 int src_stride_a, 801 uint8_t* dst_argb, 802 int dst_stride_argb, 803 const struct YuvConstants* yuvconstants, 804 int width, 805 int height, 806 int attenuate) { 807 int y; 808 void (*I422AlphaToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf, 809 const uint8_t* v_buf, const uint8_t* a_buf, 810 uint8_t* dst_argb, 811 const struct YuvConstants* yuvconstants, 812 int width) = I422AlphaToARGBRow_C; 813 void (*ARGBAttenuateRow)(const uint8_t* src_argb, uint8_t* dst_argb, 814 int width) = ARGBAttenuateRow_C; 815 if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) { 816 return -1; 817 } 818 // Negative height means invert the image. 819 if (height < 0) { 820 height = -height; 821 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 822 dst_stride_argb = -dst_stride_argb; 823 } 824 #if defined(HAS_I422ALPHATOARGBROW_SSSE3) 825 if (TestCpuFlag(kCpuHasSSSE3)) { 826 I422AlphaToARGBRow = I422AlphaToARGBRow_Any_SSSE3; 827 if (IS_ALIGNED(width, 8)) { 828 I422AlphaToARGBRow = I422AlphaToARGBRow_SSSE3; 829 } 830 } 831 #endif 832 #if defined(HAS_I422ALPHATOARGBROW_AVX2) 833 if (TestCpuFlag(kCpuHasAVX2)) { 834 I422AlphaToARGBRow = I422AlphaToARGBRow_Any_AVX2; 835 if (IS_ALIGNED(width, 16)) { 836 I422AlphaToARGBRow = I422AlphaToARGBRow_AVX2; 837 } 838 } 839 #endif 840 #if defined(HAS_I422ALPHATOARGBROW_NEON) 841 if (TestCpuFlag(kCpuHasNEON)) { 842 I422AlphaToARGBRow = I422AlphaToARGBRow_Any_NEON; 843 if (IS_ALIGNED(width, 8)) { 844 I422AlphaToARGBRow = I422AlphaToARGBRow_NEON; 845 } 846 } 847 #endif 848 #if defined(HAS_I422ALPHATOARGBROW_MSA) 849 if (TestCpuFlag(kCpuHasMSA)) { 850 I422AlphaToARGBRow = I422AlphaToARGBRow_Any_MSA; 851 if (IS_ALIGNED(width, 8)) { 852 I422AlphaToARGBRow = I422AlphaToARGBRow_MSA; 853 } 854 } 855 #endif 856 #if defined(HAS_ARGBATTENUATEROW_SSSE3) 857 if (TestCpuFlag(kCpuHasSSSE3)) { 858 ARGBAttenuateRow = ARGBAttenuateRow_Any_SSSE3; 859 if (IS_ALIGNED(width, 4)) { 860 ARGBAttenuateRow = ARGBAttenuateRow_SSSE3; 861 } 862 } 863 #endif 864 #if defined(HAS_ARGBATTENUATEROW_AVX2) 865 if (TestCpuFlag(kCpuHasAVX2)) { 866 ARGBAttenuateRow = ARGBAttenuateRow_Any_AVX2; 867 if (IS_ALIGNED(width, 8)) { 868 ARGBAttenuateRow = ARGBAttenuateRow_AVX2; 869 } 870 } 871 #endif 872 #if defined(HAS_ARGBATTENUATEROW_NEON) 873 if (TestCpuFlag(kCpuHasNEON)) { 874 ARGBAttenuateRow = ARGBAttenuateRow_Any_NEON; 875 if (IS_ALIGNED(width, 8)) { 876 ARGBAttenuateRow = ARGBAttenuateRow_NEON; 877 } 878 } 879 #endif 880 #if defined(HAS_ARGBATTENUATEROW_MSA) 881 if (TestCpuFlag(kCpuHasMSA)) { 882 ARGBAttenuateRow = ARGBAttenuateRow_Any_MSA; 883 if (IS_ALIGNED(width, 8)) { 884 ARGBAttenuateRow = ARGBAttenuateRow_MSA; 885 } 886 } 887 #endif 888 889 for (y = 0; y < height; ++y) { 890 I422AlphaToARGBRow(src_y, src_u, src_v, src_a, dst_argb, yuvconstants, 891 width); 892 if (attenuate) { 893 ARGBAttenuateRow(dst_argb, dst_argb, width); 894 } 895 dst_argb += dst_stride_argb; 896 src_a += src_stride_a; 897 src_y += src_stride_y; 898 if (y & 1) { 899 src_u += src_stride_u; 900 src_v += src_stride_v; 901 } 902 } 903 return 0; 904 } 905 906 // Convert I420 with Alpha to ARGB. 907 LIBYUV_API 908 int I420AlphaToARGB(const uint8_t* src_y, 909 int src_stride_y, 910 const uint8_t* src_u, 911 int src_stride_u, 912 const uint8_t* src_v, 913 int src_stride_v, 914 const uint8_t* src_a, 915 int src_stride_a, 916 uint8_t* dst_argb, 917 int dst_stride_argb, 918 int width, 919 int height, 920 int attenuate) { 921 return I420AlphaToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, 922 src_stride_v, src_a, src_stride_a, dst_argb, 923 dst_stride_argb, &kYuvI601Constants, width, 924 height, attenuate); 925 } 926 927 // Convert I420 with Alpha to ABGR. 928 LIBYUV_API 929 int I420AlphaToABGR(const uint8_t* src_y, 930 int src_stride_y, 931 const uint8_t* src_u, 932 int src_stride_u, 933 const uint8_t* src_v, 934 int src_stride_v, 935 const uint8_t* src_a, 936 int src_stride_a, 937 uint8_t* dst_abgr, 938 int dst_stride_abgr, 939 int width, 940 int height, 941 int attenuate) { 942 return I420AlphaToARGBMatrix( 943 src_y, src_stride_y, src_v, src_stride_v, // Swap U and V 944 src_u, src_stride_u, src_a, src_stride_a, dst_abgr, dst_stride_abgr, 945 &kYvuI601Constants, // Use Yvu matrix 946 width, height, attenuate); 947 } 948 949 // Convert I400 to ARGB. 950 LIBYUV_API 951 int I400ToARGB(const uint8_t* src_y, 952 int src_stride_y, 953 uint8_t* dst_argb, 954 int dst_stride_argb, 955 int width, 956 int height) { 957 int y; 958 void (*I400ToARGBRow)(const uint8_t* y_buf, uint8_t* rgb_buf, int width) = 959 I400ToARGBRow_C; 960 if (!src_y || !dst_argb || width <= 0 || height == 0) { 961 return -1; 962 } 963 // Negative height means invert the image. 964 if (height < 0) { 965 height = -height; 966 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 967 dst_stride_argb = -dst_stride_argb; 968 } 969 // Coalesce rows. 970 if (src_stride_y == width && dst_stride_argb == width * 4) { 971 width *= height; 972 height = 1; 973 src_stride_y = dst_stride_argb = 0; 974 } 975 #if defined(HAS_I400TOARGBROW_SSE2) 976 if (TestCpuFlag(kCpuHasSSE2)) { 977 I400ToARGBRow = I400ToARGBRow_Any_SSE2; 978 if (IS_ALIGNED(width, 8)) { 979 I400ToARGBRow = I400ToARGBRow_SSE2; 980 } 981 } 982 #endif 983 #if defined(HAS_I400TOARGBROW_AVX2) 984 if (TestCpuFlag(kCpuHasAVX2)) { 985 I400ToARGBRow = I400ToARGBRow_Any_AVX2; 986 if (IS_ALIGNED(width, 16)) { 987 I400ToARGBRow = I400ToARGBRow_AVX2; 988 } 989 } 990 #endif 991 #if defined(HAS_I400TOARGBROW_NEON) 992 if (TestCpuFlag(kCpuHasNEON)) { 993 I400ToARGBRow = I400ToARGBRow_Any_NEON; 994 if (IS_ALIGNED(width, 8)) { 995 I400ToARGBRow = I400ToARGBRow_NEON; 996 } 997 } 998 #endif 999 #if defined(HAS_I400TOARGBROW_MSA) 1000 if (TestCpuFlag(kCpuHasMSA)) { 1001 I400ToARGBRow = I400ToARGBRow_Any_MSA; 1002 if (IS_ALIGNED(width, 16)) { 1003 I400ToARGBRow = I400ToARGBRow_MSA; 1004 } 1005 } 1006 #endif 1007 1008 for (y = 0; y < height; ++y) { 1009 I400ToARGBRow(src_y, dst_argb, width); 1010 dst_argb += dst_stride_argb; 1011 src_y += src_stride_y; 1012 } 1013 return 0; 1014 } 1015 1016 // Convert J400 to ARGB. 1017 LIBYUV_API 1018 int J400ToARGB(const uint8_t* src_y, 1019 int src_stride_y, 1020 uint8_t* dst_argb, 1021 int dst_stride_argb, 1022 int width, 1023 int height) { 1024 int y; 1025 void (*J400ToARGBRow)(const uint8_t* src_y, uint8_t* dst_argb, int width) = 1026 J400ToARGBRow_C; 1027 if (!src_y || !dst_argb || width <= 0 || height == 0) { 1028 return -1; 1029 } 1030 // Negative height means invert the image. 1031 if (height < 0) { 1032 height = -height; 1033 src_y = src_y + (height - 1) * src_stride_y; 1034 src_stride_y = -src_stride_y; 1035 } 1036 // Coalesce rows. 1037 if (src_stride_y == width && dst_stride_argb == width * 4) { 1038 width *= height; 1039 height = 1; 1040 src_stride_y = dst_stride_argb = 0; 1041 } 1042 #if defined(HAS_J400TOARGBROW_SSE2) 1043 if (TestCpuFlag(kCpuHasSSE2)) { 1044 J400ToARGBRow = J400ToARGBRow_Any_SSE2; 1045 if (IS_ALIGNED(width, 8)) { 1046 J400ToARGBRow = J400ToARGBRow_SSE2; 1047 } 1048 } 1049 #endif 1050 #if defined(HAS_J400TOARGBROW_AVX2) 1051 if (TestCpuFlag(kCpuHasAVX2)) { 1052 J400ToARGBRow = J400ToARGBRow_Any_AVX2; 1053 if (IS_ALIGNED(width, 16)) { 1054 J400ToARGBRow = J400ToARGBRow_AVX2; 1055 } 1056 } 1057 #endif 1058 #if defined(HAS_J400TOARGBROW_NEON) 1059 if (TestCpuFlag(kCpuHasNEON)) { 1060 J400ToARGBRow = J400ToARGBRow_Any_NEON; 1061 if (IS_ALIGNED(width, 8)) { 1062 J400ToARGBRow = J400ToARGBRow_NEON; 1063 } 1064 } 1065 #endif 1066 #if defined(HAS_J400TOARGBROW_MSA) 1067 if (TestCpuFlag(kCpuHasMSA)) { 1068 J400ToARGBRow = J400ToARGBRow_Any_MSA; 1069 if (IS_ALIGNED(width, 16)) { 1070 J400ToARGBRow = J400ToARGBRow_MSA; 1071 } 1072 } 1073 #endif 1074 for (y = 0; y < height; ++y) { 1075 J400ToARGBRow(src_y, dst_argb, width); 1076 src_y += src_stride_y; 1077 dst_argb += dst_stride_argb; 1078 } 1079 return 0; 1080 } 1081 1082 // Shuffle table for converting BGRA to ARGB. 1083 static const uvec8 kShuffleMaskBGRAToARGB = { 1084 3u, 2u, 1u, 0u, 7u, 6u, 5u, 4u, 11u, 10u, 9u, 8u, 15u, 14u, 13u, 12u}; 1085 1086 // Shuffle table for converting ABGR to ARGB. 1087 static const uvec8 kShuffleMaskABGRToARGB = { 1088 2u, 1u, 0u, 3u, 6u, 5u, 4u, 7u, 10u, 9u, 8u, 11u, 14u, 13u, 12u, 15u}; 1089 1090 // Shuffle table for converting RGBA to ARGB. 1091 static const uvec8 kShuffleMaskRGBAToARGB = { 1092 1u, 2u, 3u, 0u, 5u, 6u, 7u, 4u, 9u, 10u, 11u, 8u, 13u, 14u, 15u, 12u}; 1093 1094 // Convert BGRA to ARGB. 1095 LIBYUV_API 1096 int BGRAToARGB(const uint8_t* src_bgra, 1097 int src_stride_bgra, 1098 uint8_t* dst_argb, 1099 int dst_stride_argb, 1100 int width, 1101 int height) { 1102 return ARGBShuffle(src_bgra, src_stride_bgra, dst_argb, dst_stride_argb, 1103 (const uint8_t*)(&kShuffleMaskBGRAToARGB), width, height); 1104 } 1105 1106 // Convert ARGB to BGRA (same as BGRAToARGB). 1107 LIBYUV_API 1108 int ARGBToBGRA(const uint8_t* src_bgra, 1109 int src_stride_bgra, 1110 uint8_t* dst_argb, 1111 int dst_stride_argb, 1112 int width, 1113 int height) { 1114 return ARGBShuffle(src_bgra, src_stride_bgra, dst_argb, dst_stride_argb, 1115 (const uint8_t*)(&kShuffleMaskBGRAToARGB), width, height); 1116 } 1117 1118 // Convert ABGR to ARGB. 1119 LIBYUV_API 1120 int ABGRToARGB(const uint8_t* src_abgr, 1121 int src_stride_abgr, 1122 uint8_t* dst_argb, 1123 int dst_stride_argb, 1124 int width, 1125 int height) { 1126 return ARGBShuffle(src_abgr, src_stride_abgr, dst_argb, dst_stride_argb, 1127 (const uint8_t*)(&kShuffleMaskABGRToARGB), width, height); 1128 } 1129 1130 // Convert ARGB to ABGR to (same as ABGRToARGB). 1131 LIBYUV_API 1132 int ARGBToABGR(const uint8_t* src_abgr, 1133 int src_stride_abgr, 1134 uint8_t* dst_argb, 1135 int dst_stride_argb, 1136 int width, 1137 int height) { 1138 return ARGBShuffle(src_abgr, src_stride_abgr, dst_argb, dst_stride_argb, 1139 (const uint8_t*)(&kShuffleMaskABGRToARGB), width, height); 1140 } 1141 1142 // Convert RGBA to ARGB. 1143 LIBYUV_API 1144 int RGBAToARGB(const uint8_t* src_rgba, 1145 int src_stride_rgba, 1146 uint8_t* dst_argb, 1147 int dst_stride_argb, 1148 int width, 1149 int height) { 1150 return ARGBShuffle(src_rgba, src_stride_rgba, dst_argb, dst_stride_argb, 1151 (const uint8_t*)(&kShuffleMaskRGBAToARGB), width, height); 1152 } 1153 1154 // Convert RGB24 to ARGB. 1155 LIBYUV_API 1156 int RGB24ToARGB(const uint8_t* src_rgb24, 1157 int src_stride_rgb24, 1158 uint8_t* dst_argb, 1159 int dst_stride_argb, 1160 int width, 1161 int height) { 1162 int y; 1163 void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) = 1164 RGB24ToARGBRow_C; 1165 if (!src_rgb24 || !dst_argb || width <= 0 || height == 0) { 1166 return -1; 1167 } 1168 // Negative height means invert the image. 1169 if (height < 0) { 1170 height = -height; 1171 src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24; 1172 src_stride_rgb24 = -src_stride_rgb24; 1173 } 1174 // Coalesce rows. 1175 if (src_stride_rgb24 == width * 3 && dst_stride_argb == width * 4) { 1176 width *= height; 1177 height = 1; 1178 src_stride_rgb24 = dst_stride_argb = 0; 1179 } 1180 #if defined(HAS_RGB24TOARGBROW_SSSE3) 1181 if (TestCpuFlag(kCpuHasSSSE3)) { 1182 RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3; 1183 if (IS_ALIGNED(width, 16)) { 1184 RGB24ToARGBRow = RGB24ToARGBRow_SSSE3; 1185 } 1186 } 1187 #endif 1188 #if defined(HAS_RGB24TOARGBROW_NEON) 1189 if (TestCpuFlag(kCpuHasNEON)) { 1190 RGB24ToARGBRow = RGB24ToARGBRow_Any_NEON; 1191 if (IS_ALIGNED(width, 8)) { 1192 RGB24ToARGBRow = RGB24ToARGBRow_NEON; 1193 } 1194 } 1195 #endif 1196 #if defined(HAS_RGB24TOARGBROW_MSA) 1197 if (TestCpuFlag(kCpuHasMSA)) { 1198 RGB24ToARGBRow = RGB24ToARGBRow_Any_MSA; 1199 if (IS_ALIGNED(width, 16)) { 1200 RGB24ToARGBRow = RGB24ToARGBRow_MSA; 1201 } 1202 } 1203 #endif 1204 1205 for (y = 0; y < height; ++y) { 1206 RGB24ToARGBRow(src_rgb24, dst_argb, width); 1207 src_rgb24 += src_stride_rgb24; 1208 dst_argb += dst_stride_argb; 1209 } 1210 return 0; 1211 } 1212 1213 // Convert RAW to ARGB. 1214 LIBYUV_API 1215 int RAWToARGB(const uint8_t* src_raw, 1216 int src_stride_raw, 1217 uint8_t* dst_argb, 1218 int dst_stride_argb, 1219 int width, 1220 int height) { 1221 int y; 1222 void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) = 1223 RAWToARGBRow_C; 1224 if (!src_raw || !dst_argb || width <= 0 || height == 0) { 1225 return -1; 1226 } 1227 // Negative height means invert the image. 1228 if (height < 0) { 1229 height = -height; 1230 src_raw = src_raw + (height - 1) * src_stride_raw; 1231 src_stride_raw = -src_stride_raw; 1232 } 1233 // Coalesce rows. 1234 if (src_stride_raw == width * 3 && dst_stride_argb == width * 4) { 1235 width *= height; 1236 height = 1; 1237 src_stride_raw = dst_stride_argb = 0; 1238 } 1239 #if defined(HAS_RAWTOARGBROW_SSSE3) 1240 if (TestCpuFlag(kCpuHasSSSE3)) { 1241 RAWToARGBRow = RAWToARGBRow_Any_SSSE3; 1242 if (IS_ALIGNED(width, 16)) { 1243 RAWToARGBRow = RAWToARGBRow_SSSE3; 1244 } 1245 } 1246 #endif 1247 #if defined(HAS_RAWTOARGBROW_NEON) 1248 if (TestCpuFlag(kCpuHasNEON)) { 1249 RAWToARGBRow = RAWToARGBRow_Any_NEON; 1250 if (IS_ALIGNED(width, 8)) { 1251 RAWToARGBRow = RAWToARGBRow_NEON; 1252 } 1253 } 1254 #endif 1255 #if defined(HAS_RAWTOARGBROW_MSA) 1256 if (TestCpuFlag(kCpuHasMSA)) { 1257 RAWToARGBRow = RAWToARGBRow_Any_MSA; 1258 if (IS_ALIGNED(width, 16)) { 1259 RAWToARGBRow = RAWToARGBRow_MSA; 1260 } 1261 } 1262 #endif 1263 1264 for (y = 0; y < height; ++y) { 1265 RAWToARGBRow(src_raw, dst_argb, width); 1266 src_raw += src_stride_raw; 1267 dst_argb += dst_stride_argb; 1268 } 1269 return 0; 1270 } 1271 1272 // Convert RGB565 to ARGB. 1273 LIBYUV_API 1274 int RGB565ToARGB(const uint8_t* src_rgb565, 1275 int src_stride_rgb565, 1276 uint8_t* dst_argb, 1277 int dst_stride_argb, 1278 int width, 1279 int height) { 1280 int y; 1281 void (*RGB565ToARGBRow)(const uint8_t* src_rgb565, uint8_t* dst_argb, 1282 int width) = RGB565ToARGBRow_C; 1283 if (!src_rgb565 || !dst_argb || width <= 0 || height == 0) { 1284 return -1; 1285 } 1286 // Negative height means invert the image. 1287 if (height < 0) { 1288 height = -height; 1289 src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565; 1290 src_stride_rgb565 = -src_stride_rgb565; 1291 } 1292 // Coalesce rows. 1293 if (src_stride_rgb565 == width * 2 && dst_stride_argb == width * 4) { 1294 width *= height; 1295 height = 1; 1296 src_stride_rgb565 = dst_stride_argb = 0; 1297 } 1298 #if defined(HAS_RGB565TOARGBROW_SSE2) 1299 if (TestCpuFlag(kCpuHasSSE2)) { 1300 RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2; 1301 if (IS_ALIGNED(width, 8)) { 1302 RGB565ToARGBRow = RGB565ToARGBRow_SSE2; 1303 } 1304 } 1305 #endif 1306 #if defined(HAS_RGB565TOARGBROW_AVX2) 1307 if (TestCpuFlag(kCpuHasAVX2)) { 1308 RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2; 1309 if (IS_ALIGNED(width, 16)) { 1310 RGB565ToARGBRow = RGB565ToARGBRow_AVX2; 1311 } 1312 } 1313 #endif 1314 #if defined(HAS_RGB565TOARGBROW_NEON) 1315 if (TestCpuFlag(kCpuHasNEON)) { 1316 RGB565ToARGBRow = RGB565ToARGBRow_Any_NEON; 1317 if (IS_ALIGNED(width, 8)) { 1318 RGB565ToARGBRow = RGB565ToARGBRow_NEON; 1319 } 1320 } 1321 #endif 1322 #if defined(HAS_RGB565TOARGBROW_MSA) 1323 if (TestCpuFlag(kCpuHasMSA)) { 1324 RGB565ToARGBRow = RGB565ToARGBRow_Any_MSA; 1325 if (IS_ALIGNED(width, 16)) { 1326 RGB565ToARGBRow = RGB565ToARGBRow_MSA; 1327 } 1328 } 1329 #endif 1330 1331 for (y = 0; y < height; ++y) { 1332 RGB565ToARGBRow(src_rgb565, dst_argb, width); 1333 src_rgb565 += src_stride_rgb565; 1334 dst_argb += dst_stride_argb; 1335 } 1336 return 0; 1337 } 1338 1339 // Convert ARGB1555 to ARGB. 1340 LIBYUV_API 1341 int ARGB1555ToARGB(const uint8_t* src_argb1555, 1342 int src_stride_argb1555, 1343 uint8_t* dst_argb, 1344 int dst_stride_argb, 1345 int width, 1346 int height) { 1347 int y; 1348 void (*ARGB1555ToARGBRow)(const uint8_t* src_argb1555, uint8_t* dst_argb, 1349 int width) = ARGB1555ToARGBRow_C; 1350 if (!src_argb1555 || !dst_argb || width <= 0 || height == 0) { 1351 return -1; 1352 } 1353 // Negative height means invert the image. 1354 if (height < 0) { 1355 height = -height; 1356 src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555; 1357 src_stride_argb1555 = -src_stride_argb1555; 1358 } 1359 // Coalesce rows. 1360 if (src_stride_argb1555 == width * 2 && dst_stride_argb == width * 4) { 1361 width *= height; 1362 height = 1; 1363 src_stride_argb1555 = dst_stride_argb = 0; 1364 } 1365 #if defined(HAS_ARGB1555TOARGBROW_SSE2) 1366 if (TestCpuFlag(kCpuHasSSE2)) { 1367 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2; 1368 if (IS_ALIGNED(width, 8)) { 1369 ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2; 1370 } 1371 } 1372 #endif 1373 #if defined(HAS_ARGB1555TOARGBROW_AVX2) 1374 if (TestCpuFlag(kCpuHasAVX2)) { 1375 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2; 1376 if (IS_ALIGNED(width, 16)) { 1377 ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2; 1378 } 1379 } 1380 #endif 1381 #if defined(HAS_ARGB1555TOARGBROW_NEON) 1382 if (TestCpuFlag(kCpuHasNEON)) { 1383 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_NEON; 1384 if (IS_ALIGNED(width, 8)) { 1385 ARGB1555ToARGBRow = ARGB1555ToARGBRow_NEON; 1386 } 1387 } 1388 #endif 1389 #if defined(HAS_ARGB1555TOARGBROW_MSA) 1390 if (TestCpuFlag(kCpuHasMSA)) { 1391 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_MSA; 1392 if (IS_ALIGNED(width, 16)) { 1393 ARGB1555ToARGBRow = ARGB1555ToARGBRow_MSA; 1394 } 1395 } 1396 #endif 1397 1398 for (y = 0; y < height; ++y) { 1399 ARGB1555ToARGBRow(src_argb1555, dst_argb, width); 1400 src_argb1555 += src_stride_argb1555; 1401 dst_argb += dst_stride_argb; 1402 } 1403 return 0; 1404 } 1405 1406 // Convert ARGB4444 to ARGB. 1407 LIBYUV_API 1408 int ARGB4444ToARGB(const uint8_t* src_argb4444, 1409 int src_stride_argb4444, 1410 uint8_t* dst_argb, 1411 int dst_stride_argb, 1412 int width, 1413 int height) { 1414 int y; 1415 void (*ARGB4444ToARGBRow)(const uint8_t* src_argb4444, uint8_t* dst_argb, 1416 int width) = ARGB4444ToARGBRow_C; 1417 if (!src_argb4444 || !dst_argb || width <= 0 || height == 0) { 1418 return -1; 1419 } 1420 // Negative height means invert the image. 1421 if (height < 0) { 1422 height = -height; 1423 src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444; 1424 src_stride_argb4444 = -src_stride_argb4444; 1425 } 1426 // Coalesce rows. 1427 if (src_stride_argb4444 == width * 2 && dst_stride_argb == width * 4) { 1428 width *= height; 1429 height = 1; 1430 src_stride_argb4444 = dst_stride_argb = 0; 1431 } 1432 #if defined(HAS_ARGB4444TOARGBROW_SSE2) 1433 if (TestCpuFlag(kCpuHasSSE2)) { 1434 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2; 1435 if (IS_ALIGNED(width, 8)) { 1436 ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2; 1437 } 1438 } 1439 #endif 1440 #if defined(HAS_ARGB4444TOARGBROW_AVX2) 1441 if (TestCpuFlag(kCpuHasAVX2)) { 1442 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2; 1443 if (IS_ALIGNED(width, 16)) { 1444 ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2; 1445 } 1446 } 1447 #endif 1448 #if defined(HAS_ARGB4444TOARGBROW_NEON) 1449 if (TestCpuFlag(kCpuHasNEON)) { 1450 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_NEON; 1451 if (IS_ALIGNED(width, 8)) { 1452 ARGB4444ToARGBRow = ARGB4444ToARGBRow_NEON; 1453 } 1454 } 1455 #endif 1456 #if defined(HAS_ARGB4444TOARGBROW_MSA) 1457 if (TestCpuFlag(kCpuHasMSA)) { 1458 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MSA; 1459 if (IS_ALIGNED(width, 16)) { 1460 ARGB4444ToARGBRow = ARGB4444ToARGBRow_MSA; 1461 } 1462 } 1463 #endif 1464 1465 for (y = 0; y < height; ++y) { 1466 ARGB4444ToARGBRow(src_argb4444, dst_argb, width); 1467 src_argb4444 += src_stride_argb4444; 1468 dst_argb += dst_stride_argb; 1469 } 1470 return 0; 1471 } 1472 1473 // Convert AR30 to ARGB. 1474 LIBYUV_API 1475 int AR30ToARGB(const uint8_t* src_ar30, 1476 int src_stride_ar30, 1477 uint8_t* dst_argb, 1478 int dst_stride_argb, 1479 int width, 1480 int height) { 1481 int y; 1482 if (!src_ar30 || !dst_argb || width <= 0 || height == 0) { 1483 return -1; 1484 } 1485 // Negative height means invert the image. 1486 if (height < 0) { 1487 height = -height; 1488 src_ar30 = src_ar30 + (height - 1) * src_stride_ar30; 1489 src_stride_ar30 = -src_stride_ar30; 1490 } 1491 // Coalesce rows. 1492 if (src_stride_ar30 == width * 4 && dst_stride_argb == width * 4) { 1493 width *= height; 1494 height = 1; 1495 src_stride_ar30 = dst_stride_argb = 0; 1496 } 1497 for (y = 0; y < height; ++y) { 1498 AR30ToARGBRow_C(src_ar30, dst_argb, width); 1499 src_ar30 += src_stride_ar30; 1500 dst_argb += dst_stride_argb; 1501 } 1502 return 0; 1503 } 1504 1505 // Convert AR30 to ABGR. 1506 LIBYUV_API 1507 int AR30ToABGR(const uint8_t* src_ar30, 1508 int src_stride_ar30, 1509 uint8_t* dst_abgr, 1510 int dst_stride_abgr, 1511 int width, 1512 int height) { 1513 int y; 1514 if (!src_ar30 || !dst_abgr || width <= 0 || height == 0) { 1515 return -1; 1516 } 1517 // Negative height means invert the image. 1518 if (height < 0) { 1519 height = -height; 1520 src_ar30 = src_ar30 + (height - 1) * src_stride_ar30; 1521 src_stride_ar30 = -src_stride_ar30; 1522 } 1523 // Coalesce rows. 1524 if (src_stride_ar30 == width * 4 && dst_stride_abgr == width * 4) { 1525 width *= height; 1526 height = 1; 1527 src_stride_ar30 = dst_stride_abgr = 0; 1528 } 1529 for (y = 0; y < height; ++y) { 1530 AR30ToABGRRow_C(src_ar30, dst_abgr, width); 1531 src_ar30 += src_stride_ar30; 1532 dst_abgr += dst_stride_abgr; 1533 } 1534 return 0; 1535 } 1536 1537 // Convert AR30 to AB30. 1538 LIBYUV_API 1539 int AR30ToAB30(const uint8_t* src_ar30, 1540 int src_stride_ar30, 1541 uint8_t* dst_ab30, 1542 int dst_stride_ab30, 1543 int width, 1544 int height) { 1545 int y; 1546 if (!src_ar30 || !dst_ab30 || width <= 0 || height == 0) { 1547 return -1; 1548 } 1549 // Negative height means invert the image. 1550 if (height < 0) { 1551 height = -height; 1552 src_ar30 = src_ar30 + (height - 1) * src_stride_ar30; 1553 src_stride_ar30 = -src_stride_ar30; 1554 } 1555 // Coalesce rows. 1556 if (src_stride_ar30 == width * 4 && dst_stride_ab30 == width * 4) { 1557 width *= height; 1558 height = 1; 1559 src_stride_ar30 = dst_stride_ab30 = 0; 1560 } 1561 for (y = 0; y < height; ++y) { 1562 AR30ToAB30Row_C(src_ar30, dst_ab30, width); 1563 src_ar30 += src_stride_ar30; 1564 dst_ab30 += dst_stride_ab30; 1565 } 1566 return 0; 1567 } 1568 1569 // Convert NV12 to ARGB with matrix 1570 static int NV12ToARGBMatrix(const uint8_t* src_y, 1571 int src_stride_y, 1572 const uint8_t* src_uv, 1573 int src_stride_uv, 1574 uint8_t* dst_argb, 1575 int dst_stride_argb, 1576 const struct YuvConstants* yuvconstants, 1577 int width, 1578 int height) { 1579 int y; 1580 void (*NV12ToARGBRow)( 1581 const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf, 1582 const struct YuvConstants* yuvconstants, int width) = NV12ToARGBRow_C; 1583 if (!src_y || !src_uv || !dst_argb || width <= 0 || height == 0) { 1584 return -1; 1585 } 1586 // Negative height means invert the image. 1587 if (height < 0) { 1588 height = -height; 1589 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 1590 dst_stride_argb = -dst_stride_argb; 1591 } 1592 #if defined(HAS_NV12TOARGBROW_SSSE3) 1593 if (TestCpuFlag(kCpuHasSSSE3)) { 1594 NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3; 1595 if (IS_ALIGNED(width, 8)) { 1596 NV12ToARGBRow = NV12ToARGBRow_SSSE3; 1597 } 1598 } 1599 #endif 1600 #if defined(HAS_NV12TOARGBROW_AVX2) 1601 if (TestCpuFlag(kCpuHasAVX2)) { 1602 NV12ToARGBRow = NV12ToARGBRow_Any_AVX2; 1603 if (IS_ALIGNED(width, 16)) { 1604 NV12ToARGBRow = NV12ToARGBRow_AVX2; 1605 } 1606 } 1607 #endif 1608 #if defined(HAS_NV12TOARGBROW_NEON) 1609 if (TestCpuFlag(kCpuHasNEON)) { 1610 NV12ToARGBRow = NV12ToARGBRow_Any_NEON; 1611 if (IS_ALIGNED(width, 8)) { 1612 NV12ToARGBRow = NV12ToARGBRow_NEON; 1613 } 1614 } 1615 #endif 1616 #if defined(HAS_NV12TOARGBROW_MSA) 1617 if (TestCpuFlag(kCpuHasMSA)) { 1618 NV12ToARGBRow = NV12ToARGBRow_Any_MSA; 1619 if (IS_ALIGNED(width, 8)) { 1620 NV12ToARGBRow = NV12ToARGBRow_MSA; 1621 } 1622 } 1623 #endif 1624 1625 for (y = 0; y < height; ++y) { 1626 NV12ToARGBRow(src_y, src_uv, dst_argb, yuvconstants, width); 1627 dst_argb += dst_stride_argb; 1628 src_y += src_stride_y; 1629 if (y & 1) { 1630 src_uv += src_stride_uv; 1631 } 1632 } 1633 return 0; 1634 } 1635 1636 // Convert NV21 to ARGB with matrix 1637 static int NV21ToARGBMatrix(const uint8_t* src_y, 1638 int src_stride_y, 1639 const uint8_t* src_vu, 1640 int src_stride_vu, 1641 uint8_t* dst_argb, 1642 int dst_stride_argb, 1643 const struct YuvConstants* yuvconstants, 1644 int width, 1645 int height) { 1646 int y; 1647 void (*NV21ToARGBRow)( 1648 const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf, 1649 const struct YuvConstants* yuvconstants, int width) = NV21ToARGBRow_C; 1650 if (!src_y || !src_vu || !dst_argb || width <= 0 || height == 0) { 1651 return -1; 1652 } 1653 // Negative height means invert the image. 1654 if (height < 0) { 1655 height = -height; 1656 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 1657 dst_stride_argb = -dst_stride_argb; 1658 } 1659 #if defined(HAS_NV21TOARGBROW_SSSE3) 1660 if (TestCpuFlag(kCpuHasSSSE3)) { 1661 NV21ToARGBRow = NV21ToARGBRow_Any_SSSE3; 1662 if (IS_ALIGNED(width, 8)) { 1663 NV21ToARGBRow = NV21ToARGBRow_SSSE3; 1664 } 1665 } 1666 #endif 1667 #if defined(HAS_NV21TOARGBROW_AVX2) 1668 if (TestCpuFlag(kCpuHasAVX2)) { 1669 NV21ToARGBRow = NV21ToARGBRow_Any_AVX2; 1670 if (IS_ALIGNED(width, 16)) { 1671 NV21ToARGBRow = NV21ToARGBRow_AVX2; 1672 } 1673 } 1674 #endif 1675 #if defined(HAS_NV21TOARGBROW_NEON) 1676 if (TestCpuFlag(kCpuHasNEON)) { 1677 NV21ToARGBRow = NV21ToARGBRow_Any_NEON; 1678 if (IS_ALIGNED(width, 8)) { 1679 NV21ToARGBRow = NV21ToARGBRow_NEON; 1680 } 1681 } 1682 #endif 1683 #if defined(HAS_NV21TOARGBROW_MSA) 1684 if (TestCpuFlag(kCpuHasMSA)) { 1685 NV21ToARGBRow = NV21ToARGBRow_Any_MSA; 1686 if (IS_ALIGNED(width, 8)) { 1687 NV21ToARGBRow = NV21ToARGBRow_MSA; 1688 } 1689 } 1690 #endif 1691 1692 for (y = 0; y < height; ++y) { 1693 NV21ToARGBRow(src_y, src_vu, dst_argb, yuvconstants, width); 1694 dst_argb += dst_stride_argb; 1695 src_y += src_stride_y; 1696 if (y & 1) { 1697 src_vu += src_stride_vu; 1698 } 1699 } 1700 return 0; 1701 } 1702 1703 // Convert NV12 to ARGB. 1704 LIBYUV_API 1705 int NV12ToARGB(const uint8_t* src_y, 1706 int src_stride_y, 1707 const uint8_t* src_uv, 1708 int src_stride_uv, 1709 uint8_t* dst_argb, 1710 int dst_stride_argb, 1711 int width, 1712 int height) { 1713 return NV12ToARGBMatrix(src_y, src_stride_y, src_uv, src_stride_uv, dst_argb, 1714 dst_stride_argb, &kYuvI601Constants, width, height); 1715 } 1716 1717 // Convert NV21 to ARGB. 1718 LIBYUV_API 1719 int NV21ToARGB(const uint8_t* src_y, 1720 int src_stride_y, 1721 const uint8_t* src_vu, 1722 int src_stride_vu, 1723 uint8_t* dst_argb, 1724 int dst_stride_argb, 1725 int width, 1726 int height) { 1727 return NV21ToARGBMatrix(src_y, src_stride_y, src_vu, src_stride_vu, dst_argb, 1728 dst_stride_argb, &kYuvI601Constants, width, height); 1729 } 1730 1731 // Convert NV12 to ABGR. 1732 // To output ABGR instead of ARGB swap the UV and use a mirrrored yuc matrix. 1733 // To swap the UV use NV12 instead of NV21.LIBYUV_API 1734 int NV12ToABGR(const uint8_t* src_y, 1735 int src_stride_y, 1736 const uint8_t* src_uv, 1737 int src_stride_uv, 1738 uint8_t* dst_abgr, 1739 int dst_stride_abgr, 1740 int width, 1741 int height) { 1742 return NV21ToARGBMatrix(src_y, src_stride_y, src_uv, src_stride_uv, dst_abgr, 1743 dst_stride_abgr, &kYvuI601Constants, width, height); 1744 } 1745 1746 // Convert NV21 to ABGR. 1747 LIBYUV_API 1748 int NV21ToABGR(const uint8_t* src_y, 1749 int src_stride_y, 1750 const uint8_t* src_vu, 1751 int src_stride_vu, 1752 uint8_t* dst_abgr, 1753 int dst_stride_abgr, 1754 int width, 1755 int height) { 1756 return NV12ToARGBMatrix(src_y, src_stride_y, src_vu, src_stride_vu, dst_abgr, 1757 dst_stride_abgr, &kYvuI601Constants, width, height); 1758 } 1759 1760 // TODO(fbarchard): Consider SSSE3 2 step conversion. 1761 // Convert NV12 to RGB24 with matrix 1762 static int NV12ToRGB24Matrix(const uint8_t* src_y, 1763 int src_stride_y, 1764 const uint8_t* src_uv, 1765 int src_stride_uv, 1766 uint8_t* dst_rgb24, 1767 int dst_stride_rgb24, 1768 const struct YuvConstants* yuvconstants, 1769 int width, 1770 int height) { 1771 int y; 1772 void (*NV12ToRGB24Row)( 1773 const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf, 1774 const struct YuvConstants* yuvconstants, int width) = NV12ToRGB24Row_C; 1775 if (!src_y || !src_uv || !dst_rgb24 || width <= 0 || height == 0) { 1776 return -1; 1777 } 1778 // Negative height means invert the image. 1779 if (height < 0) { 1780 height = -height; 1781 dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24; 1782 dst_stride_rgb24 = -dst_stride_rgb24; 1783 } 1784 #if defined(HAS_NV12TORGB24ROW_NEON) 1785 if (TestCpuFlag(kCpuHasNEON)) { 1786 NV12ToRGB24Row = NV12ToRGB24Row_Any_NEON; 1787 if (IS_ALIGNED(width, 8)) { 1788 NV12ToRGB24Row = NV12ToRGB24Row_NEON; 1789 } 1790 } 1791 #endif 1792 #if defined(HAS_NV12TORGB24ROW_SSSE3) 1793 if (TestCpuFlag(kCpuHasSSSE3)) { 1794 NV12ToRGB24Row = NV12ToRGB24Row_Any_SSSE3; 1795 if (IS_ALIGNED(width, 16)) { 1796 NV12ToRGB24Row = NV12ToRGB24Row_SSSE3; 1797 } 1798 } 1799 #endif 1800 #if defined(HAS_NV12TORGB24ROW_AVX2) 1801 if (TestCpuFlag(kCpuHasAVX2)) { 1802 NV12ToRGB24Row = NV12ToRGB24Row_Any_AVX2; 1803 if (IS_ALIGNED(width, 32)) { 1804 NV12ToRGB24Row = NV12ToRGB24Row_AVX2; 1805 } 1806 } 1807 #endif 1808 1809 for (y = 0; y < height; ++y) { 1810 NV12ToRGB24Row(src_y, src_uv, dst_rgb24, yuvconstants, width); 1811 dst_rgb24 += dst_stride_rgb24; 1812 src_y += src_stride_y; 1813 if (y & 1) { 1814 src_uv += src_stride_uv; 1815 } 1816 } 1817 return 0; 1818 } 1819 1820 // Convert NV21 to RGB24 with matrix 1821 static int NV21ToRGB24Matrix(const uint8_t* src_y, 1822 int src_stride_y, 1823 const uint8_t* src_vu, 1824 int src_stride_vu, 1825 uint8_t* dst_rgb24, 1826 int dst_stride_rgb24, 1827 const struct YuvConstants* yuvconstants, 1828 int width, 1829 int height) { 1830 int y; 1831 void (*NV21ToRGB24Row)( 1832 const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf, 1833 const struct YuvConstants* yuvconstants, int width) = NV21ToRGB24Row_C; 1834 if (!src_y || !src_vu || !dst_rgb24 || width <= 0 || height == 0) { 1835 return -1; 1836 } 1837 // Negative height means invert the image. 1838 if (height < 0) { 1839 height = -height; 1840 dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24; 1841 dst_stride_rgb24 = -dst_stride_rgb24; 1842 } 1843 #if defined(HAS_NV21TORGB24ROW_NEON) 1844 if (TestCpuFlag(kCpuHasNEON)) { 1845 NV21ToRGB24Row = NV21ToRGB24Row_Any_NEON; 1846 if (IS_ALIGNED(width, 8)) { 1847 NV21ToRGB24Row = NV21ToRGB24Row_NEON; 1848 } 1849 } 1850 #endif 1851 #if defined(HAS_NV21TORGB24ROW_SSSE3) 1852 if (TestCpuFlag(kCpuHasSSSE3)) { 1853 NV21ToRGB24Row = NV21ToRGB24Row_Any_SSSE3; 1854 if (IS_ALIGNED(width, 16)) { 1855 NV21ToRGB24Row = NV21ToRGB24Row_SSSE3; 1856 } 1857 } 1858 #endif 1859 #if defined(HAS_NV21TORGB24ROW_AVX2) 1860 if (TestCpuFlag(kCpuHasAVX2)) { 1861 NV21ToRGB24Row = NV21ToRGB24Row_Any_AVX2; 1862 if (IS_ALIGNED(width, 32)) { 1863 NV21ToRGB24Row = NV21ToRGB24Row_AVX2; 1864 } 1865 } 1866 #endif 1867 1868 for (y = 0; y < height; ++y) { 1869 NV21ToRGB24Row(src_y, src_vu, dst_rgb24, yuvconstants, width); 1870 dst_rgb24 += dst_stride_rgb24; 1871 src_y += src_stride_y; 1872 if (y & 1) { 1873 src_vu += src_stride_vu; 1874 } 1875 } 1876 return 0; 1877 } 1878 1879 // TODO(fbarchard): NV12ToRAW can be implemented by mirrored matrix. 1880 // Convert NV12 to RGB24. 1881 LIBYUV_API 1882 int NV12ToRGB24(const uint8_t* src_y, 1883 int src_stride_y, 1884 const uint8_t* src_uv, 1885 int src_stride_uv, 1886 uint8_t* dst_rgb24, 1887 int dst_stride_rgb24, 1888 int width, 1889 int height) { 1890 return NV12ToRGB24Matrix(src_y, src_stride_y, src_uv, src_stride_uv, 1891 dst_rgb24, dst_stride_rgb24, &kYuvI601Constants, 1892 width, height); 1893 } 1894 1895 // Convert NV21 to RGB24. 1896 LIBYUV_API 1897 int NV21ToRGB24(const uint8_t* src_y, 1898 int src_stride_y, 1899 const uint8_t* src_vu, 1900 int src_stride_vu, 1901 uint8_t* dst_rgb24, 1902 int dst_stride_rgb24, 1903 int width, 1904 int height) { 1905 return NV21ToRGB24Matrix(src_y, src_stride_y, src_vu, src_stride_vu, 1906 dst_rgb24, dst_stride_rgb24, &kYuvI601Constants, 1907 width, height); 1908 } 1909 1910 // Convert M420 to ARGB. 1911 LIBYUV_API 1912 int M420ToARGB(const uint8_t* src_m420, 1913 int src_stride_m420, 1914 uint8_t* dst_argb, 1915 int dst_stride_argb, 1916 int width, 1917 int height) { 1918 int y; 1919 void (*NV12ToARGBRow)( 1920 const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf, 1921 const struct YuvConstants* yuvconstants, int width) = NV12ToARGBRow_C; 1922 if (!src_m420 || !dst_argb || width <= 0 || height == 0) { 1923 return -1; 1924 } 1925 // Negative height means invert the image. 1926 if (height < 0) { 1927 height = -height; 1928 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 1929 dst_stride_argb = -dst_stride_argb; 1930 } 1931 #if defined(HAS_NV12TOARGBROW_SSSE3) 1932 if (TestCpuFlag(kCpuHasSSSE3)) { 1933 NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3; 1934 if (IS_ALIGNED(width, 8)) { 1935 NV12ToARGBRow = NV12ToARGBRow_SSSE3; 1936 } 1937 } 1938 #endif 1939 #if defined(HAS_NV12TOARGBROW_AVX2) 1940 if (TestCpuFlag(kCpuHasAVX2)) { 1941 NV12ToARGBRow = NV12ToARGBRow_Any_AVX2; 1942 if (IS_ALIGNED(width, 16)) { 1943 NV12ToARGBRow = NV12ToARGBRow_AVX2; 1944 } 1945 } 1946 #endif 1947 #if defined(HAS_NV12TOARGBROW_NEON) 1948 if (TestCpuFlag(kCpuHasNEON)) { 1949 NV12ToARGBRow = NV12ToARGBRow_Any_NEON; 1950 if (IS_ALIGNED(width, 8)) { 1951 NV12ToARGBRow = NV12ToARGBRow_NEON; 1952 } 1953 } 1954 #endif 1955 #if defined(HAS_NV12TOARGBROW_MSA) 1956 if (TestCpuFlag(kCpuHasMSA)) { 1957 NV12ToARGBRow = NV12ToARGBRow_Any_MSA; 1958 if (IS_ALIGNED(width, 8)) { 1959 NV12ToARGBRow = NV12ToARGBRow_MSA; 1960 } 1961 } 1962 #endif 1963 1964 for (y = 0; y < height - 1; y += 2) { 1965 NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb, 1966 &kYuvI601Constants, width); 1967 NV12ToARGBRow(src_m420 + src_stride_m420, src_m420 + src_stride_m420 * 2, 1968 dst_argb + dst_stride_argb, &kYuvI601Constants, width); 1969 dst_argb += dst_stride_argb * 2; 1970 src_m420 += src_stride_m420 * 3; 1971 } 1972 if (height & 1) { 1973 NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb, 1974 &kYuvI601Constants, width); 1975 } 1976 return 0; 1977 } 1978 1979 // Convert YUY2 to ARGB. 1980 LIBYUV_API 1981 int YUY2ToARGB(const uint8_t* src_yuy2, 1982 int src_stride_yuy2, 1983 uint8_t* dst_argb, 1984 int dst_stride_argb, 1985 int width, 1986 int height) { 1987 int y; 1988 void (*YUY2ToARGBRow)(const uint8_t* src_yuy2, uint8_t* dst_argb, 1989 const struct YuvConstants* yuvconstants, int width) = 1990 YUY2ToARGBRow_C; 1991 if (!src_yuy2 || !dst_argb || width <= 0 || height == 0) { 1992 return -1; 1993 } 1994 // Negative height means invert the image. 1995 if (height < 0) { 1996 height = -height; 1997 src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2; 1998 src_stride_yuy2 = -src_stride_yuy2; 1999 } 2000 // Coalesce rows. 2001 if (src_stride_yuy2 == width * 2 && dst_stride_argb == width * 4) { 2002 width *= height; 2003 height = 1; 2004 src_stride_yuy2 = dst_stride_argb = 0; 2005 } 2006 #if defined(HAS_YUY2TOARGBROW_SSSE3) 2007 if (TestCpuFlag(kCpuHasSSSE3)) { 2008 YUY2ToARGBRow = YUY2ToARGBRow_Any_SSSE3; 2009 if (IS_ALIGNED(width, 16)) { 2010 YUY2ToARGBRow = YUY2ToARGBRow_SSSE3; 2011 } 2012 } 2013 #endif 2014 #if defined(HAS_YUY2TOARGBROW_AVX2) 2015 if (TestCpuFlag(kCpuHasAVX2)) { 2016 YUY2ToARGBRow = YUY2ToARGBRow_Any_AVX2; 2017 if (IS_ALIGNED(width, 32)) { 2018 YUY2ToARGBRow = YUY2ToARGBRow_AVX2; 2019 } 2020 } 2021 #endif 2022 #if defined(HAS_YUY2TOARGBROW_NEON) 2023 if (TestCpuFlag(kCpuHasNEON)) { 2024 YUY2ToARGBRow = YUY2ToARGBRow_Any_NEON; 2025 if (IS_ALIGNED(width, 8)) { 2026 YUY2ToARGBRow = YUY2ToARGBRow_NEON; 2027 } 2028 } 2029 #endif 2030 #if defined(HAS_YUY2TOARGBROW_MSA) 2031 if (TestCpuFlag(kCpuHasMSA)) { 2032 YUY2ToARGBRow = YUY2ToARGBRow_Any_MSA; 2033 if (IS_ALIGNED(width, 8)) { 2034 YUY2ToARGBRow = YUY2ToARGBRow_MSA; 2035 } 2036 } 2037 #endif 2038 for (y = 0; y < height; ++y) { 2039 YUY2ToARGBRow(src_yuy2, dst_argb, &kYuvI601Constants, width); 2040 src_yuy2 += src_stride_yuy2; 2041 dst_argb += dst_stride_argb; 2042 } 2043 return 0; 2044 } 2045 2046 // Convert UYVY to ARGB. 2047 LIBYUV_API 2048 int UYVYToARGB(const uint8_t* src_uyvy, 2049 int src_stride_uyvy, 2050 uint8_t* dst_argb, 2051 int dst_stride_argb, 2052 int width, 2053 int height) { 2054 int y; 2055 void (*UYVYToARGBRow)(const uint8_t* src_uyvy, uint8_t* dst_argb, 2056 const struct YuvConstants* yuvconstants, int width) = 2057 UYVYToARGBRow_C; 2058 if (!src_uyvy || !dst_argb || width <= 0 || height == 0) { 2059 return -1; 2060 } 2061 // Negative height means invert the image. 2062 if (height < 0) { 2063 height = -height; 2064 src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy; 2065 src_stride_uyvy = -src_stride_uyvy; 2066 } 2067 // Coalesce rows. 2068 if (src_stride_uyvy == width * 2 && dst_stride_argb == width * 4) { 2069 width *= height; 2070 height = 1; 2071 src_stride_uyvy = dst_stride_argb = 0; 2072 } 2073 #if defined(HAS_UYVYTOARGBROW_SSSE3) 2074 if (TestCpuFlag(kCpuHasSSSE3)) { 2075 UYVYToARGBRow = UYVYToARGBRow_Any_SSSE3; 2076 if (IS_ALIGNED(width, 16)) { 2077 UYVYToARGBRow = UYVYToARGBRow_SSSE3; 2078 } 2079 } 2080 #endif 2081 #if defined(HAS_UYVYTOARGBROW_AVX2) 2082 if (TestCpuFlag(kCpuHasAVX2)) { 2083 UYVYToARGBRow = UYVYToARGBRow_Any_AVX2; 2084 if (IS_ALIGNED(width, 32)) { 2085 UYVYToARGBRow = UYVYToARGBRow_AVX2; 2086 } 2087 } 2088 #endif 2089 #if defined(HAS_UYVYTOARGBROW_NEON) 2090 if (TestCpuFlag(kCpuHasNEON)) { 2091 UYVYToARGBRow = UYVYToARGBRow_Any_NEON; 2092 if (IS_ALIGNED(width, 8)) { 2093 UYVYToARGBRow = UYVYToARGBRow_NEON; 2094 } 2095 } 2096 #endif 2097 #if defined(HAS_UYVYTOARGBROW_MSA) 2098 if (TestCpuFlag(kCpuHasMSA)) { 2099 UYVYToARGBRow = UYVYToARGBRow_Any_MSA; 2100 if (IS_ALIGNED(width, 8)) { 2101 UYVYToARGBRow = UYVYToARGBRow_MSA; 2102 } 2103 } 2104 #endif 2105 for (y = 0; y < height; ++y) { 2106 UYVYToARGBRow(src_uyvy, dst_argb, &kYuvI601Constants, width); 2107 src_uyvy += src_stride_uyvy; 2108 dst_argb += dst_stride_argb; 2109 } 2110 return 0; 2111 } 2112 static void WeavePixels(const uint8_t* src_u, 2113 const uint8_t* src_v, 2114 int src_pixel_stride_uv, 2115 uint8_t* dst_uv, 2116 int width) { 2117 int i; 2118 for (i = 0; i < width; ++i) { 2119 dst_uv[0] = *src_u; 2120 dst_uv[1] = *src_v; 2121 dst_uv += 2; 2122 src_u += src_pixel_stride_uv; 2123 src_v += src_pixel_stride_uv; 2124 } 2125 } 2126 2127 // Convert Android420 to ARGB. 2128 LIBYUV_API 2129 int Android420ToARGBMatrix(const uint8_t* src_y, 2130 int src_stride_y, 2131 const uint8_t* src_u, 2132 int src_stride_u, 2133 const uint8_t* src_v, 2134 int src_stride_v, 2135 int src_pixel_stride_uv, 2136 uint8_t* dst_argb, 2137 int dst_stride_argb, 2138 const struct YuvConstants* yuvconstants, 2139 int width, 2140 int height) { 2141 int y; 2142 uint8_t* dst_uv; 2143 const ptrdiff_t vu_off = src_v - src_u; 2144 int halfwidth = (width + 1) >> 1; 2145 int halfheight = (height + 1) >> 1; 2146 if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) { 2147 return -1; 2148 } 2149 // Negative height means invert the image. 2150 if (height < 0) { 2151 height = -height; 2152 halfheight = (height + 1) >> 1; 2153 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 2154 dst_stride_argb = -dst_stride_argb; 2155 } 2156 2157 // I420 2158 if (src_pixel_stride_uv == 1) { 2159 return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, 2160 src_stride_v, dst_argb, dst_stride_argb, 2161 yuvconstants, width, height); 2162 // NV21 2163 } 2164 if (src_pixel_stride_uv == 2 && vu_off == -1 && 2165 src_stride_u == src_stride_v) { 2166 return NV21ToARGBMatrix(src_y, src_stride_y, src_v, src_stride_v, dst_argb, 2167 dst_stride_argb, yuvconstants, width, height); 2168 // NV12 2169 } 2170 if (src_pixel_stride_uv == 2 && vu_off == 1 && src_stride_u == src_stride_v) { 2171 return NV12ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, dst_argb, 2172 dst_stride_argb, yuvconstants, width, height); 2173 } 2174 2175 // General case fallback creates NV12 2176 align_buffer_64(plane_uv, halfwidth * 2 * halfheight); 2177 dst_uv = plane_uv; 2178 for (y = 0; y < halfheight; ++y) { 2179 WeavePixels(src_u, src_v, src_pixel_stride_uv, dst_uv, halfwidth); 2180 src_u += src_stride_u; 2181 src_v += src_stride_v; 2182 dst_uv += halfwidth * 2; 2183 } 2184 NV12ToARGBMatrix(src_y, src_stride_y, plane_uv, halfwidth * 2, dst_argb, 2185 dst_stride_argb, yuvconstants, width, height); 2186 free_aligned_buffer_64(plane_uv); 2187 return 0; 2188 } 2189 2190 // Convert Android420 to ARGB. 2191 LIBYUV_API 2192 int Android420ToARGB(const uint8_t* src_y, 2193 int src_stride_y, 2194 const uint8_t* src_u, 2195 int src_stride_u, 2196 const uint8_t* src_v, 2197 int src_stride_v, 2198 int src_pixel_stride_uv, 2199 uint8_t* dst_argb, 2200 int dst_stride_argb, 2201 int width, 2202 int height) { 2203 return Android420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, 2204 src_stride_v, src_pixel_stride_uv, dst_argb, 2205 dst_stride_argb, &kYuvI601Constants, width, 2206 height); 2207 } 2208 2209 // Convert Android420 to ABGR. 2210 LIBYUV_API 2211 int Android420ToABGR(const uint8_t* src_y, 2212 int src_stride_y, 2213 const uint8_t* src_u, 2214 int src_stride_u, 2215 const uint8_t* src_v, 2216 int src_stride_v, 2217 int src_pixel_stride_uv, 2218 uint8_t* dst_abgr, 2219 int dst_stride_abgr, 2220 int width, 2221 int height) { 2222 return Android420ToARGBMatrix(src_y, src_stride_y, src_v, src_stride_v, src_u, 2223 src_stride_u, src_pixel_stride_uv, dst_abgr, 2224 dst_stride_abgr, &kYvuI601Constants, width, 2225 height); 2226 } 2227 2228 #ifdef __cplusplus 2229 } // extern "C" 2230 } // namespace libyuv 2231 #endif 2232