OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/base_paths.h" | 5 #include "base/base_paths.h" |
6 #include "base/file_util.h" | 6 #include "base/file_util.h" |
7 #include "media/base/yuv_convert.h" | 7 #include "media/base/yuv_convert.h" |
8 #include "media/base/yuv_row.h" | 8 #include "media/base/yuv_row.h" |
9 #include "testing/gtest/include/gtest/gtest.h" | 9 #include "testing/gtest/include/gtest/gtest.h" |
10 | 10 |
11 // Reference images were created with the following steps | 11 // Reference images were created with the following steps |
12 // ffmpeg -vframes 25 -i bali.mov -vcodec rawvideo -pix_fmt yuv420p -an | 12 // ffmpeg -vframes 25 -i bali.mov -vcodec rawvideo -pix_fmt yuv420p -an |
13 // bali.yv12.1280_720.yuv | 13 // bali.yv12.1280_720.yuv |
14 // yuvhalf -yv12 -skip 24 bali.yv12.1280_720.yuv bali.yv12.640_360.yuv | 14 // yuvhalf -yv12 -skip 24 bali.yv12.1280_720.yuv bali.yv12.640_360.yuv |
15 | 15 |
16 // ffmpeg -vframes 25 -i bali.mov -vcodec rawvideo -pix_fmt yuv422p -an | 16 // ffmpeg -vframes 25 -i bali.mov -vcodec rawvideo -pix_fmt yuv422p -an |
17 // bali.yv16.1280_720.yuv | 17 // bali.yv16.1280_720.yuv |
18 // yuvhalf -yv16 -skip 24 bali.yv16.1280_720.yuv bali.yv16.640_360.yuv | 18 // yuvhalf -yv16 -skip 24 bali.yv16.1280_720.yuv bali.yv16.640_360.yuv |
19 // Size of raw image. | 19 // Size of raw image. |
20 | 20 |
| 21 // Size of raw image. |
21 static const int kWidth = 640; | 22 static const int kWidth = 640; |
22 static const int kHeight = 360; | 23 static const int kHeight = 360; |
| 24 static const int kScaledWidth = 1024; |
| 25 static const int kScaledHeight = 768; |
23 static const int kBpp = 4; | 26 static const int kBpp = 4; |
24 | 27 |
25 // Surface sizes. | 28 // Surface sizes. |
26 static const size_t kYUV12Size = kWidth * kHeight * 12 / 8; | 29 static const size_t kYUV12Size = kWidth * kHeight * 12 / 8; |
27 static const size_t kYUV16Size = kWidth * kHeight * 16 / 8; | 30 static const size_t kYUV16Size = kWidth * kHeight * 16 / 8; |
28 static const size_t kRGBSize = kWidth * kHeight * kBpp; | 31 static const size_t kRGBSize = kWidth * kHeight * kBpp; |
29 static const size_t kRGBSizeConverted = kWidth * kHeight * kBpp; | 32 static const size_t kRGBSizeConverted = kWidth * kHeight * kBpp; |
30 | 33 |
| 34 namespace { |
| 35 // DJB2 hash |
| 36 unsigned int hash(unsigned char *s, size_t len, unsigned int hash = 5381) { |
| 37 while (len--) |
| 38 hash = hash * 33 + *s++; |
| 39 return hash; |
| 40 } |
| 41 } |
| 42 |
31 TEST(YUVConvertTest, YV12) { | 43 TEST(YUVConvertTest, YV12) { |
32 // Allocate all surfaces. | 44 // Allocate all surfaces. |
33 scoped_array<uint8> yuv_bytes(new uint8[kYUV12Size]); | 45 scoped_array<uint8> yuv_bytes(new uint8[kYUV12Size]); |
34 scoped_array<uint8> rgb_bytes(new uint8[kRGBSize]); | 46 scoped_array<uint8> rgb_bytes(new uint8[kRGBSize]); |
35 scoped_array<uint8> rgb_converted_bytes(new uint8[kRGBSizeConverted]); | 47 scoped_array<uint8> rgb_converted_bytes(new uint8[kRGBSizeConverted]); |
36 | 48 |
37 // Read YUV reference data from file. | 49 // Read YUV reference data from file. |
38 FilePath yuv_url; | 50 FilePath yuv_url; |
39 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &yuv_url)); | 51 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &yuv_url)); |
40 yuv_url = yuv_url.Append(FILE_PATH_LITERAL("media")) | 52 yuv_url = yuv_url.Append(FILE_PATH_LITERAL("media")) |
41 .Append(FILE_PATH_LITERAL("test")) | 53 .Append(FILE_PATH_LITERAL("test")) |
42 .Append(FILE_PATH_LITERAL("data")) | 54 .Append(FILE_PATH_LITERAL("data")) |
43 .Append(FILE_PATH_LITERAL("bali.yv12.640_360.yuv")); | 55 .Append(FILE_PATH_LITERAL("bali.yv12.640_360.yuv")); |
44 EXPECT_EQ(static_cast<int>(kYUV12Size), | 56 EXPECT_EQ(static_cast<int>(kYUV12Size), |
45 file_util::ReadFile(yuv_url, | 57 file_util::ReadFile(yuv_url, |
46 reinterpret_cast<char*>(yuv_bytes.get()), | 58 reinterpret_cast<char*>(yuv_bytes.get()), |
47 static_cast<int>(kYUV12Size))); | 59 static_cast<int>(kYUV12Size))); |
48 | 60 |
49 // Read RGB reference data from file. | 61 // Convert a frame of YUV to 32 bit ARGB. |
50 FilePath rgb_url; | 62 media::ConvertYUVToRGB32(yuv_bytes.get(), // Y |
51 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &rgb_url)); | 63 yuv_bytes.get() + kWidth * kHeight, // U |
52 rgb_url = rgb_url.Append(FILE_PATH_LITERAL("media")) | 64 yuv_bytes.get() + kWidth * kHeight * 5 / 4, // V |
53 .Append(FILE_PATH_LITERAL("test")) | 65 rgb_converted_bytes.get(), // RGB output |
54 .Append(FILE_PATH_LITERAL("data")) | 66 kWidth, kHeight, // Dimensions |
55 .Append(FILE_PATH_LITERAL("bali.yv12.640_360.rgb")); | 67 kWidth, // YStride |
56 EXPECT_EQ(static_cast<int>(kRGBSize), | 68 kWidth / 2, // UVStride |
57 file_util::ReadFile(rgb_url, | 69 kWidth * kBpp, // RGBStride |
58 reinterpret_cast<char*>(rgb_bytes.get()), | 70 media::YV12); |
59 static_cast<int>(kRGBSize))); | |
60 | 71 |
61 // Convert a frame of YUV to 32 bit ARGB. | 72 unsigned int rgb_hash = hash(rgb_converted_bytes.get(), kRGBSizeConverted); |
62 media::ConvertYV12ToRGB32(yuv_bytes.get(), // Y | |
63 yuv_bytes.get() + kWidth * kHeight, // U | |
64 yuv_bytes.get() + kWidth * kHeight * 5 / 4, // V | |
65 rgb_converted_bytes.get(), // RGB output | |
66 kWidth, kHeight, // Dimensions | |
67 kWidth, // YStride | |
68 kWidth / 2, // UVStride | |
69 kWidth * kBpp); // RGBStride | |
70 | 73 |
71 // TODO(fbarchard): The reference image was converted with MMX. | 74 // To get this hash value, run once and examine the following EXPECT_EQ. |
72 // Non-MMX implementations do not match exactly. In the future, | 75 // Then plug new hash value into EXPECT_EQ statements. |
73 // Mac and Linux will use MMX as well and the unittest will be | 76 |
74 // activated automatically. | 77 // TODO(fbarchard): Make reference code mimic MMX exactly |
75 #if USE_MMX | 78 #if USE_MMX |
76 // Compare converted YUV to reference conversion file. | 79 EXPECT_EQ(2413171226u, rgb_hash); |
77 int rgb_diff = memcmp(rgb_converted_bytes.get(), rgb_bytes.get(), kRGBSize); | 80 #else |
78 | 81 EXPECT_EQ(2936300063u, rgb_hash); |
79 EXPECT_EQ(0, rgb_diff); | |
80 #endif | 82 #endif |
81 return; // This is here to allow you to put a break point on this line | 83 return; // This is here to allow you to put a break point on this line |
82 } | 84 } |
83 | 85 |
84 TEST(YUVConvertTest, YV16) { | 86 TEST(YUVConvertTest, YV16) { |
85 // Allocate all surfaces. | 87 // Allocate all surfaces. |
86 scoped_array<uint8> yuv_bytes(new uint8[kYUV16Size]); | 88 scoped_array<uint8> yuv_bytes(new uint8[kYUV16Size]); |
87 scoped_array<uint8> rgb_bytes(new uint8[kRGBSize]); | 89 scoped_array<uint8> rgb_bytes(new uint8[kRGBSize]); |
88 scoped_array<uint8> rgb_converted_bytes(new uint8[kRGBSizeConverted]); | 90 scoped_array<uint8> rgb_converted_bytes(new uint8[kRGBSizeConverted]); |
89 | 91 |
90 // Read YV16 reference data from file. | 92 // Read YV16 reference data from file. |
91 FilePath yuv_url; | 93 FilePath yuv_url; |
92 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &yuv_url)); | 94 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &yuv_url)); |
93 yuv_url = yuv_url.Append(FILE_PATH_LITERAL("media")) | 95 yuv_url = yuv_url.Append(FILE_PATH_LITERAL("media")) |
94 .Append(FILE_PATH_LITERAL("test")) | 96 .Append(FILE_PATH_LITERAL("test")) |
95 .Append(FILE_PATH_LITERAL("data")) | 97 .Append(FILE_PATH_LITERAL("data")) |
96 .Append(FILE_PATH_LITERAL("bali.yv16.640_360.yuv")); | 98 .Append(FILE_PATH_LITERAL("bali.yv16.640_360.yuv")); |
97 EXPECT_EQ(static_cast<int>(kYUV16Size), | 99 EXPECT_EQ(static_cast<int>(kYUV16Size), |
98 file_util::ReadFile(yuv_url, | 100 file_util::ReadFile(yuv_url, |
99 reinterpret_cast<char*>(yuv_bytes.get()), | 101 reinterpret_cast<char*>(yuv_bytes.get()), |
100 static_cast<int>(kYUV16Size))); | 102 static_cast<int>(kYUV16Size))); |
101 | 103 |
102 // Read RGB reference data from file. | 104 // Convert a frame of YUV to 32 bit ARGB. |
103 FilePath rgb_url; | 105 media::ConvertYUVToRGB32(yuv_bytes.get(), // Y |
104 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &rgb_url)); | 106 yuv_bytes.get() + kWidth * kHeight, // U |
105 rgb_url = rgb_url.Append(FILE_PATH_LITERAL("media")) | 107 yuv_bytes.get() + kWidth * kHeight * 3 / 2, // V |
| 108 rgb_converted_bytes.get(), // RGB output |
| 109 kWidth, kHeight, // Dimensions |
| 110 kWidth, // YStride |
| 111 kWidth / 2, // UVStride |
| 112 kWidth * kBpp, // RGBStride |
| 113 media::YV16); |
| 114 |
| 115 unsigned int rgb_hash = hash(rgb_converted_bytes.get(), kRGBSizeConverted); |
| 116 |
| 117 // To get this hash value, run once and examine the following EXPECT_EQ. |
| 118 // Then plug new hash value into EXPECT_EQ statements. |
| 119 |
| 120 // TODO(fbarchard): Make reference code mimic MMX exactly |
| 121 #if USE_MMX |
| 122 EXPECT_EQ(4222342047u, rgb_hash); |
| 123 #else |
| 124 EXPECT_EQ(106869773u, rgb_hash); |
| 125 #endif |
| 126 return; // This is here to allow you to put a break point on this line |
| 127 } |
| 128 |
| 129 TEST(YuvScaleTest, Basic) { |
| 130 // Read YUV reference data from file. |
| 131 FilePath yuv_url; |
| 132 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &yuv_url)); |
| 133 yuv_url = yuv_url.Append(FILE_PATH_LITERAL("media")) |
106 .Append(FILE_PATH_LITERAL("test")) | 134 .Append(FILE_PATH_LITERAL("test")) |
107 .Append(FILE_PATH_LITERAL("data")) | 135 .Append(FILE_PATH_LITERAL("data")) |
108 .Append(FILE_PATH_LITERAL("bali.yv16.640_360.rgb")); | 136 .Append(FILE_PATH_LITERAL("bali.yv12.640_360.yuv")); |
109 EXPECT_EQ(static_cast<int>(kRGBSize), | 137 const size_t size_of_yuv = kWidth * kHeight * 12 / 8; // 12 bpp. |
110 file_util::ReadFile(rgb_url, | 138 uint8* yuv_bytes = new uint8[size_of_yuv]; |
111 reinterpret_cast<char*>(rgb_bytes.get()), | 139 EXPECT_EQ(static_cast<int>(size_of_yuv), |
112 static_cast<int>(kRGBSize))); | 140 file_util::ReadFile(yuv_url, |
| 141 reinterpret_cast<char*>(yuv_bytes), |
| 142 static_cast<int>(size_of_yuv))); |
113 | 143 |
114 // Convert a frame of YUV to 32 bit ARGB. | 144 // Scale a frame of YUV to 32 bit ARGB. |
115 media::ConvertYV16ToRGB32(yuv_bytes.get(), // Y | 145 const size_t size_of_rgb_scaled = kScaledWidth * kScaledHeight * kBpp; |
116 yuv_bytes.get() + kWidth * kHeight, // U | 146 uint8* rgb_scaled_bytes = new uint8[size_of_rgb_scaled]; |
117 yuv_bytes.get() + kWidth * kHeight * 3 / 2, // V | |
118 rgb_converted_bytes.get(), // RGB output | |
119 kWidth, kHeight, // Dimensions | |
120 kWidth, // YStride | |
121 kWidth / 2, // UVStride | |
122 kWidth * kBpp); // RGBStride | |
123 | 147 |
124 // TODO(fbarchard): The reference image was converted with MMX. | 148 media::ScaleYUVToRGB32(yuv_bytes, // Y plane |
125 // Non-MMX implementations do not match exactly. In the future, | 149 yuv_bytes + kWidth * kHeight, // U plane |
126 // Mac and Linux will use MMX as well and the unittest will be | 150 yuv_bytes + kWidth * kHeight * 5 / 4, // V plane |
127 // activated automatically. | 151 rgb_scaled_bytes, // Rgb output |
| 152 kWidth, kHeight, // Dimensions |
| 153 kScaledWidth, kScaledHeight, // Dimensions |
| 154 kWidth, // YStride |
| 155 kWidth / 2, // UvStride |
| 156 kScaledWidth * kBpp, // RgbStride |
| 157 media::YV12, |
| 158 media::ROTATE_0); |
| 159 |
| 160 unsigned int rgb_hash = hash(rgb_scaled_bytes, size_of_rgb_scaled); |
| 161 |
| 162 // To get this hash value, run once and examine the following EXPECT_EQ. |
| 163 // Then plug new hash value into EXPECT_EQ statements. |
| 164 |
| 165 // TODO(fbarchard): Make reference code mimic MMX exactly |
128 #if USE_MMX | 166 #if USE_MMX |
129 // Compare converted YUV to reference conversion file. | 167 EXPECT_EQ(4259656254u, rgb_hash); |
130 int rgb_diff = memcmp(rgb_converted_bytes.get(), rgb_bytes.get(), kRGBSize); | 168 #else |
| 169 EXPECT_EQ(197274901u, rgb_hash); |
| 170 #endif |
| 171 return; // This is here to allow you to put a break point on this line |
| 172 } |
131 | 173 |
132 EXPECT_EQ(0, rgb_diff); | 174 TEST(YV16ScaleTest, Basic) { |
| 175 // Read YV16 reference data from file. |
| 176 FilePath yuv_url; |
| 177 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &yuv_url)); |
| 178 yuv_url = yuv_url.Append(FILE_PATH_LITERAL("media")) |
| 179 .Append(FILE_PATH_LITERAL("test")) |
| 180 .Append(FILE_PATH_LITERAL("data")) |
| 181 .Append(FILE_PATH_LITERAL("bali.yv16.640_360.yuv")); |
| 182 const size_t size_of_yuv = kWidth * kHeight * 16 / 8; // 16 bpp. |
| 183 uint8* yuv_bytes = new uint8[size_of_yuv]; |
| 184 EXPECT_EQ(static_cast<int>(size_of_yuv), |
| 185 file_util::ReadFile(yuv_url, |
| 186 reinterpret_cast<char*>(yuv_bytes), |
| 187 static_cast<int>(size_of_yuv))); |
| 188 |
| 189 // Scale a frame of YUV to 32 bit ARGB. |
| 190 const size_t size_of_rgb_scaled = kScaledWidth * kScaledHeight * kBpp; |
| 191 uint8* rgb_scaled_bytes = new uint8[size_of_rgb_scaled]; |
| 192 |
| 193 media::ScaleYUVToRGB32(yuv_bytes, // Y plane |
| 194 yuv_bytes + kWidth * kHeight, // U plane |
| 195 yuv_bytes + kWidth * kHeight * 3 / 2, // V plane |
| 196 rgb_scaled_bytes, // Rgb output |
| 197 kWidth, kHeight, // Dimensions |
| 198 kScaledWidth, kScaledHeight, // Dimensions |
| 199 kWidth, // YStride |
| 200 kWidth / 2, // UvStride |
| 201 kScaledWidth * kBpp, // RgbStride |
| 202 media::YV16, |
| 203 media::ROTATE_0); |
| 204 |
| 205 unsigned int rgb_hash = hash(rgb_scaled_bytes, size_of_rgb_scaled); |
| 206 |
| 207 // To get this hash value, run once and examine the following EXPECT_EQ. |
| 208 // Then plug new hash value into EXPECT_EQ statements. |
| 209 |
| 210 // TODO(fbarchard): Make reference code mimic MMX exactly |
| 211 #if USE_MMX |
| 212 EXPECT_EQ(974965419u, rgb_hash); |
| 213 #else |
| 214 EXPECT_EQ(2946450771u, rgb_hash); |
133 #endif | 215 #endif |
134 return; | 216 return; |
135 } | 217 } |
136 | 218 |
OLD | NEW |