diff --git a/webrtc/video/payload_router.cc b/webrtc/video/payload_router.cc index 5bcf70532f..2cc3e887b5 100644 --- a/webrtc/video/payload_router.cc +++ b/webrtc/video/payload_router.cc @@ -90,10 +90,8 @@ void CopyCodecSpecific(const CodecSpecificInfo* info, RTPVideoHeader* rtp) { PayloadRouter::PayloadRouter(const std::vector& rtp_modules, int payload_type) : active_(false), - num_sending_modules_(1), rtp_modules_(rtp_modules), payload_type_(payload_type) { - UpdateModuleSendingState(); } PayloadRouter::~PayloadRouter() {} @@ -108,7 +106,11 @@ void PayloadRouter::set_active(bool active) { if (active_ == active) return; active_ = active; - UpdateModuleSendingState(); + + for (auto& module : rtp_modules_) { + module->SetSendingStatus(active_); + module->SetSendingMediaStatus(active_); + } } bool PayloadRouter::active() { @@ -116,34 +118,13 @@ bool PayloadRouter::active() { return active_ && !rtp_modules_.empty(); } -void PayloadRouter::SetSendStreams(const std::vector& streams) { - RTC_DCHECK_LE(streams.size(), rtp_modules_.size()); - rtc::CritScope lock(&crit_); - num_sending_modules_ = streams.size(); - streams_ = streams; - // TODO(perkj): Should SetSendStreams also call SetTargetSendBitrate? - UpdateModuleSendingState(); -} - -void PayloadRouter::UpdateModuleSendingState() { - for (size_t i = 0; i < num_sending_modules_; ++i) { - rtp_modules_[i]->SetSendingStatus(active_); - rtp_modules_[i]->SetSendingMediaStatus(active_); - } - // Disable inactive modules. - for (size_t i = num_sending_modules_; i < rtp_modules_.size(); ++i) { - rtp_modules_[i]->SetSendingStatus(false); - rtp_modules_[i]->SetSendingMediaStatus(false); - } -} - EncodedImageCallback::Result PayloadRouter::OnEncodedImage( const EncodedImage& encoded_image, const CodecSpecificInfo* codec_specific_info, const RTPFragmentationHeader* fragmentation) { rtc::CritScope lock(&crit_); RTC_DCHECK(!rtp_modules_.empty()); - if (!active_ || num_sending_modules_ == 0) + if (!active_) return Result(Result::ERROR_SEND_FAILED); int stream_index = 0; @@ -154,12 +135,6 @@ EncodedImageCallback::Result PayloadRouter::OnEncodedImage( CopyCodecSpecific(codec_specific_info, &rtp_video_header); rtp_video_header.rotation = encoded_image.rotation_; rtp_video_header.playout_delay = encoded_image.playout_delay_; - - RTC_DCHECK_LT(rtp_video_header.simulcastIdx, rtp_modules_.size()); - // The simulcast index might actually be larger than the number of modules - // in case the encoder was processing a frame during a codec reconfig. - if (rtp_video_header.simulcastIdx >= num_sending_modules_) - return Result(Result::ERROR_SEND_FAILED); stream_index = rtp_video_header.simulcastIdx; uint32_t frame_id; @@ -168,6 +143,7 @@ EncodedImageCallback::Result PayloadRouter::OnEncodedImage( encoded_image.capture_time_ms_, encoded_image._buffer, encoded_image._length, fragmentation, &rtp_video_header, &frame_id); + RTC_DCHECK_LT(rtp_video_header.simulcastIdx, rtp_modules_.size()); if (send_result < 0) return Result(Result::ERROR_SEND_FAILED); @@ -177,7 +153,7 @@ EncodedImageCallback::Result PayloadRouter::OnEncodedImage( size_t PayloadRouter::MaxPayloadLength() const { size_t min_payload_length = DefaultMaxPayloadLength(); rtc::CritScope lock(&crit_); - for (size_t i = 0; i < num_sending_modules_; ++i) { + for (size_t i = 0; i < rtp_modules_.size(); ++i) { size_t module_payload_length = rtp_modules_[i]->MaxDataPayloadLength(); if (module_payload_length < min_payload_length) min_payload_length = module_payload_length; diff --git a/webrtc/video/payload_router.h b/webrtc/video/payload_router.h index 24aee74f9b..6426b00615 100644 --- a/webrtc/video/payload_router.h +++ b/webrtc/video/payload_router.h @@ -37,7 +37,6 @@ class PayloadRouter : public EncodedImageCallback { ~PayloadRouter(); static size_t DefaultMaxPayloadLength(); - void SetSendStreams(const std::vector& streams); // PayloadRouter will only route packets if being active, all packets will be // dropped otherwise. @@ -60,8 +59,6 @@ class PayloadRouter : public EncodedImageCallback { rtc::CriticalSection crit_; bool active_ GUARDED_BY(crit_); - std::vector streams_ GUARDED_BY(crit_); - size_t num_sending_modules_ GUARDED_BY(crit_); // Rtp modules are assumed to be sorted in simulcast index order. Not owned. const std::vector rtp_modules_; diff --git a/webrtc/video/payload_router_unittest.cc b/webrtc/video/payload_router_unittest.cc index def76b73a6..b5255d3827 100644 --- a/webrtc/video/payload_router_unittest.cc +++ b/webrtc/video/payload_router_unittest.cc @@ -39,7 +39,6 @@ TEST(PayloadRouterTest, SendOnOneModule) { encoded_image._length = 1; PayloadRouter payload_router(modules, payload_type); - payload_router.SetSendStreams(streams); EXPECT_CALL(rtp, SendOutgoingData(encoded_image._frameType, payload_type, encoded_image._timeStamp, @@ -71,15 +70,6 @@ TEST(PayloadRouterTest, SendOnOneModule) { encoded_image._length, nullptr, _, _)) .Times(1); EXPECT_EQ(0, payload_router.Encoded(encoded_image, nullptr, nullptr)); - - streams.clear(); - payload_router.SetSendStreams(streams); - EXPECT_CALL(rtp, SendOutgoingData(encoded_image._frameType, payload_type, - encoded_image._timeStamp, - encoded_image.capture_time_ms_, &payload, - encoded_image._length, nullptr, _, _)) - .Times(0); - EXPECT_EQ(-1, payload_router.Encoded(encoded_image, nullptr, nullptr)); } TEST(PayloadRouterTest, SendSimulcast) { @@ -100,7 +90,6 @@ TEST(PayloadRouterTest, SendSimulcast) { encoded_image._length = 1; PayloadRouter payload_router(modules, payload_type); - payload_router.SetSendStreams(streams); CodecSpecificInfo codec_info_1; memset(&codec_info_1, 0, sizeof(CodecSpecificInfo)); @@ -138,17 +127,6 @@ TEST(PayloadRouterTest, SendSimulcast) { .Times(0); EXPECT_EQ(-1, payload_router.Encoded(encoded_image, &codec_info_1, nullptr)); EXPECT_EQ(-1, payload_router.Encoded(encoded_image, &codec_info_2, nullptr)); - - // Invalid simulcast index. - streams.pop_back(); // Remove a stream. - payload_router.SetSendStreams(streams); - payload_router.set_active(true); - EXPECT_CALL(rtp_1, SendOutgoingData(_, _, _, _, _, _, _, _, _)) - .Times(0); - EXPECT_CALL(rtp_2, SendOutgoingData(_, _, _, _, _, _, _, _, _)) - .Times(0); - codec_info_2.codecSpecific.VP8.simulcastIdx = 1; - EXPECT_EQ(-1, payload_router.Encoded(encoded_image, &codec_info_2, nullptr)); } TEST(PayloadRouterTest, MaxPayloadLength) { @@ -164,7 +142,6 @@ TEST(PayloadRouterTest, MaxPayloadLength) { EXPECT_EQ(kDefaultMaxLength, PayloadRouter::DefaultMaxPayloadLength()); std::vector streams(2); - payload_router.SetSendStreams(streams); // Modules return a higher length than the default value. EXPECT_CALL(rtp_1, MaxDataPayloadLength()) diff --git a/webrtc/video/video_send_stream.cc b/webrtc/video/video_send_stream.cc index e9654dd293..c8541fed12 100644 --- a/webrtc/video/video_send_stream.cc +++ b/webrtc/video/video_send_stream.cc @@ -202,23 +202,23 @@ bool PayloadTypeSupportsSkippingFecPackets(const std::string& payload_name) { return false; } -int CalculateMaxPadBitrateBps(const VideoEncoderConfig& config, +int CalculateMaxPadBitrateBps(std::vector streams, + int min_transmit_bitrate_bps, bool pad_to_min_bitrate) { int pad_up_to_bitrate_bps = 0; // Calculate max padding bitrate for a multi layer codec. - if (config.streams.size() > 1) { + if (streams.size() > 1) { // Pad to min bitrate of the highest layer. - pad_up_to_bitrate_bps = - config.streams[config.streams.size() - 1].min_bitrate_bps; + pad_up_to_bitrate_bps = streams[streams.size() - 1].min_bitrate_bps; // Add target_bitrate_bps of the lower layers. - for (size_t i = 0; i < config.streams.size() - 1; ++i) - pad_up_to_bitrate_bps += config.streams[i].target_bitrate_bps; + for (size_t i = 0; i < streams.size() - 1; ++i) + pad_up_to_bitrate_bps += streams[i].target_bitrate_bps; } else if (pad_to_min_bitrate) { - pad_up_to_bitrate_bps = config.streams[0].min_bitrate_bps; + pad_up_to_bitrate_bps = streams[0].min_bitrate_bps; } pad_up_to_bitrate_bps = - std::max(pad_up_to_bitrate_bps, config.min_transmit_bitrate_bps); + std::max(pad_up_to_bitrate_bps, min_transmit_bitrate_bps); return pad_up_to_bitrate_bps; } @@ -236,7 +236,7 @@ namespace internal { // arbitrary thread. class VideoSendStreamImpl : public webrtc::BitrateAllocatorObserver, public webrtc::VCMProtectionCallback, - public EncodedImageCallback { + public ViEEncoder::EncoderSink { public: VideoSendStreamImpl(SendStatisticsProxy* stats_proxy, rtc::TaskQueue* worker_queue, @@ -248,6 +248,7 @@ class VideoSendStreamImpl : public webrtc::BitrateAllocatorObserver, ViEEncoder* vie_encoder, RtcEventLog* event_log, const VideoSendStream::Config* config, + int initial_encoder_max_bitrate, std::map suspended_ssrcs); ~VideoSendStreamImpl() override; @@ -264,11 +265,11 @@ class VideoSendStreamImpl : public webrtc::BitrateAllocatorObserver, void Start(); void Stop(); - void SignalEncoderConfigurationChanged(const VideoEncoderConfig& config); VideoSendStream::RtpStateMap GetRtpStates() const; private: class CheckEncoderActivityTask; + class EncoderReconfiguredTask; // Implements BitrateAllocatorObserver. uint32_t OnBitrateUpdated(uint32_t bitrate_bps, @@ -282,6 +283,9 @@ class VideoSendStreamImpl : public webrtc::BitrateAllocatorObserver, uint32_t* sent_nack_rate_bps, uint32_t* sent_fec_rate_bps) override; + void OnEncoderConfigurationChanged(std::vector streams, + int min_transmit_bitrate_bps) override; + // Implements EncodedImageCallback. The implementation routes encoded frames // to the |payload_router_| and |config.pre_encode_callback| if set. // Called on an arbitrary encoder callback thread. @@ -306,6 +310,7 @@ class VideoSendStreamImpl : public webrtc::BitrateAllocatorObserver, rtc::CriticalSection encoder_activity_crit_sect_; CheckEncoderActivityTask* check_encoder_activity_task_ GUARDED_BY(encoder_activity_crit_sect_); + CallStats* const call_stats_; CongestionController* const congestion_controller_; BitrateAllocator* const bitrate_allocator_; @@ -346,6 +351,7 @@ class VideoSendStream::ConstructionTask : public rtc::QueuedTask { VieRemb* remb, RtcEventLog* event_log, const VideoSendStream::Config* config, + int initial_encoder_max_bitrate, const std::map& suspended_ssrcs) : send_stream_(send_stream), done_event_(done_event), @@ -358,6 +364,7 @@ class VideoSendStream::ConstructionTask : public rtc::QueuedTask { remb_(remb), event_log_(event_log), config_(config), + initial_encoder_max_bitrate_(initial_encoder_max_bitrate), suspended_ssrcs_(suspended_ssrcs) {} ~ConstructionTask() override { done_event_->Set(); } @@ -367,7 +374,8 @@ class VideoSendStream::ConstructionTask : public rtc::QueuedTask { send_stream_->reset(new VideoSendStreamImpl( stats_proxy_, rtc::TaskQueue::Current(), call_stats_, congestion_controller_, bitrate_allocator_, send_delay_stats_, remb_, - vie_encoder_, event_log_, config_, std::move(suspended_ssrcs_))); + vie_encoder_, event_log_, config_, initial_encoder_max_bitrate_, + std::move(suspended_ssrcs_))); return true; } @@ -382,6 +390,7 @@ class VideoSendStream::ConstructionTask : public rtc::QueuedTask { VieRemb* const remb_; RtcEventLog* const event_log_; const VideoSendStream::Config* config_; + int initial_encoder_max_bitrate_; std::map suspended_ssrcs_; }; @@ -461,20 +470,25 @@ class VideoSendStreamImpl::CheckEncoderActivityTask : public rtc::QueuedTask { bool timed_out_; }; -class ReconfigureVideoEncoderTask : public rtc::QueuedTask { +class VideoSendStreamImpl::EncoderReconfiguredTask : public rtc::QueuedTask { public: - ReconfigureVideoEncoderTask(VideoSendStreamImpl* send_stream, - VideoEncoderConfig config) - : send_stream_(send_stream), config_(std::move(config)) {} + EncoderReconfiguredTask(VideoSendStreamImpl* send_stream, + std::vector streams, + int min_transmit_bitrate_bps) + : send_stream_(send_stream), + streams_(std::move(streams)), + min_transmit_bitrate_bps_(min_transmit_bitrate_bps) {} private: bool Run() override { - send_stream_->SignalEncoderConfigurationChanged(std::move(config_)); + send_stream_->OnEncoderConfigurationChanged(std::move(streams_), + min_transmit_bitrate_bps_); return true; } VideoSendStreamImpl* send_stream_; - VideoEncoderConfig config_; + std::vector streams_; + int min_transmit_bitrate_bps_; }; VideoSendStream::VideoSendStream( @@ -501,11 +515,18 @@ VideoSendStream::VideoSendStream( config_.pre_encode_callback, config_.overuse_callback, config_.post_encode_callback)); + // TODO(perkj): Remove vector from VideoEncoderConfig and + // replace with max_bitrate. The VideoStream should be created by ViEEncoder + // when the video resolution is known. + int initial_max_encoder_bitrate = 0; + for (const auto& stream : encoder_config.streams) + initial_max_encoder_bitrate += stream.max_bitrate_bps; + worker_queue_->PostTask(std::unique_ptr(new ConstructionTask( &send_stream_, &thread_sync_event_, &stats_proxy_, vie_encoder_.get(), module_process_thread, call_stats, congestion_controller, bitrate_allocator, send_delay_stats, remb, event_log, &config_, - suspended_ssrcs))); + initial_max_encoder_bitrate, suspended_ssrcs))); // Wait for ConstructionTask to complete so that |send_stream_| can be used. // |module_process_thread| must be registered and deregistered on the thread @@ -558,10 +579,8 @@ void VideoSendStream::ReconfigureVideoEncoder(VideoEncoderConfig config) { // TODO(perkj): Move logic for reconfiguration the encoder due to frame size // change from WebRtcVideoChannel2::WebRtcVideoSendStream::OnFrame to // be internally handled by ViEEncoder. - vie_encoder_->ConfigureEncoder(config, config_.rtp.max_packet_size); - - worker_queue_->PostTask(std::unique_ptr( - new ReconfigureVideoEncoderTask(send_stream_.get(), std::move(config)))); + vie_encoder_->ConfigureEncoder(std::move(config), + config_.rtp.max_packet_size); } VideoSendStream::Stats VideoSendStream::GetStats() { @@ -607,6 +626,7 @@ VideoSendStreamImpl::VideoSendStreamImpl( ViEEncoder* vie_encoder, RtcEventLog* event_log, const VideoSendStream::Config* config, + int initial_encoder_max_bitrate, std::map suspended_ssrcs) : stats_proxy_(stats_proxy), config_(config), @@ -620,7 +640,7 @@ VideoSendStreamImpl::VideoSendStreamImpl( remb_(remb), max_padding_bitrate_(0), encoder_min_bitrate_bps_(0), - encoder_max_bitrate_bps_(0), + encoder_max_bitrate_bps_(initial_encoder_max_bitrate), encoder_target_rate_bps_(0), vie_encoder_(vie_encoder), encoder_feedback_(Clock::GetRealTimeClock(), @@ -801,35 +821,44 @@ void VideoSendStreamImpl::SignalEncoderActive() { max_padding_bitrate_, !config_->suspend_below_min_bitrate); } -void VideoSendStreamImpl::SignalEncoderConfigurationChanged( - const VideoEncoderConfig& config) { - RTC_DCHECK_GE(config_->rtp.ssrcs.size(), config.streams.size()); - TRACE_EVENT0("webrtc", "VideoSendStream::SignalEncoderConfigurationChanged"); - LOG(LS_INFO) << "SignalEncoderConfigurationChanged: " << config.ToString(); - RTC_DCHECK_GE(config_->rtp.ssrcs.size(), config.streams.size()); +void VideoSendStreamImpl::OnEncoderConfigurationChanged( + std::vector streams, + int min_transmit_bitrate_bps) { + if (!worker_queue_->IsCurrent()) { + // TODO(perkj): Using |this| in post is safe for now since destruction of + // VideoSendStreamImpl is synchronized in + // VideoSendStream::StopPermanentlyAndGetRtpStates. But we should really + // use some kind of weak_ptr to guarantee that VideoSendStreamImpl is still + // alive when this task runs. + worker_queue_->PostTask( + std::unique_ptr(new EncoderReconfiguredTask( + this, std::move(streams), min_transmit_bitrate_bps))); + return; + } + RTC_DCHECK_GE(config_->rtp.ssrcs.size(), streams.size()); + TRACE_EVENT0("webrtc", "VideoSendStream::OnEncoderConfigurationChanged"); + RTC_DCHECK_GE(config_->rtp.ssrcs.size(), streams.size()); RTC_DCHECK_RUN_ON(worker_queue_); const int kEncoderMinBitrateBps = 30000; encoder_min_bitrate_bps_ = - std::max(config.streams[0].min_bitrate_bps, kEncoderMinBitrateBps); + std::max(streams[0].min_bitrate_bps, kEncoderMinBitrateBps); encoder_max_bitrate_bps_ = 0; - for (const auto& stream : config.streams) + for (const auto& stream : streams) encoder_max_bitrate_bps_ += stream.max_bitrate_bps; - max_padding_bitrate_ = - CalculateMaxPadBitrateBps(config, config_->suspend_below_min_bitrate); - - payload_router_.SetSendStreams(config.streams); + max_padding_bitrate_ = CalculateMaxPadBitrateBps( + streams, min_transmit_bitrate_bps, config_->suspend_below_min_bitrate); // Clear stats for disabled layers. - for (size_t i = config.streams.size(); i < config_->rtp.ssrcs.size(); ++i) { + for (size_t i = streams.size(); i < config_->rtp.ssrcs.size(); ++i) { stats_proxy_->OnInactiveSsrc(config_->rtp.ssrcs[i]); } size_t number_of_temporal_layers = - config.streams.back().temporal_layer_thresholds_bps.size() + 1; + streams.back().temporal_layer_thresholds_bps.size() + 1; protection_bitrate_calculator_.SetEncodingData( - config.streams[0].width, config.streams[0].height, - number_of_temporal_layers, config_->rtp.max_packet_size); + streams[0].width, streams[0].height, number_of_temporal_layers, + config_->rtp.max_packet_size); if (payload_router_.active()) { // The send stream is started already. Update the allocator with new bitrate diff --git a/webrtc/video/vie_encoder.cc b/webrtc/video/vie_encoder.cc index cd6d88dafc..5e1d294dda 100644 --- a/webrtc/video/vie_encoder.cc +++ b/webrtc/video/vie_encoder.cc @@ -12,6 +12,7 @@ #include #include +#include #include "webrtc/base/checks.h" #include "webrtc/base/logging.h" @@ -367,7 +368,7 @@ void ViEEncoder::SetSource(rtc::VideoSourceInterface* source) { source_proxy_->SetSource(source); } -void ViEEncoder::SetSink(EncodedImageCallback* sink) { +void ViEEncoder::SetSink(EncoderSink* sink) { encoder_queue_.PostTask([this, sink] { RTC_DCHECK_RUN_ON(&encoder_queue_); sink_ = sink; @@ -381,18 +382,25 @@ void ViEEncoder::SetStartBitrate(int start_bitrate_bps) { }); } -void ViEEncoder::ConfigureEncoder(const VideoEncoderConfig& config, +void ViEEncoder::ConfigureEncoder(VideoEncoderConfig config, size_t max_data_payload_length) { VideoCodec video_codec = VideoEncoderConfigToVideoCodec( config, settings_.payload_name, settings_.payload_type); - encoder_queue_.PostTask([this, video_codec, max_data_payload_length] { - ConfigureEncoderInternal(video_codec, max_data_payload_length); + LOG(LS_INFO) << "ConfigureEncoder: " << config.ToString(); + std::vector stream = std::move(config.streams); + int min_transmit_bitrate = config.min_transmit_bitrate_bps; + encoder_queue_.PostTask([this, video_codec, max_data_payload_length, stream, + min_transmit_bitrate] { + ConfigureEncoderInternal(video_codec, max_data_payload_length, stream, + min_transmit_bitrate); }); return; } void ViEEncoder::ConfigureEncoderInternal(const VideoCodec& video_codec, - size_t max_data_payload_length) { + size_t max_data_payload_length, + std::vector stream, + int min_transmit_bitrate) { RTC_DCHECK_RUN_ON(&encoder_queue_); RTC_DCHECK_GE(encoder_start_bitrate_bps_, 0); RTC_DCHECK(sink_); @@ -434,6 +442,8 @@ void ViEEncoder::ConfigureEncoderInternal(const VideoCodec& video_codec, } stats_proxy_->SetContentType(content_type); } + + sink_->OnEncoderConfigurationChanged(stream, min_transmit_bitrate); } void ViEEncoder::OnFrame(const VideoFrame& video_frame) { diff --git a/webrtc/video/vie_encoder.h b/webrtc/video/vie_encoder.h index eaf2536dab..15fd9cfa58 100644 --- a/webrtc/video/vie_encoder.h +++ b/webrtc/video/vie_encoder.h @@ -49,6 +49,15 @@ class ViEEncoder : public rtc::VideoSinkInterface, public VCMSendStatisticsCallback, public CpuOveruseObserver { public: + // Interface for receiving encoded video frames and notifications about + // configuration changes. + class EncoderSink : public EncodedImageCallback { + public: + virtual void OnEncoderConfigurationChanged( + std::vector streams, + int min_transmit_bitrate_bps) = 0; + }; + ViEEncoder(uint32_t number_of_cores, SendStatisticsProxy* stats_proxy, const webrtc::VideoSendStream::Config::EncoderSettings& settings, @@ -64,12 +73,12 @@ class ViEEncoder : public rtc::VideoSinkInterface, void DeRegisterProcessThread(); void SetSource(rtc::VideoSourceInterface* source); - void SetSink(EncodedImageCallback* sink); + void SetSink(EncoderSink* sink); // TODO(perkj): Can we remove VideoCodec.startBitrate ? void SetStartBitrate(int start_bitrate_bps); - void ConfigureEncoder(const VideoEncoderConfig& config, + void ConfigureEncoder(VideoEncoderConfig config, size_t max_data_payload_length); // Permanently stop encoding. After this method has returned, it is @@ -92,7 +101,9 @@ class ViEEncoder : public rtc::VideoSinkInterface, class VideoSourceProxy; void ConfigureEncoderInternal(const VideoCodec& video_codec, - size_t max_data_payload_length); + size_t max_data_payload_length, + std::vector stream, + int min_transmit_bitrate); // Implements VideoSinkInterface. void OnFrame(const VideoFrame& video_frame) override; @@ -123,7 +134,7 @@ class ViEEncoder : public rtc::VideoSinkInterface, const uint32_t number_of_cores_; const std::unique_ptr source_proxy_; - EncodedImageCallback* sink_; + EncoderSink* sink_; const VideoSendStream::Config::EncoderSettings settings_; const std::unique_ptr vp_; diff --git a/webrtc/video/vie_encoder_unittest.cc b/webrtc/video/vie_encoder_unittest.cc index ba25a1da4d..8c43fe5740 100644 --- a/webrtc/video/vie_encoder_unittest.cc +++ b/webrtc/video/vie_encoder_unittest.cc @@ -8,6 +8,8 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include + #include "testing/gtest/include/gtest/gtest.h" #include "webrtc/base/logging.h" #include "webrtc/test/encoder_settings.h" @@ -36,7 +38,10 @@ class ViEEncoderTest : public ::testing::Test { video_send_config_.encoder_settings.payload_name = "FAKE"; video_send_config_.encoder_settings.payload_type = 125; - video_encoder_config_.streams = test::CreateVideoStreams(1); + VideoEncoderConfig video_encoder_config; + video_encoder_config.streams = test::CreateVideoStreams(1); + codec_width_ = static_cast(video_encoder_config.streams[0].width); + codec_height_ = static_cast(video_encoder_config.streams[0].height); vie_encoder_.reset(new ViEEncoder( 1 /* number_of_cores */, &stats_proxy_, @@ -45,7 +50,7 @@ class ViEEncoderTest : public ::testing::Test { vie_encoder_->SetSink(&sink_); vie_encoder_->SetSource(&video_source_); vie_encoder_->SetStartBitrate(10000); - vie_encoder_->ConfigureEncoder(video_encoder_config_, 1440); + vie_encoder_->ConfigureEncoder(std::move(video_encoder_config), 1440); } VideoFrame CreateFrame(int64_t ntp_ts, rtc::Event* destruction_event) const { @@ -63,12 +68,9 @@ class ViEEncoderTest : public ::testing::Test { rtc::Event* const event_; }; - VideoFrame frame( - new rtc::RefCountedObject( - destruction_event, - static_cast(video_encoder_config_.streams[0].width), - static_cast(video_encoder_config_.streams[0].height)), - 99, 99, kVideoRotation_0); + VideoFrame frame(new rtc::RefCountedObject( + destruction_event, codec_width_, codec_height_), + 99, 99, kVideoRotation_0); frame.set_ntp_time_ms(ntp_ts); return frame; } @@ -123,21 +125,11 @@ class ViEEncoderTest : public ::testing::Test { int64_t ntp_time_ms_ = 0; }; - class TestSink : public EncodedImageCallback { + class TestSink : public ViEEncoder::EncoderSink { public: explicit TestSink(TestEncoder* test_encoder) : test_encoder_(test_encoder), encoded_frame_event_(false, false) {} - int32_t Encoded(const EncodedImage& encoded_image, - const CodecSpecificInfo* codec_specific_info, - const RTPFragmentationHeader* fragmentation) override { - rtc::CritScope lock(&crit_); - EXPECT_TRUE(expect_frames_); - timestamp_ = encoded_image._timeStamp; - encoded_frame_event_.Set(); - return 0; - } - void WaitForEncodedFrame(int64_t expected_ntp_time) { uint32_t timestamp = 0; EXPECT_TRUE(encoded_frame_event_.Wait(kDefaultTimeoutMs)); @@ -153,16 +145,46 @@ class ViEEncoderTest : public ::testing::Test { expect_frames_ = false; } + int number_of_reconfigurations() { + rtc::CritScope lock(&crit_); + return number_of_reconfigurations_; + } + + int last_min_transmit_bitrate() { + rtc::CritScope lock(&crit_); + return min_transmit_bitrate_bps_; + } + private: + int32_t Encoded(const EncodedImage& encoded_image, + const CodecSpecificInfo* codec_specific_info, + const RTPFragmentationHeader* fragmentation) override { + rtc::CritScope lock(&crit_); + EXPECT_TRUE(expect_frames_); + timestamp_ = encoded_image._timeStamp; + encoded_frame_event_.Set(); + return 0; + } + + void OnEncoderConfigurationChanged(std::vector streams, + int min_transmit_bitrate_bps) override { + rtc::CriticalSection crit_; + ++number_of_reconfigurations_; + min_transmit_bitrate_bps_ = min_transmit_bitrate_bps; + } + rtc::CriticalSection crit_; TestEncoder* test_encoder_; rtc::Event encoded_frame_event_; uint32_t timestamp_ = 0; bool expect_frames_ = true; + int number_of_reconfigurations_ = 0; + int min_transmit_bitrate_bps_ = 0; }; VideoSendStream::Config video_send_config_; - VideoEncoderConfig video_encoder_config_; + int codec_width_; + int codec_height_; TestEncoder fake_encoder_; SendStatisticsProxy stats_proxy_; TestSink sink_; @@ -255,4 +277,27 @@ TEST_F(ViEEncoderTest, DropsPendingFramesOnSlowEncode) { vie_encoder_->Stop(); } +TEST_F(ViEEncoderTest, ConfigureEncoderTriggersOnEncoderConfigurationChanged) { + const int kTargetBitrateBps = 100000; + vie_encoder_->OnBitrateUpdated(kTargetBitrateBps, 0, 0); + + // Capture a frame and wait for it to synchronize with the encoder thread. + vie_encoder_->IncomingCapturedFrame(CreateFrame(1, nullptr)); + sink_.WaitForEncodedFrame(1); + EXPECT_EQ(1, sink_.number_of_reconfigurations()); + + VideoEncoderConfig video_encoder_config; + video_encoder_config.streams = test::CreateVideoStreams(1); + video_encoder_config.min_transmit_bitrate_bps = 9999; + vie_encoder_->ConfigureEncoder(std::move(video_encoder_config), 1440); + + // Capture a frame and wait for it to synchronize with the encoder thread. + vie_encoder_->IncomingCapturedFrame(CreateFrame(2, nullptr)); + sink_.WaitForEncodedFrame(2); + EXPECT_EQ(2, sink_.number_of_reconfigurations()); + EXPECT_EQ(9999, sink_.last_min_transmit_bitrate()); + + vie_encoder_->Stop(); +} + } // namespace webrtc