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