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