OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include <math.h> | |
12 #include <string.h> | |
13 | |
14 #include <memory> | |
15 | |
16 #include "testing/gtest/include/gtest/gtest.h" | |
17 #include "webrtc/base/timeutils.h" | |
18 #include "webrtc/common_video/libyuv/include/scaler.h" | |
19 #include "webrtc/test/testsupport/fileutils.h" | |
20 | |
21 namespace webrtc { | |
22 | |
23 class TestScaler : public ::testing::Test { | |
24 protected: | |
25 TestScaler(); | |
26 virtual void SetUp(); | |
27 virtual void TearDown(); | |
28 | |
29 void ScaleSequence(ScaleMethod method, | |
30 FILE* source_file, std::string out_name, | |
31 int src_width, int src_height, | |
32 int dst_width, int dst_height); | |
33 // Computes the sequence average PSNR between an input sequence in | |
34 // |input_file| and an output sequence with filename |out_name|. |width| and | |
35 // |height| are the frame sizes of both sequences. | |
36 double ComputeAvgSequencePSNR(FILE* input_file, std::string out_name, | |
37 int width, int height); | |
38 | |
39 Scaler test_scaler_; | |
40 FILE* source_file_; | |
41 VideoFrame test_frame_; | |
42 const int width_; | |
43 const int half_width_; | |
44 const int height_; | |
45 const int half_height_; | |
46 const int size_y_; | |
47 const int size_uv_; | |
48 const size_t frame_length_; | |
49 }; | |
50 | |
51 TestScaler::TestScaler() | |
52 : source_file_(NULL), | |
53 width_(352), | |
54 half_width_(width_ / 2), | |
55 height_(288), | |
56 half_height_(height_ / 2), | |
57 size_y_(width_ * height_), | |
58 size_uv_(half_width_ * half_height_), | |
59 frame_length_(CalcBufferSize(kI420, width_, height_)) { | |
60 } | |
61 | |
62 void TestScaler::SetUp() { | |
63 const std::string input_file_name = | |
64 webrtc::test::ResourcePath("foreman_cif", "yuv"); | |
65 source_file_ = fopen(input_file_name.c_str(), "rb"); | |
66 ASSERT_TRUE(source_file_ != NULL) << "Cannot read file: "<< | |
67 input_file_name << "\n"; | |
68 test_frame_.CreateEmptyFrame(width_, height_, | |
69 width_, half_width_, half_width_); | |
70 } | |
71 | |
72 void TestScaler::TearDown() { | |
73 if (source_file_ != NULL) { | |
74 ASSERT_EQ(0, fclose(source_file_)); | |
75 } | |
76 source_file_ = NULL; | |
77 } | |
78 | |
79 TEST_F(TestScaler, ScaleWithoutSettingValues) { | |
80 EXPECT_EQ(-2, test_scaler_.Scale(test_frame_, &test_frame_)); | |
81 } | |
82 | |
83 TEST_F(TestScaler, ScaleBadInitialValues) { | |
84 EXPECT_EQ(-1, test_scaler_.Set(0, 288, 352, 288, kI420, kI420, kScalePoint)); | |
85 EXPECT_EQ(-1, test_scaler_.Set(704, 0, 352, 288, kI420, kI420, kScaleBox)); | |
86 EXPECT_EQ(-1, test_scaler_.Set(704, 576, 352, 0, kI420, kI420, | |
87 kScaleBilinear)); | |
88 EXPECT_EQ(-1, test_scaler_.Set(704, 576, 0, 288, kI420, kI420, kScalePoint)); | |
89 } | |
90 | |
91 TEST_F(TestScaler, ScaleSendingNullSourcePointer) { | |
92 VideoFrame null_src_frame; | |
93 EXPECT_EQ(-1, test_scaler_.Scale(null_src_frame, &test_frame_)); | |
94 } | |
95 | |
96 TEST_F(TestScaler, ScaleSendingBufferTooSmall) { | |
97 // Sending a buffer which is too small (should reallocate and update size) | |
98 EXPECT_EQ(0, test_scaler_.Set(width_, height_, | |
99 half_width_, half_height_, | |
100 kI420, kI420, | |
101 kScalePoint)); | |
102 VideoFrame test_frame2; | |
103 std::unique_ptr<uint8_t[]> orig_buffer(new uint8_t[frame_length_]); | |
104 EXPECT_GT(fread(orig_buffer.get(), 1, frame_length_, source_file_), 0U); | |
105 test_frame_.CreateFrame(orig_buffer.get(), | |
106 orig_buffer.get() + size_y_, | |
107 orig_buffer.get() + size_y_ + size_uv_, | |
108 width_, height_, | |
109 width_, half_width_, half_width_, | |
110 kVideoRotation_0); | |
111 EXPECT_EQ(0, test_scaler_.Scale(test_frame_, &test_frame2)); | |
112 EXPECT_GT(width_ * height_, test_frame2.allocated_size(kYPlane)); | |
113 EXPECT_GT(size_uv_, test_frame2.allocated_size(kUPlane)); | |
114 EXPECT_GT(size_uv_, test_frame2.allocated_size(kVPlane)); | |
115 EXPECT_EQ(half_width_, test_frame2.width()); | |
116 EXPECT_EQ(half_height_, test_frame2.height()); | |
117 } | |
118 | |
119 // TODO(mikhal): Converge the test into one function that accepts the method. | |
120 #if defined(WEBRTC_ANDROID) | |
121 #define MAYBE_PointScaleTest DISABLED_PointScaleTest | |
122 #else | |
123 #define MAYBE_PointScaleTest PointScaleTest | |
124 #endif | |
125 TEST_F(TestScaler, MAYBE_PointScaleTest) { | |
126 double avg_psnr; | |
127 FILE* source_file2; | |
128 ScaleMethod method = kScalePoint; | |
129 std::string out_name = webrtc::test::OutputPath() + | |
130 "LibYuvTest_PointScale_176_144.yuv"; | |
131 ScaleSequence(method, | |
132 source_file_, out_name, | |
133 width_, height_, | |
134 half_width_, half_height_); | |
135 // Upsample back up and check PSNR. | |
136 source_file2 = fopen(out_name.c_str(), "rb"); | |
137 out_name = webrtc::test::OutputPath() + "LibYuvTest_PointScale_352_288_" | |
138 "upfrom_176_144.yuv"; | |
139 ScaleSequence(method, | |
140 source_file2, out_name, | |
141 176, 144, | |
142 352, 288); | |
143 avg_psnr = ComputeAvgSequencePSNR(source_file_, out_name, width_, height_); | |
144 printf("PSNR for scaling from: %d %d, down/up to: %d %d, and back to " | |
145 "original size: %f \n", width_, height_, 176, 144, avg_psnr); | |
146 // Average PSNR for lower bound in assert is ~0.1dB lower than the actual | |
147 // average PSNR under same conditions. | |
148 ASSERT_GT(avg_psnr, 27.9); | |
149 ASSERT_EQ(0, fclose(source_file2)); | |
150 out_name = webrtc::test::OutputPath() + "LibYuvTest_PointScale_320_240.yuv"; | |
151 ScaleSequence(method, | |
152 source_file_, out_name, | |
153 width_, height_, | |
154 320, 240); | |
155 out_name = webrtc::test::OutputPath() + "LibYuvTest_PointScale_704_576.yuv"; | |
156 ScaleSequence(method, | |
157 source_file_, out_name, | |
158 width_, height_, | |
159 width_ * 2, height_ * 2); | |
160 out_name = webrtc::test::OutputPath() + "LibYuvTest_PointScale_300_200.yuv"; | |
161 ScaleSequence(method, | |
162 source_file_, out_name, | |
163 width_, height_, | |
164 300, 200); | |
165 out_name = webrtc::test::OutputPath() + "LibYuvTest_PointScale_400_300.yuv"; | |
166 ScaleSequence(method, | |
167 source_file_, out_name, | |
168 width_, height_, | |
169 400, 300); | |
170 // Down-sample to odd size frame and scale back up. | |
171 out_name = webrtc::test::OutputPath() + "LibYuvTest_PointScale_282_231.yuv"; | |
172 ScaleSequence(method, | |
173 source_file_, out_name, | |
174 width_, height_, | |
175 282, 231); | |
176 source_file2 = fopen(out_name.c_str(), "rb"); | |
177 out_name = webrtc::test::OutputPath() + "LibYuvTest_PointScale_352_288_" | |
178 "upfrom_282_231.yuv"; | |
179 ScaleSequence(method, | |
180 source_file2, out_name, | |
181 282, 231, | |
182 352, 288); | |
183 avg_psnr = ComputeAvgSequencePSNR(source_file_, out_name, width_, height_); | |
184 printf("PSNR for scaling from: %d %d, down/up to: %d %d, and back to " | |
185 "original size: %f \n", width_, height_, 282, 231, avg_psnr); | |
186 // Average PSNR for lower bound in assert is ~0.1dB lower than the actual | |
187 // average PSNR under same conditions. | |
188 ASSERT_GT(avg_psnr, 25.8); | |
189 ASSERT_EQ(0, fclose(source_file2)); | |
190 } | |
191 | |
192 #if defined(WEBRTC_ANDROID) | |
193 #define MAYBE_BilinearScaleTest DISABLED_BiLinearScaleTest | |
194 #else | |
195 #define MAYBE_BilinearScaleTest BiLinearScaleTest | |
196 #endif | |
197 TEST_F(TestScaler, MAYBE_BiLinearScaleTest) { | |
198 double avg_psnr; | |
199 FILE* source_file2; | |
200 ScaleMethod method = kScaleBilinear; | |
201 std::string out_name = webrtc::test::OutputPath() + | |
202 "LibYuvTest_BilinearScale_176_144.yuv"; | |
203 ScaleSequence(method, | |
204 source_file_, out_name, | |
205 width_, height_, | |
206 width_ / 2, height_ / 2); | |
207 // Up-sample back up and check PSNR. | |
208 source_file2 = fopen(out_name.c_str(), "rb"); | |
209 out_name = webrtc::test::OutputPath() + "LibYuvTest_BilinearScale_352_288_" | |
210 "upfrom_176_144.yuv"; | |
211 ScaleSequence(method, | |
212 source_file2, out_name, | |
213 176, 144, | |
214 352, 288); | |
215 avg_psnr = ComputeAvgSequencePSNR(source_file_, out_name, width_, height_); | |
216 printf("PSNR for scaling from: %d %d, down/up to: %d %d, and back to " | |
217 "original size: %f \n", width_, height_, 176, 144, avg_psnr); | |
218 // Average PSNR for lower bound in assert is ~0.1dB lower than the actual | |
219 // average PSNR under same conditions. | |
220 ASSERT_GT(avg_psnr, 27.5); | |
221 ComputeAvgSequencePSNR(source_file_, out_name, width_, height_); | |
222 ASSERT_EQ(0, fclose(source_file2)); | |
223 out_name = webrtc::test::OutputPath() + | |
224 "LibYuvTest_BilinearScale_320_240.yuv"; | |
225 ScaleSequence(method, | |
226 source_file_, out_name, | |
227 width_, height_, | |
228 320, 240); | |
229 out_name = webrtc::test::OutputPath() + | |
230 "LibYuvTest_BilinearScale_704_576.yuv"; | |
231 ScaleSequence(method, | |
232 source_file_, out_name, | |
233 width_, height_, | |
234 width_ * 2, height_ * 2); | |
235 out_name = webrtc::test::OutputPath() + | |
236 "LibYuvTest_BilinearScale_300_200.yuv"; | |
237 ScaleSequence(method, | |
238 source_file_, out_name, | |
239 width_, height_, | |
240 300, 200); | |
241 out_name = webrtc::test::OutputPath() + | |
242 "LibYuvTest_BilinearScale_400_300.yuv"; | |
243 ScaleSequence(method, | |
244 source_file_, out_name, | |
245 width_, height_, | |
246 400, 300); | |
247 } | |
248 | |
249 #if defined(WEBRTC_ANDROID) | |
250 #define MAYBE_BoxScaleTest DISABLED_BoxScaleTest | |
251 #else | |
252 #define MAYBE_BoxScaleTest BoxScaleTest | |
253 #endif | |
254 TEST_F(TestScaler, MAYBE_BoxScaleTest) { | |
255 double avg_psnr; | |
256 FILE* source_file2; | |
257 ScaleMethod method = kScaleBox; | |
258 std::string out_name = webrtc::test::OutputPath() + | |
259 "LibYuvTest_BoxScale_176_144.yuv"; | |
260 ScaleSequence(method, | |
261 source_file_, out_name, | |
262 width_, height_, | |
263 width_ / 2, height_ / 2); | |
264 // Up-sample back up and check PSNR. | |
265 source_file2 = fopen(out_name.c_str(), "rb"); | |
266 out_name = webrtc::test::OutputPath() + "LibYuvTest_BoxScale_352_288_" | |
267 "upfrom_176_144.yuv"; | |
268 ScaleSequence(method, | |
269 source_file2, out_name, | |
270 176, 144, | |
271 352, 288); | |
272 avg_psnr = ComputeAvgSequencePSNR(source_file_, out_name, width_, height_); | |
273 printf("PSNR for scaling from: %d %d, down/up to: %d %d, and back to " | |
274 "original size: %f \n", width_, height_, 176, 144, avg_psnr); | |
275 // Average PSNR for lower bound in assert is ~0.1dB lower than the actual | |
276 // average PSNR under same conditions. | |
277 ASSERT_GT(avg_psnr, 27.5); | |
278 ASSERT_EQ(0, fclose(source_file2)); | |
279 out_name = webrtc::test::OutputPath() + "LibYuvTest_BoxScale_320_240.yuv"; | |
280 ScaleSequence(method, | |
281 source_file_, out_name, | |
282 width_, height_, | |
283 320, 240); | |
284 out_name = webrtc::test::OutputPath() + "LibYuvTest_BoxScale_704_576.yuv"; | |
285 ScaleSequence(method, | |
286 source_file_, out_name, | |
287 width_, height_, | |
288 width_ * 2, height_ * 2); | |
289 out_name = webrtc::test::OutputPath() + "LibYuvTest_BoxScale_300_200.yuv"; | |
290 ScaleSequence(method, | |
291 source_file_, out_name, | |
292 width_, height_, | |
293 300, 200); | |
294 out_name = webrtc::test::OutputPath() + "LibYuvTest_BoxScale_400_300.yuv"; | |
295 ScaleSequence(method, | |
296 source_file_, out_name, | |
297 width_, height_, | |
298 400, 300); | |
299 } | |
300 | |
301 double TestScaler::ComputeAvgSequencePSNR(FILE* input_file, | |
302 std::string out_name, | |
303 int width, int height) { | |
304 FILE* output_file; | |
305 output_file = fopen(out_name.c_str(), "rb"); | |
306 assert(output_file != NULL); | |
307 rewind(input_file); | |
308 rewind(output_file); | |
309 | |
310 size_t required_size = CalcBufferSize(kI420, width, height); | |
311 uint8_t* input_buffer = new uint8_t[required_size]; | |
312 uint8_t* output_buffer = new uint8_t[required_size]; | |
313 | |
314 int frame_count = 0; | |
315 double avg_psnr = 0; | |
316 VideoFrame in_frame, out_frame; | |
317 const int half_width = (width + 1) / 2; | |
318 in_frame.CreateEmptyFrame(width, height, width, half_width, half_width); | |
319 out_frame.CreateEmptyFrame(width, height, width, half_width, half_width); | |
320 while (feof(input_file) == 0) { | |
321 if (fread(input_buffer, 1, required_size, input_file) != required_size) { | |
322 break; | |
323 } | |
324 if (fread(output_buffer, 1, required_size, output_file) != required_size) { | |
325 break; | |
326 } | |
327 frame_count++; | |
328 EXPECT_EQ(0, ConvertToI420(kI420, input_buffer, 0, 0, width, height, | |
329 required_size, kVideoRotation_0, &in_frame)); | |
330 EXPECT_EQ(0, ConvertToI420(kI420, output_buffer, 0, 0, width, height, | |
331 required_size, kVideoRotation_0, &out_frame)); | |
332 double psnr = I420PSNR(&in_frame, &out_frame); | |
333 avg_psnr += psnr; | |
334 } | |
335 avg_psnr = avg_psnr / frame_count; | |
336 assert(0 == fclose(output_file)); | |
337 delete [] input_buffer; | |
338 delete [] output_buffer; | |
339 return avg_psnr; | |
340 } | |
341 | |
342 // TODO(mikhal): Move part to a separate scale test. | |
343 void TestScaler::ScaleSequence(ScaleMethod method, | |
344 FILE* source_file, std::string out_name, | |
345 int src_width, int src_height, | |
346 int dst_width, int dst_height) { | |
347 FILE* output_file; | |
348 EXPECT_EQ(0, test_scaler_.Set(src_width, src_height, | |
349 dst_width, dst_height, | |
350 kI420, kI420, method)); | |
351 | |
352 output_file = fopen(out_name.c_str(), "wb"); | |
353 ASSERT_TRUE(output_file != NULL); | |
354 | |
355 rewind(source_file); | |
356 | |
357 VideoFrame input_frame; | |
358 VideoFrame output_frame; | |
359 int64_t start_clock, total_clock; | |
360 total_clock = 0; | |
361 int frame_count = 0; | |
362 size_t src_required_size = CalcBufferSize(kI420, src_width, src_height); | |
363 std::unique_ptr<uint8_t[]> frame_buffer(new uint8_t[src_required_size]); | |
364 int size_y = src_width * src_height; | |
365 int size_uv = ((src_width + 1) / 2) * ((src_height + 1) / 2); | |
366 | |
367 // Running through entire sequence. | |
368 while (feof(source_file) == 0) { | |
369 if (fread(frame_buffer.get(), 1, src_required_size, source_file) != | |
370 src_required_size) | |
371 break; | |
372 | |
373 input_frame.CreateFrame(frame_buffer.get(), | |
374 frame_buffer.get() + size_y, | |
375 frame_buffer.get() + size_y + size_uv, | |
376 src_width, src_height, | |
377 src_width, (src_width + 1) / 2, | |
378 (src_width + 1) / 2, | |
379 kVideoRotation_0); | |
380 | |
381 start_clock = rtc::TimeMillis(); | |
382 EXPECT_EQ(0, test_scaler_.Scale(input_frame, &output_frame)); | |
383 total_clock += rtc::TimeMillis() - start_clock; | |
384 if (PrintVideoFrame(output_frame, output_file) < 0) { | |
385 return; | |
386 } | |
387 frame_count++; | |
388 } | |
389 | |
390 if (frame_count) { | |
391 printf("Scaling[%d %d] => [%d %d]: ", | |
392 src_width, src_height, dst_width, dst_height); | |
393 printf("Average time per frame[ms]: %.2lf\n", | |
394 (static_cast<double>(total_clock) / frame_count)); | |
395 } | |
396 ASSERT_EQ(0, fclose(output_file)); | |
397 } | |
398 | |
399 } // namespace webrtc | |
OLD | NEW |