1 /* 2 * Copyright 2012 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_from.h" 12 13 #include "libyuv/basic_types.h" 14 #include "libyuv/convert.h" // For I420Copy 15 #include "libyuv/cpu_id.h" 16 #include "libyuv/planar_functions.h" 17 #include "libyuv/rotate.h" 18 #include "libyuv/scale.h" // For ScalePlane() 19 #include "libyuv/video_common.h" 20 #include "libyuv/row.h" 21 22 #ifdef __cplusplus 23 namespace libyuv { 24 extern "C" { 25 #endif 26 27 #define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s) 28 static __inline int Abs(int v) { 29 return v >= 0 ? v : -v; 30 } 31 32 // I420 To any I4xx YUV format with mirroring. 33 static int I420ToI4xx(const uint8* src_y, int src_stride_y, 34 const uint8* src_u, int src_stride_u, 35 const uint8* src_v, int src_stride_v, 36 uint8* dst_y, int dst_stride_y, 37 uint8* dst_u, int dst_stride_u, 38 uint8* dst_v, int dst_stride_v, 39 int src_y_width, int src_y_height, 40 int dst_uv_width, int dst_uv_height) { 41 const int dst_y_width = Abs(src_y_width); 42 const int dst_y_height = Abs(src_y_height); 43 const int src_uv_width = SUBSAMPLE(src_y_width, 1, 1); 44 const int src_uv_height = SUBSAMPLE(src_y_height, 1, 1); 45 if (src_y_width == 0 || src_y_height == 0 || 46 dst_uv_width <= 0 || dst_uv_height <= 0) { 47 return -1; 48 } 49 ScalePlane(src_y, src_stride_y, src_y_width, src_y_height, 50 dst_y, dst_stride_y, dst_y_width, dst_y_height, 51 kFilterBilinear); 52 ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height, 53 dst_u, dst_stride_u, dst_uv_width, dst_uv_height, 54 kFilterBilinear); 55 ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height, 56 dst_v, dst_stride_v, dst_uv_width, dst_uv_height, 57 kFilterBilinear); 58 return 0; 59 } 60 61 // 420 chroma is 1/2 width, 1/2 height 62 // 422 chroma is 1/2 width, 1x height 63 LIBYUV_API 64 int I420ToI422(const uint8* src_y, int src_stride_y, 65 const uint8* src_u, int src_stride_u, 66 const uint8* src_v, int src_stride_v, 67 uint8* dst_y, int dst_stride_y, 68 uint8* dst_u, int dst_stride_u, 69 uint8* dst_v, int dst_stride_v, 70 int width, int height) { 71 const int dst_uv_width = (Abs(width) + 1) >> 1; 72 const int dst_uv_height = Abs(height); 73 return I420ToI4xx(src_y, src_stride_y, 74 src_u, src_stride_u, 75 src_v, src_stride_v, 76 dst_y, dst_stride_y, 77 dst_u, dst_stride_u, 78 dst_v, dst_stride_v, 79 width, height, 80 dst_uv_width, dst_uv_height); 81 } 82 83 // 420 chroma is 1/2 width, 1/2 height 84 // 444 chroma is 1x width, 1x height 85 LIBYUV_API 86 int I420ToI444(const uint8* src_y, int src_stride_y, 87 const uint8* src_u, int src_stride_u, 88 const uint8* src_v, int src_stride_v, 89 uint8* dst_y, int dst_stride_y, 90 uint8* dst_u, int dst_stride_u, 91 uint8* dst_v, int dst_stride_v, 92 int width, int height) { 93 const int dst_uv_width = Abs(width); 94 const int dst_uv_height = Abs(height); 95 return I420ToI4xx(src_y, src_stride_y, 96 src_u, src_stride_u, 97 src_v, src_stride_v, 98 dst_y, dst_stride_y, 99 dst_u, dst_stride_u, 100 dst_v, dst_stride_v, 101 width, height, 102 dst_uv_width, dst_uv_height); 103 } 104 105 // 420 chroma is 1/2 width, 1/2 height 106 // 411 chroma is 1/4 width, 1x height 107 LIBYUV_API 108 int I420ToI411(const uint8* src_y, int src_stride_y, 109 const uint8* src_u, int src_stride_u, 110 const uint8* src_v, int src_stride_v, 111 uint8* dst_y, int dst_stride_y, 112 uint8* dst_u, int dst_stride_u, 113 uint8* dst_v, int dst_stride_v, 114 int width, int height) { 115 const int dst_uv_width = (Abs(width) + 3) >> 2; 116 const int dst_uv_height = Abs(height); 117 return I420ToI4xx(src_y, src_stride_y, 118 src_u, src_stride_u, 119 src_v, src_stride_v, 120 dst_y, dst_stride_y, 121 dst_u, dst_stride_u, 122 dst_v, dst_stride_v, 123 width, height, 124 dst_uv_width, dst_uv_height); 125 } 126 127 // Copy to I400. Source can be I420,422,444,400,NV12,NV21 128 LIBYUV_API 129 int I400Copy(const uint8* src_y, int src_stride_y, 130 uint8* dst_y, int dst_stride_y, 131 int width, int height) { 132 if (!src_y || !dst_y || 133 width <= 0 || height == 0) { 134 return -1; 135 } 136 // Negative height means invert the image. 137 if (height < 0) { 138 height = -height; 139 src_y = src_y + (height - 1) * src_stride_y; 140 src_stride_y = -src_stride_y; 141 } 142 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); 143 return 0; 144 } 145 146 LIBYUV_API 147 int I422ToYUY2(const uint8* src_y, int src_stride_y, 148 const uint8* src_u, int src_stride_u, 149 const uint8* src_v, int src_stride_v, 150 uint8* dst_yuy2, int dst_stride_yuy2, 151 int width, int height) { 152 int y; 153 void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u, 154 const uint8* src_v, uint8* dst_yuy2, int width) = 155 I422ToYUY2Row_C; 156 if (!src_y || !src_u || !src_v || !dst_yuy2 || 157 width <= 0 || height == 0) { 158 return -1; 159 } 160 // Negative height means invert the image. 161 if (height < 0) { 162 height = -height; 163 dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2; 164 dst_stride_yuy2 = -dst_stride_yuy2; 165 } 166 // Coalesce rows. 167 if (src_stride_y == width && 168 src_stride_u * 2 == width && 169 src_stride_v * 2 == width && 170 dst_stride_yuy2 == width * 2) { 171 width *= height; 172 height = 1; 173 src_stride_y = src_stride_u = src_stride_v = dst_stride_yuy2 = 0; 174 } 175 #if defined(HAS_I422TOYUY2ROW_SSE2) 176 if (TestCpuFlag(kCpuHasSSE2)) { 177 I422ToYUY2Row = I422ToYUY2Row_Any_SSE2; 178 if (IS_ALIGNED(width, 16)) { 179 I422ToYUY2Row = I422ToYUY2Row_SSE2; 180 } 181 } 182 #endif 183 #if defined(HAS_I422TOYUY2ROW_NEON) 184 if (TestCpuFlag(kCpuHasNEON)) { 185 I422ToYUY2Row = I422ToYUY2Row_Any_NEON; 186 if (IS_ALIGNED(width, 16)) { 187 I422ToYUY2Row = I422ToYUY2Row_NEON; 188 } 189 } 190 #endif 191 192 for (y = 0; y < height; ++y) { 193 I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width); 194 src_y += src_stride_y; 195 src_u += src_stride_u; 196 src_v += src_stride_v; 197 dst_yuy2 += dst_stride_yuy2; 198 } 199 return 0; 200 } 201 202 LIBYUV_API 203 int I420ToYUY2(const uint8* src_y, int src_stride_y, 204 const uint8* src_u, int src_stride_u, 205 const uint8* src_v, int src_stride_v, 206 uint8* dst_yuy2, int dst_stride_yuy2, 207 int width, int height) { 208 int y; 209 void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u, 210 const uint8* src_v, uint8* dst_yuy2, int width) = 211 I422ToYUY2Row_C; 212 if (!src_y || !src_u || !src_v || !dst_yuy2 || 213 width <= 0 || height == 0) { 214 return -1; 215 } 216 // Negative height means invert the image. 217 if (height < 0) { 218 height = -height; 219 dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2; 220 dst_stride_yuy2 = -dst_stride_yuy2; 221 } 222 #if defined(HAS_I422TOYUY2ROW_SSE2) 223 if (TestCpuFlag(kCpuHasSSE2)) { 224 I422ToYUY2Row = I422ToYUY2Row_Any_SSE2; 225 if (IS_ALIGNED(width, 16)) { 226 I422ToYUY2Row = I422ToYUY2Row_SSE2; 227 } 228 } 229 #endif 230 #if defined(HAS_I422TOYUY2ROW_NEON) 231 if (TestCpuFlag(kCpuHasNEON)) { 232 I422ToYUY2Row = I422ToYUY2Row_Any_NEON; 233 if (IS_ALIGNED(width, 16)) { 234 I422ToYUY2Row = I422ToYUY2Row_NEON; 235 } 236 } 237 #endif 238 239 for (y = 0; y < height - 1; y += 2) { 240 I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width); 241 I422ToYUY2Row(src_y + src_stride_y, src_u, src_v, 242 dst_yuy2 + dst_stride_yuy2, width); 243 src_y += src_stride_y * 2; 244 src_u += src_stride_u; 245 src_v += src_stride_v; 246 dst_yuy2 += dst_stride_yuy2 * 2; 247 } 248 if (height & 1) { 249 I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width); 250 } 251 return 0; 252 } 253 254 LIBYUV_API 255 int I422ToUYVY(const uint8* src_y, int src_stride_y, 256 const uint8* src_u, int src_stride_u, 257 const uint8* src_v, int src_stride_v, 258 uint8* dst_uyvy, int dst_stride_uyvy, 259 int width, int height) { 260 int y; 261 void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u, 262 const uint8* src_v, uint8* dst_uyvy, int width) = 263 I422ToUYVYRow_C; 264 if (!src_y || !src_u || !src_v || !dst_uyvy || 265 width <= 0 || height == 0) { 266 return -1; 267 } 268 // Negative height means invert the image. 269 if (height < 0) { 270 height = -height; 271 dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy; 272 dst_stride_uyvy = -dst_stride_uyvy; 273 } 274 // Coalesce rows. 275 if (src_stride_y == width && 276 src_stride_u * 2 == width && 277 src_stride_v * 2 == width && 278 dst_stride_uyvy == width * 2) { 279 width *= height; 280 height = 1; 281 src_stride_y = src_stride_u = src_stride_v = dst_stride_uyvy = 0; 282 } 283 #if defined(HAS_I422TOUYVYROW_SSE2) 284 if (TestCpuFlag(kCpuHasSSE2)) { 285 I422ToUYVYRow = I422ToUYVYRow_Any_SSE2; 286 if (IS_ALIGNED(width, 16)) { 287 I422ToUYVYRow = I422ToUYVYRow_SSE2; 288 } 289 } 290 #endif 291 #if defined(HAS_I422TOUYVYROW_NEON) 292 if (TestCpuFlag(kCpuHasNEON)) { 293 I422ToUYVYRow = I422ToUYVYRow_Any_NEON; 294 if (IS_ALIGNED(width, 16)) { 295 I422ToUYVYRow = I422ToUYVYRow_NEON; 296 } 297 } 298 #endif 299 300 for (y = 0; y < height; ++y) { 301 I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width); 302 src_y += src_stride_y; 303 src_u += src_stride_u; 304 src_v += src_stride_v; 305 dst_uyvy += dst_stride_uyvy; 306 } 307 return 0; 308 } 309 310 LIBYUV_API 311 int I420ToUYVY(const uint8* src_y, int src_stride_y, 312 const uint8* src_u, int src_stride_u, 313 const uint8* src_v, int src_stride_v, 314 uint8* dst_uyvy, int dst_stride_uyvy, 315 int width, int height) { 316 int y; 317 void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u, 318 const uint8* src_v, uint8* dst_uyvy, int width) = 319 I422ToUYVYRow_C; 320 if (!src_y || !src_u || !src_v || !dst_uyvy || 321 width <= 0 || height == 0) { 322 return -1; 323 } 324 // Negative height means invert the image. 325 if (height < 0) { 326 height = -height; 327 dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy; 328 dst_stride_uyvy = -dst_stride_uyvy; 329 } 330 #if defined(HAS_I422TOUYVYROW_SSE2) 331 if (TestCpuFlag(kCpuHasSSE2)) { 332 I422ToUYVYRow = I422ToUYVYRow_Any_SSE2; 333 if (IS_ALIGNED(width, 16)) { 334 I422ToUYVYRow = I422ToUYVYRow_SSE2; 335 } 336 } 337 #endif 338 #if defined(HAS_I422TOUYVYROW_NEON) 339 if (TestCpuFlag(kCpuHasNEON)) { 340 I422ToUYVYRow = I422ToUYVYRow_Any_NEON; 341 if (IS_ALIGNED(width, 16)) { 342 I422ToUYVYRow = I422ToUYVYRow_NEON; 343 } 344 } 345 #endif 346 347 for (y = 0; y < height - 1; y += 2) { 348 I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width); 349 I422ToUYVYRow(src_y + src_stride_y, src_u, src_v, 350 dst_uyvy + dst_stride_uyvy, width); 351 src_y += src_stride_y * 2; 352 src_u += src_stride_u; 353 src_v += src_stride_v; 354 dst_uyvy += dst_stride_uyvy * 2; 355 } 356 if (height & 1) { 357 I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width); 358 } 359 return 0; 360 } 361 362 LIBYUV_API 363 int I420ToNV12(const uint8* src_y, int src_stride_y, 364 const uint8* src_u, int src_stride_u, 365 const uint8* src_v, int src_stride_v, 366 uint8* dst_y, int dst_stride_y, 367 uint8* dst_uv, int dst_stride_uv, 368 int width, int height) { 369 int y; 370 void (*MergeUVRow_)(const uint8* src_u, const uint8* src_v, uint8* dst_uv, 371 int width) = MergeUVRow_C; 372 // Coalesce rows. 373 int halfwidth = (width + 1) >> 1; 374 int halfheight = (height + 1) >> 1; 375 if (!src_y || !src_u || !src_v || !dst_y || !dst_uv || 376 width <= 0 || height == 0) { 377 return -1; 378 } 379 // Negative height means invert the image. 380 if (height < 0) { 381 height = -height; 382 halfheight = (height + 1) >> 1; 383 dst_y = dst_y + (height - 1) * dst_stride_y; 384 dst_uv = dst_uv + (halfheight - 1) * dst_stride_uv; 385 dst_stride_y = -dst_stride_y; 386 dst_stride_uv = -dst_stride_uv; 387 } 388 if (src_stride_y == width && 389 dst_stride_y == width) { 390 width *= height; 391 height = 1; 392 src_stride_y = dst_stride_y = 0; 393 } 394 // Coalesce rows. 395 if (src_stride_u == halfwidth && 396 src_stride_v == halfwidth && 397 dst_stride_uv == halfwidth * 2) { 398 halfwidth *= halfheight; 399 halfheight = 1; 400 src_stride_u = src_stride_v = dst_stride_uv = 0; 401 } 402 #if defined(HAS_MERGEUVROW_SSE2) 403 if (TestCpuFlag(kCpuHasSSE2)) { 404 MergeUVRow_ = MergeUVRow_Any_SSE2; 405 if (IS_ALIGNED(halfwidth, 16)) { 406 MergeUVRow_ = MergeUVRow_SSE2; 407 } 408 } 409 #endif 410 #if defined(HAS_MERGEUVROW_AVX2) 411 if (TestCpuFlag(kCpuHasAVX2)) { 412 MergeUVRow_ = MergeUVRow_Any_AVX2; 413 if (IS_ALIGNED(halfwidth, 32)) { 414 MergeUVRow_ = MergeUVRow_AVX2; 415 } 416 } 417 #endif 418 #if defined(HAS_MERGEUVROW_NEON) 419 if (TestCpuFlag(kCpuHasNEON)) { 420 MergeUVRow_ = MergeUVRow_Any_NEON; 421 if (IS_ALIGNED(halfwidth, 16)) { 422 MergeUVRow_ = MergeUVRow_NEON; 423 } 424 } 425 #endif 426 427 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); 428 for (y = 0; y < halfheight; ++y) { 429 // Merge a row of U and V into a row of UV. 430 MergeUVRow_(src_u, src_v, dst_uv, halfwidth); 431 src_u += src_stride_u; 432 src_v += src_stride_v; 433 dst_uv += dst_stride_uv; 434 } 435 return 0; 436 } 437 438 LIBYUV_API 439 int I420ToNV21(const uint8* src_y, int src_stride_y, 440 const uint8* src_u, int src_stride_u, 441 const uint8* src_v, int src_stride_v, 442 uint8* dst_y, int dst_stride_y, 443 uint8* dst_vu, int dst_stride_vu, 444 int width, int height) { 445 return I420ToNV12(src_y, src_stride_y, 446 src_v, src_stride_v, 447 src_u, src_stride_u, 448 dst_y, src_stride_y, 449 dst_vu, dst_stride_vu, 450 width, height); 451 } 452 453 // Convert I420 to ARGB. 454 LIBYUV_API 455 int I420ToARGB(const uint8* src_y, int src_stride_y, 456 const uint8* src_u, int src_stride_u, 457 const uint8* src_v, int src_stride_v, 458 uint8* dst_argb, int dst_stride_argb, 459 int width, int height) { 460 int y; 461 void (*I422ToARGBRow)(const uint8* y_buf, 462 const uint8* u_buf, 463 const uint8* v_buf, 464 uint8* rgb_buf, 465 int width) = I422ToARGBRow_C; 466 if (!src_y || !src_u || !src_v || !dst_argb || 467 width <= 0 || height == 0) { 468 return -1; 469 } 470 // Negative height means invert the image. 471 if (height < 0) { 472 height = -height; 473 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 474 dst_stride_argb = -dst_stride_argb; 475 } 476 #if defined(HAS_I422TOARGBROW_SSSE3) 477 if (TestCpuFlag(kCpuHasSSSE3)) { 478 I422ToARGBRow = I422ToARGBRow_Any_SSSE3; 479 if (IS_ALIGNED(width, 8)) { 480 I422ToARGBRow = I422ToARGBRow_SSSE3; 481 } 482 } 483 #endif 484 #if defined(HAS_I422TOARGBROW_AVX2) 485 if (TestCpuFlag(kCpuHasAVX2)) { 486 I422ToARGBRow = I422ToARGBRow_Any_AVX2; 487 if (IS_ALIGNED(width, 16)) { 488 I422ToARGBRow = I422ToARGBRow_AVX2; 489 } 490 } 491 #endif 492 #if defined(HAS_I422TOARGBROW_NEON) 493 if (TestCpuFlag(kCpuHasNEON)) { 494 I422ToARGBRow = I422ToARGBRow_Any_NEON; 495 if (IS_ALIGNED(width, 8)) { 496 I422ToARGBRow = I422ToARGBRow_NEON; 497 } 498 } 499 #endif 500 #if defined(HAS_I422TOARGBROW_MIPS_DSPR2) 501 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) && 502 IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) && 503 IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) && 504 IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) && 505 IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) { 506 I422ToARGBRow = I422ToARGBRow_MIPS_DSPR2; 507 } 508 #endif 509 510 for (y = 0; y < height; ++y) { 511 I422ToARGBRow(src_y, src_u, src_v, dst_argb, width); 512 dst_argb += dst_stride_argb; 513 src_y += src_stride_y; 514 if (y & 1) { 515 src_u += src_stride_u; 516 src_v += src_stride_v; 517 } 518 } 519 return 0; 520 } 521 522 // Convert I420 to BGRA. 523 LIBYUV_API 524 int I420ToBGRA(const uint8* src_y, int src_stride_y, 525 const uint8* src_u, int src_stride_u, 526 const uint8* src_v, int src_stride_v, 527 uint8* dst_bgra, int dst_stride_bgra, 528 int width, int height) { 529 int y; 530 void (*I422ToBGRARow)(const uint8* y_buf, 531 const uint8* u_buf, 532 const uint8* v_buf, 533 uint8* rgb_buf, 534 int width) = I422ToBGRARow_C; 535 if (!src_y || !src_u || !src_v || !dst_bgra || 536 width <= 0 || height == 0) { 537 return -1; 538 } 539 // Negative height means invert the image. 540 if (height < 0) { 541 height = -height; 542 dst_bgra = dst_bgra + (height - 1) * dst_stride_bgra; 543 dst_stride_bgra = -dst_stride_bgra; 544 } 545 #if defined(HAS_I422TOBGRAROW_SSSE3) 546 if (TestCpuFlag(kCpuHasSSSE3)) { 547 I422ToBGRARow = I422ToBGRARow_Any_SSSE3; 548 if (IS_ALIGNED(width, 8)) { 549 I422ToBGRARow = I422ToBGRARow_SSSE3; 550 } 551 } 552 #endif 553 #if defined(HAS_I422TOBGRAROW_AVX2) 554 if (TestCpuFlag(kCpuHasAVX2)) { 555 I422ToBGRARow = I422ToBGRARow_Any_AVX2; 556 if (IS_ALIGNED(width, 16)) { 557 I422ToBGRARow = I422ToBGRARow_AVX2; 558 } 559 } 560 #endif 561 #if defined(HAS_I422TOBGRAROW_NEON) 562 if (TestCpuFlag(kCpuHasNEON)) { 563 I422ToBGRARow = I422ToBGRARow_Any_NEON; 564 if (IS_ALIGNED(width, 8)) { 565 I422ToBGRARow = I422ToBGRARow_NEON; 566 } 567 } 568 #endif 569 #if defined(HAS_I422TOBGRAROW_MIPS_DSPR2) 570 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) && 571 IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) && 572 IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) && 573 IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) && 574 IS_ALIGNED(dst_bgra, 4) && IS_ALIGNED(dst_stride_bgra, 4)) { 575 I422ToBGRARow = I422ToBGRARow_MIPS_DSPR2; 576 } 577 #endif 578 579 for (y = 0; y < height; ++y) { 580 I422ToBGRARow(src_y, src_u, src_v, dst_bgra, width); 581 dst_bgra += dst_stride_bgra; 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 I420 to ABGR. 592 LIBYUV_API 593 int I420ToABGR(const uint8* src_y, int src_stride_y, 594 const uint8* src_u, int src_stride_u, 595 const uint8* src_v, int src_stride_v, 596 uint8* dst_abgr, int dst_stride_abgr, 597 int width, int height) { 598 int y; 599 void (*I422ToABGRRow)(const uint8* y_buf, 600 const uint8* u_buf, 601 const uint8* v_buf, 602 uint8* rgb_buf, 603 int width) = I422ToABGRRow_C; 604 if (!src_y || !src_u || !src_v || !dst_abgr || 605 width <= 0 || height == 0) { 606 return -1; 607 } 608 // Negative height means invert the image. 609 if (height < 0) { 610 height = -height; 611 dst_abgr = dst_abgr + (height - 1) * dst_stride_abgr; 612 dst_stride_abgr = -dst_stride_abgr; 613 } 614 #if defined(HAS_I422TOABGRROW_SSSE3) 615 if (TestCpuFlag(kCpuHasSSSE3)) { 616 I422ToABGRRow = I422ToABGRRow_Any_SSSE3; 617 if (IS_ALIGNED(width, 8)) { 618 I422ToABGRRow = I422ToABGRRow_SSSE3; 619 } 620 } 621 #endif 622 #if defined(HAS_I422TOABGRROW_AVX2) 623 if (TestCpuFlag(kCpuHasAVX2)) { 624 I422ToABGRRow = I422ToABGRRow_Any_AVX2; 625 if (IS_ALIGNED(width, 16)) { 626 I422ToABGRRow = I422ToABGRRow_AVX2; 627 } 628 } 629 #endif 630 #if defined(HAS_I422TOABGRROW_NEON) 631 if (TestCpuFlag(kCpuHasNEON)) { 632 I422ToABGRRow = I422ToABGRRow_Any_NEON; 633 if (IS_ALIGNED(width, 8)) { 634 I422ToABGRRow = I422ToABGRRow_NEON; 635 } 636 } 637 #endif 638 639 for (y = 0; y < height; ++y) { 640 I422ToABGRRow(src_y, src_u, src_v, dst_abgr, width); 641 dst_abgr += dst_stride_abgr; 642 src_y += src_stride_y; 643 if (y & 1) { 644 src_u += src_stride_u; 645 src_v += src_stride_v; 646 } 647 } 648 return 0; 649 } 650 651 // Convert I420 to RGBA. 652 LIBYUV_API 653 int I420ToRGBA(const uint8* src_y, int src_stride_y, 654 const uint8* src_u, int src_stride_u, 655 const uint8* src_v, int src_stride_v, 656 uint8* dst_rgba, int dst_stride_rgba, 657 int width, int height) { 658 int y; 659 void (*I422ToRGBARow)(const uint8* y_buf, 660 const uint8* u_buf, 661 const uint8* v_buf, 662 uint8* rgb_buf, 663 int width) = I422ToRGBARow_C; 664 if (!src_y || !src_u || !src_v || !dst_rgba || 665 width <= 0 || height == 0) { 666 return -1; 667 } 668 // Negative height means invert the image. 669 if (height < 0) { 670 height = -height; 671 dst_rgba = dst_rgba + (height - 1) * dst_stride_rgba; 672 dst_stride_rgba = -dst_stride_rgba; 673 } 674 #if defined(HAS_I422TORGBAROW_SSSE3) 675 if (TestCpuFlag(kCpuHasSSSE3)) { 676 I422ToRGBARow = I422ToRGBARow_Any_SSSE3; 677 if (IS_ALIGNED(width, 8)) { 678 I422ToRGBARow = I422ToRGBARow_SSSE3; 679 } 680 } 681 #endif 682 #if defined(HAS_I422TORGBAROW_AVX2) 683 if (TestCpuFlag(kCpuHasAVX2)) { 684 I422ToRGBARow = I422ToRGBARow_Any_AVX2; 685 if (IS_ALIGNED(width, 16)) { 686 I422ToRGBARow = I422ToRGBARow_AVX2; 687 } 688 } 689 #endif 690 #if defined(HAS_I422TORGBAROW_NEON) 691 if (TestCpuFlag(kCpuHasNEON)) { 692 I422ToRGBARow = I422ToRGBARow_Any_NEON; 693 if (IS_ALIGNED(width, 8)) { 694 I422ToRGBARow = I422ToRGBARow_NEON; 695 } 696 } 697 #endif 698 699 for (y = 0; y < height; ++y) { 700 I422ToRGBARow(src_y, src_u, src_v, dst_rgba, width); 701 dst_rgba += dst_stride_rgba; 702 src_y += src_stride_y; 703 if (y & 1) { 704 src_u += src_stride_u; 705 src_v += src_stride_v; 706 } 707 } 708 return 0; 709 } 710 711 // Convert I420 to RGB24. 712 LIBYUV_API 713 int I420ToRGB24(const uint8* src_y, int src_stride_y, 714 const uint8* src_u, int src_stride_u, 715 const uint8* src_v, int src_stride_v, 716 uint8* dst_rgb24, int dst_stride_rgb24, 717 int width, int height) { 718 int y; 719 void (*I422ToRGB24Row)(const uint8* y_buf, 720 const uint8* u_buf, 721 const uint8* v_buf, 722 uint8* rgb_buf, 723 int width) = I422ToRGB24Row_C; 724 if (!src_y || !src_u || !src_v || !dst_rgb24 || 725 width <= 0 || height == 0) { 726 return -1; 727 } 728 // Negative height means invert the image. 729 if (height < 0) { 730 height = -height; 731 dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24; 732 dst_stride_rgb24 = -dst_stride_rgb24; 733 } 734 #if defined(HAS_I422TORGB24ROW_SSSE3) 735 if (TestCpuFlag(kCpuHasSSSE3)) { 736 I422ToRGB24Row = I422ToRGB24Row_Any_SSSE3; 737 if (IS_ALIGNED(width, 8)) { 738 I422ToRGB24Row = I422ToRGB24Row_SSSE3; 739 } 740 } 741 #endif 742 #if defined(HAS_I422TORGB24ROW_AVX2) 743 if (TestCpuFlag(kCpuHasAVX2)) { 744 I422ToRGB24Row = I422ToRGB24Row_Any_AVX2; 745 if (IS_ALIGNED(width, 16)) { 746 I422ToRGB24Row = I422ToRGB24Row_AVX2; 747 } 748 } 749 #endif 750 #if defined(HAS_I422TORGB24ROW_NEON) 751 if (TestCpuFlag(kCpuHasNEON)) { 752 I422ToRGB24Row = I422ToRGB24Row_Any_NEON; 753 if (IS_ALIGNED(width, 8)) { 754 I422ToRGB24Row = I422ToRGB24Row_NEON; 755 } 756 } 757 #endif 758 759 for (y = 0; y < height; ++y) { 760 I422ToRGB24Row(src_y, src_u, src_v, dst_rgb24, width); 761 dst_rgb24 += dst_stride_rgb24; 762 src_y += src_stride_y; 763 if (y & 1) { 764 src_u += src_stride_u; 765 src_v += src_stride_v; 766 } 767 } 768 return 0; 769 } 770 771 // Convert I420 to RAW. 772 LIBYUV_API 773 int I420ToRAW(const uint8* src_y, int src_stride_y, 774 const uint8* src_u, int src_stride_u, 775 const uint8* src_v, int src_stride_v, 776 uint8* dst_raw, int dst_stride_raw, 777 int width, int height) { 778 int y; 779 void (*I422ToRAWRow)(const uint8* y_buf, 780 const uint8* u_buf, 781 const uint8* v_buf, 782 uint8* rgb_buf, 783 int width) = I422ToRAWRow_C; 784 if (!src_y || !src_u || !src_v || !dst_raw || 785 width <= 0 || height == 0) { 786 return -1; 787 } 788 // Negative height means invert the image. 789 if (height < 0) { 790 height = -height; 791 dst_raw = dst_raw + (height - 1) * dst_stride_raw; 792 dst_stride_raw = -dst_stride_raw; 793 } 794 #if defined(HAS_I422TORAWROW_SSSE3) 795 if (TestCpuFlag(kCpuHasSSSE3)) { 796 I422ToRAWRow = I422ToRAWRow_Any_SSSE3; 797 if (IS_ALIGNED(width, 8)) { 798 I422ToRAWRow = I422ToRAWRow_SSSE3; 799 } 800 } 801 #endif 802 #if defined(HAS_I422TORAWROW_AVX2) 803 if (TestCpuFlag(kCpuHasAVX2)) { 804 I422ToRAWRow = I422ToRAWRow_Any_AVX2; 805 if (IS_ALIGNED(width, 16)) { 806 I422ToRAWRow = I422ToRAWRow_AVX2; 807 } 808 } 809 #endif 810 #if defined(HAS_I422TORAWROW_NEON) 811 if (TestCpuFlag(kCpuHasNEON)) { 812 I422ToRAWRow = I422ToRAWRow_Any_NEON; 813 if (IS_ALIGNED(width, 8)) { 814 I422ToRAWRow = I422ToRAWRow_NEON; 815 } 816 } 817 #endif 818 819 for (y = 0; y < height; ++y) { 820 I422ToRAWRow(src_y, src_u, src_v, dst_raw, width); 821 dst_raw += dst_stride_raw; 822 src_y += src_stride_y; 823 if (y & 1) { 824 src_u += src_stride_u; 825 src_v += src_stride_v; 826 } 827 } 828 return 0; 829 } 830 831 // Convert I420 to ARGB1555. 832 LIBYUV_API 833 int I420ToARGB1555(const uint8* src_y, int src_stride_y, 834 const uint8* src_u, int src_stride_u, 835 const uint8* src_v, int src_stride_v, 836 uint8* dst_argb1555, int dst_stride_argb1555, 837 int width, int height) { 838 int y; 839 void (*I422ToARGB1555Row)(const uint8* y_buf, 840 const uint8* u_buf, 841 const uint8* v_buf, 842 uint8* rgb_buf, 843 int width) = I422ToARGB1555Row_C; 844 if (!src_y || !src_u || !src_v || !dst_argb1555 || 845 width <= 0 || height == 0) { 846 return -1; 847 } 848 // Negative height means invert the image. 849 if (height < 0) { 850 height = -height; 851 dst_argb1555 = dst_argb1555 + (height - 1) * dst_stride_argb1555; 852 dst_stride_argb1555 = -dst_stride_argb1555; 853 } 854 #if defined(HAS_I422TOARGB1555ROW_SSSE3) 855 if (TestCpuFlag(kCpuHasSSSE3)) { 856 I422ToARGB1555Row = I422ToARGB1555Row_Any_SSSE3; 857 if (IS_ALIGNED(width, 8)) { 858 I422ToARGB1555Row = I422ToARGB1555Row_SSSE3; 859 } 860 } 861 #endif 862 #if defined(HAS_I422TOARGB1555ROW_AVX2) 863 if (TestCpuFlag(kCpuHasAVX2)) { 864 I422ToARGB1555Row = I422ToARGB1555Row_Any_AVX2; 865 if (IS_ALIGNED(width, 16)) { 866 I422ToARGB1555Row = I422ToARGB1555Row_AVX2; 867 } 868 } 869 #endif 870 #if defined(HAS_I422TOARGB1555ROW_NEON) 871 if (TestCpuFlag(kCpuHasNEON)) { 872 I422ToARGB1555Row = I422ToARGB1555Row_Any_NEON; 873 if (IS_ALIGNED(width, 8)) { 874 I422ToARGB1555Row = I422ToARGB1555Row_NEON; 875 } 876 } 877 #endif 878 879 for (y = 0; y < height; ++y) { 880 I422ToARGB1555Row(src_y, src_u, src_v, dst_argb1555, width); 881 dst_argb1555 += dst_stride_argb1555; 882 src_y += src_stride_y; 883 if (y & 1) { 884 src_u += src_stride_u; 885 src_v += src_stride_v; 886 } 887 } 888 return 0; 889 } 890 891 892 // Convert I420 to ARGB4444. 893 LIBYUV_API 894 int I420ToARGB4444(const uint8* src_y, int src_stride_y, 895 const uint8* src_u, int src_stride_u, 896 const uint8* src_v, int src_stride_v, 897 uint8* dst_argb4444, int dst_stride_argb4444, 898 int width, int height) { 899 int y; 900 void (*I422ToARGB4444Row)(const uint8* y_buf, 901 const uint8* u_buf, 902 const uint8* v_buf, 903 uint8* rgb_buf, 904 int width) = I422ToARGB4444Row_C; 905 if (!src_y || !src_u || !src_v || !dst_argb4444 || 906 width <= 0 || height == 0) { 907 return -1; 908 } 909 // Negative height means invert the image. 910 if (height < 0) { 911 height = -height; 912 dst_argb4444 = dst_argb4444 + (height - 1) * dst_stride_argb4444; 913 dst_stride_argb4444 = -dst_stride_argb4444; 914 } 915 #if defined(HAS_I422TOARGB4444ROW_SSSE3) 916 if (TestCpuFlag(kCpuHasSSSE3)) { 917 I422ToARGB4444Row = I422ToARGB4444Row_Any_SSSE3; 918 if (IS_ALIGNED(width, 8)) { 919 I422ToARGB4444Row = I422ToARGB4444Row_SSSE3; 920 } 921 } 922 #endif 923 #if defined(HAS_I422TOARGB4444ROW_AVX2) 924 if (TestCpuFlag(kCpuHasAVX2)) { 925 I422ToARGB4444Row = I422ToARGB4444Row_Any_AVX2; 926 if (IS_ALIGNED(width, 16)) { 927 I422ToARGB4444Row = I422ToARGB4444Row_AVX2; 928 } 929 } 930 #endif 931 #if defined(HAS_I422TOARGB4444ROW_NEON) 932 if (TestCpuFlag(kCpuHasNEON)) { 933 I422ToARGB4444Row = I422ToARGB4444Row_Any_NEON; 934 if (IS_ALIGNED(width, 8)) { 935 I422ToARGB4444Row = I422ToARGB4444Row_NEON; 936 } 937 } 938 #endif 939 940 for (y = 0; y < height; ++y) { 941 I422ToARGB4444Row(src_y, src_u, src_v, dst_argb4444, width); 942 dst_argb4444 += dst_stride_argb4444; 943 src_y += src_stride_y; 944 if (y & 1) { 945 src_u += src_stride_u; 946 src_v += src_stride_v; 947 } 948 } 949 return 0; 950 } 951 952 // Convert I420 to RGB565. 953 LIBYUV_API 954 int I420ToRGB565(const uint8* src_y, int src_stride_y, 955 const uint8* src_u, int src_stride_u, 956 const uint8* src_v, int src_stride_v, 957 uint8* dst_rgb565, int dst_stride_rgb565, 958 int width, int height) { 959 int y; 960 void (*I422ToRGB565Row)(const uint8* y_buf, 961 const uint8* u_buf, 962 const uint8* v_buf, 963 uint8* rgb_buf, 964 int width) = I422ToRGB565Row_C; 965 if (!src_y || !src_u || !src_v || !dst_rgb565 || 966 width <= 0 || height == 0) { 967 return -1; 968 } 969 // Negative height means invert the image. 970 if (height < 0) { 971 height = -height; 972 dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565; 973 dst_stride_rgb565 = -dst_stride_rgb565; 974 } 975 #if defined(HAS_I422TORGB565ROW_SSSE3) 976 if (TestCpuFlag(kCpuHasSSSE3)) { 977 I422ToRGB565Row = I422ToRGB565Row_Any_SSSE3; 978 if (IS_ALIGNED(width, 8)) { 979 I422ToRGB565Row = I422ToRGB565Row_SSSE3; 980 } 981 } 982 #endif 983 #if defined(HAS_I422TORGB565ROW_AVX2) 984 if (TestCpuFlag(kCpuHasAVX2)) { 985 I422ToRGB565Row = I422ToRGB565Row_Any_AVX2; 986 if (IS_ALIGNED(width, 16)) { 987 I422ToRGB565Row = I422ToRGB565Row_AVX2; 988 } 989 } 990 #endif 991 #if defined(HAS_I422TORGB565ROW_NEON) 992 if (TestCpuFlag(kCpuHasNEON)) { 993 I422ToRGB565Row = I422ToRGB565Row_Any_NEON; 994 if (IS_ALIGNED(width, 8)) { 995 I422ToRGB565Row = I422ToRGB565Row_NEON; 996 } 997 } 998 #endif 999 1000 for (y = 0; y < height; ++y) { 1001 I422ToRGB565Row(src_y, src_u, src_v, dst_rgb565, width); 1002 dst_rgb565 += dst_stride_rgb565; 1003 src_y += src_stride_y; 1004 if (y & 1) { 1005 src_u += src_stride_u; 1006 src_v += src_stride_v; 1007 } 1008 } 1009 return 0; 1010 } 1011 1012 // Ordered 8x8 dither for 888 to 565. Values from 0 to 7. 1013 static const uint8 kDither565_4x4[16] = { 1014 0, 4, 1, 5, 1015 6, 2, 7, 3, 1016 1, 5, 0, 4, 1017 7, 3, 6, 2, 1018 }; 1019 1020 // Convert I420 to RGB565 with dithering. 1021 LIBYUV_API 1022 int I420ToRGB565Dither(const uint8* src_y, int src_stride_y, 1023 const uint8* src_u, int src_stride_u, 1024 const uint8* src_v, int src_stride_v, 1025 uint8* dst_rgb565, int dst_stride_rgb565, 1026 const uint8* dither4x4, int width, int height) { 1027 int y; 1028 void (*I422ToARGBRow)(const uint8* y_buf, 1029 const uint8* u_buf, 1030 const uint8* v_buf, 1031 uint8* rgb_buf, 1032 int width) = I422ToARGBRow_C; 1033 void (*ARGBToRGB565DitherRow)(const uint8* src_argb, uint8* dst_rgb, 1034 const uint32 dither4, int pix) = ARGBToRGB565DitherRow_C; 1035 if (!src_y || !src_u || !src_v || !dst_rgb565 || 1036 width <= 0 || height == 0) { 1037 return -1; 1038 } 1039 // Negative height means invert the image. 1040 if (height < 0) { 1041 height = -height; 1042 dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565; 1043 dst_stride_rgb565 = -dst_stride_rgb565; 1044 } 1045 if (!dither4x4) { 1046 dither4x4 = kDither565_4x4; 1047 } 1048 #if defined(HAS_I422TOARGBROW_SSSE3) 1049 if (TestCpuFlag(kCpuHasSSSE3)) { 1050 I422ToARGBRow = I422ToARGBRow_Any_SSSE3; 1051 if (IS_ALIGNED(width, 8)) { 1052 I422ToARGBRow = I422ToARGBRow_SSSE3; 1053 } 1054 } 1055 #endif 1056 #if defined(HAS_I422TOARGBROW_AVX2) 1057 if (TestCpuFlag(kCpuHasAVX2)) { 1058 I422ToARGBRow = I422ToARGBRow_Any_AVX2; 1059 if (IS_ALIGNED(width, 16)) { 1060 I422ToARGBRow = I422ToARGBRow_AVX2; 1061 } 1062 } 1063 #endif 1064 #if defined(HAS_I422TOARGBROW_NEON) 1065 if (TestCpuFlag(kCpuHasNEON)) { 1066 I422ToARGBRow = I422ToARGBRow_Any_NEON; 1067 if (IS_ALIGNED(width, 8)) { 1068 I422ToARGBRow = I422ToARGBRow_NEON; 1069 } 1070 } 1071 #endif 1072 #if defined(HAS_I422TOARGBROW_MIPS_DSPR2) 1073 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) && 1074 IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) && 1075 IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) && 1076 IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2)) { 1077 I422ToARGBRow = I422ToARGBRow_MIPS_DSPR2; 1078 } 1079 #endif 1080 #if defined(HAS_ARGBTORGB565DITHERROW_SSE2) 1081 if (TestCpuFlag(kCpuHasSSE2)) { 1082 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_SSE2; 1083 if (IS_ALIGNED(width, 4)) { 1084 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_SSE2; 1085 } 1086 } 1087 #endif 1088 #if defined(HAS_ARGBTORGB565DITHERROW_AVX2) 1089 if (TestCpuFlag(kCpuHasAVX2)) { 1090 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_AVX2; 1091 if (IS_ALIGNED(width, 8)) { 1092 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_AVX2; 1093 } 1094 } 1095 #endif 1096 #if defined(HAS_ARGBTORGB565DITHERROW_NEON) 1097 if (TestCpuFlag(kCpuHasNEON)) { 1098 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_NEON; 1099 if (IS_ALIGNED(width, 8)) { 1100 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_NEON; 1101 } 1102 } 1103 #endif 1104 { 1105 // Allocate a row of argb. 1106 align_buffer_64(row_argb, width * 4); 1107 for (y = 0; y < height; ++y) { 1108 I422ToARGBRow(src_y, src_u, src_v, row_argb, width); 1109 ARGBToRGB565DitherRow(row_argb, dst_rgb565, 1110 *(uint32*)(dither4x4 + ((y & 3) << 2)), width); 1111 dst_rgb565 += dst_stride_rgb565; 1112 src_y += src_stride_y; 1113 if (y & 1) { 1114 src_u += src_stride_u; 1115 src_v += src_stride_v; 1116 } 1117 } 1118 free_aligned_buffer_64(row_argb); 1119 } 1120 return 0; 1121 } 1122 1123 // Convert I420 to specified format 1124 LIBYUV_API 1125 int ConvertFromI420(const uint8* y, int y_stride, 1126 const uint8* u, int u_stride, 1127 const uint8* v, int v_stride, 1128 uint8* dst_sample, int dst_sample_stride, 1129 int width, int height, 1130 uint32 fourcc) { 1131 uint32 format = CanonicalFourCC(fourcc); 1132 int r = 0; 1133 if (!y || !u|| !v || !dst_sample || 1134 width <= 0 || height == 0) { 1135 return -1; 1136 } 1137 switch (format) { 1138 // Single plane formats 1139 case FOURCC_YUY2: 1140 r = I420ToYUY2(y, y_stride, 1141 u, u_stride, 1142 v, v_stride, 1143 dst_sample, 1144 dst_sample_stride ? dst_sample_stride : width * 2, 1145 width, height); 1146 break; 1147 case FOURCC_UYVY: 1148 r = I420ToUYVY(y, y_stride, 1149 u, u_stride, 1150 v, v_stride, 1151 dst_sample, 1152 dst_sample_stride ? dst_sample_stride : width * 2, 1153 width, height); 1154 break; 1155 case FOURCC_RGBP: 1156 r = I420ToRGB565(y, y_stride, 1157 u, u_stride, 1158 v, v_stride, 1159 dst_sample, 1160 dst_sample_stride ? dst_sample_stride : width * 2, 1161 width, height); 1162 break; 1163 case FOURCC_RGBO: 1164 r = I420ToARGB1555(y, y_stride, 1165 u, u_stride, 1166 v, v_stride, 1167 dst_sample, 1168 dst_sample_stride ? dst_sample_stride : width * 2, 1169 width, height); 1170 break; 1171 case FOURCC_R444: 1172 r = I420ToARGB4444(y, y_stride, 1173 u, u_stride, 1174 v, v_stride, 1175 dst_sample, 1176 dst_sample_stride ? dst_sample_stride : width * 2, 1177 width, height); 1178 break; 1179 case FOURCC_24BG: 1180 r = I420ToRGB24(y, y_stride, 1181 u, u_stride, 1182 v, v_stride, 1183 dst_sample, 1184 dst_sample_stride ? dst_sample_stride : width * 3, 1185 width, height); 1186 break; 1187 case FOURCC_RAW: 1188 r = I420ToRAW(y, y_stride, 1189 u, u_stride, 1190 v, v_stride, 1191 dst_sample, 1192 dst_sample_stride ? dst_sample_stride : width * 3, 1193 width, height); 1194 break; 1195 case FOURCC_ARGB: 1196 r = I420ToARGB(y, y_stride, 1197 u, u_stride, 1198 v, v_stride, 1199 dst_sample, 1200 dst_sample_stride ? dst_sample_stride : width * 4, 1201 width, height); 1202 break; 1203 case FOURCC_BGRA: 1204 r = I420ToBGRA(y, y_stride, 1205 u, u_stride, 1206 v, v_stride, 1207 dst_sample, 1208 dst_sample_stride ? dst_sample_stride : width * 4, 1209 width, height); 1210 break; 1211 case FOURCC_ABGR: 1212 r = I420ToABGR(y, y_stride, 1213 u, u_stride, 1214 v, v_stride, 1215 dst_sample, 1216 dst_sample_stride ? dst_sample_stride : width * 4, 1217 width, height); 1218 break; 1219 case FOURCC_RGBA: 1220 r = I420ToRGBA(y, y_stride, 1221 u, u_stride, 1222 v, v_stride, 1223 dst_sample, 1224 dst_sample_stride ? dst_sample_stride : width * 4, 1225 width, height); 1226 break; 1227 case FOURCC_I400: 1228 r = I400Copy(y, y_stride, 1229 dst_sample, 1230 dst_sample_stride ? dst_sample_stride : width, 1231 width, height); 1232 break; 1233 case FOURCC_NV12: { 1234 uint8* dst_uv = dst_sample + width * height; 1235 r = I420ToNV12(y, y_stride, 1236 u, u_stride, 1237 v, v_stride, 1238 dst_sample, 1239 dst_sample_stride ? dst_sample_stride : width, 1240 dst_uv, 1241 dst_sample_stride ? dst_sample_stride : width, 1242 width, height); 1243 break; 1244 } 1245 case FOURCC_NV21: { 1246 uint8* dst_vu = dst_sample + width * height; 1247 r = I420ToNV21(y, y_stride, 1248 u, u_stride, 1249 v, v_stride, 1250 dst_sample, 1251 dst_sample_stride ? dst_sample_stride : width, 1252 dst_vu, 1253 dst_sample_stride ? dst_sample_stride : width, 1254 width, height); 1255 break; 1256 } 1257 // TODO(fbarchard): Add M420. 1258 // Triplanar formats 1259 // TODO(fbarchard): halfstride instead of halfwidth 1260 case FOURCC_I420: 1261 case FOURCC_YU12: 1262 case FOURCC_YV12: { 1263 int halfwidth = (width + 1) / 2; 1264 int halfheight = (height + 1) / 2; 1265 uint8* dst_u; 1266 uint8* dst_v; 1267 if (format == FOURCC_YV12) { 1268 dst_v = dst_sample + width * height; 1269 dst_u = dst_v + halfwidth * halfheight; 1270 } else { 1271 dst_u = dst_sample + width * height; 1272 dst_v = dst_u + halfwidth * halfheight; 1273 } 1274 r = I420Copy(y, y_stride, 1275 u, u_stride, 1276 v, v_stride, 1277 dst_sample, width, 1278 dst_u, halfwidth, 1279 dst_v, halfwidth, 1280 width, height); 1281 break; 1282 } 1283 case FOURCC_I422: 1284 case FOURCC_YV16: { 1285 int halfwidth = (width + 1) / 2; 1286 uint8* dst_u; 1287 uint8* dst_v; 1288 if (format == FOURCC_YV16) { 1289 dst_v = dst_sample + width * height; 1290 dst_u = dst_v + halfwidth * height; 1291 } else { 1292 dst_u = dst_sample + width * height; 1293 dst_v = dst_u + halfwidth * height; 1294 } 1295 r = I420ToI422(y, y_stride, 1296 u, u_stride, 1297 v, v_stride, 1298 dst_sample, width, 1299 dst_u, halfwidth, 1300 dst_v, halfwidth, 1301 width, height); 1302 break; 1303 } 1304 case FOURCC_I444: 1305 case FOURCC_YV24: { 1306 uint8* dst_u; 1307 uint8* dst_v; 1308 if (format == FOURCC_YV24) { 1309 dst_v = dst_sample + width * height; 1310 dst_u = dst_v + width * height; 1311 } else { 1312 dst_u = dst_sample + width * height; 1313 dst_v = dst_u + width * height; 1314 } 1315 r = I420ToI444(y, y_stride, 1316 u, u_stride, 1317 v, v_stride, 1318 dst_sample, width, 1319 dst_u, width, 1320 dst_v, width, 1321 width, height); 1322 break; 1323 } 1324 case FOURCC_I411: { 1325 int quarterwidth = (width + 3) / 4; 1326 uint8* dst_u = dst_sample + width * height; 1327 uint8* dst_v = dst_u + quarterwidth * height; 1328 r = I420ToI411(y, y_stride, 1329 u, u_stride, 1330 v, v_stride, 1331 dst_sample, width, 1332 dst_u, quarterwidth, 1333 dst_v, quarterwidth, 1334 width, height); 1335 break; 1336 } 1337 1338 // Formats not supported - MJPG, biplanar, some rgb formats. 1339 default: 1340 return -1; // unknown fourcc - return failure code. 1341 } 1342 return r; 1343 } 1344 1345 #ifdef __cplusplus 1346 } // extern "C" 1347 } // namespace libyuv 1348 #endif 1349