From 1168fd4ed560176987116f06f5a3bd257d471d6e Mon Sep 17 00:00:00 2001 From: sprang Date: Wed, 21 Jun 2017 09:00:17 -0700 Subject: [PATCH] What can't loopback test be more like full stack test? It can; this CL makes it a lot closer, if not all the way to a merge. Performance from video_loopback and screenshare_loopback should now match what we're seeing in FullStackTest, which will make debugging and assesment of quality differences much easier. It also adds the ability to view all of the simulcast streams at once, in separate windows. BUG=webrtc:7694 Review-Url: https://codereview.webrtc.org/2946893003 Cr-Commit-Position: refs/heads/master@{#18703} --- webrtc/video/BUILD.gn | 1 + webrtc/video/screenshare_loopback.cc | 23 ++- webrtc/video/video_loopback.cc | 174 ++++++++++--------- webrtc/video/video_quality_test.cc | 249 +++++++++++++++++---------- webrtc/video/video_quality_test.h | 2 +- 5 files changed, 273 insertions(+), 176 deletions(-) diff --git a/webrtc/video/BUILD.gn b/webrtc/video/BUILD.gn index 58f58dc260..b5e8579011 100644 --- a/webrtc/video/BUILD.gn +++ b/webrtc/video/BUILD.gn @@ -154,6 +154,7 @@ if (rtc_include_tests) { ] deps = [ ":video_quality_test", + "../base:rtc_base_approved", "../system_wrappers:metrics_default", "../test:field_trial", "../test:run_test", diff --git a/webrtc/video/screenshare_loopback.cc b/webrtc/video/screenshare_loopback.cc index 46f662a45d..c0638c9b1a 100644 --- a/webrtc/video/screenshare_loopback.cc +++ b/webrtc/video/screenshare_loopback.cc @@ -127,7 +127,15 @@ int StdPropagationDelayMs() { return static_cast(FLAG_std_propagation_delay_ms); } -DEFINE_int(selected_stream, 0, "ID of the stream to show or analyze."); +DEFINE_int(num_streams, 0, "Number of streams to show or analyze."); +int NumStreams() { + return static_cast(FLAG_num_streams); +} + +DEFINE_int(selected_stream, + 0, + "ID of the stream to show or analyze. " + "Set to the number of streams to show them all."); int SelectedStream() { return static_cast(FLAG_selected_stream); } @@ -268,6 +276,11 @@ void Loopback() { params.pipe = pipe_config; params.logs = flags::FLAG_logs; + if (flags::NumStreams() > 1 && flags::Stream0().empty() && + flags::Stream1().empty()) { + params.ss.infer_streams = true; + } + std::vector stream_descriptors; stream_descriptors.push_back(flags::Stream0()); stream_descriptors.push_back(flags::Stream1()); @@ -275,7 +288,7 @@ void Loopback() { SL_descriptors.push_back(flags::SL0()); SL_descriptors.push_back(flags::SL1()); VideoQualityTest::FillScalabilitySettings( - ¶ms, stream_descriptors, flags::SelectedStream(), + ¶ms, stream_descriptors, flags::NumStreams(), flags::SelectedStream(), flags::NumSpatialLayers(), flags::SelectedSL(), SL_descriptors); VideoQualityTest test; @@ -295,8 +308,10 @@ int main(int argc, char* argv[]) { return 0; } - webrtc::test::InitFieldTrialsFromString( - webrtc::flags::FLAG_force_fieldtrials); + // InitFieldTrialsFromString needs a reference to an std::string instance, + // with a scope that outlives the test. + std::string field_trials = webrtc::flags::FLAG_force_fieldtrials; + webrtc::test::InitFieldTrialsFromString(field_trials); webrtc::test::RunTest(webrtc::Loopback); return 0; } diff --git a/webrtc/video/video_loopback.cc b/webrtc/video/video_loopback.cc index 6c2a1630fd..66bafbb6f0 100644 --- a/webrtc/video/video_loopback.cc +++ b/webrtc/video/video_loopback.cc @@ -10,7 +10,7 @@ #include -#include "gflags/gflags.h" +#include "webrtc/base/flags.h" #include "webrtc/test/field_trial.h" #include "webrtc/test/gtest.h" #include "webrtc/test/run_test.h" @@ -20,171 +20,177 @@ namespace webrtc { namespace flags { // Flags common with screenshare loopback, with different default values. -DEFINE_int32(width, 640, "Video width."); +DEFINE_int(width, 640, "Video width."); size_t Width() { - return static_cast(FLAGS_width); + return static_cast(FLAG_width); } -DEFINE_int32(height, 480, "Video height."); +DEFINE_int(height, 480, "Video height."); size_t Height() { - return static_cast(FLAGS_height); + return static_cast(FLAG_height); } -DEFINE_int32(fps, 30, "Frames per second."); +DEFINE_int(fps, 30, "Frames per second."); int Fps() { - return static_cast(FLAGS_fps); + return static_cast(FLAG_fps); } -DEFINE_int32(capture_device_index, 0, "Capture device to select"); +DEFINE_int(capture_device_index, 0, "Capture device to select"); size_t GetCaptureDevice() { - return static_cast(FLAGS_capture_device_index); + return static_cast(FLAG_capture_device_index); } -DEFINE_int32(min_bitrate, 50, "Call and stream min bitrate in kbps."); +DEFINE_int(min_bitrate, 50, "Call and stream min bitrate in kbps."); int MinBitrateKbps() { - return static_cast(FLAGS_min_bitrate); + return static_cast(FLAG_min_bitrate); } -DEFINE_int32(start_bitrate, 300, "Call start bitrate in kbps."); +DEFINE_int(start_bitrate, 300, "Call start bitrate in kbps."); int StartBitrateKbps() { - return static_cast(FLAGS_start_bitrate); + return static_cast(FLAG_start_bitrate); } -DEFINE_int32(target_bitrate, 800, "Stream target bitrate in kbps."); +DEFINE_int(target_bitrate, 800, "Stream target bitrate in kbps."); int TargetBitrateKbps() { - return static_cast(FLAGS_target_bitrate); + return static_cast(FLAG_target_bitrate); } -DEFINE_int32(max_bitrate, 800, "Call and stream max bitrate in kbps."); +DEFINE_int(max_bitrate, 800, "Call and stream max bitrate in kbps."); int MaxBitrateKbps() { - return static_cast(FLAGS_max_bitrate); + return static_cast(FLAG_max_bitrate); } DEFINE_bool(suspend_below_min_bitrate, false, "Suspends video below the configured min bitrate."); -DEFINE_int32(num_temporal_layers, - 1, - "Number of temporal layers. Set to 1-4 to override."); +DEFINE_int(num_temporal_layers, + 1, + "Number of temporal layers. Set to 1-4 to override."); int NumTemporalLayers() { - return static_cast(FLAGS_num_temporal_layers); + return static_cast(FLAG_num_temporal_layers); } // Flags common with screenshare loopback, with equal default values. DEFINE_string(codec, "VP8", "Video codec to use."); std::string Codec() { - return static_cast(FLAGS_codec); + return static_cast(FLAG_codec); } -DEFINE_int32(selected_tl, - -1, - "Temporal layer to show or analyze. -1 to disable filtering."); +DEFINE_int(selected_tl, + -1, + "Temporal layer to show or analyze. -1 to disable filtering."); int SelectedTL() { - return static_cast(FLAGS_selected_tl); + return static_cast(FLAG_selected_tl); } -DEFINE_int32( +DEFINE_int( duration, 0, "Duration of the test in seconds. If 0, rendered will be shown instead."); int DurationSecs() { - return static_cast(FLAGS_duration); + return static_cast(FLAG_duration); } DEFINE_string(output_filename, "", "Target graph data filename."); std::string OutputFilename() { - return static_cast(FLAGS_output_filename); + return static_cast(FLAG_output_filename); } DEFINE_string(graph_title, "", "If empty, title will be generated automatically."); std::string GraphTitle() { - return static_cast(FLAGS_graph_title); + return static_cast(FLAG_graph_title); } -DEFINE_int32(loss_percent, 0, "Percentage of packets randomly lost."); +DEFINE_int(loss_percent, 0, "Percentage of packets randomly lost."); int LossPercent() { - return static_cast(FLAGS_loss_percent); + return static_cast(FLAG_loss_percent); } -DEFINE_int32(avg_burst_loss_length, - -1, - "Average burst length of lost packets."); +DEFINE_int(avg_burst_loss_length, -1, "Average burst length of lost packets."); int AvgBurstLossLength() { - return static_cast(FLAGS_avg_burst_loss_length); + return static_cast(FLAG_avg_burst_loss_length); } -DEFINE_int32(link_capacity, - 0, - "Capacity (kbps) of the fake link. 0 means infinite."); +DEFINE_int(link_capacity, + 0, + "Capacity (kbps) of the fake link. 0 means infinite."); int LinkCapacityKbps() { - return static_cast(FLAGS_link_capacity); + return static_cast(FLAG_link_capacity); } -DEFINE_int32(queue_size, 0, "Size of the bottleneck link queue in packets."); +DEFINE_int(queue_size, 0, "Size of the bottleneck link queue in packets."); int QueueSize() { - return static_cast(FLAGS_queue_size); + return static_cast(FLAG_queue_size); } -DEFINE_int32(avg_propagation_delay_ms, - 0, - "Average link propagation delay in ms."); +DEFINE_int(avg_propagation_delay_ms, + 0, + "Average link propagation delay in ms."); int AvgPropagationDelayMs() { - return static_cast(FLAGS_avg_propagation_delay_ms); + return static_cast(FLAG_avg_propagation_delay_ms); } -DEFINE_int32(std_propagation_delay_ms, - 0, - "Link propagation delay standard deviation in ms."); +DEFINE_int(std_propagation_delay_ms, + 0, + "Link propagation delay standard deviation in ms."); int StdPropagationDelayMs() { - return static_cast(FLAGS_std_propagation_delay_ms); + return static_cast(FLAG_std_propagation_delay_ms); } -DEFINE_int32(selected_stream, 0, "ID of the stream to show or analyze."); +DEFINE_int(num_streams, 0, "Number of streams to show or analyze."); +int NumStreams() { + return static_cast(FLAG_num_streams); +} + +DEFINE_int(selected_stream, + 0, + "ID of the stream to show or analyze. " + "Set to the number of streams to show them all."); int SelectedStream() { - return static_cast(FLAGS_selected_stream); + return static_cast(FLAG_selected_stream); } -DEFINE_int32(num_spatial_layers, 1, "Number of spatial layers to use."); +DEFINE_int(num_spatial_layers, 1, "Number of spatial layers to use."); int NumSpatialLayers() { - return static_cast(FLAGS_num_spatial_layers); + return static_cast(FLAG_num_spatial_layers); } -DEFINE_int32(selected_sl, - -1, - "Spatial layer to show or analyze. -1 to disable filtering."); +DEFINE_int(selected_sl, + -1, + "Spatial layer to show or analyze. -1 to disable filtering."); int SelectedSL() { - return static_cast(FLAGS_selected_sl); + return static_cast(FLAG_selected_sl); } DEFINE_string(stream0, "", "Comma separated values describing VideoStream for stream #0."); std::string Stream0() { - return static_cast(FLAGS_stream0); + return static_cast(FLAG_stream0); } DEFINE_string(stream1, "", "Comma separated values describing VideoStream for stream #1."); std::string Stream1() { - return static_cast(FLAGS_stream1); + return static_cast(FLAG_stream1); } DEFINE_string(sl0, "", "Comma separated values describing SpatialLayer for layer #0."); std::string SL0() { - return static_cast(FLAGS_sl0); + return static_cast(FLAG_sl0); } DEFINE_string(sl1, "", "Comma separated values describing SpatialLayer for layer #1."); std::string SL1() { - return static_cast(FLAGS_sl1); + return static_cast(FLAG_sl1); } DEFINE_string(encoded_frame_path, @@ -192,7 +198,7 @@ DEFINE_string(encoded_frame_path, "The base path for encoded frame logs. Created files will have " "the form ..(recv|send.).ivf"); std::string EncodedFramePath() { - return static_cast(FLAGS_encoded_frame_path); + return static_cast(FLAG_encoded_frame_path); } DEFINE_bool(logs, false, "print logs to stderr"); @@ -227,9 +233,11 @@ DEFINE_string(clip, "", "Name of the clip to show. If empty, using chroma generator."); std::string Clip() { - return static_cast(FLAGS_clip); + return static_cast(FLAG_clip); } +DEFINE_bool(help, false, "prints this message"); + } // namespace flags void Loopback() { @@ -240,7 +248,7 @@ void Loopback() { pipe_config.queue_length_packets = flags::QueueSize(); pipe_config.queue_delay_ms = flags::AvgPropagationDelayMs(); pipe_config.delay_standard_deviation_ms = flags::StdPropagationDelayMs(); - pipe_config.allow_reordering = flags::FLAGS_allow_reordering; + pipe_config.allow_reordering = flags::FLAG_allow_reordering; Call::Config::BitrateConfig call_bitrate_config; call_bitrate_config.min_bitrate_bps = flags::MinBitrateKbps() * 1000; @@ -248,31 +256,36 @@ void Loopback() { call_bitrate_config.max_bitrate_bps = flags::MaxBitrateKbps() * 1000; VideoQualityTest::Params params; - params.call = {flags::FLAGS_send_side_bwe, call_bitrate_config}; - params.video = {flags::FLAGS_video, + params.call = {flags::FLAG_send_side_bwe, call_bitrate_config}; + params.video = {flags::FLAG_video, flags::Width(), flags::Height(), flags::Fps(), flags::MinBitrateKbps() * 1000, flags::TargetBitrateKbps() * 1000, flags::MaxBitrateKbps() * 1000, - flags::FLAGS_suspend_below_min_bitrate, + flags::FLAG_suspend_below_min_bitrate, flags::Codec(), flags::NumTemporalLayers(), flags::SelectedTL(), 0, // No min transmit bitrate. - flags::FLAGS_use_ulpfec, - flags::FLAGS_use_flexfec, + flags::FLAG_use_ulpfec, + flags::FLAG_use_flexfec, flags::EncodedFramePath(), flags::Clip(), flags::GetCaptureDevice()}; - params.audio = {flags::FLAGS_audio, flags::FLAGS_audio_video_sync, - flags::FLAGS_audio_dtx}; + params.audio = {flags::FLAG_audio, flags::FLAG_audio_video_sync, + flags::FLAG_audio_dtx}; params.screenshare.enabled = false; params.analyzer = {"video", 0.0, 0.0, flags::DurationSecs(), flags::OutputFilename(), flags::GraphTitle()}; params.pipe = pipe_config; - params.logs = flags::FLAGS_logs; + params.logs = flags::FLAG_logs; + + if (flags::NumStreams() > 1 && flags::Stream0().empty() && + flags::Stream1().empty()) { + params.ss.infer_streams = true; + } std::vector stream_descriptors; stream_descriptors.push_back(flags::Stream0()); @@ -281,7 +294,7 @@ void Loopback() { SL_descriptors.push_back(flags::SL0()); SL_descriptors.push_back(flags::SL1()); VideoQualityTest::FillScalabilitySettings( - ¶ms, stream_descriptors, flags::SelectedStream(), + ¶ms, stream_descriptors, flags::NumStreams(), flags::SelectedStream(), flags::NumSpatialLayers(), flags::SelectedSL(), SL_descriptors); VideoQualityTest test; @@ -295,9 +308,16 @@ void Loopback() { int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); - google::ParseCommandLineFlags(&argc, &argv, true); - webrtc::test::InitFieldTrialsFromString( - webrtc::flags::FLAGS_force_fieldtrials); + rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true); + if (webrtc::flags::FLAG_help) { + rtc::FlagList::Print(nullptr, false); + return 0; + } + + // InitFieldTrialsFromString needs a reference to an std::string instance, + // with a scope that outlives the test. + std::string field_trials = webrtc::flags::FLAG_force_fieldtrials; + webrtc::test::InitFieldTrialsFromString(field_trials); webrtc::test::RunTest(webrtc::Loopback); return 0; } diff --git a/webrtc/video/video_quality_test.cc b/webrtc/video/video_quality_test.cc index 1ab23ed3a2..4357276146 100644 --- a/webrtc/video/video_quality_test.cc +++ b/webrtc/video/video_quality_test.cc @@ -64,6 +64,8 @@ constexpr int kFramesSentInQuickTest = 1; constexpr uint32_t kThumbnailSendSsrcStart = 0xE0000; constexpr uint32_t kThumbnailRtxSsrcStart = 0xF0000; +constexpr int kDefaultMaxQp = cricket::WebRtcVideoChannel::kDefaultQpMax; + struct VoiceEngineState { VoiceEngineState() : voice_engine(nullptr), @@ -1124,13 +1126,11 @@ void VideoQualityTest::CheckParams() { RTC_CHECK_GE(params_.video.max_bitrate_bps, params_.video.target_bitrate_bps); RTC_CHECK_GE(params_.video.target_bitrate_bps, params_.video.min_bitrate_bps); RTC_CHECK_LT(params_.video.selected_tl, params_.video.num_temporal_layers); - RTC_CHECK_LT(params_.ss.selected_stream, params_.ss.streams.size()); + RTC_CHECK_LE(params_.ss.selected_stream, params_.ss.streams.size()); for (const VideoStream& stream : params_.ss.streams) { RTC_CHECK_GE(stream.min_bitrate_bps, 0); RTC_CHECK_GE(stream.target_bitrate_bps, stream.min_bitrate_bps); RTC_CHECK_GE(stream.max_bitrate_bps, stream.target_bitrate_bps); - RTC_CHECK_LE(stream.temporal_layer_thresholds_bps.size(), - params_.video.num_temporal_layers - 1); } // TODO(ivica): Should we check if the sum of all streams/layers is equal to // the total bitrate? We anyway have to update them in the case bitrate @@ -1191,7 +1191,7 @@ VideoStream VideoQualityTest::DefaultVideoStream(const Params& params) { stream.min_bitrate_bps = params.video.min_bitrate_bps; stream.target_bitrate_bps = params.video.target_bitrate_bps; stream.max_bitrate_bps = params.video.max_bitrate_bps; - stream.max_qp = cricket::WebRtcVideoChannel::kDefaultQpMax; + stream.max_qp = kDefaultMaxQp; // TODO(sprang): Can we make this less of a hack? if (params.video.num_temporal_layers == 2) { stream.temporal_layer_thresholds_bps.push_back(stream.target_bitrate_bps); @@ -1211,7 +1211,7 @@ VideoStream VideoQualityTest::DefaultThumbnailStream() { stream.min_bitrate_bps = 7500; stream.target_bitrate_bps = 37500; stream.max_bitrate_bps = 50000; - stream.max_qp = cricket::WebRtcVideoChannel::kDefaultQpMax; + stream.max_qp = kDefaultMaxQp; return stream; } @@ -1219,48 +1219,68 @@ VideoStream VideoQualityTest::DefaultThumbnailStream() { void VideoQualityTest::FillScalabilitySettings( Params* params, const std::vector& stream_descriptors, + int num_streams, size_t selected_stream, int num_spatial_layers, int selected_sl, const std::vector& sl_descriptors) { - // Read VideoStream and SpatialLayer elements from a list of comma separated - // lists. To use a default value for an element, use -1 or leave empty. - // Validity checks performed in CheckParams. - - RTC_CHECK(params->ss.streams.empty()); - for (auto descriptor : stream_descriptors) { - if (descriptor.empty()) - continue; - VideoStream stream = VideoQualityTest::DefaultVideoStream(*params); - std::vector v = VideoQualityTest::ParseCSV(descriptor); - if (v[0] != -1) - stream.width = static_cast(v[0]); - if (v[1] != -1) - stream.height = static_cast(v[1]); - if (v[2] != -1) - stream.max_framerate = v[2]; - if (v[3] != -1) - stream.min_bitrate_bps = v[3]; - if (v[4] != -1) - stream.target_bitrate_bps = v[4]; - if (v[5] != -1) - stream.max_bitrate_bps = v[5]; - if (v.size() > 6 && v[6] != -1) - stream.max_qp = v[6]; - if (v.size() > 7) { - stream.temporal_layer_thresholds_bps.clear(); - stream.temporal_layer_thresholds_bps.insert( - stream.temporal_layer_thresholds_bps.end(), v.begin() + 7, v.end()); - } else { - // Automatic TL thresholds for more than two layers not supported. - RTC_CHECK_LE(params->video.num_temporal_layers, 2); + if (params->ss.streams.empty() && params->ss.infer_streams) { + webrtc::VideoEncoderConfig encoder_config; + encoder_config.content_type = + params->screenshare.enabled + ? webrtc::VideoEncoderConfig::ContentType::kScreen + : webrtc::VideoEncoderConfig::ContentType::kRealtimeVideo; + encoder_config.max_bitrate_bps = params->video.max_bitrate_bps; + encoder_config.min_transmit_bitrate_bps = params->video.min_transmit_bps; + encoder_config.number_of_streams = num_streams; + encoder_config.spatial_layers = params->ss.spatial_layers; + encoder_config.video_stream_factory = + new rtc::RefCountedObject( + params->video.codec, kDefaultMaxQp, params->video.fps, + params->screenshare.enabled, true); + params->ss.streams = + encoder_config.video_stream_factory->CreateEncoderStreams( + static_cast(params->video.width), + static_cast(params->video.height), encoder_config); + } else { + // Read VideoStream and SpatialLayer elements from a list of comma separated + // lists. To use a default value for an element, use -1 or leave empty. + // Validity checks performed in CheckParams. + RTC_CHECK(params->ss.streams.empty()); + for (auto descriptor : stream_descriptors) { + if (descriptor.empty()) + continue; + VideoStream stream = VideoQualityTest::DefaultVideoStream(*params); + std::vector v = VideoQualityTest::ParseCSV(descriptor); + if (v[0] != -1) + stream.width = static_cast(v[0]); + if (v[1] != -1) + stream.height = static_cast(v[1]); + if (v[2] != -1) + stream.max_framerate = v[2]; + if (v[3] != -1) + stream.min_bitrate_bps = v[3]; + if (v[4] != -1) + stream.target_bitrate_bps = v[4]; + if (v[5] != -1) + stream.max_bitrate_bps = v[5]; + if (v.size() > 6 && v[6] != -1) + stream.max_qp = v[6]; + if (v.size() > 7) { + stream.temporal_layer_thresholds_bps.clear(); + stream.temporal_layer_thresholds_bps.insert( + stream.temporal_layer_thresholds_bps.end(), v.begin() + 7, v.end()); + } else { + // Automatic TL thresholds for more than two layers not supported. + RTC_CHECK_LE(params->video.num_temporal_layers, 2); + } + params->ss.streams.push_back(stream); } - params->ss.streams.push_back(stream); } - params->ss.selected_stream = selected_stream; - params->ss.infer_streams = false; - params->ss.num_spatial_layers = num_spatial_layers ? num_spatial_layers : 1; + params->ss.num_spatial_layers = std::max(1, num_spatial_layers); + params->ss.selected_stream = selected_stream; + params->ss.selected_sl = selected_sl; RTC_CHECK(params->ss.spatial_layers.empty()); for (auto descriptor : sl_descriptors) { @@ -1356,6 +1376,9 @@ void VideoQualityTest::SetupVideo(Transport* send_transport, CreateMatchingReceiveConfigs(recv_transport); + const bool decode_all_receive_streams = + params_.ss.selected_stream == params_.ss.streams.size(); + for (size_t i = 0; i < num_video_streams; ++i) { video_receive_configs_[i].rtp.nack.rtp_history_ms = kNackRtpHistoryMs; video_receive_configs_[i].rtp.rtx_ssrc = kSendRtxSsrcs[i]; @@ -1366,7 +1389,7 @@ void VideoQualityTest::SetupVideo(Transport* send_transport, // Enable RTT calculation so NTP time estimator will work. video_receive_configs_[i].rtp.rtcp_xr.receiver_reference_time_report = true; // Force fake decoders on non-selected simulcast streams. - if (i != params_.ss.selected_stream) { + if (!decode_all_receive_streams && i != params_.ss.selected_stream) { VideoReceiveStream::Decoder decoder; decoder.decoder = new test::FakeDecoder(); decoder.payload_type = video_send_config_.encoder_settings.payload_type; @@ -1379,8 +1402,15 @@ void VideoQualityTest::SetupVideo(Transport* send_transport, if (params_.video.flexfec) { // Override send config constructed by CreateSendConfig. - video_send_config_.rtp.flexfec.protected_media_ssrcs = { - kVideoSendSsrcs[params_.ss.selected_stream]}; + if (decode_all_receive_streams) { + for (uint32_t media_ssrc : video_send_config_.rtp.ssrcs) { + video_send_config_.rtp.flexfec.protected_media_ssrcs.push_back( + media_ssrc); + } + } else { + video_send_config_.rtp.flexfec.protected_media_ssrcs = { + kVideoSendSsrcs[params_.ss.selected_stream]}; + } // The matching receive config is _not_ created by // CreateMatchingReceiveConfigs, since VideoQualityTest is not a BaseTest. @@ -1409,15 +1439,27 @@ void VideoQualityTest::SetupVideo(Transport* send_transport, video_send_config_.rtp.ulpfec.ulpfec_payload_type = kUlpfecPayloadType; video_send_config_.rtp.ulpfec.red_rtx_payload_type = kRtxRedPayloadType; - video_receive_configs_[params_.ss.selected_stream] - .rtp.ulpfec.red_payload_type = - video_send_config_.rtp.ulpfec.red_payload_type; - video_receive_configs_[params_.ss.selected_stream] - .rtp.ulpfec.ulpfec_payload_type = - video_send_config_.rtp.ulpfec.ulpfec_payload_type; - video_receive_configs_[params_.ss.selected_stream] - .rtp.ulpfec.red_rtx_payload_type = - video_send_config_.rtp.ulpfec.red_rtx_payload_type; + if (decode_all_receive_streams) { + for (auto it = video_receive_configs_.begin(); + it != video_receive_configs_.end(); ++it) { + it->rtp.ulpfec.red_payload_type = + video_send_config_.rtp.ulpfec.red_payload_type; + it->rtp.ulpfec.ulpfec_payload_type = + video_send_config_.rtp.ulpfec.ulpfec_payload_type; + it->rtp.ulpfec.red_rtx_payload_type = + video_send_config_.rtp.ulpfec.red_rtx_payload_type; + } + } else { + video_receive_configs_[params_.ss.selected_stream] + .rtp.ulpfec.red_payload_type = + video_send_config_.rtp.ulpfec.red_payload_type; + video_receive_configs_[params_.ss.selected_stream] + .rtp.ulpfec.ulpfec_payload_type = + video_send_config_.rtp.ulpfec.ulpfec_payload_type; + video_receive_configs_[params_.ss.selected_stream] + .rtp.ulpfec.red_rtx_payload_type = + video_send_config_.rtp.ulpfec.red_rtx_payload_type; + } } } @@ -1754,7 +1796,6 @@ void VideoQualityTest::RunWithAnalyzer(const Params& params) { void VideoQualityTest::SetupAudio(int send_channel_id, int receive_channel_id, - Call* call, Transport* transport, AudioReceiveStream** audio_receive_stream) { audio_send_config_ = AudioSendStream::Config(transport); @@ -1778,7 +1819,7 @@ void VideoQualityTest::SetupAudio(int send_channel_id, {{"usedtx", (params_.audio.dtx ? "1" : "0")}, {"stereo", "1"}}}}); audio_send_config_.encoder_factory = encoder_factory_; - audio_send_stream_ = call->CreateAudioSendStream(audio_send_config_); + audio_send_stream_ = sender_call_->CreateAudioSendStream(audio_send_config_); AudioReceiveStream::Config audio_config; audio_config.rtp.local_ssrc = kReceiverLocalAudioSsrc; @@ -1792,7 +1833,8 @@ void VideoQualityTest::SetupAudio(int send_channel_id, if (params_.video.enabled && params_.audio.sync_video) audio_config.sync_group = kSyncGroup; - *audio_receive_stream = call->CreateAudioReceiveStream(audio_config); + *audio_receive_stream = + receiver_call_->CreateAudioReceiveStream(audio_config); } void VideoQualityTest::RunWithRenderers(const Params& params) { @@ -1813,58 +1855,71 @@ void VideoQualityTest::RunWithRenderers(const Params& params) { call_config.audio_state = AudioState::Create(audio_state_config); } - std::unique_ptr call(Call::Create(call_config)); + CreateCalls(call_config, call_config); // TODO(minyue): consider if this is a good transport even for audio only // calls. - test::LayerFilteringTransport transport( - params.pipe, call.get(), kPayloadTypeVP8, kPayloadTypeVP9, + test::LayerFilteringTransport send_transport( + params.pipe, sender_call_.get(), kPayloadTypeVP8, kPayloadTypeVP9, params.video.selected_tl, params_.ss.selected_sl, payload_type_map_); + test::DirectTransport recv_transport(params_.pipe, receiver_call_.get(), + payload_type_map_); + // TODO(ivica): Use two calls to be able to merge with RunWithAnalyzer or at // least share as much code as possible. That way this test would also match // the full stack tests better. - transport.SetReceiver(call->Receiver()); + send_transport.SetReceiver(receiver_call_->Receiver()); + recv_transport.SetReceiver(sender_call_->Receiver()); - VideoReceiveStream* video_receive_stream = nullptr; FlexfecReceiveStream* flexfec_receive_stream = nullptr; std::unique_ptr local_preview; - std::unique_ptr loopback_video; + std::vector> loopback_renderers_; if (params_.video.enabled) { // Create video renderers. local_preview.reset(test::VideoRenderer::Create( "Local Preview", params_.video.width, params_.video.height)); - size_t stream_id = params_.ss.selected_stream; - std::string title = "Loopback Video"; - if (params_.ss.streams.size() > 1) { - std::ostringstream s; - s << stream_id; - title += " - Stream #" + s.str(); + const size_t selected_stream_id = params_.ss.selected_stream; + const size_t num_streams = params_.ss.streams.size(); + + if (selected_stream_id == num_streams) { + for (size_t stream_id = 0; stream_id < num_streams; ++stream_id) { + std::ostringstream oss; + oss << "Loopback Video - Stream #" << static_cast(stream_id); + loopback_renderers_.emplace_back(test::VideoRenderer::Create( + oss.str().c_str(), params_.ss.streams[stream_id].width, + params_.ss.streams[stream_id].height)); + } + } else { + loopback_renderers_.emplace_back(test::VideoRenderer::Create( + "Loopback Video", params_.ss.streams[selected_stream_id].width, + params_.ss.streams[selected_stream_id].height)); } - loopback_video.reset(test::VideoRenderer::Create( - title.c_str(), params_.ss.streams[stream_id].width, - params_.ss.streams[stream_id].height)); + SetupVideo(&send_transport, &recv_transport); - SetupVideo(&transport, &transport); video_send_config_.pre_encode_callback = local_preview.get(); - video_receive_configs_[stream_id].renderer = loopback_video.get(); - if (params_.audio.enabled && params_.audio.sync_video) - video_receive_configs_[stream_id].sync_group = kSyncGroup; + if (selected_stream_id == num_streams) { + for (size_t stream_id = 0; stream_id < num_streams; ++stream_id) { + video_receive_configs_[stream_id].renderer = + loopback_renderers_[stream_id].get(); + if (params_.audio.enabled && params_.audio.sync_video) + video_receive_configs_[stream_id].sync_group = kSyncGroup; + } + } else { + video_receive_configs_[selected_stream_id].renderer = + loopback_renderers_.back().get(); + if (params_.audio.enabled && params_.audio.sync_video) + video_receive_configs_[selected_stream_id].sync_group = kSyncGroup; + } if (params_.screenshare.enabled) SetupScreenshareOrSVC(); - video_send_stream_ = call->CreateVideoSendStream( - video_send_config_.Copy(), video_encoder_config_.Copy()); - if (params_.video.flexfec) { - RTC_DCHECK(!flexfec_receive_configs_.empty()); - flexfec_receive_stream = - call->CreateFlexfecReceiveStream(flexfec_receive_configs_[0]); - } - video_receive_stream = call->CreateVideoReceiveStream( - video_receive_configs_[stream_id].Copy()); + CreateFlexfecStreams(); + CreateVideoStreams(); + CreateCapturer(); video_send_stream_->SetSource(video_capturer_.get(), degradation_preference_); @@ -1872,18 +1927,20 @@ void VideoQualityTest::RunWithRenderers(const Params& params) { AudioReceiveStream* audio_receive_stream = nullptr; if (params_.audio.enabled) { - SetupAudio(voe.send_channel_id, voe.receive_channel_id, call.get(), - &transport, &audio_receive_stream); + SetupAudio(voe.send_channel_id, voe.receive_channel_id, &send_transport, + &audio_receive_stream); } - StartEncodedFrameLogs(video_receive_stream); + for (VideoReceiveStream* receive_stream : video_receive_streams_) + StartEncodedFrameLogs(receive_stream); StartEncodedFrameLogs(video_send_stream_); // Start sending and receiving video. if (params_.video.enabled) { if (flexfec_receive_stream) flexfec_receive_stream->Start(); - video_receive_stream->Start(); + for (VideoReceiveStream* receive_stream : video_receive_streams_) + receive_stream->Start(); video_send_stream_->Start(); video_capturer_->Start(); } @@ -1908,24 +1965,28 @@ void VideoQualityTest::RunWithRenderers(const Params& params) { // Stop receiving audio. EXPECT_EQ(0, voe.base->StopPlayout(voe.receive_channel_id)); audio_receive_stream->Stop(); - call->DestroyAudioSendStream(audio_send_stream_); - call->DestroyAudioReceiveStream(audio_receive_stream); + sender_call_->DestroyAudioSendStream(audio_send_stream_); + receiver_call_->DestroyAudioReceiveStream(audio_receive_stream); } // Stop receiving and sending video. if (params_.video.enabled) { video_capturer_->Stop(); video_send_stream_->Stop(); - video_receive_stream->Stop(); + for (VideoReceiveStream* receive_stream : video_receive_streams_) + receive_stream->Stop(); if (flexfec_receive_stream) { flexfec_receive_stream->Stop(); - call->DestroyFlexfecReceiveStream(flexfec_receive_stream); + receiver_call_->DestroyFlexfecReceiveStream(flexfec_receive_stream); } - call->DestroyVideoReceiveStream(video_receive_stream); - call->DestroyVideoSendStream(video_send_stream_); + for (VideoReceiveStream* receive_stream : video_receive_streams_) + receiver_call_->DestroyVideoReceiveStream(receive_stream); + sender_call_->DestroyVideoSendStream(video_send_stream_); } - transport.StopSending(); + send_transport.StopSending(); + recv_transport.StopSending(); + if (params_.audio.enabled) DestroyVoiceEngine(&voe); } diff --git a/webrtc/video/video_quality_test.h b/webrtc/video/video_quality_test.h index d2fa2ed9a2..0221f68993 100644 --- a/webrtc/video/video_quality_test.h +++ b/webrtc/video/video_quality_test.h @@ -95,6 +95,7 @@ class VideoQualityTest : public test::CallTest { static void FillScalabilitySettings( Params* params, const std::vector& stream_descriptors, + int num_streams, size_t selected_stream, int num_spatial_layers, int selected_sl, @@ -125,7 +126,6 @@ class VideoQualityTest : public test::CallTest { void SetupScreenshareOrSVC(); void SetupAudio(int send_channel_id, int receive_channel_id, - Call* call, Transport* transport, AudioReceiveStream** audio_receive_stream);