diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-01-31 16:33:43 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-02-06 16:33:22 +0000 |
commit | da51f56cc21233c2d30f0fe0d171727c3102b2e0 (patch) | |
tree | 4e579ab70ce4b19bee7984237f3ce05a96d59d83 /chromium/third_party/webrtc/video/video_quality_test.cc | |
parent | c8c2d1901aec01e934adf561a9fdf0cc776cdef8 (diff) | |
download | qtwebengine-chromium-da51f56cc21233c2d30f0fe0d171727c3102b2e0.tar.gz |
BASELINE: Update Chromium to 65.0.3525.40
Also imports missing submodules
Change-Id: I36901b7c6a325cda3d2c10cedb2186c25af3b79b
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/third_party/webrtc/video/video_quality_test.cc')
-rw-r--r-- | chromium/third_party/webrtc/video/video_quality_test.cc | 1187 |
1 files changed, 607 insertions, 580 deletions
diff --git a/chromium/third_party/webrtc/video/video_quality_test.cc b/chromium/third_party/webrtc/video/video_quality_test.cc index e40d2955f05..ec110ff694e 100644 --- a/chromium/third_party/webrtc/video/video_quality_test.cc +++ b/chromium/third_party/webrtc/video/video_quality_test.cc @@ -17,46 +17,30 @@ #include <string> #include <vector> -#include "api/optional.h" -#include "call/call.h" -#include "common_video/libyuv/include/webrtc_libyuv.h" #include "logging/rtc_event_log/output/rtc_event_log_output_file.h" -#include "logging/rtc_event_log/rtc_event_log.h" #include "media/engine/internalencoderfactory.h" #include "media/engine/webrtcvideoengine.h" #include "modules/audio_mixer/audio_mixer_impl.h" -#include "modules/rtp_rtcp/include/rtp_header_parser.h" #include "modules/rtp_rtcp/source/rtp_format.h" #include "modules/rtp_rtcp/source/rtp_utility.h" #include "modules/video_coding/codecs/h264/include/h264.h" -#include "modules/video_coding/codecs/vp8/include/vp8.h" #include "modules/video_coding/codecs/vp8/include/vp8_common_types.h" #include "modules/video_coding/codecs/vp9/include/vp9.h" -#include "rtc_base/checks.h" #include "rtc_base/cpu_time.h" -#include "rtc_base/event.h" #include "rtc_base/flags.h" #include "rtc_base/format_macros.h" -#include "rtc_base/logging.h" #include "rtc_base/memory_usage.h" #include "rtc_base/pathutils.h" -#include "rtc_base/platform_file.h" -#include "rtc_base/ptr_util.h" -#include "rtc_base/timeutils.h" #include "system_wrappers/include/cpu_info.h" -#include "system_wrappers/include/field_trial.h" -#include "test/gtest.h" -#include "test/layer_filtering_transport.h" +#include "test/rtp_file_writer.h" #include "test/run_loop.h" #include "test/statistics.h" #include "test/testsupport/fileutils.h" #include "test/testsupport/frame_writer.h" +#include "test/testsupport/perf_test.h" #include "test/testsupport/test_artifacts.h" #include "test/vcm_capturer.h" #include "test/video_renderer.h" -#include "voice_engine/include/voe_base.h" - -#include "test/rtp_file_writer.h" DEFINE_bool(save_worst_frame, false, @@ -77,48 +61,6 @@ constexpr uint32_t kThumbnailRtxSsrcStart = 0xF0000; constexpr int kDefaultMaxQp = cricket::WebRtcVideoChannel::kDefaultQpMax; -struct VoiceEngineState { - VoiceEngineState() - : voice_engine(nullptr), - base(nullptr), - send_channel_id(-1), - receive_channel_id(-1) {} - - webrtc::VoiceEngine* voice_engine; - webrtc::VoEBase* base; - int send_channel_id; - int receive_channel_id; -}; - -void CreateVoiceEngine( - VoiceEngineState* voe, - webrtc::AudioDeviceModule* adm, - webrtc::AudioProcessing* apm, - rtc::scoped_refptr<webrtc::AudioDecoderFactory> decoder_factory) { - voe->voice_engine = webrtc::VoiceEngine::Create(); - voe->base = webrtc::VoEBase::GetInterface(voe->voice_engine); - EXPECT_EQ(0, adm->Init()); - EXPECT_EQ(0, voe->base->Init(adm, apm, decoder_factory)); - webrtc::VoEBase::ChannelConfig config; - config.enable_voice_pacing = true; - voe->send_channel_id = voe->base->CreateChannel(config); - EXPECT_GE(voe->send_channel_id, 0); - voe->receive_channel_id = voe->base->CreateChannel(); - EXPECT_GE(voe->receive_channel_id, 0); -} - -void DestroyVoiceEngine(VoiceEngineState* voe) { - voe->base->DeleteChannel(voe->send_channel_id); - voe->send_channel_id = -1; - voe->base->DeleteChannel(voe->receive_channel_id); - voe->receive_channel_id = -1; - voe->base->Release(); - voe->base = nullptr; - - webrtc::VoiceEngine::Delete(voe->voice_engine); - voe->voice_engine = nullptr; -} - class VideoStreamFactory : public webrtc::VideoEncoderConfig::VideoStreamFactoryInterface { public: @@ -134,6 +76,8 @@ class VideoStreamFactory std::vector<webrtc::VideoStream> streams = streams_; streams[streams_.size() - 1].height = height; streams[streams_.size() - 1].width = width; + + streams[0].bitrate_priority = encoder_config.bitrate_priority; return streams; } @@ -280,25 +224,25 @@ class VideoAnalyzer : public PacketReceiver, } DeliveryStatus DeliverPacket(MediaType media_type, - const uint8_t* packet, - size_t length, + rtc::CopyOnWriteBuffer packet, const PacketTime& packet_time) override { // Ignore timestamps of RTCP packets. They're not synchronized with // RTP packet timestamps and so they would confuse wrap_handler_. - if (RtpHeaderParser::IsRtcp(packet, length)) { - return receiver_->DeliverPacket(media_type, packet, length, packet_time); + if (RtpHeaderParser::IsRtcp(packet.cdata(), packet.size())) { + return receiver_->DeliverPacket(media_type, std::move(packet), + packet_time); } if (rtp_file_writer_) { test::RtpPacket p; - memcpy(p.data, packet, length); - p.length = length; - p.original_length = length; + memcpy(p.data, packet.cdata(), packet.size()); + p.length = packet.size(); + p.original_length = packet.size(); p.time_ms = clock_->TimeInMilliseconds() - start_ms_; rtp_file_writer_->WritePacket(&p); } - RtpUtility::RtpHeaderParser parser(packet, length); + RtpUtility::RtpHeaderParser parser(packet.cdata(), packet.size()); RTPHeader header; parser.Parse(&header); if (!IsFlexfec(header.payloadType) && @@ -315,12 +259,7 @@ class VideoAnalyzer : public PacketReceiver, Clock::GetRealTimeClock()->CurrentNtpInMilliseconds(); } - return receiver_->DeliverPacket(media_type, packet, length, packet_time); - } - - void MeasuredEncodeTiming(int64_t ntp_time_ms, int encode_time_ms) { - rtc::CritScope crit(&comparison_lock_); - samples_encode_time_ms_[ntp_time_ms] = encode_time_ms; + return receiver_->DeliverPacket(media_type, std::move(packet), packet_time); } void PreEncodeOnFrame(const VideoFrame& video_frame) { @@ -331,8 +270,7 @@ class VideoAnalyzer : public PacketReceiver, frames_.pop_front(); RTC_CHECK(!frames_.empty()); } - first_encoded_timestamp_ = - rtc::Optional<uint32_t>(video_frame.timestamp()); + first_encoded_timestamp_ = video_frame.timestamp(); } } @@ -340,7 +278,7 @@ class VideoAnalyzer : public PacketReceiver, rtc::CritScope lock(&crit_); if (!first_sent_timestamp_ && encoded_frame.stream_id_ == selected_stream_) { - first_sent_timestamp_ = rtc::Optional<uint32_t>(encoded_frame.timestamp_); + first_sent_timestamp_ = encoded_frame.timestamp_; } } @@ -426,7 +364,7 @@ class VideoAnalyzer : public PacketReceiver, AddFrameComparison(reference_frame, video_frame, false, render_time_ms); - last_rendered_frame_ = rtc::Optional<VideoFrame>(video_frame); + last_rendered_frame_ = video_frame; StopExcludingCpuThreadTime(); } @@ -592,9 +530,6 @@ class VideoAnalyzer : public PacketReceiver, public: explicit OnEncodeTimingProxy(VideoAnalyzer* parent) : parent_(parent) {} - void OnEncodeTiming(int64_t ntp_time_ms, int encode_time_ms) override { - parent_->MeasuredEncodeTiming(ntp_time_ms, encode_time_ms); - } void EncodedFrameCallback(const EncodedFrame& frame) override { parent_->PostEncodeFrameCallback(frame); } @@ -818,18 +753,18 @@ class VideoAnalyzer : public PacketReceiver, PrintResult("send_bandwidth", send_bandwidth_bps_, " bps"); if (worst_frame_) { - printf("RESULT min_psnr: %s = %lf dB\n", test_label_.c_str(), - worst_frame_->psnr); + test::PrintResult("min_psnr", "", test_label_.c_str(), worst_frame_->psnr, + "dB", false); } if (receive_stream_ != nullptr) { PrintResult("decode_time", decode_time_ms_, " ms"); } - printf("RESULT dropped_frames: %s = %d frames\n", test_label_.c_str(), - dropped_frames_); - printf("RESULT cpu_usage: %s = %lf %%\n", test_label_.c_str(), - GetCpuUsagePercent()); + test::PrintResult("dropped_frames", "", test_label_.c_str(), + dropped_frames_, "frames", false); + test::PrintResult("cpu_usage", "", test_label_.c_str(), + GetCpuUsagePercent(), "%", false); #if defined(WEBRTC_WIN) // On Linux and Mac in Resident Set some unused pages may be counted. @@ -918,12 +853,9 @@ class VideoAnalyzer : public PacketReceiver, void PrintResult(const char* result_type, test::Statistics stats, const char* unit) { - printf("RESULT %s: %s = {%f, %f}%s\n", - result_type, - test_label_.c_str(), - stats.Mean(), - stats.StandardDeviation(), - unit); + test::PrintResultMeanAndError(result_type, "", test_label_.c_str(), + stats.Mean(), stats.StandardDeviation(), unit, + false); } void PrintSamplesToFile(void) { @@ -946,27 +878,12 @@ class VideoAnalyzer : public PacketReceiver, "psnr " "ssim " "encode_time_ms\n"); - int missing_encode_time_samples = 0; for (const Sample& sample : samples_) { - auto it = samples_encode_time_ms_.find(sample.input_time_ms); - int encode_time_ms; - if (it != samples_encode_time_ms_.end()) { - encode_time_ms = it->second; - } else { - ++missing_encode_time_samples; - encode_time_ms = -1; - } fprintf(out, "%d %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %" PRIuS - " %lf %lf %d\n", + " %lf %lf\n", sample.dropped, sample.input_time_ms, sample.send_time_ms, sample.recv_time_ms, sample.render_time_ms, - sample.encoded_frame_size, sample.psnr, sample.ssim, - encode_time_ms); - } - if (missing_encode_time_samples) { - fprintf(stderr, - "Warning: Missing encode_time_ms samples for %d frame(s).\n", - missing_encode_time_samples); + sample.encoded_frame_size, sample.psnr, sample.ssim); } } @@ -1061,8 +978,6 @@ class VideoAnalyzer : public PacketReceiver, PreEncodeProxy pre_encode_proxy_; OnEncodeTimingProxy encode_timing_proxy_; std::vector<Sample> samples_ RTC_GUARDED_BY(comparison_lock_); - std::map<int64_t, int> samples_encode_time_ms_ - RTC_GUARDED_BY(comparison_lock_); test::Statistics sender_time_ RTC_GUARDED_BY(comparison_lock_); test::Statistics receiver_time_ RTC_GUARDED_BY(comparison_lock_); test::Statistics psnr_ RTC_GUARDED_BY(comparison_lock_); @@ -1147,13 +1062,16 @@ VideoQualityTest::VideoQualityTest() VideoQualityTest::Params::Params() : call({false, Call::Config::BitrateConfig(), 0}), - video({false, 640, 480, 30, 50, 800, 800, false, "VP8", 1, -1, 0, false, - false, ""}), + video{{false, 640, 480, 30, 50, 800, 800, false, "VP8", 1, -1, 0, false, + false, ""}, + {false, 640, 480, 30, 50, 800, 800, false, "VP8", 1, -1, 0, false, + false, ""}}, audio({false, false, false}), - screenshare({false, false, 10, 0}), + screenshare{{false, false, 10, 0}, {false, false, 10, 0}}, analyzer({"", 0.0, 0.0, 0, "", ""}), pipe(), - ss({std::vector<VideoStream>(), 0, 0, -1, std::vector<SpatialLayer>()}), + ss{{std::vector<VideoStream>(), 0, 0, -1, std::vector<SpatialLayer>()}, + {std::vector<VideoStream>(), 0, 0, -1, std::vector<SpatialLayer>()}}, logging({false, "", "", ""}) {} VideoQualityTest::Params::~Params() = default; @@ -1162,70 +1080,84 @@ void VideoQualityTest::TestBody() {} std::string VideoQualityTest::GenerateGraphTitle() const { std::stringstream ss; - ss << params_.video.codec; - ss << " (" << params_.video.target_bitrate_bps / 1000 << "kbps"; - ss << ", " << params_.video.fps << " FPS"; - if (params_.screenshare.scroll_duration) - ss << ", " << params_.screenshare.scroll_duration << "s scroll"; - if (params_.ss.streams.size() > 1) - ss << ", Stream #" << params_.ss.selected_stream; - if (params_.ss.num_spatial_layers > 1) - ss << ", Layer #" << params_.ss.selected_sl; + ss << params_.video[0].codec; + ss << " (" << params_.video[0].target_bitrate_bps / 1000 << "kbps"; + ss << ", " << params_.video[0].fps << " FPS"; + if (params_.screenshare[0].scroll_duration) + ss << ", " << params_.screenshare[0].scroll_duration << "s scroll"; + if (params_.ss[0].streams.size() > 1) + ss << ", Stream #" << params_.ss[0].selected_stream; + if (params_.ss[0].num_spatial_layers > 1) + ss << ", Layer #" << params_.ss[0].selected_sl; ss << ")"; return ss.str(); } void VideoQualityTest::CheckParams() { - if (!params_.video.enabled) - return; - // Add a default stream in none specified. - if (params_.ss.streams.empty()) - params_.ss.streams.push_back(VideoQualityTest::DefaultVideoStream(params_)); - if (params_.ss.num_spatial_layers == 0) - params_.ss.num_spatial_layers = 1; - - if (params_.pipe.loss_percent != 0 || - params_.pipe.queue_length_packets != 0) { - // Since LayerFilteringTransport changes the sequence numbers, we can't - // use that feature with pack loss, since the NACK request would end up - // retransmitting the wrong packets. - RTC_CHECK(params_.ss.selected_sl == -1 || - params_.ss.selected_sl == params_.ss.num_spatial_layers - 1); - RTC_CHECK(params_.video.selected_tl == -1 || - params_.video.selected_tl == - params_.video.num_temporal_layers - 1); - } + for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) { + // Iterate over primary and secondary video streams. + if (!params_.video[video_idx].enabled) + return; + // Add a default stream in none specified. + if (params_.ss[video_idx].streams.empty()) + params_.ss[video_idx].streams.push_back( + VideoQualityTest::DefaultVideoStream(params_, video_idx)); + if (params_.ss[video_idx].num_spatial_layers == 0) + params_.ss[video_idx].num_spatial_layers = 1; + + if (params_.pipe.loss_percent != 0 || + params_.pipe.queue_length_packets != 0) { + // Since LayerFilteringTransport changes the sequence numbers, we can't + // use that feature with pack loss, since the NACK request would end up + // retransmitting the wrong packets. + RTC_CHECK(params_.ss[video_idx].selected_sl == -1 || + params_.ss[video_idx].selected_sl == + params_.ss[video_idx].num_spatial_layers - 1); + RTC_CHECK(params_.video[video_idx].selected_tl == -1 || + params_.video[video_idx].selected_tl == + params_.video[video_idx].num_temporal_layers - 1); + } - // TODO(ivica): Should max_bitrate_bps == -1 represent inf max bitrate, as it - // does in some parts of the code? - 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_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); - } - // 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 - // estimator changes the total bitrates. - RTC_CHECK_GE(params_.ss.num_spatial_layers, 1); - RTC_CHECK_LE(params_.ss.selected_sl, params_.ss.num_spatial_layers); - RTC_CHECK(params_.ss.spatial_layers.empty() || - params_.ss.spatial_layers.size() == - static_cast<size_t>(params_.ss.num_spatial_layers)); - if (params_.video.codec == "VP8") { - RTC_CHECK_EQ(params_.ss.num_spatial_layers, 1); - } else if (params_.video.codec == "VP9") { - RTC_CHECK_EQ(params_.ss.streams.size(), 1); - } - RTC_CHECK_GE(params_.call.num_thumbnails, 0); - if (params_.call.num_thumbnails > 0) { - RTC_CHECK_EQ(params_.ss.num_spatial_layers, 1); - RTC_CHECK_EQ(params_.ss.streams.size(), 3); - RTC_CHECK_EQ(params_.video.num_temporal_layers, 3); - RTC_CHECK_EQ(params_.video.codec, "VP8"); + // TODO(ivica): Should max_bitrate_bps == -1 represent inf max bitrate, as + // it does in some parts of the code? + RTC_CHECK_GE(params_.video[video_idx].max_bitrate_bps, + params_.video[video_idx].target_bitrate_bps); + RTC_CHECK_GE(params_.video[video_idx].target_bitrate_bps, + params_.video[video_idx].min_bitrate_bps); + RTC_CHECK_LT(params_.video[video_idx].selected_tl, + params_.video[video_idx].num_temporal_layers); + RTC_CHECK_LE(params_.ss[video_idx].selected_stream, + params_.ss[video_idx].streams.size()); + for (const VideoStream& stream : params_.ss[video_idx].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); + } + // 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 + // estimator changes the total bitrates. + RTC_CHECK_GE(params_.ss[video_idx].num_spatial_layers, 1); + RTC_CHECK_LE(params_.ss[video_idx].selected_sl, + params_.ss[video_idx].num_spatial_layers); + RTC_CHECK( + params_.ss[video_idx].spatial_layers.empty() || + params_.ss[video_idx].spatial_layers.size() == + static_cast<size_t>(params_.ss[video_idx].num_spatial_layers)); + if (params_.video[video_idx].codec == "VP8") { + RTC_CHECK_EQ(params_.ss[video_idx].num_spatial_layers, 1); + } else if (params_.video[video_idx].codec == "VP9") { + RTC_CHECK_EQ(params_.ss[video_idx].streams.size(), 1); + } + RTC_CHECK_GE(params_.call.num_thumbnails, 0); + if (params_.call.num_thumbnails > 0) { + RTC_CHECK_EQ(params_.ss[video_idx].num_spatial_layers, 1); + RTC_CHECK_EQ(params_.ss[video_idx].streams.size(), 3); + RTC_CHECK_EQ(params_.video[video_idx].num_temporal_layers, 3); + RTC_CHECK_EQ(params_.video[video_idx].codec, "VP8"); + } + // Dual streams with FEC not supported in tests yet. + RTC_CHECK(!params_.video[video_idx].flexfec || num_video_streams_ == 1); + RTC_CHECK(!params_.video[video_idx].ulpfec || num_video_streams_ == 1); } } @@ -1258,24 +1190,26 @@ std::vector<int> VideoQualityTest::ParseCSV(const std::string& str) { } // Static. -VideoStream VideoQualityTest::DefaultVideoStream(const Params& params) { +VideoStream VideoQualityTest::DefaultVideoStream(const Params& params, + size_t video_idx) { VideoStream stream; - stream.width = params.video.width; - stream.height = params.video.height; - stream.max_framerate = params.video.fps; - 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.width = params.video[video_idx].width; + stream.height = params.video[video_idx].height; + stream.max_framerate = params.video[video_idx].fps; + stream.min_bitrate_bps = params.video[video_idx].min_bitrate_bps; + stream.target_bitrate_bps = params.video[video_idx].target_bitrate_bps; + stream.max_bitrate_bps = params.video[video_idx].max_bitrate_bps; stream.max_qp = kDefaultMaxQp; // TODO(sprang): Can we make this less of a hack? - if (params.video.num_temporal_layers == 2) { + if (params.video[video_idx].num_temporal_layers == 2) { stream.temporal_layer_thresholds_bps.push_back(stream.target_bitrate_bps); - } else if (params.video.num_temporal_layers == 3) { + } else if (params.video[video_idx].num_temporal_layers == 3) { stream.temporal_layer_thresholds_bps.push_back(stream.max_bitrate_bps / 4); stream.temporal_layer_thresholds_bps.push_back(stream.target_bitrate_bps); } else { - RTC_CHECK_LE(params.video.num_temporal_layers, kMaxTemporalStreams); - for (int i = 0; i < params.video.num_temporal_layers - 1; ++i) { + RTC_CHECK_LE(params.video[video_idx].num_temporal_layers, + kMaxTemporalStreams); + for (int i = 0; i < params.video[video_idx].num_temporal_layers - 1; ++i) { stream.temporal_layer_thresholds_bps.push_back(static_cast<int>( stream.max_bitrate_bps * kVp8LayerRateAlloction[0][i] + 0.5)); } @@ -1299,39 +1233,44 @@ VideoStream VideoQualityTest::DefaultThumbnailStream() { // Static. void VideoQualityTest::FillScalabilitySettings( Params* params, + size_t video_idx, const std::vector<std::string>& stream_descriptors, int num_streams, size_t selected_stream, int num_spatial_layers, int selected_sl, const std::vector<std::string>& sl_descriptors) { - if (params->ss.streams.empty() && params->ss.infer_streams) { + if (params->ss[video_idx].streams.empty() && + params->ss[video_idx].infer_streams) { webrtc::VideoEncoderConfig encoder_config; encoder_config.content_type = - params->screenshare.enabled + params->screenshare[video_idx].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.max_bitrate_bps = params->video[video_idx].max_bitrate_bps; + encoder_config.min_transmit_bitrate_bps = + params->video[video_idx].min_transmit_bps; encoder_config.number_of_streams = num_streams; - encoder_config.spatial_layers = params->ss.spatial_layers; + encoder_config.spatial_layers = params->ss[video_idx].spatial_layers; encoder_config.video_stream_factory = new rtc::RefCountedObject<cricket::EncoderStreamFactory>( - params->video.codec, kDefaultMaxQp, params->video.fps, - params->screenshare.enabled, true); - params->ss.streams = + params->video[video_idx].codec, kDefaultMaxQp, + params->video[video_idx].fps, + params->screenshare[video_idx].enabled, true); + params->ss[video_idx].streams = encoder_config.video_stream_factory->CreateEncoderStreams( - static_cast<int>(params->video.width), - static_cast<int>(params->video.height), encoder_config); + static_cast<int>(params->video[video_idx].width), + static_cast<int>(params->video[video_idx].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()); + RTC_CHECK(params->ss[video_idx].streams.empty()); for (auto descriptor : stream_descriptors) { if (descriptor.empty()) continue; - VideoStream stream = VideoQualityTest::DefaultVideoStream(*params); + VideoStream stream = + VideoQualityTest::DefaultVideoStream(*params, video_idx); std::vector<int> v = VideoQualityTest::ParseCSV(descriptor); if (v[0] != -1) stream.width = static_cast<size_t>(v[0]); @@ -1353,17 +1292,17 @@ void VideoQualityTest::FillScalabilitySettings( 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); + RTC_CHECK_LE(params->video[video_idx].num_temporal_layers, 2); } - params->ss.streams.push_back(stream); + params->ss[video_idx].streams.push_back(stream); } } - params->ss.num_spatial_layers = std::max(1, num_spatial_layers); - params->ss.selected_stream = selected_stream; + params->ss[video_idx].num_spatial_layers = std::max(1, num_spatial_layers); + params->ss[video_idx].selected_stream = selected_stream; - params->ss.selected_sl = selected_sl; - RTC_CHECK(params->ss.spatial_layers.empty()); + params->ss[video_idx].selected_sl = selected_sl; + RTC_CHECK(params->ss[video_idx].spatial_layers.empty()); for (auto descriptor : sl_descriptors) { if (descriptor.empty()) continue; @@ -1374,120 +1313,203 @@ void VideoQualityTest::FillScalabilitySettings( layer.scaling_factor_num = v[0] == -1 ? 1 : v[0]; layer.scaling_factor_den = v[1] == -1 ? 1 : v[1]; layer.target_bitrate_bps = v[2]; - params->ss.spatial_layers.push_back(layer); + params->ss[video_idx].spatial_layers.push_back(layer); } } void VideoQualityTest::SetupVideo(Transport* send_transport, Transport* recv_transport) { - size_t num_video_streams = params_.ss.streams.size(); - size_t num_flexfec_streams = params_.video.flexfec ? 1 : 0; - CreateSendConfig(num_video_streams, 0, num_flexfec_streams, send_transport); - - int payload_type; - if (params_.video.codec == "H264") { - video_encoder_ = H264Encoder::Create(cricket::VideoCodec("H264")); - payload_type = kPayloadTypeH264; - } else if (params_.video.codec == "VP8") { - if (params_.screenshare.enabled && params_.ss.streams.size() > 1) { - // Simulcast screenshare needs a simulcast encoder adapter to work, since - // encoders usually can't natively do simulcast with different frame rates - // for the different layers. - video_encoder_.reset( - new SimulcastEncoderAdapter(new InternalEncoderFactory())); + size_t total_streams_used = 0; + size_t num_flexfec_streams = params_.video[0].flexfec ? 1 : 0; + CreateAudioAndFecSendConfigs(0, num_flexfec_streams, send_transport); + CreateMatchingAudioAndFecConfigs(recv_transport); + video_receive_configs_.clear(); + video_send_configs_.clear(); + video_encoders_.clear(); + video_encoder_configs_.clear(); + allocated_decoders_.clear(); + bool decode_all_receive_streams = true; + size_t num_video_substreams = params_.ss[0].streams.size(); + RTC_CHECK(num_video_streams_ > 0); + video_encoder_configs_.resize(num_video_streams_); + for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) { + video_send_configs_.push_back(VideoSendStream::Config(send_transport)); + video_encoders_.push_back(nullptr); + video_encoder_configs_.push_back(VideoEncoderConfig()); + num_video_substreams = params_.ss[video_idx].streams.size(); + RTC_CHECK_GT(num_video_substreams, 0); + CreateVideoSendConfig(&video_send_configs_[video_idx], num_video_substreams, + total_streams_used, send_transport); + + int payload_type; + if (params_.video[video_idx].codec == "H264") { + video_encoders_[video_idx] = + H264Encoder::Create(cricket::VideoCodec("H264")); + payload_type = kPayloadTypeH264; + } else if (params_.video[video_idx].codec == "VP8") { + if (params_.screenshare[video_idx].enabled && + params_.ss[video_idx].streams.size() > 1) { + // Simulcast screenshare needs a simulcast encoder adapter to work, + // since encoders usually can't natively do simulcast with different + // frame rates for the different layers. + video_encoders_[video_idx].reset( + new SimulcastEncoderAdapter(new InternalEncoderFactory())); + } else { + video_encoders_[video_idx] = VP8Encoder::Create(); + } + payload_type = kPayloadTypeVP8; + } else if (params_.video[video_idx].codec == "VP9") { + video_encoders_[video_idx] = VP9Encoder::Create(); + payload_type = kPayloadTypeVP9; } else { - video_encoder_ = VP8Encoder::Create(); + RTC_NOTREACHED() << "Codec not supported!"; + return; + } + video_send_configs_[video_idx].encoder_settings.encoder = + video_encoders_[video_idx].get(); + video_send_configs_[video_idx].encoder_settings.payload_name = + params_.video[video_idx].codec; + video_send_configs_[video_idx].encoder_settings.payload_type = payload_type; + video_send_configs_[video_idx].rtp.nack.rtp_history_ms = kNackRtpHistoryMs; + video_send_configs_[video_idx].rtp.rtx.payload_type = kSendRtxPayloadType; + for (size_t i = 0; i < num_video_substreams; ++i) { + video_send_configs_[video_idx].rtp.rtx.ssrcs.push_back( + kSendRtxSsrcs[i + total_streams_used]); + } + video_send_configs_[video_idx].rtp.extensions.clear(); + if (params_.call.send_side_bwe) { + video_send_configs_[video_idx].rtp.extensions.push_back( + RtpExtension(RtpExtension::kTransportSequenceNumberUri, + test::kTransportSequenceNumberExtensionId)); + } else { + video_send_configs_[video_idx].rtp.extensions.push_back(RtpExtension( + RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId)); + } + video_send_configs_[video_idx].rtp.extensions.push_back( + RtpExtension(RtpExtension::kVideoContentTypeUri, + test::kVideoContentTypeExtensionId)); + video_send_configs_[video_idx].rtp.extensions.push_back(RtpExtension( + RtpExtension::kVideoTimingUri, test::kVideoTimingExtensionId)); + + video_encoder_configs_[video_idx].min_transmit_bitrate_bps = + params_.video[video_idx].min_transmit_bps; + + video_send_configs_[video_idx].suspend_below_min_bitrate = + params_.video[video_idx].suspend_below_min_bitrate; + + video_encoder_configs_[video_idx].number_of_streams = + params_.ss[video_idx].streams.size(); + video_encoder_configs_[video_idx].max_bitrate_bps = 0; + for (size_t i = 0; i < params_.ss[video_idx].streams.size(); ++i) { + video_encoder_configs_[video_idx].max_bitrate_bps += + params_.ss[video_idx].streams[i].max_bitrate_bps; + } + if (params_.ss[video_idx].infer_streams) { + video_encoder_configs_[video_idx].video_stream_factory = + new rtc::RefCountedObject<cricket::EncoderStreamFactory>( + params_.video[video_idx].codec, + params_.ss[video_idx].streams[0].max_qp, + params_.video[video_idx].fps, + params_.screenshare[video_idx].enabled, true); + } else { + video_encoder_configs_[video_idx].video_stream_factory = + new rtc::RefCountedObject<VideoStreamFactory>( + params_.ss[video_idx].streams); } - payload_type = kPayloadTypeVP8; - } else if (params_.video.codec == "VP9") { - video_encoder_ = VP9Encoder::Create(); - payload_type = kPayloadTypeVP9; - } else { - RTC_NOTREACHED() << "Codec not supported!"; - return; - } - video_send_config_.encoder_settings.encoder = video_encoder_.get(); - video_send_config_.encoder_settings.payload_name = params_.video.codec; - video_send_config_.encoder_settings.payload_type = payload_type; - video_send_config_.rtp.nack.rtp_history_ms = kNackRtpHistoryMs; - video_send_config_.rtp.rtx.payload_type = kSendRtxPayloadType; - for (size_t i = 0; i < num_video_streams; ++i) - video_send_config_.rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[i]); - - video_send_config_.rtp.extensions.clear(); - if (params_.call.send_side_bwe) { - video_send_config_.rtp.extensions.push_back( - RtpExtension(RtpExtension::kTransportSequenceNumberUri, - test::kTransportSequenceNumberExtensionId)); - } else { - video_send_config_.rtp.extensions.push_back(RtpExtension( - RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId)); - } - video_send_config_.rtp.extensions.push_back(RtpExtension( - RtpExtension::kVideoContentTypeUri, test::kVideoContentTypeExtensionId)); - video_send_config_.rtp.extensions.push_back(RtpExtension( - RtpExtension::kVideoTimingUri, test::kVideoTimingExtensionId)); - - video_encoder_config_.min_transmit_bitrate_bps = - params_.video.min_transmit_bps; - - video_send_config_.suspend_below_min_bitrate = - params_.video.suspend_below_min_bitrate; - - video_encoder_config_.number_of_streams = params_.ss.streams.size(); - video_encoder_config_.max_bitrate_bps = 0; - for (size_t i = 0; i < params_.ss.streams.size(); ++i) { - video_encoder_config_.max_bitrate_bps += - params_.ss.streams[i].max_bitrate_bps; - } - if (params_.ss.infer_streams) { - video_encoder_config_.video_stream_factory = - new rtc::RefCountedObject<cricket::EncoderStreamFactory>( - params_.video.codec, params_.ss.streams[0].max_qp, - params_.video.fps, params_.screenshare.enabled, true); - } else { - video_encoder_config_.video_stream_factory = - new rtc::RefCountedObject<VideoStreamFactory>(params_.ss.streams); - } - video_encoder_config_.spatial_layers = params_.ss.spatial_layers; - - 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]; - video_receive_configs_[i] - .rtp.rtx_associated_payload_types[kSendRtxPayloadType] = payload_type; - video_receive_configs_[i].rtp.transport_cc = params_.call.send_side_bwe; - video_receive_configs_[i].rtp.remb = !params_.call.send_side_bwe; - // 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 (!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; - decoder.payload_name = video_send_config_.encoder_settings.payload_name; - video_receive_configs_[i].decoders.clear(); - allocated_decoders_.emplace_back(decoder.decoder); - video_receive_configs_[i].decoders.push_back(decoder); + video_encoder_configs_[video_idx].spatial_layers = + params_.ss[video_idx].spatial_layers; + + std::vector<VideoReceiveStream::Config> new_receive_configs = + CreateMatchingVideoReceiveConfigs(video_send_configs_[video_idx], + recv_transport); + + decode_all_receive_streams = params_.ss[video_idx].selected_stream == + params_.ss[video_idx].streams.size(); + + for (size_t i = 0; i < num_video_substreams; ++i) { + new_receive_configs[i].rtp.nack.rtp_history_ms = kNackRtpHistoryMs; + new_receive_configs[i].rtp.rtx_ssrc = + kSendRtxSsrcs[i + total_streams_used]; + new_receive_configs[i] + .rtp.rtx_associated_payload_types[kSendRtxPayloadType] = payload_type; + new_receive_configs[i].rtp.transport_cc = params_.call.send_side_bwe; + new_receive_configs[i].rtp.remb = !params_.call.send_side_bwe; + // Enable RTT calculation so NTP time estimator will work. + new_receive_configs[i].rtp.rtcp_xr.receiver_reference_time_report = true; + // Force fake decoders on non-selected simulcast streams. + if (!decode_all_receive_streams && + i != params_.ss[video_idx].selected_stream) { + VideoReceiveStream::Decoder decoder; + decoder.decoder = new test::FakeDecoder(); + decoder.payload_type = + video_send_configs_[video_idx].encoder_settings.payload_type; + decoder.payload_name = + video_send_configs_[video_idx].encoder_settings.payload_name; + new_receive_configs[i].decoders.clear(); + allocated_decoders_.emplace_back(decoder.decoder); + new_receive_configs[i].decoders.push_back(decoder); + } + } + + for (VideoReceiveStream::Config& config : new_receive_configs) { + video_receive_configs_.push_back(config.Copy()); } + + if (params_.screenshare[video_idx].enabled) { + // Fill out codec settings. + video_encoder_configs_[video_idx].content_type = + VideoEncoderConfig::ContentType::kScreen; + degradation_preference_ = + VideoSendStream::DegradationPreference::kMaintainResolution; + if (params_.video[video_idx].codec == "VP8") { + VideoCodecVP8 vp8_settings = VideoEncoder::GetDefaultVp8Settings(); + vp8_settings.denoisingOn = false; + vp8_settings.frameDroppingOn = false; + vp8_settings.numberOfTemporalLayers = static_cast<unsigned char>( + params_.video[video_idx].num_temporal_layers); + video_encoder_configs_[video_idx].encoder_specific_settings = + new rtc::RefCountedObject< + VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings); + } else if (params_.video[video_idx].codec == "VP9") { + VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings(); + vp9_settings.denoisingOn = false; + vp9_settings.frameDroppingOn = false; + vp9_settings.numberOfTemporalLayers = static_cast<unsigned char>( + params_.video[video_idx].num_temporal_layers); + vp9_settings.numberOfSpatialLayers = static_cast<unsigned char>( + params_.ss[video_idx].num_spatial_layers); + video_encoder_configs_[video_idx].encoder_specific_settings = + new rtc::RefCountedObject< + VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings); + } + } else if (params_.ss[video_idx].num_spatial_layers > 1) { + // If SVC mode without screenshare, still need to set codec specifics. + RTC_CHECK(params_.video[video_idx].codec == "VP9"); + VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings(); + vp9_settings.numberOfTemporalLayers = static_cast<unsigned char>( + params_.video[video_idx].num_temporal_layers); + vp9_settings.numberOfSpatialLayers = + static_cast<unsigned char>(params_.ss[video_idx].num_spatial_layers); + video_encoder_configs_[video_idx].encoder_specific_settings = + new rtc::RefCountedObject< + VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings); + } + total_streams_used += num_video_substreams; } - if (params_.video.flexfec) { - // Override send config constructed by CreateSendConfig. + // FEC supported only for single video stream mode yet. + if (params_.video[0].flexfec) { + video_send_configs_[0].rtp.flexfec.payload_type = kFlexfecPayloadType; + video_send_configs_[0].rtp.flexfec.ssrc = kFlexfecSendSsrc; 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( + for (uint32_t media_ssrc : video_send_configs_[0].rtp.ssrcs) { + video_send_configs_[0].rtp.flexfec.protected_media_ssrcs.push_back( media_ssrc); } } else { - video_send_config_.rtp.flexfec.protected_media_ssrcs = { - kVideoSendSsrcs[params_.ss.selected_stream]}; + video_send_configs_[0].rtp.flexfec.protected_media_ssrcs = { + kVideoSendSsrcs[params_.ss[0].selected_stream]}; } // The matching receive config is _not_ created by @@ -1495,10 +1517,11 @@ void VideoQualityTest::SetupVideo(Transport* send_transport, // Set up the receive config manually instead. FlexfecReceiveStream::Config flexfec_receive_config(recv_transport); flexfec_receive_config.payload_type = - video_send_config_.rtp.flexfec.payload_type; - flexfec_receive_config.remote_ssrc = video_send_config_.rtp.flexfec.ssrc; + video_send_configs_[0].rtp.flexfec.payload_type; + flexfec_receive_config.remote_ssrc = + video_send_configs_[0].rtp.flexfec.ssrc; flexfec_receive_config.protected_media_ssrcs = - video_send_config_.rtp.flexfec.protected_media_ssrcs; + video_send_configs_[0].rtp.flexfec.protected_media_ssrcs; flexfec_receive_config.local_ssrc = kReceiverLocalVideoSsrc; flexfec_receive_config.transport_cc = params_.call.send_side_bwe; if (params_.call.send_side_bwe) { @@ -1510,37 +1533,38 @@ void VideoQualityTest::SetupVideo(Transport* send_transport, RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId)); } flexfec_receive_configs_.push_back(flexfec_receive_config); - if (num_video_streams > 0) { + if (num_video_substreams > 0) { video_receive_configs_[0].rtp.protected_by_flexfec = true; } } - if (params_.video.ulpfec) { - video_send_config_.rtp.ulpfec.red_payload_type = kRedPayloadType; - video_send_config_.rtp.ulpfec.ulpfec_payload_type = kUlpfecPayloadType; - video_send_config_.rtp.ulpfec.red_rtx_payload_type = kRtxRedPayloadType; + if (params_.video[0].ulpfec) { + video_send_configs_[0].rtp.ulpfec.red_payload_type = kRedPayloadType; + video_send_configs_[0].rtp.ulpfec.ulpfec_payload_type = kUlpfecPayloadType; + video_send_configs_[0].rtp.ulpfec.red_rtx_payload_type = kRtxRedPayloadType; if (decode_all_receive_streams) { for (auto it = video_receive_configs_.begin(); it != video_receive_configs_.end(); ++it) { it->rtp.red_payload_type = - video_send_config_.rtp.ulpfec.red_payload_type; + video_send_configs_[0].rtp.ulpfec.red_payload_type; it->rtp.ulpfec_payload_type = - video_send_config_.rtp.ulpfec.ulpfec_payload_type; - it->rtp.rtx_associated_payload_types[video_send_config_.rtp.ulpfec - .red_rtx_payload_type] = - video_send_config_.rtp.ulpfec.red_payload_type; + video_send_configs_[0].rtp.ulpfec.ulpfec_payload_type; + it->rtp.rtx_associated_payload_types + [video_send_configs_[0].rtp.ulpfec.red_rtx_payload_type] = + video_send_configs_[0].rtp.ulpfec.red_payload_type; } } else { - video_receive_configs_[params_.ss.selected_stream].rtp.red_payload_type = - video_send_config_.rtp.ulpfec.red_payload_type; - video_receive_configs_[params_.ss.selected_stream] + video_receive_configs_[params_.ss[0].selected_stream] + .rtp.red_payload_type = + video_send_configs_[0].rtp.ulpfec.red_payload_type; + video_receive_configs_[params_.ss[0].selected_stream] .rtp.ulpfec_payload_type = - video_send_config_.rtp.ulpfec.ulpfec_payload_type; - video_receive_configs_[params_.ss.selected_stream] - .rtp.rtx_associated_payload_types[video_send_config_.rtp.ulpfec - .red_rtx_payload_type] = - video_send_config_.rtp.ulpfec.red_payload_type; + video_send_configs_[0].rtp.ulpfec.ulpfec_payload_type; + video_receive_configs_[params_.ss[0].selected_stream] + .rtp.rtx_associated_payload_types + [video_send_configs_[0].rtp.ulpfec.red_rtx_payload_type] = + video_send_configs_[0].rtp.ulpfec.red_payload_type; } } } @@ -1556,7 +1580,8 @@ void VideoQualityTest::SetupThumbnails(Transport* send_transport, thumbnail_send_config.rtp.ssrcs.push_back(kThumbnailSendSsrcStart + i); thumbnail_send_config.encoder_settings.encoder = thumbnail_encoders_.back().get(); - thumbnail_send_config.encoder_settings.payload_name = params_.video.codec; + thumbnail_send_config.encoder_settings.payload_name = + params_.video[0].codec; thumbnail_send_config.encoder_settings.payload_type = kPayloadTypeVP8; thumbnail_send_config.rtp.nack.rtp_history_ms = kNackRtpHistoryMs; thumbnail_send_config.rtp.rtx.payload_type = kSendRtxPayloadType; @@ -1574,19 +1599,19 @@ void VideoQualityTest::SetupThumbnails(Transport* send_transport, VideoEncoderConfig thumbnail_encoder_config; thumbnail_encoder_config.min_transmit_bitrate_bps = 7500; thumbnail_send_config.suspend_below_min_bitrate = - params_.video.suspend_below_min_bitrate; + params_.video[0].suspend_below_min_bitrate; thumbnail_encoder_config.number_of_streams = 1; thumbnail_encoder_config.max_bitrate_bps = 50000; - if (params_.ss.infer_streams) { + if (params_.ss[0].infer_streams) { thumbnail_encoder_config.video_stream_factory = - new rtc::RefCountedObject<VideoStreamFactory>(params_.ss.streams); + new rtc::RefCountedObject<VideoStreamFactory>(params_.ss[0].streams); } else { thumbnail_encoder_config.video_stream_factory = new rtc::RefCountedObject<cricket::EncoderStreamFactory>( - params_.video.codec, params_.ss.streams[0].max_qp, - params_.video.fps, params_.screenshare.enabled, true); + params_.video[0].codec, params_.ss[0].streams[0].max_qp, + params_.video[0].fps, params_.screenshare[0].enabled, true); } - thumbnail_encoder_config.spatial_layers = params_.ss.spatial_layers; + thumbnail_encoder_config.spatial_layers = params_.ss[0].spatial_layers; VideoReceiveStream::Config thumbnail_receive_config(send_transport); thumbnail_receive_config.rtp.remb = false; @@ -1627,12 +1652,14 @@ void VideoQualityTest::SetupThumbnails(Transport* send_transport, } void VideoQualityTest::DestroyThumbnailStreams() { - for (VideoSendStream* thumbnail_send_stream : thumbnail_send_streams_) + for (VideoSendStream* thumbnail_send_stream : thumbnail_send_streams_) { receiver_call_->DestroyVideoSendStream(thumbnail_send_stream); + } thumbnail_send_streams_.clear(); for (VideoReceiveStream* thumbnail_receive_stream : - thumbnail_receive_streams_) + thumbnail_receive_streams_) { sender_call_->DestroyVideoReceiveStream(thumbnail_receive_stream); + } thumbnail_send_streams_.clear(); thumbnail_receive_streams_.clear(); for (std::unique_ptr<test::VideoCapturer>& video_caputurer : @@ -1641,85 +1668,6 @@ void VideoQualityTest::DestroyThumbnailStreams() { } } -void VideoQualityTest::SetupScreenshareOrSVC() { - if (params_.screenshare.enabled) { - // Fill out codec settings. - video_encoder_config_.content_type = - VideoEncoderConfig::ContentType::kScreen; - degradation_preference_ = - VideoSendStream::DegradationPreference::kMaintainResolution; - if (params_.video.codec == "VP8") { - VideoCodecVP8 vp8_settings = VideoEncoder::GetDefaultVp8Settings(); - vp8_settings.denoisingOn = false; - vp8_settings.frameDroppingOn = false; - vp8_settings.numberOfTemporalLayers = - static_cast<unsigned char>(params_.video.num_temporal_layers); - video_encoder_config_.encoder_specific_settings = - new rtc::RefCountedObject< - VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings); - } else if (params_.video.codec == "VP9") { - VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings(); - vp9_settings.denoisingOn = false; - vp9_settings.frameDroppingOn = false; - vp9_settings.numberOfTemporalLayers = - static_cast<unsigned char>(params_.video.num_temporal_layers); - vp9_settings.numberOfSpatialLayers = - static_cast<unsigned char>(params_.ss.num_spatial_layers); - video_encoder_config_.encoder_specific_settings = - new rtc::RefCountedObject< - VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings); - } - // Setup frame generator. - const size_t kWidth = 1850; - const size_t kHeight = 1110; - if (params_.screenshare.generate_slides) { - frame_generator_ = test::FrameGenerator::CreateSlideGenerator( - kWidth, kHeight, - params_.screenshare.slide_change_interval * params_.video.fps); - } else { - std::vector<std::string> slides = params_.screenshare.slides; - if (slides.size() == 0) { - slides.push_back(test::ResourcePath("web_screenshot_1850_1110", "yuv")); - slides.push_back(test::ResourcePath("presentation_1850_1110", "yuv")); - slides.push_back(test::ResourcePath("photo_1850_1110", "yuv")); - slides.push_back( - test::ResourcePath("difficult_photo_1850_1110", "yuv")); - } - if (params_.screenshare.scroll_duration == 0) { - // Cycle image every slide_change_interval seconds. - frame_generator_ = test::FrameGenerator::CreateFromYuvFile( - slides, kWidth, kHeight, - params_.screenshare.slide_change_interval * params_.video.fps); - } else { - RTC_CHECK_LE(params_.video.width, kWidth); - RTC_CHECK_LE(params_.video.height, kHeight); - RTC_CHECK_GT(params_.screenshare.slide_change_interval, 0); - const int kPauseDurationMs = - (params_.screenshare.slide_change_interval - - params_.screenshare.scroll_duration) * - 1000; - RTC_CHECK_LE(params_.screenshare.scroll_duration, - params_.screenshare.slide_change_interval); - - frame_generator_ = - test::FrameGenerator::CreateScrollingInputFromYuvFiles( - clock_, slides, kWidth, kHeight, params_.video.width, - params_.video.height, - params_.screenshare.scroll_duration * 1000, kPauseDurationMs); - } - } - } else if (params_.ss.num_spatial_layers > 1) { // For non-screenshare case. - RTC_CHECK(params_.video.codec == "VP9"); - VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings(); - vp9_settings.numberOfTemporalLayers = - static_cast<unsigned char>(params_.video.num_temporal_layers); - vp9_settings.numberOfSpatialLayers = - static_cast<unsigned char>(params_.ss.num_spatial_layers); - video_encoder_config_.encoder_specific_settings = new rtc::RefCountedObject< - VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings); - } -} - void VideoQualityTest::SetupThumbnailCapturers(size_t num_thumbnail_streams) { VideoStream thumbnail = DefaultThumbnailStream(); for (size_t i = 0; i < num_thumbnail_streams; ++i) { @@ -1730,47 +1678,106 @@ void VideoQualityTest::SetupThumbnailCapturers(size_t num_thumbnail_streams) { } } -void VideoQualityTest::CreateCapturer() { - if (params_.screenshare.enabled) { - test::FrameGeneratorCapturer* frame_generator_capturer = - new test::FrameGeneratorCapturer(clock_, std::move(frame_generator_), - params_.video.fps); - EXPECT_TRUE(frame_generator_capturer->Init()); - video_capturer_.reset(frame_generator_capturer); +std::unique_ptr<test::FrameGenerator> VideoQualityTest::CreateFrameGenerator( + size_t video_idx) { + // Setup frame generator. + const size_t kWidth = 1850; + const size_t kHeight = 1110; + std::unique_ptr<test::FrameGenerator> frame_generator; + if (params_.screenshare[video_idx].generate_slides) { + frame_generator = test::FrameGenerator::CreateSlideGenerator( + kWidth, kHeight, + params_.screenshare[video_idx].slide_change_interval * + params_.video[video_idx].fps); } else { - if (params_.video.clip_name == "Generator") { - video_capturer_.reset(test::FrameGeneratorCapturer::Create( - static_cast<int>(params_.video.width), - static_cast<int>(params_.video.height), params_.video.fps, clock_)); - } else if (params_.video.clip_name.empty()) { - video_capturer_.reset(test::VcmCapturer::Create( - params_.video.width, params_.video.height, params_.video.fps, - params_.video.capture_device_index)); - if (!video_capturer_) { - // Failed to get actual camera, use chroma generator as backup. - video_capturer_.reset(test::FrameGeneratorCapturer::Create( - static_cast<int>(params_.video.width), - static_cast<int>(params_.video.height), params_.video.fps, clock_)); - } + std::vector<std::string> slides = params_.screenshare[video_idx].slides; + if (slides.size() == 0) { + slides.push_back(test::ResourcePath("web_screenshot_1850_1110", "yuv")); + slides.push_back(test::ResourcePath("presentation_1850_1110", "yuv")); + slides.push_back(test::ResourcePath("photo_1850_1110", "yuv")); + slides.push_back(test::ResourcePath("difficult_photo_1850_1110", "yuv")); + } + if (params_.screenshare[video_idx].scroll_duration == 0) { + // Cycle image every slide_change_interval seconds. + frame_generator = test::FrameGenerator::CreateFromYuvFile( + slides, kWidth, kHeight, + params_.screenshare[video_idx].slide_change_interval * + params_.video[video_idx].fps); } else { - video_capturer_.reset(test::FrameGeneratorCapturer::CreateFromYuvFile( - test::ResourcePath(params_.video.clip_name, "yuv"), - params_.video.width, params_.video.height, params_.video.fps, - clock_)); - ASSERT_TRUE(video_capturer_) << "Could not create capturer for " - << params_.video.clip_name - << ".yuv. Is this resource file present?"; + RTC_CHECK_LE(params_.video[video_idx].width, kWidth); + RTC_CHECK_LE(params_.video[video_idx].height, kHeight); + RTC_CHECK_GT(params_.screenshare[video_idx].slide_change_interval, 0); + const int kPauseDurationMs = + (params_.screenshare[video_idx].slide_change_interval - + params_.screenshare[video_idx].scroll_duration) * + 1000; + RTC_CHECK_LE(params_.screenshare[video_idx].scroll_duration, + params_.screenshare[video_idx].slide_change_interval); + + frame_generator = test::FrameGenerator::CreateScrollingInputFromYuvFiles( + clock_, slides, kWidth, kHeight, params_.video[video_idx].width, + params_.video[video_idx].height, + params_.screenshare[video_idx].scroll_duration * 1000, + kPauseDurationMs); } } - RTC_DCHECK(video_capturer_.get()); + return frame_generator; +} + +void VideoQualityTest::CreateCapturers() { + video_capturers_.resize(num_video_streams_); + for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) { + if (params_.screenshare[video_idx].enabled) { + std::unique_ptr<test::FrameGenerator> frame_generator = + CreateFrameGenerator(video_idx); + test::FrameGeneratorCapturer* frame_generator_capturer = + new test::FrameGeneratorCapturer(clock_, std::move(frame_generator), + params_.video[video_idx].fps); + EXPECT_TRUE(frame_generator_capturer->Init()); + video_capturers_[video_idx].reset(frame_generator_capturer); + } else { + if (params_.video[video_idx].clip_name == "Generator") { + video_capturers_[video_idx].reset(test::FrameGeneratorCapturer::Create( + static_cast<int>(params_.video[video_idx].width), + static_cast<int>(params_.video[video_idx].height), + params_.video[video_idx].fps, clock_)); + } else if (params_.video[video_idx].clip_name.empty()) { + video_capturers_[video_idx].reset(test::VcmCapturer::Create( + params_.video[video_idx].width, params_.video[video_idx].height, + params_.video[video_idx].fps, + params_.video[video_idx].capture_device_index)); + if (!video_capturers_[video_idx]) { + // Failed to get actual camera, use chroma generator as backup. + video_capturers_[video_idx].reset( + test::FrameGeneratorCapturer::Create( + static_cast<int>(params_.video[video_idx].width), + static_cast<int>(params_.video[video_idx].height), + params_.video[video_idx].fps, clock_)); + } + } else { + video_capturers_[video_idx].reset( + test::FrameGeneratorCapturer::CreateFromYuvFile( + test::ResourcePath(params_.video[video_idx].clip_name, "yuv"), + params_.video[video_idx].width, params_.video[video_idx].height, + params_.video[video_idx].fps, clock_)); + ASSERT_TRUE(video_capturers_[video_idx]) + << "Could not create capturer for " + << params_.video[video_idx].clip_name + << ".yuv. Is this resource file present?"; + } + } + RTC_DCHECK(video_capturers_[video_idx].get()); + } } std::unique_ptr<test::LayerFilteringTransport> VideoQualityTest::CreateSendTransport() { return rtc::MakeUnique<test::LayerFilteringTransport>( &task_queue_, params_.pipe, sender_call_.get(), kPayloadTypeVP8, - kPayloadTypeVP9, params_.video.selected_tl, params_.ss.selected_sl, - payload_type_map_); + kPayloadTypeVP9, params_.video[0].selected_tl, params_.ss[0].selected_sl, + payload_type_map_, kVideoSendSsrcs[0], + static_cast<uint32_t>(kVideoSendSsrcs[0] + params_.ss[0].streams.size() - + 1)); } std::unique_ptr<test::DirectTransport> @@ -1779,7 +1786,31 @@ VideoQualityTest::CreateReceiveTransport() { &task_queue_, params_.pipe, receiver_call_.get(), payload_type_map_); } +void VideoQualityTest::CreateVideoStreams() { + RTC_DCHECK(video_send_streams_.empty()); + RTC_DCHECK(video_receive_streams_.empty()); + RTC_DCHECK_EQ(video_send_configs_.size(), num_video_streams_); + for (size_t i = 0; i < video_send_configs_.size(); ++i) { + video_send_streams_.push_back(sender_call_->CreateVideoSendStream( + video_send_configs_[i].Copy(), video_encoder_configs_[i].Copy())); + } + for (size_t i = 0; i < video_receive_configs_.size(); ++i) { + video_receive_streams_.push_back(receiver_call_->CreateVideoReceiveStream( + video_receive_configs_[i].Copy())); + } + + AssociateFlexfecStreamsWithVideoStreams(); +} + +void VideoQualityTest::DestroyStreams() { + CallTest::DestroyStreams(); + + for (VideoSendStream* video_send_stream : video_send_streams_) + sender_call_->DestroyVideoSendStream(video_send_stream); +} + void VideoQualityTest::RunWithAnalyzer(const Params& params) { + num_video_streams_ = params.call.dual_video ? 2 : 1; std::unique_ptr<test::LayerFilteringTransport> send_transport; std::unique_ptr<test::DirectTransport> recv_transport; FILE* graph_data_output_file = nullptr; @@ -1801,24 +1832,40 @@ void VideoQualityTest::RunWithAnalyzer(const Params& params) { } if (!params.logging.rtc_event_log_name.empty()) { - event_log_ = RtcEventLog::Create(clock_, RtcEventLog::EncodingType::Legacy); - std::unique_ptr<RtcEventLogOutputFile> output( + send_event_log_ = + RtcEventLog::Create(clock_, RtcEventLog::EncodingType::Legacy); + recv_event_log_ = + RtcEventLog::Create(clock_, RtcEventLog::EncodingType::Legacy); + std::unique_ptr<RtcEventLogOutputFile> send_output( + rtc::MakeUnique<RtcEventLogOutputFile>( + params.logging.rtc_event_log_name + "_send", + RtcEventLog::kUnlimitedOutput)); + std::unique_ptr<RtcEventLogOutputFile> recv_output( rtc::MakeUnique<RtcEventLogOutputFile>( - params.logging.rtc_event_log_name, RtcEventLog::kUnlimitedOutput)); - bool event_log_started = event_log_->StartLogging( - std::move(output), RtcEventLog::kImmediateOutput); + params.logging.rtc_event_log_name + "_recv", + RtcEventLog::kUnlimitedOutput)); + bool event_log_started = + send_event_log_->StartLogging(std::move(send_output), + RtcEventLog::kImmediateOutput) && + recv_event_log_->StartLogging(std::move(recv_output), + RtcEventLog::kImmediateOutput); RTC_DCHECK(event_log_started); + } else { + send_event_log_ = RtcEventLog::CreateNull(); + recv_event_log_ = RtcEventLog::CreateNull(); } - Call::Config call_config(event_log_.get()); - call_config.bitrate_config = params.call.call_bitrate_config; + Call::Config send_call_config(send_event_log_.get()); + Call::Config recv_call_config(recv_event_log_.get()); + send_call_config.bitrate_config = params.call.call_bitrate_config; + recv_call_config.bitrate_config = params.call.call_bitrate_config; - task_queue_.SendTask( - [this, &call_config, &send_transport, &recv_transport]() { - CreateCalls(call_config, call_config); - send_transport = CreateSendTransport(); - recv_transport = CreateReceiveTransport(); - }); + task_queue_.SendTask([this, &send_call_config, &recv_call_config, + &send_transport, &recv_transport]() { + CreateCalls(send_call_config, recv_call_config); + send_transport = CreateSendTransport(); + recv_transport = CreateReceiveTransport(); + }); std::string graph_title = params_.analyzer.graph_title; if (graph_title.empty()) @@ -1829,13 +1876,13 @@ void VideoQualityTest::RunWithAnalyzer(const Params& params) { params_.analyzer.avg_psnr_threshold, params_.analyzer.avg_ssim_threshold, is_quick_test_enabled ? kFramesSentInQuickTest - : params_.analyzer.test_durations_secs * params_.video.fps, + : params_.analyzer.test_durations_secs * params_.video[0].fps, graph_data_output_file, graph_title, - kVideoSendSsrcs[params_.ss.selected_stream], - kSendRtxSsrcs[params_.ss.selected_stream], - static_cast<size_t>(params_.ss.selected_stream), params.ss.selected_sl, - params_.video.selected_tl, is_quick_test_enabled, clock_, - params_.logging.rtp_dump_name); + kVideoSendSsrcs[params_.ss[0].selected_stream], + kSendRtxSsrcs[params_.ss[0].selected_stream], + static_cast<size_t>(params_.ss[0].selected_stream), + params.ss[0].selected_sl, params_.video[0].selected_tl, + is_quick_test_enabled, clock_, params_.logging.rtp_dump_name); task_queue_.SendTask([&]() { analyzer->SetCall(sender_call_.get()); @@ -1845,36 +1892,41 @@ void VideoQualityTest::RunWithAnalyzer(const Params& params) { SetupVideo(analyzer.get(), recv_transport.get()); SetupThumbnails(analyzer.get(), recv_transport.get()); - video_receive_configs_[params_.ss.selected_stream].renderer = + video_receive_configs_[params_.ss[0].selected_stream].renderer = analyzer.get(); - video_send_config_.pre_encode_callback = analyzer->pre_encode_proxy(); - RTC_DCHECK(!video_send_config_.post_encode_callback); - video_send_config_.post_encode_callback = analyzer->encode_timing_proxy(); - - SetupScreenshareOrSVC(); + video_send_configs_[0].pre_encode_callback = analyzer->pre_encode_proxy(); + RTC_DCHECK(!video_send_configs_[0].post_encode_callback); + video_send_configs_[0].post_encode_callback = + analyzer->encode_timing_proxy(); CreateFlexfecStreams(); CreateVideoStreams(); - analyzer->SetSendStream(video_send_stream_); + analyzer->SetSendStream(video_send_streams_[0]); if (video_receive_streams_.size() == 1) analyzer->SetReceiveStream(video_receive_streams_[0]); - video_send_stream_->SetSource(analyzer->OutputInterface(), - degradation_preference_); - + video_send_streams_[0]->SetSource(analyzer->OutputInterface(), + degradation_preference_); SetupThumbnailCapturers(params_.call.num_thumbnails); for (size_t i = 0; i < thumbnail_send_streams_.size(); ++i) { thumbnail_send_streams_[i]->SetSource(thumbnail_capturers_[i].get(), degradation_preference_); } - CreateCapturer(); + CreateCapturers(); - analyzer->SetSource(video_capturer_.get(), params_.ss.infer_streams); + analyzer->SetSource(video_capturers_[0].get(), params_.ss[0].infer_streams); - StartEncodedFrameLogs(video_send_stream_); - StartEncodedFrameLogs(video_receive_streams_[params_.ss.selected_stream]); - video_send_stream_->Start(); + for (size_t video_idx = 1; video_idx < num_video_streams_; ++video_idx) { + video_send_streams_[video_idx]->SetSource( + video_capturers_[video_idx].get(), degradation_preference_); + } + + StartEncodedFrameLogs(video_send_streams_[0]); + StartEncodedFrameLogs( + video_receive_streams_[params_.ss[0].selected_stream]); + for (VideoSendStream* video_send_stream : video_send_streams_) + video_send_stream->Start(); for (VideoSendStream* thumbnail_send_stream : thumbnail_send_streams_) thumbnail_send_stream->Start(); for (VideoReceiveStream* receive_stream : video_receive_streams_) @@ -1885,7 +1937,9 @@ void VideoQualityTest::RunWithAnalyzer(const Params& params) { analyzer->StartMeasuringCpuProcessTime(); - video_capturer_->Start(); + for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) { + video_capturers_[video_idx]->Start(); + } for (std::unique_ptr<test::VideoCapturer>& video_caputurer : thumbnail_capturers_) { video_caputurer->Start(); @@ -1900,7 +1954,9 @@ void VideoQualityTest::RunWithAnalyzer(const Params& params) { for (std::unique_ptr<test::VideoCapturer>& video_caputurer : thumbnail_capturers_) video_caputurer->Stop(); - video_capturer_->Stop(); + for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) { + video_capturers_[video_idx]->Stop(); + } for (VideoReceiveStream* thumbnail_receive_stream : thumbnail_receive_streams_) thumbnail_receive_stream->Stop(); @@ -1908,7 +1964,8 @@ void VideoQualityTest::RunWithAnalyzer(const Params& params) { receive_stream->Stop(); for (VideoSendStream* thumbnail_send_stream : thumbnail_send_streams_) thumbnail_send_stream->Stop(); - video_send_stream_->Stop(); + for (VideoSendStream* video_send_stream : video_send_streams_) + video_send_stream->Stop(); DestroyStreams(); DestroyThumbnailStreams(); @@ -1916,7 +1973,7 @@ void VideoQualityTest::RunWithAnalyzer(const Params& params) { if (graph_data_output_file) fclose(graph_data_output_file); - video_capturer_.reset(); + video_capturers_.clear(); send_transport.reset(); recv_transport.reset(); @@ -1924,12 +1981,9 @@ void VideoQualityTest::RunWithAnalyzer(const Params& params) { }); } -void VideoQualityTest::SetupAudio(int send_channel_id, - int receive_channel_id, - Transport* transport, +void VideoQualityTest::SetupAudio(Transport* transport, AudioReceiveStream** audio_receive_stream) { audio_send_config_ = AudioSendStream::Config(transport); - audio_send_config_.voe_channel_id = send_channel_id; audio_send_config_.rtp.ssrc = kAudioSendSsrc; // Add extension to enable audio send side BWE, and allow audio bit rate @@ -1942,25 +1996,23 @@ void VideoQualityTest::SetupAudio(int send_channel_id, audio_send_config_.min_bitrate_bps = kOpusMinBitrateBps; audio_send_config_.max_bitrate_bps = kOpusBitrateFbBps; } - audio_send_config_.send_codec_spec = - rtc::Optional<AudioSendStream::Config::SendCodecSpec>( - {kAudioSendPayloadType, - {"OPUS", 48000, 2, - {{"usedtx", (params_.audio.dtx ? "1" : "0")}, - {"stereo", "1"}}}}); + audio_send_config_.send_codec_spec = AudioSendStream::Config::SendCodecSpec( + kAudioSendPayloadType, + {"OPUS", 48000, 2, + {{"usedtx", (params_.audio.dtx ? "1" : "0")}, + {"stereo", "1"}}}); audio_send_config_.encoder_factory = encoder_factory_; audio_send_stream_ = sender_call_->CreateAudioSendStream(audio_send_config_); AudioReceiveStream::Config audio_config; audio_config.rtp.local_ssrc = kReceiverLocalAudioSsrc; audio_config.rtcp_send_transport = transport; - audio_config.voe_channel_id = receive_channel_id; audio_config.rtp.remote_ssrc = audio_send_config_.rtp.ssrc; audio_config.rtp.transport_cc = params_.call.send_side_bwe; audio_config.rtp.extensions = audio_send_config_.rtp.extensions; audio_config.decoder_factory = decoder_factory_; audio_config.decoder_map = {{kAudioSendPayloadType, {"OPUS", 48000, 2}}}; - if (params_.video.enabled && params_.audio.sync_video) + if (params_.video[0].enabled && params_.audio.sync_video) audio_config.sync_group = kSyncGroup; *audio_receive_stream = @@ -1968,10 +2020,9 @@ void VideoQualityTest::SetupAudio(int send_channel_id, } void VideoQualityTest::RunWithRenderers(const Params& params) { + num_video_streams_ = params.call.dual_video ? 2 : 1; std::unique_ptr<test::LayerFilteringTransport> send_transport; std::unique_ptr<test::DirectTransport> recv_transport; - std::unique_ptr<test::FakeAudioDevice> fake_audio_device; - ::VoiceEngineState voe; std::unique_ptr<test::VideoRenderer> local_preview; std::vector<std::unique_ptr<test::VideoRenderer>> loopback_renderers; AudioReceiveStream* audio_receive_stream = nullptr; @@ -1985,21 +2036,17 @@ void VideoQualityTest::RunWithRenderers(const Params& params) { Call::Config call_config(event_log_.get()); call_config.bitrate_config = params_.call.call_bitrate_config; - fake_audio_device.reset(new test::FakeAudioDevice( - test::FakeAudioDevice::CreatePulsedNoiseCapturer(32000, 48000), - test::FakeAudioDevice::CreateDiscardRenderer(48000), - 1.f)); - - rtc::scoped_refptr<webrtc::AudioProcessing> audio_processing( - webrtc::AudioProcessing::Create()); + rtc::scoped_refptr<test::FakeAudioDevice> fake_audio_device = + new rtc::RefCountedObject<test::FakeAudioDevice>( + test::FakeAudioDevice::CreatePulsedNoiseCapturer(32000, 48000), + test::FakeAudioDevice::CreateDiscardRenderer(48000), + 1.f); if (params_.audio.enabled) { - CreateVoiceEngine(&voe, fake_audio_device.get(), audio_processing.get(), - decoder_factory_); AudioState::Config audio_state_config; - audio_state_config.voice_engine = voe.voice_engine; audio_state_config.audio_mixer = AudioMixerImpl::Create(); - audio_state_config.audio_processing = audio_processing; + audio_state_config.audio_processing = AudioProcessingBuilder().Create(); + audio_state_config.audio_device_module = fake_audio_device; call_config.audio_state = AudioState::Create(audio_state_config); fake_audio_device->RegisterAudioCallback( call_config.audio_state->audio_transport()); @@ -2009,13 +2056,9 @@ void VideoQualityTest::RunWithRenderers(const Params& params) { // TODO(minyue): consider if this is a good transport even for audio only // calls. - send_transport = rtc::MakeUnique<test::LayerFilteringTransport>( - &task_queue_, params.pipe, sender_call_.get(), kPayloadTypeVP8, - kPayloadTypeVP9, params.video.selected_tl, params_.ss.selected_sl, - payload_type_map_); + send_transport = CreateSendTransport(); - recv_transport = rtc::MakeUnique<test::DirectTransport>( - &task_queue_, params_.pipe, receiver_call_.get(), payload_type_map_); + recv_transport = CreateReceiveTransport(); // 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 @@ -2023,81 +2066,82 @@ void VideoQualityTest::RunWithRenderers(const Params& params) { send_transport->SetReceiver(receiver_call_->Receiver()); recv_transport->SetReceiver(sender_call_->Receiver()); - if (params_.video.enabled) { + if (params_.video[0].enabled) { // Create video renderers. local_preview.reset(test::VideoRenderer::Create( - "Local Preview", params_.video.width, params_.video.height)); - - const size_t selected_stream_id = params_.ss.selected_stream; - const size_t num_streams = params_.ss.streams.size(); + "Local Preview", params_.video[0].width, params_.video[0].height)); - if (selected_stream_id == num_streams) { - for (size_t stream_id = 0; stream_id < num_streams; ++stream_id) { + SetupVideo(send_transport.get(), recv_transport.get()); + video_send_configs_[0].pre_encode_callback = local_preview.get(); + + size_t num_streams_processed = 0; + for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) { + const size_t selected_stream_id = params_.ss[video_idx].selected_stream; + const size_t num_streams = params_.ss[video_idx].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 #" << video_idx << " - Stream #" + << static_cast<int>(stream_id); + loopback_renderers.emplace_back(test::VideoRenderer::Create( + oss.str().c_str(), + params_.ss[video_idx].streams[stream_id].width, + params_.ss[video_idx].streams[stream_id].height)); + video_receive_configs_[stream_id + num_streams_processed].renderer = + loopback_renderers.back().get(); + if (params_.audio.enabled && params_.audio.sync_video) + video_receive_configs_[stream_id + num_streams_processed] + .sync_group = kSyncGroup; + } + } else { std::ostringstream oss; - oss << "Loopback Video - Stream #" << static_cast<int>(stream_id); + oss << "Loopback Video #" << video_idx; 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)); - } - - SetupVideo(send_transport.get(), recv_transport.get()); - - video_send_config_.pre_encode_callback = local_preview.get(); - 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(); + oss.str().c_str(), + params_.ss[video_idx].streams[selected_stream_id].width, + params_.ss[video_idx].streams[selected_stream_id].height)); + video_receive_configs_[selected_stream_id + num_streams_processed] + .renderer = loopback_renderers.back().get(); if (params_.audio.enabled && params_.audio.sync_video) - video_receive_configs_[stream_id].sync_group = kSyncGroup; + video_receive_configs_[num_streams_processed + selected_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; + num_streams_processed += num_streams; } - - SetupScreenshareOrSVC(); - CreateFlexfecStreams(); CreateVideoStreams(); - CreateCapturer(); - video_send_stream_->SetSource(video_capturer_.get(), - degradation_preference_); + CreateCapturers(); + for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) { + video_send_streams_[video_idx]->SetSource( + video_capturers_[video_idx].get(), degradation_preference_); + } } if (params_.audio.enabled) { - SetupAudio(voe.send_channel_id, voe.receive_channel_id, - send_transport.get(), &audio_receive_stream); + SetupAudio(send_transport.get(), &audio_receive_stream); } for (VideoReceiveStream* receive_stream : video_receive_streams_) StartEncodedFrameLogs(receive_stream); - StartEncodedFrameLogs(video_send_stream_); + StartEncodedFrameLogs(video_send_streams_[0]); // Start sending and receiving video. - if (params_.video.enabled) { + if (params_.video[0].enabled) { for (VideoReceiveStream* video_receive_stream : video_receive_streams_) video_receive_stream->Start(); - - video_send_stream_->Start(); - video_capturer_->Start(); + for (VideoSendStream* video_send_stream : video_send_streams_) + video_send_stream->Start(); + for (auto& video_capturer : video_capturers_) + video_capturer->Start(); } if (params_.audio.enabled) { // Start receiving audio. audio_receive_stream->Start(); - EXPECT_EQ(0, voe.base->StartPlayout(voe.receive_channel_id)); // Start sending audio. audio_send_stream_->Start(); - EXPECT_EQ(0, voe.base->StartSend(voe.send_channel_id)); } }); @@ -2106,42 +2150,25 @@ void VideoQualityTest::RunWithRenderers(const Params& params) { task_queue_.SendTask([&]() { if (params_.audio.enabled) { // Stop sending audio. - EXPECT_EQ(0, voe.base->StopSend(voe.send_channel_id)); audio_send_stream_->Stop(); // Stop receiving audio. - EXPECT_EQ(0, voe.base->StopPlayout(voe.receive_channel_id)); audio_receive_stream->Stop(); - 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(); - for (FlexfecReceiveStream* flexfec_receive_stream : - flexfec_receive_streams_) { - for (VideoReceiveStream* video_receive_stream : - video_receive_streams_) { - video_receive_stream->RemoveSecondarySink(flexfec_receive_stream); - } - receiver_call_->DestroyFlexfecReceiveStream(flexfec_receive_stream); - } - for (VideoReceiveStream* receive_stream : video_receive_streams_) { - receive_stream->Stop(); - receiver_call_->DestroyVideoReceiveStream(receive_stream); - } - sender_call_->DestroyVideoSendStream(video_send_stream_); + if (params_.video[0].enabled) { + for (auto& video_capturer : video_capturers_) + video_capturer->Stop(); + for (VideoSendStream* video_send_stream : video_send_streams_) + video_send_stream->Stop(); + DestroyStreams(); } - video_capturer_.reset(); + video_capturers_.clear(); send_transport.reset(); recv_transport.reset(); - if (params_.audio.enabled) - DestroyVoiceEngine(&voe); - local_preview.reset(); loopback_renderers.clear(); |