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