Chromium Code Reviews| Index: media/base/yuv_convert_unittest.cc |
| =================================================================== |
| --- media/base/yuv_convert_unittest.cc (revision 99154) |
| +++ media/base/yuv_convert_unittest.cc (working copy) |
| @@ -6,11 +6,68 @@ |
| #include "base/file_util.h" |
| #include "base/logging.h" |
| #include "base/path_service.h" |
| +#include "base/stringprintf.h" |
| #include "media/base/djb2.h" |
| #include "media/base/yuv_convert.h" |
| #include "media/base/yuv_row.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| +namespace { |
| + |
| +// Reference code that converts RGB pixels to YUV pixels. |
| +int ConvertRGBToY(const uint8* rgb) { |
| + int y = 25 * rgb[0] + 129 * rgb[1] + 66 * rgb[2]; |
| + y = ((y + 128) >> 8) + 16; |
| + return std::max(0, std::min(255, y)); |
| +} |
| + |
| +int ConvertRGBToU(const uint8* rgb, int size, bool subsampling) { |
| + int u = 0; |
| + if (!subsampling) { |
| + u = 112 * rgb[0] - 74 * rgb[1] - 38 * rgb[2]; |
| + } else { |
| + int u0 = 112 * rgb[0] - 74 * rgb[1] - 38 * rgb[2]; |
| + int u1 = 112 * rgb[size] - 74 * rgb[size + 1] - 38 * rgb[size + 2]; |
| + u = (u0 + u1 + 1) / 2; |
| + } |
| + u = ((u + 128) >> 8) + 128; |
| + return std::max(0, std::min(255, u)); |
| +} |
| + |
| +int ConvertRGBToV(const uint8* rgb, int size, bool subsampling) { |
| + int v = 0; |
| + if (!subsampling) { |
| + v = -18 * rgb[0] - 94 * rgb[1] + 112 * rgb[2]; |
| + } else { |
| + int v0 = -18 * rgb[0] - 94 * rgb[1] + 112 * rgb[2]; |
| + int v1 = -18 * rgb[size] - 94 * rgb[size + 1] + 112 * rgb[size + 2]; |
| + v = (v0 + v1 + 1) / 2; |
| + } |
| + v = ((v + 128) >> 8) + 128; |
| + return std::max(0, std::min(255, v)); |
| +} |
| + |
| +// Reference code that converts YUV pixels to RGB pixels. |
| +int ConvertYUVToR(uint8 y, uint8 u, uint8 v) { |
| + int r = 298 * (y - 16) + 409 * (v - 128); |
| + r = (r + 128) >> 8; |
| + return std::max(0, std::min(255, r)); |
| +} |
| + |
| +int ConvertYUVToG(uint8 y, uint8 u, uint8 v) { |
| + int g = 298 * (y - 16) - 100 * (u - 128) - 208 * (v - 128); |
| + g = (g + 128) >> 8; |
| + return std::max(0, std::min(255, g)); |
| +} |
| + |
| +int ConvertYUVToB(uint8 y, uint8 u, uint8 v) { |
| + int b = 298 * (y - 16) + 516 * (u - 128); |
| + b = (b + 128) >> 8; |
| + return std::max(0, std::min(255, b)); |
| +} |
| + |
| +} // namespace |
| + |
| // Size of raw image. |
| static const int kSourceWidth = 640; |
| static const int kSourceHeight = 360; |
| @@ -294,3 +351,115 @@ |
| kDJB2HashSeed); |
| EXPECT_EQ(666823187u, yuy_hash); |
| } |
| + |
| +// A side-by-side test that verifies our ASM functions that convert RGB pixels |
| +// to YUV pixels can output the expected results. This test converts RGB pixels |
| +// to YUV pixels with our ASM functions (which use SSE, SSE2, SSE3, and SSSE3) |
| +// and compare the output YUV pixels with the ones calculated with out reference |
| +// functions implemented in C++. |
| +TEST(YUVConvertTest, SideBySideRGB) { |
|
Alpha Left Google
2011/09/01 13:26:41
One more comment on these tests, since they test C
|
| + // This test checks a subset of all RGB values so this test does not take so |
| + // long time. |
| + const int kStep = 8; |
| + const int kWidth = 256 / kStep; |
| + |
| +#ifdef ENABLE_SUBSAMPLING |
| + const bool kSubsampling = true; |
| +#else |
| + const bool kSubsampling = false; |
| +#endif |
| + |
| + for (int size = 3; size <= 4; ++size) { |
| + // Create the output buffers. |
| + scoped_array<uint8> rgb(new uint8[kWidth * size]); |
| + scoped_array<uint8> y(new uint8[kWidth]); |
| + scoped_array<uint8> u(new uint8[kWidth / 2]); |
| + scoped_array<uint8> v(new uint8[kWidth / 2]); |
| + |
| + // Choose the function that converts from RGB pixels to YUV ones. |
| + void (*convert)(const uint8*, uint8*, uint8*, uint8*, |
| + int, int, int, int, int) = NULL; |
| + if (size == 3) |
| + convert = media::ConvertRGB24ToYUV; |
| + else |
| + convert = media::ConvertRGB32ToYUV; |
| + |
| + for (int r = 0; r < kWidth; ++r) { |
| + for (int g = 0; g < kWidth; ++g) { |
| + |
| + // Fill the input pixels. |
| + for (int b = 0; b < kWidth; ++b) { |
| + rgb[b * size + 0] = b * kStep; |
| + rgb[b * size + 1] = g * kStep; |
| + rgb[b * size + 2] = r * kStep; |
| + if (size == 4) |
| + rgb[b * size + 3] = 255; |
| + } |
| + |
| + // Convert the input RGB pixels to YUV ones. |
| + convert(rgb.get(), y.get(), u.get(), v.get(), kWidth, 1, kWidth * size, |
| + kWidth, kWidth / 2); |
| + |
| + // Check the output Y pixels. |
| + for (int i = 0; i < kWidth; ++i) { |
| + const uint8* p = &rgb[i * size]; |
| + SCOPED_TRACE(base::StringPrintf("r=%d,g=%d,b=%d", p[2], p[1], p[0])); |
| + EXPECT_EQ(ConvertRGBToY(p), y[i]); |
| + } |
| + |
| + // Check the output U pixels. |
| + for (int i = 0; i < kWidth / 2; ++i) { |
| + const uint8* p = &rgb[i * 2 * size]; |
| + SCOPED_TRACE(base::StringPrintf("r=%d,g=%d,b=%d", p[2], p[1], p[0])); |
| + EXPECT_EQ(ConvertRGBToU(p, size, kSubsampling), u[i]); |
| + } |
| + |
| + // Check the output V pixels. |
| + for (int i = 0; i < kWidth / 2; ++i) { |
| + const uint8* p = &rgb[i * 2 * size]; |
| + SCOPED_TRACE(base::StringPrintf("r=%d,g=%d,b=%d", p[2], p[1], p[0])); |
| + EXPECT_EQ(ConvertRGBToV(p, size, kSubsampling), v[i]); |
| + } |
| + } |
| + } |
| + } |
| +} |
| + |
| +// Another side-by-side test for our ASM functions that convert YUV pixels |
| +// to RGB pixels. |
| +TEST(YUVConvertTest, SideBySideYUV) { |
| + const int kStep = 4; |
| + const int kWidth = 256 / kStep; |
| + |
| + // Create the output buffers. |
| + scoped_array<uint8> rgb(new uint8[kWidth * 4]); |
| + scoped_array<uint8> y(new uint8[kWidth]); |
| + scoped_array<uint8> u(new uint8[kWidth / 2]); |
| + scoped_array<uint8> v(new uint8[kWidth / 2]); |
| + |
| + for (int y0 = 0; y0 < kWidth; ++y0) { |
| + for (int i = 0; i < kWidth; ++i) |
| + y[i] = y0 * kStep; |
| + |
| + for (int u0 = 0; u0 < kWidth / 2; ++u0) { |
| + for (int i = 0; i < kWidth / 2; ++i) |
| + u[i] = u0 * kStep * 2; |
| + |
| + for (int v0 = 0; v0 < kWidth / 2; ++v0) |
| + v[v0] = v0 * kStep * 2; |
| + |
| + // Convert the input YUV pixels to RGB ones. |
| + media::ConvertYUVToRGB32(y.get(), u.get(), v.get(), rgb.get(), kWidth, 1, |
| + kWidth, kWidth / 2, kWidth * 4, media::YV12); |
| + |
| + for (int i = 0; i < kWidth; ++i) { |
| + SCOPED_TRACE( |
| + base::StringPrintf("y=%d,u=%d,v=%d", y[i], u[i / 2], v[i / 2])); |
| + EXPECT_EQ(255, rgb[i * 4 + 3]); |
| + EXPECT_EQ(ConvertYUVToR(y[i], u[i / 2], v[i / 2]), rgb[i * 4 + 2]); |
| + EXPECT_EQ(ConvertYUVToG(y[i], u[i / 2], v[i / 2]), rgb[i * 4 + 1]); |
| + EXPECT_EQ(ConvertYUVToB(y[i], u[i / 2], v[i / 2]), rgb[i * 4 + 0]); |
| + } |
| + } |
| + } |
| +} |