| 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 |