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/format_conversion.h" 17 #include "libyuv/planar_functions.h" 18 #include "libyuv/rotate.h" 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 LIBYUV_API 28 int I420ToI422(const uint8* src_y, int src_stride_y, 29 const uint8* src_u, int src_stride_u, 30 const uint8* src_v, int src_stride_v, 31 uint8* dst_y, int dst_stride_y, 32 uint8* dst_u, int dst_stride_u, 33 uint8* dst_v, int dst_stride_v, 34 int width, int height) { 35 if (!src_y || !src_u || !src_v || 36 !dst_y || !dst_u || !dst_v || 37 width <= 0 || height == 0) { 38 return -1; 39 } 40 // Negative height means invert the image. 41 if (height < 0) { 42 height = -height; 43 dst_y = dst_y + (height - 1) * dst_stride_y; 44 dst_u = dst_u + (height - 1) * dst_stride_u; 45 dst_v = dst_v + (height - 1) * dst_stride_v; 46 dst_stride_y = -dst_stride_y; 47 dst_stride_u = -dst_stride_u; 48 dst_stride_v = -dst_stride_v; 49 } 50 int halfwidth = (width + 1) >> 1; 51 void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C; 52 #if defined(HAS_COPYROW_NEON) 53 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(halfwidth, 64)) { 54 CopyRow = CopyRow_NEON; 55 } 56 #elif defined(HAS_COPYROW_X86) 57 if (IS_ALIGNED(halfwidth, 4)) { 58 CopyRow = CopyRow_X86; 59 #if defined(HAS_COPYROW_SSE2) 60 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(halfwidth, 32) && 61 IS_ALIGNED(src_u, 16) && IS_ALIGNED(src_stride_u, 16) && 62 IS_ALIGNED(src_v, 16) && IS_ALIGNED(src_stride_v, 16) && 63 IS_ALIGNED(dst_u, 16) && IS_ALIGNED(dst_stride_u, 16) && 64 IS_ALIGNED(dst_v, 16) && IS_ALIGNED(dst_stride_v, 16)) { 65 CopyRow = CopyRow_SSE2; 66 } 67 #endif 68 } 69 #endif 70 71 // Copy Y plane 72 if (dst_y) { 73 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); 74 } 75 76 // UpSample U plane. 77 int y; 78 for (y = 0; y < height - 1; y += 2) { 79 CopyRow(src_u, dst_u, halfwidth); 80 CopyRow(src_u, dst_u + dst_stride_u, halfwidth); 81 src_u += src_stride_u; 82 dst_u += dst_stride_u * 2; 83 } 84 if (height & 1) { 85 CopyRow(src_u, dst_u, halfwidth); 86 } 87 88 // UpSample V plane. 89 for (y = 0; y < height - 1; y += 2) { 90 CopyRow(src_v, dst_v, halfwidth); 91 CopyRow(src_v, dst_v + dst_stride_v, halfwidth); 92 src_v += src_stride_v; 93 dst_v += dst_stride_v * 2; 94 } 95 if (height & 1) { 96 CopyRow(src_v, dst_v, halfwidth); 97 } 98 return 0; 99 } 100 101 // use Bilinear for upsampling chroma 102 void ScalePlaneBilinear(int src_width, int src_height, 103 int dst_width, int dst_height, 104 int src_stride, int dst_stride, 105 const uint8* src_ptr, uint8* dst_ptr); 106 107 LIBYUV_API 108 int I420ToI444(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 if (!src_y || !src_u|| !src_v || 116 !dst_y || !dst_u || !dst_v || 117 width <= 0 || height == 0) { 118 return -1; 119 } 120 // Negative height means invert the image. 121 if (height < 0) { 122 height = -height; 123 dst_y = dst_y + (height - 1) * dst_stride_y; 124 dst_u = dst_u + (height - 1) * dst_stride_u; 125 dst_v = dst_v + (height - 1) * dst_stride_v; 126 dst_stride_y = -dst_stride_y; 127 dst_stride_u = -dst_stride_u; 128 dst_stride_v = -dst_stride_v; 129 } 130 131 // Copy Y plane 132 if (dst_y) { 133 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); 134 } 135 136 int halfwidth = (width + 1) >> 1; 137 int halfheight = (height + 1) >> 1; 138 139 // Upsample U plane. 140 ScalePlaneBilinear(halfwidth, halfheight, 141 width, height, 142 src_stride_u, 143 dst_stride_u, 144 src_u, dst_u); 145 146 // Upsample V plane. 147 ScalePlaneBilinear(halfwidth, halfheight, 148 width, height, 149 src_stride_v, 150 dst_stride_v, 151 src_v, dst_v); 152 return 0; 153 } 154 155 // 420 chroma is 1/2 width, 1/2 height 156 // 411 chroma is 1/4 width, 1x height 157 LIBYUV_API 158 int I420ToI411(const uint8* src_y, int src_stride_y, 159 const uint8* src_u, int src_stride_u, 160 const uint8* src_v, int src_stride_v, 161 uint8* dst_y, int dst_stride_y, 162 uint8* dst_u, int dst_stride_u, 163 uint8* dst_v, int dst_stride_v, 164 int width, int height) { 165 if (!src_y || !src_u || !src_v || 166 !dst_y || !dst_u || !dst_v || 167 width <= 0 || height == 0) { 168 return -1; 169 } 170 // Negative height means invert the image. 171 if (height < 0) { 172 height = -height; 173 dst_y = dst_y + (height - 1) * dst_stride_y; 174 dst_u = dst_u + (height - 1) * dst_stride_u; 175 dst_v = dst_v + (height - 1) * dst_stride_v; 176 dst_stride_y = -dst_stride_y; 177 dst_stride_u = -dst_stride_u; 178 dst_stride_v = -dst_stride_v; 179 } 180 181 // Copy Y plane 182 if (dst_y) { 183 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); 184 } 185 186 int halfwidth = (width + 1) >> 1; 187 int halfheight = (height + 1) >> 1; 188 int quarterwidth = (width + 3) >> 2; 189 190 // Resample U plane. 191 ScalePlaneBilinear(halfwidth, halfheight, // from 1/2 width, 1/2 height 192 quarterwidth, height, // to 1/4 width, 1x height 193 src_stride_u, 194 dst_stride_u, 195 src_u, dst_u); 196 197 // Resample V plane. 198 ScalePlaneBilinear(halfwidth, halfheight, // from 1/2 width, 1/2 height 199 quarterwidth, height, // to 1/4 width, 1x height 200 src_stride_v, 201 dst_stride_v, 202 src_v, dst_v); 203 return 0; 204 } 205 206 // Copy to I400. Source can be I420,422,444,400,NV12,NV21 207 LIBYUV_API 208 int I400Copy(const uint8* src_y, int src_stride_y, 209 uint8* dst_y, int dst_stride_y, 210 int width, int height) { 211 if (!src_y || !dst_y || 212 width <= 0 || height == 0) { 213 return -1; 214 } 215 // Negative height means invert the image. 216 if (height < 0) { 217 height = -height; 218 src_y = src_y + (height - 1) * src_stride_y; 219 src_stride_y = -src_stride_y; 220 } 221 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); 222 return 0; 223 } 224 225 // YUY2 - Macro-pixel = 2 image pixels 226 // Y0U0Y1V0....Y2U2Y3V2...Y4U4Y5V4.... 227 228 // UYVY - Macro-pixel = 2 image pixels 229 // U0Y0V0Y1 230 231 #if !defined(YUV_DISABLE_ASM) && defined(_M_IX86) 232 #define HAS_I42XTOYUY2ROW_SSE2 233 __declspec(naked) __declspec(align(16)) 234 static void I42xToYUY2Row_SSE2(const uint8* src_y, 235 const uint8* src_u, 236 const uint8* src_v, 237 uint8* dst_frame, int width) { 238 __asm { 239 push esi 240 push edi 241 mov eax, [esp + 8 + 4] // src_y 242 mov esi, [esp + 8 + 8] // src_u 243 mov edx, [esp + 8 + 12] // src_v 244 mov edi, [esp + 8 + 16] // dst_frame 245 mov ecx, [esp + 8 + 20] // width 246 sub edx, esi 247 248 align 16 249 convertloop: 250 movq xmm2, qword ptr [esi] // U 251 movq xmm3, qword ptr [esi + edx] // V 252 lea esi, [esi + 8] 253 punpcklbw xmm2, xmm3 // UV 254 movdqa xmm0, [eax] // Y 255 lea eax, [eax + 16] 256 movdqa xmm1, xmm0 257 punpcklbw xmm0, xmm2 // YUYV 258 punpckhbw xmm1, xmm2 259 movdqa [edi], xmm0 260 movdqa [edi + 16], xmm1 261 lea edi, [edi + 32] 262 sub ecx, 16 263 jg convertloop 264 265 pop edi 266 pop esi 267 ret 268 } 269 } 270 271 #define HAS_I42XTOUYVYROW_SSE2 272 __declspec(naked) __declspec(align(16)) 273 static void I42xToUYVYRow_SSE2(const uint8* src_y, 274 const uint8* src_u, 275 const uint8* src_v, 276 uint8* dst_frame, int width) { 277 __asm { 278 push esi 279 push edi 280 mov eax, [esp + 8 + 4] // src_y 281 mov esi, [esp + 8 + 8] // src_u 282 mov edx, [esp + 8 + 12] // src_v 283 mov edi, [esp + 8 + 16] // dst_frame 284 mov ecx, [esp + 8 + 20] // width 285 sub edx, esi 286 287 align 16 288 convertloop: 289 movq xmm2, qword ptr [esi] // U 290 movq xmm3, qword ptr [esi + edx] // V 291 lea esi, [esi + 8] 292 punpcklbw xmm2, xmm3 // UV 293 movdqa xmm0, [eax] // Y 294 movdqa xmm1, xmm2 295 lea eax, [eax + 16] 296 punpcklbw xmm1, xmm0 // UYVY 297 punpckhbw xmm2, xmm0 298 movdqa [edi], xmm1 299 movdqa [edi + 16], xmm2 300 lea edi, [edi + 32] 301 sub ecx, 16 302 jg convertloop 303 304 pop edi 305 pop esi 306 ret 307 } 308 } 309 #elif !defined(YUV_DISABLE_ASM) && (defined(__x86_64__) || defined(__i386__)) 310 #define HAS_I42XTOYUY2ROW_SSE2 311 static void I42xToYUY2Row_SSE2(const uint8* src_y, 312 const uint8* src_u, 313 const uint8* src_v, 314 uint8* dst_frame, int width) { 315 asm volatile ( 316 "sub %1,%2 \n" 317 ".p2align 4 \n" 318 "1: \n" 319 "movq (%1),%%xmm2 \n" 320 "movq (%1,%2,1),%%xmm3 \n" 321 "lea 0x8(%1),%1 \n" 322 "punpcklbw %%xmm3,%%xmm2 \n" 323 "movdqa (%0),%%xmm0 \n" 324 "lea 0x10(%0),%0 \n" 325 "movdqa %%xmm0,%%xmm1 \n" 326 "punpcklbw %%xmm2,%%xmm0 \n" 327 "punpckhbw %%xmm2,%%xmm1 \n" 328 "movdqa %%xmm0,(%3) \n" 329 "movdqa %%xmm1,0x10(%3) \n" 330 "lea 0x20(%3),%3 \n" 331 "sub $0x10,%4 \n" 332 "jg 1b \n" 333 : "+r"(src_y), // %0 334 "+r"(src_u), // %1 335 "+r"(src_v), // %2 336 "+r"(dst_frame), // %3 337 "+rm"(width) // %4 338 : 339 : "memory", "cc" 340 #if defined(__SSE2__) 341 , "xmm0", "xmm1", "xmm2", "xmm3" 342 #endif 343 ); 344 } 345 346 #define HAS_I42XTOUYVYROW_SSE2 347 static void I42xToUYVYRow_SSE2(const uint8* src_y, 348 const uint8* src_u, 349 const uint8* src_v, 350 uint8* dst_frame, int width) { 351 asm volatile ( 352 "sub %1,%2 \n" 353 ".p2align 4 \n" 354 "1: \n" 355 "movq (%1),%%xmm2 \n" 356 "movq (%1,%2,1),%%xmm3 \n" 357 "lea 0x8(%1),%1 \n" 358 "punpcklbw %%xmm3,%%xmm2 \n" 359 "movdqa (%0),%%xmm0 \n" 360 "movdqa %%xmm2,%%xmm1 \n" 361 "lea 0x10(%0),%0 \n" 362 "punpcklbw %%xmm0,%%xmm1 \n" 363 "punpckhbw %%xmm0,%%xmm2 \n" 364 "movdqa %%xmm1,(%3) \n" 365 "movdqa %%xmm2,0x10(%3) \n" 366 "lea 0x20(%3),%3 \n" 367 "sub $0x10,%4 \n" 368 "jg 1b \n" 369 : "+r"(src_y), // %0 370 "+r"(src_u), // %1 371 "+r"(src_v), // %2 372 "+r"(dst_frame), // %3 373 "+rm"(width) // %4 374 : 375 : "memory", "cc" 376 #if defined(__SSE2__) 377 , "xmm0", "xmm1", "xmm2", "xmm3" 378 #endif 379 ); 380 } 381 #endif 382 383 static void I42xToYUY2Row_C(const uint8* src_y, 384 const uint8* src_u, 385 const uint8* src_v, 386 uint8* dst_frame, int width) { 387 for (int x = 0; x < width - 1; x += 2) { 388 dst_frame[0] = src_y[0]; 389 dst_frame[1] = src_u[0]; 390 dst_frame[2] = src_y[1]; 391 dst_frame[3] = src_v[0]; 392 dst_frame += 4; 393 src_y += 2; 394 src_u += 1; 395 src_v += 1; 396 } 397 if (width & 1) { 398 dst_frame[0] = src_y[0]; 399 dst_frame[1] = src_u[0]; 400 dst_frame[2] = src_y[0]; // duplicate last y 401 dst_frame[3] = src_v[0]; 402 } 403 } 404 405 static void I42xToUYVYRow_C(const uint8* src_y, 406 const uint8* src_u, 407 const uint8* src_v, 408 uint8* dst_frame, int width) { 409 for (int x = 0; x < width - 1; x += 2) { 410 dst_frame[0] = src_u[0]; 411 dst_frame[1] = src_y[0]; 412 dst_frame[2] = src_v[0]; 413 dst_frame[3] = src_y[1]; 414 dst_frame += 4; 415 src_y += 2; 416 src_u += 1; 417 src_v += 1; 418 } 419 if (width & 1) { 420 dst_frame[0] = src_u[0]; 421 dst_frame[1] = src_y[0]; 422 dst_frame[2] = src_v[0]; 423 dst_frame[3] = src_y[0]; // duplicate last y 424 } 425 } 426 427 // Visual C x86 or GCC little endian. 428 #if defined(__x86_64__) || defined(_M_X64) || \ 429 defined(__i386__) || defined(_M_IX86) || \ 430 defined(__arm__) || defined(_M_ARM) || \ 431 (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) 432 #define LIBYUV_LITTLE_ENDIAN 433 #endif 434 435 #ifdef LIBYUV_LITTLE_ENDIAN 436 #define WRITEWORD(p, v) *reinterpret_cast<uint32*>(p) = v 437 #else 438 static inline void WRITEWORD(uint8* p, uint32 v) { 439 p[0] = (uint8)(v & 255); 440 p[1] = (uint8)((v >> 8) & 255); 441 p[2] = (uint8)((v >> 16) & 255); 442 p[3] = (uint8)((v >> 24) & 255); 443 } 444 #endif 445 446 #define EIGHTTOTEN(x) (x << 2 | x >> 6) 447 static void UYVYToV210Row_C(const uint8* src_uyvy, uint8* dst_v210, int width) { 448 for (int x = 0; x < width; x += 6) { 449 WRITEWORD(dst_v210 + 0, (EIGHTTOTEN(src_uyvy[0])) | 450 (EIGHTTOTEN(src_uyvy[1]) << 10) | 451 (EIGHTTOTEN(src_uyvy[2]) << 20)); 452 WRITEWORD(dst_v210 + 4, (EIGHTTOTEN(src_uyvy[3])) | 453 (EIGHTTOTEN(src_uyvy[4]) << 10) | 454 (EIGHTTOTEN(src_uyvy[5]) << 20)); 455 WRITEWORD(dst_v210 + 8, (EIGHTTOTEN(src_uyvy[6])) | 456 (EIGHTTOTEN(src_uyvy[7]) << 10) | 457 (EIGHTTOTEN(src_uyvy[8]) << 20)); 458 WRITEWORD(dst_v210 + 12, (EIGHTTOTEN(src_uyvy[9])) | 459 (EIGHTTOTEN(src_uyvy[10]) << 10) | 460 (EIGHTTOTEN(src_uyvy[11]) << 20)); 461 src_uyvy += 12; 462 dst_v210 += 16; 463 } 464 } 465 466 // TODO(fbarchard): Deprecate, move or expand 422 support? 467 LIBYUV_API 468 int I422ToYUY2(const uint8* src_y, int src_stride_y, 469 const uint8* src_u, int src_stride_u, 470 const uint8* src_v, int src_stride_v, 471 uint8* dst_frame, int dst_stride_frame, 472 int width, int height) { 473 if (!src_y || !src_u || !src_v || !dst_frame || 474 width <= 0 || height == 0) { 475 return -1; 476 } 477 // Negative height means invert the image. 478 if (height < 0) { 479 height = -height; 480 dst_frame = dst_frame + (height - 1) * dst_stride_frame; 481 dst_stride_frame = -dst_stride_frame; 482 } 483 void (*I42xToYUY2Row)(const uint8* src_y, const uint8* src_u, 484 const uint8* src_v, uint8* dst_frame, int width) = 485 I42xToYUY2Row_C; 486 #if defined(HAS_I42XTOYUY2ROW_SSE2) 487 if (TestCpuFlag(kCpuHasSSE2) && 488 IS_ALIGNED(width, 16) && 489 IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) && 490 IS_ALIGNED(dst_frame, 16) && IS_ALIGNED(dst_stride_frame, 16)) { 491 I42xToYUY2Row = I42xToYUY2Row_SSE2; 492 } 493 #endif 494 495 for (int y = 0; y < height; ++y) { 496 I42xToYUY2Row(src_y, src_u, src_y, dst_frame, width); 497 src_y += src_stride_y; 498 src_u += src_stride_u; 499 src_v += src_stride_v; 500 dst_frame += dst_stride_frame; 501 } 502 return 0; 503 } 504 505 LIBYUV_API 506 int I420ToYUY2(const uint8* src_y, int src_stride_y, 507 const uint8* src_u, int src_stride_u, 508 const uint8* src_v, int src_stride_v, 509 uint8* dst_frame, int dst_stride_frame, 510 int width, int height) { 511 if (!src_y || !src_u || !src_v || !dst_frame || 512 width <= 0 || height == 0) { 513 return -1; 514 } 515 // Negative height means invert the image. 516 if (height < 0) { 517 height = -height; 518 dst_frame = dst_frame + (height - 1) * dst_stride_frame; 519 dst_stride_frame = -dst_stride_frame; 520 } 521 void (*I42xToYUY2Row)(const uint8* src_y, const uint8* src_u, 522 const uint8* src_v, uint8* dst_frame, int width) = 523 I42xToYUY2Row_C; 524 #if defined(HAS_I42XTOYUY2ROW_SSE2) 525 if (TestCpuFlag(kCpuHasSSE2) && 526 IS_ALIGNED(width, 16) && 527 IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) && 528 IS_ALIGNED(dst_frame, 16) && IS_ALIGNED(dst_stride_frame, 16)) { 529 I42xToYUY2Row = I42xToYUY2Row_SSE2; 530 } 531 #endif 532 533 for (int y = 0; y < height - 1; y += 2) { 534 I42xToYUY2Row(src_y, src_u, src_v, dst_frame, width); 535 I42xToYUY2Row(src_y + src_stride_y, src_u, src_v, 536 dst_frame + dst_stride_frame, width); 537 src_y += src_stride_y * 2; 538 src_u += src_stride_u; 539 src_v += src_stride_v; 540 dst_frame += dst_stride_frame * 2; 541 } 542 if (height & 1) { 543 I42xToYUY2Row(src_y, src_u, src_v, dst_frame, width); 544 } 545 return 0; 546 } 547 548 // TODO(fbarchard): Deprecate, move or expand 422 support? 549 LIBYUV_API 550 int I422ToUYVY(const uint8* src_y, int src_stride_y, 551 const uint8* src_u, int src_stride_u, 552 const uint8* src_v, int src_stride_v, 553 uint8* dst_frame, int dst_stride_frame, 554 int width, int height) { 555 if (!src_y || !src_u || !src_v || !dst_frame || 556 width <= 0 || height == 0) { 557 return -1; 558 } 559 // Negative height means invert the image. 560 if (height < 0) { 561 height = -height; 562 dst_frame = dst_frame + (height - 1) * dst_stride_frame; 563 dst_stride_frame = -dst_stride_frame; 564 } 565 void (*I42xToUYVYRow)(const uint8* src_y, const uint8* src_u, 566 const uint8* src_v, uint8* dst_frame, int width) = 567 I42xToUYVYRow_C; 568 #if defined(HAS_I42XTOUYVYROW_SSE2) 569 if (TestCpuFlag(kCpuHasSSE2) && 570 IS_ALIGNED(width, 16) && 571 IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) && 572 IS_ALIGNED(dst_frame, 16) && IS_ALIGNED(dst_stride_frame, 16)) { 573 I42xToUYVYRow = I42xToUYVYRow_SSE2; 574 } 575 #endif 576 577 for (int y = 0; y < height; ++y) { 578 I42xToUYVYRow(src_y, src_u, src_y, dst_frame, width); 579 src_y += src_stride_y; 580 src_u += src_stride_u; 581 src_v += src_stride_v; 582 dst_frame += dst_stride_frame; 583 } 584 return 0; 585 } 586 587 LIBYUV_API 588 int I420ToUYVY(const uint8* src_y, int src_stride_y, 589 const uint8* src_u, int src_stride_u, 590 const uint8* src_v, int src_stride_v, 591 uint8* dst_frame, int dst_stride_frame, 592 int width, int height) { 593 if (!src_y || !src_u || !src_v || !dst_frame || 594 width <= 0 || height == 0) { 595 return -1; 596 } 597 // Negative height means invert the image. 598 if (height < 0) { 599 height = -height; 600 dst_frame = dst_frame + (height - 1) * dst_stride_frame; 601 dst_stride_frame = -dst_stride_frame; 602 } 603 void (*I42xToUYVYRow)(const uint8* src_y, const uint8* src_u, 604 const uint8* src_v, uint8* dst_frame, int width) = 605 I42xToUYVYRow_C; 606 #if defined(HAS_I42XTOUYVYROW_SSE2) 607 if (TestCpuFlag(kCpuHasSSE2) && 608 IS_ALIGNED(width, 16) && 609 IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) && 610 IS_ALIGNED(dst_frame, 16) && IS_ALIGNED(dst_stride_frame, 16)) { 611 I42xToUYVYRow = I42xToUYVYRow_SSE2; 612 } 613 #endif 614 615 for (int y = 0; y < height - 1; y += 2) { 616 I42xToUYVYRow(src_y, src_u, src_v, dst_frame, width); 617 I42xToUYVYRow(src_y + src_stride_y, src_u, src_v, 618 dst_frame + dst_stride_frame, width); 619 src_y += src_stride_y * 2; 620 src_u += src_stride_u; 621 src_v += src_stride_v; 622 dst_frame += dst_stride_frame * 2; 623 } 624 if (height & 1) { 625 I42xToUYVYRow(src_y, src_u, src_v, dst_frame, width); 626 } 627 return 0; 628 } 629 630 LIBYUV_API 631 int I420ToV210(const uint8* src_y, int src_stride_y, 632 const uint8* src_u, int src_stride_u, 633 const uint8* src_v, int src_stride_v, 634 uint8* dst_frame, int dst_stride_frame, 635 int width, int height) { 636 if (width * 16 / 6 > kMaxStride) { // Row buffer of V210 is required. 637 return -1; 638 } else if (!src_y || !src_u || !src_v || !dst_frame || 639 width <= 0 || height == 0) { 640 return -1; 641 } 642 // Negative height means invert the image. 643 if (height < 0) { 644 height = -height; 645 dst_frame = dst_frame + (height - 1) * dst_stride_frame; 646 dst_stride_frame = -dst_stride_frame; 647 } 648 649 SIMD_ALIGNED(uint8 row[kMaxStride]); 650 void (*UYVYToV210Row)(const uint8* src_uyvy, uint8* dst_v210, int pix); 651 UYVYToV210Row = UYVYToV210Row_C; 652 653 void (*I42xToUYVYRow)(const uint8* src_y, const uint8* src_u, 654 const uint8* src_v, uint8* dst_frame, int width) = 655 I42xToUYVYRow_C; 656 #if defined(HAS_I42XTOUYVYROW_SSE2) 657 if (TestCpuFlag(kCpuHasSSE2) && 658 IS_ALIGNED(width, 16) && 659 IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16)) { 660 I42xToUYVYRow = I42xToUYVYRow_SSE2; 661 } 662 #endif 663 664 for (int y = 0; y < height - 1; y += 2) { 665 I42xToUYVYRow(src_y, src_u, src_v, row, width); 666 UYVYToV210Row(row, dst_frame, width); 667 I42xToUYVYRow(src_y + src_stride_y, src_u, src_v, row, width); 668 UYVYToV210Row(row, dst_frame + dst_stride_frame, width); 669 670 src_y += src_stride_y * 2; 671 src_u += src_stride_u; 672 src_v += src_stride_v; 673 dst_frame += dst_stride_frame * 2; 674 } 675 if (height & 1) { 676 I42xToUYVYRow(src_y, src_u, src_v, row, width); 677 UYVYToV210Row(row, dst_frame, width); 678 } 679 return 0; 680 } 681 682 // Convert I420 to ARGB. 683 LIBYUV_API 684 int I420ToARGB(const uint8* src_y, int src_stride_y, 685 const uint8* src_u, int src_stride_u, 686 const uint8* src_v, int src_stride_v, 687 uint8* dst_argb, int dst_stride_argb, 688 int width, int height) { 689 if (!src_y || !src_u || !src_v || !dst_argb || 690 width <= 0 || height == 0) { 691 return -1; 692 } 693 // Negative height means invert the image. 694 if (height < 0) { 695 height = -height; 696 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 697 dst_stride_argb = -dst_stride_argb; 698 } 699 void (*I422ToARGBRow)(const uint8* y_buf, 700 const uint8* u_buf, 701 const uint8* v_buf, 702 uint8* rgb_buf, 703 int width) = I422ToARGBRow_C; 704 #if defined(HAS_I422TOARGBROW_NEON) 705 if (TestCpuFlag(kCpuHasNEON)) { 706 I422ToARGBRow = I422ToARGBRow_Any_NEON; 707 if (IS_ALIGNED(width, 16)) { 708 I422ToARGBRow = I422ToARGBRow_NEON; 709 } 710 } 711 #elif defined(HAS_I422TOARGBROW_SSSE3) 712 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 713 I422ToARGBRow = I422ToARGBRow_Any_SSSE3; 714 if (IS_ALIGNED(width, 8)) { 715 I422ToARGBRow = I422ToARGBRow_Unaligned_SSSE3; 716 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { 717 I422ToARGBRow = I422ToARGBRow_SSSE3; 718 } 719 } 720 } 721 #endif 722 723 for (int y = 0; y < height; ++y) { 724 I422ToARGBRow(src_y, src_u, src_v, dst_argb, width); 725 dst_argb += dst_stride_argb; 726 src_y += src_stride_y; 727 if (y & 1) { 728 src_u += src_stride_u; 729 src_v += src_stride_v; 730 } 731 } 732 return 0; 733 } 734 735 // Convert I420 to BGRA. 736 LIBYUV_API 737 int I420ToBGRA(const uint8* src_y, int src_stride_y, 738 const uint8* src_u, int src_stride_u, 739 const uint8* src_v, int src_stride_v, 740 uint8* dst_bgra, int dst_stride_bgra, 741 int width, int height) { 742 if (!src_y || !src_u || !src_v || 743 !dst_bgra || 744 width <= 0 || height == 0) { 745 return -1; 746 } 747 // Negative height means invert the image. 748 if (height < 0) { 749 height = -height; 750 dst_bgra = dst_bgra + (height - 1) * dst_stride_bgra; 751 dst_stride_bgra = -dst_stride_bgra; 752 } 753 void (*I422ToBGRARow)(const uint8* y_buf, 754 const uint8* u_buf, 755 const uint8* v_buf, 756 uint8* rgb_buf, 757 int width) = I422ToBGRARow_C; 758 #if defined(HAS_I422TOBGRAROW_NEON) 759 if (TestCpuFlag(kCpuHasNEON)) { 760 I422ToBGRARow = I422ToBGRARow_Any_NEON; 761 if (IS_ALIGNED(width, 16)) { 762 I422ToBGRARow = I422ToBGRARow_NEON; 763 } 764 } 765 #elif defined(HAS_I422TOBGRAROW_SSSE3) 766 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 767 I422ToBGRARow = I422ToBGRARow_Any_SSSE3; 768 if (IS_ALIGNED(width, 8)) { 769 I422ToBGRARow = I422ToBGRARow_Unaligned_SSSE3; 770 if (IS_ALIGNED(dst_bgra, 16) && IS_ALIGNED(dst_stride_bgra, 16)) { 771 I422ToBGRARow = I422ToBGRARow_SSSE3; 772 } 773 } 774 } 775 #endif 776 777 for (int y = 0; y < height; ++y) { 778 I422ToBGRARow(src_y, src_u, src_v, dst_bgra, width); 779 dst_bgra += dst_stride_bgra; 780 src_y += src_stride_y; 781 if (y & 1) { 782 src_u += src_stride_u; 783 src_v += src_stride_v; 784 } 785 } 786 return 0; 787 } 788 789 // Convert I420 to ABGR. 790 LIBYUV_API 791 int I420ToABGR(const uint8* src_y, int src_stride_y, 792 const uint8* src_u, int src_stride_u, 793 const uint8* src_v, int src_stride_v, 794 uint8* dst_abgr, int dst_stride_abgr, 795 int width, int height) { 796 if (!src_y || !src_u || !src_v || 797 !dst_abgr || 798 width <= 0 || height == 0) { 799 return -1; 800 } 801 // Negative height means invert the image. 802 if (height < 0) { 803 height = -height; 804 dst_abgr = dst_abgr + (height - 1) * dst_stride_abgr; 805 dst_stride_abgr = -dst_stride_abgr; 806 } 807 void (*I422ToABGRRow)(const uint8* y_buf, 808 const uint8* u_buf, 809 const uint8* v_buf, 810 uint8* rgb_buf, 811 int width) = I422ToABGRRow_C; 812 #if defined(HAS_I422TOABGRROW_NEON) 813 if (TestCpuFlag(kCpuHasNEON)) { 814 I422ToABGRRow = I422ToABGRRow_Any_NEON; 815 if (IS_ALIGNED(width, 16)) { 816 I422ToABGRRow = I422ToABGRRow_NEON; 817 } 818 } 819 #elif defined(HAS_I422TOABGRROW_SSSE3) 820 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 821 I422ToABGRRow = I422ToABGRRow_Any_SSSE3; 822 if (IS_ALIGNED(width, 8)) { 823 I422ToABGRRow = I422ToABGRRow_Unaligned_SSSE3; 824 if (IS_ALIGNED(dst_abgr, 16) && IS_ALIGNED(dst_stride_abgr, 16)) { 825 I422ToABGRRow = I422ToABGRRow_SSSE3; 826 } 827 } 828 } 829 #endif 830 831 for (int y = 0; y < height; ++y) { 832 I422ToABGRRow(src_y, src_u, src_v, dst_abgr, width); 833 dst_abgr += dst_stride_abgr; 834 src_y += src_stride_y; 835 if (y & 1) { 836 src_u += src_stride_u; 837 src_v += src_stride_v; 838 } 839 } 840 return 0; 841 } 842 843 // Convert I420 to RGBA. 844 LIBYUV_API 845 int I420ToRGBA(const uint8* src_y, int src_stride_y, 846 const uint8* src_u, int src_stride_u, 847 const uint8* src_v, int src_stride_v, 848 uint8* dst_rgba, int dst_stride_rgba, 849 int width, int height) { 850 if (!src_y || !src_u || !src_v || 851 !dst_rgba || 852 width <= 0 || height == 0) { 853 return -1; 854 } 855 // Negative height means invert the image. 856 if (height < 0) { 857 height = -height; 858 dst_rgba = dst_rgba + (height - 1) * dst_stride_rgba; 859 dst_stride_rgba = -dst_stride_rgba; 860 } 861 void (*I422ToRGBARow)(const uint8* y_buf, 862 const uint8* u_buf, 863 const uint8* v_buf, 864 uint8* rgb_buf, 865 int width) = I422ToRGBARow_C; 866 #if defined(HAS_I422TORGBAROW_NEON) 867 if (TestCpuFlag(kCpuHasNEON)) { 868 I422ToRGBARow = I422ToRGBARow_Any_NEON; 869 if (IS_ALIGNED(width, 16)) { 870 I422ToRGBARow = I422ToRGBARow_NEON; 871 } 872 } 873 #elif defined(HAS_I422TORGBAROW_SSSE3) 874 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 875 I422ToRGBARow = I422ToRGBARow_Any_SSSE3; 876 if (IS_ALIGNED(width, 8)) { 877 I422ToRGBARow = I422ToRGBARow_Unaligned_SSSE3; 878 if (IS_ALIGNED(dst_rgba, 16) && IS_ALIGNED(dst_stride_rgba, 16)) { 879 I422ToRGBARow = I422ToRGBARow_SSSE3; 880 } 881 } 882 } 883 #endif 884 885 for (int y = 0; y < height; ++y) { 886 I422ToRGBARow(src_y, src_u, src_v, dst_rgba, width); 887 dst_rgba += dst_stride_rgba; 888 src_y += src_stride_y; 889 if (y & 1) { 890 src_u += src_stride_u; 891 src_v += src_stride_v; 892 } 893 } 894 return 0; 895 } 896 897 // Convert I420 to RGB24. 898 LIBYUV_API 899 int I420ToRGB24(const uint8* src_y, int src_stride_y, 900 const uint8* src_u, int src_stride_u, 901 const uint8* src_v, int src_stride_v, 902 uint8* dst_rgb24, int dst_stride_rgb24, 903 int width, int height) { 904 if (!src_y || !src_u || !src_v || 905 !dst_rgb24 || 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_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24; 913 dst_stride_rgb24 = -dst_stride_rgb24; 914 } 915 void (*I422ToRGB24Row)(const uint8* y_buf, 916 const uint8* u_buf, 917 const uint8* v_buf, 918 uint8* rgb_buf, 919 int width) = I422ToRGB24Row_C; 920 #if defined(HAS_I422TORGB24ROW_NEON) 921 if (TestCpuFlag(kCpuHasNEON)) { 922 I422ToRGB24Row = I422ToRGB24Row_Any_NEON; 923 if (IS_ALIGNED(width, 16)) { 924 I422ToRGB24Row = I422ToRGB24Row_NEON; 925 } 926 } 927 #elif defined(HAS_I422TORGB24ROW_SSSE3) 928 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 929 I422ToRGB24Row = I422ToRGB24Row_Any_SSSE3; 930 if (IS_ALIGNED(width, 8)) { 931 I422ToRGB24Row = I422ToRGB24Row_Unaligned_SSSE3; 932 if (IS_ALIGNED(dst_rgb24, 16) && IS_ALIGNED(dst_stride_rgb24, 16)) { 933 I422ToRGB24Row = I422ToRGB24Row_SSSE3; 934 } 935 } 936 } 937 #endif 938 939 for (int y = 0; y < height; ++y) { 940 I422ToRGB24Row(src_y, src_u, src_v, dst_rgb24, width); 941 dst_rgb24 += dst_stride_rgb24; 942 src_y += src_stride_y; 943 if (y & 1) { 944 src_u += src_stride_u; 945 src_v += src_stride_v; 946 } 947 } 948 return 0; 949 } 950 951 // Convert I420 to RAW. 952 LIBYUV_API 953 int I420ToRAW(const uint8* src_y, int src_stride_y, 954 const uint8* src_u, int src_stride_u, 955 const uint8* src_v, int src_stride_v, 956 uint8* dst_raw, int dst_stride_raw, 957 int width, int height) { 958 if (!src_y || !src_u || !src_v || 959 !dst_raw || 960 width <= 0 || height == 0) { 961 return -1; 962 } 963 // Negative height means invert the image. 964 if (height < 0) { 965 height = -height; 966 dst_raw = dst_raw + (height - 1) * dst_stride_raw; 967 dst_stride_raw = -dst_stride_raw; 968 } 969 void (*I422ToRAWRow)(const uint8* y_buf, 970 const uint8* u_buf, 971 const uint8* v_buf, 972 uint8* rgb_buf, 973 int width) = I422ToRAWRow_C; 974 #if defined(HAS_I422TORAWROW_NEON) 975 if (TestCpuFlag(kCpuHasNEON)) { 976 I422ToRAWRow = I422ToRAWRow_Any_NEON; 977 if (IS_ALIGNED(width, 16)) { 978 I422ToRAWRow = I422ToRAWRow_NEON; 979 } 980 } 981 #elif defined(HAS_I422TORAWROW_SSSE3) 982 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 983 I422ToRAWRow = I422ToRAWRow_Any_SSSE3; 984 if (IS_ALIGNED(width, 8)) { 985 I422ToRAWRow = I422ToRAWRow_Unaligned_SSSE3; 986 if (IS_ALIGNED(dst_raw, 16) && IS_ALIGNED(dst_stride_raw, 16)) { 987 I422ToRAWRow = I422ToRAWRow_SSSE3; 988 } 989 } 990 } 991 #endif 992 993 for (int y = 0; y < height; ++y) { 994 I422ToRAWRow(src_y, src_u, src_v, dst_raw, width); 995 dst_raw += dst_stride_raw; 996 src_y += src_stride_y; 997 if (y & 1) { 998 src_u += src_stride_u; 999 src_v += src_stride_v; 1000 } 1001 } 1002 return 0; 1003 } 1004 1005 // Convert I420 to RGB565. 1006 LIBYUV_API 1007 int I420ToRGB565(const uint8* src_y, int src_stride_y, 1008 const uint8* src_u, int src_stride_u, 1009 const uint8* src_v, int src_stride_v, 1010 uint8* dst_rgb, int dst_stride_rgb, 1011 int width, int height) { 1012 if (!src_y || !src_u || !src_v || 1013 !dst_rgb || 1014 width <= 0 || height == 0) { 1015 return -1; 1016 } 1017 // Negative height means invert the image. 1018 if (height < 0) { 1019 height = -height; 1020 dst_rgb = dst_rgb + (height - 1) * dst_stride_rgb; 1021 dst_stride_rgb = -dst_stride_rgb; 1022 } 1023 void (*I422ToARGBRow)(const uint8* y_buf, 1024 const uint8* u_buf, 1025 const uint8* v_buf, 1026 uint8* rgb_buf, 1027 int width) = I422ToARGBRow_C; 1028 #if defined(HAS_I422TOARGBROW_NEON) 1029 if (TestCpuFlag(kCpuHasNEON)) { 1030 I422ToARGBRow = I422ToARGBRow_NEON; 1031 } 1032 #elif defined(HAS_I422TOARGBROW_SSSE3) 1033 if (TestCpuFlag(kCpuHasSSSE3)) { 1034 I422ToARGBRow = I422ToARGBRow_SSSE3; 1035 } 1036 #endif 1037 1038 SIMD_ALIGNED(uint8 row[kMaxStride]); 1039 void (*ARGBToRGB565Row)(const uint8* src_rgb, uint8* dst_rgb, int pix) = 1040 ARGBToRGB565Row_C; 1041 #if defined(HAS_ARGBTORGB565ROW_SSE2) 1042 if (TestCpuFlag(kCpuHasSSE2)) { 1043 if (width * 2 <= kMaxStride) { 1044 ARGBToRGB565Row = ARGBToRGB565Row_Any_SSE2; 1045 } 1046 if (IS_ALIGNED(width, 4)) { 1047 ARGBToRGB565Row = ARGBToRGB565Row_SSE2; 1048 } 1049 } 1050 #endif 1051 1052 for (int y = 0; y < height; ++y) { 1053 I422ToARGBRow(src_y, src_u, src_v, row, width); 1054 ARGBToRGB565Row(row, dst_rgb, width); 1055 dst_rgb += dst_stride_rgb; 1056 src_y += src_stride_y; 1057 if (y & 1) { 1058 src_u += src_stride_u; 1059 src_v += src_stride_v; 1060 } 1061 } 1062 return 0; 1063 } 1064 1065 // Convert I420 to ARGB1555. 1066 LIBYUV_API 1067 int I420ToARGB1555(const uint8* src_y, int src_stride_y, 1068 const uint8* src_u, int src_stride_u, 1069 const uint8* src_v, int src_stride_v, 1070 uint8* dst_argb, int dst_stride_argb, 1071 int width, int height) { 1072 if (!src_y || !src_u || !src_v || 1073 !dst_argb || 1074 width <= 0 || height == 0) { 1075 return -1; 1076 } 1077 // Negative height means invert the image. 1078 if (height < 0) { 1079 height = -height; 1080 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 1081 dst_stride_argb = -dst_stride_argb; 1082 } 1083 void (*I422ToARGBRow)(const uint8* y_buf, 1084 const uint8* u_buf, 1085 const uint8* v_buf, 1086 uint8* rgb_buf, 1087 int width) = I422ToARGBRow_C; 1088 #if defined(HAS_I422TOARGBROW_NEON) 1089 if (TestCpuFlag(kCpuHasNEON)) { 1090 I422ToARGBRow = I422ToARGBRow_NEON; 1091 } 1092 #elif defined(HAS_I422TOARGBROW_SSSE3) 1093 if (TestCpuFlag(kCpuHasSSSE3)) { 1094 I422ToARGBRow = I422ToARGBRow_SSSE3; 1095 } 1096 #endif 1097 1098 SIMD_ALIGNED(uint8 row[kMaxStride]); 1099 void (*ARGBToARGB1555Row)(const uint8* src_argb, uint8* dst_rgb, int pix) = 1100 ARGBToARGB1555Row_C; 1101 #if defined(HAS_ARGBTOARGB1555ROW_SSE2) 1102 if (TestCpuFlag(kCpuHasSSE2)) { 1103 if (width * 2 <= kMaxStride) { 1104 ARGBToARGB1555Row = ARGBToARGB1555Row_Any_SSE2; 1105 } 1106 if (IS_ALIGNED(width, 4)) { 1107 ARGBToARGB1555Row = ARGBToARGB1555Row_SSE2; 1108 } 1109 } 1110 #endif 1111 1112 for (int y = 0; y < height; ++y) { 1113 I422ToARGBRow(src_y, src_u, src_v, row, width); 1114 ARGBToARGB1555Row(row, dst_argb, width); 1115 dst_argb += dst_stride_argb; 1116 src_y += src_stride_y; 1117 if (y & 1) { 1118 src_u += src_stride_u; 1119 src_v += src_stride_v; 1120 } 1121 } 1122 return 0; 1123 } 1124 1125 // Convert I420 to ARGB4444. 1126 LIBYUV_API 1127 int I420ToARGB4444(const uint8* src_y, int src_stride_y, 1128 const uint8* src_u, int src_stride_u, 1129 const uint8* src_v, int src_stride_v, 1130 uint8* dst_argb, int dst_stride_argb, 1131 int width, int height) { 1132 if (!src_y || !src_u || !src_v || 1133 !dst_argb || 1134 width <= 0 || height == 0) { 1135 return -1; 1136 } 1137 // Negative height means invert the image. 1138 if (height < 0) { 1139 height = -height; 1140 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 1141 dst_stride_argb = -dst_stride_argb; 1142 } 1143 void (*I422ToARGBRow)(const uint8* y_buf, 1144 const uint8* u_buf, 1145 const uint8* v_buf, 1146 uint8* rgb_buf, 1147 int width) = I422ToARGBRow_C; 1148 #if defined(HAS_I422TOARGBROW_NEON) 1149 if (TestCpuFlag(kCpuHasNEON)) { 1150 I422ToARGBRow = I422ToARGBRow_NEON; 1151 } 1152 #elif defined(HAS_I422TOARGBROW_SSSE3) 1153 if (TestCpuFlag(kCpuHasSSSE3)) { 1154 I422ToARGBRow = I422ToARGBRow_SSSE3; 1155 } 1156 #endif 1157 1158 SIMD_ALIGNED(uint8 row[kMaxStride]); 1159 void (*ARGBToARGB4444Row)(const uint8* src_argb, uint8* dst_rgb, int pix) = 1160 ARGBToARGB4444Row_C; 1161 #if defined(HAS_ARGBTOARGB4444ROW_SSE2) 1162 if (TestCpuFlag(kCpuHasSSE2)) { 1163 if (width * 2 <= kMaxStride) { 1164 ARGBToARGB4444Row = ARGBToARGB4444Row_Any_SSE2; 1165 } 1166 if (IS_ALIGNED(width, 4)) { 1167 ARGBToARGB4444Row = ARGBToARGB4444Row_SSE2; 1168 } 1169 } 1170 #endif 1171 1172 for (int y = 0; y < height; ++y) { 1173 I422ToARGBRow(src_y, src_u, src_v, row, width); 1174 ARGBToARGB4444Row(row, dst_argb, width); 1175 dst_argb += dst_stride_argb; 1176 src_y += src_stride_y; 1177 if (y & 1) { 1178 src_u += src_stride_u; 1179 src_v += src_stride_v; 1180 } 1181 } 1182 return 0; 1183 } 1184 1185 // Convert I420 to specified format 1186 LIBYUV_API 1187 int ConvertFromI420(const uint8* y, int y_stride, 1188 const uint8* u, int u_stride, 1189 const uint8* v, int v_stride, 1190 uint8* dst_sample, int dst_sample_stride, 1191 int width, int height, 1192 uint32 format) { 1193 if (!y || !u|| !v || !dst_sample || 1194 width <= 0 || height == 0) { 1195 return -1; 1196 } 1197 int r = 0; 1198 switch (format) { 1199 // Single plane formats 1200 case FOURCC_YUY2: 1201 r = I420ToYUY2(y, y_stride, 1202 u, u_stride, 1203 v, v_stride, 1204 dst_sample, 1205 dst_sample_stride ? dst_sample_stride : width * 2, 1206 width, height); 1207 break; 1208 case FOURCC_UYVY: 1209 r = I420ToUYVY(y, y_stride, 1210 u, u_stride, 1211 v, v_stride, 1212 dst_sample, 1213 dst_sample_stride ? dst_sample_stride : width * 2, 1214 width, height); 1215 break; 1216 case FOURCC_V210: 1217 r = I420ToV210(y, y_stride, 1218 u, u_stride, 1219 v, v_stride, 1220 dst_sample, 1221 dst_sample_stride ? dst_sample_stride : 1222 (width + 47) / 48 * 128, 1223 width, height); 1224 break; 1225 case FOURCC_RGBP: 1226 r = I420ToRGB565(y, y_stride, 1227 u, u_stride, 1228 v, v_stride, 1229 dst_sample, 1230 dst_sample_stride ? dst_sample_stride : width * 2, 1231 width, height); 1232 break; 1233 case FOURCC_RGBO: 1234 r = I420ToARGB1555(y, y_stride, 1235 u, u_stride, 1236 v, v_stride, 1237 dst_sample, 1238 dst_sample_stride ? dst_sample_stride : width * 2, 1239 width, height); 1240 break; 1241 case FOURCC_R444: 1242 r = I420ToARGB4444(y, y_stride, 1243 u, u_stride, 1244 v, v_stride, 1245 dst_sample, 1246 dst_sample_stride ? dst_sample_stride : width * 2, 1247 width, height); 1248 break; 1249 case FOURCC_24BG: 1250 r = I420ToRGB24(y, y_stride, 1251 u, u_stride, 1252 v, v_stride, 1253 dst_sample, 1254 dst_sample_stride ? dst_sample_stride : width * 3, 1255 width, height); 1256 break; 1257 case FOURCC_RAW: 1258 r = I420ToRAW(y, y_stride, 1259 u, u_stride, 1260 v, v_stride, 1261 dst_sample, 1262 dst_sample_stride ? dst_sample_stride : width * 3, 1263 width, height); 1264 break; 1265 case FOURCC_ARGB: 1266 r = I420ToARGB(y, y_stride, 1267 u, u_stride, 1268 v, v_stride, 1269 dst_sample, 1270 dst_sample_stride ? dst_sample_stride : width * 4, 1271 width, height); 1272 break; 1273 case FOURCC_BGRA: 1274 r = I420ToBGRA(y, y_stride, 1275 u, u_stride, 1276 v, v_stride, 1277 dst_sample, 1278 dst_sample_stride ? dst_sample_stride : width * 4, 1279 width, height); 1280 break; 1281 case FOURCC_ABGR: 1282 r = I420ToABGR(y, y_stride, 1283 u, u_stride, 1284 v, v_stride, 1285 dst_sample, 1286 dst_sample_stride ? dst_sample_stride : width * 4, 1287 width, height); 1288 break; 1289 case FOURCC_RGBA: 1290 r = I420ToRGBA(y, y_stride, 1291 u, u_stride, 1292 v, v_stride, 1293 dst_sample, 1294 dst_sample_stride ? dst_sample_stride : width * 4, 1295 width, height); 1296 break; 1297 case FOURCC_BGGR: 1298 r = I420ToBayerBGGR(y, y_stride, 1299 u, u_stride, 1300 v, v_stride, 1301 dst_sample, 1302 dst_sample_stride ? dst_sample_stride : width, 1303 width, height); 1304 break; 1305 case FOURCC_GBRG: 1306 r = I420ToBayerGBRG(y, y_stride, 1307 u, u_stride, 1308 v, v_stride, 1309 dst_sample, 1310 dst_sample_stride ? dst_sample_stride : width, 1311 width, height); 1312 break; 1313 case FOURCC_GRBG: 1314 r = I420ToBayerGRBG(y, y_stride, 1315 u, u_stride, 1316 v, v_stride, 1317 dst_sample, 1318 dst_sample_stride ? dst_sample_stride : width, 1319 width, height); 1320 break; 1321 case FOURCC_RGGB: 1322 r = I420ToBayerRGGB(y, y_stride, 1323 u, u_stride, 1324 v, v_stride, 1325 dst_sample, 1326 dst_sample_stride ? dst_sample_stride : width, 1327 width, height); 1328 break; 1329 case FOURCC_I400: 1330 r = I400Copy(y, y_stride, 1331 dst_sample, 1332 dst_sample_stride ? dst_sample_stride : width, 1333 width, height); 1334 break; 1335 // Triplanar formats 1336 // TODO(fbarchard): halfstride instead of halfwidth 1337 case FOURCC_I420: 1338 case FOURCC_YU12: 1339 case FOURCC_YV12: { 1340 int halfwidth = (width + 1) / 2; 1341 int halfheight = (height + 1) / 2; 1342 uint8* dst_u; 1343 uint8* dst_v; 1344 if (format == FOURCC_YV12) { 1345 dst_v = dst_sample + width * height; 1346 dst_u = dst_v + halfwidth * halfheight; 1347 } else { 1348 dst_u = dst_sample + width * height; 1349 dst_v = dst_u + halfwidth * halfheight; 1350 } 1351 r = I420Copy(y, y_stride, 1352 u, u_stride, 1353 v, v_stride, 1354 dst_sample, width, 1355 dst_u, halfwidth, 1356 dst_v, halfwidth, 1357 width, height); 1358 break; 1359 } 1360 case FOURCC_I422: 1361 case FOURCC_YV16: { 1362 int halfwidth = (width + 1) / 2; 1363 uint8* dst_u; 1364 uint8* dst_v; 1365 if (format == FOURCC_YV16) { 1366 dst_v = dst_sample + width * height; 1367 dst_u = dst_v + halfwidth * height; 1368 } else { 1369 dst_u = dst_sample + width * height; 1370 dst_v = dst_u + halfwidth * height; 1371 } 1372 r = I420ToI422(y, y_stride, 1373 u, u_stride, 1374 v, v_stride, 1375 dst_sample, width, 1376 dst_u, halfwidth, 1377 dst_v, halfwidth, 1378 width, height); 1379 break; 1380 } 1381 case FOURCC_I444: 1382 case FOURCC_YV24: { 1383 uint8* dst_u; 1384 uint8* dst_v; 1385 if (format == FOURCC_YV24) { 1386 dst_v = dst_sample + width * height; 1387 dst_u = dst_v + width * height; 1388 } else { 1389 dst_u = dst_sample + width * height; 1390 dst_v = dst_u + width * height; 1391 } 1392 r = I420ToI444(y, y_stride, 1393 u, u_stride, 1394 v, v_stride, 1395 dst_sample, width, 1396 dst_u, width, 1397 dst_v, width, 1398 width, height); 1399 break; 1400 } 1401 case FOURCC_I411: { 1402 int quarterwidth = (width + 3) / 4; 1403 uint8* dst_u = dst_sample + width * height; 1404 uint8* dst_v = dst_u + quarterwidth * height; 1405 r = I420ToI411(y, y_stride, 1406 u, u_stride, 1407 v, v_stride, 1408 dst_sample, width, 1409 dst_u, quarterwidth, 1410 dst_v, quarterwidth, 1411 width, height); 1412 break; 1413 } 1414 1415 // Formats not supported - MJPG, biplanar, some rgb formats. 1416 default: 1417 return -1; // unknown fourcc - return failure code. 1418 } 1419 return r; 1420 } 1421 1422 #ifdef __cplusplus 1423 } // extern "C" 1424 } // namespace libyuv 1425 #endif 1426