1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/cpu.h" 6 #include "base/memory/scoped_ptr.h" 7 #include "media/base/simd/convert_rgb_to_yuv.h" 8 #include "testing/gtest/include/gtest/gtest.h" 9 10 namespace { 11 12 // Reference code that converts RGB pixels to YUV pixels. 13 int ConvertRGBToY(const uint8* rgb) { 14 int y = 25 * rgb[0] + 129 * rgb[1] + 66 * rgb[2]; 15 y = ((y + 128) >> 8) + 16; 16 return std::max(0, std::min(255, y)); 17 } 18 19 int ConvertRGBToU(const uint8* rgb, int size) { 20 int u = 112 * rgb[0] - 74 * rgb[1] - 38 * rgb[2]; 21 u = ((u + 128) >> 8) + 128; 22 return std::max(0, std::min(255, u)); 23 } 24 25 int ConvertRGBToV(const uint8* rgb, int size) { 26 int v = -18 * rgb[0] - 94 * rgb[1] + 112 * rgb[2]; 27 v = ((v + 128) >> 8) + 128; 28 return std::max(0, std::min(255, v)); 29 } 30 31 } // namespace 32 33 // Assembly code confuses MemorySanitizer. Do not run it in MSan builds. 34 #if defined(MEMORY_SANITIZER) 35 #define MAYBE_SideBySideRGB DISABLED_SideBySideRGB 36 #else 37 #define MAYBE_SideBySideRGB SideBySideRGB 38 #endif 39 40 // A side-by-side test that verifies our ASM functions that convert RGB pixels 41 // to YUV pixels can output the expected results. This test converts RGB pixels 42 // to YUV pixels with our ASM functions (which use SSE, SSE2, SSE3, and SSSE3) 43 // and compare the output YUV pixels with the ones calculated with out reference 44 // functions implemented in C++. 45 TEST(YUVConvertTest, MAYBE_SideBySideRGB) { 46 // We skip this test on PCs which does not support SSE3 because this test 47 // needs it. 48 base::CPU cpu; 49 if (!cpu.has_ssse3()) 50 return; 51 52 // This test checks a subset of all RGB values so this test does not take so 53 // long time. 54 const int kStep = 8; 55 const int kWidth = 256 / kStep; 56 57 for (int size = 3; size <= 4; ++size) { 58 // Create the output buffers. 59 scoped_ptr<uint8[]> rgb(new uint8[kWidth * size]); 60 scoped_ptr<uint8[]> y(new uint8[kWidth]); 61 scoped_ptr<uint8[]> u(new uint8[kWidth / 2]); 62 scoped_ptr<uint8[]> v(new uint8[kWidth / 2]); 63 64 // Choose the function that converts from RGB pixels to YUV ones. 65 void (*convert)(const uint8*, uint8*, uint8*, uint8*, 66 int, int, int, int, int) = NULL; 67 if (size == 3) 68 convert = media::ConvertRGB24ToYUV_SSSE3; 69 else 70 convert = media::ConvertRGB32ToYUV_SSSE3; 71 72 int total_error = 0; 73 for (int r = 0; r < kWidth; ++r) { 74 for (int g = 0; g < kWidth; ++g) { 75 76 // Fill the input pixels. 77 for (int b = 0; b < kWidth; ++b) { 78 rgb[b * size + 0] = b * kStep; 79 rgb[b * size + 1] = g * kStep; 80 rgb[b * size + 2] = r * kStep; 81 if (size == 4) 82 rgb[b * size + 3] = 255; 83 } 84 85 // Convert the input RGB pixels to YUV ones. 86 convert(rgb.get(), y.get(), u.get(), v.get(), kWidth, 1, kWidth * size, 87 kWidth, kWidth / 2); 88 89 // Check the output Y pixels. 90 for (int i = 0; i < kWidth; ++i) { 91 const uint8* p = &rgb[i * size]; 92 int error = ConvertRGBToY(p) - y[i]; 93 total_error += error > 0 ? error : -error; 94 } 95 96 // Check the output U pixels. 97 for (int i = 0; i < kWidth / 2; ++i) { 98 const uint8* p = &rgb[i * 2 * size]; 99 int error = ConvertRGBToU(p, size) - u[i]; 100 total_error += error > 0 ? error : -error; 101 } 102 103 // Check the output V pixels. 104 for (int i = 0; i < kWidth / 2; ++i) { 105 const uint8* p = &rgb[i * 2 * size]; 106 int error = ConvertRGBToV(p, size) - v[i]; 107 total_error += error > 0 ? error : -error; 108 } 109 } 110 } 111 112 EXPECT_EQ(0, total_error); 113 } 114 } 115