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 10namespace { 11 12// Reference code that converts RGB pixels to YUV pixels. 13int 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 19int 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 25int 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// A side-by-side test that verifies our ASM functions that convert RGB pixels 34// to YUV pixels can output the expected results. This test converts RGB pixels 35// to YUV pixels with our ASM functions (which use SSE, SSE2, SSE3, and SSSE3) 36// and compare the output YUV pixels with the ones calculated with out reference 37// functions implemented in C++. 38TEST(YUVConvertTest, SideBySideRGB) { 39 // We skip this test on PCs which does not support SSE3 because this test 40 // needs it. 41 base::CPU cpu; 42 if (!cpu.has_ssse3()) 43 return; 44 45 // This test checks a subset of all RGB values so this test does not take so 46 // long time. 47 const int kStep = 8; 48 const int kWidth = 256 / kStep; 49 50 for (int size = 3; size <= 4; ++size) { 51 // Create the output buffers. 52 scoped_ptr<uint8[]> rgb(new uint8[kWidth * size]); 53 scoped_ptr<uint8[]> y(new uint8[kWidth]); 54 scoped_ptr<uint8[]> u(new uint8[kWidth / 2]); 55 scoped_ptr<uint8[]> v(new uint8[kWidth / 2]); 56 57 // Choose the function that converts from RGB pixels to YUV ones. 58 void (*convert)(const uint8*, uint8*, uint8*, uint8*, 59 int, int, int, int, int) = NULL; 60 if (size == 3) 61 convert = media::ConvertRGB24ToYUV_SSSE3; 62 else 63 convert = media::ConvertRGB32ToYUV_SSSE3; 64 65 int total_error = 0; 66 for (int r = 0; r < kWidth; ++r) { 67 for (int g = 0; g < kWidth; ++g) { 68 69 // Fill the input pixels. 70 for (int b = 0; b < kWidth; ++b) { 71 rgb[b * size + 0] = b * kStep; 72 rgb[b * size + 1] = g * kStep; 73 rgb[b * size + 2] = r * kStep; 74 if (size == 4) 75 rgb[b * size + 3] = 255; 76 } 77 78 // Convert the input RGB pixels to YUV ones. 79 convert(rgb.get(), y.get(), u.get(), v.get(), kWidth, 1, kWidth * size, 80 kWidth, kWidth / 2); 81 82 // Check the output Y pixels. 83 for (int i = 0; i < kWidth; ++i) { 84 const uint8* p = &rgb[i * size]; 85 int error = ConvertRGBToY(p) - y[i]; 86 total_error += error > 0 ? error : -error; 87 } 88 89 // Check the output U pixels. 90 for (int i = 0; i < kWidth / 2; ++i) { 91 const uint8* p = &rgb[i * 2 * size]; 92 int error = ConvertRGBToU(p, size) - u[i]; 93 total_error += error > 0 ? error : -error; 94 } 95 96 // Check the output V pixels. 97 for (int i = 0; i < kWidth / 2; ++i) { 98 const uint8* p = &rgb[i * 2 * size]; 99 int error = ConvertRGBToV(p, size) - v[i]; 100 total_error += error > 0 ? error : -error; 101 } 102 } 103 } 104 105 EXPECT_EQ(0, total_error); 106 } 107} 108