From 3bd2c7976b6973833909fffbecfdb4cfdd0ed07e Mon Sep 17 00:00:00 2001 From: Sebastian Jansson Date: Fri, 13 Jul 2018 13:29:03 +0200 Subject: [PATCH] Moving functionality from VideoQualityTest to CallTest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: webrtc:9510 Change-Id: Ie1cd34693e08d2c4b8fd79470573a6069564ded5 Reviewed-on: https://webrtc-review.googlesource.com/88182 Commit-Queue: Sebastian Jansson Reviewed-by: Erik Språng Cr-Commit-Position: refs/heads/master@{#23969} --- test/call_test.cc | 313 ++++++++++++++++++++++++++---------- test/call_test.h | 55 +++++-- video/video_quality_test.cc | 311 ++++++++--------------------------- video/video_quality_test.h | 15 +- 4 files changed, 342 insertions(+), 352 deletions(-) diff --git a/test/call_test.cc b/test/call_test.cc index 641f03c3d6..99bedaaf84 100644 --- a/test/call_test.cc +++ b/test/call_test.cc @@ -47,15 +47,13 @@ CallTest::CallTest() num_flexfec_streams_(0), audio_decoder_factory_(CreateBuiltinAudioDecoderFactory()), audio_encoder_factory_(CreateBuiltinAudioEncoderFactory()), - task_queue_("CallTestTaskQueue"), - video_send_config_(nullptr), - video_send_stream_(nullptr) {} + task_queue_("CallTestTaskQueue") {} CallTest::~CallTest() { task_queue_.SendTask([this]() { fake_send_audio_device_ = nullptr; fake_recv_audio_device_ = nullptr; - frame_generator_capturer_.reset(); + video_capturers_.clear(); }); } @@ -140,7 +138,7 @@ void CallTest::RunBaseTest(BaseTest* test) { } if (num_video_streams_ > 0) { CreateVideoStreams(); - test->OnVideoStreamsCreated(video_send_stream_, video_receive_streams_); + test->OnVideoStreamsCreated(GetVideoSendStream(), video_receive_streams_); } if (num_audio_streams_ > 0) { CreateAudioStreams(); @@ -153,7 +151,7 @@ void CallTest::RunBaseTest(BaseTest* test) { int frame_rate = kDefaultFramerate; test->ModifyVideoCaptureStartResolution(&width, &height, &frame_rate); CreateFrameGeneratorCapturer(frame_rate, width, height); - test->OnFrameGeneratorCapturerCreated(frame_generator_capturer_.get()); + test->OnFrameGeneratorCapturerCreated(frame_generator_capturer_); } Start(); @@ -218,8 +216,11 @@ void CallTest::CreateVideoSendConfig(VideoSendStream::Config* video_config, kTransportSequenceNumberExtensionId)); video_config->rtp.extensions.push_back(RtpExtension( RtpExtension::kVideoContentTypeUri, kVideoContentTypeExtensionId)); - FillEncoderConfiguration(kVideoCodecGeneric, num_video_streams, - &video_encoder_config_); + if (video_encoder_configs_.empty()) { + video_encoder_configs_.emplace_back(); + FillEncoderConfiguration(kVideoCodecGeneric, num_video_streams, + &video_encoder_configs_.back()); + } for (size_t i = 0; i < num_video_streams; ++i) video_config->rtp.ssrcs.push_back(kVideoSendSsrcs[num_used_ssrcs + i]); @@ -233,98 +234,184 @@ void CallTest::CreateAudioAndFecSendConfigs(size_t num_audio_streams, RTC_DCHECK_LE(num_audio_streams, 1); RTC_DCHECK_LE(num_flexfec_streams, 1); if (num_audio_streams > 0) { - audio_send_config_ = AudioSendStream::Config(send_transport); - audio_send_config_.rtp.ssrc = kAudioSendSsrc; - audio_send_config_.send_codec_spec = AudioSendStream::Config::SendCodecSpec( + AudioSendStream::Config audio_send_config(send_transport); + audio_send_config.rtp.ssrc = kAudioSendSsrc; + audio_send_config.send_codec_spec = AudioSendStream::Config::SendCodecSpec( kAudioSendPayloadType, {"opus", 48000, 2, {{"stereo", "1"}}}); - audio_send_config_.encoder_factory = audio_encoder_factory_; + audio_send_config.encoder_factory = audio_encoder_factory_; + SetAudioConfig(audio_send_config); } // TODO(brandtr): Update this when we support multistream protection. if (num_flexfec_streams > 0) { - GetVideoSendConfig()->rtp.flexfec.payload_type = kFlexfecPayloadType; - GetVideoSendConfig()->rtp.flexfec.ssrc = kFlexfecSendSsrc; - GetVideoSendConfig()->rtp.flexfec.protected_media_ssrcs = { - kVideoSendSsrcs[0]}; + SetSendFecConfig({kVideoSendSsrcs[0]}); } } +void CallTest::SetAudioConfig(const AudioSendStream::Config& config) { + audio_send_config_ = config; +} + +void CallTest::SetSendFecConfig(std::vector video_send_ssrcs) { + GetVideoSendConfig()->rtp.flexfec.payload_type = kFlexfecPayloadType; + GetVideoSendConfig()->rtp.flexfec.ssrc = kFlexfecSendSsrc; + GetVideoSendConfig()->rtp.flexfec.protected_media_ssrcs = video_send_ssrcs; +} + +void CallTest::SetSendUlpFecConfig(VideoSendStream::Config* send_config) { + send_config->rtp.ulpfec.red_payload_type = kRedPayloadType; + send_config->rtp.ulpfec.ulpfec_payload_type = kUlpfecPayloadType; + send_config->rtp.ulpfec.red_rtx_payload_type = kRtxRedPayloadType; +} + +void CallTest::SetReceiveUlpFecConfig( + VideoReceiveStream::Config* receive_config) { + receive_config->rtp.red_payload_type = kRedPayloadType; + receive_config->rtp.ulpfec_payload_type = kUlpfecPayloadType; + receive_config->rtp.rtx_associated_payload_types[kRtxRedPayloadType] = + kRedPayloadType; +} + void CallTest::CreateSendConfig(size_t num_video_streams, size_t num_audio_streams, size_t num_flexfec_streams, Transport* send_transport) { if (num_video_streams > 0) { - CreateVideoSendConfig(&video_send_config_, num_video_streams, 0, + video_send_configs_.clear(); + video_send_configs_.emplace_back(nullptr); + CreateVideoSendConfig(&video_send_configs_.back(), num_video_streams, 0, send_transport); } CreateAudioAndFecSendConfigs(num_audio_streams, num_flexfec_streams, send_transport); } -std::vector -CallTest::CreateMatchingVideoReceiveConfigs( +void CallTest::CreateMatchingVideoReceiveConfigs( const VideoSendStream::Config& video_send_config, Transport* rtcp_send_transport) { - std::vector result; + CreateMatchingVideoReceiveConfigs(video_send_config, rtcp_send_transport, + true, absl::nullopt, false, 0); +} + +void CallTest::CreateMatchingVideoReceiveConfigs( + const VideoSendStream::Config& video_send_config, + Transport* rtcp_send_transport, + bool send_side_bwe, + absl::optional decode_sub_stream, + bool receiver_reference_time_report, + int rtp_history_ms) { + AddMatchingVideoReceiveConfigs( + &video_receive_configs_, video_send_config, rtcp_send_transport, + send_side_bwe, decode_sub_stream, receiver_reference_time_report, + rtp_history_ms); +} + +void CallTest::AddMatchingVideoReceiveConfigs( + std::vector* receive_configs, + const VideoSendStream::Config& video_send_config, + Transport* rtcp_send_transport, + bool send_side_bwe, + absl::optional decode_sub_stream, + bool receiver_reference_time_report, + int rtp_history_ms) { RTC_DCHECK(!video_send_config.rtp.ssrcs.empty()); - VideoReceiveStream::Config video_config(rtcp_send_transport); - video_config.rtp.remb = false; - video_config.rtp.transport_cc = true; - video_config.rtp.local_ssrc = kReceiverLocalVideoSsrc; + VideoReceiveStream::Config default_config(rtcp_send_transport); + default_config.rtp.remb = !send_side_bwe; + default_config.rtp.transport_cc = send_side_bwe; + default_config.rtp.local_ssrc = kReceiverLocalVideoSsrc; for (const RtpExtension& extension : video_send_config.rtp.extensions) - video_config.rtp.extensions.push_back(extension); - video_config.renderer = &fake_renderer_; + default_config.rtp.extensions.push_back(extension); + default_config.rtp.nack.rtp_history_ms = rtp_history_ms; + // Enable RTT calculation so NTP time estimator will work. + default_config.rtp.rtcp_xr.receiver_reference_time_report = + receiver_reference_time_report; + default_config.renderer = &fake_renderer_; + for (size_t i = 0; i < video_send_config.rtp.ssrcs.size(); ++i) { - VideoReceiveStream::Decoder decoder = - test::CreateMatchingDecoder(video_send_config); - allocated_decoders_.push_back( - std::unique_ptr(decoder.decoder)); - video_config.decoders.clear(); - video_config.decoders.push_back(decoder); - video_config.rtp.remote_ssrc = video_send_config.rtp.ssrcs[i]; - result.push_back(video_config.Copy()); + VideoReceiveStream::Config video_recv_config(default_config.Copy()); + video_recv_config.decoders.clear(); + if (!video_send_config.rtp.rtx.ssrcs.empty()) { + video_recv_config.rtp.rtx_ssrc = video_send_config.rtp.rtx.ssrcs[i]; + video_recv_config.rtp.rtx_associated_payload_types[kSendRtxPayloadType] = + video_send_config.rtp.payload_type; + } + video_recv_config.rtp.remote_ssrc = video_send_config.rtp.ssrcs[i]; + VideoReceiveStream::Decoder decoder; + + // Force fake decoders on non-selected simulcast streams. + if (!decode_sub_stream || i == *decode_sub_stream) { + decoder = test::CreateMatchingDecoder(video_send_config); + } else { + decoder.decoder = new test::FakeDecoder(); + decoder.payload_type = video_send_config.rtp.payload_type; + decoder.payload_name = video_send_config.rtp.payload_name; + } + allocated_decoders_.emplace_back(decoder.decoder); + video_recv_config.decoders.push_back(decoder); + receive_configs->emplace_back(std::move(video_recv_config)); } - result[0].rtp.protected_by_flexfec = (num_flexfec_streams_ == 1); - return result; } void CallTest::CreateMatchingAudioAndFecConfigs( Transport* rtcp_send_transport) { RTC_DCHECK_GE(1, num_audio_streams_); if (num_audio_streams_ == 1) { - AudioReceiveStream::Config audio_config; - audio_config.rtp.local_ssrc = kReceiverLocalAudioSsrc; - audio_config.rtcp_send_transport = rtcp_send_transport; - audio_config.rtp.remote_ssrc = audio_send_config_.rtp.ssrc; - audio_config.decoder_factory = audio_decoder_factory_; - audio_config.decoder_map = {{kAudioSendPayloadType, {"opus", 48000, 2}}}; - audio_receive_configs_.push_back(audio_config); + CreateMatchingAudioConfigs(rtcp_send_transport, ""); } // TODO(brandtr): Update this when we support multistream protection. RTC_DCHECK(num_flexfec_streams_ <= 1); if (num_flexfec_streams_ == 1) { - FlexfecReceiveStream::Config config(rtcp_send_transport); - config.payload_type = kFlexfecPayloadType; - config.remote_ssrc = kFlexfecSendSsrc; - config.protected_media_ssrcs = {kVideoSendSsrcs[0]}; - config.local_ssrc = kReceiverLocalVideoSsrc; + CreateMatchingFecConfig(rtcp_send_transport, *GetVideoSendConfig()); for (const RtpExtension& extension : GetVideoSendConfig()->rtp.extensions) - config.rtp_header_extensions.push_back(extension); - flexfec_receive_configs_.push_back(config); + GetFlexFecConfig()->rtp_header_extensions.push_back(extension); } } +void CallTest::CreateMatchingAudioConfigs(Transport* transport, + std::string sync_group) { + audio_receive_configs_.push_back(CreateMatchingAudioConfig( + audio_send_config_, audio_decoder_factory_, transport, sync_group)); +} + +AudioReceiveStream::Config CallTest::CreateMatchingAudioConfig( + const AudioSendStream::Config& send_config, + rtc::scoped_refptr audio_decoder_factory, + Transport* transport, + std::string sync_group) { + AudioReceiveStream::Config audio_config; + audio_config.rtp.local_ssrc = kReceiverLocalAudioSsrc; + audio_config.rtcp_send_transport = transport; + audio_config.rtp.remote_ssrc = send_config.rtp.ssrc; + audio_config.rtp.transport_cc = + send_config.send_codec_spec + ? send_config.send_codec_spec->transport_cc_enabled + : false; + audio_config.rtp.extensions = send_config.rtp.extensions; + audio_config.decoder_factory = audio_decoder_factory; + audio_config.decoder_map = {{kAudioSendPayloadType, {"opus", 48000, 2}}}; + audio_config.sync_group = sync_group; + return audio_config; +} + +void CallTest::CreateMatchingFecConfig( + Transport* transport, + const VideoSendStream::Config& send_config) { + FlexfecReceiveStream::Config config(transport); + config.payload_type = send_config.rtp.flexfec.payload_type; + config.remote_ssrc = send_config.rtp.flexfec.ssrc; + config.protected_media_ssrcs = send_config.rtp.flexfec.protected_media_ssrcs; + config.local_ssrc = kReceiverLocalVideoSsrc; + if (!video_receive_configs_.empty()) + video_receive_configs_[0].rtp.protected_by_flexfec = true; + flexfec_receive_configs_.push_back(config); +} + void CallTest::CreateMatchingReceiveConfigs(Transport* rtcp_send_transport) { video_receive_configs_.clear(); allocated_decoders_.clear(); - if (num_video_streams_ > 0) { - std::vector new_configs = - CreateMatchingVideoReceiveConfigs(*GetVideoSendConfig(), - rtcp_send_transport); - for (VideoReceiveStream::Config& config : new_configs) { - video_receive_configs_.push_back(config.Copy()); - } + for (VideoSendStream::Config& video_send_config : video_send_configs_) { + CreateMatchingVideoReceiveConfigs(video_send_config, rtcp_send_transport); } CreateMatchingAudioAndFecConfigs(rtcp_send_transport); } @@ -334,16 +421,26 @@ void CallTest::CreateFrameGeneratorCapturerWithDrift(Clock* clock, int framerate, int width, int height) { - frame_generator_capturer_.reset(test::FrameGeneratorCapturer::Create( - width, height, absl::nullopt, absl::nullopt, framerate * speed, clock)); + video_sources_.clear(); + video_capturers_.clear(); + frame_generator_capturer_ = test::FrameGeneratorCapturer::Create( + width, height, absl::nullopt, absl::nullopt, framerate * speed, clock); + video_capturers_.emplace_back( + std::unique_ptr(frame_generator_capturer_)); + video_sources_.push_back(video_capturers_.back().get()); ConnectVideoSourcesToStreams(); } void CallTest::CreateFrameGeneratorCapturer(int framerate, int width, int height) { - frame_generator_capturer_.reset(test::FrameGeneratorCapturer::Create( - width, height, absl::nullopt, absl::nullopt, framerate, clock_)); + video_sources_.clear(); + video_capturers_.clear(); + frame_generator_capturer_ = test::FrameGeneratorCapturer::Create( + width, height, absl::nullopt, absl::nullopt, framerate, clock_); + video_capturers_.emplace_back( + std::unique_ptr(frame_generator_capturer_)); + video_sources_.push_back(video_capturers_.back().get()); ConnectVideoSourcesToStreams(); } @@ -368,15 +465,45 @@ void CallTest::CreateVideoStreams() { } void CallTest::CreateVideoSendStreams() { - RTC_DCHECK(video_send_stream_ == nullptr); - video_send_stream_ = sender_call_->CreateVideoSendStream( - GetVideoSendConfig()->Copy(), GetVideoEncoderConfig()->Copy()); + RTC_DCHECK(video_send_streams_.empty()); + + // We currently only support testing external fec controllers with a single + // VideoSendStream. + if (fec_controller_factory_.get()) { + RTC_DCHECK_LE(video_send_configs_.size(), 1); + } + + // TODO(http://crbug/818127): + // Remove this workaround when ALR is not screenshare-specific. + std::list streams_creation_order; + for (size_t i = 0; i < video_send_configs_.size(); ++i) { + // If dual streams are created, add the screenshare stream last. + if (video_encoder_configs_[i].content_type == + VideoEncoderConfig::ContentType::kScreen) { + streams_creation_order.push_back(i); + } else { + streams_creation_order.push_front(i); + } + } + + video_send_streams_.resize(video_send_configs_.size(), nullptr); + + for (size_t i : streams_creation_order) { + if (fec_controller_factory_.get()) { + video_send_streams_[i] = sender_call_->CreateVideoSendStream( + video_send_configs_[i].Copy(), video_encoder_configs_[i].Copy(), + fec_controller_factory_->CreateFecController()); + } else { + video_send_streams_[i] = sender_call_->CreateVideoSendStream( + video_send_configs_[i].Copy(), video_encoder_configs_[i].Copy()); + } + } } void CallTest::CreateVideoSendStream(const VideoEncoderConfig& encoder_config) { - RTC_DCHECK(video_send_stream_ == nullptr); - video_send_stream_ = sender_call_->CreateVideoSendStream( - GetVideoSendConfig()->Copy(), encoder_config.Copy()); + RTC_DCHECK(video_send_streams_.empty()); + video_send_streams_.push_back(sender_call_->CreateVideoSendStream( + GetVideoSendConfig()->Copy(), encoder_config.Copy())); } void CallTest::CreateAudioStreams() { @@ -400,8 +527,9 @@ void CallTest::CreateFlexfecStreams() { } void CallTest::ConnectVideoSourcesToStreams() { - GetVideoSendStream()->SetSource(frame_generator_capturer_.get(), - degradation_preference_); + for (size_t i = 0; i < video_sources_.size(); ++i) + video_send_streams_[i]->SetSource(video_sources_[i], + degradation_preference_); } void CallTest::AssociateFlexfecStreamsWithVideoStreams() { @@ -432,29 +560,37 @@ void CallTest::Start() { } void CallTest::StartVideoStreams() { - if (video_send_stream_) - video_send_stream_->Start(); + for (VideoSendStream* video_send_stream : video_send_streams_) + video_send_stream->Start(); for (VideoReceiveStream* video_recv_stream : video_receive_streams_) video_recv_stream->Start(); } void CallTest::StartVideoCapture() { - if (frame_generator_capturer_.get() != NULL) - frame_generator_capturer_->Start(); + for (auto& capturer : video_capturers_) + capturer->Start(); } void CallTest::Stop() { - if (frame_generator_capturer_.get() != NULL) - frame_generator_capturer_->Stop(); + StopVideoCapture(); for (AudioReceiveStream* audio_recv_stream : audio_receive_streams_) audio_recv_stream->Stop(); if (audio_send_stream_) { audio_send_stream_->Stop(); } + StopVideoStreams(); +} + +void CallTest::StopVideoCapture() { + for (auto& capturer : video_capturers_) + capturer->Stop(); +} + +void CallTest::StopVideoStreams() { + for (VideoSendStream* video_send_stream : video_send_streams_) + video_send_stream->Stop(); for (VideoReceiveStream* video_recv_stream : video_receive_streams_) video_recv_stream->Stop(); - if (video_send_stream_) - video_send_stream_->Stop(); } void CallTest::DestroyStreams() { @@ -479,9 +615,9 @@ void CallTest::DestroyStreams() { } void CallTest::DestroyVideoSendStreams() { - if (video_send_stream_) - sender_call_->DestroyVideoSendStream(video_send_stream_); - video_send_stream_ = nullptr; + for (VideoSendStream* video_send_stream : video_send_streams_) + sender_call_->DestroyVideoSendStream(video_send_stream); + video_send_streams_.clear(); } void CallTest::SetFakeVideoCaptureRotation(VideoRotation rotation) { @@ -489,27 +625,32 @@ void CallTest::SetFakeVideoCaptureRotation(VideoRotation rotation) { } void CallTest::SetVideoDegradation(DegradationPreference preference) { - GetVideoSendStream()->SetSource(frame_generator_capturer_.get(), preference); + GetVideoSendStream()->SetSource(frame_generator_capturer_, preference); } VideoSendStream::Config* CallTest::GetVideoSendConfig() { - return &video_send_config_; + return &video_send_configs_[0]; } void CallTest::SetVideoSendConfig(const VideoSendStream::Config& config) { - video_send_config_ = config.Copy(); + video_send_configs_.clear(); + video_send_configs_.push_back(config.Copy()); } VideoEncoderConfig* CallTest::GetVideoEncoderConfig() { - return &video_encoder_config_; + return &video_encoder_configs_[0]; } void CallTest::SetVideoEncoderConfig(const VideoEncoderConfig& config) { - video_encoder_config_ = config.Copy(); + video_encoder_configs_.clear(); + video_encoder_configs_.push_back(config.Copy()); } VideoSendStream* CallTest::GetVideoSendStream() { - return video_send_stream_; + return video_send_streams_[0]; +} +FlexfecReceiveStream::Config* CallTest::GetFlexFecConfig() { + return &flexfec_receive_configs_[0]; } constexpr size_t CallTest::kNumSsrcs; diff --git a/test/call_test.h b/test/call_test.h index 12301e8d63..dcaff2e57b 100644 --- a/test/call_test.h +++ b/test/call_test.h @@ -85,15 +85,45 @@ class CallTest : public ::testing::Test { void CreateAudioAndFecSendConfigs(size_t num_audio_streams, size_t num_flexfec_streams, Transport* send_transport); + void SetAudioConfig(const AudioSendStream::Config& config); + + void SetSendFecConfig(std::vector video_send_ssrcs); + void SetSendUlpFecConfig(VideoSendStream::Config* send_config); + void SetReceiveUlpFecConfig(VideoReceiveStream::Config* receive_config); void CreateSendConfig(size_t num_video_streams, size_t num_audio_streams, size_t num_flexfec_streams, Transport* send_transport); - std::vector CreateMatchingVideoReceiveConfigs( + void CreateMatchingVideoReceiveConfigs( const VideoSendStream::Config& video_send_config, Transport* rtcp_send_transport); + void CreateMatchingVideoReceiveConfigs( + const VideoSendStream::Config& video_send_config, + Transport* rtcp_send_transport, + bool send_side_bwe, + absl::optional decode_sub_stream, + bool receiver_reference_time_report, + int rtp_history_ms); + void AddMatchingVideoReceiveConfigs( + std::vector* receive_configs, + const VideoSendStream::Config& video_send_config, + Transport* rtcp_send_transport, + bool send_side_bwe, + absl::optional decode_sub_stream, + bool receiver_reference_time_report, + int rtp_history_ms); + void CreateMatchingAudioAndFecConfigs(Transport* rtcp_send_transport); + void CreateMatchingAudioConfigs(Transport* transport, std::string sync_group); + static AudioReceiveStream::Config CreateMatchingAudioConfig( + const AudioSendStream::Config& send_config, + rtc::scoped_refptr audio_decoder_factory, + Transport* transport, + std::string sync_group); + void CreateMatchingFecConfig( + Transport* transport, + const VideoSendStream::Config& video_send_config); void CreateMatchingReceiveConfigs(Transport* rtcp_send_transport); void CreateFrameGeneratorCapturerWithDrift(Clock* drift_clock, @@ -121,6 +151,8 @@ class CallTest : public ::testing::Test { void StartVideoStreams(); void StartVideoCapture(); void Stop(); + void StopVideoCapture(); + void StopVideoStreams(); void DestroyStreams(); void DestroyVideoSendStreams(); void SetFakeVideoCaptureRotation(VideoRotation rotation); @@ -132,6 +164,7 @@ class CallTest : public ::testing::Test { VideoEncoderConfig* GetVideoEncoderConfig(); void SetVideoEncoderConfig(const VideoEncoderConfig& config); VideoSendStream* GetVideoSendStream(); + FlexfecReceiveStream::Config* GetFlexFecConfig(); Clock* const clock_; @@ -140,6 +173,9 @@ class CallTest : public ::testing::Test { std::unique_ptr sender_call_; RtpTransportControllerSend* sender_call_transport_controller_; std::unique_ptr send_transport_; + std::vector video_send_configs_; + std::vector video_encoder_configs_; + std::vector video_send_streams_; AudioSendStream::Config audio_send_config_; AudioSendStream* audio_send_stream_; @@ -152,10 +188,18 @@ class CallTest : public ::testing::Test { std::vector flexfec_receive_configs_; std::vector flexfec_receive_streams_; - std::unique_ptr frame_generator_capturer_; + test::FrameGeneratorCapturer* frame_generator_capturer_; + std::vector*> video_sources_; + std::vector> video_capturers_; + DegradationPreference degradation_preference_ = + DegradationPreference::MAINTAIN_FRAMERATE; + + std::unique_ptr fec_controller_factory_; + test::FunctionVideoEncoderFactory fake_encoder_factory_; int fake_encoder_max_bitrate_ = -1; std::vector> allocated_decoders_; + // Number of simulcast substreams. size_t num_video_streams_; size_t num_audio_streams_; size_t num_flexfec_streams_; @@ -166,13 +210,6 @@ class CallTest : public ::testing::Test { SingleThreadedTaskQueueForTesting task_queue_; private: - VideoSendStream::Config video_send_config_; - VideoEncoderConfig video_encoder_config_; - VideoSendStream* video_send_stream_; - - DegradationPreference degradation_preference_ = - DegradationPreference::MAINTAIN_FRAMERATE; - rtc::scoped_refptr apm_send_; rtc::scoped_refptr apm_recv_; rtc::scoped_refptr fake_send_audio_device_; diff --git a/video/video_quality_test.cc b/video/video_quality_test.cc index cbf9dbe3ef..fbf8a07834 100644 --- a/video/video_quality_test.cc +++ b/video/video_quality_test.cc @@ -361,9 +361,6 @@ void VideoQualityTest::FillScalabilitySettings( void VideoQualityTest::SetupVideo(Transport* send_transport, Transport* recv_transport) { 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_encoder_configs_.clear(); @@ -377,8 +374,9 @@ void VideoQualityTest::SetupVideo(Transport* send_transport, 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); + for (size_t i = 0; i < num_video_substreams; ++i) + video_send_configs_[video_idx].rtp.ssrcs.push_back( + kVideoSendSsrcs[total_streams_used + i]); int payload_type; if (params_.video[video_idx].codec == "H264") { @@ -456,40 +454,14 @@ void VideoQualityTest::SetupVideo(Transport* send_transport, video_encoder_configs_[video_idx].spatial_layers = params_.ss[video_idx].spatial_layers; - - std::vector 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].rtp.payload_type; - decoder.payload_name = video_send_configs_[video_idx].rtp.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()); - } + absl::optional decode_sub_stream; + if (!decode_all_receive_streams) + decode_sub_stream = params_.ss[video_idx].selected_stream; + CreateMatchingVideoReceiveConfigs( + video_send_configs_[video_idx], recv_transport, + params_.call.send_side_bwe, decode_sub_stream, true, kNackRtpHistoryMs); if (params_.screenshare[video_idx].enabled) { // Fill out codec settings. @@ -554,71 +526,33 @@ void VideoQualityTest::SetupVideo(Transport* send_transport, // 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_configs_[0].rtp.ssrcs) { - video_send_configs_[0].rtp.flexfec.protected_media_ssrcs.push_back( - media_ssrc); - } + SetSendFecConfig(GetVideoSendConfig()->rtp.ssrcs); } else { - video_send_configs_[0].rtp.flexfec.protected_media_ssrcs = { - kVideoSendSsrcs[params_.ss[0].selected_stream]}; + SetSendFecConfig({kVideoSendSsrcs[params_.ss[0].selected_stream]}); } - // The matching receive config is _not_ created by - // CreateMatchingReceiveConfigs, since VideoQualityTest is not a BaseTest. - // Set up the receive config manually instead. - FlexfecReceiveStream::Config flexfec_receive_config(recv_transport); - flexfec_receive_config.payload_type = - 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_configs_[0].rtp.flexfec.protected_media_ssrcs; - flexfec_receive_config.local_ssrc = kReceiverLocalVideoSsrc; - flexfec_receive_config.transport_cc = params_.call.send_side_bwe; + CreateMatchingFecConfig(recv_transport, *GetVideoSendConfig()); + GetFlexFecConfig()->transport_cc = params_.call.send_side_bwe; if (params_.call.send_side_bwe) { - flexfec_receive_config.rtp_header_extensions.push_back( + GetFlexFecConfig()->rtp_header_extensions.push_back( RtpExtension(RtpExtension::kTransportSequenceNumberUri, test::kTransportSequenceNumberExtensionId)); } else { - flexfec_receive_config.rtp_header_extensions.push_back(RtpExtension( + GetFlexFecConfig()->rtp_header_extensions.push_back(RtpExtension( RtpExtension::kAbsSendTimeUri, test::kAbsSendTimeExtensionId)); } - flexfec_receive_configs_.push_back(flexfec_receive_config); - if (num_video_substreams > 0) { - video_receive_configs_[0].rtp.protected_by_flexfec = true; - } } 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; - + SetSendUlpFecConfig(GetVideoSendConfig()); 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_configs_[0].rtp.ulpfec.red_payload_type; - it->rtp.ulpfec_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; + for (auto& receive_config : video_receive_configs_) { + SetReceiveUlpFecConfig(&receive_config); } } else { - 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_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; + SetReceiveUlpFecConfig( + &video_receive_configs_[params_.ss[0].selected_stream]); } } } @@ -668,39 +602,19 @@ void VideoQualityTest::SetupThumbnails(Transport* send_transport, } thumbnail_encoder_config.spatial_layers = params_.ss[0].spatial_layers; - VideoReceiveStream::Config thumbnail_receive_config(send_transport); - thumbnail_receive_config.rtp.remb = false; - thumbnail_receive_config.rtp.transport_cc = true; - thumbnail_receive_config.rtp.local_ssrc = kReceiverLocalVideoSsrc; - for (const RtpExtension& extension : thumbnail_send_config.rtp.extensions) - thumbnail_receive_config.rtp.extensions.push_back(extension); - thumbnail_receive_config.renderer = &fake_renderer_; - - VideoReceiveStream::Decoder decoder = - test::CreateMatchingDecoder(thumbnail_send_config); - allocated_decoders_.push_back( - std::unique_ptr(decoder.decoder)); - thumbnail_receive_config.decoders.clear(); - thumbnail_receive_config.decoders.push_back(decoder); - thumbnail_receive_config.rtp.remote_ssrc = - thumbnail_send_config.rtp.ssrcs[0]; - - thumbnail_receive_config.rtp.nack.rtp_history_ms = kNackRtpHistoryMs; - thumbnail_receive_config.rtp.rtx_ssrc = kThumbnailRtxSsrcStart + i; - thumbnail_receive_config.rtp - .rtx_associated_payload_types[kSendRtxPayloadType] = kPayloadTypeVP8; - thumbnail_receive_config.rtp.transport_cc = params_.call.send_side_bwe; - thumbnail_receive_config.rtp.remb = !params_.call.send_side_bwe; - thumbnail_encoder_configs_.push_back(thumbnail_encoder_config.Copy()); thumbnail_send_configs_.push_back(thumbnail_send_config.Copy()); - thumbnail_receive_configs_.push_back(thumbnail_receive_config.Copy()); - } - for (int i = 0; i < params_.call.num_thumbnails; ++i) { + AddMatchingVideoReceiveConfigs( + &thumbnail_receive_configs_, thumbnail_send_config, send_transport, + params_.call.send_side_bwe, absl::nullopt, false, kNackRtpHistoryMs); + } + for (size_t i = 0; i < thumbnail_send_configs_.size(); ++i) { thumbnail_send_streams_.push_back(receiver_call_->CreateVideoSendStream( thumbnail_send_configs_[i].Copy(), thumbnail_encoder_configs_[i].Copy())); + } + for (size_t i = 0; i < thumbnail_receive_configs_.size(); ++i) { thumbnail_receive_streams_.push_back(sender_call_->CreateVideoReceiveStream( thumbnail_receive_configs_[i].Copy())); } @@ -780,6 +694,8 @@ std::unique_ptr VideoQualityTest::CreateFrameGenerator( } void VideoQualityTest::CreateCapturers() { + RTC_DCHECK(video_sources_.empty()); + RTC_DCHECK(video_capturers_.empty()); 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) { @@ -829,6 +745,7 @@ void VideoQualityTest::CreateCapturers() { } } RTC_DCHECK(video_capturers_[video_idx].get()); + video_sources_.push_back(video_capturers_[video_idx].get()); } } @@ -848,57 +765,6 @@ 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_); - - // We currently only support testing external fec controllers with a single - // VideoSendStream. - if (fec_controller_factory_.get()) { - RTC_DCHECK_LE(video_send_configs_.size(), 1); - } - - // TODO(http://crbug/818127): - // Remove this workaround when ALR is not screenshare-specific. - std::list streams_creation_order; - for (size_t i = 0; i < video_send_configs_.size(); ++i) { - // If dual streams are created, add the screenshare stream last. - if (video_encoder_configs_[i].content_type == - VideoEncoderConfig::ContentType::kScreen) { - streams_creation_order.push_back(i); - } else { - streams_creation_order.push_front(i); - } - } - - video_send_streams_.resize(video_send_configs_.size(), nullptr); - - for (size_t i : streams_creation_order) { - if (fec_controller_factory_.get()) { - video_send_streams_[i] = sender_call_->CreateVideoSendStream( - video_send_configs_[i].Copy(), video_encoder_configs_[i].Copy(), - fec_controller_factory_->CreateFecController()); - } else { - video_send_streams_[i] = 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) { rtc::LogMessage::SetLogToStderr(params.logging.logs); num_video_streams_ = params.call.dual_video ? 2 : 1; @@ -983,9 +849,9 @@ void VideoQualityTest::RunWithAnalyzer(const Params& params) { SetupThumbnails(analyzer.get(), recv_transport.get()); video_receive_configs_[params_.ss[0].selected_stream].renderer = analyzer.get(); - 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.get(); + GetVideoSendConfig()->pre_encode_callback = analyzer->pre_encode_proxy(); + RTC_DCHECK(!GetVideoSendConfig()->post_encode_callback); + GetVideoSendConfig()->post_encode_callback = analyzer.get(); CreateFlexfecStreams(); CreateVideoStreams(); @@ -993,8 +859,8 @@ void VideoQualityTest::RunWithAnalyzer(const Params& params) { if (video_receive_streams_.size() == 1) analyzer->SetReceiveStream(video_receive_streams_[0]); - video_send_streams_[0]->SetSource(analyzer->OutputInterface(), - degradation_preference_); + GetVideoSendStream()->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(), @@ -1010,24 +876,18 @@ void VideoQualityTest::RunWithAnalyzer(const Params& params) { video_capturers_[video_idx].get(), degradation_preference_); } - StartEncodedFrameLogs(video_send_streams_[0]); + StartEncodedFrameLogs(GetVideoSendStream()); StartEncodedFrameLogs( video_receive_streams_[params_.ss[0].selected_stream]); - for (VideoSendStream* video_send_stream : video_send_streams_) - video_send_stream->Start(); + StartVideoStreams(); for (VideoSendStream* thumbnail_send_stream : thumbnail_send_streams_) thumbnail_send_stream->Start(); - for (VideoReceiveStream* receive_stream : video_receive_streams_) - receive_stream->Start(); for (VideoReceiveStream* thumbnail_receive_stream : thumbnail_receive_streams_) thumbnail_receive_stream->Start(); analyzer->StartMeasuringCpuProcessTime(); - - for (size_t video_idx = 0; video_idx < num_video_streams_; ++video_idx) { - video_capturers_[video_idx]->Start(); - } + StartVideoCapture(); for (std::unique_ptr& video_caputurer : thumbnail_capturers_) { video_caputurer->Start(); @@ -1067,43 +927,37 @@ void VideoQualityTest::RunWithAnalyzer(const Params& params) { }); } -void VideoQualityTest::SetupAudio(Transport* transport, - AudioReceiveStream** audio_receive_stream) { - audio_send_config_ = AudioSendStream::Config(transport); - audio_send_config_.rtp.ssrc = kAudioSendSsrc; +void VideoQualityTest::SetupAudio(Transport* transport) { + AudioSendStream::Config audio_send_config(transport); + audio_send_config.rtp.ssrc = kAudioSendSsrc; // Add extension to enable audio send side BWE, and allow audio bit rate // adaptation. - audio_send_config_.rtp.extensions.clear(); - if (params_.call.send_side_bwe) { - audio_send_config_.rtp.extensions.push_back( - webrtc::RtpExtension(webrtc::RtpExtension::kTransportSequenceNumberUri, - test::kTransportSequenceNumberExtensionId)); - audio_send_config_.min_bitrate_bps = kOpusMinBitrateBps; - audio_send_config_.max_bitrate_bps = kOpusBitrateFbBps; - } - audio_send_config_.send_codec_spec = AudioSendStream::Config::SendCodecSpec( + audio_send_config.rtp.extensions.clear(); + 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 = audio_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.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 = audio_decoder_factory_; - audio_config.decoder_map = {{kAudioSendPayloadType, {"OPUS", 48000, 2}}}; + if (params_.call.send_side_bwe) { + audio_send_config.rtp.extensions.push_back( + webrtc::RtpExtension(webrtc::RtpExtension::kTransportSequenceNumberUri, + test::kTransportSequenceNumberExtensionId)); + audio_send_config.min_bitrate_bps = kOpusMinBitrateBps; + audio_send_config.max_bitrate_bps = kOpusBitrateFbBps; + audio_send_config.send_codec_spec->transport_cc_enabled = true; + } + audio_send_config.encoder_factory = audio_encoder_factory_; + SetAudioConfig(audio_send_config); + + const char* sync_group = nullptr; if (params_.video[0].enabled && params_.audio.sync_video) - audio_config.sync_group = kSyncGroup; + sync_group = kSyncGroup; - *audio_receive_stream = - receiver_call_->CreateAudioReceiveStream(audio_config); + CreateMatchingAudioConfigs(transport, sync_group); + CreateAudioStreams(); } void VideoQualityTest::RunWithRenderers(const Params& params) { @@ -1113,7 +967,6 @@ void VideoQualityTest::RunWithRenderers(const Params& params) { std::unique_ptr recv_transport; std::unique_ptr local_preview; std::vector> loopback_renderers; - AudioReceiveStream* audio_receive_stream = nullptr; RtcEventLogNullImpl null_event_log; task_queue_.SendTask([&]() { @@ -1160,7 +1013,7 @@ void VideoQualityTest::RunWithRenderers(const Params& params) { "Local Preview", params_.video[0].width, params_.video[0].height)); SetupVideo(send_transport.get(), recv_transport.get()); - video_send_configs_[0].pre_encode_callback = local_preview.get(); + GetVideoSendConfig()->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) { @@ -1200,58 +1053,24 @@ void VideoQualityTest::RunWithRenderers(const Params& params) { CreateVideoStreams(); 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_); - } + ConnectVideoSourcesToStreams(); } if (params_.audio.enabled) { - SetupAudio(send_transport.get(), &audio_receive_stream); + SetupAudio(send_transport.get()); } for (VideoReceiveStream* receive_stream : video_receive_streams_) StartEncodedFrameLogs(receive_stream); - StartEncodedFrameLogs(video_send_streams_[0]); - - // Start sending and receiving video. - if (params_.video[0].enabled) { - for (VideoReceiveStream* video_receive_stream : video_receive_streams_) - video_receive_stream->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(); - - // Start sending audio. - audio_send_stream_->Start(); - } + StartEncodedFrameLogs(GetVideoSendStream()); + Start(); }); test::PressEnterToContinue(); task_queue_.SendTask([&]() { - if (params_.audio.enabled) { - // Stop sending audio. - audio_send_stream_->Stop(); - - // Stop receiving audio. - audio_receive_stream->Stop(); - } - - // Stop receiving and sending video. - 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(); - } + Stop(); + DestroyStreams(); video_capturers_.clear(); send_transport.reset(); diff --git a/video/video_quality_test.h b/video/video_quality_test.h index dbc5b6b9ca..67facfda30 100644 --- a/video/video_quality_test.h +++ b/video/video_quality_test.h @@ -56,7 +56,6 @@ class VideoQualityTest : protected: std::map payload_type_map_; - std::unique_ptr fec_controller_factory_; // No-op implementation to be able to instantiate this class from non-TEST_F // locations. @@ -67,8 +66,6 @@ class VideoQualityTest : void CheckParams(); // Helper methods for setting up the call. - void CreateVideoStreams(); - void DestroyStreams(); void CreateCapturers(); std::unique_ptr CreateFrameGenerator(size_t video_idx); void SetupThumbnailCapturers(size_t num_thumbnail_streams); @@ -77,8 +74,7 @@ class VideoQualityTest : void SetupVideo(Transport* send_transport, Transport* recv_transport); void SetupThumbnails(Transport* send_transport, Transport* recv_transport); void DestroyThumbnailStreams(); - void SetupAudio(Transport* transport, - AudioReceiveStream** audio_receive_stream); + void SetupAudio(Transport* transport); void StartEncodedFrameLogs(VideoSendStream* stream); void StartEncodedFrameLogs(VideoReceiveStream* stream); @@ -86,7 +82,6 @@ class VideoQualityTest : virtual std::unique_ptr CreateSendTransport(); virtual std::unique_ptr CreateReceiveTransport(); - std::vector> video_capturers_; std::vector> thumbnail_capturers_; Clock* const clock_; @@ -98,16 +93,14 @@ class VideoQualityTest : std::vector thumbnail_receive_configs_; std::vector thumbnail_receive_streams_; - std::vector video_send_configs_; - std::vector video_encoder_configs_; - std::vector video_send_streams_; int receive_logs_; int send_logs_; - DegradationPreference degradation_preference_ = - DegradationPreference::MAINTAIN_FRAMERATE; Params params_; + // Note: not same as similarly named member in CallTest. This is the number of + // separate send streams, the one in CallTest is the number of substreams for + // a single send stream. size_t num_video_streams_; };