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 21 namespace libyuv { 22 extern "C" { 23 #endif 24 25 #define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s) 26 static __inline int Abs(int v) { 27 return v >= 0 ? v : -v; 28 } 29 30 // Any I4xx To I420 format with mirroring. 31 static 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. 62 LIBYUV_API 63 int 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 100 LIBYUV_API 101 int 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 121 LIBYUV_API 122 int 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 141 LIBYUV_API 142 int 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 161 LIBYUV_API 162 int 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 186 static 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. 241 static 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. 348 LIBYUV_API 349 int 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. 364 LIBYUV_API 365 int 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. 380 LIBYUV_API 381 int 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 396 LIBYUV_API 397 int 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 = (height + 1) >> 1; 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. 514 LIBYUV_API 515 int 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. 587 LIBYUV_API 588 int 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. 660 LIBYUV_API 661 int 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 if (width >= 16) { 715 ARGBToUVRow = ARGBToUVRow_Any_NEON; 716 if (IS_ALIGNED(width, 16)) { 717 ARGBToUVRow = ARGBToUVRow_NEON; 718 } 719 } 720 } 721 #endif 722 723 for (y = 0; y < height - 1; y += 2) { 724 ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width); 725 ARGBToYRow(src_argb, dst_y, width); 726 ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width); 727 src_argb += src_stride_argb * 2; 728 dst_y += dst_stride_y * 2; 729 dst_u += dst_stride_u; 730 dst_v += dst_stride_v; 731 } 732 if (height & 1) { 733 ARGBToUVRow(src_argb, 0, dst_u, dst_v, width); 734 ARGBToYRow(src_argb, dst_y, width); 735 } 736 return 0; 737 } 738 739 // Convert BGRA to I420. 740 LIBYUV_API 741 int BGRAToI420(const uint8* src_bgra, int src_stride_bgra, 742 uint8* dst_y, int dst_stride_y, 743 uint8* dst_u, int dst_stride_u, 744 uint8* dst_v, int dst_stride_v, 745 int width, int height) { 746 int y; 747 void (*BGRAToUVRow)(const uint8* src_bgra0, int src_stride_bgra, 748 uint8* dst_u, uint8* dst_v, int width) = BGRAToUVRow_C; 749 void (*BGRAToYRow)(const uint8* src_bgra, uint8* dst_y, int pix) = 750 BGRAToYRow_C; 751 if (!src_bgra || 752 !dst_y || !dst_u || !dst_v || 753 width <= 0 || height == 0) { 754 return -1; 755 } 756 // Negative height means invert the image. 757 if (height < 0) { 758 height = -height; 759 src_bgra = src_bgra + (height - 1) * src_stride_bgra; 760 src_stride_bgra = -src_stride_bgra; 761 } 762 #if defined(HAS_BGRATOYROW_SSSE3) 763 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 764 BGRAToUVRow = BGRAToUVRow_Any_SSSE3; 765 BGRAToYRow = BGRAToYRow_Any_SSSE3; 766 if (IS_ALIGNED(width, 16)) { 767 BGRAToUVRow = BGRAToUVRow_Unaligned_SSSE3; 768 BGRAToYRow = BGRAToYRow_Unaligned_SSSE3; 769 if (IS_ALIGNED(src_bgra, 16) && IS_ALIGNED(src_stride_bgra, 16)) { 770 BGRAToUVRow = BGRAToUVRow_SSSE3; 771 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 772 BGRAToYRow = BGRAToYRow_SSSE3; 773 } 774 } 775 } 776 } 777 #elif defined(HAS_BGRATOYROW_NEON) 778 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 779 BGRAToYRow = BGRAToYRow_Any_NEON; 780 if (IS_ALIGNED(width, 8)) { 781 BGRAToYRow = BGRAToYRow_NEON; 782 } 783 if (width >= 16) { 784 BGRAToUVRow = BGRAToUVRow_Any_NEON; 785 if (IS_ALIGNED(width, 16)) { 786 BGRAToUVRow = BGRAToUVRow_NEON; 787 } 788 } 789 } 790 #endif 791 792 for (y = 0; y < height - 1; y += 2) { 793 BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width); 794 BGRAToYRow(src_bgra, dst_y, width); 795 BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width); 796 src_bgra += src_stride_bgra * 2; 797 dst_y += dst_stride_y * 2; 798 dst_u += dst_stride_u; 799 dst_v += dst_stride_v; 800 } 801 if (height & 1) { 802 BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width); 803 BGRAToYRow(src_bgra, dst_y, width); 804 } 805 return 0; 806 } 807 808 // Convert ABGR to I420. 809 LIBYUV_API 810 int ABGRToI420(const uint8* src_abgr, int src_stride_abgr, 811 uint8* dst_y, int dst_stride_y, 812 uint8* dst_u, int dst_stride_u, 813 uint8* dst_v, int dst_stride_v, 814 int width, int height) { 815 int y; 816 void (*ABGRToUVRow)(const uint8* src_abgr0, int src_stride_abgr, 817 uint8* dst_u, uint8* dst_v, int width) = ABGRToUVRow_C; 818 void (*ABGRToYRow)(const uint8* src_abgr, uint8* dst_y, int pix) = 819 ABGRToYRow_C; 820 if (!src_abgr || 821 !dst_y || !dst_u || !dst_v || 822 width <= 0 || height == 0) { 823 return -1; 824 } 825 // Negative height means invert the image. 826 if (height < 0) { 827 height = -height; 828 src_abgr = src_abgr + (height - 1) * src_stride_abgr; 829 src_stride_abgr = -src_stride_abgr; 830 } 831 #if defined(HAS_ABGRTOYROW_SSSE3) 832 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 833 ABGRToUVRow = ABGRToUVRow_Any_SSSE3; 834 ABGRToYRow = ABGRToYRow_Any_SSSE3; 835 if (IS_ALIGNED(width, 16)) { 836 ABGRToUVRow = ABGRToUVRow_Unaligned_SSSE3; 837 ABGRToYRow = ABGRToYRow_Unaligned_SSSE3; 838 if (IS_ALIGNED(src_abgr, 16) && IS_ALIGNED(src_stride_abgr, 16)) { 839 ABGRToUVRow = ABGRToUVRow_SSSE3; 840 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 841 ABGRToYRow = ABGRToYRow_SSSE3; 842 } 843 } 844 } 845 } 846 #elif defined(HAS_ABGRTOYROW_NEON) 847 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 848 ABGRToYRow = ABGRToYRow_Any_NEON; 849 if (IS_ALIGNED(width, 8)) { 850 ABGRToYRow = ABGRToYRow_NEON; 851 } 852 if (width >= 16) { 853 ABGRToUVRow = ABGRToUVRow_Any_NEON; 854 if (IS_ALIGNED(width, 16)) { 855 ABGRToUVRow = ABGRToUVRow_NEON; 856 } 857 } 858 } 859 #endif 860 861 for (y = 0; y < height - 1; y += 2) { 862 ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width); 863 ABGRToYRow(src_abgr, dst_y, width); 864 ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width); 865 src_abgr += src_stride_abgr * 2; 866 dst_y += dst_stride_y * 2; 867 dst_u += dst_stride_u; 868 dst_v += dst_stride_v; 869 } 870 if (height & 1) { 871 ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width); 872 ABGRToYRow(src_abgr, dst_y, width); 873 } 874 return 0; 875 } 876 877 // Convert RGBA to I420. 878 LIBYUV_API 879 int RGBAToI420(const uint8* src_rgba, int src_stride_rgba, 880 uint8* dst_y, int dst_stride_y, 881 uint8* dst_u, int dst_stride_u, 882 uint8* dst_v, int dst_stride_v, 883 int width, int height) { 884 int y; 885 void (*RGBAToUVRow)(const uint8* src_rgba0, int src_stride_rgba, 886 uint8* dst_u, uint8* dst_v, int width) = RGBAToUVRow_C; 887 void (*RGBAToYRow)(const uint8* src_rgba, uint8* dst_y, int pix) = 888 RGBAToYRow_C; 889 if (!src_rgba || 890 !dst_y || !dst_u || !dst_v || 891 width <= 0 || height == 0) { 892 return -1; 893 } 894 // Negative height means invert the image. 895 if (height < 0) { 896 height = -height; 897 src_rgba = src_rgba + (height - 1) * src_stride_rgba; 898 src_stride_rgba = -src_stride_rgba; 899 } 900 #if defined(HAS_RGBATOYROW_SSSE3) 901 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 902 RGBAToUVRow = RGBAToUVRow_Any_SSSE3; 903 RGBAToYRow = RGBAToYRow_Any_SSSE3; 904 if (IS_ALIGNED(width, 16)) { 905 RGBAToUVRow = RGBAToUVRow_Unaligned_SSSE3; 906 RGBAToYRow = RGBAToYRow_Unaligned_SSSE3; 907 if (IS_ALIGNED(src_rgba, 16) && IS_ALIGNED(src_stride_rgba, 16)) { 908 RGBAToUVRow = RGBAToUVRow_SSSE3; 909 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 910 RGBAToYRow = RGBAToYRow_SSSE3; 911 } 912 } 913 } 914 } 915 #elif defined(HAS_RGBATOYROW_NEON) 916 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 917 RGBAToYRow = RGBAToYRow_Any_NEON; 918 if (IS_ALIGNED(width, 8)) { 919 RGBAToYRow = RGBAToYRow_NEON; 920 } 921 if (width >= 16) { 922 RGBAToUVRow = RGBAToUVRow_Any_NEON; 923 if (IS_ALIGNED(width, 16)) { 924 RGBAToUVRow = RGBAToUVRow_NEON; 925 } 926 } 927 } 928 #endif 929 930 for (y = 0; y < height - 1; y += 2) { 931 RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width); 932 RGBAToYRow(src_rgba, dst_y, width); 933 RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width); 934 src_rgba += src_stride_rgba * 2; 935 dst_y += dst_stride_y * 2; 936 dst_u += dst_stride_u; 937 dst_v += dst_stride_v; 938 } 939 if (height & 1) { 940 RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width); 941 RGBAToYRow(src_rgba, dst_y, width); 942 } 943 return 0; 944 } 945 946 // Convert RGB24 to I420. 947 LIBYUV_API 948 int RGB24ToI420(const uint8* src_rgb24, int src_stride_rgb24, 949 uint8* dst_y, int dst_stride_y, 950 uint8* dst_u, int dst_stride_u, 951 uint8* dst_v, int dst_stride_v, 952 int width, int height) { 953 int y; 954 #if defined(HAS_RGB24TOYROW_NEON) 955 void (*RGB24ToUVRow)(const uint8* src_rgb24, int src_stride_rgb24, 956 uint8* dst_u, uint8* dst_v, int width) = RGB24ToUVRow_C; 957 void (*RGB24ToYRow)(const uint8* src_rgb24, uint8* dst_y, int pix) = 958 RGB24ToYRow_C; 959 #else 960 void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = 961 RGB24ToARGBRow_C; 962 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, 963 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; 964 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) = 965 ARGBToYRow_C; 966 // Allocate 2 rows of ARGB. 967 const int kRowSize = (width * 4 + 15) & ~15; 968 align_buffer_64(row, kRowSize * 2); 969 #endif 970 if (!src_rgb24 || !dst_y || !dst_u || !dst_v || 971 width <= 0 || height == 0) { 972 return -1; 973 } 974 // Negative height means invert the image. 975 if (height < 0) { 976 height = -height; 977 src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24; 978 src_stride_rgb24 = -src_stride_rgb24; 979 } 980 981 #if defined(HAS_RGB24TOYROW_NEON) 982 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 983 RGB24ToYRow = RGB24ToYRow_Any_NEON; 984 if (IS_ALIGNED(width, 8)) { 985 RGB24ToYRow = RGB24ToYRow_NEON; 986 } 987 if (width >= 16) { 988 RGB24ToUVRow = RGB24ToUVRow_Any_NEON; 989 if (IS_ALIGNED(width, 16)) { 990 RGB24ToUVRow = RGB24ToUVRow_NEON; 991 } 992 } 993 } 994 #else // HAS_RGB24TOYROW_NEON 995 996 #if defined(HAS_RGB24TOARGBROW_SSSE3) 997 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 998 RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3; 999 if (IS_ALIGNED(width, 16)) { 1000 RGB24ToARGBRow = RGB24ToARGBRow_SSSE3; 1001 } 1002 } 1003 #endif 1004 #if defined(HAS_ARGBTOUVROW_SSSE3) 1005 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1006 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1007 if (IS_ALIGNED(width, 16)) { 1008 ARGBToUVRow = ARGBToUVRow_SSSE3; 1009 } 1010 } 1011 #endif 1012 #if defined(HAS_ARGBTOUVROW_SSSE3) 1013 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1014 ARGBToYRow = ARGBToYRow_Any_SSSE3; 1015 if (IS_ALIGNED(width, 16)) { 1016 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3; 1017 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 1018 ARGBToYRow = ARGBToYRow_SSSE3; 1019 } 1020 } 1021 } 1022 #endif // HAS_ARGBTOUVROW_SSSE3 1023 #endif // HAS_RGB24TOYROW_NEON 1024 1025 for (y = 0; y < height - 1; y += 2) { 1026 #if defined(HAS_RGB24TOYROW_NEON) 1027 RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width); 1028 RGB24ToYRow(src_rgb24, dst_y, width); 1029 RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width); 1030 #else 1031 RGB24ToARGBRow(src_rgb24, row, width); 1032 RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width); 1033 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1034 ARGBToYRow(row, dst_y, width); 1035 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1036 #endif 1037 src_rgb24 += src_stride_rgb24 * 2; 1038 dst_y += dst_stride_y * 2; 1039 dst_u += dst_stride_u; 1040 dst_v += dst_stride_v; 1041 } 1042 if (height & 1) { 1043 #if defined(HAS_RGB24TOYROW_NEON) 1044 RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width); 1045 RGB24ToYRow(src_rgb24, dst_y, width); 1046 #else 1047 RGB24ToARGBRow(src_rgb24, row, width); 1048 ARGBToUVRow(row, 0, dst_u, dst_v, width); 1049 ARGBToYRow(row, dst_y, width); 1050 #endif 1051 } 1052 #if !defined(HAS_RGB24TOYROW_NEON) 1053 free_aligned_buffer_64(row); 1054 #endif 1055 return 0; 1056 } 1057 1058 // Convert RAW to I420. 1059 LIBYUV_API 1060 int RAWToI420(const uint8* src_raw, int src_stride_raw, 1061 uint8* dst_y, int dst_stride_y, 1062 uint8* dst_u, int dst_stride_u, 1063 uint8* dst_v, int dst_stride_v, 1064 int width, int height) { 1065 int y; 1066 #if defined(HAS_RAWTOYROW_NEON) 1067 void (*RAWToUVRow)(const uint8* src_raw, int src_stride_raw, 1068 uint8* dst_u, uint8* dst_v, int width) = RAWToUVRow_C; 1069 void (*RAWToYRow)(const uint8* src_raw, uint8* dst_y, int pix) = 1070 RAWToYRow_C; 1071 #else 1072 void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = 1073 RAWToARGBRow_C; 1074 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, 1075 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; 1076 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) = 1077 ARGBToYRow_C; 1078 // Allocate 2 rows of ARGB. 1079 const int kRowSize = (width * 4 + 15) & ~15; 1080 align_buffer_64(row, kRowSize * 2); 1081 #endif 1082 if (!src_raw || !dst_y || !dst_u || !dst_v || 1083 width <= 0 || height == 0) { 1084 return -1; 1085 } 1086 // Negative height means invert the image. 1087 if (height < 0) { 1088 height = -height; 1089 src_raw = src_raw + (height - 1) * src_stride_raw; 1090 src_stride_raw = -src_stride_raw; 1091 } 1092 1093 #if defined(HAS_RAWTOYROW_NEON) 1094 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1095 RAWToYRow = RAWToYRow_Any_NEON; 1096 if (IS_ALIGNED(width, 8)) { 1097 RAWToYRow = RAWToYRow_NEON; 1098 } 1099 if (width >= 16) { 1100 RAWToUVRow = RAWToUVRow_Any_NEON; 1101 if (IS_ALIGNED(width, 16)) { 1102 RAWToUVRow = RAWToUVRow_NEON; 1103 } 1104 } 1105 } 1106 #else // HAS_RAWTOYROW_NEON 1107 1108 #if defined(HAS_RAWTOARGBROW_SSSE3) 1109 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1110 RAWToARGBRow = RAWToARGBRow_Any_SSSE3; 1111 if (IS_ALIGNED(width, 16)) { 1112 RAWToARGBRow = RAWToARGBRow_SSSE3; 1113 } 1114 } 1115 #endif 1116 #if defined(HAS_ARGBTOUVROW_SSSE3) 1117 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1118 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1119 if (IS_ALIGNED(width, 16)) { 1120 ARGBToUVRow = ARGBToUVRow_SSSE3; 1121 } 1122 } 1123 #endif 1124 #if defined(HAS_ARGBTOUVROW_SSSE3) 1125 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1126 ARGBToYRow = ARGBToYRow_Any_SSSE3; 1127 if (IS_ALIGNED(width, 16)) { 1128 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3; 1129 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 1130 ARGBToYRow = ARGBToYRow_SSSE3; 1131 } 1132 } 1133 } 1134 #endif // HAS_ARGBTOUVROW_SSSE3 1135 #endif // HAS_RAWTOYROW_NEON 1136 1137 for (y = 0; y < height - 1; y += 2) { 1138 #if defined(HAS_RAWTOYROW_NEON) 1139 RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width); 1140 RAWToYRow(src_raw, dst_y, width); 1141 RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width); 1142 #else 1143 RAWToARGBRow(src_raw, row, width); 1144 RAWToARGBRow(src_raw + src_stride_raw, row + kRowSize, width); 1145 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1146 ARGBToYRow(row, dst_y, width); 1147 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1148 #endif 1149 src_raw += src_stride_raw * 2; 1150 dst_y += dst_stride_y * 2; 1151 dst_u += dst_stride_u; 1152 dst_v += dst_stride_v; 1153 } 1154 if (height & 1) { 1155 #if defined(HAS_RAWTOYROW_NEON) 1156 RAWToUVRow(src_raw, 0, dst_u, dst_v, width); 1157 RAWToYRow(src_raw, dst_y, width); 1158 #else 1159 RAWToARGBRow(src_raw, row, width); 1160 ARGBToUVRow(row, 0, dst_u, dst_v, width); 1161 ARGBToYRow(row, dst_y, width); 1162 #endif 1163 } 1164 #if !defined(HAS_RAWTOYROW_NEON) 1165 free_aligned_buffer_64(row); 1166 #endif 1167 return 0; 1168 } 1169 1170 // Convert RGB565 to I420. 1171 LIBYUV_API 1172 int RGB565ToI420(const uint8* src_rgb565, int src_stride_rgb565, 1173 uint8* dst_y, int dst_stride_y, 1174 uint8* dst_u, int dst_stride_u, 1175 uint8* dst_v, int dst_stride_v, 1176 int width, int height) { 1177 int y; 1178 #if defined(HAS_RGB565TOYROW_NEON) 1179 void (*RGB565ToUVRow)(const uint8* src_rgb565, int src_stride_rgb565, 1180 uint8* dst_u, uint8* dst_v, int width) = RGB565ToUVRow_C; 1181 void (*RGB565ToYRow)(const uint8* src_rgb565, uint8* dst_y, int pix) = 1182 RGB565ToYRow_C; 1183 #else 1184 void (*RGB565ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = 1185 RGB565ToARGBRow_C; 1186 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, 1187 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; 1188 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) = 1189 ARGBToYRow_C; 1190 // Allocate 2 rows of ARGB. 1191 const int kRowSize = (width * 4 + 15) & ~15; 1192 align_buffer_64(row, kRowSize * 2); 1193 #endif 1194 if (!src_rgb565 || !dst_y || !dst_u || !dst_v || 1195 width <= 0 || height == 0) { 1196 return -1; 1197 } 1198 // Negative height means invert the image. 1199 if (height < 0) { 1200 height = -height; 1201 src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565; 1202 src_stride_rgb565 = -src_stride_rgb565; 1203 } 1204 1205 #if defined(HAS_RGB565TOYROW_NEON) 1206 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1207 RGB565ToYRow = RGB565ToYRow_Any_NEON; 1208 if (IS_ALIGNED(width, 8)) { 1209 RGB565ToYRow = RGB565ToYRow_NEON; 1210 } 1211 if (width >= 16) { 1212 RGB565ToUVRow = RGB565ToUVRow_Any_NEON; 1213 if (IS_ALIGNED(width, 16)) { 1214 RGB565ToUVRow = RGB565ToUVRow_NEON; 1215 } 1216 } 1217 } 1218 #else // HAS_RGB565TOYROW_NEON 1219 1220 #if defined(HAS_RGB565TOARGBROW_SSE2) 1221 if (TestCpuFlag(kCpuHasSSE2) && width >= 8) { 1222 RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2; 1223 if (IS_ALIGNED(width, 8)) { 1224 RGB565ToARGBRow = RGB565ToARGBRow_SSE2; 1225 } 1226 } 1227 #endif 1228 #if defined(HAS_ARGBTOUVROW_SSSE3) 1229 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1230 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1231 if (IS_ALIGNED(width, 16)) { 1232 ARGBToUVRow = ARGBToUVRow_SSSE3; 1233 } 1234 } 1235 #endif 1236 #if defined(HAS_ARGBTOUVROW_SSSE3) 1237 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1238 ARGBToYRow = ARGBToYRow_Any_SSSE3; 1239 if (IS_ALIGNED(width, 16)) { 1240 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3; 1241 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 1242 ARGBToYRow = ARGBToYRow_SSSE3; 1243 } 1244 } 1245 } 1246 #endif // HAS_ARGBTOUVROW_SSSE3 1247 #endif // HAS_RGB565TOYROW_NEON 1248 1249 for (y = 0; y < height - 1; y += 2) { 1250 #if defined(HAS_RGB565TOYROW_NEON) 1251 RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width); 1252 RGB565ToYRow(src_rgb565, dst_y, width); 1253 RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width); 1254 #else 1255 RGB565ToARGBRow(src_rgb565, row, width); 1256 RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kRowSize, width); 1257 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1258 ARGBToYRow(row, dst_y, width); 1259 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1260 #endif 1261 src_rgb565 += src_stride_rgb565 * 2; 1262 dst_y += dst_stride_y * 2; 1263 dst_u += dst_stride_u; 1264 dst_v += dst_stride_v; 1265 } 1266 if (height & 1) { 1267 #if defined(HAS_RGB565TOYROW_NEON) 1268 RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width); 1269 RGB565ToYRow(src_rgb565, dst_y, width); 1270 #else 1271 RGB565ToARGBRow(src_rgb565, row, width); 1272 ARGBToUVRow(row, 0, dst_u, dst_v, width); 1273 ARGBToYRow(row, dst_y, width); 1274 #endif 1275 } 1276 #if !defined(HAS_RGB565TOYROW_NEON) 1277 free_aligned_buffer_64(row); 1278 #endif 1279 return 0; 1280 } 1281 1282 // Convert ARGB1555 to I420. 1283 LIBYUV_API 1284 int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555, 1285 uint8* dst_y, int dst_stride_y, 1286 uint8* dst_u, int dst_stride_u, 1287 uint8* dst_v, int dst_stride_v, 1288 int width, int height) { 1289 int y; 1290 #if defined(HAS_ARGB1555TOYROW_NEON) 1291 void (*ARGB1555ToUVRow)(const uint8* src_argb1555, int src_stride_argb1555, 1292 uint8* dst_u, uint8* dst_v, int width) = ARGB1555ToUVRow_C; 1293 void (*ARGB1555ToYRow)(const uint8* src_argb1555, uint8* dst_y, int pix) = 1294 ARGB1555ToYRow_C; 1295 #else 1296 void (*ARGB1555ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = 1297 ARGB1555ToARGBRow_C; 1298 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, 1299 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; 1300 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) = 1301 ARGBToYRow_C; 1302 // Allocate 2 rows of ARGB. 1303 const int kRowSize = (width * 4 + 15) & ~15; 1304 align_buffer_64(row, kRowSize * 2); 1305 #endif 1306 if (!src_argb1555 || !dst_y || !dst_u || !dst_v || 1307 width <= 0 || height == 0) { 1308 return -1; 1309 } 1310 // Negative height means invert the image. 1311 if (height < 0) { 1312 height = -height; 1313 src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555; 1314 src_stride_argb1555 = -src_stride_argb1555; 1315 } 1316 1317 #if defined(HAS_ARGB1555TOYROW_NEON) 1318 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1319 ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON; 1320 if (IS_ALIGNED(width, 8)) { 1321 ARGB1555ToYRow = ARGB1555ToYRow_NEON; 1322 } 1323 if (width >= 16) { 1324 ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON; 1325 if (IS_ALIGNED(width, 16)) { 1326 ARGB1555ToUVRow = ARGB1555ToUVRow_NEON; 1327 } 1328 } 1329 } 1330 #else // HAS_ARGB1555TOYROW_NEON 1331 1332 #if defined(HAS_ARGB1555TOARGBROW_SSE2) 1333 if (TestCpuFlag(kCpuHasSSE2) && width >= 8) { 1334 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2; 1335 if (IS_ALIGNED(width, 8)) { 1336 ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2; 1337 } 1338 } 1339 #endif 1340 #if defined(HAS_ARGBTOUVROW_SSSE3) 1341 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1342 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1343 if (IS_ALIGNED(width, 16)) { 1344 ARGBToUVRow = ARGBToUVRow_SSSE3; 1345 } 1346 } 1347 #endif 1348 #if defined(HAS_ARGBTOUVROW_SSSE3) 1349 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1350 ARGBToYRow = ARGBToYRow_Any_SSSE3; 1351 if (IS_ALIGNED(width, 16)) { 1352 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3; 1353 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 1354 ARGBToYRow = ARGBToYRow_SSSE3; 1355 } 1356 } 1357 } 1358 #endif // HAS_ARGBTOUVROW_SSSE3 1359 #endif // HAS_ARGB1555TOYROW_NEON 1360 1361 for (y = 0; y < height - 1; y += 2) { 1362 #if defined(HAS_ARGB1555TOYROW_NEON) 1363 ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width); 1364 ARGB1555ToYRow(src_argb1555, dst_y, width); 1365 ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y, 1366 width); 1367 #else 1368 ARGB1555ToARGBRow(src_argb1555, row, width); 1369 ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize, 1370 width); 1371 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1372 ARGBToYRow(row, dst_y, width); 1373 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1374 #endif 1375 src_argb1555 += src_stride_argb1555 * 2; 1376 dst_y += dst_stride_y * 2; 1377 dst_u += dst_stride_u; 1378 dst_v += dst_stride_v; 1379 } 1380 if (height & 1) { 1381 #if defined(HAS_ARGB1555TOYROW_NEON) 1382 ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width); 1383 ARGB1555ToYRow(src_argb1555, dst_y, width); 1384 #else 1385 ARGB1555ToARGBRow(src_argb1555, row, width); 1386 ARGBToUVRow(row, 0, dst_u, dst_v, width); 1387 ARGBToYRow(row, dst_y, width); 1388 #endif 1389 } 1390 #if !defined(HAS_ARGB1555TOYROW_NEON) 1391 free_aligned_buffer_64(row); 1392 #endif 1393 return 0; 1394 } 1395 1396 // Convert ARGB4444 to I420. 1397 LIBYUV_API 1398 int ARGB4444ToI420(const uint8* src_argb4444, int src_stride_argb4444, 1399 uint8* dst_y, int dst_stride_y, 1400 uint8* dst_u, int dst_stride_u, 1401 uint8* dst_v, int dst_stride_v, 1402 int width, int height) { 1403 int y; 1404 #if defined(HAS_ARGB4444TOYROW_NEON) 1405 void (*ARGB4444ToUVRow)(const uint8* src_argb4444, int src_stride_argb4444, 1406 uint8* dst_u, uint8* dst_v, int width) = ARGB4444ToUVRow_C; 1407 void (*ARGB4444ToYRow)(const uint8* src_argb4444, uint8* dst_y, int pix) = 1408 ARGB4444ToYRow_C; 1409 #else 1410 void (*ARGB4444ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = 1411 ARGB4444ToARGBRow_C; 1412 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, 1413 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; 1414 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) = 1415 ARGBToYRow_C; 1416 // Allocate 2 rows of ARGB. 1417 const int kRowSize = (width * 4 + 15) & ~15; 1418 align_buffer_64(row, kRowSize * 2); 1419 #endif 1420 if (!src_argb4444 || !dst_y || !dst_u || !dst_v || 1421 width <= 0 || height == 0) { 1422 return -1; 1423 } 1424 // Negative height means invert the image. 1425 if (height < 0) { 1426 height = -height; 1427 src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444; 1428 src_stride_argb4444 = -src_stride_argb4444; 1429 } 1430 1431 #if defined(HAS_ARGB4444TOYROW_NEON) 1432 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 1433 ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON; 1434 if (IS_ALIGNED(width, 8)) { 1435 ARGB4444ToYRow = ARGB4444ToYRow_NEON; 1436 } 1437 if (width >= 16) { 1438 ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON; 1439 if (IS_ALIGNED(width, 16)) { 1440 ARGB4444ToUVRow = ARGB4444ToUVRow_NEON; 1441 } 1442 } 1443 } 1444 #else // HAS_ARGB4444TOYROW_NEON 1445 1446 #if defined(HAS_ARGB4444TOARGBROW_SSE2) 1447 if (TestCpuFlag(kCpuHasSSE2) && width >= 8) { 1448 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2; 1449 if (IS_ALIGNED(width, 8)) { 1450 ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2; 1451 } 1452 } 1453 #endif 1454 #if defined(HAS_ARGBTOUVROW_SSSE3) 1455 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1456 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 1457 if (IS_ALIGNED(width, 16)) { 1458 ARGBToUVRow = ARGBToUVRow_SSSE3; 1459 } 1460 } 1461 #endif 1462 #if defined(HAS_ARGBTOUVROW_SSSE3) 1463 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 1464 ARGBToYRow = ARGBToYRow_Any_SSSE3; 1465 if (IS_ALIGNED(width, 16)) { 1466 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3; 1467 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 1468 ARGBToYRow = ARGBToYRow_SSSE3; 1469 } 1470 } 1471 } 1472 #endif // HAS_ARGBTOUVROW_SSSE3 1473 #endif // HAS_ARGB4444TOYROW_NEON 1474 1475 for (y = 0; y < height - 1; y += 2) { 1476 #if defined(HAS_ARGB4444TOYROW_NEON) 1477 ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width); 1478 ARGB4444ToYRow(src_argb4444, dst_y, width); 1479 ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y, 1480 width); 1481 #else 1482 ARGB4444ToARGBRow(src_argb4444, row, width); 1483 ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kRowSize, 1484 width); 1485 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 1486 ARGBToYRow(row, dst_y, width); 1487 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 1488 #endif 1489 src_argb4444 += src_stride_argb4444 * 2; 1490 dst_y += dst_stride_y * 2; 1491 dst_u += dst_stride_u; 1492 dst_v += dst_stride_v; 1493 } 1494 if (height & 1) { 1495 #if defined(HAS_ARGB4444TOYROW_NEON) 1496 ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width); 1497 ARGB4444ToYRow(src_argb4444, dst_y, width); 1498 #else 1499 ARGB4444ToARGBRow(src_argb4444, row, width); 1500 ARGBToUVRow(row, 0, dst_u, dst_v, width); 1501 ARGBToYRow(row, dst_y, width); 1502 #endif 1503 } 1504 #if !defined(HAS_ARGB4444TOYROW_NEON) 1505 free_aligned_buffer_64(row); 1506 #endif 1507 return 0; 1508 } 1509 1510 #ifdef __cplusplus 1511 } // extern "C" 1512 } // namespace libyuv 1513 #endif 1514