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