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
21namespace 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* 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_, 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
139TESTCS(TestI420, I420ToARGB, ARGBToI420, 1, 2, benchmark_width_, ERROR_FULL)
140TESTCS(TestI422, I422ToARGB, ARGBToI422, 0, 1, 0, ERROR_FULL)
141TESTCS(TestJ420, J420ToARGB, ARGBToJ420, 1, 2, benchmark_width_, ERROR_J420)
142TESTCS(TestJ422, J422ToARGB, ARGBToJ422, 0, 1, 0, ERROR_J420)
143
144static 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 orig_y[16]);
151  SIMD_ALIGNED(uint8 orig_u[8]);
152  SIMD_ALIGNED(uint8 orig_v[8]);
153  SIMD_ALIGNED(uint8 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
167static 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 orig_y[16]);
174  SIMD_ALIGNED(uint8 orig_u[8]);
175  SIMD_ALIGNED(uint8 orig_v[8]);
176  SIMD_ALIGNED(uint8 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
190static 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 orig_y[16]);
196  SIMD_ALIGNED(uint8 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
207static 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 orig_y[16]);
213  SIMD_ALIGNED(uint8 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)
237static 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)
248static 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
305static int RoundToByte(float f) {
306  return clamptable[ROUND(f) + 276];
307}
308#elif defined(CLAMPMETHOD_TERNARY)
309static int RoundToByte(float f) {
310  int i = ROUND(f);
311  return (i < 0) ? 0 : ((i > 255) ? 255 : i);
312}
313#elif defined(CLAMPMETHOD_MASK)
314static 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
323TEST_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
338static 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
344static 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
350TEST_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
396TEST_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
445static 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
474TEST_F(LibYUVColorTest, TestFullYUV) {
475  int rh[256] =
476      {
477          0,
478      },
479      gh[256] =
480          {
481              0,
482          },
483      bh[256] = {
484          0,
485      };
486  for (int u = 0; u < 256; ++u) {
487    for (int v = 0; v < 256; ++v) {
488      for (int y2 = 0; y2 < 256; ++y2) {
489        int r0, g0, b0, r1, g1, b1;
490        int y = RANDOM256(y2);
491        YUVToRGBReference(y, u, v, &r0, &g0, &b0);
492        YUVToRGB(y, u, v, &r1, &g1, &b1);
493        EXPECT_NEAR(r0, r1, ERROR_R);
494        EXPECT_NEAR(g0, g1, ERROR_G);
495        EXPECT_NEAR(b0, b1, ERROR_B);
496        ++rh[r1 - r0 + 128];
497        ++gh[g1 - g0 + 128];
498        ++bh[b1 - b0 + 128];
499      }
500    }
501  }
502  PrintHistogram(rh, gh, bh);
503}
504
505TEST_F(LibYUVColorTest, TestFullYUVJ) {
506  int rh[256] =
507      {
508          0,
509      },
510      gh[256] =
511          {
512              0,
513          },
514      bh[256] = {
515          0,
516      };
517  for (int u = 0; u < 256; ++u) {
518    for (int v = 0; v < 256; ++v) {
519      for (int y2 = 0; y2 < 256; ++y2) {
520        int r0, g0, b0, r1, g1, b1;
521        int y = RANDOM256(y2);
522        YUVJToRGBReference(y, u, v, &r0, &g0, &b0);
523        YUVJToRGB(y, u, v, &r1, &g1, &b1);
524        EXPECT_NEAR(r0, r1, 1);
525        EXPECT_NEAR(g0, g1, 1);
526        EXPECT_NEAR(b0, b1, 1);
527        ++rh[r1 - r0 + 128];
528        ++gh[g1 - g0 + 128];
529        ++bh[b1 - b0 + 128];
530      }
531    }
532  }
533  PrintHistogram(rh, gh, bh);
534}
535
536TEST_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