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 #include "libyuv/format_conversion.h" 15 #ifdef HAVE_JPEG 16 #include "libyuv/mjpeg_decoder.h" 17 #endif 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* src_argb, int src_stride_argb, 30 uint8* dst_argb, int dst_stride_argb, 31 int width, int height) { 32 if (!src_argb || !dst_argb || 33 width <= 0 || height == 0) { 34 return -1; 35 } 36 // Negative height means invert the image. 37 if (height < 0) { 38 height = -height; 39 src_argb = src_argb + (height - 1) * src_stride_argb; 40 src_stride_argb = -src_stride_argb; 41 } 42 43 CopyPlane(src_argb, src_stride_argb, dst_argb, dst_stride_argb, 44 width * 4, height); 45 return 0; 46 } 47 48 // Convert I444 to ARGB. 49 LIBYUV_API 50 int I444ToARGB(const uint8* src_y, int src_stride_y, 51 const uint8* src_u, int src_stride_u, 52 const uint8* src_v, int src_stride_v, 53 uint8* dst_argb, int dst_stride_argb, 54 int width, int height) { 55 if (!src_y || !src_u || !src_v || 56 !dst_argb || 57 width <= 0 || height == 0) { 58 return -1; 59 } 60 // Negative height means invert the image. 61 if (height < 0) { 62 height = -height; 63 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 64 dst_stride_argb = -dst_stride_argb; 65 } 66 // Coalesce rows. 67 if (src_stride_y == width && 68 src_stride_u == width && 69 src_stride_v == width && 70 dst_stride_argb == width * 4) { 71 width *= height; 72 height = 1; 73 src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0; 74 } 75 void (*I444ToARGBRow)(const uint8* y_buf, 76 const uint8* u_buf, 77 const uint8* v_buf, 78 uint8* rgb_buf, 79 int width) = I444ToARGBRow_C; 80 #if defined(HAS_I444TOARGBROW_SSSE3) 81 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 82 I444ToARGBRow = I444ToARGBRow_Any_SSSE3; 83 if (IS_ALIGNED(width, 8)) { 84 I444ToARGBRow = I444ToARGBRow_Unaligned_SSSE3; 85 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 86 I444ToARGBRow = I444ToARGBRow_SSSE3; 87 } 88 } 89 } 90 #elif defined(HAS_I444TOARGBROW_NEON) 91 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 92 I444ToARGBRow = I444ToARGBRow_Any_NEON; 93 if (IS_ALIGNED(width, 8)) { 94 I444ToARGBRow = I444ToARGBRow_NEON; 95 } 96 } 97 #endif 98 99 for (int y = 0; y < height; ++y) { 100 I444ToARGBRow(src_y, src_u, src_v, dst_argb, width); 101 dst_argb += dst_stride_argb; 102 src_y += src_stride_y; 103 src_u += src_stride_u; 104 src_v += src_stride_v; 105 } 106 return 0; 107 } 108 109 // Convert I422 to ARGB. 110 LIBYUV_API 111 int I422ToARGB(const uint8* src_y, int src_stride_y, 112 const uint8* src_u, int src_stride_u, 113 const uint8* src_v, int src_stride_v, 114 uint8* dst_argb, int dst_stride_argb, 115 int width, int height) { 116 if (!src_y || !src_u || !src_v || 117 !dst_argb || 118 width <= 0 || height == 0) { 119 return -1; 120 } 121 // Negative height means invert the image. 122 if (height < 0) { 123 height = -height; 124 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 125 dst_stride_argb = -dst_stride_argb; 126 } 127 // Coalesce rows. 128 if (src_stride_y == width && 129 src_stride_u * 2 == width && 130 src_stride_v * 2 == width && 131 dst_stride_argb == width * 4) { 132 width *= height; 133 height = 1; 134 src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0; 135 } 136 void (*I422ToARGBRow)(const uint8* y_buf, 137 const uint8* u_buf, 138 const uint8* v_buf, 139 uint8* rgb_buf, 140 int width) = I422ToARGBRow_C; 141 #if defined(HAS_I422TOARGBROW_SSSE3) 142 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 143 I422ToARGBRow = I422ToARGBRow_Any_SSSE3; 144 if (IS_ALIGNED(width, 8)) { 145 I422ToARGBRow = I422ToARGBRow_Unaligned_SSSE3; 146 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 147 I422ToARGBRow = I422ToARGBRow_SSSE3; 148 } 149 } 150 } 151 #endif 152 #if defined(HAS_I422TOARGBROW_AVX2) 153 if (TestCpuFlag(kCpuHasAVX2) && width >= 16) { 154 I422ToARGBRow = I422ToARGBRow_Any_AVX2; 155 if (IS_ALIGNED(width, 16)) { 156 I422ToARGBRow = I422ToARGBRow_AVX2; 157 } 158 } 159 #endif 160 #if defined(HAS_I422TOARGBROW_NEON) 161 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 162 I422ToARGBRow = I422ToARGBRow_Any_NEON; 163 if (IS_ALIGNED(width, 8)) { 164 I422ToARGBRow = I422ToARGBRow_NEON; 165 } 166 } 167 #endif 168 #if defined(HAS_I422TOARGBROW_MIPS_DSPR2) 169 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) && 170 IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) && 171 IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) && 172 IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) && 173 IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) { 174 I422ToARGBRow = I422ToARGBRow_MIPS_DSPR2; 175 } 176 #endif 177 178 for (int y = 0; y < height; ++y) { 179 I422ToARGBRow(src_y, src_u, src_v, dst_argb, width); 180 dst_argb += dst_stride_argb; 181 src_y += src_stride_y; 182 src_u += src_stride_u; 183 src_v += src_stride_v; 184 } 185 return 0; 186 } 187 188 // Convert I411 to ARGB. 189 LIBYUV_API 190 int I411ToARGB(const uint8* src_y, int src_stride_y, 191 const uint8* src_u, int src_stride_u, 192 const uint8* src_v, int src_stride_v, 193 uint8* dst_argb, int dst_stride_argb, 194 int width, int height) { 195 if (!src_y || !src_u || !src_v || 196 !dst_argb || 197 width <= 0 || height == 0) { 198 return -1; 199 } 200 // Negative height means invert the image. 201 if (height < 0) { 202 height = -height; 203 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 204 dst_stride_argb = -dst_stride_argb; 205 } 206 // Coalesce rows. 207 if (src_stride_y == width && 208 src_stride_u * 4 == width && 209 src_stride_v * 4 == width && 210 dst_stride_argb == width * 4) { 211 width *= height; 212 height = 1; 213 src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0; 214 } 215 void (*I411ToARGBRow)(const uint8* y_buf, 216 const uint8* u_buf, 217 const uint8* v_buf, 218 uint8* rgb_buf, 219 int width) = I411ToARGBRow_C; 220 #if defined(HAS_I411TOARGBROW_SSSE3) 221 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 222 I411ToARGBRow = I411ToARGBRow_Any_SSSE3; 223 if (IS_ALIGNED(width, 8)) { 224 I411ToARGBRow = I411ToARGBRow_Unaligned_SSSE3; 225 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 226 I411ToARGBRow = I411ToARGBRow_SSSE3; 227 } 228 } 229 } 230 #elif defined(HAS_I411TOARGBROW_NEON) 231 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 232 I411ToARGBRow = I411ToARGBRow_Any_NEON; 233 if (IS_ALIGNED(width, 8)) { 234 I411ToARGBRow = I411ToARGBRow_NEON; 235 } 236 } 237 #endif 238 239 for (int y = 0; y < height; ++y) { 240 I411ToARGBRow(src_y, src_u, src_v, dst_argb, width); 241 dst_argb += dst_stride_argb; 242 src_y += src_stride_y; 243 src_u += src_stride_u; 244 src_v += src_stride_v; 245 } 246 return 0; 247 } 248 249 // Convert I400 to ARGB. 250 LIBYUV_API 251 int I400ToARGB_Reference(const uint8* src_y, int src_stride_y, 252 uint8* dst_argb, int dst_stride_argb, 253 int width, int height) { 254 if (!src_y || !dst_argb || 255 width <= 0 || height == 0) { 256 return -1; 257 } 258 // Negative height means invert the image. 259 if (height < 0) { 260 height = -height; 261 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 262 dst_stride_argb = -dst_stride_argb; 263 } 264 // Coalesce rows. 265 if (src_stride_y == width && 266 dst_stride_argb == width * 4) { 267 width *= height; 268 height = 1; 269 src_stride_y = dst_stride_argb = 0; 270 } 271 void (*YToARGBRow)(const uint8* y_buf, 272 uint8* rgb_buf, 273 int width) = YToARGBRow_C; 274 #if defined(HAS_YTOARGBROW_SSE2) 275 if (TestCpuFlag(kCpuHasSSE2) && width >= 8 && 276 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 277 YToARGBRow = YToARGBRow_Any_SSE2; 278 if (IS_ALIGNED(width, 8)) { 279 YToARGBRow = YToARGBRow_SSE2; 280 } 281 } 282 #elif defined(HAS_YTOARGBROW_NEON) 283 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 284 YToARGBRow = YToARGBRow_Any_NEON; 285 if (IS_ALIGNED(width, 8)) { 286 YToARGBRow = YToARGBRow_NEON; 287 } 288 } 289 #endif 290 291 for (int y = 0; y < height; ++y) { 292 YToARGBRow(src_y, dst_argb, width); 293 dst_argb += dst_stride_argb; 294 src_y += src_stride_y; 295 } 296 return 0; 297 } 298 299 // Convert I400 to ARGB. 300 LIBYUV_API 301 int I400ToARGB(const uint8* src_y, int src_stride_y, 302 uint8* dst_argb, int dst_stride_argb, 303 int width, int height) { 304 if (!src_y || !dst_argb || 305 width <= 0 || height == 0) { 306 return -1; 307 } 308 // Negative height means invert the image. 309 if (height < 0) { 310 height = -height; 311 src_y = src_y + (height - 1) * src_stride_y; 312 src_stride_y = -src_stride_y; 313 } 314 // Coalesce rows. 315 if (src_stride_y == width && 316 dst_stride_argb == width * 4) { 317 width *= height; 318 height = 1; 319 src_stride_y = dst_stride_argb = 0; 320 } 321 void (*I400ToARGBRow)(const uint8* src_y, uint8* dst_argb, int pix) = 322 I400ToARGBRow_C; 323 #if defined(HAS_I400TOARGBROW_SSE2) 324 if (TestCpuFlag(kCpuHasSSE2) && width >= 8) { 325 I400ToARGBRow = I400ToARGBRow_Any_SSE2; 326 if (IS_ALIGNED(width, 8)) { 327 I400ToARGBRow = I400ToARGBRow_Unaligned_SSE2; 328 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 329 I400ToARGBRow = I400ToARGBRow_SSE2; 330 } 331 } 332 } 333 #elif defined(HAS_I400TOARGBROW_NEON) 334 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 335 I400ToARGBRow = I400ToARGBRow_Any_NEON; 336 if (IS_ALIGNED(width, 8)) { 337 I400ToARGBRow = I400ToARGBRow_NEON; 338 } 339 } 340 #endif 341 for (int y = 0; y < height; ++y) { 342 I400ToARGBRow(src_y, dst_argb, width); 343 src_y += src_stride_y; 344 dst_argb += dst_stride_argb; 345 } 346 return 0; 347 } 348 349 // Shuffle table for converting BGRA to ARGB. 350 static uvec8 kShuffleMaskBGRAToARGB = { 351 3u, 2u, 1u, 0u, 7u, 6u, 5u, 4u, 11u, 10u, 9u, 8u, 15u, 14u, 13u, 12u 352 }; 353 354 // Shuffle table for converting ABGR to ARGB. 355 static uvec8 kShuffleMaskABGRToARGB = { 356 2u, 1u, 0u, 3u, 6u, 5u, 4u, 7u, 10u, 9u, 8u, 11u, 14u, 13u, 12u, 15u 357 }; 358 359 // Shuffle table for converting RGBA to ARGB. 360 static uvec8 kShuffleMaskRGBAToARGB = { 361 1u, 2u, 3u, 0u, 5u, 6u, 7u, 4u, 9u, 10u, 11u, 8u, 13u, 14u, 15u, 12u 362 }; 363 364 // Convert BGRA to ARGB. 365 LIBYUV_API 366 int BGRAToARGB(const uint8* src_bgra, int src_stride_bgra, 367 uint8* dst_argb, int dst_stride_argb, 368 int width, int height) { 369 return ARGBShuffle(src_bgra, src_stride_bgra, 370 dst_argb, dst_stride_argb, 371 (const uint8*)(&kShuffleMaskBGRAToARGB), 372 width, height); 373 } 374 375 // Convert ABGR to ARGB. 376 LIBYUV_API 377 int ABGRToARGB(const uint8* src_abgr, int src_stride_abgr, 378 uint8* dst_argb, int dst_stride_argb, 379 int width, int height) { 380 return ARGBShuffle(src_abgr, src_stride_abgr, 381 dst_argb, dst_stride_argb, 382 (const uint8*)(&kShuffleMaskABGRToARGB), 383 width, height); 384 } 385 386 // Convert RGBA to ARGB. 387 LIBYUV_API 388 int RGBAToARGB(const uint8* src_rgba, int src_stride_rgba, 389 uint8* dst_argb, int dst_stride_argb, 390 int width, int height) { 391 return ARGBShuffle(src_rgba, src_stride_rgba, 392 dst_argb, dst_stride_argb, 393 (const uint8*)(&kShuffleMaskRGBAToARGB), 394 width, height); 395 } 396 397 // Convert RGB24 to ARGB. 398 LIBYUV_API 399 int RGB24ToARGB(const uint8* src_rgb24, int src_stride_rgb24, 400 uint8* dst_argb, int dst_stride_argb, 401 int width, int height) { 402 if (!src_rgb24 || !dst_argb || 403 width <= 0 || height == 0) { 404 return -1; 405 } 406 // Negative height means invert the image. 407 if (height < 0) { 408 height = -height; 409 src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24; 410 src_stride_rgb24 = -src_stride_rgb24; 411 } 412 // Coalesce rows. 413 if (src_stride_rgb24 == width * 3 && 414 dst_stride_argb == width * 4) { 415 width *= height; 416 height = 1; 417 src_stride_rgb24 = dst_stride_argb = 0; 418 } 419 void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = 420 RGB24ToARGBRow_C; 421 #if defined(HAS_RGB24TOARGBROW_SSSE3) 422 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16 && 423 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 424 RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3; 425 if (IS_ALIGNED(width, 16)) { 426 RGB24ToARGBRow = RGB24ToARGBRow_SSSE3; 427 } 428 } 429 #elif defined(HAS_RGB24TOARGBROW_NEON) 430 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 431 RGB24ToARGBRow = RGB24ToARGBRow_Any_NEON; 432 if (IS_ALIGNED(width, 8)) { 433 RGB24ToARGBRow = RGB24ToARGBRow_NEON; 434 } 435 } 436 #endif 437 438 for (int y = 0; y < height; ++y) { 439 RGB24ToARGBRow(src_rgb24, dst_argb, width); 440 src_rgb24 += src_stride_rgb24; 441 dst_argb += dst_stride_argb; 442 } 443 return 0; 444 } 445 446 // Convert RAW to ARGB. 447 LIBYUV_API 448 int RAWToARGB(const uint8* src_raw, int src_stride_raw, 449 uint8* dst_argb, int dst_stride_argb, 450 int width, int height) { 451 if (!src_raw || !dst_argb || 452 width <= 0 || height == 0) { 453 return -1; 454 } 455 // Negative height means invert the image. 456 if (height < 0) { 457 height = -height; 458 src_raw = src_raw + (height - 1) * src_stride_raw; 459 src_stride_raw = -src_stride_raw; 460 } 461 // Coalesce rows. 462 if (src_stride_raw == width * 3 && 463 dst_stride_argb == width * 4) { 464 width *= height; 465 height = 1; 466 src_stride_raw = dst_stride_argb = 0; 467 } 468 void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = 469 RAWToARGBRow_C; 470 #if defined(HAS_RAWTOARGBROW_SSSE3) 471 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16 && 472 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 473 RAWToARGBRow = RAWToARGBRow_Any_SSSE3; 474 if (IS_ALIGNED(width, 16)) { 475 RAWToARGBRow = RAWToARGBRow_SSSE3; 476 } 477 } 478 #elif defined(HAS_RAWTOARGBROW_NEON) 479 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 480 RAWToARGBRow = RAWToARGBRow_Any_NEON; 481 if (IS_ALIGNED(width, 8)) { 482 RAWToARGBRow = RAWToARGBRow_NEON; 483 } 484 } 485 #endif 486 487 for (int y = 0; y < height; ++y) { 488 RAWToARGBRow(src_raw, dst_argb, width); 489 src_raw += src_stride_raw; 490 dst_argb += dst_stride_argb; 491 } 492 return 0; 493 } 494 495 // Convert RGB565 to ARGB. 496 LIBYUV_API 497 int RGB565ToARGB(const uint8* src_rgb565, int src_stride_rgb565, 498 uint8* dst_argb, int dst_stride_argb, 499 int width, int height) { 500 if (!src_rgb565 || !dst_argb || 501 width <= 0 || height == 0) { 502 return -1; 503 } 504 // Negative height means invert the image. 505 if (height < 0) { 506 height = -height; 507 src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565; 508 src_stride_rgb565 = -src_stride_rgb565; 509 } 510 // Coalesce rows. 511 if (src_stride_rgb565 == width * 2 && 512 dst_stride_argb == width * 4) { 513 width *= height; 514 height = 1; 515 src_stride_rgb565 = dst_stride_argb = 0; 516 } 517 void (*RGB565ToARGBRow)(const uint8* src_rgb565, uint8* dst_argb, int pix) = 518 RGB565ToARGBRow_C; 519 #if defined(HAS_RGB565TOARGBROW_SSE2) 520 if (TestCpuFlag(kCpuHasSSE2) && width >= 8 && 521 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 522 RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2; 523 if (IS_ALIGNED(width, 8)) { 524 RGB565ToARGBRow = RGB565ToARGBRow_SSE2; 525 } 526 } 527 #elif defined(HAS_RGB565TOARGBROW_NEON) 528 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 529 RGB565ToARGBRow = RGB565ToARGBRow_Any_NEON; 530 if (IS_ALIGNED(width, 8)) { 531 RGB565ToARGBRow = RGB565ToARGBRow_NEON; 532 } 533 } 534 #endif 535 536 for (int y = 0; y < height; ++y) { 537 RGB565ToARGBRow(src_rgb565, dst_argb, width); 538 src_rgb565 += src_stride_rgb565; 539 dst_argb += dst_stride_argb; 540 } 541 return 0; 542 } 543 544 // Convert ARGB1555 to ARGB. 545 LIBYUV_API 546 int ARGB1555ToARGB(const uint8* src_argb1555, int src_stride_argb1555, 547 uint8* dst_argb, int dst_stride_argb, 548 int width, int height) { 549 if (!src_argb1555 || !dst_argb || 550 width <= 0 || height == 0) { 551 return -1; 552 } 553 // Negative height means invert the image. 554 if (height < 0) { 555 height = -height; 556 src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555; 557 src_stride_argb1555 = -src_stride_argb1555; 558 } 559 // Coalesce rows. 560 if (src_stride_argb1555 == width * 2 && 561 dst_stride_argb == width * 4) { 562 width *= height; 563 height = 1; 564 src_stride_argb1555 = dst_stride_argb = 0; 565 } 566 void (*ARGB1555ToARGBRow)(const uint8* src_argb1555, uint8* dst_argb, 567 int pix) = ARGB1555ToARGBRow_C; 568 #if defined(HAS_ARGB1555TOARGBROW_SSE2) 569 if (TestCpuFlag(kCpuHasSSE2) && width >= 8 && 570 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 571 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2; 572 if (IS_ALIGNED(width, 8)) { 573 ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2; 574 } 575 } 576 #elif defined(HAS_ARGB1555TOARGBROW_NEON) 577 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 578 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_NEON; 579 if (IS_ALIGNED(width, 8)) { 580 ARGB1555ToARGBRow = ARGB1555ToARGBRow_NEON; 581 } 582 } 583 #endif 584 585 for (int y = 0; y < height; ++y) { 586 ARGB1555ToARGBRow(src_argb1555, dst_argb, width); 587 src_argb1555 += src_stride_argb1555; 588 dst_argb += dst_stride_argb; 589 } 590 return 0; 591 } 592 593 // Convert ARGB4444 to ARGB. 594 LIBYUV_API 595 int ARGB4444ToARGB(const uint8* src_argb4444, int src_stride_argb4444, 596 uint8* dst_argb, int dst_stride_argb, 597 int width, int height) { 598 if (!src_argb4444 || !dst_argb || 599 width <= 0 || height == 0) { 600 return -1; 601 } 602 // Negative height means invert the image. 603 if (height < 0) { 604 height = -height; 605 src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444; 606 src_stride_argb4444 = -src_stride_argb4444; 607 } 608 // Coalesce rows. 609 if (src_stride_argb4444 == width * 2 && 610 dst_stride_argb == width * 4) { 611 width *= height; 612 height = 1; 613 src_stride_argb4444 = dst_stride_argb = 0; 614 } 615 void (*ARGB4444ToARGBRow)(const uint8* src_argb4444, uint8* dst_argb, 616 int pix) = ARGB4444ToARGBRow_C; 617 #if defined(HAS_ARGB4444TOARGBROW_SSE2) 618 if (TestCpuFlag(kCpuHasSSE2) && width >= 8 && 619 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 620 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2; 621 if (IS_ALIGNED(width, 8)) { 622 ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2; 623 } 624 } 625 #elif defined(HAS_ARGB4444TOARGBROW_NEON) 626 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 627 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_NEON; 628 if (IS_ALIGNED(width, 8)) { 629 ARGB4444ToARGBRow = ARGB4444ToARGBRow_NEON; 630 } 631 } 632 #endif 633 634 for (int y = 0; y < height; ++y) { 635 ARGB4444ToARGBRow(src_argb4444, dst_argb, width); 636 src_argb4444 += src_stride_argb4444; 637 dst_argb += dst_stride_argb; 638 } 639 return 0; 640 } 641 642 // Convert NV12 to ARGB. 643 LIBYUV_API 644 int NV12ToARGB(const uint8* src_y, int src_stride_y, 645 const uint8* src_uv, int src_stride_uv, 646 uint8* dst_argb, int dst_stride_argb, 647 int width, int height) { 648 if (!src_y || !src_uv || !dst_argb || 649 width <= 0 || height == 0) { 650 return -1; 651 } 652 // Negative height means invert the image. 653 if (height < 0) { 654 height = -height; 655 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 656 dst_stride_argb = -dst_stride_argb; 657 } 658 void (*NV12ToARGBRow)(const uint8* y_buf, 659 const uint8* uv_buf, 660 uint8* rgb_buf, 661 int width) = NV12ToARGBRow_C; 662 #if defined(HAS_NV12TOARGBROW_SSSE3) 663 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 664 NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3; 665 if (IS_ALIGNED(width, 8)) { 666 NV12ToARGBRow = NV12ToARGBRow_Unaligned_SSSE3; 667 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 668 NV12ToARGBRow = NV12ToARGBRow_SSSE3; 669 } 670 } 671 } 672 #elif defined(HAS_NV12TOARGBROW_NEON) 673 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 674 NV12ToARGBRow = NV12ToARGBRow_Any_NEON; 675 if (IS_ALIGNED(width, 8)) { 676 NV12ToARGBRow = NV12ToARGBRow_NEON; 677 } 678 } 679 #endif 680 681 for (int y = 0; y < height; ++y) { 682 NV12ToARGBRow(src_y, src_uv, dst_argb, width); 683 dst_argb += dst_stride_argb; 684 src_y += src_stride_y; 685 if (y & 1) { 686 src_uv += src_stride_uv; 687 } 688 } 689 return 0; 690 } 691 692 // Convert NV21 to ARGB. 693 LIBYUV_API 694 int NV21ToARGB(const uint8* src_y, int src_stride_y, 695 const uint8* src_uv, int src_stride_uv, 696 uint8* dst_argb, int dst_stride_argb, 697 int width, int height) { 698 if (!src_y || !src_uv || !dst_argb || 699 width <= 0 || height == 0) { 700 return -1; 701 } 702 // Negative height means invert the image. 703 if (height < 0) { 704 height = -height; 705 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 706 dst_stride_argb = -dst_stride_argb; 707 } 708 void (*NV21ToARGBRow)(const uint8* y_buf, 709 const uint8* uv_buf, 710 uint8* rgb_buf, 711 int width) = NV21ToARGBRow_C; 712 #if defined(HAS_NV21TOARGBROW_SSSE3) 713 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 714 NV21ToARGBRow = NV21ToARGBRow_Any_SSSE3; 715 if (IS_ALIGNED(width, 8)) { 716 NV21ToARGBRow = NV21ToARGBRow_Unaligned_SSSE3; 717 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 718 NV21ToARGBRow = NV21ToARGBRow_SSSE3; 719 } 720 } 721 } 722 #endif 723 #if defined(HAS_NV21TOARGBROW_NEON) 724 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 725 NV21ToARGBRow = NV21ToARGBRow_Any_NEON; 726 if (IS_ALIGNED(width, 8)) { 727 NV21ToARGBRow = NV21ToARGBRow_NEON; 728 } 729 } 730 #endif 731 732 for (int y = 0; y < height; ++y) { 733 NV21ToARGBRow(src_y, src_uv, dst_argb, width); 734 dst_argb += dst_stride_argb; 735 src_y += src_stride_y; 736 if (y & 1) { 737 src_uv += src_stride_uv; 738 } 739 } 740 return 0; 741 } 742 743 // Convert M420 to ARGB. 744 LIBYUV_API 745 int M420ToARGB(const uint8* src_m420, int src_stride_m420, 746 uint8* dst_argb, int dst_stride_argb, 747 int width, int height) { 748 if (!src_m420 || !dst_argb || 749 width <= 0 || height == 0) { 750 return -1; 751 } 752 // Negative height means invert the image. 753 if (height < 0) { 754 height = -height; 755 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 756 dst_stride_argb = -dst_stride_argb; 757 } 758 void (*NV12ToARGBRow)(const uint8* y_buf, 759 const uint8* uv_buf, 760 uint8* rgb_buf, 761 int width) = NV12ToARGBRow_C; 762 #if defined(HAS_NV12TOARGBROW_SSSE3) 763 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 764 NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3; 765 if (IS_ALIGNED(width, 8)) { 766 NV12ToARGBRow = NV12ToARGBRow_Unaligned_SSSE3; 767 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 768 NV12ToARGBRow = NV12ToARGBRow_SSSE3; 769 } 770 } 771 } 772 #elif defined(HAS_NV12TOARGBROW_NEON) 773 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 774 NV12ToARGBRow = NV12ToARGBRow_Any_NEON; 775 if (IS_ALIGNED(width, 8)) { 776 NV12ToARGBRow = NV12ToARGBRow_NEON; 777 } 778 } 779 #endif 780 781 for (int y = 0; y < height - 1; y += 2) { 782 NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb, width); 783 NV12ToARGBRow(src_m420 + src_stride_m420, src_m420 + src_stride_m420 * 2, 784 dst_argb + dst_stride_argb, width); 785 dst_argb += dst_stride_argb * 2; 786 src_m420 += src_stride_m420 * 3; 787 } 788 if (height & 1) { 789 NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb, width); 790 } 791 return 0; 792 } 793 794 // Convert YUY2 to ARGB. 795 LIBYUV_API 796 int YUY2ToARGB(const uint8* src_yuy2, int src_stride_yuy2, 797 uint8* dst_argb, int dst_stride_argb, 798 int width, int height) { 799 if (!src_yuy2 || !dst_argb || 800 width <= 0 || height == 0) { 801 return -1; 802 } 803 // Negative height means invert the image. 804 if (height < 0) { 805 height = -height; 806 src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2; 807 src_stride_yuy2 = -src_stride_yuy2; 808 } 809 // Coalesce rows. 810 if (src_stride_yuy2 == width * 2 && 811 dst_stride_argb == width * 4) { 812 width *= height; 813 height = 1; 814 src_stride_yuy2 = dst_stride_argb = 0; 815 } 816 void (*YUY2ToARGBRow)(const uint8* src_yuy2, uint8* dst_argb, int pix) = 817 YUY2ToARGBRow_C; 818 #if defined(HAS_YUY2TOARGBROW_SSSE3) 819 // Posix is 16, Windows is 8. 820 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 821 YUY2ToARGBRow = YUY2ToARGBRow_Any_SSSE3; 822 if (IS_ALIGNED(width, 16)) { 823 YUY2ToARGBRow = YUY2ToARGBRow_Unaligned_SSSE3; 824 if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16) && 825 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 826 YUY2ToARGBRow = YUY2ToARGBRow_SSSE3; 827 } 828 } 829 } 830 #elif defined(HAS_YUY2TOARGBROW_NEON) 831 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 832 YUY2ToARGBRow = YUY2ToARGBRow_Any_NEON; 833 if (IS_ALIGNED(width, 8)) { 834 YUY2ToARGBRow = YUY2ToARGBRow_NEON; 835 } 836 } 837 #endif 838 for (int y = 0; y < height; ++y) { 839 YUY2ToARGBRow(src_yuy2, dst_argb, width); 840 src_yuy2 += src_stride_yuy2; 841 dst_argb += dst_stride_argb; 842 } 843 return 0; 844 } 845 846 // Convert UYVY to ARGB. 847 LIBYUV_API 848 int UYVYToARGB(const uint8* src_uyvy, int src_stride_uyvy, 849 uint8* dst_argb, int dst_stride_argb, 850 int width, int height) { 851 if (!src_uyvy || !dst_argb || 852 width <= 0 || height == 0) { 853 return -1; 854 } 855 // Negative height means invert the image. 856 if (height < 0) { 857 height = -height; 858 src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy; 859 src_stride_uyvy = -src_stride_uyvy; 860 } 861 // Coalesce rows. 862 if (src_stride_uyvy == width * 2 && 863 dst_stride_argb == width * 4) { 864 width *= height; 865 height = 1; 866 src_stride_uyvy = dst_stride_argb = 0; 867 } 868 void (*UYVYToARGBRow)(const uint8* src_uyvy, uint8* dst_argb, int pix) = 869 UYVYToARGBRow_C; 870 #if defined(HAS_UYVYTOARGBROW_SSSE3) 871 // Posix is 16, Windows is 8. 872 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 873 UYVYToARGBRow = UYVYToARGBRow_Any_SSSE3; 874 if (IS_ALIGNED(width, 16)) { 875 UYVYToARGBRow = UYVYToARGBRow_Unaligned_SSSE3; 876 if (IS_ALIGNED(src_uyvy, 16) && IS_ALIGNED(src_stride_uyvy, 16) && 877 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 878 UYVYToARGBRow = UYVYToARGBRow_SSSE3; 879 } 880 } 881 } 882 #elif defined(HAS_UYVYTOARGBROW_NEON) 883 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 884 UYVYToARGBRow = UYVYToARGBRow_Any_NEON; 885 if (IS_ALIGNED(width, 8)) { 886 UYVYToARGBRow = UYVYToARGBRow_NEON; 887 } 888 } 889 #endif 890 for (int y = 0; y < height; ++y) { 891 UYVYToARGBRow(src_uyvy, dst_argb, width); 892 src_uyvy += src_stride_uyvy; 893 dst_argb += dst_stride_argb; 894 } 895 return 0; 896 } 897 898 #ifdef __cplusplus 899 } // extern "C" 900 } // namespace libyuv 901 #endif 902