Index: webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.h |
diff --git a/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.h b/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.h |
index e1c085ed436e39d0cf5a798fd50f2397a15f7fe0..ea0749057a04ec07e3ad33464092d5cce00108d4 100644 |
--- a/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.h |
+++ b/webrtc/modules/video_coding/codecs/test/videoprocessor_integrationtest.h |
@@ -15,6 +15,7 @@ |
#include <memory> |
#include <string> |
+#include <utility> |
#if defined(WEBRTC_ANDROID) |
#include "webrtc/modules/video_coding/codecs/test/android_test_initializer.h" |
@@ -26,6 +27,7 @@ |
#endif |
#include "webrtc/base/checks.h" |
+#include "webrtc/base/file.h" |
#include "webrtc/media/engine/webrtcvideodecoderfactory.h" |
#include "webrtc/media/engine/webrtcvideoencoderfactory.h" |
#include "webrtc/modules/video_coding/codecs/h264/include/h264.h" |
@@ -33,10 +35,10 @@ |
#include "webrtc/modules/video_coding/codecs/test/videoprocessor.h" |
#include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h" |
#include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h" |
-#include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h" |
#include "webrtc/modules/video_coding/codecs/vp9/include/vp9.h" |
#include "webrtc/modules/video_coding/include/video_codec_interface.h" |
#include "webrtc/modules/video_coding/include/video_coding.h" |
+#include "webrtc/modules/video_coding/utility/ivf_file_writer.h" |
#include "webrtc/test/gtest.h" |
#include "webrtc/test/testsupport/fileutils.h" |
#include "webrtc/test/testsupport/frame_reader.h" |
@@ -109,6 +111,13 @@ struct RateControlMetrics { |
int num_key_frames; |
}; |
+// Should video files be saved persistently to disk for post-run visualization? |
+struct VisualizationParams { |
+ bool save_source_y4m; |
+ bool save_encoded_ivf; |
+ bool save_decoded_y4m; |
+}; |
+ |
#if !defined(WEBRTC_IOS) |
const int kNumFramesShort = 100; |
#endif |
@@ -145,7 +154,8 @@ class VideoProcessorIntegrationTest : public testing::Test { |
void SetUpCodecConfig(const std::string& filename, |
int width, |
int height, |
- bool verbose_logging) { |
+ bool verbose_logging, |
+ const VisualizationParams* visualization_params) { |
if (hw_codec_) { |
#if defined(WEBRTC_VIDEOPROCESSOR_INTEGRATIONTEST_HW_CODECS_ENABLED) |
#if defined(WEBRTC_ANDROID) |
@@ -248,19 +258,54 @@ class VideoProcessorIntegrationTest : public testing::Test { |
RTC_NOTREACHED(); |
break; |
} |
- frame_reader_.reset(new test::FrameReaderImpl( |
+ |
+ // Create file objects for quality analysis. |
+ analysis_frame_reader_.reset(new test::YuvFrameReaderImpl( |
config_.input_filename, config_.codec_settings->width, |
config_.codec_settings->height)); |
- frame_writer_.reset(new test::FrameWriterImpl( |
- config_.output_filename, config_.frame_length_in_bytes)); |
- RTC_CHECK(frame_reader_->Init()); |
- RTC_CHECK(frame_writer_->Init()); |
+ analysis_frame_writer_.reset(new test::YuvFrameWriterImpl( |
+ config_.output_filename, config_.codec_settings->width, |
+ config_.codec_settings->height)); |
+ RTC_CHECK(analysis_frame_reader_->Init()); |
+ RTC_CHECK(analysis_frame_writer_->Init()); |
+ |
+ if (visualization_params) { |
+ // clang-format off |
+ const std::string output_filename_base = |
+ test::OutputPath() + filename + |
+ "_cd-" + CodecTypeToPayloadName(codec_type_).value_or("") + |
+ "_hw-" + std::to_string(hw_codec_) + |
+ "_fr-" + std::to_string(start_frame_rate_) + |
+ "_br-" + std::to_string(static_cast<int>(start_bitrate_)); |
+ // clang-format on |
+ if (visualization_params->save_source_y4m) { |
+ source_frame_writer_.reset(new test::Y4mFrameWriterImpl( |
+ output_filename_base + "_source.y4m", config_.codec_settings->width, |
+ config_.codec_settings->height, start_frame_rate_)); |
+ RTC_CHECK(source_frame_writer_->Init()); |
+ } |
+ if (visualization_params->save_encoded_ivf) { |
+ rtc::File post_encode_file = |
+ rtc::File::Create(output_filename_base + "_encoded.ivf"); |
+ encoded_frame_writer_ = |
+ IvfFileWriter::Wrap(std::move(post_encode_file), 0); |
+ } |
+ if (visualization_params->save_decoded_y4m) { |
+ decoded_frame_writer_.reset(new test::Y4mFrameWriterImpl( |
+ output_filename_base + "_decoded.y4m", |
+ config_.codec_settings->width, config_.codec_settings->height, |
+ start_frame_rate_)); |
+ RTC_CHECK(decoded_frame_writer_->Init()); |
+ } |
+ } |
packet_manipulator_.reset(new test::PacketManipulatorImpl( |
&packet_reader_, config_.networking_config, config_.verbose)); |
processor_.reset(new test::VideoProcessorImpl( |
- encoder_.get(), decoder_.get(), frame_reader_.get(), |
- frame_writer_.get(), packet_manipulator_.get(), config_, &stats_)); |
+ encoder_.get(), decoder_.get(), analysis_frame_reader_.get(), |
+ analysis_frame_writer_.get(), packet_manipulator_.get(), config_, |
+ &stats_, source_frame_writer_.get(), encoded_frame_writer_.get(), |
+ decoded_frame_writer_.get())); |
RTC_CHECK(processor_->Init()); |
} |
@@ -446,11 +491,13 @@ class VideoProcessorIntegrationTest : public testing::Test { |
void ProcessFramesAndVerify(QualityMetrics quality_metrics, |
RateProfile rate_profile, |
CodecConfigPars process, |
- RateControlMetrics* rc_metrics) { |
+ RateControlMetrics* rc_metrics, |
+ const VisualizationParams* visualization_params) { |
// Codec/config settings. |
codec_type_ = process.codec_type; |
hw_codec_ = process.hw_codec; |
start_bitrate_ = rate_profile.target_bit_rate[0]; |
+ start_frame_rate_ = rate_profile.input_frame_rate[0]; |
packet_loss_ = process.packet_loss; |
key_frame_interval_ = process.key_frame_interval; |
num_temporal_layers_ = process.num_temporal_layers; |
@@ -459,7 +506,8 @@ class VideoProcessorIntegrationTest : public testing::Test { |
frame_dropper_on_ = process.frame_dropper_on; |
spatial_resize_on_ = process.spatial_resize_on; |
SetUpCodecConfig(process.filename, process.width, process.height, |
- process.verbose_logging); |
+ process.verbose_logging, visualization_params); |
+ |
// Update the layers and the codec with the initial rates. |
bit_rate_ = rate_profile.target_bit_rate[0]; |
frame_rate_ = rate_profile.input_frame_rate[0]; |
@@ -522,20 +570,31 @@ class VideoProcessorIntegrationTest : public testing::Test { |
EXPECT_EQ(num_frames + 1, 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()); |
+ RTC_DCHECK_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Release()); |
+ RTC_DCHECK_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->Release()); |
+ |
+ // Close the analysis files before we use them for SSIM/PSNR calculations. |
+ analysis_frame_reader_->Close(); |
+ analysis_frame_writer_->Close(); |
- // Close the files before we start using them for SSIM/PSNR calculations. |
- frame_reader_->Close(); |
- frame_writer_->Close(); |
+ // Close visualization files. |
+ if (source_frame_writer_) { |
+ source_frame_writer_->Close(); |
+ } |
+ if (encoded_frame_writer_) { |
+ encoded_frame_writer_->Close(); |
+ } |
+ if (decoded_frame_writer_) { |
+ decoded_frame_writer_->Close(); |
+ } |
- // TODO(marpan): should compute these quality metrics per SetRates update. |
+ // TODO(marpan): Should compute these quality metrics per SetRates update. |
test::QualityMetricsResult psnr_result, ssim_result; |
- EXPECT_EQ(0, test::I420MetricsFromFiles(config_.input_filename.c_str(), |
- config_.output_filename.c_str(), |
- config_.codec_settings->width, |
- config_.codec_settings->height, |
- &psnr_result, &ssim_result)); |
+ RTC_DCHECK_EQ(0, 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\nSSIM avg: %f, min: %f\n", |
psnr_result.average, psnr_result.min, ssim_result.average, |
ssim_result.min); |
@@ -544,22 +603,13 @@ class VideoProcessorIntegrationTest : public testing::Test { |
EXPECT_GT(psnr_result.min, quality_metrics.minimum_min_psnr); |
EXPECT_GT(ssim_result.average, quality_metrics.minimum_avg_ssim); |
EXPECT_GT(ssim_result.min, quality_metrics.minimum_min_ssim); |
+ |
+ // Remove analysis file. |
if (remove(config_.output_filename.c_str()) < 0) { |
fprintf(stderr, "Failed to remove temporary file!\n"); |
} |
} |
- static void SetRateProfilePars(RateProfile* rate_profile, |
- int update_index, |
- int bit_rate, |
- int frame_rate, |
- int frame_index_rate_update) { |
- rate_profile->target_bit_rate[update_index] = bit_rate; |
- rate_profile->input_frame_rate[update_index] = frame_rate; |
- rate_profile->frame_index_rate_update[update_index] = |
- frame_index_rate_update; |
- } |
- |
static void SetCodecParameters(CodecConfigPars* process_settings, |
VideoCodecType codec_type, |
bool hw_codec, |
@@ -617,6 +667,17 @@ class VideoProcessorIntegrationTest : public testing::Test { |
quality_metrics->minimum_min_ssim = minimum_min_ssim; |
} |
+ static void SetRateProfilePars(RateProfile* rate_profile, |
+ int update_index, |
+ int bit_rate, |
+ int frame_rate, |
+ int frame_index_rate_update) { |
+ rate_profile->target_bit_rate[update_index] = bit_rate; |
+ rate_profile->input_frame_rate[update_index] = frame_rate; |
+ rate_profile->frame_index_rate_update[update_index] = |
+ frame_index_rate_update; |
+ } |
+ |
static void SetRateControlMetrics(RateControlMetrics* rc_metrics, |
int update_index, |
int max_num_dropped_frames, |
@@ -638,20 +699,27 @@ class VideoProcessorIntegrationTest : public testing::Test { |
rc_metrics[update_index].num_key_frames = num_key_frames; |
} |
+ // Codecs. |
std::unique_ptr<VideoEncoder> encoder_; |
std::unique_ptr<cricket::WebRtcVideoEncoderFactory> external_encoder_factory_; |
std::unique_ptr<VideoDecoder> decoder_; |
std::unique_ptr<cricket::WebRtcVideoDecoderFactory> external_decoder_factory_; |
- std::unique_ptr<test::FrameReader> frame_reader_; |
- std::unique_ptr<test::FrameWriter> frame_writer_; |
+ VideoCodec codec_settings_; |
+ |
+ // Helper objects. |
+ std::unique_ptr<test::FrameReader> analysis_frame_reader_; |
+ std::unique_ptr<test::FrameWriter> analysis_frame_writer_; |
test::PacketReader packet_reader_; |
std::unique_ptr<test::PacketManipulator> packet_manipulator_; |
test::Stats stats_; |
test::TestConfig config_; |
- VideoCodec codec_settings_; |
// Must be destroyed before |encoder_| and |decoder_|. |
std::unique_ptr<test::VideoProcessor> processor_; |
- TemporalLayersFactory tl_factory_; |
+ |
+ // Visualization objects. |
+ std::unique_ptr<test::FrameWriter> source_frame_writer_; |
+ std::unique_ptr<IvfFileWriter> encoded_frame_writer_; |
+ std::unique_ptr<test::FrameWriter> decoded_frame_writer_; |
// Quantities defined/updated for every encoder rate update. |
// Some quantities defined per temporal layer (at most 3 layers in this test). |
@@ -676,6 +744,7 @@ class VideoProcessorIntegrationTest : public testing::Test { |
float sum_key_frame_size_mismatch_; |
int num_key_frames_; |
float start_bitrate_; |
+ int start_frame_rate_; |
// Codec and network settings. |
VideoCodecType codec_type_; |