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