1 /* 2 * Copyright 2015 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 <stdlib.h> 12 13 #include "libyuv/basic_types.h" 14 #include "libyuv/convert.h" 15 #include "libyuv/convert_argb.h" 16 #include "libyuv/convert_from.h" 17 #include "libyuv/convert_from_argb.h" 18 #include "libyuv/cpu_id.h" 19 #include "../unit_test/unit_test.h" 20 21 namespace libyuv { 22 23 // TODO(fbarchard): Port high accuracy YUV to RGB to Neon. 24 #if !defined(LIBYUV_DISABLE_NEON) && \ 25 (defined(__aarch64__) || defined(__ARM_NEON__) || defined(LIBYUV_NEON)) 26 #define ERROR_R 1 27 #define ERROR_G 1 28 #define ERROR_B 3 29 #define ERROR_FULL 6 30 #define ERROR_J420 5 31 #else 32 #define ERROR_R 1 33 #define ERROR_G 1 34 #define ERROR_B 3 35 #define ERROR_FULL 5 36 #define ERROR_J420 3 37 #endif 38 39 #define TESTCS(TESTNAME, YUVTOARGB, ARGBTOYUV, HS1, HS, HN, DIFF) \ 40 TEST_F(LibYUVColorTest, TESTNAME) { \ 41 const int kPixels = benchmark_width_ * benchmark_height_; \ 42 const int kHalfPixels = ((benchmark_width_ + 1) / 2) * \ 43 ((benchmark_height_ + HS1) / HS); \ 44 align_buffer_page_end(orig_y, kPixels); \ 45 align_buffer_page_end(orig_u, kHalfPixels); \ 46 align_buffer_page_end(orig_v, kHalfPixels); \ 47 align_buffer_page_end(orig_pixels, kPixels * 4); \ 48 align_buffer_page_end(temp_y, kPixels); \ 49 align_buffer_page_end(temp_u, kHalfPixels); \ 50 align_buffer_page_end(temp_v, kHalfPixels); \ 51 align_buffer_page_end(dst_pixels_opt, kPixels * 4); \ 52 align_buffer_page_end(dst_pixels_c, kPixels * 4); \ 53 \ 54 MemRandomize(orig_pixels, kPixels * 4); \ 55 MemRandomize(orig_y, kPixels); \ 56 MemRandomize(orig_u, kHalfPixels); \ 57 MemRandomize(orig_v, kHalfPixels); \ 58 MemRandomize(temp_y, kPixels); \ 59 MemRandomize(temp_u, kHalfPixels); \ 60 MemRandomize(temp_v, kHalfPixels); \ 61 MemRandomize(dst_pixels_opt, kPixels * 4); \ 62 MemRandomize(dst_pixels_c, kPixels * 4); \ 63 \ 64 /* The test is overall for color conversion matrix being reversible, so */ \ 65 /* this initializes the pixel with 2x2 blocks to eliminate subsampling. */ \ 66 uint8* p = orig_y; \ 67 for (int y = 0; y < benchmark_height_ - HS1; y += HS) { \ 68 for (int x = 0; x < benchmark_width_ - 1; x += 2) { \ 69 uint8 r = static_cast<uint8>(fastrand()); \ 70 p[0] = r; \ 71 p[1] = r; \ 72 p[HN] = r; \ 73 p[HN + 1] = r; \ 74 p += 2; \ 75 } \ 76 if (benchmark_width_ & 1) { \ 77 uint8 r = static_cast<uint8>(fastrand()); \ 78 p[0] = r; \ 79 p[HN] = r; \ 80 p += 1; \ 81 } \ 82 p += HN; \ 83 } \ 84 if ((benchmark_height_ & 1) && HS == 2) { \ 85 for (int x = 0; x < benchmark_width_ - 1; x += 2) { \ 86 uint8 r = static_cast<uint8>(fastrand()); \ 87 p[0] = r; \ 88 p[1] = r; \ 89 p += 2; \ 90 } \ 91 if (benchmark_width_ & 1) { \ 92 uint8 r = static_cast<uint8>(fastrand()); \ 93 p[0] = r; \ 94 p += 1; \ 95 } \ 96 } \ 97 /* Start with YUV converted to ARGB. */ \ 98 YUVTOARGB(orig_y, benchmark_width_, \ 99 orig_u, (benchmark_width_ + 1) / 2, \ 100 orig_v, (benchmark_width_ + 1) / 2, \ 101 orig_pixels, benchmark_width_ * 4, \ 102 benchmark_width_, benchmark_height_); \ 103 \ 104 ARGBTOYUV(orig_pixels, benchmark_width_ * 4, \ 105 temp_y, benchmark_width_, \ 106 temp_u, (benchmark_width_ + 1) / 2, \ 107 temp_v, (benchmark_width_ + 1) / 2, \ 108 benchmark_width_, benchmark_height_); \ 109 \ 110 MaskCpuFlags(disable_cpu_flags_); \ 111 YUVTOARGB(temp_y, benchmark_width_, \ 112 temp_u, (benchmark_width_ + 1) / 2, \ 113 temp_v, (benchmark_width_ + 1) / 2, \ 114 dst_pixels_c, benchmark_width_ * 4, \ 115 benchmark_width_, benchmark_height_); \ 116 MaskCpuFlags(benchmark_cpu_info_); \ 117 \ 118 for (int i = 0; i < benchmark_iterations_; ++i) { \ 119 YUVTOARGB(temp_y, benchmark_width_, \ 120 temp_u, (benchmark_width_ + 1) / 2, \ 121 temp_v, (benchmark_width_ + 1) / 2, \ 122 dst_pixels_opt, benchmark_width_ * 4, \ 123 benchmark_width_, benchmark_height_); \ 124 } \ 125 /* Test C and SIMD match. */ \ 126 for (int i = 0; i < kPixels * 4; ++i) { \ 127 EXPECT_EQ(dst_pixels_c[i], dst_pixels_opt[i]); \ 128 } \ 129 /* Test SIMD is close to original. */ \ 130 for (int i = 0; i < kPixels * 4; ++i) { \ 131 EXPECT_NEAR(static_cast<int>(orig_pixels[i]), \ 132 static_cast<int>(dst_pixels_opt[i]), DIFF); \ 133 } \ 134 \ 135 free_aligned_buffer_page_end(orig_pixels); \ 136 free_aligned_buffer_page_end(orig_y); \ 137 free_aligned_buffer_page_end(orig_u); \ 138 free_aligned_buffer_page_end(orig_v); \ 139 free_aligned_buffer_page_end(temp_y); \ 140 free_aligned_buffer_page_end(temp_u); \ 141 free_aligned_buffer_page_end(temp_v); \ 142 free_aligned_buffer_page_end(dst_pixels_opt); \ 143 free_aligned_buffer_page_end(dst_pixels_c); \ 144 } \ 145 146 TESTCS(TestI420, I420ToARGB, ARGBToI420, 1, 2, benchmark_width_, ERROR_FULL) 147 TESTCS(TestI422, I422ToARGB, ARGBToI422, 0, 1, 0, ERROR_FULL) 148 TESTCS(TestJ420, J420ToARGB, ARGBToJ420, 1, 2, benchmark_width_, ERROR_J420) 149 TESTCS(TestJ422, J422ToARGB, ARGBToJ422, 0, 1, 0, ERROR_J420) 150 151 static void YUVToRGB(int y, int u, int v, int* r, int* g, int* b) { 152 const int kWidth = 16; 153 const int kHeight = 1; 154 const int kPixels = kWidth * kHeight; 155 const int kHalfPixels = ((kWidth + 1) / 2) * ((kHeight + 1) / 2); 156 157 SIMD_ALIGNED(uint8 orig_y[16]); 158 SIMD_ALIGNED(uint8 orig_u[8]); 159 SIMD_ALIGNED(uint8 orig_v[8]); 160 SIMD_ALIGNED(uint8 orig_pixels[16 * 4]); 161 memset(orig_y, y, kPixels); 162 memset(orig_u, u, kHalfPixels); 163 memset(orig_v, v, kHalfPixels); 164 165 /* YUV converted to ARGB. */ 166 I422ToARGB(orig_y, kWidth, 167 orig_u, (kWidth + 1) / 2, 168 orig_v, (kWidth + 1) / 2, 169 orig_pixels, kWidth * 4, 170 kWidth, kHeight); 171 172 *b = orig_pixels[0]; 173 *g = orig_pixels[1]; 174 *r = orig_pixels[2]; 175 } 176 177 static void YUVJToRGB(int y, int u, int v, int* r, int* g, int* b) { 178 const int kWidth = 16; 179 const int kHeight = 1; 180 const int kPixels = kWidth * kHeight; 181 const int kHalfPixels = ((kWidth + 1) / 2) * ((kHeight + 1) / 2); 182 183 SIMD_ALIGNED(uint8 orig_y[16]); 184 SIMD_ALIGNED(uint8 orig_u[8]); 185 SIMD_ALIGNED(uint8 orig_v[8]); 186 SIMD_ALIGNED(uint8 orig_pixels[16 * 4]); 187 memset(orig_y, y, kPixels); 188 memset(orig_u, u, kHalfPixels); 189 memset(orig_v, v, kHalfPixels); 190 191 /* YUV converted to ARGB. */ 192 J422ToARGB(orig_y, kWidth, 193 orig_u, (kWidth + 1) / 2, 194 orig_v, (kWidth + 1) / 2, 195 orig_pixels, kWidth * 4, 196 kWidth, kHeight); 197 198 *b = orig_pixels[0]; 199 *g = orig_pixels[1]; 200 *r = orig_pixels[2]; 201 } 202 203 static void YToRGB(int y, int* r, int* g, int* b) { 204 const int kWidth = 16; 205 const int kHeight = 1; 206 const int kPixels = kWidth * kHeight; 207 208 SIMD_ALIGNED(uint8 orig_y[16]); 209 SIMD_ALIGNED(uint8 orig_pixels[16 * 4]); 210 memset(orig_y, y, kPixels); 211 212 /* YUV converted to ARGB. */ 213 I400ToARGB(orig_y, kWidth, orig_pixels, kWidth * 4, kWidth, kHeight); 214 215 *b = orig_pixels[0]; 216 *g = orig_pixels[1]; 217 *r = orig_pixels[2]; 218 } 219 220 static void YJToRGB(int y, int* r, int* g, int* b) { 221 const int kWidth = 16; 222 const int kHeight = 1; 223 const int kPixels = kWidth * kHeight; 224 225 SIMD_ALIGNED(uint8 orig_y[16]); 226 SIMD_ALIGNED(uint8 orig_pixels[16 * 4]); 227 memset(orig_y, y, kPixels); 228 229 /* YUV converted to ARGB. */ 230 J400ToARGB(orig_y, kWidth, orig_pixels, kWidth * 4, kWidth, kHeight); 231 232 *b = orig_pixels[0]; 233 *g = orig_pixels[1]; 234 *r = orig_pixels[2]; 235 } 236 237 // Pick a method for clamping. 238 // #define CLAMPMETHOD_IF 1 239 // #define CLAMPMETHOD_TABLE 1 240 #define CLAMPMETHOD_TERNARY 1 241 // #define CLAMPMETHOD_MASK 1 242 243 // Pick a method for rounding. 244 #define ROUND(f) static_cast<int>(f + 0.5f) 245 // #define ROUND(f) lrintf(f) 246 // #define ROUND(f) static_cast<int>(round(f)) 247 // #define ROUND(f) _mm_cvt_ss2si(_mm_load_ss(&f)) 248 249 #if defined(CLAMPMETHOD_IF) 250 static int RoundToByte(float f) { 251 int i = ROUND(f); 252 if (i < 0) { 253 i = 0; 254 } 255 if (i > 255) { 256 i = 255; 257 } 258 return i; 259 } 260 #elif defined(CLAMPMETHOD_TABLE) 261 static const unsigned char clamptable[811] = { 262 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 263 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 264 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 265 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 266 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 267 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 268 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 269 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 270 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 271 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 272 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 273 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 274 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 275 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 276 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 277 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 278 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 279 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 280 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 281 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 282 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 283 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 284 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 285 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 286 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 287 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 288 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 289 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 290 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 291 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 292 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 293 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 294 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 295 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 296 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 297 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 298 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 299 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 300 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 301 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 302 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 303 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 304 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 305 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 306 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 307 }; 308 309 static int RoundToByte(float f) { 310 return clamptable[ROUND(f) + 276]; 311 } 312 #elif defined(CLAMPMETHOD_TERNARY) 313 static int RoundToByte(float f) { 314 int i = ROUND(f); 315 return (i < 0) ? 0 : ((i > 255) ? 255 : i); 316 } 317 #elif defined(CLAMPMETHOD_MASK) 318 static int RoundToByte(float f) { 319 int i = ROUND(f); 320 i = ((-(i) >> 31) & (i)); // clamp to 0. 321 return (((255 - (i)) >> 31) | (i)) & 255; // clamp to 255. 322 } 323 #endif 324 325 #define RANDOM256(s) ((s & 1) ? ((s >> 1) ^ 0xb8) : (s >> 1)) 326 327 TEST_F(LibYUVColorTest, TestRoundToByte) { 328 int allb = 0; 329 int count = benchmark_width_ * benchmark_height_; 330 for (int i = 0; i < benchmark_iterations_; ++i) { 331 float f = (fastrand() & 255) * 3.14f - 260.f; 332 for (int j = 0; j < count; ++j) { 333 int b = RoundToByte(f); 334 f += 0.91f; 335 allb |= b; 336 } 337 } 338 EXPECT_GE(allb, 0); 339 EXPECT_LE(allb, 255); 340 } 341 342 static void YUVToRGBReference(int y, int u, int v, int* r, int* g, int* b) { 343 *r = RoundToByte((y - 16) * 1.164 - (v - 128) * -1.596); 344 *g = RoundToByte((y - 16) * 1.164 - (u - 128) * 0.391 - (v - 128) * 0.813); 345 *b = RoundToByte((y - 16) * 1.164 - (u - 128) * -2.018); 346 } 347 348 static void YUVJToRGBReference(int y, int u, int v, int* r, int* g, int* b) { 349 *r = RoundToByte(y - (v - 128) * -1.40200); 350 *g = RoundToByte(y - (u - 128) * 0.34414 - (v - 128) * 0.71414); 351 *b = RoundToByte(y - (u - 128) * -1.77200); 352 } 353 354 TEST_F(LibYUVColorTest, TestYUV) { 355 int r0, g0, b0, r1, g1, b1; 356 357 // cyan (less red) 358 YUVToRGBReference(240, 255, 0, &r0, &g0, &b0); 359 EXPECT_EQ(56, r0); 360 EXPECT_EQ(255, g0); 361 EXPECT_EQ(255, b0); 362 363 YUVToRGB(240, 255, 0, &r1, &g1, &b1); 364 EXPECT_EQ(57, r1); 365 EXPECT_EQ(255, g1); 366 EXPECT_EQ(255, b1); 367 368 // green (less red and blue) 369 YUVToRGBReference(240, 0, 0, &r0, &g0, &b0); 370 EXPECT_EQ(56, r0); 371 EXPECT_EQ(255, g0); 372 EXPECT_EQ(2, b0); 373 374 YUVToRGB(240, 0, 0, &r1, &g1, &b1); 375 EXPECT_EQ(57, r1); 376 EXPECT_EQ(255, g1); 377 EXPECT_EQ(5, b1); 378 379 for (int i = 0; i < 256; ++i) { 380 YUVToRGBReference(i, 128, 128, &r0, &g0, &b0); 381 YUVToRGB(i, 128, 128, &r1, &g1, &b1); 382 EXPECT_NEAR(r0, r1, ERROR_R); 383 EXPECT_NEAR(g0, g1, ERROR_G); 384 EXPECT_NEAR(b0, b1, ERROR_B); 385 386 YUVToRGBReference(i, 0, 0, &r0, &g0, &b0); 387 YUVToRGB(i, 0, 0, &r1, &g1, &b1); 388 EXPECT_NEAR(r0, r1, ERROR_R); 389 EXPECT_NEAR(g0, g1, ERROR_G); 390 EXPECT_NEAR(b0, b1, ERROR_B); 391 392 YUVToRGBReference(i, 0, 255, &r0, &g0, &b0); 393 YUVToRGB(i, 0, 255, &r1, &g1, &b1); 394 EXPECT_NEAR(r0, r1, ERROR_R); 395 EXPECT_NEAR(g0, g1, ERROR_G); 396 EXPECT_NEAR(b0, b1, ERROR_B); 397 } 398 } 399 400 TEST_F(LibYUVColorTest, TestGreyYUV) { 401 int r0, g0, b0, r1, g1, b1, r2, g2, b2; 402 403 // black 404 YUVToRGBReference(16, 128, 128, &r0, &g0, &b0); 405 EXPECT_EQ(0, r0); 406 EXPECT_EQ(0, g0); 407 EXPECT_EQ(0, b0); 408 409 YUVToRGB(16, 128, 128, &r1, &g1, &b1); 410 EXPECT_EQ(0, r1); 411 EXPECT_EQ(0, g1); 412 EXPECT_EQ(0, b1); 413 414 // white 415 YUVToRGBReference(240, 128, 128, &r0, &g0, &b0); 416 EXPECT_EQ(255, r0); 417 EXPECT_EQ(255, g0); 418 EXPECT_EQ(255, b0); 419 420 YUVToRGB(240, 128, 128, &r1, &g1, &b1); 421 EXPECT_EQ(255, r1); 422 EXPECT_EQ(255, g1); 423 EXPECT_EQ(255, b1); 424 425 // grey 426 YUVToRGBReference(128, 128, 128, &r0, &g0, &b0); 427 EXPECT_EQ(130, r0); 428 EXPECT_EQ(130, g0); 429 EXPECT_EQ(130, b0); 430 431 YUVToRGB(128, 128, 128, &r1, &g1, &b1); 432 EXPECT_EQ(130, r1); 433 EXPECT_EQ(130, g1); 434 EXPECT_EQ(130, b1); 435 436 437 for (int y = 0; y < 256; ++y) { 438 YUVToRGBReference(y, 128, 128, &r0, &g0, &b0); 439 YUVToRGB(y, 128, 128, &r1, &g1, &b1); 440 YToRGB(y, &r2, &g2, &b2); 441 EXPECT_EQ(r0, r1); 442 EXPECT_EQ(g0, g1); 443 EXPECT_EQ(b0, b1); 444 EXPECT_EQ(r0, r2); 445 EXPECT_EQ(g0, g2); 446 EXPECT_EQ(b0, b2); 447 } 448 } 449 450 static void PrintHistogram(int rh[256], int gh[256], int bh[256]) { 451 int i; 452 printf("hist"); 453 for (i = 0; i < 256; ++i) { 454 if (rh[i] || gh[i] || bh[i]) { 455 printf("\t%8d", i - 128); 456 } 457 } 458 printf("\nred"); 459 for (i = 0; i < 256; ++i) { 460 if (rh[i] || gh[i] || bh[i]) { 461 printf("\t%8d", rh[i]); 462 } 463 } 464 printf("\ngreen"); 465 for (i = 0; i < 256; ++i) { 466 if (rh[i] || gh[i] || bh[i]) { 467 printf("\t%8d", gh[i]); 468 } 469 } 470 printf("\nblue"); 471 for (i = 0; i < 256; ++i) { 472 if (rh[i] || gh[i] || bh[i]) { 473 printf("\t%8d", bh[i]); 474 } 475 } 476 printf("\n"); 477 } 478 479 TEST_F(LibYUVColorTest, TestFullYUV) { 480 int rh[256] = { 0, }, gh[256] = { 0, }, bh[256] = { 0, }; 481 for (int u = 0; u < 256; ++u) { 482 for (int v = 0; v < 256; ++v) { 483 for (int y2 = 0; y2 < 256; ++y2) { 484 int r0, g0, b0, r1, g1, b1; 485 int y = RANDOM256(y2); 486 YUVToRGBReference(y, u, v, &r0, &g0, &b0); 487 YUVToRGB(y, u, v, &r1, &g1, &b1); 488 EXPECT_NEAR(r0, r1, ERROR_R); 489 EXPECT_NEAR(g0, g1, ERROR_G); 490 EXPECT_NEAR(b0, b1, ERROR_B); 491 ++rh[r1 - r0 + 128]; 492 ++gh[g1 - g0 + 128]; 493 ++bh[b1 - b0 + 128]; 494 } 495 } 496 } 497 PrintHistogram(rh, gh, bh); 498 } 499 500 TEST_F(LibYUVColorTest, TestFullYUVJ) { 501 int rh[256] = { 0, }, gh[256] = { 0, }, bh[256] = { 0, }; 502 for (int u = 0; u < 256; ++u) { 503 for (int v = 0; v < 256; ++v) { 504 for (int y2 = 0; y2 < 256; ++y2) { 505 int r0, g0, b0, r1, g1, b1; 506 int y = RANDOM256(y2); 507 YUVJToRGBReference(y, u, v, &r0, &g0, &b0); 508 YUVJToRGB(y, u, v, &r1, &g1, &b1); 509 EXPECT_NEAR(r0, r1, 1); 510 EXPECT_NEAR(g0, g1, 1); 511 EXPECT_NEAR(b0, b1, 1); 512 ++rh[r1 - r0 + 128]; 513 ++gh[g1 - g0 + 128]; 514 ++bh[b1 - b0 + 128]; 515 } 516 } 517 } 518 PrintHistogram(rh, gh, bh); 519 } 520 521 TEST_F(LibYUVColorTest, TestGreyYUVJ) { 522 int r0, g0, b0, r1, g1, b1, r2, g2, b2; 523 524 // black 525 YUVJToRGBReference(0, 128, 128, &r0, &g0, &b0); 526 EXPECT_EQ(0, r0); 527 EXPECT_EQ(0, g0); 528 EXPECT_EQ(0, b0); 529 530 YUVJToRGB(0, 128, 128, &r1, &g1, &b1); 531 EXPECT_EQ(0, r1); 532 EXPECT_EQ(0, g1); 533 EXPECT_EQ(0, b1); 534 535 // white 536 YUVJToRGBReference(255, 128, 128, &r0, &g0, &b0); 537 EXPECT_EQ(255, r0); 538 EXPECT_EQ(255, g0); 539 EXPECT_EQ(255, b0); 540 541 YUVJToRGB(255, 128, 128, &r1, &g1, &b1); 542 EXPECT_EQ(255, r1); 543 EXPECT_EQ(255, g1); 544 EXPECT_EQ(255, b1); 545 546 // grey 547 YUVJToRGBReference(128, 128, 128, &r0, &g0, &b0); 548 EXPECT_EQ(128, r0); 549 EXPECT_EQ(128, g0); 550 EXPECT_EQ(128, b0); 551 552 YUVJToRGB(128, 128, 128, &r1, &g1, &b1); 553 EXPECT_EQ(128, r1); 554 EXPECT_EQ(128, g1); 555 EXPECT_EQ(128, b1); 556 557 for (int y = 0; y < 256; ++y) { 558 YUVJToRGBReference(y, 128, 128, &r0, &g0, &b0); 559 YUVJToRGB(y, 128, 128, &r1, &g1, &b1); 560 YJToRGB(y, &r2, &g2, &b2); 561 EXPECT_EQ(r0, r1); 562 EXPECT_EQ(g0, g1); 563 EXPECT_EQ(b0, b1); 564 EXPECT_EQ(r0, r2); 565 EXPECT_EQ(g0, g2); 566 EXPECT_EQ(b0, b2); 567 } 568 } 569 570 } // namespace libyuv 571