Home | History | Annotate | Download | only in unit_test
      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