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/format_conversion.h" 12 13 #include "libyuv/basic_types.h" 14 #include "libyuv/cpu_id.h" 15 #include "libyuv/video_common.h" 16 #include "libyuv/row.h" 17 18 #ifdef __cplusplus 19 namespace libyuv { 20 extern "C" { 21 #endif 22 23 // generate a selector mask useful for pshufb 24 static uint32 GenerateSelector(int select0, int select1) { 25 return (uint32)(select0) | 26 (uint32)((select1 + 4) << 8) | 27 (uint32)((select0 + 8) << 16) | 28 (uint32)((select1 + 12) << 24); 29 } 30 31 static int MakeSelectors(const int blue_index, 32 const int green_index, 33 const int red_index, 34 uint32 dst_fourcc_bayer, 35 uint32* index_map) { 36 // Now build a lookup table containing the indices for the four pixels in each 37 // 2x2 Bayer grid. 38 switch (dst_fourcc_bayer) { 39 case FOURCC_BGGR: 40 index_map[0] = GenerateSelector(blue_index, green_index); 41 index_map[1] = GenerateSelector(green_index, red_index); 42 break; 43 case FOURCC_GBRG: 44 index_map[0] = GenerateSelector(green_index, blue_index); 45 index_map[1] = GenerateSelector(red_index, green_index); 46 break; 47 case FOURCC_RGGB: 48 index_map[0] = GenerateSelector(red_index, green_index); 49 index_map[1] = GenerateSelector(green_index, blue_index); 50 break; 51 case FOURCC_GRBG: 52 index_map[0] = GenerateSelector(green_index, red_index); 53 index_map[1] = GenerateSelector(blue_index, green_index); 54 break; 55 default: 56 return -1; // Bad FourCC 57 } 58 return 0; 59 } 60 61 // Converts 32 bit ARGB to Bayer RGB formats. 62 LIBYUV_API 63 int ARGBToBayer(const uint8* src_argb, int src_stride_argb, 64 uint8* dst_bayer, int dst_stride_bayer, 65 int width, int height, 66 uint32 dst_fourcc_bayer) { 67 int y; 68 const int blue_index = 0; // Offsets for ARGB format 69 const int green_index = 1; 70 const int red_index = 2; 71 uint32 index_map[2]; 72 void (*ARGBToBayerRow)(const uint8* src_argb, uint8* dst_bayer, 73 uint32 selector, int pix) = ARGBToBayerRow_C; 74 if (height < 0) { 75 height = -height; 76 src_argb = src_argb + (height - 1) * src_stride_argb; 77 src_stride_argb = -src_stride_argb; 78 } 79 #if defined(HAS_ARGBTOBAYERROW_SSSE3) 80 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8 && 81 IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) { 82 ARGBToBayerRow = ARGBToBayerRow_Any_SSSE3; 83 if (IS_ALIGNED(width, 8)) { 84 ARGBToBayerRow = ARGBToBayerRow_SSSE3; 85 } 86 } 87 #elif defined(HAS_ARGBTOBAYERROW_NEON) 88 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 89 ARGBToBayerRow = ARGBToBayerRow_Any_NEON; 90 if (IS_ALIGNED(width, 8)) { 91 ARGBToBayerRow = ARGBToBayerRow_NEON; 92 } 93 } 94 #endif 95 if (MakeSelectors(blue_index, green_index, red_index, 96 dst_fourcc_bayer, index_map)) { 97 return -1; // Bad FourCC 98 } 99 100 for (y = 0; y < height; ++y) { 101 ARGBToBayerRow(src_argb, dst_bayer, index_map[y & 1], width); 102 src_argb += src_stride_argb; 103 dst_bayer += dst_stride_bayer; 104 } 105 return 0; 106 } 107 108 #define AVG(a, b) (((a) + (b)) >> 1) 109 110 static void BayerRowBG(const uint8* src_bayer0, int src_stride_bayer, 111 uint8* dst_argb, int pix) { 112 const uint8* src_bayer1 = src_bayer0 + src_stride_bayer; 113 uint8 g = src_bayer0[1]; 114 uint8 r = src_bayer1[1]; 115 int x; 116 for (x = 0; x < pix - 2; x += 2) { 117 dst_argb[0] = src_bayer0[0]; 118 dst_argb[1] = AVG(g, src_bayer0[1]); 119 dst_argb[2] = AVG(r, src_bayer1[1]); 120 dst_argb[3] = 255U; 121 dst_argb[4] = AVG(src_bayer0[0], src_bayer0[2]); 122 dst_argb[5] = src_bayer0[1]; 123 dst_argb[6] = src_bayer1[1]; 124 dst_argb[7] = 255U; 125 g = src_bayer0[1]; 126 r = src_bayer1[1]; 127 src_bayer0 += 2; 128 src_bayer1 += 2; 129 dst_argb += 8; 130 } 131 dst_argb[0] = src_bayer0[0]; 132 dst_argb[1] = AVG(g, src_bayer0[1]); 133 dst_argb[2] = AVG(r, src_bayer1[1]); 134 dst_argb[3] = 255U; 135 if (!(pix & 1)) { 136 dst_argb[4] = src_bayer0[0]; 137 dst_argb[5] = src_bayer0[1]; 138 dst_argb[6] = src_bayer1[1]; 139 dst_argb[7] = 255U; 140 } 141 } 142 143 static void BayerRowRG(const uint8* src_bayer0, int src_stride_bayer, 144 uint8* dst_argb, int pix) { 145 const uint8* src_bayer1 = src_bayer0 + src_stride_bayer; 146 uint8 g = src_bayer0[1]; 147 uint8 b = src_bayer1[1]; 148 int x; 149 for (x = 0; x < pix - 2; x += 2) { 150 dst_argb[0] = AVG(b, src_bayer1[1]); 151 dst_argb[1] = AVG(g, src_bayer0[1]); 152 dst_argb[2] = src_bayer0[0]; 153 dst_argb[3] = 255U; 154 dst_argb[4] = src_bayer1[1]; 155 dst_argb[5] = src_bayer0[1]; 156 dst_argb[6] = AVG(src_bayer0[0], src_bayer0[2]); 157 dst_argb[7] = 255U; 158 g = src_bayer0[1]; 159 b = src_bayer1[1]; 160 src_bayer0 += 2; 161 src_bayer1 += 2; 162 dst_argb += 8; 163 } 164 dst_argb[0] = AVG(b, src_bayer1[1]); 165 dst_argb[1] = AVG(g, src_bayer0[1]); 166 dst_argb[2] = src_bayer0[0]; 167 dst_argb[3] = 255U; 168 if (!(pix & 1)) { 169 dst_argb[4] = src_bayer1[1]; 170 dst_argb[5] = src_bayer0[1]; 171 dst_argb[6] = src_bayer0[0]; 172 dst_argb[7] = 255U; 173 } 174 } 175 176 static void BayerRowGB(const uint8* src_bayer0, int src_stride_bayer, 177 uint8* dst_argb, int pix) { 178 const uint8* src_bayer1 = src_bayer0 + src_stride_bayer; 179 uint8 b = src_bayer0[1]; 180 int x; 181 for (x = 0; x < pix - 2; x += 2) { 182 dst_argb[0] = AVG(b, src_bayer0[1]); 183 dst_argb[1] = src_bayer0[0]; 184 dst_argb[2] = src_bayer1[0]; 185 dst_argb[3] = 255U; 186 dst_argb[4] = src_bayer0[1]; 187 dst_argb[5] = AVG(src_bayer0[0], src_bayer0[2]); 188 dst_argb[6] = AVG(src_bayer1[0], src_bayer1[2]); 189 dst_argb[7] = 255U; 190 b = src_bayer0[1]; 191 src_bayer0 += 2; 192 src_bayer1 += 2; 193 dst_argb += 8; 194 } 195 dst_argb[0] = AVG(b, src_bayer0[1]); 196 dst_argb[1] = src_bayer0[0]; 197 dst_argb[2] = src_bayer1[0]; 198 dst_argb[3] = 255U; 199 if (!(pix & 1)) { 200 dst_argb[4] = src_bayer0[1]; 201 dst_argb[5] = src_bayer0[0]; 202 dst_argb[6] = src_bayer1[0]; 203 dst_argb[7] = 255U; 204 } 205 } 206 207 static void BayerRowGR(const uint8* src_bayer0, int src_stride_bayer, 208 uint8* dst_argb, int pix) { 209 const uint8* src_bayer1 = src_bayer0 + src_stride_bayer; 210 uint8 r = src_bayer0[1]; 211 int x; 212 for (x = 0; x < pix - 2; x += 2) { 213 dst_argb[0] = src_bayer1[0]; 214 dst_argb[1] = src_bayer0[0]; 215 dst_argb[2] = AVG(r, src_bayer0[1]); 216 dst_argb[3] = 255U; 217 dst_argb[4] = AVG(src_bayer1[0], src_bayer1[2]); 218 dst_argb[5] = AVG(src_bayer0[0], src_bayer0[2]); 219 dst_argb[6] = src_bayer0[1]; 220 dst_argb[7] = 255U; 221 r = src_bayer0[1]; 222 src_bayer0 += 2; 223 src_bayer1 += 2; 224 dst_argb += 8; 225 } 226 dst_argb[0] = src_bayer1[0]; 227 dst_argb[1] = src_bayer0[0]; 228 dst_argb[2] = AVG(r, src_bayer0[1]); 229 dst_argb[3] = 255U; 230 if (!(pix & 1)) { 231 dst_argb[4] = src_bayer1[0]; 232 dst_argb[5] = src_bayer0[0]; 233 dst_argb[6] = src_bayer0[1]; 234 dst_argb[7] = 255U; 235 } 236 } 237 238 // Converts any Bayer RGB format to ARGB. 239 LIBYUV_API 240 int BayerToARGB(const uint8* src_bayer, int src_stride_bayer, 241 uint8* dst_argb, int dst_stride_argb, 242 int width, int height, 243 uint32 src_fourcc_bayer) { 244 int y; 245 void (*BayerRow0)(const uint8* src_bayer, int src_stride_bayer, 246 uint8* dst_argb, int pix); 247 void (*BayerRow1)(const uint8* src_bayer, int src_stride_bayer, 248 uint8* dst_argb, int pix); 249 if (height < 0) { 250 height = -height; 251 dst_argb = dst_argb + (height - 1) * dst_stride_argb; 252 dst_stride_argb = -dst_stride_argb; 253 } 254 switch (src_fourcc_bayer) { 255 case FOURCC_BGGR: 256 BayerRow0 = BayerRowBG; 257 BayerRow1 = BayerRowGR; 258 break; 259 case FOURCC_GBRG: 260 BayerRow0 = BayerRowGB; 261 BayerRow1 = BayerRowRG; 262 break; 263 case FOURCC_GRBG: 264 BayerRow0 = BayerRowGR; 265 BayerRow1 = BayerRowBG; 266 break; 267 case FOURCC_RGGB: 268 BayerRow0 = BayerRowRG; 269 BayerRow1 = BayerRowGB; 270 break; 271 default: 272 return -1; // Bad FourCC 273 } 274 275 for (y = 0; y < height - 1; y += 2) { 276 BayerRow0(src_bayer, src_stride_bayer, dst_argb, width); 277 BayerRow1(src_bayer + src_stride_bayer, -src_stride_bayer, 278 dst_argb + dst_stride_argb, width); 279 src_bayer += src_stride_bayer * 2; 280 dst_argb += dst_stride_argb * 2; 281 } 282 if (height & 1) { 283 BayerRow0(src_bayer, src_stride_bayer, dst_argb, width); 284 } 285 return 0; 286 } 287 288 // Converts any Bayer RGB format to ARGB. 289 LIBYUV_API 290 int BayerToI420(const uint8* src_bayer, int src_stride_bayer, 291 uint8* dst_y, int dst_stride_y, 292 uint8* dst_u, int dst_stride_u, 293 uint8* dst_v, int dst_stride_v, 294 int width, int height, 295 uint32 src_fourcc_bayer) { 296 void (*BayerRow0)(const uint8* src_bayer, int src_stride_bayer, 297 uint8* dst_argb, int pix); 298 void (*BayerRow1)(const uint8* src_bayer, int src_stride_bayer, 299 uint8* dst_argb, int pix); 300 301 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, 302 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; 303 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) = 304 ARGBToYRow_C; 305 // Negative height means invert the image. 306 if (height < 0) { 307 int halfheight; 308 height = -height; 309 halfheight = (height + 1) >> 1; 310 dst_y = dst_y + (height - 1) * dst_stride_y; 311 dst_u = dst_u + (halfheight - 1) * dst_stride_u; 312 dst_v = dst_v + (halfheight - 1) * dst_stride_v; 313 dst_stride_y = -dst_stride_y; 314 dst_stride_u = -dst_stride_u; 315 dst_stride_v = -dst_stride_v; 316 } 317 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) 318 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { 319 ARGBToUVRow = ARGBToUVRow_Any_SSSE3; 320 ARGBToYRow = ARGBToYRow_Any_SSSE3; 321 if (IS_ALIGNED(width, 16)) { 322 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3; 323 ARGBToUVRow = ARGBToUVRow_SSSE3; 324 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { 325 ARGBToYRow = ARGBToYRow_SSSE3; 326 } 327 } 328 } 329 #elif defined(HAS_ARGBTOYROW_NEON) 330 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 331 ARGBToYRow = ARGBToYRow_Any_NEON; 332 if (IS_ALIGNED(width, 8)) { 333 ARGBToYRow = ARGBToYRow_NEON; 334 } 335 if (width >= 16) { 336 ARGBToUVRow = ARGBToUVRow_Any_NEON; 337 if (IS_ALIGNED(width, 16)) { 338 ARGBToUVRow = ARGBToUVRow_NEON; 339 } 340 } 341 } 342 #endif 343 344 switch (src_fourcc_bayer) { 345 case FOURCC_BGGR: 346 BayerRow0 = BayerRowBG; 347 BayerRow1 = BayerRowGR; 348 break; 349 case FOURCC_GBRG: 350 BayerRow0 = BayerRowGB; 351 BayerRow1 = BayerRowRG; 352 break; 353 case FOURCC_GRBG: 354 BayerRow0 = BayerRowGR; 355 BayerRow1 = BayerRowBG; 356 break; 357 case FOURCC_RGGB: 358 BayerRow0 = BayerRowRG; 359 BayerRow1 = BayerRowGB; 360 break; 361 default: 362 return -1; // Bad FourCC 363 } 364 365 { 366 // Allocate 2 rows of ARGB. 367 const int kRowSize = (width * 4 + 15) & ~15; 368 align_buffer_64(row, kRowSize * 2); 369 int y; 370 for (y = 0; y < height - 1; y += 2) { 371 BayerRow0(src_bayer, src_stride_bayer, row, width); 372 BayerRow1(src_bayer + src_stride_bayer, -src_stride_bayer, 373 row + kRowSize, width); 374 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); 375 ARGBToYRow(row, dst_y, width); 376 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); 377 src_bayer += src_stride_bayer * 2; 378 dst_y += dst_stride_y * 2; 379 dst_u += dst_stride_u; 380 dst_v += dst_stride_v; 381 } 382 if (height & 1) { 383 BayerRow0(src_bayer, src_stride_bayer, row, width); 384 ARGBToUVRow(row, 0, dst_u, dst_v, width); 385 ARGBToYRow(row, dst_y, width); 386 } 387 free_aligned_buffer_64(row); 388 } 389 return 0; 390 } 391 392 // Convert I420 to Bayer. 393 LIBYUV_API 394 int I420ToBayer(const uint8* src_y, int src_stride_y, 395 const uint8* src_u, int src_stride_u, 396 const uint8* src_v, int src_stride_v, 397 uint8* dst_bayer, int dst_stride_bayer, 398 int width, int height, 399 uint32 dst_fourcc_bayer) { 400 void (*I422ToARGBRow)(const uint8* y_buf, 401 const uint8* u_buf, 402 const uint8* v_buf, 403 uint8* rgb_buf, 404 int width) = I422ToARGBRow_C; 405 void (*ARGBToBayerRow)(const uint8* src_argb, uint8* dst_bayer, 406 uint32 selector, int pix) = ARGBToBayerRow_C; 407 const int blue_index = 0; // Offsets for ARGB format 408 const int green_index = 1; 409 const int red_index = 2; 410 uint32 index_map[2]; 411 // Negative height means invert the image. 412 if (height < 0) { 413 int halfheight; 414 height = -height; 415 halfheight = (height + 1) >> 1; 416 src_y = src_y + (height - 1) * src_stride_y; 417 src_u = src_u + (halfheight - 1) * src_stride_u; 418 src_v = src_v + (halfheight - 1) * src_stride_v; 419 src_stride_y = -src_stride_y; 420 src_stride_u = -src_stride_u; 421 src_stride_v = -src_stride_v; 422 } 423 #if defined(HAS_I422TOARGBROW_SSSE3) 424 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 425 I422ToARGBRow = I422ToARGBRow_Any_SSSE3; 426 if (IS_ALIGNED(width, 8)) { 427 I422ToARGBRow = I422ToARGBRow_SSSE3; 428 } 429 } 430 #endif 431 #if defined(HAS_I422TOARGBROW_AVX2) 432 if (TestCpuFlag(kCpuHasAVX2) && width >= 16) { 433 I422ToARGBRow = I422ToARGBRow_Any_AVX2; 434 if (IS_ALIGNED(width, 16)) { 435 I422ToARGBRow = I422ToARGBRow_AVX2; 436 } 437 } 438 #endif 439 #if defined(HAS_I422TOARGBROW_NEON) 440 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 441 I422ToARGBRow = I422ToARGBRow_Any_NEON; 442 if (IS_ALIGNED(width, 8)) { 443 I422ToARGBRow = I422ToARGBRow_NEON; 444 } 445 } 446 #endif 447 #if defined(HAS_I422TOARGBROW_MIPS_DSPR2) 448 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) && 449 IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) && 450 IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) && 451 IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2)) { 452 I422ToARGBRow = I422ToARGBRow_MIPS_DSPR2; 453 } 454 #endif 455 456 #if defined(HAS_ARGBTOBAYERROW_SSSE3) 457 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { 458 ARGBToBayerRow = ARGBToBayerRow_Any_SSSE3; 459 if (IS_ALIGNED(width, 8)) { 460 ARGBToBayerRow = ARGBToBayerRow_SSSE3; 461 } 462 } 463 #elif defined(HAS_ARGBTOBAYERROW_NEON) 464 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { 465 ARGBToBayerRow = ARGBToBayerRow_Any_NEON; 466 if (IS_ALIGNED(width, 8)) { 467 ARGBToBayerRow = ARGBToBayerRow_NEON; 468 } 469 } 470 #endif 471 472 if (MakeSelectors(blue_index, green_index, red_index, 473 dst_fourcc_bayer, index_map)) { 474 return -1; // Bad FourCC 475 } 476 { 477 // Allocate a row of ARGB. 478 align_buffer_64(row, width * 4); 479 int y; 480 for (y = 0; y < height; ++y) { 481 I422ToARGBRow(src_y, src_u, src_v, row, width); 482 ARGBToBayerRow(row, dst_bayer, index_map[y & 1], width); 483 dst_bayer += dst_stride_bayer; 484 src_y += src_stride_y; 485 if (y & 1) { 486 src_u += src_stride_u; 487 src_v += src_stride_v; 488 } 489 } 490 free_aligned_buffer_64(row); 491 } 492 return 0; 493 } 494 495 #define MAKEBAYERFOURCC(BAYER) \ 496 LIBYUV_API \ 497 int Bayer##BAYER##ToI420(const uint8* src_bayer, int src_stride_bayer, \ 498 uint8* dst_y, int dst_stride_y, \ 499 uint8* dst_u, int dst_stride_u, \ 500 uint8* dst_v, int dst_stride_v, \ 501 int width, int height) { \ 502 return BayerToI420(src_bayer, src_stride_bayer, \ 503 dst_y, dst_stride_y, \ 504 dst_u, dst_stride_u, \ 505 dst_v, dst_stride_v, \ 506 width, height, \ 507 FOURCC_##BAYER); \ 508 } \ 509 \ 510 LIBYUV_API \ 511 int I420ToBayer##BAYER(const uint8* src_y, int src_stride_y, \ 512 const uint8* src_u, int src_stride_u, \ 513 const uint8* src_v, int src_stride_v, \ 514 uint8* dst_bayer, int dst_stride_bayer, \ 515 int width, int height) { \ 516 return I420ToBayer(src_y, src_stride_y, \ 517 src_u, src_stride_u, \ 518 src_v, src_stride_v, \ 519 dst_bayer, dst_stride_bayer, \ 520 width, height, \ 521 FOURCC_##BAYER); \ 522 } \ 523 \ 524 LIBYUV_API \ 525 int ARGBToBayer##BAYER(const uint8* src_argb, int src_stride_argb, \ 526 uint8* dst_bayer, int dst_stride_bayer, \ 527 int width, int height) { \ 528 return ARGBToBayer(src_argb, src_stride_argb, \ 529 dst_bayer, dst_stride_bayer, \ 530 width, height, \ 531 FOURCC_##BAYER); \ 532 } \ 533 \ 534 LIBYUV_API \ 535 int Bayer##BAYER##ToARGB(const uint8* src_bayer, int src_stride_bayer, \ 536 uint8* dst_argb, int dst_stride_argb, \ 537 int width, int height) { \ 538 return BayerToARGB(src_bayer, src_stride_bayer, \ 539 dst_argb, dst_stride_argb, \ 540 width, height, \ 541 FOURCC_##BAYER); \ 542 } 543 544 MAKEBAYERFOURCC(BGGR) 545 MAKEBAYERFOURCC(GBRG) 546 MAKEBAYERFOURCC(GRBG) 547 MAKEBAYERFOURCC(RGGB) 548 549 #ifdef __cplusplus 550 } // extern "C" 551 } // namespace libyuv 552 #endif 553