| /* |
| * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "gtest/gtest.h" |
| #include "modules/video_coding/codecs/interface/video_codec_interface.h" |
| #include "modules/video_coding/codecs/test/packet_manipulator.h" |
| #include "modules/video_coding/codecs/test/videoprocessor.h" |
| #include "modules/video_coding/codecs/vp8/main/interface/vp8.h" |
| #include "modules/video_coding/main/interface/video_coding.h" |
| #include "testsupport/fileutils.h" |
| #include "testsupport/frame_reader.h" |
| #include "testsupport/frame_writer.h" |
| #include "testsupport/metrics/video_metrics.h" |
| #include "testsupport/packet_reader.h" |
| #include "typedefs.h" |
| |
| namespace webrtc { |
| |
| const int kNbrFrames = 61; // foreman_cif_short.yuv |
| const int kCIFWidth = 352; |
| const int kCIFHeight = 288; |
| const int kBitRateKbps = 500; |
| |
| // Integration test for video processor. Encodes+decodes a small clip and |
| // writes it to the output directory. After completion, PSNR and SSIM |
| // measurements are performed on the original and the processed clip to verify |
| // the quality is acceptable. |
| // The limits for the PSNR and SSIM values must be set quite low, since we have |
| // no control over the random function used for packet loss in this test. |
| class VideoProcessorIntegrationTest: public testing::Test { |
| protected: |
| VideoEncoder* encoder_; |
| VideoDecoder* decoder_; |
| webrtc::test::FrameReader* frame_reader_; |
| webrtc::test::FrameWriter* frame_writer_; |
| webrtc::test::PacketReader packet_reader_; |
| webrtc::test::PacketManipulator* packet_manipulator_; |
| webrtc::test::Stats stats_; |
| webrtc::test::TestConfig config_; |
| VideoCodec codec_settings_; |
| webrtc::test::VideoProcessor* processor_; |
| |
| VideoProcessorIntegrationTest() {} |
| virtual ~VideoProcessorIntegrationTest() {} |
| |
| void SetUp() { |
| encoder_ = VP8Encoder::Create(); |
| decoder_ = VP8Decoder::Create(); |
| |
| // Setup the TestConfig struct for processing of a clip in CIF resolution. |
| config_.input_filename = |
| webrtc::test::ResourcePath("foreman_cif_short", "yuv"); |
| config_.output_filename = webrtc::test::OutputPath() + |
| "foreman_cif_short_video_codecs_test_framework_integrationtests.yuv"; |
| config_.frame_length_in_bytes = 3 * kCIFWidth * kCIFHeight / 2; |
| config_.verbose = false; |
| // Only allow encoder/decoder to use single core, for predictability. |
| config_.use_single_core = true; |
| |
| // Get a codec configuration struct and configure it. |
| VideoCodingModule::Codec(kVideoCodecVP8, &codec_settings_); |
| config_.codec_settings = &codec_settings_; |
| config_.codec_settings->startBitrate = kBitRateKbps; |
| config_.codec_settings->width = kCIFWidth; |
| config_.codec_settings->height = kCIFHeight; |
| |
| frame_reader_ = |
| new webrtc::test::FrameReaderImpl(config_.input_filename, |
| config_.frame_length_in_bytes); |
| frame_writer_ = |
| new webrtc::test::FrameWriterImpl(config_.output_filename, |
| config_.frame_length_in_bytes); |
| ASSERT_TRUE(frame_reader_->Init()); |
| ASSERT_TRUE(frame_writer_->Init()); |
| |
| packet_manipulator_ = new webrtc::test::PacketManipulatorImpl( |
| &packet_reader_, config_.networking_config, config_.verbose); |
| processor_ = new webrtc::test::VideoProcessorImpl(encoder_, decoder_, |
| frame_reader_, |
| frame_writer_, |
| packet_manipulator_, |
| config_, &stats_); |
| ASSERT_TRUE(processor_->Init()); |
| } |
| |
| void TearDown() { |
| delete processor_; |
| delete packet_manipulator_; |
| delete frame_writer_; |
| delete frame_reader_; |
| delete decoder_; |
| delete encoder_; |
| } |
| |
| // Processes all frames in the clip and verifies the result. |
| void ProcessFramesAndVerify(double minimum_avg_psnr, |
| double minimum_min_psnr, |
| double minimum_avg_ssim, |
| double minimum_min_ssim) { |
| int frame_number = 0; |
| while (processor_->ProcessFrame(frame_number)) { |
| frame_number++; |
| } |
| EXPECT_EQ(kNbrFrames, frame_number); |
| EXPECT_EQ(kNbrFrames, static_cast<int>(stats_.stats_.size())); |
| |
| // Release encoder and decoder to make sure they have finished processing: |
| EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Release()); |
| EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->Release()); |
| // Close the files before we start using them for SSIM/PSNR calculations. |
| frame_reader_->Close(); |
| frame_writer_->Close(); |
| |
| webrtc::test::QualityMetricsResult psnr_result, ssim_result; |
| EXPECT_EQ(0, webrtc::test::I420MetricsFromFiles( |
| config_.input_filename.c_str(), |
| config_.output_filename.c_str(), |
| config_.codec_settings->width, |
| config_.codec_settings->height, |
| &psnr_result, |
| &ssim_result)); |
| printf("PSNR avg: %f, min: %f SSIM avg: %f, min: %f\n", |
| psnr_result.average, psnr_result.min, |
| ssim_result.average, ssim_result.min); |
| EXPECT_GT(psnr_result.average, minimum_avg_psnr); |
| EXPECT_GT(psnr_result.min, minimum_min_psnr); |
| EXPECT_GT(ssim_result.average, minimum_avg_ssim); |
| EXPECT_GT(ssim_result.min, minimum_min_ssim); |
| } |
| }; |
| |
| // Run with no packet loss. Quality should be very high. |
| TEST_F(VideoProcessorIntegrationTest, ProcessZeroPacketLoss) { |
| config_.networking_config.packet_loss_probability = 0; |
| double minimum_avg_psnr = 36; |
| double minimum_min_psnr = 34; |
| double minimum_avg_ssim = 0.9; |
| double minimum_min_ssim = 0.9; |
| ProcessFramesAndVerify(minimum_avg_psnr, minimum_min_psnr, |
| minimum_avg_ssim, minimum_min_ssim); |
| } |
| |
| // Run with 5% packet loss. Quality should be a bit lower. |
| // TODO(mflodman): Reenable this once it's not flaky. |
| TEST_F(VideoProcessorIntegrationTest, Process5PercentPacketLoss) { |
| config_.networking_config.packet_loss_probability = 0.05; |
| double minimum_avg_psnr = 21; |
| double minimum_min_psnr = 17; |
| double minimum_avg_ssim = 0.6; |
| double minimum_min_ssim = 0.4; |
| ProcessFramesAndVerify(minimum_avg_psnr, minimum_min_psnr, |
| minimum_avg_ssim, minimum_min_ssim); |
| } |
| |
| // Run with 10% packet loss. Quality should be even lower. |
| TEST_F(VideoProcessorIntegrationTest, Process10PercentPacketLoss) { |
| config_.networking_config.packet_loss_probability = 0.10; |
| double minimum_avg_psnr = 19; |
| double minimum_min_psnr = 16; |
| double minimum_avg_ssim = 0.6; |
| double minimum_min_ssim = 0.4; |
| ProcessFramesAndVerify(minimum_avg_psnr, minimum_min_psnr, |
| minimum_avg_ssim, minimum_min_ssim); |
| } |
| |
| } // namespace webrtc |