1/* 2 * Copyright 2012 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_from_argb.h" 12 13#include "libyuv/basic_types.h" 14#include "libyuv/cpu_id.h" 15#include "libyuv/planar_functions.h" 16#include "libyuv/row.h" 17 18#ifdef __cplusplus 19namespace libyuv { 20extern "C" { 21#endif 22 23// ARGB little endian (bgra in memory) to I444 24LIBYUV_API 25int ARGBToI444(const uint8* src_argb, int src_stride_argb, 26 uint8* dst_y, int dst_stride_y, 27 uint8* dst_u, int dst_stride_u, 28 uint8* dst_v, int dst_stride_v, 29 int width, int height) { 30 int y; 31 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = 32 ARGBToYRow_C; 33 void (*ARGBToUV444Row)(const uint8* src_argb, uint8* dst_u, uint8* dst_v, 34 int width) = ARGBToUV444Row_C; 35 if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { 36 return -1; 37 } 38 if (height < 0) { 39 height = -height; 40 src_argb = src_argb + (height - 1) * src_stride_argb; 41 src_stride_argb = -src_stride_argb; 42 } 43 // Coalesce rows. 44 if (src_stride_argb == width * 4 && 45 dst_stride_y == width && 46 dst_stride_u == width && 47 dst_stride_v == width) { 48 width *= height; 49 height = 1; 50 src_stride_argb = dst_stride_y = dst_stride_u = dst_stride_v = 0; 51 } 52#if defined(HAS_ARGBTOUV444ROW_SSSE3) 53 if (TestCpuFlag(kCpuHasSSSE3)) { 54 ARGBToUV444Row = ARGBToUV444Row_Any_SSSE3; 55 if (IS_ALIGNED(width, 16)) { 56 ARGBToUV444Row = ARGBToUV444Row_SSSE3; 57 } 58 } 59#endif 60#if defined(HAS_ARGBTOUV444ROW_NEON) 61 if (TestCpuFlag(kCpuHasNEON)) { 62 ARGBToUV444Row = ARGBToUV444Row_Any_NEON; 63 if (IS_ALIGNED(width, 8)) { 64 ARGBToUV444Row = ARGBToUV444Row_NEON; 65 } 66 } 67#endif 68#if defined(HAS_ARGBTOYROW_SSSE3) 69 if (TestCpuFlag(kCpuHasSSSE3)) { 70 ARGBToYRow = ARGBToYRow_Any_SSSE3; 71 if (IS_ALIGNED(width, 16)) { 72 ARGBToYRow = ARGBToYRow_SSSE3; 73 } 74 } 75#endif 76#if defined(HAS_ARGBTOYROW_AVX2) 77 if (TestCpuFlag(kCpuHasAVX2)) { 78 ARGBToYRow = ARGBToYRow_Any_AVX2; 79 if (IS_ALIGNED(width, 32)) { 80 ARGBToYRow = ARGBToYRow_AVX2; 81 } 82 } 83#endif 84#if defined(HAS_ARGBTOYROW_NEON) 85 if (TestCpuFlag(kCpuHasNEON)) { 86 ARGBToYRow = ARGBToYRow_Any_NEON; 87 if (IS_ALIGNED(width, 8)) { 88 ARGBToYRow = ARGBToYRow_NEON; 89 } 90 } 91#endif 92 93 for (y = 0; y < height; ++y) { 94 ARGBToUV444Row(src_argb, dst_u, dst_v, width); 95 ARGBToYRow(src_argb, dst_y, width); 96 src_argb += src_stride_argb; 97 dst_y += dst_stride_y; 98 dst_u += dst_stride_u; 99 dst_v += dst_stride_v; 100 } 101 return 0; 102} 103 104// ARGB little endian (bgra in memory) to I422 105LIBYUV_API 106int ARGBToI422(const uint8* src_argb, int src_stride_argb, 107 uint8* dst_y, int dst_stride_y, 108 uint8* dst_u, int dst_stride_u, 109 uint8* dst_v, int dst_stride_v, 110 int width, int height) { 111 int y; 112 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, 113 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; 114 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = 115 ARGBToYRow_C; 116 if (!src_argb || 117 !dst_y || !dst_u || !dst_v || 118 width <= 0 || height == 0) { 119 return -1; 120 } 121 // Negative height means invert the image. 122 if (height < 0) { 123 height = -height; 124 src_argb = src_argb + (height - 1) * src_stride_argb; 125 src_stride_argb = -src_stride_argb; 126 } 127 // Coalesce rows. 128 if (src_stride_argb == width * 4 && 129 dst_stride_y == width && 130 dst_stride_u * 2 == width && 131 dst_stride_v * 2 == width) { 132 width *= height; 133 height = 1; 134 src_stride_argb = dst_stride_y = dst_stride_u = dst_stride_v = 0; 135 } 136#if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) 137 if (TestCpuFlag(kCpuHasSSSE3)) { 138 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 139 ARGBToYRow = ARGBToYRow_Any_SSSE3; 140 if (IS_ALIGNED(width, 16)) { 141 ARGBToUVRow = ARGBToUVRow_SSSE3; 142 ARGBToYRow = ARGBToYRow_SSSE3; 143 } 144 } 145#endif 146#if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) 147 if (TestCpuFlag(kCpuHasAVX2)) { 148 ARGBToUVRow = ARGBToUVRow_Any_AVX2; 149 ARGBToYRow = ARGBToYRow_Any_AVX2; 150 if (IS_ALIGNED(width, 32)) { 151 ARGBToUVRow = ARGBToUVRow_AVX2; 152 ARGBToYRow = ARGBToYRow_AVX2; 153 } 154 } 155#endif 156#if defined(HAS_ARGBTOYROW_NEON) 157 if (TestCpuFlag(kCpuHasNEON)) { 158 ARGBToYRow = ARGBToYRow_Any_NEON; 159 if (IS_ALIGNED(width, 8)) { 160 ARGBToYRow = ARGBToYRow_NEON; 161 } 162 } 163#endif 164#if defined(HAS_ARGBTOUVROW_NEON) 165 if (TestCpuFlag(kCpuHasNEON)) { 166 ARGBToUVRow = ARGBToUVRow_Any_NEON; 167 if (IS_ALIGNED(width, 16)) { 168 ARGBToUVRow = ARGBToUVRow_NEON; 169 } 170 } 171#endif 172 173 for (y = 0; y < height; ++y) { 174 ARGBToUVRow(src_argb, 0, dst_u, dst_v, width); 175 ARGBToYRow(src_argb, dst_y, width); 176 src_argb += src_stride_argb; 177 dst_y += dst_stride_y; 178 dst_u += dst_stride_u; 179 dst_v += dst_stride_v; 180 } 181 return 0; 182} 183 184// ARGB little endian (bgra in memory) to I411 185LIBYUV_API 186int ARGBToI411(const uint8* src_argb, int src_stride_argb, 187 uint8* dst_y, int dst_stride_y, 188 uint8* dst_u, int dst_stride_u, 189 uint8* dst_v, int dst_stride_v, 190 int width, int height) { 191 int y; 192 void (*ARGBToUV411Row)(const uint8* src_argb, uint8* dst_u, uint8* dst_v, 193 int width) = ARGBToUV411Row_C; 194 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = 195 ARGBToYRow_C; 196 if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { 197 return -1; 198 } 199 if (height < 0) { 200 height = -height; 201 src_argb = src_argb + (height - 1) * src_stride_argb; 202 src_stride_argb = -src_stride_argb; 203 } 204 // Coalesce rows. 205 if (src_stride_argb == width * 4 && 206 dst_stride_y == width && 207 dst_stride_u * 4 == width && 208 dst_stride_v * 4 == width) { 209 width *= height; 210 height = 1; 211 src_stride_argb = dst_stride_y = dst_stride_u = dst_stride_v = 0; 212 } 213#if defined(HAS_ARGBTOYROW_SSSE3) 214 if (TestCpuFlag(kCpuHasSSSE3)) { 215 ARGBToYRow = ARGBToYRow_Any_SSSE3; 216 if (IS_ALIGNED(width, 16)) { 217 ARGBToYRow = ARGBToYRow_SSSE3; 218 } 219 } 220#endif 221#if defined(HAS_ARGBTOYROW_AVX2) 222 if (TestCpuFlag(kCpuHasAVX2)) { 223 ARGBToYRow = ARGBToYRow_Any_AVX2; 224 if (IS_ALIGNED(width, 32)) { 225 ARGBToYRow = ARGBToYRow_AVX2; 226 } 227 } 228#endif 229#if defined(HAS_ARGBTOYROW_NEON) 230 if (TestCpuFlag(kCpuHasNEON)) { 231 ARGBToYRow = ARGBToYRow_Any_NEON; 232 if (IS_ALIGNED(width, 8)) { 233 ARGBToYRow = ARGBToYRow_NEON; 234 } 235 } 236#endif 237#if defined(HAS_ARGBTOUV411ROW_NEON) 238 if (TestCpuFlag(kCpuHasNEON)) { 239 ARGBToUV411Row = ARGBToUV411Row_Any_NEON; 240 if (IS_ALIGNED(width, 32)) { 241 ARGBToUV411Row = ARGBToUV411Row_NEON; 242 } 243 } 244#endif 245 246 for (y = 0; y < height; ++y) { 247 ARGBToUV411Row(src_argb, dst_u, dst_v, width); 248 ARGBToYRow(src_argb, dst_y, width); 249 src_argb += src_stride_argb; 250 dst_y += dst_stride_y; 251 dst_u += dst_stride_u; 252 dst_v += dst_stride_v; 253 } 254 return 0; 255} 256 257LIBYUV_API 258int ARGBToNV12(const uint8* src_argb, int src_stride_argb, 259 uint8* dst_y, int dst_stride_y, 260 uint8* dst_uv, int dst_stride_uv, 261 int width, int height) { 262 int y; 263 int halfwidth = (width + 1) >> 1; 264 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, 265 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; 266 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = 267 ARGBToYRow_C; 268 void (*MergeUVRow_)(const uint8* src_u, const uint8* src_v, uint8* dst_uv, 269 int width) = MergeUVRow_C; 270 if (!src_argb || 271 !dst_y || !dst_uv || 272 width <= 0 || height == 0) { 273 return -1; 274 } 275 // Negative height means invert the image. 276 if (height < 0) { 277 height = -height; 278 src_argb = src_argb + (height - 1) * src_stride_argb; 279 src_stride_argb = -src_stride_argb; 280 } 281#if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) 282 if (TestCpuFlag(kCpuHasSSSE3)) { 283 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 284 ARGBToYRow = ARGBToYRow_Any_SSSE3; 285 if (IS_ALIGNED(width, 16)) { 286 ARGBToUVRow = ARGBToUVRow_SSSE3; 287 ARGBToYRow = ARGBToYRow_SSSE3; 288 } 289 } 290#endif 291#if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) 292 if (TestCpuFlag(kCpuHasAVX2)) { 293 ARGBToUVRow = ARGBToUVRow_Any_AVX2; 294 ARGBToYRow = ARGBToYRow_Any_AVX2; 295 if (IS_ALIGNED(width, 32)) { 296 ARGBToUVRow = ARGBToUVRow_AVX2; 297 ARGBToYRow = ARGBToYRow_AVX2; 298 } 299 } 300#endif 301#if defined(HAS_ARGBTOYROW_NEON) 302 if (TestCpuFlag(kCpuHasNEON)) { 303 ARGBToYRow = ARGBToYRow_Any_NEON; 304 if (IS_ALIGNED(width, 8)) { 305 ARGBToYRow = ARGBToYRow_NEON; 306 } 307 } 308#endif 309#if defined(HAS_ARGBTOUVROW_NEON) 310 if (TestCpuFlag(kCpuHasNEON)) { 311 ARGBToUVRow = ARGBToUVRow_Any_NEON; 312 if (IS_ALIGNED(width, 16)) { 313 ARGBToUVRow = ARGBToUVRow_NEON; 314 } 315 } 316#endif 317#if defined(HAS_MERGEUVROW_SSE2) 318 if (TestCpuFlag(kCpuHasSSE2)) { 319 MergeUVRow_ = MergeUVRow_Any_SSE2; 320 if (IS_ALIGNED(halfwidth, 16)) { 321 MergeUVRow_ = MergeUVRow_SSE2; 322 } 323 } 324#endif 325#if defined(HAS_MERGEUVROW_AVX2) 326 if (TestCpuFlag(kCpuHasAVX2)) { 327 MergeUVRow_ = MergeUVRow_Any_AVX2; 328 if (IS_ALIGNED(halfwidth, 32)) { 329 MergeUVRow_ = MergeUVRow_AVX2; 330 } 331 } 332#endif 333#if defined(HAS_MERGEUVROW_NEON) 334 if (TestCpuFlag(kCpuHasNEON)) { 335 MergeUVRow_ = MergeUVRow_Any_NEON; 336 if (IS_ALIGNED(halfwidth, 16)) { 337 MergeUVRow_ = MergeUVRow_NEON; 338 } 339 } 340#endif 341 { 342 // Allocate a rows of uv. 343 align_buffer_64(row_u, ((halfwidth + 31) & ~31) * 2); 344 uint8* row_v = row_u + ((halfwidth + 31) & ~31); 345 346 for (y = 0; y < height - 1; y += 2) { 347 ARGBToUVRow(src_argb, src_stride_argb, row_u, row_v, width); 348 MergeUVRow_(row_u, row_v, dst_uv, halfwidth); 349 ARGBToYRow(src_argb, dst_y, width); 350 ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width); 351 src_argb += src_stride_argb * 2; 352 dst_y += dst_stride_y * 2; 353 dst_uv += dst_stride_uv; 354 } 355 if (height & 1) { 356 ARGBToUVRow(src_argb, 0, row_u, row_v, width); 357 MergeUVRow_(row_u, row_v, dst_uv, halfwidth); 358 ARGBToYRow(src_argb, dst_y, width); 359 } 360 free_aligned_buffer_64(row_u); 361 } 362 return 0; 363} 364 365// Same as NV12 but U and V swapped. 366LIBYUV_API 367int ARGBToNV21(const uint8* src_argb, int src_stride_argb, 368 uint8* dst_y, int dst_stride_y, 369 uint8* dst_uv, int dst_stride_uv, 370 int width, int height) { 371 int y; 372 int halfwidth = (width + 1) >> 1; 373 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, 374 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; 375 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = 376 ARGBToYRow_C; 377 void (*MergeUVRow_)(const uint8* src_u, const uint8* src_v, uint8* dst_uv, 378 int width) = MergeUVRow_C; 379 if (!src_argb || 380 !dst_y || !dst_uv || 381 width <= 0 || height == 0) { 382 return -1; 383 } 384 // Negative height means invert the image. 385 if (height < 0) { 386 height = -height; 387 src_argb = src_argb + (height - 1) * src_stride_argb; 388 src_stride_argb = -src_stride_argb; 389 } 390#if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) 391 if (TestCpuFlag(kCpuHasSSSE3)) { 392 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 393 ARGBToYRow = ARGBToYRow_Any_SSSE3; 394 if (IS_ALIGNED(width, 16)) { 395 ARGBToUVRow = ARGBToUVRow_SSSE3; 396 ARGBToYRow = ARGBToYRow_SSSE3; 397 } 398 } 399#endif 400#if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) 401 if (TestCpuFlag(kCpuHasAVX2)) { 402 ARGBToUVRow = ARGBToUVRow_Any_AVX2; 403 ARGBToYRow = ARGBToYRow_Any_AVX2; 404 if (IS_ALIGNED(width, 32)) { 405 ARGBToUVRow = ARGBToUVRow_AVX2; 406 ARGBToYRow = ARGBToYRow_AVX2; 407 } 408 } 409#endif 410#if defined(HAS_ARGBTOYROW_NEON) 411 if (TestCpuFlag(kCpuHasNEON)) { 412 ARGBToYRow = ARGBToYRow_Any_NEON; 413 if (IS_ALIGNED(width, 8)) { 414 ARGBToYRow = ARGBToYRow_NEON; 415 } 416 } 417#endif 418#if defined(HAS_ARGBTOUVROW_NEON) 419 if (TestCpuFlag(kCpuHasNEON)) { 420 ARGBToUVRow = ARGBToUVRow_Any_NEON; 421 if (IS_ALIGNED(width, 16)) { 422 ARGBToUVRow = ARGBToUVRow_NEON; 423 } 424 } 425#endif 426#if defined(HAS_MERGEUVROW_SSE2) 427 if (TestCpuFlag(kCpuHasSSE2)) { 428 MergeUVRow_ = MergeUVRow_Any_SSE2; 429 if (IS_ALIGNED(halfwidth, 16)) { 430 MergeUVRow_ = MergeUVRow_SSE2; 431 } 432 } 433#endif 434#if defined(HAS_MERGEUVROW_AVX2) 435 if (TestCpuFlag(kCpuHasAVX2)) { 436 MergeUVRow_ = MergeUVRow_Any_AVX2; 437 if (IS_ALIGNED(halfwidth, 32)) { 438 MergeUVRow_ = MergeUVRow_AVX2; 439 } 440 } 441#endif 442#if defined(HAS_MERGEUVROW_NEON) 443 if (TestCpuFlag(kCpuHasNEON)) { 444 MergeUVRow_ = MergeUVRow_Any_NEON; 445 if (IS_ALIGNED(halfwidth, 16)) { 446 MergeUVRow_ = MergeUVRow_NEON; 447 } 448 } 449#endif 450 { 451 // Allocate a rows of uv. 452 align_buffer_64(row_u, ((halfwidth + 31) & ~31) * 2); 453 uint8* row_v = row_u + ((halfwidth + 31) & ~31); 454 455 for (y = 0; y < height - 1; y += 2) { 456 ARGBToUVRow(src_argb, src_stride_argb, row_u, row_v, width); 457 MergeUVRow_(row_v, row_u, dst_uv, halfwidth); 458 ARGBToYRow(src_argb, dst_y, width); 459 ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width); 460 src_argb += src_stride_argb * 2; 461 dst_y += dst_stride_y * 2; 462 dst_uv += dst_stride_uv; 463 } 464 if (height & 1) { 465 ARGBToUVRow(src_argb, 0, row_u, row_v, width); 466 MergeUVRow_(row_v, row_u, dst_uv, halfwidth); 467 ARGBToYRow(src_argb, dst_y, width); 468 } 469 free_aligned_buffer_64(row_u); 470 } 471 return 0; 472} 473 474// Convert ARGB to YUY2. 475LIBYUV_API 476int ARGBToYUY2(const uint8* src_argb, int src_stride_argb, 477 uint8* dst_yuy2, int dst_stride_yuy2, 478 int width, int height) { 479 int y; 480 void (*ARGBToUVRow)(const uint8* src_argb, int src_stride_argb, 481 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; 482 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = 483 ARGBToYRow_C; 484 void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u, 485 const uint8* src_v, uint8* dst_yuy2, int width) = I422ToYUY2Row_C; 486 487 if (!src_argb || !dst_yuy2 || 488 width <= 0 || height == 0) { 489 return -1; 490 } 491 // Negative height means invert the image. 492 if (height < 0) { 493 height = -height; 494 dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2; 495 dst_stride_yuy2 = -dst_stride_yuy2; 496 } 497 // Coalesce rows. 498 if (src_stride_argb == width * 4 && 499 dst_stride_yuy2 == width * 2) { 500 width *= height; 501 height = 1; 502 src_stride_argb = dst_stride_yuy2 = 0; 503 } 504#if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) 505 if (TestCpuFlag(kCpuHasSSSE3)) { 506 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 507 ARGBToYRow = ARGBToYRow_Any_SSSE3; 508 if (IS_ALIGNED(width, 16)) { 509 ARGBToUVRow = ARGBToUVRow_SSSE3; 510 ARGBToYRow = ARGBToYRow_SSSE3; 511 } 512 } 513#endif 514#if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) 515 if (TestCpuFlag(kCpuHasAVX2)) { 516 ARGBToUVRow = ARGBToUVRow_Any_AVX2; 517 ARGBToYRow = ARGBToYRow_Any_AVX2; 518 if (IS_ALIGNED(width, 32)) { 519 ARGBToUVRow = ARGBToUVRow_AVX2; 520 ARGBToYRow = ARGBToYRow_AVX2; 521 } 522 } 523#endif 524#if defined(HAS_ARGBTOYROW_NEON) 525 if (TestCpuFlag(kCpuHasNEON)) { 526 ARGBToYRow = ARGBToYRow_Any_NEON; 527 if (IS_ALIGNED(width, 8)) { 528 ARGBToYRow = ARGBToYRow_NEON; 529 } 530 } 531#endif 532#if defined(HAS_ARGBTOUVROW_NEON) 533 if (TestCpuFlag(kCpuHasNEON)) { 534 ARGBToUVRow = ARGBToUVRow_Any_NEON; 535 if (IS_ALIGNED(width, 16)) { 536 ARGBToUVRow = ARGBToUVRow_NEON; 537 } 538 } 539#endif 540#if defined(HAS_I422TOYUY2ROW_SSE2) 541 if (TestCpuFlag(kCpuHasSSE2)) { 542 I422ToYUY2Row = I422ToYUY2Row_Any_SSE2; 543 if (IS_ALIGNED(width, 16)) { 544 I422ToYUY2Row = I422ToYUY2Row_SSE2; 545 } 546 } 547#endif 548#if defined(HAS_I422TOYUY2ROW_NEON) 549 if (TestCpuFlag(kCpuHasNEON)) { 550 I422ToYUY2Row = I422ToYUY2Row_Any_NEON; 551 if (IS_ALIGNED(width, 16)) { 552 I422ToYUY2Row = I422ToYUY2Row_NEON; 553 } 554 } 555#endif 556 557 { 558 // Allocate a rows of yuv. 559 align_buffer_64(row_y, ((width + 63) & ~63) * 2); 560 uint8* row_u = row_y + ((width + 63) & ~63); 561 uint8* row_v = row_u + ((width + 63) & ~63) / 2; 562 563 for (y = 0; y < height; ++y) { 564 ARGBToUVRow(src_argb, 0, row_u, row_v, width); 565 ARGBToYRow(src_argb, row_y, width); 566 I422ToYUY2Row(row_y, row_u, row_v, dst_yuy2, width); 567 src_argb += src_stride_argb; 568 dst_yuy2 += dst_stride_yuy2; 569 } 570 571 free_aligned_buffer_64(row_y); 572 } 573 return 0; 574} 575 576// Convert ARGB to UYVY. 577LIBYUV_API 578int ARGBToUYVY(const uint8* src_argb, int src_stride_argb, 579 uint8* dst_uyvy, int dst_stride_uyvy, 580 int width, int height) { 581 int y; 582 void (*ARGBToUVRow)(const uint8* src_argb, int src_stride_argb, 583 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; 584 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = 585 ARGBToYRow_C; 586 void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u, 587 const uint8* src_v, uint8* dst_uyvy, int width) = I422ToUYVYRow_C; 588 589 if (!src_argb || !dst_uyvy || 590 width <= 0 || height == 0) { 591 return -1; 592 } 593 // Negative height means invert the image. 594 if (height < 0) { 595 height = -height; 596 dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy; 597 dst_stride_uyvy = -dst_stride_uyvy; 598 } 599 // Coalesce rows. 600 if (src_stride_argb == width * 4 && 601 dst_stride_uyvy == width * 2) { 602 width *= height; 603 height = 1; 604 src_stride_argb = dst_stride_uyvy = 0; 605 } 606#if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) 607 if (TestCpuFlag(kCpuHasSSSE3)) { 608 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 609 ARGBToYRow = ARGBToYRow_Any_SSSE3; 610 if (IS_ALIGNED(width, 16)) { 611 ARGBToUVRow = ARGBToUVRow_SSSE3; 612 ARGBToYRow = ARGBToYRow_SSSE3; 613 } 614 } 615#endif 616#if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) 617 if (TestCpuFlag(kCpuHasAVX2)) { 618 ARGBToUVRow = ARGBToUVRow_Any_AVX2; 619 ARGBToYRow = ARGBToYRow_Any_AVX2; 620 if (IS_ALIGNED(width, 32)) { 621 ARGBToUVRow = ARGBToUVRow_AVX2; 622 ARGBToYRow = ARGBToYRow_AVX2; 623 } 624 } 625#endif 626#if defined(HAS_ARGBTOYROW_NEON) 627 if (TestCpuFlag(kCpuHasNEON)) { 628 ARGBToYRow = ARGBToYRow_Any_NEON; 629 if (IS_ALIGNED(width, 8)) { 630 ARGBToYRow = ARGBToYRow_NEON; 631 } 632 } 633#endif 634#if defined(HAS_ARGBTOUVROW_NEON) 635 if (TestCpuFlag(kCpuHasNEON)) { 636 ARGBToUVRow = ARGBToUVRow_Any_NEON; 637 if (IS_ALIGNED(width, 16)) { 638 ARGBToUVRow = ARGBToUVRow_NEON; 639 } 640 } 641#endif 642#if defined(HAS_I422TOUYVYROW_SSE2) 643 if (TestCpuFlag(kCpuHasSSE2)) { 644 I422ToUYVYRow = I422ToUYVYRow_Any_SSE2; 645 if (IS_ALIGNED(width, 16)) { 646 I422ToUYVYRow = I422ToUYVYRow_SSE2; 647 } 648 } 649#endif 650#if defined(HAS_I422TOUYVYROW_NEON) 651 if (TestCpuFlag(kCpuHasNEON)) { 652 I422ToUYVYRow = I422ToUYVYRow_Any_NEON; 653 if (IS_ALIGNED(width, 16)) { 654 I422ToUYVYRow = I422ToUYVYRow_NEON; 655 } 656 } 657#endif 658 659 { 660 // Allocate a rows of yuv. 661 align_buffer_64(row_y, ((width + 63) & ~63) * 2); 662 uint8* row_u = row_y + ((width + 63) & ~63); 663 uint8* row_v = row_u + ((width + 63) & ~63) / 2; 664 665 for (y = 0; y < height; ++y) { 666 ARGBToUVRow(src_argb, 0, row_u, row_v, width); 667 ARGBToYRow(src_argb, row_y, width); 668 I422ToUYVYRow(row_y, row_u, row_v, dst_uyvy, width); 669 src_argb += src_stride_argb; 670 dst_uyvy += dst_stride_uyvy; 671 } 672 673 free_aligned_buffer_64(row_y); 674 } 675 return 0; 676} 677 678// Convert ARGB to I400. 679LIBYUV_API 680int ARGBToI400(const uint8* src_argb, int src_stride_argb, 681 uint8* dst_y, int dst_stride_y, 682 int width, int height) { 683 int y; 684 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = 685 ARGBToYRow_C; 686 if (!src_argb || !dst_y || width <= 0 || height == 0) { 687 return -1; 688 } 689 if (height < 0) { 690 height = -height; 691 src_argb = src_argb + (height - 1) * src_stride_argb; 692 src_stride_argb = -src_stride_argb; 693 } 694 // Coalesce rows. 695 if (src_stride_argb == width * 4 && 696 dst_stride_y == width) { 697 width *= height; 698 height = 1; 699 src_stride_argb = dst_stride_y = 0; 700 } 701#if defined(HAS_ARGBTOYROW_SSSE3) 702 if (TestCpuFlag(kCpuHasSSSE3)) { 703 ARGBToYRow = ARGBToYRow_Any_SSSE3; 704 if (IS_ALIGNED(width, 16)) { 705 ARGBToYRow = ARGBToYRow_SSSE3; 706 } 707 } 708#endif 709#if defined(HAS_ARGBTOYROW_AVX2) 710 if (TestCpuFlag(kCpuHasAVX2)) { 711 ARGBToYRow = ARGBToYRow_Any_AVX2; 712 if (IS_ALIGNED(width, 32)) { 713 ARGBToYRow = ARGBToYRow_AVX2; 714 } 715 } 716#endif 717#if defined(HAS_ARGBTOYROW_NEON) 718 if (TestCpuFlag(kCpuHasNEON)) { 719 ARGBToYRow = ARGBToYRow_Any_NEON; 720 if (IS_ALIGNED(width, 8)) { 721 ARGBToYRow = ARGBToYRow_NEON; 722 } 723 } 724#endif 725 726 for (y = 0; y < height; ++y) { 727 ARGBToYRow(src_argb, dst_y, width); 728 src_argb += src_stride_argb; 729 dst_y += dst_stride_y; 730 } 731 return 0; 732} 733 734// Shuffle table for converting ARGB to RGBA. 735static uvec8 kShuffleMaskARGBToRGBA = { 736 3u, 0u, 1u, 2u, 7u, 4u, 5u, 6u, 11u, 8u, 9u, 10u, 15u, 12u, 13u, 14u 737}; 738 739// Convert ARGB to RGBA. 740LIBYUV_API 741int ARGBToRGBA(const uint8* src_argb, int src_stride_argb, 742 uint8* dst_rgba, int dst_stride_rgba, 743 int width, int height) { 744 return ARGBShuffle(src_argb, src_stride_argb, 745 dst_rgba, dst_stride_rgba, 746 (const uint8*)(&kShuffleMaskARGBToRGBA), 747 width, height); 748} 749 750// Convert ARGB To RGB24. 751LIBYUV_API 752int ARGBToRGB24(const uint8* src_argb, int src_stride_argb, 753 uint8* dst_rgb24, int dst_stride_rgb24, 754 int width, int height) { 755 int y; 756 void (*ARGBToRGB24Row)(const uint8* src_argb, uint8* dst_rgb, int width) = 757 ARGBToRGB24Row_C; 758 if (!src_argb || !dst_rgb24 || width <= 0 || height == 0) { 759 return -1; 760 } 761 if (height < 0) { 762 height = -height; 763 src_argb = src_argb + (height - 1) * src_stride_argb; 764 src_stride_argb = -src_stride_argb; 765 } 766 // Coalesce rows. 767 if (src_stride_argb == width * 4 && 768 dst_stride_rgb24 == width * 3) { 769 width *= height; 770 height = 1; 771 src_stride_argb = dst_stride_rgb24 = 0; 772 } 773#if defined(HAS_ARGBTORGB24ROW_SSSE3) 774 if (TestCpuFlag(kCpuHasSSSE3)) { 775 ARGBToRGB24Row = ARGBToRGB24Row_Any_SSSE3; 776 if (IS_ALIGNED(width, 16)) { 777 ARGBToRGB24Row = ARGBToRGB24Row_SSSE3; 778 } 779 } 780#endif 781#if defined(HAS_ARGBTORGB24ROW_NEON) 782 if (TestCpuFlag(kCpuHasNEON)) { 783 ARGBToRGB24Row = ARGBToRGB24Row_Any_NEON; 784 if (IS_ALIGNED(width, 8)) { 785 ARGBToRGB24Row = ARGBToRGB24Row_NEON; 786 } 787 } 788#endif 789 790 for (y = 0; y < height; ++y) { 791 ARGBToRGB24Row(src_argb, dst_rgb24, width); 792 src_argb += src_stride_argb; 793 dst_rgb24 += dst_stride_rgb24; 794 } 795 return 0; 796} 797 798// Convert ARGB To RAW. 799LIBYUV_API 800int ARGBToRAW(const uint8* src_argb, int src_stride_argb, 801 uint8* dst_raw, int dst_stride_raw, 802 int width, int height) { 803 int y; 804 void (*ARGBToRAWRow)(const uint8* src_argb, uint8* dst_rgb, int width) = 805 ARGBToRAWRow_C; 806 if (!src_argb || !dst_raw || width <= 0 || height == 0) { 807 return -1; 808 } 809 if (height < 0) { 810 height = -height; 811 src_argb = src_argb + (height - 1) * src_stride_argb; 812 src_stride_argb = -src_stride_argb; 813 } 814 // Coalesce rows. 815 if (src_stride_argb == width * 4 && 816 dst_stride_raw == width * 3) { 817 width *= height; 818 height = 1; 819 src_stride_argb = dst_stride_raw = 0; 820 } 821#if defined(HAS_ARGBTORAWROW_SSSE3) 822 if (TestCpuFlag(kCpuHasSSSE3)) { 823 ARGBToRAWRow = ARGBToRAWRow_Any_SSSE3; 824 if (IS_ALIGNED(width, 16)) { 825 ARGBToRAWRow = ARGBToRAWRow_SSSE3; 826 } 827 } 828#endif 829#if defined(HAS_ARGBTORAWROW_NEON) 830 if (TestCpuFlag(kCpuHasNEON)) { 831 ARGBToRAWRow = ARGBToRAWRow_Any_NEON; 832 if (IS_ALIGNED(width, 8)) { 833 ARGBToRAWRow = ARGBToRAWRow_NEON; 834 } 835 } 836#endif 837 838 for (y = 0; y < height; ++y) { 839 ARGBToRAWRow(src_argb, dst_raw, width); 840 src_argb += src_stride_argb; 841 dst_raw += dst_stride_raw; 842 } 843 return 0; 844} 845 846// Ordered 8x8 dither for 888 to 565. Values from 0 to 7. 847static const uint8 kDither565_4x4[16] = { 848 0, 4, 1, 5, 849 6, 2, 7, 3, 850 1, 5, 0, 4, 851 7, 3, 6, 2, 852}; 853 854// Convert ARGB To RGB565 with 4x4 dither matrix (16 bytes). 855LIBYUV_API 856int ARGBToRGB565Dither(const uint8* src_argb, int src_stride_argb, 857 uint8* dst_rgb565, int dst_stride_rgb565, 858 const uint8* dither4x4, int width, int height) { 859 int y; 860 void (*ARGBToRGB565DitherRow)(const uint8* src_argb, uint8* dst_rgb, 861 const uint32 dither4, int width) = ARGBToRGB565DitherRow_C; 862 if (!src_argb || !dst_rgb565 || width <= 0 || height == 0) { 863 return -1; 864 } 865 if (height < 0) { 866 height = -height; 867 src_argb = src_argb + (height - 1) * src_stride_argb; 868 src_stride_argb = -src_stride_argb; 869 } 870 if (!dither4x4) { 871 dither4x4 = kDither565_4x4; 872 } 873#if defined(HAS_ARGBTORGB565DITHERROW_SSE2) 874 if (TestCpuFlag(kCpuHasSSE2)) { 875 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_SSE2; 876 if (IS_ALIGNED(width, 4)) { 877 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_SSE2; 878 } 879 } 880#endif 881#if defined(HAS_ARGBTORGB565DITHERROW_AVX2) 882 if (TestCpuFlag(kCpuHasAVX2)) { 883 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_AVX2; 884 if (IS_ALIGNED(width, 8)) { 885 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_AVX2; 886 } 887 } 888#endif 889#if defined(HAS_ARGBTORGB565DITHERROW_NEON) 890 if (TestCpuFlag(kCpuHasNEON)) { 891 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_NEON; 892 if (IS_ALIGNED(width, 8)) { 893 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_NEON; 894 } 895 } 896#endif 897 for (y = 0; y < height; ++y) { 898 ARGBToRGB565DitherRow(src_argb, dst_rgb565, 899 *(uint32*)(dither4x4 + ((y & 3) << 2)), width); 900 src_argb += src_stride_argb; 901 dst_rgb565 += dst_stride_rgb565; 902 } 903 return 0; 904} 905 906// Convert ARGB To RGB565. 907// TODO(fbarchard): Consider using dither function low level with zeros. 908LIBYUV_API 909int ARGBToRGB565(const uint8* src_argb, int src_stride_argb, 910 uint8* dst_rgb565, int dst_stride_rgb565, 911 int width, int height) { 912 int y; 913 void (*ARGBToRGB565Row)(const uint8* src_argb, uint8* dst_rgb, int width) = 914 ARGBToRGB565Row_C; 915 if (!src_argb || !dst_rgb565 || width <= 0 || height == 0) { 916 return -1; 917 } 918 if (height < 0) { 919 height = -height; 920 src_argb = src_argb + (height - 1) * src_stride_argb; 921 src_stride_argb = -src_stride_argb; 922 } 923 // Coalesce rows. 924 if (src_stride_argb == width * 4 && 925 dst_stride_rgb565 == width * 2) { 926 width *= height; 927 height = 1; 928 src_stride_argb = dst_stride_rgb565 = 0; 929 } 930#if defined(HAS_ARGBTORGB565ROW_SSE2) 931 if (TestCpuFlag(kCpuHasSSE2)) { 932 ARGBToRGB565Row = ARGBToRGB565Row_Any_SSE2; 933 if (IS_ALIGNED(width, 4)) { 934 ARGBToRGB565Row = ARGBToRGB565Row_SSE2; 935 } 936 } 937#endif 938#if defined(HAS_ARGBTORGB565ROW_AVX2) 939 if (TestCpuFlag(kCpuHasAVX2)) { 940 ARGBToRGB565Row = ARGBToRGB565Row_Any_AVX2; 941 if (IS_ALIGNED(width, 8)) { 942 ARGBToRGB565Row = ARGBToRGB565Row_AVX2; 943 } 944 } 945#endif 946#if defined(HAS_ARGBTORGB565ROW_NEON) 947 if (TestCpuFlag(kCpuHasNEON)) { 948 ARGBToRGB565Row = ARGBToRGB565Row_Any_NEON; 949 if (IS_ALIGNED(width, 8)) { 950 ARGBToRGB565Row = ARGBToRGB565Row_NEON; 951 } 952 } 953#endif 954 955 for (y = 0; y < height; ++y) { 956 ARGBToRGB565Row(src_argb, dst_rgb565, width); 957 src_argb += src_stride_argb; 958 dst_rgb565 += dst_stride_rgb565; 959 } 960 return 0; 961} 962 963// Convert ARGB To ARGB1555. 964LIBYUV_API 965int ARGBToARGB1555(const uint8* src_argb, int src_stride_argb, 966 uint8* dst_argb1555, int dst_stride_argb1555, 967 int width, int height) { 968 int y; 969 void (*ARGBToARGB1555Row)(const uint8* src_argb, uint8* dst_rgb, int width) = 970 ARGBToARGB1555Row_C; 971 if (!src_argb || !dst_argb1555 || width <= 0 || height == 0) { 972 return -1; 973 } 974 if (height < 0) { 975 height = -height; 976 src_argb = src_argb + (height - 1) * src_stride_argb; 977 src_stride_argb = -src_stride_argb; 978 } 979 // Coalesce rows. 980 if (src_stride_argb == width * 4 && 981 dst_stride_argb1555 == width * 2) { 982 width *= height; 983 height = 1; 984 src_stride_argb = dst_stride_argb1555 = 0; 985 } 986#if defined(HAS_ARGBTOARGB1555ROW_SSE2) 987 if (TestCpuFlag(kCpuHasSSE2)) { 988 ARGBToARGB1555Row = ARGBToARGB1555Row_Any_SSE2; 989 if (IS_ALIGNED(width, 4)) { 990 ARGBToARGB1555Row = ARGBToARGB1555Row_SSE2; 991 } 992 } 993#endif 994#if defined(HAS_ARGBTOARGB1555ROW_AVX2) 995 if (TestCpuFlag(kCpuHasAVX2)) { 996 ARGBToARGB1555Row = ARGBToARGB1555Row_Any_AVX2; 997 if (IS_ALIGNED(width, 8)) { 998 ARGBToARGB1555Row = ARGBToARGB1555Row_AVX2; 999 } 1000 } 1001#endif 1002#if defined(HAS_ARGBTOARGB1555ROW_NEON) 1003 if (TestCpuFlag(kCpuHasNEON)) { 1004 ARGBToARGB1555Row = ARGBToARGB1555Row_Any_NEON; 1005 if (IS_ALIGNED(width, 8)) { 1006 ARGBToARGB1555Row = ARGBToARGB1555Row_NEON; 1007 } 1008 } 1009#endif 1010 1011 for (y = 0; y < height; ++y) { 1012 ARGBToARGB1555Row(src_argb, dst_argb1555, width); 1013 src_argb += src_stride_argb; 1014 dst_argb1555 += dst_stride_argb1555; 1015 } 1016 return 0; 1017} 1018 1019// Convert ARGB To ARGB4444. 1020LIBYUV_API 1021int ARGBToARGB4444(const uint8* src_argb, int src_stride_argb, 1022 uint8* dst_argb4444, int dst_stride_argb4444, 1023 int width, int height) { 1024 int y; 1025 void (*ARGBToARGB4444Row)(const uint8* src_argb, uint8* dst_rgb, int width) = 1026 ARGBToARGB4444Row_C; 1027 if (!src_argb || !dst_argb4444 || width <= 0 || height == 0) { 1028 return -1; 1029 } 1030 if (height < 0) { 1031 height = -height; 1032 src_argb = src_argb + (height - 1) * src_stride_argb; 1033 src_stride_argb = -src_stride_argb; 1034 } 1035 // Coalesce rows. 1036 if (src_stride_argb == width * 4 && 1037 dst_stride_argb4444 == width * 2) { 1038 width *= height; 1039 height = 1; 1040 src_stride_argb = dst_stride_argb4444 = 0; 1041 } 1042#if defined(HAS_ARGBTOARGB4444ROW_SSE2) 1043 if (TestCpuFlag(kCpuHasSSE2)) { 1044 ARGBToARGB4444Row = ARGBToARGB4444Row_Any_SSE2; 1045 if (IS_ALIGNED(width, 4)) { 1046 ARGBToARGB4444Row = ARGBToARGB4444Row_SSE2; 1047 } 1048 } 1049#endif 1050#if defined(HAS_ARGBTOARGB4444ROW_AVX2) 1051 if (TestCpuFlag(kCpuHasAVX2)) { 1052 ARGBToARGB4444Row = ARGBToARGB4444Row_Any_AVX2; 1053 if (IS_ALIGNED(width, 8)) { 1054 ARGBToARGB4444Row = ARGBToARGB4444Row_AVX2; 1055 } 1056 } 1057#endif 1058#if defined(HAS_ARGBTOARGB4444ROW_NEON) 1059 if (TestCpuFlag(kCpuHasNEON)) { 1060 ARGBToARGB4444Row = ARGBToARGB4444Row_Any_NEON; 1061 if (IS_ALIGNED(width, 8)) { 1062 ARGBToARGB4444Row = ARGBToARGB4444Row_NEON; 1063 } 1064 } 1065#endif 1066 1067 for (y = 0; y < height; ++y) { 1068 ARGBToARGB4444Row(src_argb, dst_argb4444, width); 1069 src_argb += src_stride_argb; 1070 dst_argb4444 += dst_stride_argb4444; 1071 } 1072 return 0; 1073} 1074 1075// Convert ARGB to J420. (JPeg full range I420). 1076LIBYUV_API 1077int ARGBToJ420(const uint8* src_argb, int src_stride_argb, 1078 uint8* dst_yj, int dst_stride_yj, 1079 uint8* dst_u, int dst_stride_u, 1080 uint8* dst_v, int dst_stride_v, 1081 int width, int height) { 1082 int y; 1083 void (*ARGBToUVJRow)(const uint8* src_argb0, int src_stride_argb, 1084 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVJRow_C; 1085 void (*ARGBToYJRow)(const uint8* src_argb, uint8* dst_yj, int width) = 1086 ARGBToYJRow_C; 1087 if (!src_argb || 1088 !dst_yj || !dst_u || !dst_v || 1089 width <= 0 || height == 0) { 1090 return -1; 1091 } 1092 // Negative height means invert the image. 1093 if (height < 0) { 1094 height = -height; 1095 src_argb = src_argb + (height - 1) * src_stride_argb; 1096 src_stride_argb = -src_stride_argb; 1097 } 1098#if defined(HAS_ARGBTOYJROW_SSSE3) && defined(HAS_ARGBTOUVJROW_SSSE3) 1099 if (TestCpuFlag(kCpuHasSSSE3)) { 1100 ARGBToUVJRow = ARGBToUVJRow_Any_SSSE3; 1101 ARGBToYJRow = ARGBToYJRow_Any_SSSE3; 1102 if (IS_ALIGNED(width, 16)) { 1103 ARGBToUVJRow = ARGBToUVJRow_SSSE3; 1104 ARGBToYJRow = ARGBToYJRow_SSSE3; 1105 } 1106 } 1107#endif 1108#if defined(HAS_ARGBTOYJROW_AVX2) 1109 if (TestCpuFlag(kCpuHasAVX2)) { 1110 ARGBToYJRow = ARGBToYJRow_Any_AVX2; 1111 if (IS_ALIGNED(width, 32)) { 1112 ARGBToYJRow = ARGBToYJRow_AVX2; 1113 } 1114 } 1115#endif 1116#if defined(HAS_ARGBTOYJROW_NEON) 1117 if (TestCpuFlag(kCpuHasNEON)) { 1118 ARGBToYJRow = ARGBToYJRow_Any_NEON; 1119 if (IS_ALIGNED(width, 8)) { 1120 ARGBToYJRow = ARGBToYJRow_NEON; 1121 } 1122 } 1123#endif 1124#if defined(HAS_ARGBTOUVJROW_NEON) 1125 if (TestCpuFlag(kCpuHasNEON)) { 1126 ARGBToUVJRow = ARGBToUVJRow_Any_NEON; 1127 if (IS_ALIGNED(width, 16)) { 1128 ARGBToUVJRow = ARGBToUVJRow_NEON; 1129 } 1130 } 1131#endif 1132 1133 for (y = 0; y < height - 1; y += 2) { 1134 ARGBToUVJRow(src_argb, src_stride_argb, dst_u, dst_v, width); 1135 ARGBToYJRow(src_argb, dst_yj, width); 1136 ARGBToYJRow(src_argb + src_stride_argb, dst_yj + dst_stride_yj, width); 1137 src_argb += src_stride_argb * 2; 1138 dst_yj += dst_stride_yj * 2; 1139 dst_u += dst_stride_u; 1140 dst_v += dst_stride_v; 1141 } 1142 if (height & 1) { 1143 ARGBToUVJRow(src_argb, 0, dst_u, dst_v, width); 1144 ARGBToYJRow(src_argb, dst_yj, width); 1145 } 1146 return 0; 1147} 1148 1149// Convert ARGB to J422. (JPeg full range I422). 1150LIBYUV_API 1151int ARGBToJ422(const uint8* src_argb, int src_stride_argb, 1152 uint8* dst_yj, int dst_stride_yj, 1153 uint8* dst_u, int dst_stride_u, 1154 uint8* dst_v, int dst_stride_v, 1155 int width, int height) { 1156 int y; 1157 void (*ARGBToUVJRow)(const uint8* src_argb0, int src_stride_argb, 1158 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVJRow_C; 1159 void (*ARGBToYJRow)(const uint8* src_argb, uint8* dst_yj, int width) = 1160 ARGBToYJRow_C; 1161 if (!src_argb || 1162 !dst_yj || !dst_u || !dst_v || 1163 width <= 0 || height == 0) { 1164 return -1; 1165 } 1166 // Negative height means invert the image. 1167 if (height < 0) { 1168 height = -height; 1169 src_argb = src_argb + (height - 1) * src_stride_argb; 1170 src_stride_argb = -src_stride_argb; 1171 } 1172 // Coalesce rows. 1173 if (src_stride_argb == width * 4 && 1174 dst_stride_yj == width && 1175 dst_stride_u * 2 == width && 1176 dst_stride_v * 2 == width) { 1177 width *= height; 1178 height = 1; 1179 src_stride_argb = dst_stride_yj = dst_stride_u = dst_stride_v = 0; 1180 } 1181#if defined(HAS_ARGBTOYJROW_SSSE3) && defined(HAS_ARGBTOUVJROW_SSSE3) 1182 if (TestCpuFlag(kCpuHasSSSE3)) { 1183 ARGBToUVJRow = ARGBToUVJRow_Any_SSSE3; 1184 ARGBToYJRow = ARGBToYJRow_Any_SSSE3; 1185 if (IS_ALIGNED(width, 16)) { 1186 ARGBToUVJRow = ARGBToUVJRow_SSSE3; 1187 ARGBToYJRow = ARGBToYJRow_SSSE3; 1188 } 1189 } 1190#endif 1191#if defined(HAS_ARGBTOYJROW_AVX2) 1192 if (TestCpuFlag(kCpuHasAVX2)) { 1193 ARGBToYJRow = ARGBToYJRow_Any_AVX2; 1194 if (IS_ALIGNED(width, 32)) { 1195 ARGBToYJRow = ARGBToYJRow_AVX2; 1196 } 1197 } 1198#endif 1199#if defined(HAS_ARGBTOYJROW_NEON) 1200 if (TestCpuFlag(kCpuHasNEON)) { 1201 ARGBToYJRow = ARGBToYJRow_Any_NEON; 1202 if (IS_ALIGNED(width, 8)) { 1203 ARGBToYJRow = ARGBToYJRow_NEON; 1204 } 1205 } 1206#endif 1207#if defined(HAS_ARGBTOUVJROW_NEON) 1208 if (TestCpuFlag(kCpuHasNEON)) { 1209 ARGBToUVJRow = ARGBToUVJRow_Any_NEON; 1210 if (IS_ALIGNED(width, 16)) { 1211 ARGBToUVJRow = ARGBToUVJRow_NEON; 1212 } 1213 } 1214#endif 1215 1216 for (y = 0; y < height; ++y) { 1217 ARGBToUVJRow(src_argb, 0, dst_u, dst_v, width); 1218 ARGBToYJRow(src_argb, dst_yj, width); 1219 src_argb += src_stride_argb; 1220 dst_yj += dst_stride_yj; 1221 dst_u += dst_stride_u; 1222 dst_v += dst_stride_v; 1223 } 1224 return 0; 1225} 1226 1227// Convert ARGB to J400. 1228LIBYUV_API 1229int ARGBToJ400(const uint8* src_argb, int src_stride_argb, 1230 uint8* dst_yj, int dst_stride_yj, 1231 int width, int height) { 1232 int y; 1233 void (*ARGBToYJRow)(const uint8* src_argb, uint8* dst_yj, int width) = 1234 ARGBToYJRow_C; 1235 if (!src_argb || !dst_yj || width <= 0 || height == 0) { 1236 return -1; 1237 } 1238 if (height < 0) { 1239 height = -height; 1240 src_argb = src_argb + (height - 1) * src_stride_argb; 1241 src_stride_argb = -src_stride_argb; 1242 } 1243 // Coalesce rows. 1244 if (src_stride_argb == width * 4 && 1245 dst_stride_yj == width) { 1246 width *= height; 1247 height = 1; 1248 src_stride_argb = dst_stride_yj = 0; 1249 } 1250#if defined(HAS_ARGBTOYJROW_SSSE3) 1251 if (TestCpuFlag(kCpuHasSSSE3)) { 1252 ARGBToYJRow = ARGBToYJRow_Any_SSSE3; 1253 if (IS_ALIGNED(width, 16)) { 1254 ARGBToYJRow = ARGBToYJRow_SSSE3; 1255 } 1256 } 1257#endif 1258#if defined(HAS_ARGBTOYJROW_AVX2) 1259 if (TestCpuFlag(kCpuHasAVX2)) { 1260 ARGBToYJRow = ARGBToYJRow_Any_AVX2; 1261 if (IS_ALIGNED(width, 32)) { 1262 ARGBToYJRow = ARGBToYJRow_AVX2; 1263 } 1264 } 1265#endif 1266#if defined(HAS_ARGBTOYJROW_NEON) 1267 if (TestCpuFlag(kCpuHasNEON)) { 1268 ARGBToYJRow = ARGBToYJRow_Any_NEON; 1269 if (IS_ALIGNED(width, 8)) { 1270 ARGBToYJRow = ARGBToYJRow_NEON; 1271 } 1272 } 1273#endif 1274 1275 for (y = 0; y < height; ++y) { 1276 ARGBToYJRow(src_argb, dst_yj, width); 1277 src_argb += src_stride_argb; 1278 dst_yj += dst_stride_yj; 1279 } 1280 return 0; 1281} 1282 1283#ifdef __cplusplus 1284} // extern "C" 1285} // namespace libyuv 1286#endif 1287