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