From 72bc2e24cc1f9694b87bbaef845605d8c6992195 Mon Sep 17 00:00:00 2001 From: Artem Titov Date: Tue, 2 Aug 2022 14:03:03 +0200 Subject: [PATCH] [PCLF] Introduce VideoDumpOptions API to better control video dumping This CL propose a new API for video dumps in PCLF also removing differences between p2p and multipeer usage of API. Bug: b/240540206 Change-Id: Id4d32cc98250500949b3f9e2cf2e86c4bdce7efb Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/270400 Commit-Queue: Artem Titov Reviewed-by: Mirko Bonadei Cr-Commit-Position: refs/heads/main@{#37665} --- api/BUILD.gn | 1 + .../peerconnection_quality_test_fixture.cc | 25 +++++++ .../peerconnection_quality_test_fixture.h | 66 +++++++++++++++---- ...video_quality_analyzer_injection_helper.cc | 56 +++++++++++----- 4 files changed, 119 insertions(+), 29 deletions(-) diff --git a/api/BUILD.gn b/api/BUILD.gn index 9b7301002d..5300a6a128 100644 --- a/api/BUILD.gn +++ b/api/BUILD.gn @@ -530,6 +530,7 @@ rtc_source_set("peer_connection_quality_test_fixture_api") { "../rtc_base:rtc_base", "../rtc_base:stringutils", "../rtc_base:threading", + "../test:fileutils", "audio:audio_mixer_api", "rtc_event_log", "task_queue", diff --git a/api/test/peerconnection_quality_test_fixture.cc b/api/test/peerconnection_quality_test_fixture.cc index 11da060fb4..78fe0dbefc 100644 --- a/api/test/peerconnection_quality_test_fixture.cc +++ b/api/test/peerconnection_quality_test_fixture.cc @@ -16,6 +16,7 @@ #include "api/array_view.h" #include "rtc_base/checks.h" #include "rtc_base/strings/string_builder.h" +#include "test/testsupport/file_utils.h" namespace webrtc { namespace webrtc_pc_e2e { @@ -122,6 +123,30 @@ std::string PeerConnectionE2EQualityTestFixture::VideoSubscription::ToString() return out.Release(); } +PeerConnectionE2EQualityTestFixture::VideoDumpOptions::VideoDumpOptions( + absl::string_view output_directory, + int sampling_modulo) + : output_directory_(output_directory), sampling_modulo_(sampling_modulo) { + RTC_CHECK_GT(sampling_modulo, 0); +} + +std::string +PeerConnectionE2EQualityTestFixture::VideoDumpOptions::GetInputDumpFileName( + absl::string_view stream_label) const { + rtc::StringBuilder file_name; + file_name << stream_label << ".y4m"; + return test::JoinFilename(output_directory_, file_name.Release()); +} + +std::string +PeerConnectionE2EQualityTestFixture::VideoDumpOptions::GetOutputDumpFileName( + absl::string_view stream_label, + absl::string_view receiver) const { + rtc::StringBuilder file_name; + file_name << stream_label << "_" << receiver << ".y4m"; + return test::JoinFilename(output_directory_, file_name.Release()); +} + PeerConnectionE2EQualityTestFixture::VideoConfig::VideoConfig( const VideoResolution& resolution) : width(resolution.width()), diff --git a/api/test/peerconnection_quality_test_fixture.h b/api/test/peerconnection_quality_test_fixture.h index 7f39ba8292..fb34affbf4 100644 --- a/api/test/peerconnection_quality_test_fixture.h +++ b/api/test/peerconnection_quality_test_fixture.h @@ -217,6 +217,36 @@ class PeerConnectionE2EQualityTestFixture { Spec spec_ = Spec::kNone; }; + class VideoDumpOptions { + public: + // output_directory - the output directory where stream will be dumped. The + // output files' names will be constructed as + // _. for output dumps and + // . for input dumps. By default is + // "y4m". + // sampling_modulo - the module for the video frames to be dumped. Modulo + // equals X means every Xth frame will be written to the dump file. The + // value must be greater than 0. (Default: 1) + explicit VideoDumpOptions(absl::string_view output_directory, + int sampling_modulo = 1); + + VideoDumpOptions(const VideoDumpOptions&) = default; + VideoDumpOptions& operator=(const VideoDumpOptions&) = default; + VideoDumpOptions(VideoDumpOptions&&) = default; + VideoDumpOptions& operator=(VideoDumpOptions&&) = default; + + std::string output_directory() const { return output_directory_; } + int sampling_modulo() const { return sampling_modulo_; } + + std::string GetInputDumpFileName(absl::string_view stream_label) const; + std::string GetOutputDumpFileName(absl::string_view stream_label, + absl::string_view receiver) const; + + private: + std::string output_directory_; + int sampling_modulo_ = 1; + }; + // Contains properties of single video stream. struct VideoConfig { explicit VideoConfig(const VideoResolution& resolution); @@ -267,17 +297,24 @@ class PeerConnectionE2EQualityTestFixture { // each RtpEncodingParameters of RtpParameters of corresponding // RtpSenderInterface for this video stream. absl::optional temporal_layers_count; - // If specified the input stream will be also copied to specified file. - // It is actually one of the test's output file, which contains copy of what - // was captured during the test for this video stream on sender side. - // It is useful when generator is used as input. + // DEPRECATED: use input_dump_options instead. If specified the input stream + // will be also copied to specified file. It is actually one of the test's + // output file, which contains copy of what was captured during the test for + // this video stream on sender side. It is useful when generator is used as + // input. absl::optional input_dump_file_name; - // Used only if `input_dump_file_name` is set. Specifies the module for the - // video frames to be dumped. Modulo equals X means every Xth frame will be - // written to the dump file. The value must be greater than 0. + // DEPRECATED: use input_dump_options instead. Used only if + // `input_dump_file_name` is set. Specifies the module for the video frames + // to be dumped. Modulo equals X means every Xth frame will be written to + // the dump file. The value must be greater than 0. int input_dump_sampling_modulo = 1; - // If specified this file will be used as output on the receiver side for - // this stream. + // If specified defines how input should be dumped. It is actually one of + // the test's output file, which contains copy of what was captured during + // the test for this video stream on sender side. It is useful when + // generator is used as input. + absl::optional input_dump_options; + // DEPRECATED: use output_dump_options instead. If specified this file will + // be used as output on the receiver side for this stream. // // If multiple output streams will be produced by this stream (e.g. when the // stream represented by this `VideoConfig` is received by more than one @@ -303,10 +340,15 @@ class PeerConnectionE2EQualityTestFixture { // The produced files contains what was rendered for this video stream on // receiver side. absl::optional output_dump_file_name; - // Used only if `output_dump_file_name` is set. Specifies the module for the - // video frames to be dumped. Modulo equals X means every Xth frame will be - // written to the dump file. The value must be greater than 0. + // DEPRECATED: use output_dump_options instead. Used only if + // `output_dump_file_name` is set. Specifies the module for the video frames + // to be dumped. Modulo equals X means every Xth frame will be written to + // the dump file. The value must be greater than 0. int output_dump_sampling_modulo = 1; + // If specified defines how output should be dumped on the receiver side for + // this stream. The produced files contain what was rendered for this video + // stream on receiver side per each receiver. + absl::optional output_dump_options; // If set to true uses fixed frame rate while dumping output video to the // file. `fps` will be used as frame rate. bool output_dump_use_fixed_framerate = false; diff --git a/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.cc b/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.cc index 9ad7ab578d..c423611e1c 100644 --- a/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.cc +++ b/test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.cc @@ -128,11 +128,21 @@ VideoQualityAnalyzerInjectionHelper::CreateFramePreprocessor( absl::string_view peer_name, const VideoConfig& config) { std::vector>> sinks; - test::VideoFrameWriter* writer = - MaybeCreateVideoWriter(config.input_dump_file_name, config); - if (writer) { + test::VideoFrameWriter* writer = nullptr; + if (config.input_dump_options.has_value()) { + // Using new API for video dumping. + writer = MaybeCreateVideoWriter( + config.input_dump_options->GetInputDumpFileName(peer_name), config); + RTC_CHECK(writer); sinks.push_back(std::make_unique( - writer, config.input_dump_sampling_modulo)); + writer, config.input_dump_options->sampling_modulo())); + } else { + // Using old API. To be removed. + writer = MaybeCreateVideoWriter(config.input_dump_file_name, config); + if (writer) { + sinks.push_back(std::make_unique( + writer, config.input_dump_sampling_modulo)); + } } if (config.show_on_screen) { sinks.push_back(absl::WrapUnique( @@ -206,7 +216,7 @@ VideoQualityAnalyzerInjectionHelper::MaybeCreateVideoWriter( // only one file will be used. std::unique_ptr video_writer = std::make_unique( - file_name.value(), config.width, config.height, config.fps); + *file_name, config.width, config.height, config.fps); if (config.output_dump_use_fixed_framerate) { video_writer = std::make_unique( config.fps, clock_, std::move(video_writer)); @@ -257,19 +267,31 @@ VideoQualityAnalyzerInjectionHelper::PopulateSinks( const VideoConfig& config = it->second; std::vector>> sinks; - absl::optional output_dump_file_name = - config.output_dump_file_name; - if (output_dump_file_name.has_value() && peers_count_ > 2) { - // TODO(titovartem): make this default behavior for any amount of peers. - rtc::StringBuilder builder(*output_dump_file_name); - builder << "." << receiver_stream.peer_name; - output_dump_file_name = builder.str(); - } - test::VideoFrameWriter* writer = - MaybeCreateVideoWriter(output_dump_file_name, config); - if (writer) { + test::VideoFrameWriter* writer = nullptr; + if (config.output_dump_options.has_value()) { + // Using new API with output directory. + writer = MaybeCreateVideoWriter( + config.output_dump_options->GetOutputDumpFileName( + receiver_stream.stream_label, receiver_stream.peer_name), + config); + RTC_CHECK(writer); sinks.push_back(std::make_unique( - writer, config.output_dump_sampling_modulo)); + writer, config.output_dump_options->sampling_modulo())); + } else { + // Using old API. To be removed. + absl::optional output_dump_file_name = + config.output_dump_file_name; + if (output_dump_file_name.has_value() && peers_count_ > 2) { + // TODO(titovartem): make this default behavior for any amount of peers. + rtc::StringBuilder builder(*output_dump_file_name); + builder << "." << receiver_stream.peer_name; + output_dump_file_name = builder.str(); + } + writer = MaybeCreateVideoWriter(output_dump_file_name, config); + if (writer) { + sinks.push_back(std::make_unique( + writer, config.output_dump_sampling_modulo)); + } } if (config.show_on_screen) { sinks.push_back(absl::WrapUnique(