123d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie/* 223d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie * Copyright 2015 The LibYuv Project Authors. All rights reserved. 323d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie * 423d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie * Use of this source code is governed by a BSD-style license 523d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie * that can be found in the LICENSE file in the root of the source 623d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie * tree. An additional intellectual property rights grant can be found 723d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie * in the file PATENTS. All contributing project authors may 823d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie * be found in the AUTHORS file in the root of the source tree. 923d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie */ 1023d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie 1123d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#include <stdlib.h> 1223d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie 1323d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#include "../unit_test/unit_test.h" 1423d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#include "libyuv/basic_types.h" 1523d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#include "libyuv/convert.h" 1623d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#include "libyuv/convert_argb.h" 1723d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#include "libyuv/convert_from.h" 1823d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#include "libyuv/convert_from_argb.h" 1923d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#include "libyuv/cpu_id.h" 2023d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie 2123d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlienamespace libyuv { 2223d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie 2323d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie// TODO(fbarchard): Port high accuracy YUV to RGB to Neon. 2423d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#if !defined(LIBYUV_DISABLE_NEON) && \ 2523d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie (defined(__aarch64__) || defined(__ARM_NEON__) || defined(LIBYUV_NEON)) 2623d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#define ERROR_R 1 2723d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#define ERROR_G 1 2823d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#define ERROR_B 3 2923d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#define ERROR_FULL 6 3023d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#define ERROR_J420 5 3123d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#else 3223d3559bd4ece1fcab5513ebdaa38600d6654374Dave Airlie#define ERROR_R 1 331f7c914ad0beea8a29c1a171c7cd1a12f2efe0faBrian Paul#define ERROR_G 1 341f7c914ad0beea8a29c1a171c7cd1a12f2efe0faBrian Paul#define ERROR_B 3 351f7c914ad0beea8a29c1a171c7cd1a12f2efe0faBrian Paul#define ERROR_FULL 5 3671fe9437169cfdafda8814aa814bb85429fb6cfcMark Mueller#define ERROR_J420 3 3771fe9437169cfdafda8814aa814bb85429fb6cfcMark Mueller#endif 3871fe9437169cfdafda8814aa814bb85429fb6cfcMark Mueller 3971fe9437169cfdafda8814aa814bb85429fb6cfcMark Mueller#define TESTCS(TESTNAME, YUVTOARGB, ARGBTOYUV, HS1, HS, HN, DIFF) \ 4071fe9437169cfdafda8814aa814bb85429fb6cfcMark Mueller TEST_F(LibYUVColorTest, TESTNAME) { \ 4171fe9437169cfdafda8814aa814bb85429fb6cfcMark Mueller const int kPixels = benchmark_width_ * benchmark_height_; \ 42c2711cdfb68d92ede740e2cc1fd7d78f604dc201Kristian Høgsberg const int kHalfPixels = \ 43c2711cdfb68d92ede740e2cc1fd7d78f604dc201Kristian Høgsberg ((benchmark_width_ + 1) / 2) * ((benchmark_height_ + HS1) / HS); \ 4423ec7c457483aae1e0d399e9b570f1860c27c780Maciej Cencora align_buffer_page_end(orig_y, kPixels); \ 4523ec7c457483aae1e0d399e9b570f1860c27c780Maciej Cencora align_buffer_page_end(orig_u, kHalfPixels); \ 46f9995b30756140724f41daf963fa06167912be7fKristian Høgsberg align_buffer_page_end(orig_v, kHalfPixels); \ 470bb29949ba8a9e5a15dc0640dbb0a4e7990a1d57Eric Anholt align_buffer_page_end(orig_pixels, kPixels * 4); \ 48e0ec3243e87cbdfb5db2657fe791748e145930e8Dave Airlie align_buffer_page_end(temp_y, kPixels); \ 496f6bd8aedcf2b2f0e1ca9a1fa7ded1cb1f5a88edPauli Nieminen align_buffer_page_end(temp_u, kHalfPixels); \ 506f6bd8aedcf2b2f0e1ca9a1fa7ded1cb1f5a88edPauli Nieminen align_buffer_page_end(temp_v, kHalfPixels); \ 516f6bd8aedcf2b2f0e1ca9a1fa7ded1cb1f5a88edPauli Nieminen align_buffer_page_end(dst_pixels_opt, kPixels * 4); \ 521f7c914ad0beea8a29c1a171c7cd1a12f2efe0faBrian Paul align_buffer_page_end(dst_pixels_c, kPixels * 4); \ 53b2596c36c8f73e8bb7a0b1679b491662aeb2f9d9Dave Airlie \ 5471fe9437169cfdafda8814aa814bb85429fb6cfcMark Mueller MemRandomize(orig_pixels, kPixels * 4); \ 55d47a6ada9ca9670c60fc141fabadf40c63031c08Brian Paul MemRandomize(orig_y, kPixels); \ 561f7c914ad0beea8a29c1a171c7cd1a12f2efe0faBrian Paul MemRandomize(orig_u, kHalfPixels); \ 571f7c914ad0beea8a29c1a171c7cd1a12f2efe0faBrian Paul MemRandomize(orig_v, kHalfPixels); \ 581f7c914ad0beea8a29c1a171c7cd1a12f2efe0faBrian Paul MemRandomize(temp_y, kPixels); \ 591f7c914ad0beea8a29c1a171c7cd1a12f2efe0faBrian Paul MemRandomize(temp_u, kHalfPixels); \ 6071fe9437169cfdafda8814aa814bb85429fb6cfcMark Mueller MemRandomize(temp_v, kHalfPixels); \ 611f7c914ad0beea8a29c1a171c7cd1a12f2efe0faBrian Paul MemRandomize(dst_pixels_opt, kPixels * 4); \ 621f7c914ad0beea8a29c1a171c7cd1a12f2efe0faBrian Paul MemRandomize(dst_pixels_c, kPixels * 4); \ 631f7c914ad0beea8a29c1a171c7cd1a12f2efe0faBrian Paul \ 6461bb82636f7b1681b5509e1a9038bbcc1feea35cDave Airlie /* The test is overall for color conversion matrix being reversible, so */ \ 65cd9ab2584f5e2a5eb0e96a948e6aedc9a33c886dBrian Paul /* this initializes the pixel with 2x2 blocks to eliminate subsampling. */ \ 66cd9ab2584f5e2a5eb0e96a948e6aedc9a33c886dBrian Paul uint8* p = orig_y; \ 67cd9ab2584f5e2a5eb0e96a948e6aedc9a33c886dBrian Paul for (int y = 0; y < benchmark_height_ - HS1; y += HS) { \ 68cd9ab2584f5e2a5eb0e96a948e6aedc9a33c886dBrian Paul for (int x = 0; x < benchmark_width_ - 1; x += 2) { \ 69cd9ab2584f5e2a5eb0e96a948e6aedc9a33c886dBrian Paul uint8 r = static_cast<uint8>(fastrand()); \ 70cd9ab2584f5e2a5eb0e96a948e6aedc9a33c886dBrian Paul p[0] = r; \ 718a4d7393bd8a752eba2ee687c1c3e2df5c82745dMaciej Cencora p[1] = r; \ 7271fe9437169cfdafda8814aa814bb85429fb6cfcMark Mueller p[HN] = r; \ 73a17563c7ddfa58fe7f09d22a62a10f3488ef3147Maciej Cencora p[HN + 1] = r; \ 74d7855ee3323e8493f139af70db9d0cdb853c2a08Johann Rudloff p += 2; \ 75d7855ee3323e8493f139af70db9d0cdb853c2a08Johann Rudloff } \ 76d7855ee3323e8493f139af70db9d0cdb853c2a08Johann Rudloff if (benchmark_width_ & 1) { \ 77d7855ee3323e8493f139af70db9d0cdb853c2a08Johann Rudloff uint8 r = static_cast<uint8>(fastrand()); \ 78d7855ee3323e8493f139af70db9d0cdb853c2a08Johann Rudloff p[0] = r; \ 79ff68e3d30415712e0c3d36dc48b47345c852da01Eric Anholt p[HN] = r; \ 80ff68e3d30415712e0c3d36dc48b47345c852da01Eric Anholt p += 1; \ 81ff68e3d30415712e0c3d36dc48b47345c852da01Eric Anholt } \ 82ff68e3d30415712e0c3d36dc48b47345c852da01Eric Anholt p += HN; \ 83d29e96bf33e91d071770b86d87ffc4ef4dfc2f70Dave Airlie } \ 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