1/* 2 * Copyright 2011 The LibYuv Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#include "libyuv/convert.h" 12 13#include "libyuv/basic_types.h" 14#include "libyuv/cpu_id.h" 15#include "libyuv/planar_functions.h" 16#include "libyuv/rotate.h" 17#include "libyuv/row.h" 18#include "libyuv/scale.h" // For ScalePlane() 19 20#ifdef __cplusplus 21namespace libyuv { 22extern "C" { 23#endif 24 25#define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s) 26static __inline int Abs(int v) { 27 return v >= 0 ? v : -v; 28} 29 30// Any I4xx To I420 format with mirroring. 31static int I4xxToI420(const uint8* src_y, 32 int src_stride_y, 33 const uint8* src_u, 34 int src_stride_u, 35 const uint8* src_v, 36 int src_stride_v, 37 uint8* dst_y, 38 int dst_stride_y, 39 uint8* dst_u, 40 int dst_stride_u, 41 uint8* dst_v, 42 int dst_stride_v, 43 int src_y_width, 44 int src_y_height, 45 int src_uv_width, 46 int src_uv_height) { 47 const int dst_y_width = Abs(src_y_width); 48 const int dst_y_height = Abs(src_y_height); 49 const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1); 50 const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1); 51 if (src_uv_width == 0 || src_uv_height == 0) { 52 return -1; 53 } 54 if (dst_y) { 55 ScalePlane(src_y, src_stride_y, src_y_width, src_y_height, dst_y, 56 dst_stride_y, dst_y_width, dst_y_height, kFilterBilinear); 57 } 58 ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u, 59 dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear); 60 ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height, dst_v, 61 dst_stride_v, dst_uv_width, dst_uv_height, kFilterBilinear); 62 return 0; 63} 64 65// Copy I420 with optional flipping 66// TODO(fbarchard): Use Scale plane which supports mirroring, but ensure 67// is does row coalescing. 68LIBYUV_API 69int I420Copy(const uint8* src_y, 70 int src_stride_y, 71 const uint8* src_u, 72 int src_stride_u, 73 const uint8* src_v, 74 int src_stride_v, 75 uint8* dst_y, 76 int dst_stride_y, 77 uint8* dst_u, 78 int dst_stride_u, 79 uint8* dst_v, 80 int dst_stride_v, 81 int width, 82 int height) { 83 int halfwidth = (width + 1) >> 1; 84 int halfheight = (height + 1) >> 1; 85 if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) { 86 return -1; 87 } 88 // Negative height means invert the image. 89 if (height < 0) { 90 height = -height; 91 halfheight = (height + 1) >> 1; 92 src_y = src_y + (height - 1) * src_stride_y; 93 src_u = src_u + (halfheight - 1) * src_stride_u; 94 src_v = src_v + (halfheight - 1) * src_stride_v; 95 src_stride_y = -src_stride_y; 96 src_stride_u = -src_stride_u; 97 src_stride_v = -src_stride_v; 98 } 99 100 if (dst_y) { 101 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); 102 } 103 // Copy UV planes. 104 CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight); 105 CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight); 106 return 0; 107} 108 109// 422 chroma is 1/2 width, 1x height 110// 420 chroma is 1/2 width, 1/2 height 111LIBYUV_API 112int I422ToI420(const uint8* src_y, 113 int src_stride_y, 114 const uint8* src_u, 115 int src_stride_u, 116 const uint8* src_v, 117 int src_stride_v, 118 uint8* dst_y, 119 int dst_stride_y, 120 uint8* dst_u, 121 int dst_stride_u, 122 uint8* dst_v, 123 int dst_stride_v, 124 int width, 125 int height) { 126 const int src_uv_width = SUBSAMPLE(width, 1, 1); 127 return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v, 128 src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u, 129 dst_v, dst_stride_v, width, height, src_uv_width, height); 130} 131 132// 444 chroma is 1x width, 1x height 133// 420 chroma is 1/2 width, 1/2 height 134LIBYUV_API 135int I444ToI420(const uint8* src_y, 136 int src_stride_y, 137 const uint8* src_u, 138 int src_stride_u, 139 const uint8* src_v, 140 int src_stride_v, 141 uint8* dst_y, 142 int dst_stride_y, 143 uint8* dst_u, 144 int dst_stride_u, 145 uint8* dst_v, 146 int dst_stride_v, 147 int width, 148 int height) { 149 return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v, 150 src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u, 151 dst_v, dst_stride_v, width, height, width, height); 152} 153 154// I400 is greyscale typically used in MJPG 155LIBYUV_API 156int I400ToI420(const uint8* src_y, 157 int src_stride_y, 158 uint8* dst_y, 159 int dst_stride_y, 160 uint8* dst_u, 161 int dst_stride_u, 162 uint8* dst_v, 163 int dst_stride_v, 164 int width, 165 int height) { 166 int halfwidth = (width + 1) >> 1; 167 int halfheight = (height + 1) >> 1; 168 if (!dst_u || !dst_v || width <= 0 || height == 0) { 169 return -1; 170 } 171 // Negative height means invert the image. 172 if (height < 0) { 173 height = -height; 174 halfheight = (height + 1) >> 1; 175 src_y = src_y + (height - 1) * src_stride_y; 176 src_stride_y = -src_stride_y; 177 } 178 if (dst_y) { 179 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); 180 } 181 SetPlane(dst_u, dst_stride_u, halfwidth, halfheight, 128); 182 SetPlane(dst_v, dst_stride_v, halfwidth, halfheight, 128); 183 return 0; 184} 185 186static void CopyPlane2(const uint8* src, 187 int src_stride_0, 188 int src_stride_1, 189 uint8* dst, 190 int dst_stride, 191 int width, 192 int height) { 193 int y; 194 void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C; 195#if defined(HAS_COPYROW_SSE2) 196 if (TestCpuFlag(kCpuHasSSE2)) { 197 CopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2; 198 } 199#endif 200#if defined(HAS_COPYROW_AVX) 201 if (TestCpuFlag(kCpuHasAVX)) { 202 CopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX; 203 } 204#endif 205#if defined(HAS_COPYROW_ERMS) 206 if (TestCpuFlag(kCpuHasERMS)) { 207 CopyRow = CopyRow_ERMS; 208 } 209#endif 210#if defined(HAS_COPYROW_NEON) 211 if (TestCpuFlag(kCpuHasNEON)) { 212 CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON; 213 } 214#endif 215#if defined(HAS_COPYROW_MIPS) 216 if (TestCpuFlag(kCpuHasMIPS)) { 217 CopyRow = CopyRow_MIPS; 218 } 219#endif 220 221 // Copy plane 222 for (y = 0; y < height - 1; y += 2) { 223 CopyRow(src, dst, width); 224 CopyRow(src + src_stride_0, dst + dst_stride, width); 225 src += src_stride_0 + src_stride_1; 226 dst += dst_stride * 2; 227 } 228 if (height & 1) { 229 CopyRow(src, dst, width); 230 } 231} 232 233// Support converting from FOURCC_M420 234// Useful for bandwidth constrained transports like USB 1.0 and 2.0 and for 235// easy conversion to I420. 236// M420 format description: 237// M420 is row biplanar 420: 2 rows of Y and 1 row of UV. 238// Chroma is half width / half height. (420) 239// src_stride_m420 is row planar. Normally this will be the width in pixels. 240// The UV plane is half width, but 2 values, so src_stride_m420 applies to 241// this as well as the two Y planes. 242static int X420ToI420(const uint8* src_y, 243 int src_stride_y0, 244 int src_stride_y1, 245 const uint8* src_uv, 246 int src_stride_uv, 247 uint8* dst_y, 248 int dst_stride_y, 249 uint8* dst_u, 250 int dst_stride_u, 251 uint8* dst_v, 252 int dst_stride_v, 253 int width, 254 int height) { 255 int halfwidth = (width + 1) >> 1; 256 int halfheight = (height + 1) >> 1; 257 if (!src_uv || !dst_u || !dst_v || width <= 0 || height == 0) { 258 return -1; 259 } 260 // Negative height means invert the image. 261 if (height < 0) { 262 height = -height; 263 halfheight = (height + 1) >> 1; 264 if (dst_y) { 265 dst_y = dst_y + (height - 1) * dst_stride_y; 266 } 267 dst_u = dst_u + (halfheight - 1) * dst_stride_u; 268 dst_v = dst_v + (halfheight - 1) * dst_stride_v; 269 dst_stride_y = -dst_stride_y; 270 dst_stride_u = -dst_stride_u; 271 dst_stride_v = -dst_stride_v; 272 } 273 // Coalesce rows. 274 if (src_stride_y0 == width && src_stride_y1 == width && 275 dst_stride_y == width) { 276 width *= height; 277 height = 1; 278 src_stride_y0 = src_stride_y1 = dst_stride_y = 0; 279 } 280 // Coalesce rows. 281 if (src_stride_uv == halfwidth * 2 && dst_stride_u == halfwidth && 282 dst_stride_v == halfwidth) { 283 halfwidth *= halfheight; 284 halfheight = 1; 285 src_stride_uv = dst_stride_u = dst_stride_v = 0; 286 } 287 288 if (dst_y) { 289 if (src_stride_y0 == src_stride_y1) { 290 CopyPlane(src_y, src_stride_y0, dst_y, dst_stride_y, width, height); 291 } else { 292 CopyPlane2(src_y, src_stride_y0, src_stride_y1, dst_y, dst_stride_y, 293 width, height); 294 } 295 } 296 297 // Split UV plane - NV12 / NV21 298 SplitUVPlane(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v, dst_stride_v, 299 halfwidth, halfheight); 300 301 return 0; 302} 303 304// Convert NV12 to I420. 305LIBYUV_API 306int NV12ToI420(const uint8* src_y, 307 int src_stride_y, 308 const uint8* src_uv, 309 int src_stride_uv, 310 uint8* dst_y, 311 int dst_stride_y, 312 uint8* dst_u, 313 int dst_stride_u, 314 uint8* dst_v, 315 int dst_stride_v, 316 int width, 317 int height) { 318 return X420ToI420(src_y, src_stride_y, src_stride_y, src_uv, src_stride_uv, 319 dst_y, dst_stride_y, dst_u, dst_stride_u, dst_v, 320 dst_stride_v, width, height); 321} 322 323// Convert NV21 to I420. Same as NV12 but u and v pointers swapped. 324LIBYUV_API 325int NV21ToI420(const uint8* src_y, 326 int src_stride_y, 327 const uint8* src_vu, 328 int src_stride_vu, 329 uint8* dst_y, 330 int dst_stride_y, 331 uint8* dst_u, 332 int dst_stride_u, 333 uint8* dst_v, 334 int dst_stride_v, 335 int width, 336 int height) { 337 return X420ToI420(src_y, src_stride_y, src_stride_y, src_vu, src_stride_vu, 338 dst_y, dst_stride_y, dst_v, dst_stride_v, dst_u, 339 dst_stride_u, width, height); 340} 341 342// Convert M420 to I420. 343LIBYUV_API 344int M420ToI420(const uint8* src_m420, 345 int src_stride_m420, 346 uint8* dst_y, 347 int dst_stride_y, 348 uint8* dst_u, 349 int dst_stride_u, 350 uint8* dst_v, 351 int dst_stride_v, 352 int width, 353 int height) { 354 return X420ToI420(src_m420, src_stride_m420, src_stride_m420 * 2, 355 src_m420 + src_stride_m420 * 2, src_stride_m420 * 3, dst_y, 356 dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v, 357 width, height); 358} 359 360// Convert YUY2 to I420. 361LIBYUV_API 362int YUY2ToI420(const uint8* src_yuy2, 363 int src_stride_yuy2, 364 uint8* dst_y, 365 int dst_stride_y, 366 uint8* dst_u, 367 int dst_stride_u, 368 uint8* dst_v, 369 int dst_stride_v, 370 int width, 371 int height) { 372 int y; 373 void (*YUY2ToUVRow)(const uint8* src_yuy2, int src_stride_yuy2, uint8* dst_u, 374 uint8* dst_v, int width) = YUY2ToUVRow_C; 375 void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int width) = 376 YUY2ToYRow_C; 377 // Negative height means invert the image. 378 if (height < 0) { 379 height = -height; 380 src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2; 381 src_stride_yuy2 = -src_stride_yuy2; 382 } 383#if defined(HAS_YUY2TOYROW_SSE2) 384 if (TestCpuFlag(kCpuHasSSE2)) { 385 YUY2ToUVRow = YUY2ToUVRow_Any_SSE2; 386 YUY2ToYRow = YUY2ToYRow_Any_SSE2; 387 if (IS_ALIGNED(width, 16)) { 388 YUY2ToUVRow = YUY2ToUVRow_SSE2; 389 YUY2ToYRow = YUY2ToYRow_SSE2; 390 } 391 } 392#endif 393#if defined(HAS_YUY2TOYROW_AVX2) 394 if (TestCpuFlag(kCpuHasAVX2)) { 395 YUY2ToUVRow = YUY2ToUVRow_Any_AVX2; 396 YUY2ToYRow = YUY2ToYRow_Any_AVX2; 397 if (IS_ALIGNED(width, 32)) { 398 YUY2ToUVRow = YUY2ToUVRow_AVX2; 399 YUY2ToYRow = YUY2ToYRow_AVX2; 400 } 401 } 402#endif 403#if defined(HAS_YUY2TOYROW_NEON) 404 if (TestCpuFlag(kCpuHasNEON)) { 405 YUY2ToYRow = YUY2ToYRow_Any_NEON; 406 YUY2ToUVRow = YUY2ToUVRow_Any_NEON; 407 if (IS_ALIGNED(width, 16)) { 408 YUY2ToYRow = YUY2ToYRow_NEON; 409 YUY2ToUVRow = YUY2ToUVRow_NEON; 410 } 411 } 412#endif 413#if defined(HAS_YUY2TOYROW_MSA) 414 if (TestCpuFlag(kCpuHasMSA)) { 415 YUY2ToYRow = YUY2ToYRow_Any_MSA; 416 YUY2ToUVRow = YUY2ToUVRow_Any_MSA; 417 if (IS_ALIGNED(width, 32)) { 418 YUY2ToYRow = YUY2ToYRow_MSA; 419 YUY2ToUVRow = YUY2ToUVRow_MSA; 420 } 421 } 422#endif 423 424 for (y = 0; y < height - 1; y += 2) { 425 YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width); 426 YUY2ToYRow(src_yuy2, dst_y, width); 427 YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width); 428 src_yuy2 += src_stride_yuy2 * 2; 429 dst_y += dst_stride_y * 2; 430 dst_u += dst_stride_u; 431 dst_v += dst_stride_v; 432 } 433 if (height & 1) { 434 YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width); 435 YUY2ToYRow(src_yuy2, dst_y, width); 436 } 437 return 0; 438} 439 440// Convert UYVY to I420. 441LIBYUV_API 442int UYVYToI420(const uint8* src_uyvy, 443 int src_stride_uyvy, 444 uint8* dst_y, 445 int dst_stride_y, 446 uint8* dst_u, 447 int dst_stride_u, 448 uint8* dst_v, 449 int dst_stride_v, 450 int width, 451 int height) { 452 int y; 453 void (*UYVYToUVRow)(const uint8* src_uyvy, int src_stride_uyvy, uint8* dst_u, 454 uint8* dst_v, int width) = UYVYToUVRow_C; 455 void (*UYVYToYRow)(const uint8* src_uyvy, uint8* dst_y, int width) = 456 UYVYToYRow_C; 457 // Negative height means invert the image. 458 if (height < 0) { 459 height = -height; 460 src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy; 461 src_stride_uyvy = -src_stride_uyvy; 462 } 463#if defined(HAS_UYVYTOYROW_SSE2) 464 if (TestCpuFlag(kCpuHasSSE2)) { 465 UYVYToUVRow = UYVYToUVRow_Any_SSE2; 466 UYVYToYRow = UYVYToYRow_Any_SSE2; 467 if (IS_ALIGNED(width, 16)) { 468 UYVYToUVRow = UYVYToUVRow_SSE2; 469 UYVYToYRow = UYVYToYRow_SSE2; 470 } 471 } 472#endif 473#if defined(HAS_UYVYTOYROW_AVX2) 474 if (TestCpuFlag(kCpuHasAVX2)) { 475 UYVYToUVRow = UYVYToUVRow_Any_AVX2; 476 UYVYToYRow = UYVYToYRow_Any_AVX2; 477 if (IS_ALIGNED(width, 32)) { 478 UYVYToUVRow = UYVYToUVRow_AVX2; 479 UYVYToYRow = UYVYToYRow_AVX2; 480 } 481 } 482#endif 483#if defined(HAS_UYVYTOYROW_NEON) 484 if (TestCpuFlag(kCpuHasNEON)) { 485 UYVYToYRow = UYVYToYRow_Any_NEON; 486 UYVYToUVRow = UYVYToUVRow_Any_NEON; 487 if (IS_ALIGNED(width, 16)) { 488 UYVYToYRow = UYVYToYRow_NEON; 489 UYVYToUVRow = UYVYToUVRow_NEON; 490 } 491 } 492#endif 493#if defined(HAS_UYVYTOYROW_MSA) 494 if (TestCpuFlag(kCpuHasMSA)) { 495 UYVYToYRow = UYVYToYRow_Any_MSA; 496 UYVYToUVRow = UYVYToUVRow_Any_MSA; 497 if (IS_ALIGNED(width, 32)) { 498 UYVYToYRow = UYVYToYRow_MSA; 499 UYVYToUVRow = UYVYToUVRow_MSA; 500 } 501 } 502#endif 503 504 for (y = 0; y < height - 1; y += 2) { 505 UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width); 506 UYVYToYRow(src_uyvy, dst_y, width); 507 UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width); 508 src_uyvy += src_stride_uyvy * 2; 509 dst_y += dst_stride_y * 2; 510 dst_u += dst_stride_u; 511 dst_v += dst_stride_v; 512 } 513 if (height & 1) { 514 UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width); 515 UYVYToYRow(src_uyvy, dst_y, width); 516 } 517 return 0; 518} 519 520// Convert ARGB to I420. 521LIBYUV_API 522int ARGBToI420(const uint8* src_argb, 523 int src_stride_argb, 524 uint8* dst_y, 525 int dst_stride_y, 526 uint8* dst_u, 527 int dst_stride_u, 528 uint8* dst_v, 529 int dst_stride_v, 530 int width, 531 int height) { 532 int y; 533 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u, 534 uint8* dst_v, int width) = ARGBToUVRow_C; 535 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = 536 ARGBToYRow_C; 537 if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { 538 return -1; 539 } 540 // Negative height means invert the image. 541 if (height < 0) { 542 height = -height; 543 src_argb = src_argb + (height - 1) * src_stride_argb; 544 src_stride_argb = -src_stride_argb; 545 } 546#if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) 547 if (TestCpuFlag(kCpuHasSSSE3)) { 548 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 549 ARGBToYRow = ARGBToYRow_Any_SSSE3; 550 if (IS_ALIGNED(width, 16)) { 551 ARGBToUVRow = ARGBToUVRow_SSSE3; 552 ARGBToYRow = ARGBToYRow_SSSE3; 553 } 554 } 555#endif 556#if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) 557 if (TestCpuFlag(kCpuHasAVX2)) { 558 ARGBToUVRow = ARGBToUVRow_Any_AVX2; 559 ARGBToYRow = ARGBToYRow_Any_AVX2; 560 if (IS_ALIGNED(width, 32)) { 561 ARGBToUVRow = ARGBToUVRow_AVX2; 562 ARGBToYRow = ARGBToYRow_AVX2; 563 } 564 } 565#endif 566#if defined(HAS_ARGBTOYROW_NEON) 567 if (TestCpuFlag(kCpuHasNEON)) { 568 ARGBToYRow = ARGBToYRow_Any_NEON; 569 if (IS_ALIGNED(width, 8)) { 570 ARGBToYRow = ARGBToYRow_NEON; 571 } 572 } 573#endif 574#if defined(HAS_ARGBTOUVROW_NEON) 575 if (TestCpuFlag(kCpuHasNEON)) { 576 ARGBToUVRow = ARGBToUVRow_Any_NEON; 577 if (IS_ALIGNED(width, 16)) { 578 ARGBToUVRow = ARGBToUVRow_NEON; 579 } 580 } 581#endif 582#if defined(HAS_ARGBTOYROW_DSPR2) 583 if (TestCpuFlag(kCpuHasDSPR2)) { 584 ARGBToYRow = ARGBToYRow_Any_DSPR2; 585 if (IS_ALIGNED(width, 8)) { 586 ARGBToYRow = ARGBToYRow_DSPR2; 587 } 588 } 589#endif 590#if defined(HAS_ARGBTOYROW_MSA) 591 if (TestCpuFlag(kCpuHasMSA)) { 592 ARGBToYRow = ARGBToYRow_Any_MSA; 593 if (IS_ALIGNED(width, 16)) { 594 ARGBToYRow = ARGBToYRow_MSA; 595 } 596 } 597#endif 598#if defined(HAS_ARGBTOUVROW_DSPR2) 599 if (TestCpuFlag(kCpuHasDSPR2)) { 600 ARGBToUVRow = ARGBToUVRow_Any_DSPR2; 601 if (IS_ALIGNED(width, 16)) { 602 ARGBToUVRow = ARGBToUVRow_DSPR2; 603 } 604 } 605#endif 606#if defined(HAS_ARGBTOUVROW_MSA) 607 if (TestCpuFlag(kCpuHasMSA)) { 608 ARGBToUVRow = ARGBToUVRow_Any_MSA; 609 if (IS_ALIGNED(width, 32)) { 610 ARGBToUVRow = ARGBToUVRow_MSA; 611 } 612 } 613#endif 614 615 for (y = 0; y < height - 1; y += 2) { 616 ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width); 617 ARGBToYRow(src_argb, dst_y, width); 618 ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width); 619 src_argb += src_stride_argb * 2; 620 dst_y += dst_stride_y * 2; 621 dst_u += dst_stride_u; 622 dst_v += dst_stride_v; 623 } 624 if (height & 1) { 625 ARGBToUVRow(src_argb, 0, dst_u, dst_v, width); 626 ARGBToYRow(src_argb, dst_y, width); 627 } 628 return 0; 629} 630 631// Convert BGRA to I420. 632LIBYUV_API 633int BGRAToI420(const uint8* src_bgra, 634 int src_stride_bgra, 635 uint8* dst_y, 636 int dst_stride_y, 637 uint8* dst_u, 638 int dst_stride_u, 639 uint8* dst_v, 640 int dst_stride_v, 641 int width, 642 int height) { 643 int y; 644 void (*BGRAToUVRow)(const uint8* src_bgra0, int src_stride_bgra, uint8* dst_u, 645 uint8* dst_v, int width) = BGRAToUVRow_C; 646 void (*BGRAToYRow)(const uint8* src_bgra, uint8* dst_y, int width) = 647 BGRAToYRow_C; 648 if (!src_bgra || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { 649 return -1; 650 } 651 // Negative height means invert the image. 652 if (height < 0) { 653 height = -height; 654 src_bgra = src_bgra + (height - 1) * src_stride_bgra; 655 src_stride_bgra = -src_stride_bgra; 656 } 657#if defined(HAS_BGRATOYROW_SSSE3) && defined(HAS_BGRATOUVROW_SSSE3) 658 if (TestCpuFlag(kCpuHasSSSE3)) { 659 BGRAToUVRow = BGRAToUVRow_Any_SSSE3; 660 BGRAToYRow = BGRAToYRow_Any_SSSE3; 661 if (IS_ALIGNED(width, 16)) { 662 BGRAToUVRow = BGRAToUVRow_SSSE3; 663 BGRAToYRow = BGRAToYRow_SSSE3; 664 } 665 } 666#endif 667#if defined(HAS_BGRATOYROW_NEON) 668 if (TestCpuFlag(kCpuHasNEON)) { 669 BGRAToYRow = BGRAToYRow_Any_NEON; 670 if (IS_ALIGNED(width, 8)) { 671 BGRAToYRow = BGRAToYRow_NEON; 672 } 673 } 674#endif 675#if defined(HAS_BGRATOUVROW_NEON) 676 if (TestCpuFlag(kCpuHasNEON)) { 677 BGRAToUVRow = BGRAToUVRow_Any_NEON; 678 if (IS_ALIGNED(width, 16)) { 679 BGRAToUVRow = BGRAToUVRow_NEON; 680 } 681 } 682#endif 683#if defined(HAS_BGRATOYROW_DSPR2) 684 if (TestCpuFlag(kCpuHasDSPR2)) { 685 BGRAToYRow = BGRAToYRow_Any_DSPR2; 686 if (IS_ALIGNED(width, 8)) { 687 BGRAToYRow = BGRAToYRow_DSPR2; 688 } 689 } 690#endif 691#if defined(HAS_BGRATOUVROW_DSPR2) 692 if (TestCpuFlag(kCpuHasDSPR2)) { 693 BGRAToUVRow = BGRAToUVRow_Any_DSPR2; 694 if (IS_ALIGNED(width, 16)) { 695 BGRAToUVRow = BGRAToUVRow_DSPR2; 696 } 697 } 698#endif 699#if defined(HAS_BGRATOYROW_MSA) 700 if (TestCpuFlag(kCpuHasMSA)) { 701 BGRAToYRow = BGRAToYRow_Any_MSA; 702 if (IS_ALIGNED(width, 16)) { 703 BGRAToYRow = BGRAToYRow_MSA; 704 } 705 } 706#endif 707#if defined(HAS_BGRATOUVROW_MSA) 708 if (TestCpuFlag(kCpuHasMSA)) { 709 BGRAToUVRow = BGRAToUVRow_Any_MSA; 710 if (IS_ALIGNED(width, 16)) { 711 BGRAToUVRow = BGRAToUVRow_MSA; 712 } 713 } 714#endif 715 716 for (y = 0; y < height - 1; y += 2) { 717 BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width); 718 BGRAToYRow(src_bgra, dst_y, width); 719 BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width); 720 src_bgra += src_stride_bgra * 2; 721 dst_y += dst_stride_y * 2; 722 dst_u += dst_stride_u; 723 dst_v += dst_stride_v; 724 } 725 if (height & 1) { 726 BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width); 727 BGRAToYRow(src_bgra, dst_y, width); 728 } 729 return 0; 730} 731 732// Convert ABGR to I420. 733LIBYUV_API 734int ABGRToI420(const uint8* src_abgr, 735 int src_stride_abgr, 736 uint8* dst_y, 737 int dst_stride_y, 738 uint8* dst_u, 739 int dst_stride_u, 740 uint8* dst_v, 741 int dst_stride_v, 742 int width, 743 int height) { 744 int y; 745 void (*ABGRToUVRow)(const uint8* src_abgr0, int src_stride_abgr, uint8* dst_u, 746 uint8* dst_v, int width) = ABGRToUVRow_C; 747 void (*ABGRToYRow)(const uint8* src_abgr, uint8* dst_y, int width) = 748 ABGRToYRow_C; 749 if (!src_abgr || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { 750 return -1; 751 } 752 // Negative height means invert the image. 753 if (height < 0) { 754 height = -height; 755 src_abgr = src_abgr + (height - 1) * src_stride_abgr; 756 src_stride_abgr = -src_stride_abgr; 757 } 758#if defined(HAS_ABGRTOYROW_SSSE3) && defined(HAS_ABGRTOUVROW_SSSE3) 759 if (TestCpuFlag(kCpuHasSSSE3)) { 760 ABGRToUVRow = ABGRToUVRow_Any_SSSE3; 761 ABGRToYRow = ABGRToYRow_Any_SSSE3; 762 if (IS_ALIGNED(width, 16)) { 763 ABGRToUVRow = ABGRToUVRow_SSSE3; 764 ABGRToYRow = ABGRToYRow_SSSE3; 765 } 766 } 767#endif 768#if defined(HAS_ABGRTOYROW_NEON) 769 if (TestCpuFlag(kCpuHasNEON)) { 770 ABGRToYRow = ABGRToYRow_Any_NEON; 771 if (IS_ALIGNED(width, 8)) { 772 ABGRToYRow = ABGRToYRow_NEON; 773 } 774 } 775#endif 776#if defined(HAS_ABGRTOUVROW_NEON) 777 if (TestCpuFlag(kCpuHasNEON)) { 778 ABGRToUVRow = ABGRToUVRow_Any_NEON; 779 if (IS_ALIGNED(width, 16)) { 780 ABGRToUVRow = ABGRToUVRow_NEON; 781 } 782 } 783#endif 784#if defined(HAS_ABGRTOYROW_DSPR2) 785 if (TestCpuFlag(kCpuHasDSPR2)) { 786 ABGRToYRow = ABGRToYRow_Any_DSPR2; 787 if (IS_ALIGNED(width, 8)) { 788 ABGRToYRow = ABGRToYRow_DSPR2; 789 } 790 } 791#endif 792#if defined(HAS_ABGRTOUVROW_DSPR2) 793 if (TestCpuFlag(kCpuHasDSPR2)) { 794 ABGRToUVRow = ABGRToUVRow_Any_DSPR2; 795 if (IS_ALIGNED(width, 16)) { 796 ABGRToUVRow = ABGRToUVRow_DSPR2; 797 } 798 } 799#endif 800#if defined(HAS_ABGRTOYROW_MSA) 801 if (TestCpuFlag(kCpuHasMSA)) { 802 ABGRToYRow = ABGRToYRow_Any_MSA; 803 if (IS_ALIGNED(width, 16)) { 804 ABGRToYRow = ABGRToYRow_MSA; 805 } 806 } 807#endif 808#if defined(HAS_ABGRTOUVROW_MSA) 809 if (TestCpuFlag(kCpuHasMSA)) { 810 ABGRToUVRow = ABGRToUVRow_Any_MSA; 811 if (IS_ALIGNED(width, 16)) { 812 ABGRToUVRow = ABGRToUVRow_MSA; 813 } 814 } 815#endif 816 817 for (y = 0; y < height - 1; y += 2) { 818 ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width); 819 ABGRToYRow(src_abgr, dst_y, width); 820 ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width); 821 src_abgr += src_stride_abgr * 2; 822 dst_y += dst_stride_y * 2; 823 dst_u += dst_stride_u; 824 dst_v += dst_stride_v; 825 } 826 if (height & 1) { 827 ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width); 828 ABGRToYRow(src_abgr, dst_y, width); 829 } 830 return 0; 831} 832 833// Convert RGBA to I420. 834LIBYUV_API 835int RGBAToI420(const uint8* src_rgba, 836 int src_stride_rgba, 837 uint8* dst_y, 838 int dst_stride_y, 839 uint8* dst_u, 840 int dst_stride_u, 841 uint8* dst_v, 842 int dst_stride_v, 843 int width, 844 int height) { 845 int y; 846 void (*RGBAToUVRow)(const uint8* src_rgba0, int src_stride_rgba, uint8* dst_u, 847 uint8* dst_v, int width) = RGBAToUVRow_C; 848 void (*RGBAToYRow)(const uint8* src_rgba, uint8* dst_y, int width) = 849 RGBAToYRow_C; 850 if (!src_rgba || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { 851 return -1; 852 } 853 // Negative height means invert the image. 854 if (height < 0) { 855 height = -height; 856 src_rgba = src_rgba + (height - 1) * src_stride_rgba; 857 src_stride_rgba = -src_stride_rgba; 858 } 859#if defined(HAS_RGBATOYROW_SSSE3) && defined(HAS_RGBATOUVROW_SSSE3) 860 if (TestCpuFlag(kCpuHasSSSE3)) { 861 RGBAToUVRow = RGBAToUVRow_Any_SSSE3; 862 RGBAToYRow = RGBAToYRow_Any_SSSE3; 863 if (IS_ALIGNED(width, 16)) { 864 RGBAToUVRow = RGBAToUVRow_SSSE3; 865 RGBAToYRow = RGBAToYRow_SSSE3; 866 } 867 } 868#endif 869#if defined(HAS_RGBATOYROW_NEON) 870 if (TestCpuFlag(kCpuHasNEON)) { 871 RGBAToYRow = RGBAToYRow_Any_NEON; 872 if (IS_ALIGNED(width, 8)) { 873 RGBAToYRow = RGBAToYRow_NEON; 874 } 875 } 876#endif 877#if defined(HAS_RGBATOUVROW_NEON) 878 if (TestCpuFlag(kCpuHasNEON)) { 879 RGBAToUVRow = RGBAToUVRow_Any_NEON; 880 if (IS_ALIGNED(width, 16)) { 881 RGBAToUVRow = RGBAToUVRow_NEON; 882 } 883 } 884#endif 885#if defined(HAS_RGBATOYROW_DSPR2) 886 if (TestCpuFlag(kCpuHasDSPR2)) { 887 RGBAToYRow = RGBAToYRow_Any_DSPR2; 888 if (IS_ALIGNED(width, 8)) { 889 RGBAToYRow = RGBAToYRow_DSPR2; 890 } 891 } 892#endif 893#if defined(HAS_RGBATOUVROW_DSPR2) 894 if (TestCpuFlag(kCpuHasDSPR2)) { 895 RGBAToUVRow = RGBAToUVRow_Any_DSPR2; 896 if (IS_ALIGNED(width, 16)) { 897 RGBAToUVRow = RGBAToUVRow_DSPR2; 898 } 899 } 900#endif 901#if defined(HAS_RGBATOYROW_MSA) 902 if (TestCpuFlag(kCpuHasMSA)) { 903 RGBAToYRow = RGBAToYRow_Any_MSA; 904 if (IS_ALIGNED(width, 16)) { 905 RGBAToYRow = RGBAToYRow_MSA; 906 } 907 } 908#endif 909#if defined(HAS_RGBATOUVROW_MSA) 910 if (TestCpuFlag(kCpuHasMSA)) { 911 RGBAToUVRow = RGBAToUVRow_Any_MSA; 912 if (IS_ALIGNED(width, 16)) { 913 RGBAToUVRow = RGBAToUVRow_MSA; 914 } 915 } 916#endif 917 918 for (y = 0; y < height - 1; y += 2) { 919 RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width); 920 RGBAToYRow(src_rgba, dst_y, width); 921 RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width); 922 src_rgba += src_stride_rgba * 2; 923 dst_y += dst_stride_y * 2; 924 dst_u += dst_stride_u; 925 dst_v += dst_stride_v; 926 } 927 if (height & 1) { 928 RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width); 929 RGBAToYRow(src_rgba, dst_y, width); 930 } 931 return 0; 932} 933 934// Convert RGB24 to I420. 935LIBYUV_API 936int RGB24ToI420(const uint8* src_rgb24, 937 int src_stride_rgb24, 938 uint8* dst_y, 939 int dst_stride_y, 940 uint8* dst_u, 941 int dst_stride_u, 942 uint8* dst_v, 943 int dst_stride_v, 944 int width, 945 int height) { 946 int y; 947#if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA)) 948 void (*RGB24ToUVRow)(const uint8* src_rgb24, int src_stride_rgb24, 949 uint8* dst_u, uint8* dst_v, int width) = RGB24ToUVRow_C; 950 void (*RGB24ToYRow)(const uint8* src_rgb24, uint8* dst_y, int width) = 951 RGB24ToYRow_C; 952#else 953 void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) = 954 RGB24ToARGBRow_C; 955 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u, 956 uint8* dst_v, int width) = ARGBToUVRow_C; 957 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = 958 ARGBToYRow_C; 959#endif 960 if (!src_rgb24 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { 961 return -1; 962 } 963 // Negative height means invert the image. 964 if (height < 0) { 965 height = -height; 966 src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24; 967 src_stride_rgb24 = -src_stride_rgb24; 968 } 969 970// Neon version does direct RGB24 to YUV. 971#if defined(HAS_RGB24TOYROW_NEON) 972 if (TestCpuFlag(kCpuHasNEON)) { 973 RGB24ToUVRow = RGB24ToUVRow_Any_NEON; 974 RGB24ToYRow = RGB24ToYRow_Any_NEON; 975 if (IS_ALIGNED(width, 8)) { 976 RGB24ToYRow = RGB24ToYRow_NEON; 977 if (IS_ALIGNED(width, 16)) { 978 RGB24ToUVRow = RGB24ToUVRow_NEON; 979 } 980 } 981 } 982#elif defined(HAS_RGB24TOYROW_MSA) 983 if (TestCpuFlag(kCpuHasMSA)) { 984 RGB24ToUVRow = RGB24ToUVRow_Any_MSA; 985 RGB24ToYRow = RGB24ToYRow_Any_MSA; 986 if (IS_ALIGNED(width, 16)) { 987 RGB24ToYRow = RGB24ToYRow_MSA; 988 RGB24ToUVRow = RGB24ToUVRow_MSA; 989 } 990 } 991// Other platforms do intermediate conversion from RGB24 to ARGB. 992#else 993#if defined(HAS_RGB24TOARGBROW_SSSE3) 994 if (TestCpuFlag(kCpuHasSSSE3)) { 995 RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3; 996 if (IS_ALIGNED(width, 16)) { 997 RGB24ToARGBRow = RGB24ToARGBRow_SSSE3; 998 } 999 } 1000#endif 1001#if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) 1002 if (TestCpuFlag(kCpuHasSSSE3)) { 1003 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1004 ARGBToYRow = ARGBToYRow_Any_SSSE3; 1005 if (IS_ALIGNED(width, 16)) { 1006 ARGBToUVRow = ARGBToUVRow_SSSE3; 1007 ARGBToYRow = ARGBToYRow_SSSE3; 1008 } 1009 } 1010#endif 1011#if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) 1012 if (TestCpuFlag(kCpuHasAVX2)) { 1013 ARGBToUVRow = ARGBToUVRow_Any_AVX2; 1014 ARGBToYRow = ARGBToYRow_Any_AVX2; 1015 if (IS_ALIGNED(width, 32)) { 1016 ARGBToUVRow = ARGBToUVRow_AVX2; 1017 ARGBToYRow = ARGBToYRow_AVX2; 1018 } 1019 } 1020#endif 1021#endif 1022 1023 { 1024#if !(defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA)) 1025 // Allocate 2 rows of ARGB. 1026 const int kRowSize = (width * 4 + 31) & ~31; 1027 align_buffer_64(row, kRowSize * 2); 1028#endif 1029 1030 for (y = 0; y < height - 1; y += 2) { 1031#if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA)) 1032 RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width); 1033 RGB24ToYRow(src_rgb24, dst_y, width); 1034 RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width); 1035#else 1036 RGB24ToARGBRow(src_rgb24, row, width); 1037 RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width); 1038 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1039 ARGBToYRow(row, dst_y, width); 1040 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1041#endif 1042 src_rgb24 += src_stride_rgb24 * 2; 1043 dst_y += dst_stride_y * 2; 1044 dst_u += dst_stride_u; 1045 dst_v += dst_stride_v; 1046 } 1047 if (height & 1) { 1048#if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA)) 1049 RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width); 1050 RGB24ToYRow(src_rgb24, dst_y, width); 1051#else 1052 RGB24ToARGBRow(src_rgb24, row, width); 1053 ARGBToUVRow(row, 0, dst_u, dst_v, width); 1054 ARGBToYRow(row, dst_y, width); 1055#endif 1056 } 1057#if !(defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA)) 1058 free_aligned_buffer_64(row); 1059#endif 1060 } 1061 return 0; 1062} 1063 1064// Convert RAW to I420. 1065LIBYUV_API 1066int RAWToI420(const uint8* src_raw, 1067 int src_stride_raw, 1068 uint8* dst_y, 1069 int dst_stride_y, 1070 uint8* dst_u, 1071 int dst_stride_u, 1072 uint8* dst_v, 1073 int dst_stride_v, 1074 int width, 1075 int height) { 1076 int y; 1077#if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA)) 1078 void (*RAWToUVRow)(const uint8* src_raw, int src_stride_raw, uint8* dst_u, 1079 uint8* dst_v, int width) = RAWToUVRow_C; 1080 void (*RAWToYRow)(const uint8* src_raw, uint8* dst_y, int width) = 1081 RAWToYRow_C; 1082#else 1083 void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) = 1084 RAWToARGBRow_C; 1085 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u, 1086 uint8* dst_v, int width) = ARGBToUVRow_C; 1087 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = 1088 ARGBToYRow_C; 1089#endif 1090 if (!src_raw || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { 1091 return -1; 1092 } 1093 // Negative height means invert the image. 1094 if (height < 0) { 1095 height = -height; 1096 src_raw = src_raw + (height - 1) * src_stride_raw; 1097 src_stride_raw = -src_stride_raw; 1098 } 1099 1100// Neon version does direct RAW to YUV. 1101#if defined(HAS_RAWTOYROW_NEON) 1102 if (TestCpuFlag(kCpuHasNEON)) { 1103 RAWToUVRow = RAWToUVRow_Any_NEON; 1104 RAWToYRow = RAWToYRow_Any_NEON; 1105 if (IS_ALIGNED(width, 8)) { 1106 RAWToYRow = RAWToYRow_NEON; 1107 if (IS_ALIGNED(width, 16)) { 1108 RAWToUVRow = RAWToUVRow_NEON; 1109 } 1110 } 1111 } 1112#elif defined(HAS_RAWTOYROW_MSA) 1113 if (TestCpuFlag(kCpuHasMSA)) { 1114 RAWToUVRow = RAWToUVRow_Any_MSA; 1115 RAWToYRow = RAWToYRow_Any_MSA; 1116 if (IS_ALIGNED(width, 16)) { 1117 RAWToYRow = RAWToYRow_MSA; 1118 RAWToUVRow = RAWToUVRow_MSA; 1119 } 1120 } 1121// Other platforms do intermediate conversion from RAW to ARGB. 1122#else 1123#if defined(HAS_RAWTOARGBROW_SSSE3) 1124 if (TestCpuFlag(kCpuHasSSSE3)) { 1125 RAWToARGBRow = RAWToARGBRow_Any_SSSE3; 1126 if (IS_ALIGNED(width, 16)) { 1127 RAWToARGBRow = RAWToARGBRow_SSSE3; 1128 } 1129 } 1130#endif 1131#if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) 1132 if (TestCpuFlag(kCpuHasSSSE3)) { 1133 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1134 ARGBToYRow = ARGBToYRow_Any_SSSE3; 1135 if (IS_ALIGNED(width, 16)) { 1136 ARGBToUVRow = ARGBToUVRow_SSSE3; 1137 ARGBToYRow = ARGBToYRow_SSSE3; 1138 } 1139 } 1140#endif 1141#if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) 1142 if (TestCpuFlag(kCpuHasAVX2)) { 1143 ARGBToUVRow = ARGBToUVRow_Any_AVX2; 1144 ARGBToYRow = ARGBToYRow_Any_AVX2; 1145 if (IS_ALIGNED(width, 32)) { 1146 ARGBToUVRow = ARGBToUVRow_AVX2; 1147 ARGBToYRow = ARGBToYRow_AVX2; 1148 } 1149 } 1150#endif 1151#endif 1152 1153 { 1154#if !(defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA)) 1155 // Allocate 2 rows of ARGB. 1156 const int kRowSize = (width * 4 + 31) & ~31; 1157 align_buffer_64(row, kRowSize * 2); 1158#endif 1159 1160 for (y = 0; y < height - 1; y += 2) { 1161#if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA)) 1162 RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width); 1163 RAWToYRow(src_raw, dst_y, width); 1164 RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width); 1165#else 1166 RAWToARGBRow(src_raw, row, width); 1167 RAWToARGBRow(src_raw + src_stride_raw, row + kRowSize, width); 1168 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1169 ARGBToYRow(row, dst_y, width); 1170 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1171#endif 1172 src_raw += src_stride_raw * 2; 1173 dst_y += dst_stride_y * 2; 1174 dst_u += dst_stride_u; 1175 dst_v += dst_stride_v; 1176 } 1177 if (height & 1) { 1178#if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA)) 1179 RAWToUVRow(src_raw, 0, dst_u, dst_v, width); 1180 RAWToYRow(src_raw, dst_y, width); 1181#else 1182 RAWToARGBRow(src_raw, row, width); 1183 ARGBToUVRow(row, 0, dst_u, dst_v, width); 1184 ARGBToYRow(row, dst_y, width); 1185#endif 1186 } 1187#if !(defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA)) 1188 free_aligned_buffer_64(row); 1189#endif 1190 } 1191 return 0; 1192} 1193 1194// Convert RGB565 to I420. 1195LIBYUV_API 1196int RGB565ToI420(const uint8* src_rgb565, 1197 int src_stride_rgb565, 1198 uint8* dst_y, 1199 int dst_stride_y, 1200 uint8* dst_u, 1201 int dst_stride_u, 1202 uint8* dst_v, 1203 int dst_stride_v, 1204 int width, 1205 int height) { 1206 int y; 1207#if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA)) 1208 void (*RGB565ToUVRow)(const uint8* src_rgb565, int src_stride_rgb565, 1209 uint8* dst_u, uint8* dst_v, int width) = 1210 RGB565ToUVRow_C; 1211 void (*RGB565ToYRow)(const uint8* src_rgb565, uint8* dst_y, int width) = 1212 RGB565ToYRow_C; 1213#else 1214 void (*RGB565ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) = 1215 RGB565ToARGBRow_C; 1216 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u, 1217 uint8* dst_v, int width) = ARGBToUVRow_C; 1218 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = 1219 ARGBToYRow_C; 1220#endif 1221 if (!src_rgb565 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { 1222 return -1; 1223 } 1224 // Negative height means invert the image. 1225 if (height < 0) { 1226 height = -height; 1227 src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565; 1228 src_stride_rgb565 = -src_stride_rgb565; 1229 } 1230 1231// Neon version does direct RGB565 to YUV. 1232#if defined(HAS_RGB565TOYROW_NEON) 1233 if (TestCpuFlag(kCpuHasNEON)) { 1234 RGB565ToUVRow = RGB565ToUVRow_Any_NEON; 1235 RGB565ToYRow = RGB565ToYRow_Any_NEON; 1236 if (IS_ALIGNED(width, 8)) { 1237 RGB565ToYRow = RGB565ToYRow_NEON; 1238 if (IS_ALIGNED(width, 16)) { 1239 RGB565ToUVRow = RGB565ToUVRow_NEON; 1240 } 1241 } 1242 } 1243#elif defined(HAS_RGB565TOYROW_MSA) 1244 if (TestCpuFlag(kCpuHasMSA)) { 1245 RGB565ToUVRow = RGB565ToUVRow_Any_MSA; 1246 RGB565ToYRow = RGB565ToYRow_Any_MSA; 1247 if (IS_ALIGNED(width, 16)) { 1248 RGB565ToYRow = RGB565ToYRow_MSA; 1249 RGB565ToUVRow = RGB565ToUVRow_MSA; 1250 } 1251 } 1252// Other platforms do intermediate conversion from RGB565 to ARGB. 1253#else 1254#if defined(HAS_RGB565TOARGBROW_SSE2) 1255 if (TestCpuFlag(kCpuHasSSE2)) { 1256 RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2; 1257 if (IS_ALIGNED(width, 8)) { 1258 RGB565ToARGBRow = RGB565ToARGBRow_SSE2; 1259 } 1260 } 1261#endif 1262#if defined(HAS_RGB565TOARGBROW_AVX2) 1263 if (TestCpuFlag(kCpuHasAVX2)) { 1264 RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2; 1265 if (IS_ALIGNED(width, 16)) { 1266 RGB565ToARGBRow = RGB565ToARGBRow_AVX2; 1267 } 1268 } 1269#endif 1270#if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) 1271 if (TestCpuFlag(kCpuHasSSSE3)) { 1272 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1273 ARGBToYRow = ARGBToYRow_Any_SSSE3; 1274 if (IS_ALIGNED(width, 16)) { 1275 ARGBToUVRow = ARGBToUVRow_SSSE3; 1276 ARGBToYRow = ARGBToYRow_SSSE3; 1277 } 1278 } 1279#endif 1280#if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) 1281 if (TestCpuFlag(kCpuHasAVX2)) { 1282 ARGBToUVRow = ARGBToUVRow_Any_AVX2; 1283 ARGBToYRow = ARGBToYRow_Any_AVX2; 1284 if (IS_ALIGNED(width, 32)) { 1285 ARGBToUVRow = ARGBToUVRow_AVX2; 1286 ARGBToYRow = ARGBToYRow_AVX2; 1287 } 1288 } 1289#endif 1290#if defined(HAS_RGB565TOARGBROW_DSPR2) 1291 if (TestCpuFlag(kCpuHasDSPR2)) { 1292 RGB565ToARGBRow = RGB565ToARGBRow_Any_DSPR2; 1293 if (IS_ALIGNED(width, 8)) { 1294 RGB565ToARGBRow = RGB565ToARGBRow_DSPR2; 1295 } 1296 } 1297#endif 1298#endif 1299 { 1300#if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA)) 1301 // Allocate 2 rows of ARGB. 1302 const int kRowSize = (width * 4 + 31) & ~31; 1303 align_buffer_64(row, kRowSize * 2); 1304#endif 1305 for (y = 0; y < height - 1; y += 2) { 1306#if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA)) 1307 RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width); 1308 RGB565ToYRow(src_rgb565, dst_y, width); 1309 RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width); 1310#else 1311 RGB565ToARGBRow(src_rgb565, row, width); 1312 RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kRowSize, width); 1313 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1314 ARGBToYRow(row, dst_y, width); 1315 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1316#endif 1317 src_rgb565 += src_stride_rgb565 * 2; 1318 dst_y += dst_stride_y * 2; 1319 dst_u += dst_stride_u; 1320 dst_v += dst_stride_v; 1321 } 1322 if (height & 1) { 1323#if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA)) 1324 RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width); 1325 RGB565ToYRow(src_rgb565, dst_y, width); 1326#else 1327 RGB565ToARGBRow(src_rgb565, row, width); 1328 ARGBToUVRow(row, 0, dst_u, dst_v, width); 1329 ARGBToYRow(row, dst_y, width); 1330#endif 1331 } 1332#if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA)) 1333 free_aligned_buffer_64(row); 1334#endif 1335 } 1336 return 0; 1337} 1338 1339// Convert ARGB1555 to I420. 1340LIBYUV_API 1341int ARGB1555ToI420(const uint8* src_argb1555, 1342 int src_stride_argb1555, 1343 uint8* dst_y, 1344 int dst_stride_y, 1345 uint8* dst_u, 1346 int dst_stride_u, 1347 uint8* dst_v, 1348 int dst_stride_v, 1349 int width, 1350 int height) { 1351 int y; 1352#if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA)) 1353 void (*ARGB1555ToUVRow)(const uint8* src_argb1555, int src_stride_argb1555, 1354 uint8* dst_u, uint8* dst_v, int width) = 1355 ARGB1555ToUVRow_C; 1356 void (*ARGB1555ToYRow)(const uint8* src_argb1555, uint8* dst_y, int width) = 1357 ARGB1555ToYRow_C; 1358#else 1359 void (*ARGB1555ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) = 1360 ARGB1555ToARGBRow_C; 1361 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u, 1362 uint8* dst_v, int width) = ARGBToUVRow_C; 1363 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = 1364 ARGBToYRow_C; 1365#endif 1366 if (!src_argb1555 || !dst_y || !dst_u || !dst_v || width <= 0 || 1367 height == 0) { 1368 return -1; 1369 } 1370 // Negative height means invert the image. 1371 if (height < 0) { 1372 height = -height; 1373 src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555; 1374 src_stride_argb1555 = -src_stride_argb1555; 1375 } 1376 1377// Neon version does direct ARGB1555 to YUV. 1378#if defined(HAS_ARGB1555TOYROW_NEON) 1379 if (TestCpuFlag(kCpuHasNEON)) { 1380 ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON; 1381 ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON; 1382 if (IS_ALIGNED(width, 8)) { 1383 ARGB1555ToYRow = ARGB1555ToYRow_NEON; 1384 if (IS_ALIGNED(width, 16)) { 1385 ARGB1555ToUVRow = ARGB1555ToUVRow_NEON; 1386 } 1387 } 1388 } 1389#elif defined(HAS_ARGB1555TOYROW_MSA) 1390 if (TestCpuFlag(kCpuHasMSA)) { 1391 ARGB1555ToUVRow = ARGB1555ToUVRow_Any_MSA; 1392 ARGB1555ToYRow = ARGB1555ToYRow_Any_MSA; 1393 if (IS_ALIGNED(width, 16)) { 1394 ARGB1555ToYRow = ARGB1555ToYRow_MSA; 1395 ARGB1555ToUVRow = ARGB1555ToUVRow_MSA; 1396 } 1397 } 1398// Other platforms do intermediate conversion from ARGB1555 to ARGB. 1399#else 1400#if defined(HAS_ARGB1555TOARGBROW_SSE2) 1401 if (TestCpuFlag(kCpuHasSSE2)) { 1402 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2; 1403 if (IS_ALIGNED(width, 8)) { 1404 ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2; 1405 } 1406 } 1407#endif 1408#if defined(HAS_ARGB1555TOARGBROW_AVX2) 1409 if (TestCpuFlag(kCpuHasAVX2)) { 1410 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2; 1411 if (IS_ALIGNED(width, 16)) { 1412 ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2; 1413 } 1414 } 1415#endif 1416#if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) 1417 if (TestCpuFlag(kCpuHasSSSE3)) { 1418 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1419 ARGBToYRow = ARGBToYRow_Any_SSSE3; 1420 if (IS_ALIGNED(width, 16)) { 1421 ARGBToUVRow = ARGBToUVRow_SSSE3; 1422 ARGBToYRow = ARGBToYRow_SSSE3; 1423 } 1424 } 1425#endif 1426#if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) 1427 if (TestCpuFlag(kCpuHasAVX2)) { 1428 ARGBToUVRow = ARGBToUVRow_Any_AVX2; 1429 ARGBToYRow = ARGBToYRow_Any_AVX2; 1430 if (IS_ALIGNED(width, 32)) { 1431 ARGBToUVRow = ARGBToUVRow_AVX2; 1432 ARGBToYRow = ARGBToYRow_AVX2; 1433 } 1434 } 1435#endif 1436#endif 1437 { 1438#if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA)) 1439 // Allocate 2 rows of ARGB. 1440 const int kRowSize = (width * 4 + 31) & ~31; 1441 align_buffer_64(row, kRowSize * 2); 1442#endif 1443 1444 for (y = 0; y < height - 1; y += 2) { 1445#if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA)) 1446 ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width); 1447 ARGB1555ToYRow(src_argb1555, dst_y, width); 1448 ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y, 1449 width); 1450#else 1451 ARGB1555ToARGBRow(src_argb1555, row, width); 1452 ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize, 1453 width); 1454 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1455 ARGBToYRow(row, dst_y, width); 1456 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1457#endif 1458 src_argb1555 += src_stride_argb1555 * 2; 1459 dst_y += dst_stride_y * 2; 1460 dst_u += dst_stride_u; 1461 dst_v += dst_stride_v; 1462 } 1463 if (height & 1) { 1464#if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA)) 1465 ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width); 1466 ARGB1555ToYRow(src_argb1555, dst_y, width); 1467#else 1468 ARGB1555ToARGBRow(src_argb1555, row, width); 1469 ARGBToUVRow(row, 0, dst_u, dst_v, width); 1470 ARGBToYRow(row, dst_y, width); 1471#endif 1472 } 1473#if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA)) 1474 free_aligned_buffer_64(row); 1475#endif 1476 } 1477 return 0; 1478} 1479 1480// Convert ARGB4444 to I420. 1481LIBYUV_API 1482int ARGB4444ToI420(const uint8* src_argb4444, 1483 int src_stride_argb4444, 1484 uint8* dst_y, 1485 int dst_stride_y, 1486 uint8* dst_u, 1487 int dst_stride_u, 1488 uint8* dst_v, 1489 int dst_stride_v, 1490 int width, 1491 int height) { 1492 int y; 1493#if defined(HAS_ARGB4444TOYROW_NEON) 1494 void (*ARGB4444ToUVRow)(const uint8* src_argb4444, int src_stride_argb4444, 1495 uint8* dst_u, uint8* dst_v, int width) = 1496 ARGB4444ToUVRow_C; 1497 void (*ARGB4444ToYRow)(const uint8* src_argb4444, uint8* dst_y, int width) = 1498 ARGB4444ToYRow_C; 1499#else 1500 void (*ARGB4444ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) = 1501 ARGB4444ToARGBRow_C; 1502 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u, 1503 uint8* dst_v, int width) = ARGBToUVRow_C; 1504 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = 1505 ARGBToYRow_C; 1506#endif 1507 if (!src_argb4444 || !dst_y || !dst_u || !dst_v || width <= 0 || 1508 height == 0) { 1509 return -1; 1510 } 1511 // Negative height means invert the image. 1512 if (height < 0) { 1513 height = -height; 1514 src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444; 1515 src_stride_argb4444 = -src_stride_argb4444; 1516 } 1517 1518// Neon version does direct ARGB4444 to YUV. 1519#if defined(HAS_ARGB4444TOYROW_NEON) 1520 if (TestCpuFlag(kCpuHasNEON)) { 1521 ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON; 1522 ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON; 1523 if (IS_ALIGNED(width, 8)) { 1524 ARGB4444ToYRow = ARGB4444ToYRow_NEON; 1525 if (IS_ALIGNED(width, 16)) { 1526 ARGB4444ToUVRow = ARGB4444ToUVRow_NEON; 1527 } 1528 } 1529 } 1530// Other platforms do intermediate conversion from ARGB4444 to ARGB. 1531#else 1532#if defined(HAS_ARGB4444TOARGBROW_SSE2) 1533 if (TestCpuFlag(kCpuHasSSE2)) { 1534 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2; 1535 if (IS_ALIGNED(width, 8)) { 1536 ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2; 1537 } 1538 } 1539#endif 1540#if defined(HAS_ARGB4444TOARGBROW_AVX2) 1541 if (TestCpuFlag(kCpuHasAVX2)) { 1542 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2; 1543 if (IS_ALIGNED(width, 16)) { 1544 ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2; 1545 } 1546 } 1547#endif 1548#if defined(HAS_ARGB4444TOARGBROW_MSA) 1549 if (TestCpuFlag(kCpuHasMSA)) { 1550 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MSA; 1551 if (IS_ALIGNED(width, 16)) { 1552 ARGB4444ToARGBRow = ARGB4444ToARGBRow_MSA; 1553 } 1554 } 1555#endif 1556#if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) 1557 if (TestCpuFlag(kCpuHasSSSE3)) { 1558 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1559 ARGBToYRow = ARGBToYRow_Any_SSSE3; 1560 if (IS_ALIGNED(width, 16)) { 1561 ARGBToUVRow = ARGBToUVRow_SSSE3; 1562 ARGBToYRow = ARGBToYRow_SSSE3; 1563 } 1564 } 1565#endif 1566#if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) 1567 if (TestCpuFlag(kCpuHasAVX2)) { 1568 ARGBToUVRow = ARGBToUVRow_Any_AVX2; 1569 ARGBToYRow = ARGBToYRow_Any_AVX2; 1570 if (IS_ALIGNED(width, 32)) { 1571 ARGBToUVRow = ARGBToUVRow_AVX2; 1572 ARGBToYRow = ARGBToYRow_AVX2; 1573 } 1574 } 1575#endif 1576#if defined(HAS_ARGBTOYROW_MSA) 1577 if (TestCpuFlag(kCpuHasMSA)) { 1578 ARGBToUVRow = ARGBToUVRow_Any_MSA; 1579 ARGBToYRow = ARGBToYRow_Any_MSA; 1580 if (IS_ALIGNED(width, 16)) { 1581 ARGBToYRow = ARGBToYRow_MSA; 1582 if (IS_ALIGNED(width, 32)) { 1583 ARGBToUVRow = ARGBToUVRow_MSA; 1584 } 1585 } 1586 } 1587#endif 1588#endif 1589 1590 { 1591#if !defined(HAS_ARGB4444TOYROW_NEON) 1592 // Allocate 2 rows of ARGB. 1593 const int kRowSize = (width * 4 + 31) & ~31; 1594 align_buffer_64(row, kRowSize * 2); 1595#endif 1596 1597 for (y = 0; y < height - 1; y += 2) { 1598#if defined(HAS_ARGB4444TOYROW_NEON) 1599 ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width); 1600 ARGB4444ToYRow(src_argb4444, dst_y, width); 1601 ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y, 1602 width); 1603#else 1604 ARGB4444ToARGBRow(src_argb4444, row, width); 1605 ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kRowSize, 1606 width); 1607 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1608 ARGBToYRow(row, dst_y, width); 1609 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1610#endif 1611 src_argb4444 += src_stride_argb4444 * 2; 1612 dst_y += dst_stride_y * 2; 1613 dst_u += dst_stride_u; 1614 dst_v += dst_stride_v; 1615 } 1616 if (height & 1) { 1617#if defined(HAS_ARGB4444TOYROW_NEON) 1618 ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width); 1619 ARGB4444ToYRow(src_argb4444, dst_y, width); 1620#else 1621 ARGB4444ToARGBRow(src_argb4444, row, width); 1622 ARGBToUVRow(row, 0, dst_u, dst_v, width); 1623 ARGBToYRow(row, dst_y, width); 1624#endif 1625 } 1626#if !defined(HAS_ARGB4444TOYROW_NEON) 1627 free_aligned_buffer_64(row); 1628#endif 1629 } 1630 return 0; 1631} 1632 1633static void SplitPixels(const uint8* src_u, 1634 int src_pixel_stride_uv, 1635 uint8* dst_u, 1636 int width) { 1637 int i; 1638 for (i = 0; i < width; ++i) { 1639 *dst_u = *src_u; 1640 ++dst_u; 1641 src_u += src_pixel_stride_uv; 1642 } 1643} 1644 1645// Convert Android420 to I420. 1646LIBYUV_API 1647int Android420ToI420(const uint8* src_y, 1648 int src_stride_y, 1649 const uint8* src_u, 1650 int src_stride_u, 1651 const uint8* src_v, 1652 int src_stride_v, 1653 int src_pixel_stride_uv, 1654 uint8* dst_y, 1655 int dst_stride_y, 1656 uint8* dst_u, 1657 int dst_stride_u, 1658 uint8* dst_v, 1659 int dst_stride_v, 1660 int width, 1661 int height) { 1662 int y; 1663 const ptrdiff_t vu_off = src_v - src_u; 1664 int halfwidth = (width + 1) >> 1; 1665 int halfheight = (height + 1) >> 1; 1666 if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) { 1667 return -1; 1668 } 1669 // Negative height means invert the image. 1670 if (height < 0) { 1671 height = -height; 1672 halfheight = (height + 1) >> 1; 1673 src_y = src_y + (height - 1) * src_stride_y; 1674 src_u = src_u + (halfheight - 1) * src_stride_u; 1675 src_v = src_v + (halfheight - 1) * src_stride_v; 1676 src_stride_y = -src_stride_y; 1677 src_stride_u = -src_stride_u; 1678 src_stride_v = -src_stride_v; 1679 } 1680 1681 if (dst_y) { 1682 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); 1683 } 1684 1685 // Copy UV planes as is - I420 1686 if (src_pixel_stride_uv == 1) { 1687 CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight); 1688 CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight); 1689 return 0; 1690 // Split UV planes - NV21 1691 } else if (src_pixel_stride_uv == 2 && vu_off == -1 && 1692 src_stride_u == src_stride_v) { 1693 SplitUVPlane(src_v, src_stride_v, dst_v, dst_stride_v, dst_u, dst_stride_u, 1694 halfwidth, halfheight); 1695 return 0; 1696 // Split UV planes - NV12 1697 } else if (src_pixel_stride_uv == 2 && vu_off == 1 && 1698 src_stride_u == src_stride_v) { 1699 SplitUVPlane(src_u, src_stride_u, dst_u, dst_stride_u, dst_v, dst_stride_v, 1700 halfwidth, halfheight); 1701 return 0; 1702 } 1703 1704 for (y = 0; y < halfheight; ++y) { 1705 SplitPixels(src_u, src_pixel_stride_uv, dst_u, halfwidth); 1706 SplitPixels(src_v, src_pixel_stride_uv, dst_v, halfwidth); 1707 src_u += src_stride_u; 1708 src_v += src_stride_v; 1709 dst_u += dst_stride_u; 1710 dst_v += dst_stride_v; 1711 } 1712 return 0; 1713} 1714 1715#ifdef __cplusplus 1716} // extern "C" 1717} // namespace libyuv 1718#endif 1719