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 <string.h> // for memset() 14 15 #include "libyuv/cpu_id.h" 16 #include "libyuv/format_conversion.h" 17 #ifdef HAVE_JPEG 18 #include "libyuv/mjpeg_decoder.h" 19 #endif 20 #include "libyuv/rotate_argb.h" 21 #include "libyuv/video_common.h" 22 #include "libyuv/row.h" 23 24 #ifdef __cplusplus 25 namespace libyuv { 26 extern "C" { 27 #endif 28 29 // Copy ARGB with optional flipping 30 LIBYUV_API 31 int ARGBCopy(const uint8* src_argb, int src_stride_argb, 32 uint8* dst_argb, int dst_stride_argb, 33 int width, int height) { 34 if (!src_argb || !dst_argb || 35 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, 46 width * 4, height); 47 return 0; 48 } 49 50 // Convert I444 to ARGB. 51 LIBYUV_API 52 int I444ToARGB(const uint8* src_y, int src_stride_y, 53 const uint8* src_u, int src_stride_u, 54 const uint8* src_v, int src_stride_v, 55 uint8* dst_argb, int dst_stride_argb, 56 int width, int height) { 57 if (!src_y || !src_u || !src_v || 58 !dst_argb || 59 width <= 0 || height == 0) { 60 return -1; 61 } 62 // Negative height means invert the image. 63 if (height < 0) { 64 height = -height; 65 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 66 dst_stride_argb = -dst_stride_argb; 67 } 68 void (*I444ToARGBRow)(const uint8* y_buf, 69 const uint8* u_buf, 70 const uint8* v_buf, 71 uint8* rgb_buf, 72 int width) = I444ToARGBRow_C; 73 #if defined(HAS_I444TOARGBROW_SSSE3) 74 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 75 I444ToARGBRow = I444ToARGBRow_Any_SSSE3; 76 if (IS_ALIGNED(width, 8)) { 77 I444ToARGBRow = I444ToARGBRow_Unaligned_SSSE3; 78 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 79 I444ToARGBRow = I444ToARGBRow_SSSE3; 80 } 81 } 82 } 83 #endif 84 85 for (int y = 0; y < height; ++y) { 86 I444ToARGBRow(src_y, src_u, src_v, dst_argb, width); 87 dst_argb += dst_stride_argb; 88 src_y += src_stride_y; 89 src_u += src_stride_u; 90 src_v += src_stride_v; 91 } 92 return 0; 93 } 94 95 // Convert I422 to ARGB. 96 LIBYUV_API 97 int I422ToARGB(const uint8* src_y, int src_stride_y, 98 const uint8* src_u, int src_stride_u, 99 const uint8* src_v, int src_stride_v, 100 uint8* dst_argb, int dst_stride_argb, 101 int width, int height) { 102 if (!src_y || !src_u || !src_v || 103 !dst_argb || 104 width <= 0 || height == 0) { 105 return -1; 106 } 107 // Negative height means invert the image. 108 if (height < 0) { 109 height = -height; 110 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 111 dst_stride_argb = -dst_stride_argb; 112 } 113 void (*I422ToARGBRow)(const uint8* y_buf, 114 const uint8* u_buf, 115 const uint8* v_buf, 116 uint8* rgb_buf, 117 int width) = I422ToARGBRow_C; 118 #if defined(HAS_I422TOARGBROW_NEON) 119 if (TestCpuFlag(kCpuHasNEON)) { 120 I422ToARGBRow = I422ToARGBRow_Any_NEON; 121 if (IS_ALIGNED(width, 16)) { 122 I422ToARGBRow = I422ToARGBRow_NEON; 123 } 124 } 125 #elif defined(HAS_I422TOARGBROW_SSSE3) 126 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 127 I422ToARGBRow = I422ToARGBRow_Any_SSSE3; 128 if (IS_ALIGNED(width, 8)) { 129 I422ToARGBRow = I422ToARGBRow_Unaligned_SSSE3; 130 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 131 I422ToARGBRow = I422ToARGBRow_SSSE3; 132 } 133 } 134 } 135 #endif 136 137 for (int y = 0; y < height; ++y) { 138 I422ToARGBRow(src_y, src_u, src_v, dst_argb, width); 139 dst_argb += dst_stride_argb; 140 src_y += src_stride_y; 141 src_u += src_stride_u; 142 src_v += src_stride_v; 143 } 144 return 0; 145 } 146 147 // Convert I411 to ARGB. 148 LIBYUV_API 149 int I411ToARGB(const uint8* src_y, int src_stride_y, 150 const uint8* src_u, int src_stride_u, 151 const uint8* src_v, int src_stride_v, 152 uint8* dst_argb, int dst_stride_argb, 153 int width, int height) { 154 if (!src_y || !src_u || !src_v || 155 !dst_argb || 156 width <= 0 || height == 0) { 157 return -1; 158 } 159 // Negative height means invert the image. 160 if (height < 0) { 161 height = -height; 162 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 163 dst_stride_argb = -dst_stride_argb; 164 } 165 void (*I411ToARGBRow)(const uint8* y_buf, 166 const uint8* u_buf, 167 const uint8* v_buf, 168 uint8* rgb_buf, 169 int width) = I411ToARGBRow_C; 170 #if defined(HAS_I411TOARGBROW_SSSE3) 171 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 172 I411ToARGBRow = I411ToARGBRow_Any_SSSE3; 173 if (IS_ALIGNED(width, 8)) { 174 I411ToARGBRow = I411ToARGBRow_Unaligned_SSSE3; 175 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 176 I411ToARGBRow = I411ToARGBRow_SSSE3; 177 } 178 } 179 } 180 #endif 181 182 for (int y = 0; y < height; ++y) { 183 I411ToARGBRow(src_y, src_u, src_v, dst_argb, width); 184 dst_argb += dst_stride_argb; 185 src_y += src_stride_y; 186 src_u += src_stride_u; 187 src_v += src_stride_v; 188 } 189 return 0; 190 } 191 192 193 // Convert I400 to ARGB. 194 LIBYUV_API 195 int I400ToARGB_Reference(const uint8* src_y, int src_stride_y, 196 uint8* dst_argb, int dst_stride_argb, 197 int width, int height) { 198 if (!src_y || !dst_argb || 199 width <= 0 || height == 0) { 200 return -1; 201 } 202 // Negative height means invert the image. 203 if (height < 0) { 204 height = -height; 205 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 206 dst_stride_argb = -dst_stride_argb; 207 } 208 void (*YToARGBRow)(const uint8* y_buf, 209 uint8* rgb_buf, 210 int width) = YToARGBRow_C; 211 #if defined(HAS_YTOARGBROW_SSE2) 212 if (TestCpuFlag(kCpuHasSSE2) && 213 IS_ALIGNED(width, 8) && 214 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 215 YToARGBRow = YToARGBRow_SSE2; 216 } 217 #endif 218 219 for (int y = 0; y < height; ++y) { 220 YToARGBRow(src_y, dst_argb, width); 221 dst_argb += dst_stride_argb; 222 src_y += src_stride_y; 223 } 224 return 0; 225 } 226 227 // Convert I400 to ARGB. 228 LIBYUV_API 229 int I400ToARGB(const uint8* src_y, int src_stride_y, 230 uint8* dst_argb, int dst_stride_argb, 231 int width, int height) { 232 if (!src_y || !dst_argb || 233 width <= 0 || height == 0) { 234 return -1; 235 } 236 // Negative height means invert the image. 237 if (height < 0) { 238 height = -height; 239 src_y = src_y + (height - 1) * src_stride_y; 240 src_stride_y = -src_stride_y; 241 } 242 void (*I400ToARGBRow)(const uint8* src_y, uint8* dst_argb, int pix) = 243 I400ToARGBRow_C; 244 #if defined(HAS_I400TOARGBROW_SSE2) 245 if (TestCpuFlag(kCpuHasSSE2) && 246 IS_ALIGNED(width, 8) && 247 IS_ALIGNED(src_y, 8) && IS_ALIGNED(src_stride_y, 8) && 248 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 249 I400ToARGBRow = I400ToARGBRow_SSE2; 250 } 251 #endif 252 253 for (int y = 0; y < height; ++y) { 254 I400ToARGBRow(src_y, dst_argb, width); 255 src_y += src_stride_y; 256 dst_argb += dst_stride_argb; 257 } 258 return 0; 259 } 260 261 // Convert BGRA to ARGB. 262 LIBYUV_API 263 int BGRAToARGB(const uint8* src_bgra, int src_stride_bgra, 264 uint8* dst_argb, int dst_stride_argb, 265 int width, int height) { 266 if (!src_bgra || !dst_argb || 267 width <= 0 || height == 0) { 268 return -1; 269 } 270 // Negative height means invert the image. 271 if (height < 0) { 272 height = -height; 273 src_bgra = src_bgra + (height - 1) * src_stride_bgra; 274 src_stride_bgra = -src_stride_bgra; 275 } 276 void (*BGRAToARGBRow)(const uint8* src_bgra, uint8* dst_argb, int pix) = 277 BGRAToARGBRow_C; 278 #if defined(HAS_BGRATOARGBROW_SSSE3) 279 if (TestCpuFlag(kCpuHasSSSE3) && 280 IS_ALIGNED(width, 4) && 281 IS_ALIGNED(src_bgra, 16) && IS_ALIGNED(src_stride_bgra, 16) && 282 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 283 BGRAToARGBRow = BGRAToARGBRow_SSSE3; 284 } 285 #endif 286 287 for (int y = 0; y < height; ++y) { 288 BGRAToARGBRow(src_bgra, dst_argb, width); 289 src_bgra += src_stride_bgra; 290 dst_argb += dst_stride_argb; 291 } 292 return 0; 293 } 294 295 // Convert ABGR to ARGB. 296 LIBYUV_API 297 int ABGRToARGB(const uint8* src_abgr, int src_stride_abgr, 298 uint8* dst_argb, int dst_stride_argb, 299 int width, int height) { 300 if (!src_abgr || !dst_argb || 301 width <= 0 || height == 0) { 302 return -1; 303 } 304 // Negative height means invert the image. 305 if (height < 0) { 306 height = -height; 307 src_abgr = src_abgr + (height - 1) * src_stride_abgr; 308 src_stride_abgr = -src_stride_abgr; 309 } 310 void (*ABGRToARGBRow)(const uint8* src_abgr, uint8* dst_argb, int pix) = 311 ABGRToARGBRow_C; 312 #if defined(HAS_ABGRTOARGBROW_SSSE3) 313 if (TestCpuFlag(kCpuHasSSSE3) && 314 IS_ALIGNED(width, 4) && 315 IS_ALIGNED(src_abgr, 16) && IS_ALIGNED(src_stride_abgr, 16) && 316 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 317 ABGRToARGBRow = ABGRToARGBRow_SSSE3; 318 } 319 #endif 320 321 for (int y = 0; y < height; ++y) { 322 ABGRToARGBRow(src_abgr, dst_argb, width); 323 src_abgr += src_stride_abgr; 324 dst_argb += dst_stride_argb; 325 } 326 return 0; 327 } 328 329 // Convert RGBA to ARGB. 330 LIBYUV_API 331 int RGBAToARGB(const uint8* src_rgba, int src_stride_rgba, 332 uint8* dst_argb, int dst_stride_argb, 333 int width, int height) { 334 if (!src_rgba || !dst_argb || 335 width <= 0 || height == 0) { 336 return -1; 337 } 338 // Negative height means invert the image. 339 if (height < 0) { 340 height = -height; 341 src_rgba = src_rgba + (height - 1) * src_stride_rgba; 342 src_stride_rgba = -src_stride_rgba; 343 } 344 void (*RGBAToARGBRow)(const uint8* src_rgba, uint8* dst_argb, int pix) = 345 RGBAToARGBRow_C; 346 #if defined(HAS_RGBATOARGBROW_SSSE3) 347 if (TestCpuFlag(kCpuHasSSSE3) && 348 IS_ALIGNED(width, 4) && 349 IS_ALIGNED(src_rgba, 16) && IS_ALIGNED(src_stride_rgba, 16) && 350 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 351 RGBAToARGBRow = RGBAToARGBRow_SSSE3; 352 } 353 #endif 354 355 for (int y = 0; y < height; ++y) { 356 RGBAToARGBRow(src_rgba, dst_argb, width); 357 src_rgba += src_stride_rgba; 358 dst_argb += dst_stride_argb; 359 } 360 return 0; 361 } 362 363 // Convert RAW to ARGB. 364 LIBYUV_API 365 int RAWToARGB(const uint8* src_raw, int src_stride_raw, 366 uint8* dst_argb, int dst_stride_argb, 367 int width, int height) { 368 if (!src_raw || !dst_argb || 369 width <= 0 || height == 0) { 370 return -1; 371 } 372 // Negative height means invert the image. 373 if (height < 0) { 374 height = -height; 375 src_raw = src_raw + (height - 1) * src_stride_raw; 376 src_stride_raw = -src_stride_raw; 377 } 378 void (*RAWToARGBRow)(const uint8* src_raw, uint8* dst_argb, int pix) = 379 RAWToARGBRow_C; 380 #if defined(HAS_RAWTOARGBROW_SSSE3) 381 if (TestCpuFlag(kCpuHasSSSE3) && 382 IS_ALIGNED(width, 16) && 383 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 384 RAWToARGBRow = RAWToARGBRow_SSSE3; 385 } 386 #endif 387 388 for (int y = 0; y < height; ++y) { 389 RAWToARGBRow(src_raw, dst_argb, width); 390 src_raw += src_stride_raw; 391 dst_argb += dst_stride_argb; 392 } 393 return 0; 394 } 395 396 // Convert RGB24 to ARGB. 397 LIBYUV_API 398 int RGB24ToARGB(const uint8* src_rgb24, int src_stride_rgb24, 399 uint8* dst_argb, int dst_stride_argb, 400 int width, int height) { 401 if (!src_rgb24 || !dst_argb || 402 width <= 0 || height == 0) { 403 return -1; 404 } 405 // Negative height means invert the image. 406 if (height < 0) { 407 height = -height; 408 src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24; 409 src_stride_rgb24 = -src_stride_rgb24; 410 } 411 void (*RGB24ToARGBRow)(const uint8* src_rgb24, uint8* dst_argb, int pix) = 412 RGB24ToARGBRow_C; 413 #if defined(HAS_RGB24TOARGBROW_SSSE3) 414 if (TestCpuFlag(kCpuHasSSSE3) && 415 IS_ALIGNED(width, 16) && 416 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 417 RGB24ToARGBRow = RGB24ToARGBRow_SSSE3; 418 } 419 #endif 420 421 for (int y = 0; y < height; ++y) { 422 RGB24ToARGBRow(src_rgb24, dst_argb, width); 423 src_rgb24 += src_stride_rgb24; 424 dst_argb += dst_stride_argb; 425 } 426 return 0; 427 } 428 429 // Convert RGB565 to ARGB. 430 LIBYUV_API 431 int RGB565ToARGB(const uint8* src_rgb565, int src_stride_rgb565, 432 uint8* dst_argb, int dst_stride_argb, 433 int width, int height) { 434 if (!src_rgb565 || !dst_argb || 435 width <= 0 || height == 0) { 436 return -1; 437 } 438 // Negative height means invert the image. 439 if (height < 0) { 440 height = -height; 441 src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565; 442 src_stride_rgb565 = -src_stride_rgb565; 443 } 444 void (*RGB565ToARGBRow)(const uint8* src_rgb565, uint8* dst_argb, int pix) = 445 RGB565ToARGBRow_C; 446 #if defined(HAS_RGB565TOARGBROW_SSE2) 447 if (TestCpuFlag(kCpuHasSSE2) && 448 IS_ALIGNED(width, 8) && 449 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 450 RGB565ToARGBRow = RGB565ToARGBRow_SSE2; 451 } 452 #endif 453 454 for (int y = 0; y < height; ++y) { 455 RGB565ToARGBRow(src_rgb565, dst_argb, width); 456 src_rgb565 += src_stride_rgb565; 457 dst_argb += dst_stride_argb; 458 } 459 return 0; 460 } 461 462 // Convert ARGB1555 to ARGB. 463 LIBYUV_API 464 int ARGB1555ToARGB(const uint8* src_argb1555, int src_stride_argb1555, 465 uint8* dst_argb, int dst_stride_argb, 466 int width, int height) { 467 if (!src_argb1555 || !dst_argb || 468 width <= 0 || height == 0) { 469 return -1; 470 } 471 // Negative height means invert the image. 472 if (height < 0) { 473 height = -height; 474 src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555; 475 src_stride_argb1555 = -src_stride_argb1555; 476 } 477 void (*ARGB1555ToARGBRow)(const uint8* src_argb1555, uint8* dst_argb, 478 int pix) = ARGB1555ToARGBRow_C; 479 #if defined(HAS_ARGB1555TOARGBROW_SSE2) 480 if (TestCpuFlag(kCpuHasSSE2) && 481 IS_ALIGNED(width, 8) && 482 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 483 ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2; 484 } 485 #endif 486 487 for (int y = 0; y < height; ++y) { 488 ARGB1555ToARGBRow(src_argb1555, dst_argb, width); 489 src_argb1555 += src_stride_argb1555; 490 dst_argb += dst_stride_argb; 491 } 492 return 0; 493 } 494 495 // Convert ARGB4444 to ARGB. 496 LIBYUV_API 497 int ARGB4444ToARGB(const uint8* src_argb4444, int src_stride_argb4444, 498 uint8* dst_argb, int dst_stride_argb, 499 int width, int height) { 500 if (!src_argb4444 || !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_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444; 508 src_stride_argb4444 = -src_stride_argb4444; 509 } 510 void (*ARGB4444ToARGBRow)(const uint8* src_argb4444, uint8* dst_argb, 511 int pix) = ARGB4444ToARGBRow_C; 512 #if defined(HAS_ARGB4444TOARGBROW_SSE2) 513 if (TestCpuFlag(kCpuHasSSE2) && 514 IS_ALIGNED(width, 8) && 515 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 516 ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2; 517 } 518 #endif 519 520 for (int y = 0; y < height; ++y) { 521 ARGB4444ToARGBRow(src_argb4444, dst_argb, width); 522 src_argb4444 += src_stride_argb4444; 523 dst_argb += dst_stride_argb; 524 } 525 return 0; 526 } 527 528 // Convert NV12 to ARGB. 529 LIBYUV_API 530 int NV12ToARGB(const uint8* src_y, int src_stride_y, 531 const uint8* src_uv, int src_stride_uv, 532 uint8* dst_argb, int dst_stride_argb, 533 int width, int height) { 534 if (!src_y || !src_uv || !dst_argb || 535 width <= 0 || height == 0) { 536 return -1; 537 } 538 // Negative height means invert the image. 539 if (height < 0) { 540 height = -height; 541 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 542 dst_stride_argb = -dst_stride_argb; 543 } 544 void (*NV12ToARGBRow)(const uint8* y_buf, 545 const uint8* uv_buf, 546 uint8* rgb_buf, 547 int width) = NV12ToARGBRow_C; 548 #if defined(HAS_NV12TOARGBROW_SSSE3) 549 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 550 NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3; 551 if (IS_ALIGNED(width, 8)) { 552 NV12ToARGBRow = NV12ToARGBRow_Unaligned_SSSE3; 553 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 554 NV12ToARGBRow = NV12ToARGBRow_SSSE3; 555 } 556 } 557 } 558 #endif 559 #if defined(HAS_NV12TOARGBROW_NEON) 560 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 561 NV12ToARGBRow = NV12ToARGBRow_Any_NEON; 562 if (IS_ALIGNED(width, 8)) { 563 NV12ToARGBRow = NV12ToARGBRow_NEON; 564 } 565 } 566 #endif 567 568 for (int y = 0; y < height; ++y) { 569 NV12ToARGBRow(src_y, src_uv, dst_argb, width); 570 dst_argb += dst_stride_argb; 571 src_y += src_stride_y; 572 if (y & 1) { 573 src_uv += src_stride_uv; 574 } 575 } 576 return 0; 577 } 578 579 // Convert NV21 to ARGB. 580 LIBYUV_API 581 int NV21ToARGB(const uint8* src_y, int src_stride_y, 582 const uint8* src_uv, int src_stride_uv, 583 uint8* dst_argb, int dst_stride_argb, 584 int width, int height) { 585 if (!src_y || !src_uv || !dst_argb || 586 width <= 0 || height == 0) { 587 return -1; 588 } 589 // Negative height means invert the image. 590 if (height < 0) { 591 height = -height; 592 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 593 dst_stride_argb = -dst_stride_argb; 594 } 595 void (*NV21ToARGBRow)(const uint8* y_buf, 596 const uint8* uv_buf, 597 uint8* rgb_buf, 598 int width) = NV21ToARGBRow_C; 599 #if defined(HAS_NV21TOARGBROW_SSSE3) 600 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 601 NV21ToARGBRow = NV21ToARGBRow_Any_SSSE3; 602 if (IS_ALIGNED(width, 8)) { 603 NV21ToARGBRow = NV21ToARGBRow_Unaligned_SSSE3; 604 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 605 NV21ToARGBRow = NV21ToARGBRow_SSSE3; 606 } 607 } 608 } 609 #endif 610 #if defined(HAS_NV21TOARGBROW_NEON) 611 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 612 NV21ToARGBRow = NV21ToARGBRow_Any_NEON; 613 if (IS_ALIGNED(width, 8)) { 614 NV21ToARGBRow = NV21ToARGBRow_NEON; 615 } 616 } 617 #endif 618 619 for (int y = 0; y < height; ++y) { 620 NV21ToARGBRow(src_y, src_uv, dst_argb, width); 621 dst_argb += dst_stride_argb; 622 src_y += src_stride_y; 623 if (y & 1) { 624 src_uv += src_stride_uv; 625 } 626 } 627 return 0; 628 } 629 630 // Convert M420 to ARGB. 631 LIBYUV_API 632 int M420ToARGB(const uint8* src_m420, int src_stride_m420, 633 uint8* dst_argb, int dst_stride_argb, 634 int width, int height) { 635 if (!src_m420 || !dst_argb || 636 width <= 0 || height == 0) { 637 return -1; 638 } 639 // Negative height means invert the image. 640 if (height < 0) { 641 height = -height; 642 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 643 dst_stride_argb = -dst_stride_argb; 644 } 645 void (*NV12ToARGBRow)(const uint8* y_buf, 646 const uint8* uv_buf, 647 uint8* rgb_buf, 648 int width) = NV12ToARGBRow_C; 649 #if defined(HAS_NV12TOARGBROW_SSSE3) 650 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 651 NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3; 652 if (IS_ALIGNED(width, 8)) { 653 NV12ToARGBRow = NV12ToARGBRow_Unaligned_SSSE3; 654 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 655 NV12ToARGBRow = NV12ToARGBRow_SSSE3; 656 } 657 } 658 } 659 #endif 660 661 for (int y = 0; y < height - 1; y += 2) { 662 NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb, width); 663 NV12ToARGBRow(src_m420 + src_stride_m420, src_m420 + src_stride_m420 * 2, 664 dst_argb + dst_stride_argb, width); 665 dst_argb += dst_stride_argb * 2; 666 src_m420 += src_stride_m420 * 3; 667 } 668 if (height & 1) { 669 NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb, width); 670 } 671 return 0; 672 } 673 674 // Convert YUY2 to ARGB. 675 LIBYUV_API 676 int YUY2ToARGB(const uint8* src_yuy2, int src_stride_yuy2, 677 uint8* dst_argb, int dst_stride_argb, 678 int width, int height) { 679 if (!src_yuy2 || !dst_argb || 680 width <= 0 || height == 0) { 681 return -1; 682 } 683 // Negative height means invert the image. 684 if (height < 0) { 685 height = -height; 686 src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2; 687 src_stride_yuy2 = -src_stride_yuy2; 688 } 689 void (*YUY2ToUV422Row)(const uint8* src_yuy2, uint8* dst_u, uint8* dst_v, 690 int pix) = YUY2ToUV422Row_C; 691 void (*YUY2ToYRow)(const uint8* src_yuy2, 692 uint8* dst_y, int pix) = YUY2ToYRow_C; 693 #if defined(HAS_YUY2TOYROW_SSE2) 694 if (TestCpuFlag(kCpuHasSSE2)) { 695 if (width > 16) { 696 YUY2ToUV422Row = YUY2ToUV422Row_Any_SSE2; 697 YUY2ToYRow = YUY2ToYRow_Any_SSE2; 698 } 699 if (IS_ALIGNED(width, 16)) { 700 YUY2ToUV422Row = YUY2ToUV422Row_Unaligned_SSE2; 701 YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2; 702 if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) { 703 YUY2ToUV422Row = YUY2ToUV422Row_SSE2; 704 YUY2ToYRow = YUY2ToYRow_SSE2; 705 } 706 } 707 } 708 #elif defined(HAS_YUY2TOYROW_NEON) 709 if (TestCpuFlag(kCpuHasNEON)) { 710 if (width > 8) { 711 YUY2ToYRow = YUY2ToYRow_Any_NEON; 712 if (width > 16) { 713 YUY2ToUV422Row = YUY2ToUV422Row_Any_NEON; 714 } 715 } 716 if (IS_ALIGNED(width, 8)) { 717 YUY2ToYRow = YUY2ToYRow_NEON; 718 if (IS_ALIGNED(width, 16)) { 719 YUY2ToUV422Row = YUY2ToUV422Row_NEON; 720 } 721 } 722 } 723 #endif 724 725 void (*I422ToARGBRow)(const uint8* y_buf, 726 const uint8* u_buf, 727 const uint8* v_buf, 728 uint8* argb_buf, 729 int width) = I422ToARGBRow_C; 730 #if defined(HAS_I422TOARGBROW_NEON) 731 if (TestCpuFlag(kCpuHasNEON)) { 732 I422ToARGBRow = I422ToARGBRow_Any_NEON; 733 if (IS_ALIGNED(width, 16)) { 734 I422ToARGBRow = I422ToARGBRow_NEON; 735 } 736 } 737 #elif defined(HAS_I422TOARGBROW_SSSE3) 738 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 739 I422ToARGBRow = I422ToARGBRow_Any_SSSE3; 740 if (IS_ALIGNED(width, 8) && 741 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 742 I422ToARGBRow = I422ToARGBRow_SSSE3; 743 } 744 } 745 #endif 746 747 SIMD_ALIGNED(uint8 rowy[kMaxStride]); 748 SIMD_ALIGNED(uint8 rowu[kMaxStride]); 749 SIMD_ALIGNED(uint8 rowv[kMaxStride]); 750 751 for (int y = 0; y < height; ++y) { 752 YUY2ToUV422Row(src_yuy2, rowu, rowv, width); 753 YUY2ToYRow(src_yuy2, rowy, width); 754 I422ToARGBRow(rowy, rowu, rowv, dst_argb, width); 755 src_yuy2 += src_stride_yuy2; 756 dst_argb += dst_stride_argb; 757 } 758 return 0; 759 } 760 761 // Convert UYVY to ARGB. 762 LIBYUV_API 763 int UYVYToARGB(const uint8* src_uyvy, int src_stride_uyvy, 764 uint8* dst_argb, int dst_stride_argb, 765 int width, int height) { 766 if (!src_uyvy || !dst_argb || 767 width <= 0 || height == 0) { 768 return -1; 769 } 770 // Negative height means invert the image. 771 if (height < 0) { 772 height = -height; 773 src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy; 774 src_stride_uyvy = -src_stride_uyvy; 775 } 776 void (*UYVYToUV422Row)(const uint8* src_uyvy, uint8* dst_u, uint8* dst_v, 777 int pix) = UYVYToUV422Row_C; 778 void (*UYVYToYRow)(const uint8* src_uyvy, 779 uint8* dst_y, int pix) = UYVYToYRow_C; 780 #if defined(HAS_UYVYTOYROW_SSE2) 781 if (TestCpuFlag(kCpuHasSSE2)) { 782 if (width > 16) { 783 UYVYToUV422Row = UYVYToUV422Row_Any_SSE2; 784 UYVYToYRow = UYVYToYRow_Any_SSE2; 785 } 786 if (IS_ALIGNED(width, 16)) { 787 UYVYToUV422Row = UYVYToUV422Row_Unaligned_SSE2; 788 UYVYToYRow = UYVYToYRow_Unaligned_SSE2; 789 if (IS_ALIGNED(src_uyvy, 16) && IS_ALIGNED(src_stride_uyvy, 16)) { 790 UYVYToUV422Row = UYVYToUV422Row_SSE2; 791 UYVYToYRow = UYVYToYRow_SSE2; 792 } 793 } 794 } 795 #endif 796 void (*I422ToARGBRow)(const uint8* y_buf, 797 const uint8* u_buf, 798 const uint8* v_buf, 799 uint8* argb_buf, 800 int width) = I422ToARGBRow_C; 801 #if defined(HAS_I422TOARGBROW_NEON) 802 if (TestCpuFlag(kCpuHasNEON)) { 803 I422ToARGBRow = I422ToARGBRow_Any_NEON; 804 if (IS_ALIGNED(width, 16)) { 805 I422ToARGBRow = I422ToARGBRow_NEON; 806 } 807 } 808 #elif defined(HAS_I422TOARGBROW_SSSE3) 809 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 810 I422ToARGBRow = I422ToARGBRow_Any_SSSE3; 811 if (IS_ALIGNED(width, 8) && 812 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 813 I422ToARGBRow = I422ToARGBRow_SSSE3; 814 } 815 } 816 #endif 817 818 SIMD_ALIGNED(uint8 rowy[kMaxStride]); 819 SIMD_ALIGNED(uint8 rowu[kMaxStride]); 820 SIMD_ALIGNED(uint8 rowv[kMaxStride]); 821 822 for (int y = 0; y < height; ++y) { 823 UYVYToUV422Row(src_uyvy, rowu, rowv, width); 824 UYVYToYRow(src_uyvy, rowy, width); 825 I422ToARGBRow(rowy, rowu, rowv, dst_argb, width); 826 src_uyvy += src_stride_uyvy; 827 dst_argb += dst_stride_argb; 828 } 829 return 0; 830 } 831 832 #ifdef HAVE_JPEG 833 struct ARGBBuffers { 834 uint8* argb; 835 int argb_stride; 836 int w; 837 int h; 838 }; 839 840 static void JpegI420ToARGB(void* opaque, 841 const uint8* const* data, 842 const int* strides, 843 int rows) { 844 ARGBBuffers* dest = static_cast<ARGBBuffers*>(opaque); 845 I420ToARGB(data[0], strides[0], 846 data[1], strides[1], 847 data[2], strides[2], 848 dest->argb, dest->argb_stride, 849 dest->w, rows); 850 dest->argb += rows * dest->argb_stride; 851 dest->h -= rows; 852 } 853 854 static void JpegI422ToARGB(void* opaque, 855 const uint8* const* data, 856 const int* strides, 857 int rows) { 858 ARGBBuffers* dest = static_cast<ARGBBuffers*>(opaque); 859 I422ToARGB(data[0], strides[0], 860 data[1], strides[1], 861 data[2], strides[2], 862 dest->argb, dest->argb_stride, 863 dest->w, rows); 864 dest->argb += rows * dest->argb_stride; 865 dest->h -= rows; 866 } 867 868 static void JpegI444ToARGB(void* opaque, 869 const uint8* const* data, 870 const int* strides, 871 int rows) { 872 ARGBBuffers* dest = static_cast<ARGBBuffers*>(opaque); 873 I444ToARGB(data[0], strides[0], 874 data[1], strides[1], 875 data[2], strides[2], 876 dest->argb, dest->argb_stride, 877 dest->w, rows); 878 dest->argb += rows * dest->argb_stride; 879 dest->h -= rows; 880 } 881 882 static void JpegI411ToARGB(void* opaque, 883 const uint8* const* data, 884 const int* strides, 885 int rows) { 886 ARGBBuffers* dest = static_cast<ARGBBuffers*>(opaque); 887 I411ToARGB(data[0], strides[0], 888 data[1], strides[1], 889 data[2], strides[2], 890 dest->argb, dest->argb_stride, 891 dest->w, rows); 892 dest->argb += rows * dest->argb_stride; 893 dest->h -= rows; 894 } 895 896 static void JpegI400ToARGB(void* opaque, 897 const uint8* const* data, 898 const int* strides, 899 int rows) { 900 ARGBBuffers* dest = static_cast<ARGBBuffers*>(opaque); 901 I400ToARGB(data[0], strides[0], 902 dest->argb, dest->argb_stride, 903 dest->w, rows); 904 dest->argb += rows * dest->argb_stride; 905 dest->h -= rows; 906 } 907 908 // MJPG (Motion JPeg) to ARGB 909 // TODO(fbarchard): review w and h requirement. dw and dh may be enough. 910 LIBYUV_API 911 int MJPGToARGB(const uint8* sample, 912 size_t sample_size, 913 uint8* argb, int argb_stride, 914 int w, int h, 915 int dw, int dh) { 916 if (sample_size == kUnknownDataSize) { 917 // ERROR: MJPEG frame size unknown 918 return -1; 919 } 920 921 // TODO(fbarchard): Port to C 922 MJpegDecoder mjpeg_decoder; 923 bool ret = mjpeg_decoder.LoadFrame(sample, sample_size); 924 if (ret && (mjpeg_decoder.GetWidth() != w || 925 mjpeg_decoder.GetHeight() != h)) { 926 // ERROR: MJPEG frame has unexpected dimensions 927 mjpeg_decoder.UnloadFrame(); 928 return 1; // runtime failure 929 } 930 if (ret) { 931 ARGBBuffers bufs = { argb, argb_stride, dw, dh }; 932 // YUV420 933 if (mjpeg_decoder.GetColorSpace() == 934 MJpegDecoder::kColorSpaceYCbCr && 935 mjpeg_decoder.GetNumComponents() == 3 && 936 mjpeg_decoder.GetVertSampFactor(0) == 2 && 937 mjpeg_decoder.GetHorizSampFactor(0) == 2 && 938 mjpeg_decoder.GetVertSampFactor(1) == 1 && 939 mjpeg_decoder.GetHorizSampFactor(1) == 1 && 940 mjpeg_decoder.GetVertSampFactor(2) == 1 && 941 mjpeg_decoder.GetHorizSampFactor(2) == 1) { 942 ret = mjpeg_decoder.DecodeToCallback(&JpegI420ToARGB, &bufs, dw, dh); 943 // YUV422 944 } else if (mjpeg_decoder.GetColorSpace() == 945 MJpegDecoder::kColorSpaceYCbCr && 946 mjpeg_decoder.GetNumComponents() == 3 && 947 mjpeg_decoder.GetVertSampFactor(0) == 1 && 948 mjpeg_decoder.GetHorizSampFactor(0) == 2 && 949 mjpeg_decoder.GetVertSampFactor(1) == 1 && 950 mjpeg_decoder.GetHorizSampFactor(1) == 1 && 951 mjpeg_decoder.GetVertSampFactor(2) == 1 && 952 mjpeg_decoder.GetHorizSampFactor(2) == 1) { 953 ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToARGB, &bufs, dw, dh); 954 // YUV444 955 } else if (mjpeg_decoder.GetColorSpace() == 956 MJpegDecoder::kColorSpaceYCbCr && 957 mjpeg_decoder.GetNumComponents() == 3 && 958 mjpeg_decoder.GetVertSampFactor(0) == 1 && 959 mjpeg_decoder.GetHorizSampFactor(0) == 1 && 960 mjpeg_decoder.GetVertSampFactor(1) == 1 && 961 mjpeg_decoder.GetHorizSampFactor(1) == 1 && 962 mjpeg_decoder.GetVertSampFactor(2) == 1 && 963 mjpeg_decoder.GetHorizSampFactor(2) == 1) { 964 ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToARGB, &bufs, dw, dh); 965 // YUV411 966 } else if (mjpeg_decoder.GetColorSpace() == 967 MJpegDecoder::kColorSpaceYCbCr && 968 mjpeg_decoder.GetNumComponents() == 3 && 969 mjpeg_decoder.GetVertSampFactor(0) == 1 && 970 mjpeg_decoder.GetHorizSampFactor(0) == 4 && 971 mjpeg_decoder.GetVertSampFactor(1) == 1 && 972 mjpeg_decoder.GetHorizSampFactor(1) == 1 && 973 mjpeg_decoder.GetVertSampFactor(2) == 1 && 974 mjpeg_decoder.GetHorizSampFactor(2) == 1) { 975 ret = mjpeg_decoder.DecodeToCallback(&JpegI411ToARGB, &bufs, dw, dh); 976 // YUV400 977 } else if (mjpeg_decoder.GetColorSpace() == 978 MJpegDecoder::kColorSpaceGrayscale && 979 mjpeg_decoder.GetNumComponents() == 1 && 980 mjpeg_decoder.GetVertSampFactor(0) == 1 && 981 mjpeg_decoder.GetHorizSampFactor(0) == 1) { 982 ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToARGB, &bufs, dw, dh); 983 } else { 984 // TODO(fbarchard): Implement conversion for any other colorspace/sample 985 // factors that occur in practice. 411 is supported by libjpeg 986 // ERROR: Unable to convert MJPEG frame because format is not supported 987 mjpeg_decoder.UnloadFrame(); 988 return 1; 989 } 990 } 991 return 0; 992 } 993 #endif 994 995 // Convert camera sample to I420 with cropping, rotation and vertical flip. 996 // src_width is used for source stride computation 997 // src_height is used to compute location of planes, and indicate inversion 998 // sample_size is measured in bytes and is the size of the frame. 999 // With MJPEG it is the compressed size of the frame. 1000 LIBYUV_API 1001 int ConvertToARGB(const uint8* sample, size_t sample_size, 1002 uint8* dst_argb, int argb_stride, 1003 int crop_x, int crop_y, 1004 int src_width, int src_height, 1005 int dst_width, int dst_height, 1006 RotationMode rotation, 1007 uint32 format) { 1008 if (dst_argb == NULL || sample == NULL || 1009 src_width <= 0 || dst_width <= 0 || 1010 src_height == 0 || dst_height == 0) { 1011 return -1; 1012 } 1013 int aligned_src_width = (src_width + 1) & ~1; 1014 const uint8* src; 1015 const uint8* src_uv; 1016 int abs_src_height = (src_height < 0) ? -src_height : src_height; 1017 int inv_dst_height = (dst_height < 0) ? -dst_height : dst_height; 1018 if (src_height < 0) { 1019 inv_dst_height = -inv_dst_height; 1020 } 1021 int r = 0; 1022 1023 // One pass rotation is available for some formats. For the rest, convert 1024 // to I420 (with optional vertical flipping) into a temporary I420 buffer, 1025 // and then rotate the I420 to the final destination buffer. 1026 // For in-place conversion, if destination dst_argb is same as source sample, 1027 // also enable temporary buffer. 1028 bool need_buf = (rotation && format != FOURCC_ARGB) || dst_argb == sample; 1029 uint8* tmp_argb = dst_argb; 1030 int tmp_argb_stride = argb_stride; 1031 uint8* buf = NULL; 1032 int abs_dst_height = (dst_height < 0) ? -dst_height : dst_height; 1033 if (need_buf) { 1034 int argb_size = dst_width * abs_dst_height * 4; 1035 buf = new uint8[argb_size]; 1036 if (!buf) { 1037 return 1; // Out of memory runtime error. 1038 } 1039 dst_argb = buf; 1040 argb_stride = dst_width; 1041 } 1042 1043 switch (format) { 1044 // Single plane formats 1045 case FOURCC_YUY2: 1046 src = sample + (aligned_src_width * crop_y + crop_x) * 2; 1047 r = YUY2ToARGB(src, aligned_src_width * 2, 1048 dst_argb, argb_stride, 1049 dst_width, inv_dst_height); 1050 break; 1051 case FOURCC_UYVY: 1052 src = sample + (aligned_src_width * crop_y + crop_x) * 2; 1053 r = UYVYToARGB(src, aligned_src_width * 2, 1054 dst_argb, argb_stride, 1055 dst_width, inv_dst_height); 1056 break; 1057 // case FOURCC_V210: 1058 // stride is multiple of 48 pixels (128 bytes). 1059 // pixels come in groups of 6 = 16 bytes 1060 // src = sample + (aligned_src_width + 47) / 48 * 128 * crop_y + 1061 // crop_x / 6 * 16; 1062 // r = V210ToARGB(src, (aligned_src_width + 47) / 48 * 128, 1063 // dst_argb, argb_stride, 1064 // dst_width, inv_dst_height); 1065 // break; 1066 case FOURCC_24BG: 1067 src = sample + (src_width * crop_y + crop_x) * 3; 1068 r = RGB24ToARGB(src, src_width * 3, 1069 dst_argb, argb_stride, 1070 dst_width, inv_dst_height); 1071 break; 1072 case FOURCC_RAW: 1073 src = sample + (src_width * crop_y + crop_x) * 3; 1074 r = RAWToARGB(src, src_width * 3, 1075 dst_argb, argb_stride, 1076 dst_width, inv_dst_height); 1077 break; 1078 case FOURCC_ARGB: 1079 src = sample + (src_width * crop_y + crop_x) * 4; 1080 r = ARGBToARGB(src, src_width * 4, 1081 dst_argb, argb_stride, 1082 dst_width, inv_dst_height); 1083 break; 1084 case FOURCC_BGRA: 1085 src = sample + (src_width * crop_y + crop_x) * 4; 1086 r = BGRAToARGB(src, src_width * 4, 1087 dst_argb, argb_stride, 1088 dst_width, inv_dst_height); 1089 break; 1090 case FOURCC_ABGR: 1091 src = sample + (src_width * crop_y + crop_x) * 4; 1092 r = ABGRToARGB(src, src_width * 4, 1093 dst_argb, argb_stride, 1094 dst_width, inv_dst_height); 1095 break; 1096 case FOURCC_RGBA: 1097 src = sample + (src_width * crop_y + crop_x) * 4; 1098 r = RGBAToARGB(src, src_width * 4, 1099 dst_argb, argb_stride, 1100 dst_width, inv_dst_height); 1101 break; 1102 case FOURCC_RGBP: 1103 src = sample + (src_width * crop_y + crop_x) * 2; 1104 r = RGB565ToARGB(src, src_width * 2, 1105 dst_argb, argb_stride, 1106 dst_width, inv_dst_height); 1107 break; 1108 case FOURCC_RGBO: 1109 src = sample + (src_width * crop_y + crop_x) * 2; 1110 r = ARGB1555ToARGB(src, src_width * 2, 1111 dst_argb, argb_stride, 1112 dst_width, inv_dst_height); 1113 break; 1114 case FOURCC_R444: 1115 src = sample + (src_width * crop_y + crop_x) * 2; 1116 r = ARGB4444ToARGB(src, src_width * 2, 1117 dst_argb, argb_stride, 1118 dst_width, inv_dst_height); 1119 break; 1120 // TODO(fbarchard): Support cropping Bayer by odd numbers 1121 // by adjusting fourcc. 1122 case FOURCC_BGGR: 1123 src = sample + (src_width * crop_y + crop_x); 1124 r = BayerBGGRToARGB(src, src_width, 1125 dst_argb, argb_stride, 1126 dst_width, inv_dst_height); 1127 break; 1128 1129 case FOURCC_GBRG: 1130 src = sample + (src_width * crop_y + crop_x); 1131 r = BayerGBRGToARGB(src, src_width, 1132 dst_argb, argb_stride, 1133 dst_width, inv_dst_height); 1134 break; 1135 1136 case FOURCC_GRBG: 1137 src = sample + (src_width * crop_y + crop_x); 1138 r = BayerGRBGToARGB(src, src_width, 1139 dst_argb, argb_stride, 1140 dst_width, inv_dst_height); 1141 break; 1142 1143 case FOURCC_RGGB: 1144 src = sample + (src_width * crop_y + crop_x); 1145 r = BayerRGGBToARGB(src, src_width, 1146 dst_argb, argb_stride, 1147 dst_width, inv_dst_height); 1148 break; 1149 1150 case FOURCC_I400: 1151 src = sample + src_width * crop_y + crop_x; 1152 r = I400ToARGB(src, src_width, 1153 dst_argb, argb_stride, 1154 dst_width, inv_dst_height); 1155 break; 1156 1157 // Biplanar formats 1158 case FOURCC_NV12: 1159 src = sample + (src_width * crop_y + crop_x); 1160 src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x; 1161 r = NV12ToARGB(src, src_width, 1162 src_uv, aligned_src_width, 1163 dst_argb, argb_stride, 1164 dst_width, inv_dst_height); 1165 break; 1166 case FOURCC_NV21: 1167 src = sample + (src_width * crop_y + crop_x); 1168 src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x; 1169 // Call NV12 but with u and v parameters swapped. 1170 r = NV21ToARGB(src, src_width, 1171 src_uv, aligned_src_width, 1172 dst_argb, argb_stride, 1173 dst_width, inv_dst_height); 1174 break; 1175 case FOURCC_M420: 1176 src = sample + (src_width * crop_y) * 12 / 8 + crop_x; 1177 r = M420ToARGB(src, src_width, 1178 dst_argb, argb_stride, 1179 dst_width, inv_dst_height); 1180 break; 1181 // case FOURCC_Q420: 1182 // src = sample + (src_width + aligned_src_width * 2) * crop_y + crop_x; 1183 // src_uv = sample + (src_width + aligned_src_width * 2) * crop_y + 1184 // src_width + crop_x * 2; 1185 // r = Q420ToARGB(src, src_width * 3, 1186 // src_uv, src_width * 3, 1187 // dst_argb, argb_stride, 1188 // dst_width, inv_dst_height); 1189 // break; 1190 // Triplanar formats 1191 case FOURCC_I420: 1192 case FOURCC_YU12: 1193 case FOURCC_YV12: { 1194 const uint8* src_y = sample + (src_width * crop_y + crop_x); 1195 const uint8* src_u; 1196 const uint8* src_v; 1197 int halfwidth = (src_width + 1) / 2; 1198 int halfheight = (abs_src_height + 1) / 2; 1199 if (format == FOURCC_YV12) { 1200 src_v = sample + src_width * abs_src_height + 1201 (halfwidth * crop_y + crop_x) / 2; 1202 src_u = sample + src_width * abs_src_height + 1203 halfwidth * (halfheight + crop_y / 2) + crop_x / 2; 1204 } else { 1205 src_u = sample + src_width * abs_src_height + 1206 (halfwidth * crop_y + crop_x) / 2; 1207 src_v = sample + src_width * abs_src_height + 1208 halfwidth * (halfheight + crop_y / 2) + crop_x / 2; 1209 } 1210 r = I420ToARGB(src_y, src_width, 1211 src_u, halfwidth, 1212 src_v, halfwidth, 1213 dst_argb, argb_stride, 1214 dst_width, inv_dst_height); 1215 break; 1216 } 1217 case FOURCC_I422: 1218 case FOURCC_YV16: { 1219 const uint8* src_y = sample + src_width * crop_y + crop_x; 1220 const uint8* src_u; 1221 const uint8* src_v; 1222 int halfwidth = (src_width + 1) / 2; 1223 if (format == FOURCC_YV16) { 1224 src_v = sample + src_width * abs_src_height + 1225 halfwidth * crop_y + crop_x / 2; 1226 src_u = sample + src_width * abs_src_height + 1227 halfwidth * (abs_src_height + crop_y) + crop_x / 2; 1228 } else { 1229 src_u = sample + src_width * abs_src_height + 1230 halfwidth * crop_y + crop_x / 2; 1231 src_v = sample + src_width * abs_src_height + 1232 halfwidth * (abs_src_height + crop_y) + crop_x / 2; 1233 } 1234 r = I422ToARGB(src_y, src_width, 1235 src_u, halfwidth, 1236 src_v, halfwidth, 1237 dst_argb, argb_stride, 1238 dst_width, inv_dst_height); 1239 break; 1240 } 1241 case FOURCC_I444: 1242 case FOURCC_YV24: { 1243 const uint8* src_y = sample + src_width * crop_y + crop_x; 1244 const uint8* src_u; 1245 const uint8* src_v; 1246 if (format == FOURCC_YV24) { 1247 src_v = sample + src_width * (abs_src_height + crop_y) + crop_x; 1248 src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x; 1249 } else { 1250 src_u = sample + src_width * (abs_src_height + crop_y) + crop_x; 1251 src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x; 1252 } 1253 r = I444ToARGB(src_y, src_width, 1254 src_u, src_width, 1255 src_v, src_width, 1256 dst_argb, argb_stride, 1257 dst_width, inv_dst_height); 1258 break; 1259 } 1260 case FOURCC_I411: { 1261 int quarterwidth = (src_width + 3) / 4; 1262 const uint8* src_y = sample + src_width * crop_y + crop_x; 1263 const uint8* src_u = sample + src_width * abs_src_height + 1264 quarterwidth * crop_y + crop_x / 4; 1265 const uint8* src_v = sample + src_width * abs_src_height + 1266 quarterwidth * (abs_src_height + crop_y) + crop_x / 4; 1267 r = I411ToARGB(src_y, src_width, 1268 src_u, quarterwidth, 1269 src_v, quarterwidth, 1270 dst_argb, argb_stride, 1271 dst_width, inv_dst_height); 1272 break; 1273 } 1274 #ifdef HAVE_JPEG 1275 case FOURCC_MJPG: 1276 r = MJPGToARGB(sample, sample_size, 1277 dst_argb, argb_stride, 1278 src_width, abs_src_height, dst_width, inv_dst_height); 1279 break; 1280 #endif 1281 default: 1282 r = -1; // unknown fourcc - return failure code. 1283 } 1284 1285 if (need_buf) { 1286 if (!r) { 1287 r = ARGBRotate(dst_argb, argb_stride, 1288 tmp_argb, tmp_argb_stride, 1289 dst_width, abs_dst_height, rotation); 1290 } 1291 delete buf; 1292 } 1293 1294 return r; 1295 } 1296 1297 #ifdef __cplusplus 1298 } // extern "C" 1299 } // namespace libyuv 1300 #endif 1301