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_X86) 192 if (TestCpuFlag(kCpuHasX86) && IS_ALIGNED(width, 4)) { 193 CopyRow = CopyRow_X86; 194 } 195#endif 196#if defined(HAS_COPYROW_SSE2) 197 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32) && 198 IS_ALIGNED(src, 16) && 199 IS_ALIGNED(src_stride_0, 16) && IS_ALIGNED(src_stride_1, 16) && 200 IS_ALIGNED(dst, 16) && IS_ALIGNED(dst_stride, 16)) { 201 CopyRow = CopyRow_SSE2; 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) && IS_ALIGNED(width, 32)) { 211 CopyRow = CopyRow_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 y; 249 int halfwidth = (width + 1) >> 1; 250 int halfheight = (height + 1) >> 1; 251 void (*SplitUVRow)(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix) = 252 SplitUVRow_C; 253 if (!src_y || !src_uv || 254 !dst_y || !dst_u || !dst_v || 255 width <= 0 || height == 0) { 256 return -1; 257 } 258 // Negative height means invert the image. 259 if (height < 0) { 260 height = -height; 261 halfheight = (height + 1) >> 1; 262 dst_y = dst_y + (height - 1) * dst_stride_y; 263 dst_u = dst_u + (halfheight - 1) * dst_stride_u; 264 dst_v = dst_v + (halfheight - 1) * dst_stride_v; 265 dst_stride_y = -dst_stride_y; 266 dst_stride_u = -dst_stride_u; 267 dst_stride_v = -dst_stride_v; 268 } 269 // Coalesce rows. 270 if (src_stride_y0 == width && 271 src_stride_y1 == width && 272 dst_stride_y == width) { 273 width *= height; 274 height = 1; 275 src_stride_y0 = src_stride_y1 = dst_stride_y = 0; 276 } 277 // Coalesce rows. 278 if (src_stride_uv == halfwidth * 2 && 279 dst_stride_u == halfwidth && 280 dst_stride_v == halfwidth) { 281 halfwidth *= halfheight; 282 halfheight = 1; 283 src_stride_uv = dst_stride_u = dst_stride_v = 0; 284 } 285#if defined(HAS_SPLITUVROW_SSE2) 286 if (TestCpuFlag(kCpuHasSSE2) && halfwidth >= 16) { 287 SplitUVRow = SplitUVRow_Any_SSE2; 288 if (IS_ALIGNED(halfwidth, 16)) { 289 SplitUVRow = SplitUVRow_Unaligned_SSE2; 290 if (IS_ALIGNED(src_uv, 16) && IS_ALIGNED(src_stride_uv, 16) && 291 IS_ALIGNED(dst_u, 16) && IS_ALIGNED(dst_stride_u, 16) && 292 IS_ALIGNED(dst_v, 16) && IS_ALIGNED(dst_stride_v, 16)) { 293 SplitUVRow = SplitUVRow_SSE2; 294 } 295 } 296 } 297#endif 298#if defined(HAS_SPLITUVROW_AVX2) 299 if (TestCpuFlag(kCpuHasAVX2) && halfwidth >= 32) { 300 SplitUVRow = SplitUVRow_Any_AVX2; 301 if (IS_ALIGNED(halfwidth, 32)) { 302 SplitUVRow = SplitUVRow_AVX2; 303 } 304 } 305#endif 306#if defined(HAS_SPLITUVROW_NEON) 307 if (TestCpuFlag(kCpuHasNEON) && halfwidth >= 16) { 308 SplitUVRow = SplitUVRow_Any_NEON; 309 if (IS_ALIGNED(halfwidth, 16)) { 310 SplitUVRow = SplitUVRow_NEON; 311 } 312 } 313#endif 314#if defined(HAS_SPLITUVROW_MIPS_DSPR2) 315 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && halfwidth >= 16) { 316 SplitUVRow = SplitUVRow_Any_MIPS_DSPR2; 317 if (IS_ALIGNED(halfwidth, 16)) { 318 SplitUVRow = SplitUVRow_Unaligned_MIPS_DSPR2; 319 if (IS_ALIGNED(src_uv, 4) && IS_ALIGNED(src_stride_uv, 4) && 320 IS_ALIGNED(dst_u, 4) && IS_ALIGNED(dst_stride_u, 4) && 321 IS_ALIGNED(dst_v, 4) && IS_ALIGNED(dst_stride_v, 4)) { 322 SplitUVRow = SplitUVRow_MIPS_DSPR2; 323 } 324 } 325 } 326#endif 327 328 if (dst_y) { 329 if (src_stride_y0 == src_stride_y1) { 330 CopyPlane(src_y, src_stride_y0, dst_y, dst_stride_y, width, height); 331 } else { 332 CopyPlane2(src_y, src_stride_y0, src_stride_y1, dst_y, dst_stride_y, 333 width, height); 334 } 335 } 336 337 for (y = 0; y < halfheight; ++y) { 338 // Copy a row of UV. 339 SplitUVRow(src_uv, dst_u, dst_v, halfwidth); 340 dst_u += dst_stride_u; 341 dst_v += dst_stride_v; 342 src_uv += src_stride_uv; 343 } 344 return 0; 345} 346 347// Convert NV12 to I420. 348LIBYUV_API 349int NV12ToI420(const uint8* src_y, int src_stride_y, 350 const uint8* src_uv, int src_stride_uv, 351 uint8* dst_y, int dst_stride_y, 352 uint8* dst_u, int dst_stride_u, 353 uint8* dst_v, int dst_stride_v, 354 int width, int height) { 355 return X420ToI420(src_y, src_stride_y, src_stride_y, 356 src_uv, src_stride_uv, 357 dst_y, dst_stride_y, 358 dst_u, dst_stride_u, 359 dst_v, dst_stride_v, 360 width, height); 361} 362 363// Convert NV21 to I420. Same as NV12 but u and v pointers swapped. 364LIBYUV_API 365int NV21ToI420(const uint8* src_y, int src_stride_y, 366 const uint8* src_vu, int src_stride_vu, 367 uint8* dst_y, int dst_stride_y, 368 uint8* dst_u, int dst_stride_u, 369 uint8* dst_v, int dst_stride_v, 370 int width, int height) { 371 return X420ToI420(src_y, src_stride_y, src_stride_y, 372 src_vu, src_stride_vu, 373 dst_y, dst_stride_y, 374 dst_v, dst_stride_v, 375 dst_u, dst_stride_u, 376 width, height); 377} 378 379// Convert M420 to I420. 380LIBYUV_API 381int M420ToI420(const uint8* src_m420, int src_stride_m420, 382 uint8* dst_y, int dst_stride_y, 383 uint8* dst_u, int dst_stride_u, 384 uint8* dst_v, int dst_stride_v, 385 int width, int height) { 386 return X420ToI420(src_m420, src_stride_m420, src_stride_m420 * 2, 387 src_m420 + src_stride_m420 * 2, src_stride_m420 * 3, 388 dst_y, dst_stride_y, 389 dst_u, dst_stride_u, 390 dst_v, dst_stride_v, 391 width, height); 392} 393 394// Convert Q420 to I420. 395// Format is rows of YY/YUYV 396LIBYUV_API 397int Q420ToI420(const uint8* src_y, int src_stride_y, 398 const uint8* src_yuy2, int src_stride_yuy2, 399 uint8* dst_y, int dst_stride_y, 400 uint8* dst_u, int dst_stride_u, 401 uint8* dst_v, int dst_stride_v, 402 int width, int height) { 403 int y; 404 int halfheight; 405 void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C; 406 void (*YUY2ToUV422Row)(const uint8* src_yuy2, uint8* dst_u, uint8* dst_v, 407 int pix) = YUY2ToUV422Row_C; 408 void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int pix) = 409 YUY2ToYRow_C; 410 if (!src_y || !src_yuy2 || 411 !dst_y || !dst_u || !dst_v || 412 width <= 0 || height == 0) { 413 return -1; 414 } 415 // Negative height means invert the image. 416 if (height < 0) { 417 height = -height; 418 halfheight = (height + 1) >> 1; 419 dst_y = dst_y + (height - 1) * dst_stride_y; 420 dst_u = dst_u + (halfheight - 1) * dst_stride_u; 421 dst_v = dst_v + (halfheight - 1) * dst_stride_v; 422 dst_stride_y = -dst_stride_y; 423 dst_stride_u = -dst_stride_u; 424 dst_stride_v = -dst_stride_v; 425 } 426 // CopyRow for rows of just Y in Q420 copied to Y plane of I420. 427#if defined(HAS_COPYROW_NEON) 428 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) { 429 CopyRow = CopyRow_NEON; 430 } 431#endif 432#if defined(HAS_COPYROW_X86) 433 if (IS_ALIGNED(width, 4)) { 434 CopyRow = CopyRow_X86; 435 } 436#endif 437#if defined(HAS_COPYROW_SSE2) 438 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32) && 439 IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) && 440 IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 441 CopyRow = CopyRow_SSE2; 442 } 443#endif 444#if defined(HAS_COPYROW_ERMS) 445 if (TestCpuFlag(kCpuHasERMS)) { 446 CopyRow = CopyRow_ERMS; 447 } 448#endif 449#if defined(HAS_COPYROW_MIPS) 450 if (TestCpuFlag(kCpuHasMIPS)) { 451 CopyRow = CopyRow_MIPS; 452 } 453#endif 454 455#if defined(HAS_YUY2TOYROW_SSE2) 456 if (TestCpuFlag(kCpuHasSSE2) && width >= 16) { 457 YUY2ToUV422Row = YUY2ToUV422Row_Any_SSE2; 458 YUY2ToYRow = YUY2ToYRow_Any_SSE2; 459 if (IS_ALIGNED(width, 16)) { 460 YUY2ToUV422Row = YUY2ToUV422Row_Unaligned_SSE2; 461 YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2; 462 if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) { 463 YUY2ToUV422Row = YUY2ToUV422Row_SSE2; 464 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 465 YUY2ToYRow = YUY2ToYRow_SSE2; 466 } 467 } 468 } 469 } 470#endif 471#if defined(HAS_YUY2TOYROW_AVX2) 472 if (TestCpuFlag(kCpuHasAVX2) && width >= 32) { 473 YUY2ToUV422Row = YUY2ToUV422Row_Any_AVX2; 474 YUY2ToYRow = YUY2ToYRow_Any_AVX2; 475 if (IS_ALIGNED(width, 32)) { 476 YUY2ToUV422Row = YUY2ToUV422Row_AVX2; 477 YUY2ToYRow = YUY2ToYRow_AVX2; 478 } 479 } 480#endif 481#if defined(HAS_YUY2TOYROW_NEON) 482 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 483 YUY2ToYRow = YUY2ToYRow_Any_NEON; 484 if (width >= 16) { 485 YUY2ToUV422Row = YUY2ToUV422Row_Any_NEON; 486 } 487 if (IS_ALIGNED(width, 16)) { 488 YUY2ToYRow = YUY2ToYRow_NEON; 489 YUY2ToUV422Row = YUY2ToUV422Row_NEON; 490 } 491 } 492#endif 493 494 for (y = 0; y < height - 1; y += 2) { 495 CopyRow(src_y, dst_y, width); 496 src_y += src_stride_y; 497 dst_y += dst_stride_y; 498 499 YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width); 500 YUY2ToYRow(src_yuy2, dst_y, width); 501 src_yuy2 += src_stride_yuy2; 502 dst_y += dst_stride_y; 503 dst_u += dst_stride_u; 504 dst_v += dst_stride_v; 505 } 506 if (height & 1) { 507 CopyRow(src_y, dst_y, width); 508 YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width); 509 } 510 return 0; 511} 512 513// Convert YUY2 to I420. 514LIBYUV_API 515int YUY2ToI420(const uint8* src_yuy2, int src_stride_yuy2, 516 uint8* dst_y, int dst_stride_y, 517 uint8* dst_u, int dst_stride_u, 518 uint8* dst_v, int dst_stride_v, 519 int width, int height) { 520 int y; 521 void (*YUY2ToUVRow)(const uint8* src_yuy2, int src_stride_yuy2, 522 uint8* dst_u, uint8* dst_v, int pix) = YUY2ToUVRow_C; 523 void (*YUY2ToYRow)(const uint8* src_yuy2, 524 uint8* dst_y, int pix) = YUY2ToYRow_C; 525 // Negative height means invert the image. 526 if (height < 0) { 527 height = -height; 528 src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2; 529 src_stride_yuy2 = -src_stride_yuy2; 530 } 531#if defined(HAS_YUY2TOYROW_SSE2) 532 if (TestCpuFlag(kCpuHasSSE2) && width >= 16) { 533 YUY2ToUVRow = YUY2ToUVRow_Any_SSE2; 534 YUY2ToYRow = YUY2ToYRow_Any_SSE2; 535 if (IS_ALIGNED(width, 16)) { 536 YUY2ToUVRow = YUY2ToUVRow_Unaligned_SSE2; 537 YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2; 538 if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) { 539 YUY2ToUVRow = YUY2ToUVRow_SSE2; 540 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 541 YUY2ToYRow = YUY2ToYRow_SSE2; 542 } 543 } 544 } 545 } 546#endif 547#if defined(HAS_YUY2TOYROW_AVX2) 548 if (TestCpuFlag(kCpuHasAVX2) && width >= 32) { 549 YUY2ToUVRow = YUY2ToUVRow_Any_AVX2; 550 YUY2ToYRow = YUY2ToYRow_Any_AVX2; 551 if (IS_ALIGNED(width, 32)) { 552 YUY2ToUVRow = YUY2ToUVRow_AVX2; 553 YUY2ToYRow = YUY2ToYRow_AVX2; 554 } 555 } 556#endif 557#if defined(HAS_YUY2TOYROW_NEON) 558 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 559 YUY2ToYRow = YUY2ToYRow_Any_NEON; 560 if (width >= 16) { 561 YUY2ToUVRow = YUY2ToUVRow_Any_NEON; 562 } 563 if (IS_ALIGNED(width, 16)) { 564 YUY2ToYRow = YUY2ToYRow_NEON; 565 YUY2ToUVRow = YUY2ToUVRow_NEON; 566 } 567 } 568#endif 569 570 for (y = 0; y < height - 1; y += 2) { 571 YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width); 572 YUY2ToYRow(src_yuy2, dst_y, width); 573 YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width); 574 src_yuy2 += src_stride_yuy2 * 2; 575 dst_y += dst_stride_y * 2; 576 dst_u += dst_stride_u; 577 dst_v += dst_stride_v; 578 } 579 if (height & 1) { 580 YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width); 581 YUY2ToYRow(src_yuy2, dst_y, width); 582 } 583 return 0; 584} 585 586// Convert UYVY to I420. 587LIBYUV_API 588int UYVYToI420(const uint8* src_uyvy, int src_stride_uyvy, 589 uint8* dst_y, int dst_stride_y, 590 uint8* dst_u, int dst_stride_u, 591 uint8* dst_v, int dst_stride_v, 592 int width, int height) { 593 int y; 594 void (*UYVYToUVRow)(const uint8* src_uyvy, int src_stride_uyvy, 595 uint8* dst_u, uint8* dst_v, int pix) = UYVYToUVRow_C; 596 void (*UYVYToYRow)(const uint8* src_uyvy, 597 uint8* dst_y, int pix) = UYVYToYRow_C; 598 // Negative height means invert the image. 599 if (height < 0) { 600 height = -height; 601 src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy; 602 src_stride_uyvy = -src_stride_uyvy; 603 } 604#if defined(HAS_UYVYTOYROW_SSE2) 605 if (TestCpuFlag(kCpuHasSSE2) && width >= 16) { 606 UYVYToUVRow = UYVYToUVRow_Any_SSE2; 607 UYVYToYRow = UYVYToYRow_Any_SSE2; 608 if (IS_ALIGNED(width, 16)) { 609 UYVYToUVRow = UYVYToUVRow_Unaligned_SSE2; 610 UYVYToYRow = UYVYToYRow_Unaligned_SSE2; 611 if (IS_ALIGNED(src_uyvy, 16) && IS_ALIGNED(src_stride_uyvy, 16)) { 612 UYVYToUVRow = UYVYToUVRow_SSE2; 613 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 614 UYVYToYRow = UYVYToYRow_SSE2; 615 } 616 } 617 } 618 } 619#endif 620#if defined(HAS_UYVYTOYROW_AVX2) 621 if (TestCpuFlag(kCpuHasAVX2) && width >= 32) { 622 UYVYToUVRow = UYVYToUVRow_Any_AVX2; 623 UYVYToYRow = UYVYToYRow_Any_AVX2; 624 if (IS_ALIGNED(width, 32)) { 625 UYVYToUVRow = UYVYToUVRow_AVX2; 626 UYVYToYRow = UYVYToYRow_AVX2; 627 } 628 } 629#endif 630#if defined(HAS_UYVYTOYROW_NEON) 631 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 632 UYVYToYRow = UYVYToYRow_Any_NEON; 633 if (width >= 16) { 634 UYVYToUVRow = UYVYToUVRow_Any_NEON; 635 } 636 if (IS_ALIGNED(width, 16)) { 637 UYVYToYRow = UYVYToYRow_NEON; 638 UYVYToUVRow = UYVYToUVRow_NEON; 639 } 640 } 641#endif 642 643 for (y = 0; y < height - 1; y += 2) { 644 UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width); 645 UYVYToYRow(src_uyvy, dst_y, width); 646 UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width); 647 src_uyvy += src_stride_uyvy * 2; 648 dst_y += dst_stride_y * 2; 649 dst_u += dst_stride_u; 650 dst_v += dst_stride_v; 651 } 652 if (height & 1) { 653 UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width); 654 UYVYToYRow(src_uyvy, dst_y, width); 655 } 656 return 0; 657} 658 659// Convert ARGB to I420. 660LIBYUV_API 661int ARGBToI420(const uint8* src_argb, int src_stride_argb, 662 uint8* dst_y, int dst_stride_y, 663 uint8* dst_u, int dst_stride_u, 664 uint8* dst_v, int dst_stride_v, 665 int width, int height) { 666 int y; 667 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, 668 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; 669 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) = 670 ARGBToYRow_C; 671 if (!src_argb || 672 !dst_y || !dst_u || !dst_v || 673 width <= 0 || height == 0) { 674 return -1; 675 } 676 // Negative height means invert the image. 677 if (height < 0) { 678 height = -height; 679 src_argb = src_argb + (height - 1) * src_stride_argb; 680 src_stride_argb = -src_stride_argb; 681 } 682#if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) 683 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 684 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 685 ARGBToYRow = ARGBToYRow_Any_SSSE3; 686 if (IS_ALIGNED(width, 16)) { 687 ARGBToUVRow = ARGBToUVRow_Unaligned_SSSE3; 688 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3; 689 if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) { 690 ARGBToUVRow = ARGBToUVRow_SSSE3; 691 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 692 ARGBToYRow = ARGBToYRow_SSSE3; 693 } 694 } 695 } 696 } 697#endif 698#if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) 699 if (TestCpuFlag(kCpuHasAVX2) && width >= 32) { 700 ARGBToUVRow = ARGBToUVRow_Any_AVX2; 701 ARGBToYRow = ARGBToYRow_Any_AVX2; 702 if (IS_ALIGNED(width, 32)) { 703 ARGBToUVRow = ARGBToUVRow_AVX2; 704 ARGBToYRow = ARGBToYRow_AVX2; 705 } 706 } 707#endif 708#if defined(HAS_ARGBTOYROW_NEON) 709 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 710 ARGBToYRow = ARGBToYRow_Any_NEON; 711 if (IS_ALIGNED(width, 8)) { 712 ARGBToYRow = ARGBToYRow_NEON; 713 } 714 } 715#endif 716#if defined(HAS_ARGBTOUVROW_NEON) 717 if (TestCpuFlag(kCpuHasNEON) && width >= 16) { 718 ARGBToUVRow = ARGBToUVRow_Any_NEON; 719 if (IS_ALIGNED(width, 16)) { 720 ARGBToUVRow = ARGBToUVRow_NEON; 721 } 722 } 723#endif 724 725 for (y = 0; y < height - 1; y += 2) { 726 ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width); 727 ARGBToYRow(src_argb, dst_y, width); 728 ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width); 729 src_argb += src_stride_argb * 2; 730 dst_y += dst_stride_y * 2; 731 dst_u += dst_stride_u; 732 dst_v += dst_stride_v; 733 } 734 if (height & 1) { 735 ARGBToUVRow(src_argb, 0, dst_u, dst_v, width); 736 ARGBToYRow(src_argb, dst_y, width); 737 } 738 return 0; 739} 740 741// Convert BGRA to I420. 742LIBYUV_API 743int BGRAToI420(const uint8* src_bgra, int src_stride_bgra, 744 uint8* dst_y, int dst_stride_y, 745 uint8* dst_u, int dst_stride_u, 746 uint8* dst_v, int dst_stride_v, 747 int width, int height) { 748 int y; 749 void (*BGRAToUVRow)(const uint8* src_bgra0, int src_stride_bgra, 750 uint8* dst_u, uint8* dst_v, int width) = BGRAToUVRow_C; 751 void (*BGRAToYRow)(const uint8* src_bgra, uint8* dst_y, int pix) = 752 BGRAToYRow_C; 753 if (!src_bgra || 754 !dst_y || !dst_u || !dst_v || 755 width <= 0 || height == 0) { 756 return -1; 757 } 758 // Negative height means invert the image. 759 if (height < 0) { 760 height = -height; 761 src_bgra = src_bgra + (height - 1) * src_stride_bgra; 762 src_stride_bgra = -src_stride_bgra; 763 } 764#if defined(HAS_BGRATOYROW_SSSE3) 765 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 766 BGRAToUVRow = BGRAToUVRow_Any_SSSE3; 767 BGRAToYRow = BGRAToYRow_Any_SSSE3; 768 if (IS_ALIGNED(width, 16)) { 769 BGRAToUVRow = BGRAToUVRow_Unaligned_SSSE3; 770 BGRAToYRow = BGRAToYRow_Unaligned_SSSE3; 771 if (IS_ALIGNED(src_bgra, 16) && IS_ALIGNED(src_stride_bgra, 16)) { 772 BGRAToUVRow = BGRAToUVRow_SSSE3; 773 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 774 BGRAToYRow = BGRAToYRow_SSSE3; 775 } 776 } 777 } 778 } 779#elif defined(HAS_BGRATOYROW_NEON) 780 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 781 BGRAToYRow = BGRAToYRow_Any_NEON; 782 if (IS_ALIGNED(width, 8)) { 783 BGRAToYRow = BGRAToYRow_NEON; 784 } 785 if (width >= 16) { 786 BGRAToUVRow = BGRAToUVRow_Any_NEON; 787 if (IS_ALIGNED(width, 16)) { 788 BGRAToUVRow = BGRAToUVRow_NEON; 789 } 790 } 791 } 792#endif 793 794 for (y = 0; y < height - 1; y += 2) { 795 BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width); 796 BGRAToYRow(src_bgra, dst_y, width); 797 BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width); 798 src_bgra += src_stride_bgra * 2; 799 dst_y += dst_stride_y * 2; 800 dst_u += dst_stride_u; 801 dst_v += dst_stride_v; 802 } 803 if (height & 1) { 804 BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width); 805 BGRAToYRow(src_bgra, dst_y, width); 806 } 807 return 0; 808} 809 810// Convert ABGR to I420. 811LIBYUV_API 812int ABGRToI420(const uint8* src_abgr, int src_stride_abgr, 813 uint8* dst_y, int dst_stride_y, 814 uint8* dst_u, int dst_stride_u, 815 uint8* dst_v, int dst_stride_v, 816 int width, int height) { 817 int y; 818 void (*ABGRToUVRow)(const uint8* src_abgr0, int src_stride_abgr, 819 uint8* dst_u, uint8* dst_v, int width) = ABGRToUVRow_C; 820 void (*ABGRToYRow)(const uint8* src_abgr, uint8* dst_y, int pix) = 821 ABGRToYRow_C; 822 if (!src_abgr || 823 !dst_y || !dst_u || !dst_v || 824 width <= 0 || height == 0) { 825 return -1; 826 } 827 // Negative height means invert the image. 828 if (height < 0) { 829 height = -height; 830 src_abgr = src_abgr + (height - 1) * src_stride_abgr; 831 src_stride_abgr = -src_stride_abgr; 832 } 833#if defined(HAS_ABGRTOYROW_SSSE3) 834 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 835 ABGRToUVRow = ABGRToUVRow_Any_SSSE3; 836 ABGRToYRow = ABGRToYRow_Any_SSSE3; 837 if (IS_ALIGNED(width, 16)) { 838 ABGRToUVRow = ABGRToUVRow_Unaligned_SSSE3; 839 ABGRToYRow = ABGRToYRow_Unaligned_SSSE3; 840 if (IS_ALIGNED(src_abgr, 16) && IS_ALIGNED(src_stride_abgr, 16)) { 841 ABGRToUVRow = ABGRToUVRow_SSSE3; 842 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 843 ABGRToYRow = ABGRToYRow_SSSE3; 844 } 845 } 846 } 847 } 848#elif defined(HAS_ABGRTOYROW_NEON) 849 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 850 ABGRToYRow = ABGRToYRow_Any_NEON; 851 if (IS_ALIGNED(width, 8)) { 852 ABGRToYRow = ABGRToYRow_NEON; 853 } 854 if (width >= 16) { 855 ABGRToUVRow = ABGRToUVRow_Any_NEON; 856 if (IS_ALIGNED(width, 16)) { 857 ABGRToUVRow = ABGRToUVRow_NEON; 858 } 859 } 860 } 861#endif 862 863 for (y = 0; y < height - 1; y += 2) { 864 ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width); 865 ABGRToYRow(src_abgr, dst_y, width); 866 ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width); 867 src_abgr += src_stride_abgr * 2; 868 dst_y += dst_stride_y * 2; 869 dst_u += dst_stride_u; 870 dst_v += dst_stride_v; 871 } 872 if (height & 1) { 873 ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width); 874 ABGRToYRow(src_abgr, dst_y, width); 875 } 876 return 0; 877} 878 879// Convert RGBA to I420. 880LIBYUV_API 881int RGBAToI420(const uint8* src_rgba, int src_stride_rgba, 882 uint8* dst_y, int dst_stride_y, 883 uint8* dst_u, int dst_stride_u, 884 uint8* dst_v, int dst_stride_v, 885 int width, int height) { 886 int y; 887 void (*RGBAToUVRow)(const uint8* src_rgba0, int src_stride_rgba, 888 uint8* dst_u, uint8* dst_v, int width) = RGBAToUVRow_C; 889 void (*RGBAToYRow)(const uint8* src_rgba, uint8* dst_y, int pix) = 890 RGBAToYRow_C; 891 if (!src_rgba || 892 !dst_y || !dst_u || !dst_v || 893 width <= 0 || height == 0) { 894 return -1; 895 } 896 // Negative height means invert the image. 897 if (height < 0) { 898 height = -height; 899 src_rgba = src_rgba + (height - 1) * src_stride_rgba; 900 src_stride_rgba = -src_stride_rgba; 901 } 902#if defined(HAS_RGBATOYROW_SSSE3) 903 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 904 RGBAToUVRow = RGBAToUVRow_Any_SSSE3; 905 RGBAToYRow = RGBAToYRow_Any_SSSE3; 906 if (IS_ALIGNED(width, 16)) { 907 RGBAToUVRow = RGBAToUVRow_Unaligned_SSSE3; 908 RGBAToYRow = RGBAToYRow_Unaligned_SSSE3; 909 if (IS_ALIGNED(src_rgba, 16) && IS_ALIGNED(src_stride_rgba, 16)) { 910 RGBAToUVRow = RGBAToUVRow_SSSE3; 911 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 912 RGBAToYRow = RGBAToYRow_SSSE3; 913 } 914 } 915 } 916 } 917#elif defined(HAS_RGBATOYROW_NEON) 918 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 919 RGBAToYRow = RGBAToYRow_Any_NEON; 920 if (IS_ALIGNED(width, 8)) { 921 RGBAToYRow = RGBAToYRow_NEON; 922 } 923 if (width >= 16) { 924 RGBAToUVRow = RGBAToUVRow_Any_NEON; 925 if (IS_ALIGNED(width, 16)) { 926 RGBAToUVRow = RGBAToUVRow_NEON; 927 } 928 } 929 } 930#endif 931 932 for (y = 0; y < height - 1; y += 2) { 933 RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width); 934 RGBAToYRow(src_rgba, dst_y, width); 935 RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width); 936 src_rgba += src_stride_rgba * 2; 937 dst_y += dst_stride_y * 2; 938 dst_u += dst_stride_u; 939 dst_v += dst_stride_v; 940 } 941 if (height & 1) { 942 RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width); 943 RGBAToYRow(src_rgba, dst_y, width); 944 } 945 return 0; 946} 947 948// Convert RGB24 to I420. 949LIBYUV_API 950int RGB24ToI420(const uint8* src_rgb24, int src_stride_rgb24, 951 uint8* dst_y, int dst_stride_y, 952 uint8* dst_u, int dst_stride_u, 953 uint8* dst_v, int dst_stride_v, 954 int width, int height) { 955 int y; 956#if defined(HAS_RGB24TOYROW_NEON) 957 void (*RGB24ToUVRow)(const uint8* src_rgb24, int src_stride_rgb24, 958 uint8* dst_u, uint8* dst_v, int width) = RGB24ToUVRow_C; 959 void (*RGB24ToYRow)(const uint8* src_rgb24, uint8* dst_y, int pix) = 960 RGB24ToYRow_C; 961#else 962 void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = 963 RGB24ToARGBRow_C; 964 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, 965 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; 966 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) = 967 ARGBToYRow_C; 968#endif 969 if (!src_rgb24 || !dst_y || !dst_u || !dst_v || 970 width <= 0 || height == 0) { 971 return -1; 972 } 973 // Negative height means invert the image. 974 if (height < 0) { 975 height = -height; 976 src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24; 977 src_stride_rgb24 = -src_stride_rgb24; 978 } 979 980#if defined(HAS_RGB24TOYROW_NEON) 981 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 982 RGB24ToYRow = RGB24ToYRow_Any_NEON; 983 if (IS_ALIGNED(width, 8)) { 984 RGB24ToYRow = RGB24ToYRow_NEON; 985 } 986 if (width >= 16) { 987 RGB24ToUVRow = RGB24ToUVRow_Any_NEON; 988 if (IS_ALIGNED(width, 16)) { 989 RGB24ToUVRow = RGB24ToUVRow_NEON; 990 } 991 } 992 } 993#else // HAS_RGB24TOYROW_NEON 994 995#if defined(HAS_RGB24TOARGBROW_SSSE3) 996 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 997 RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3; 998 if (IS_ALIGNED(width, 16)) { 999 RGB24ToARGBRow = RGB24ToARGBRow_SSSE3; 1000 } 1001 } 1002#endif 1003#if defined(HAS_ARGBTOUVROW_SSSE3) 1004 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1005 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1006 if (IS_ALIGNED(width, 16)) { 1007 ARGBToUVRow = ARGBToUVRow_SSSE3; 1008 } 1009 } 1010#endif 1011#if defined(HAS_ARGBTOUVROW_SSSE3) 1012 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1013 ARGBToYRow = ARGBToYRow_Any_SSSE3; 1014 if (IS_ALIGNED(width, 16)) { 1015 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3; 1016 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 1017 ARGBToYRow = ARGBToYRow_SSSE3; 1018 } 1019 } 1020 } 1021#endif // HAS_ARGBTOUVROW_SSSE3 1022#endif // HAS_RGB24TOYROW_NEON 1023 1024 { 1025#if !defined(HAS_RGB24TOYROW_NEON) 1026 // Allocate 2 rows of ARGB. 1027 const int kRowSize = (width * 4 + 15) & ~15; 1028 align_buffer_64(row, kRowSize * 2); 1029#endif 1030 1031 for (y = 0; y < height - 1; y += 2) { 1032#if defined(HAS_RGB24TOYROW_NEON) 1033 RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width); 1034 RGB24ToYRow(src_rgb24, dst_y, width); 1035 RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width); 1036#else 1037 RGB24ToARGBRow(src_rgb24, row, width); 1038 RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width); 1039 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1040 ARGBToYRow(row, dst_y, width); 1041 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1042#endif 1043 src_rgb24 += src_stride_rgb24 * 2; 1044 dst_y += dst_stride_y * 2; 1045 dst_u += dst_stride_u; 1046 dst_v += dst_stride_v; 1047 } 1048 if (height & 1) { 1049#if defined(HAS_RGB24TOYROW_NEON) 1050 RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width); 1051 RGB24ToYRow(src_rgb24, dst_y, width); 1052#else 1053 RGB24ToARGBRow(src_rgb24, row, width); 1054 ARGBToUVRow(row, 0, dst_u, dst_v, width); 1055 ARGBToYRow(row, dst_y, width); 1056#endif 1057 } 1058#if !defined(HAS_RGB24TOYROW_NEON) 1059 free_aligned_buffer_64(row); 1060#endif 1061 } 1062 return 0; 1063} 1064 1065// Convert RAW to I420. 1066LIBYUV_API 1067int RAWToI420(const uint8* src_raw, int src_stride_raw, 1068 uint8* dst_y, int dst_stride_y, 1069 uint8* dst_u, int dst_stride_u, 1070 uint8* dst_v, int dst_stride_v, 1071 int width, int height) { 1072 int y; 1073#if defined(HAS_RAWTOYROW_NEON) 1074 void (*RAWToUVRow)(const uint8* src_raw, int src_stride_raw, 1075 uint8* dst_u, uint8* dst_v, int width) = RAWToUVRow_C; 1076 void (*RAWToYRow)(const uint8* src_raw, uint8* dst_y, int pix) = 1077 RAWToYRow_C; 1078#else 1079 void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = 1080 RAWToARGBRow_C; 1081 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, 1082 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; 1083 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) = 1084 ARGBToYRow_C; 1085#endif 1086 if (!src_raw || !dst_y || !dst_u || !dst_v || 1087 width <= 0 || height == 0) { 1088 return -1; 1089 } 1090 // Negative height means invert the image. 1091 if (height < 0) { 1092 height = -height; 1093 src_raw = src_raw + (height - 1) * src_stride_raw; 1094 src_stride_raw = -src_stride_raw; 1095 } 1096 1097#if defined(HAS_RAWTOYROW_NEON) 1098 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1099 RAWToYRow = RAWToYRow_Any_NEON; 1100 if (IS_ALIGNED(width, 8)) { 1101 RAWToYRow = RAWToYRow_NEON; 1102 } 1103 if (width >= 16) { 1104 RAWToUVRow = RAWToUVRow_Any_NEON; 1105 if (IS_ALIGNED(width, 16)) { 1106 RAWToUVRow = RAWToUVRow_NEON; 1107 } 1108 } 1109 } 1110#else // HAS_RAWTOYROW_NEON 1111 1112#if defined(HAS_RAWTOARGBROW_SSSE3) 1113 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1114 RAWToARGBRow = RAWToARGBRow_Any_SSSE3; 1115 if (IS_ALIGNED(width, 16)) { 1116 RAWToARGBRow = RAWToARGBRow_SSSE3; 1117 } 1118 } 1119#endif 1120#if defined(HAS_ARGBTOUVROW_SSSE3) 1121 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1122 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1123 if (IS_ALIGNED(width, 16)) { 1124 ARGBToUVRow = ARGBToUVRow_SSSE3; 1125 } 1126 } 1127#endif 1128#if defined(HAS_ARGBTOUVROW_SSSE3) 1129 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1130 ARGBToYRow = ARGBToYRow_Any_SSSE3; 1131 if (IS_ALIGNED(width, 16)) { 1132 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3; 1133 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 1134 ARGBToYRow = ARGBToYRow_SSSE3; 1135 } 1136 } 1137 } 1138#endif // HAS_ARGBTOUVROW_SSSE3 1139#endif // HAS_RAWTOYROW_NEON 1140 1141 { 1142 // Allocate 2 rows of ARGB. 1143 const int kRowSize = (width * 4 + 15) & ~15; 1144 align_buffer_64(row, kRowSize * 2); 1145 1146 for (y = 0; y < height - 1; y += 2) { 1147 #if defined(HAS_RAWTOYROW_NEON) 1148 RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width); 1149 RAWToYRow(src_raw, dst_y, width); 1150 RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width); 1151 #else 1152 RAWToARGBRow(src_raw, row, width); 1153 RAWToARGBRow(src_raw + src_stride_raw, row + kRowSize, width); 1154 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1155 ARGBToYRow(row, dst_y, width); 1156 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1157 #endif 1158 src_raw += src_stride_raw * 2; 1159 dst_y += dst_stride_y * 2; 1160 dst_u += dst_stride_u; 1161 dst_v += dst_stride_v; 1162 } 1163 if (height & 1) { 1164 #if defined(HAS_RAWTOYROW_NEON) 1165 RAWToUVRow(src_raw, 0, dst_u, dst_v, width); 1166 RAWToYRow(src_raw, dst_y, width); 1167 #else 1168 RAWToARGBRow(src_raw, row, width); 1169 ARGBToUVRow(row, 0, dst_u, dst_v, width); 1170 ARGBToYRow(row, dst_y, width); 1171 #endif 1172 } 1173 #if !defined(HAS_RAWTOYROW_NEON) 1174 free_aligned_buffer_64(row); 1175 #endif 1176 } 1177 return 0; 1178} 1179 1180// Convert RGB565 to I420. 1181LIBYUV_API 1182int RGB565ToI420(const uint8* src_rgb565, int src_stride_rgb565, 1183 uint8* dst_y, int dst_stride_y, 1184 uint8* dst_u, int dst_stride_u, 1185 uint8* dst_v, int dst_stride_v, 1186 int width, int height) { 1187 int y; 1188#if defined(HAS_RGB565TOYROW_NEON) 1189 void (*RGB565ToUVRow)(const uint8* src_rgb565, int src_stride_rgb565, 1190 uint8* dst_u, uint8* dst_v, int width) = RGB565ToUVRow_C; 1191 void (*RGB565ToYRow)(const uint8* src_rgb565, uint8* dst_y, int pix) = 1192 RGB565ToYRow_C; 1193#else 1194 void (*RGB565ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = 1195 RGB565ToARGBRow_C; 1196 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, 1197 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; 1198 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) = 1199 ARGBToYRow_C; 1200#endif 1201 if (!src_rgb565 || !dst_y || !dst_u || !dst_v || 1202 width <= 0 || height == 0) { 1203 return -1; 1204 } 1205 // Negative height means invert the image. 1206 if (height < 0) { 1207 height = -height; 1208 src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565; 1209 src_stride_rgb565 = -src_stride_rgb565; 1210 } 1211 1212#if defined(HAS_RGB565TOYROW_NEON) 1213 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1214 RGB565ToYRow = RGB565ToYRow_Any_NEON; 1215 if (IS_ALIGNED(width, 8)) { 1216 RGB565ToYRow = RGB565ToYRow_NEON; 1217 } 1218 if (width >= 16) { 1219 RGB565ToUVRow = RGB565ToUVRow_Any_NEON; 1220 if (IS_ALIGNED(width, 16)) { 1221 RGB565ToUVRow = RGB565ToUVRow_NEON; 1222 } 1223 } 1224 } 1225#else // HAS_RGB565TOYROW_NEON 1226 1227#if defined(HAS_RGB565TOARGBROW_SSE2) 1228 if (TestCpuFlag(kCpuHasSSE2) && width >= 8) { 1229 RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2; 1230 if (IS_ALIGNED(width, 8)) { 1231 RGB565ToARGBRow = RGB565ToARGBRow_SSE2; 1232 } 1233 } 1234#endif 1235#if defined(HAS_ARGBTOUVROW_SSSE3) 1236 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1237 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1238 if (IS_ALIGNED(width, 16)) { 1239 ARGBToUVRow = ARGBToUVRow_SSSE3; 1240 } 1241 } 1242#endif 1243#if defined(HAS_ARGBTOUVROW_SSSE3) 1244 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1245 ARGBToYRow = ARGBToYRow_Any_SSSE3; 1246 if (IS_ALIGNED(width, 16)) { 1247 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3; 1248 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 1249 ARGBToYRow = ARGBToYRow_SSSE3; 1250 } 1251 } 1252 } 1253#endif // HAS_ARGBTOUVROW_SSSE3 1254#endif // HAS_RGB565TOYROW_NEON 1255 1256 { 1257#if !defined(HAS_RGB565TOYROW_NEON) 1258 // Allocate 2 rows of ARGB. 1259 const int kRowSize = (width * 4 + 15) & ~15; 1260 align_buffer_64(row, kRowSize * 2); 1261#endif 1262 1263 for (y = 0; y < height - 1; y += 2) { 1264#if defined(HAS_RGB565TOYROW_NEON) 1265 RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width); 1266 RGB565ToYRow(src_rgb565, dst_y, width); 1267 RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width); 1268#else 1269 RGB565ToARGBRow(src_rgb565, row, width); 1270 RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kRowSize, width); 1271 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1272 ARGBToYRow(row, dst_y, width); 1273 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1274#endif 1275 src_rgb565 += src_stride_rgb565 * 2; 1276 dst_y += dst_stride_y * 2; 1277 dst_u += dst_stride_u; 1278 dst_v += dst_stride_v; 1279 } 1280 if (height & 1) { 1281#if defined(HAS_RGB565TOYROW_NEON) 1282 RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width); 1283 RGB565ToYRow(src_rgb565, dst_y, width); 1284#else 1285 RGB565ToARGBRow(src_rgb565, row, width); 1286 ARGBToUVRow(row, 0, dst_u, dst_v, width); 1287 ARGBToYRow(row, dst_y, width); 1288#endif 1289 } 1290#if !defined(HAS_RGB565TOYROW_NEON) 1291 free_aligned_buffer_64(row); 1292#endif 1293 } 1294 return 0; 1295} 1296 1297// Convert ARGB1555 to I420. 1298LIBYUV_API 1299int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555, 1300 uint8* dst_y, int dst_stride_y, 1301 uint8* dst_u, int dst_stride_u, 1302 uint8* dst_v, int dst_stride_v, 1303 int width, int height) { 1304 int y; 1305#if defined(HAS_ARGB1555TOYROW_NEON) 1306 void (*ARGB1555ToUVRow)(const uint8* src_argb1555, int src_stride_argb1555, 1307 uint8* dst_u, uint8* dst_v, int width) = ARGB1555ToUVRow_C; 1308 void (*ARGB1555ToYRow)(const uint8* src_argb1555, uint8* dst_y, int pix) = 1309 ARGB1555ToYRow_C; 1310#else 1311 void (*ARGB1555ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = 1312 ARGB1555ToARGBRow_C; 1313 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, 1314 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; 1315 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) = 1316 ARGBToYRow_C; 1317#endif 1318 if (!src_argb1555 || !dst_y || !dst_u || !dst_v || 1319 width <= 0 || height == 0) { 1320 return -1; 1321 } 1322 // Negative height means invert the image. 1323 if (height < 0) { 1324 height = -height; 1325 src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555; 1326 src_stride_argb1555 = -src_stride_argb1555; 1327 } 1328 1329#if defined(HAS_ARGB1555TOYROW_NEON) 1330 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1331 ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON; 1332 if (IS_ALIGNED(width, 8)) { 1333 ARGB1555ToYRow = ARGB1555ToYRow_NEON; 1334 } 1335 if (width >= 16) { 1336 ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON; 1337 if (IS_ALIGNED(width, 16)) { 1338 ARGB1555ToUVRow = ARGB1555ToUVRow_NEON; 1339 } 1340 } 1341 } 1342#else // HAS_ARGB1555TOYROW_NEON 1343 1344#if defined(HAS_ARGB1555TOARGBROW_SSE2) 1345 if (TestCpuFlag(kCpuHasSSE2) && width >= 8) { 1346 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2; 1347 if (IS_ALIGNED(width, 8)) { 1348 ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2; 1349 } 1350 } 1351#endif 1352#if defined(HAS_ARGBTOUVROW_SSSE3) 1353 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1354 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1355 if (IS_ALIGNED(width, 16)) { 1356 ARGBToUVRow = ARGBToUVRow_SSSE3; 1357 } 1358 } 1359#endif 1360#if defined(HAS_ARGBTOUVROW_SSSE3) 1361 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1362 ARGBToYRow = ARGBToYRow_Any_SSSE3; 1363 if (IS_ALIGNED(width, 16)) { 1364 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3; 1365 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 1366 ARGBToYRow = ARGBToYRow_SSSE3; 1367 } 1368 } 1369 } 1370#endif // HAS_ARGBTOUVROW_SSSE3 1371#endif // HAS_ARGB1555TOYROW_NEON 1372 1373 { 1374#if !defined(HAS_ARGB1555TOYROW_NEON) 1375 // Allocate 2 rows of ARGB. 1376 const int kRowSize = (width * 4 + 15) & ~15; 1377 align_buffer_64(row, kRowSize * 2); 1378#endif 1379 for (y = 0; y < height - 1; y += 2) { 1380#if defined(HAS_ARGB1555TOYROW_NEON) 1381 ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width); 1382 ARGB1555ToYRow(src_argb1555, dst_y, width); 1383 ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y, 1384 width); 1385#else 1386 ARGB1555ToARGBRow(src_argb1555, row, width); 1387 ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize, 1388 width); 1389 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1390 ARGBToYRow(row, dst_y, width); 1391 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1392#endif 1393 src_argb1555 += src_stride_argb1555 * 2; 1394 dst_y += dst_stride_y * 2; 1395 dst_u += dst_stride_u; 1396 dst_v += dst_stride_v; 1397 } 1398 if (height & 1) { 1399#if defined(HAS_ARGB1555TOYROW_NEON) 1400 ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width); 1401 ARGB1555ToYRow(src_argb1555, dst_y, width); 1402#else 1403 ARGB1555ToARGBRow(src_argb1555, row, width); 1404 ARGBToUVRow(row, 0, dst_u, dst_v, width); 1405 ARGBToYRow(row, dst_y, width); 1406#endif 1407 } 1408#if !defined(HAS_ARGB1555TOYROW_NEON) 1409 free_aligned_buffer_64(row); 1410#endif 1411 } 1412 return 0; 1413} 1414 1415// Convert ARGB4444 to I420. 1416LIBYUV_API 1417int ARGB4444ToI420(const uint8* src_argb4444, int src_stride_argb4444, 1418 uint8* dst_y, int dst_stride_y, 1419 uint8* dst_u, int dst_stride_u, 1420 uint8* dst_v, int dst_stride_v, 1421 int width, int height) { 1422 int y; 1423#if defined(HAS_ARGB4444TOYROW_NEON) 1424 void (*ARGB4444ToUVRow)(const uint8* src_argb4444, int src_stride_argb4444, 1425 uint8* dst_u, uint8* dst_v, int width) = ARGB4444ToUVRow_C; 1426 void (*ARGB4444ToYRow)(const uint8* src_argb4444, uint8* dst_y, int pix) = 1427 ARGB4444ToYRow_C; 1428#else 1429 void (*ARGB4444ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = 1430 ARGB4444ToARGBRow_C; 1431 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, 1432 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; 1433 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) = 1434 ARGBToYRow_C; 1435#endif 1436 if (!src_argb4444 || !dst_y || !dst_u || !dst_v || 1437 width <= 0 || height == 0) { 1438 return -1; 1439 } 1440 // Negative height means invert the image. 1441 if (height < 0) { 1442 height = -height; 1443 src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444; 1444 src_stride_argb4444 = -src_stride_argb4444; 1445 } 1446 1447#if defined(HAS_ARGB4444TOYROW_NEON) 1448 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1449 ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON; 1450 if (IS_ALIGNED(width, 8)) { 1451 ARGB4444ToYRow = ARGB4444ToYRow_NEON; 1452 } 1453 if (width >= 16) { 1454 ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON; 1455 if (IS_ALIGNED(width, 16)) { 1456 ARGB4444ToUVRow = ARGB4444ToUVRow_NEON; 1457 } 1458 } 1459 } 1460#else // HAS_ARGB4444TOYROW_NEON 1461 1462#if defined(HAS_ARGB4444TOARGBROW_SSE2) 1463 if (TestCpuFlag(kCpuHasSSE2) && width >= 8) { 1464 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2; 1465 if (IS_ALIGNED(width, 8)) { 1466 ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2; 1467 } 1468 } 1469#endif 1470#if defined(HAS_ARGBTOUVROW_SSSE3) 1471 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1472 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1473 if (IS_ALIGNED(width, 16)) { 1474 ARGBToUVRow = ARGBToUVRow_SSSE3; 1475 } 1476 } 1477#endif 1478#if defined(HAS_ARGBTOUVROW_SSSE3) 1479 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1480 ARGBToYRow = ARGBToYRow_Any_SSSE3; 1481 if (IS_ALIGNED(width, 16)) { 1482 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3; 1483 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 1484 ARGBToYRow = ARGBToYRow_SSSE3; 1485 } 1486 } 1487 } 1488#endif // HAS_ARGBTOUVROW_SSSE3 1489#endif // HAS_ARGB4444TOYROW_NEON 1490 1491 { 1492#if !defined(HAS_ARGB4444TOYROW_NEON) 1493 // Allocate 2 rows of ARGB. 1494 const int kRowSize = (width * 4 + 15) & ~15; 1495 align_buffer_64(row, kRowSize * 2); 1496#endif 1497 1498 for (y = 0; y < height - 1; y += 2) { 1499#if defined(HAS_ARGB4444TOYROW_NEON) 1500 ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width); 1501 ARGB4444ToYRow(src_argb4444, dst_y, width); 1502 ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y, 1503 width); 1504#else 1505 ARGB4444ToARGBRow(src_argb4444, row, width); 1506 ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kRowSize, 1507 width); 1508 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1509 ARGBToYRow(row, dst_y, width); 1510 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1511#endif 1512 src_argb4444 += src_stride_argb4444 * 2; 1513 dst_y += dst_stride_y * 2; 1514 dst_u += dst_stride_u; 1515 dst_v += dst_stride_v; 1516 } 1517 if (height & 1) { 1518#if defined(HAS_ARGB4444TOYROW_NEON) 1519 ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width); 1520 ARGB4444ToYRow(src_argb4444, dst_y, width); 1521#else 1522 ARGB4444ToARGBRow(src_argb4444, row, width); 1523 ARGBToUVRow(row, 0, dst_u, dst_v, width); 1524 ARGBToYRow(row, dst_y, width); 1525#endif 1526 } 1527#if !defined(HAS_ARGB4444TOYROW_NEON) 1528 free_aligned_buffer_64(row); 1529#endif 1530 } 1531 return 0; 1532} 1533 1534#ifdef __cplusplus 1535} // extern "C" 1536} // namespace libyuv 1537#endif 1538