• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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