OLD | NEW |
1 /* | 1 /* |
2 * libjingle | 2 * libjingle |
3 * Copyright 2010 Google Inc. | 3 * Copyright 2010 Google Inc. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions are met: | 6 * modification, are permitted provided that the following conditions are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright notice, | 8 * 1. Redistributions of source code must retain the above copyright notice, |
9 * this list of conditions and the following disclaimer. | 9 * this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright notice, | 10 * 2. Redistributions in binary form must reproduce the above copyright notice, |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
58 // #define TEST_UNCACHED 1 | 58 // #define TEST_UNCACHED 1 |
59 // #define TEST_RSTSC 1 | 59 // #define TEST_RSTSC 1 |
60 #endif | 60 #endif |
61 | 61 |
62 #if defined(TEST_UNCACHED) || defined(TEST_RSTSC) | 62 #if defined(TEST_UNCACHED) || defined(TEST_RSTSC) |
63 #ifdef _MSC_VER | 63 #ifdef _MSC_VER |
64 #include <emmintrin.h> // NOLINT | 64 #include <emmintrin.h> // NOLINT |
65 #endif | 65 #endif |
66 | 66 |
67 #if defined(__GNUC__) && defined(__i386__) | 67 #if defined(__GNUC__) && defined(__i386__) |
68 static inline uint64 __rdtsc(void) { | 68 static inline uint64_t __rdtsc(void) { |
69 uint32_t a, d; | 69 uint32_t a, d; |
70 __asm__ volatile("rdtsc" : "=a" (a), "=d" (d)); | 70 __asm__ volatile("rdtsc" : "=a" (a), "=d" (d)); |
71 return (reinterpret_cast<uint64>(d) << 32) + a; | 71 return (reinterpret_cast<uint64_t>(d) << 32) + a; |
72 } | 72 } |
73 | 73 |
74 static inline void _mm_clflush(volatile void *__p) { | 74 static inline void _mm_clflush(volatile void *__p) { |
75 asm volatile("clflush %0" : "+m" (*(volatile char *)__p)); | 75 asm volatile("clflush %0" : "+m" (*(volatile char *)__p)); |
76 } | 76 } |
77 #endif | 77 #endif |
78 | 78 |
79 static void FlushCache(uint8* dst, int count) { | 79 static void FlushCache(uint8_t* dst, int count) { |
80 while (count >= 32) { | 80 while (count >= 32) { |
81 _mm_clflush(dst); | 81 _mm_clflush(dst); |
82 dst += 32; | 82 dst += 32; |
83 count -= 32; | 83 count -= 32; |
84 } | 84 } |
85 } | 85 } |
86 #endif | 86 #endif |
87 | 87 |
88 class YuvScalerTest : public testing::Test { | 88 class YuvScalerTest : public testing::Test { |
89 protected: | 89 protected: |
90 virtual void SetUp() { | 90 virtual void SetUp() { |
91 dump_ = *rtc::FlagList::Lookup("yuvscaler_dump")->bool_variable(); | 91 dump_ = *rtc::FlagList::Lookup("yuvscaler_dump")->bool_variable(); |
92 repeat_ = *rtc::FlagList::Lookup("yuvscaler_repeat")->int_variable(); | 92 repeat_ = *rtc::FlagList::Lookup("yuvscaler_repeat")->int_variable(); |
93 } | 93 } |
94 | 94 |
95 // Scale an image and compare against a Lanczos-filtered test image. | 95 // Scale an image and compare against a Lanczos-filtered test image. |
96 // Lanczos is considered to be the "ideal" image resampling method, so we try | 96 // Lanczos is considered to be the "ideal" image resampling method, so we try |
97 // to get as close to that as possible, while being as fast as possible. | 97 // to get as close to that as possible, while being as fast as possible. |
98 bool TestScale(int iw, int ih, int ow, int oh, int offset, bool usefile, | 98 bool TestScale(int iw, int ih, int ow, int oh, int offset, bool usefile, |
99 bool optimize, int cpuflags, bool interpolate, | 99 bool optimize, int cpuflags, bool interpolate, |
100 int memoffset, double* error) { | 100 int memoffset, double* error) { |
101 *error = 0.; | 101 *error = 0.; |
102 size_t isize = I420_SIZE(iw, ih); | 102 size_t isize = I420_SIZE(iw, ih); |
103 size_t osize = I420_SIZE(ow, oh); | 103 size_t osize = I420_SIZE(ow, oh); |
104 scoped_ptr<uint8[]> ibuffer(new uint8[isize + kAlignment + memoffset]()); | 104 scoped_ptr<uint8_t[]> ibuffer( |
105 scoped_ptr<uint8[]> obuffer(new uint8[osize + kAlignment + memoffset]()); | 105 new uint8_t[isize + kAlignment + memoffset]()); |
106 scoped_ptr<uint8[]> xbuffer(new uint8[osize + kAlignment + memoffset]()); | 106 scoped_ptr<uint8_t[]> obuffer( |
| 107 new uint8_t[osize + kAlignment + memoffset]()); |
| 108 scoped_ptr<uint8_t[]> xbuffer( |
| 109 new uint8_t[osize + kAlignment + memoffset]()); |
107 | 110 |
108 uint8 *ibuf = ALIGNP(ibuffer.get(), kAlignment) + memoffset; | 111 uint8_t* ibuf = ALIGNP(ibuffer.get(), kAlignment) + memoffset; |
109 uint8 *obuf = ALIGNP(obuffer.get(), kAlignment) + memoffset; | 112 uint8_t* obuf = ALIGNP(obuffer.get(), kAlignment) + memoffset; |
110 uint8 *xbuf = ALIGNP(xbuffer.get(), kAlignment) + memoffset; | 113 uint8_t* xbuf = ALIGNP(xbuffer.get(), kAlignment) + memoffset; |
111 | 114 |
112 if (usefile) { | 115 if (usefile) { |
113 if (!LoadPlanarYuvTestImage("faces", iw, ih, ibuf) || | 116 if (!LoadPlanarYuvTestImage("faces", iw, ih, ibuf) || |
114 !LoadPlanarYuvTestImage("faces", ow, oh, xbuf)) { | 117 !LoadPlanarYuvTestImage("faces", ow, oh, xbuf)) { |
115 LOG(LS_ERROR) << "Failed to load image"; | 118 LOG(LS_ERROR) << "Failed to load image"; |
116 return false; | 119 return false; |
117 } | 120 } |
118 } else { | 121 } else { |
119 // These are used to test huge images. | 122 // These are used to test huge images. |
120 memset(ibuf, 213, isize); // Input is constant color. | 123 memset(ibuf, 213, isize); // Input is constant color. |
121 memset(obuf, 100, osize); // Output set to something wrong for now. | 124 memset(obuf, 100, osize); // Output set to something wrong for now. |
122 memset(xbuf, 213, osize); // Expected result. | 125 memset(xbuf, 213, osize); // Expected result. |
123 } | 126 } |
124 | 127 |
125 #ifdef TEST_UNCACHED | 128 #ifdef TEST_UNCACHED |
126 FlushCache(ibuf, isize); | 129 FlushCache(ibuf, isize); |
127 FlushCache(obuf, osize); | 130 FlushCache(obuf, osize); |
128 FlushCache(xbuf, osize); | 131 FlushCache(xbuf, osize); |
129 #endif | 132 #endif |
130 | 133 |
131 // Scale down. | 134 // Scale down. |
132 // If cpu true, disable cpu optimizations. Else allow auto detect | 135 // If cpu true, disable cpu optimizations. Else allow auto detect |
133 // TODO(fbarchard): set flags for libyuv | 136 // TODO(fbarchard): set flags for libyuv |
134 libyuv::MaskCpuFlags(cpuflags); | 137 libyuv::MaskCpuFlags(cpuflags); |
135 #ifdef TEST_RSTSC | 138 #ifdef TEST_RSTSC |
136 uint64 t = 0; | 139 uint64_t t = 0; |
137 #endif | 140 #endif |
138 for (int i = 0; i < repeat_; ++i) { | 141 for (int i = 0; i < repeat_; ++i) { |
139 #ifdef TEST_UNCACHED | 142 #ifdef TEST_UNCACHED |
140 FlushCache(ibuf, isize); | 143 FlushCache(ibuf, isize); |
141 FlushCache(obuf, osize); | 144 FlushCache(obuf, osize); |
142 #endif | 145 #endif |
143 #ifdef TEST_RSTSC | 146 #ifdef TEST_RSTSC |
144 uint64 t1 = __rdtsc(); | 147 uint64_t t1 = __rdtsc(); |
145 #endif | 148 #endif |
146 EXPECT_EQ(0, libyuv::ScaleOffset(ibuf, iw, ih, obuf, ow, oh, | 149 EXPECT_EQ(0, libyuv::ScaleOffset(ibuf, iw, ih, obuf, ow, oh, |
147 offset, interpolate)); | 150 offset, interpolate)); |
148 #ifdef TEST_RSTSC | 151 #ifdef TEST_RSTSC |
149 uint64 t2 = __rdtsc(); | 152 uint64_t t2 = __rdtsc(); |
150 t += t2 - t1; | 153 t += t2 - t1; |
151 #endif | 154 #endif |
152 } | 155 } |
153 | 156 |
154 #ifdef TEST_RSTSC | 157 #ifdef TEST_RSTSC |
155 LOG(LS_INFO) << "Time: " << std::setw(9) << t; | 158 LOG(LS_INFO) << "Time: " << std::setw(9) << t; |
156 #endif | 159 #endif |
157 | 160 |
158 if (dump_) { | 161 if (dump_) { |
159 const testing::TestInfo* const test_info = | 162 const testing::TestInfo* const test_info = |
160 testing::UnitTest::GetInstance()->current_test_info(); | 163 testing::UnitTest::GetInstance()->current_test_info(); |
161 std::string test_name(test_info->name()); | 164 std::string test_name(test_info->name()); |
162 DumpPlanarYuvTestImage(test_name, obuf, ow, oh); | 165 DumpPlanarYuvTestImage(test_name, obuf, ow, oh); |
163 } | 166 } |
164 | 167 |
165 double sse = cricket::ComputeSumSquareError(obuf, xbuf, osize); | 168 double sse = cricket::ComputeSumSquareError(obuf, xbuf, osize); |
166 *error = sse / osize; // Mean Squared Error. | 169 *error = sse / osize; // Mean Squared Error. |
167 double PSNR = cricket::ComputePSNR(sse, osize); | 170 double PSNR = cricket::ComputePSNR(sse, osize); |
168 LOG(LS_INFO) << "Image MSE: " << | 171 LOG(LS_INFO) << "Image MSE: " << |
169 std::setw(6) << std::setprecision(4) << *error << | 172 std::setw(6) << std::setprecision(4) << *error << |
170 " Image PSNR: " << PSNR; | 173 " Image PSNR: " << PSNR; |
171 return true; | 174 return true; |
172 } | 175 } |
173 | 176 |
174 // Returns the index of the first differing byte. Easier to debug than memcmp. | 177 // Returns the index of the first differing byte. Easier to debug than memcmp. |
175 static int FindDiff(const uint8* buf1, const uint8* buf2, int len) { | 178 static int FindDiff(const uint8_t* buf1, const uint8_t* buf2, int len) { |
176 int i = 0; | 179 int i = 0; |
177 while (i < len && buf1[i] == buf2[i]) { | 180 while (i < len && buf1[i] == buf2[i]) { |
178 i++; | 181 i++; |
179 } | 182 } |
180 return (i < len) ? i : -1; | 183 return (i < len) ? i : -1; |
181 } | 184 } |
182 | 185 |
183 protected: | 186 protected: |
184 bool dump_; | 187 bool dump_; |
185 int repeat_; | 188 int repeat_; |
186 }; | 189 }; |
187 | 190 |
188 // Tests straight copy of data. | 191 // Tests straight copy of data. |
189 TEST_F(YuvScalerTest, TestCopy) { | 192 TEST_F(YuvScalerTest, TestCopy) { |
190 const int iw = 640, ih = 360; | 193 const int iw = 640, ih = 360; |
191 const int ow = 640, oh = 360; | 194 const int ow = 640, oh = 360; |
192 ALIGN16(uint8 ibuf[I420_SIZE(iw, ih)]); | 195 ALIGN16(uint8_t ibuf[I420_SIZE(iw, ih)]); |
193 ALIGN16(uint8 obuf[I420_SIZE(ow, oh)]); | 196 ALIGN16(uint8_t obuf[I420_SIZE(ow, oh)]); |
194 | 197 |
195 // Load the frame, scale it, check it. | 198 // Load the frame, scale it, check it. |
196 ASSERT_TRUE(LoadPlanarYuvTestImage("faces", iw, ih, ibuf)); | 199 ASSERT_TRUE(LoadPlanarYuvTestImage("faces", iw, ih, ibuf)); |
197 for (int i = 0; i < repeat_; ++i) { | 200 for (int i = 0; i < repeat_; ++i) { |
198 libyuv::ScaleOffset(ibuf, iw, ih, obuf, ow, oh, 0, false); | 201 libyuv::ScaleOffset(ibuf, iw, ih, obuf, ow, oh, 0, false); |
199 } | 202 } |
200 if (dump_) DumpPlanarYuvTestImage("TestCopy", obuf, ow, oh); | 203 if (dump_) DumpPlanarYuvTestImage("TestCopy", obuf, ow, oh); |
201 EXPECT_EQ(-1, FindDiff(obuf, ibuf, sizeof(ibuf))); | 204 EXPECT_EQ(-1, FindDiff(obuf, ibuf, sizeof(ibuf))); |
202 } | 205 } |
203 | 206 |
204 // Tests copy from 4:3 to 16:9. | 207 // Tests copy from 4:3 to 16:9. |
205 TEST_F(YuvScalerTest, TestOffset16_10Copy) { | 208 TEST_F(YuvScalerTest, TestOffset16_10Copy) { |
206 const int iw = 640, ih = 360; | 209 const int iw = 640, ih = 360; |
207 const int ow = 640, oh = 480; | 210 const int ow = 640, oh = 480; |
208 const int offset = (480 - 360) / 2; | 211 const int offset = (480 - 360) / 2; |
209 scoped_ptr<uint8[]> ibuffer(new uint8[I420_SIZE(iw, ih) + kAlignment]); | 212 scoped_ptr<uint8_t[]> ibuffer(new uint8_t[I420_SIZE(iw, ih) + kAlignment]); |
210 scoped_ptr<uint8[]> obuffer(new uint8[I420_SIZE(ow, oh) + kAlignment]); | 213 scoped_ptr<uint8_t[]> obuffer(new uint8_t[I420_SIZE(ow, oh) + kAlignment]); |
211 | 214 |
212 uint8 *ibuf = ALIGNP(ibuffer.get(), kAlignment); | 215 uint8_t* ibuf = ALIGNP(ibuffer.get(), kAlignment); |
213 uint8 *obuf = ALIGNP(obuffer.get(), kAlignment); | 216 uint8_t* obuf = ALIGNP(obuffer.get(), kAlignment); |
214 | 217 |
215 // Load the frame, scale it, check it. | 218 // Load the frame, scale it, check it. |
216 ASSERT_TRUE(LoadPlanarYuvTestImage("faces", iw, ih, ibuf)); | 219 ASSERT_TRUE(LoadPlanarYuvTestImage("faces", iw, ih, ibuf)); |
217 | 220 |
218 // Clear to black, which is Y = 0 and U and V = 128 | 221 // Clear to black, which is Y = 0 and U and V = 128 |
219 memset(obuf, 0, ow * oh); | 222 memset(obuf, 0, ow * oh); |
220 memset(obuf + ow * oh, 128, ow * oh / 2); | 223 memset(obuf + ow * oh, 128, ow * oh / 2); |
221 for (int i = 0; i < repeat_; ++i) { | 224 for (int i = 0; i < repeat_; ++i) { |
222 libyuv::ScaleOffset(ibuf, iw, ih, obuf, ow, oh, offset, false); | 225 libyuv::ScaleOffset(ibuf, iw, ih, obuf, ow, oh, offset, false); |
223 } | 226 } |
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
606 TEST_H(TestScaleDown8xHDOptInt, 1280, 720, 1280 / 8, 720 / 8, true, ALLFLAGS, | 609 TEST_H(TestScaleDown8xHDOptInt, 1280, 720, 1280 / 8, 720 / 8, true, ALLFLAGS, |
607 true, 1) | 610 true, 1) |
608 | 611 |
609 // Tests interpolated 1/8x scale down, using optimized algorithm. | 612 // Tests interpolated 1/8x scale down, using optimized algorithm. |
610 TEST_H(TestScaleDown9xHDOptInt, 1280, 720, 1280 / 9, 720 / 9, true, ALLFLAGS, | 613 TEST_H(TestScaleDown9xHDOptInt, 1280, 720, 1280 / 9, 720 / 9, true, ALLFLAGS, |
611 true, 1) | 614 true, 1) |
612 | 615 |
613 // Tests interpolated 1/8x scale down, using optimized algorithm. | 616 // Tests interpolated 1/8x scale down, using optimized algorithm. |
614 TEST_H(TestScaleDown10xHDOptInt, 1280, 720, 1280 / 10, 720 / 10, true, ALLFLAGS, | 617 TEST_H(TestScaleDown10xHDOptInt, 1280, 720, 1280 / 10, 720 / 10, true, ALLFLAGS, |
615 true, 1) | 618 true, 1) |
OLD | NEW |