Add VideoSendStream::Stats::prefered_media_bitrate_bps This cl move calculation of stats for prefered_media_bitrate_bps from webrtcvideoengine2.GetStats to SendStatisticsProxy::OnEncoderReconfigured. This aligns better with how other send stats are reported and is needed as a prerequisite for moving video encoder configuration due to video resolution change from WebRtcVideoEngine2 to ViEEncoder. BUG=webrtc:6371 R=mflodman@webrtc.org, sprang@webrtc.org Review URL: https://codereview.webrtc.org/2368223002 . Cr-Commit-Position: refs/heads/master@{#14431}
diff --git a/webrtc/media/engine/webrtcvideoengine2.cc b/webrtc/media/engine/webrtcvideoengine2.cc index a9e5225..5176c11 100644 --- a/webrtc/media/engine/webrtcvideoengine2.cc +++ b/webrtc/media/engine/webrtcvideoengine2.cc
@@ -2152,15 +2152,6 @@ if (parameters_.codec_settings) info.codec_name = parameters_.codec_settings->codec.name; - for (size_t i = 0; i < parameters_.encoder_config.streams.size(); ++i) { - if (i == parameters_.encoder_config.streams.size() - 1) { - info.preferred_bitrate += - parameters_.encoder_config.streams[i].max_bitrate_bps; - } else { - info.preferred_bitrate += - parameters_.encoder_config.streams[i].target_bitrate_bps; - } - } if (stream_ == NULL) return info; @@ -2190,6 +2181,7 @@ info.encode_usage_percent = stats.encode_usage_percent; info.nominal_bitrate = stats.media_bitrate_bps; + info.preferred_bitrate = stats.preferred_media_bitrate_bps; info.send_frame_width = 0; info.send_frame_height = 0;
diff --git a/webrtc/media/engine/webrtcvideoengine2_unittest.cc b/webrtc/media/engine/webrtcvideoengine2_unittest.cc index c81fd88..955fd35 100644 --- a/webrtc/media/engine/webrtcvideoengine2_unittest.cc +++ b/webrtc/media/engine/webrtcvideoengine2_unittest.cc
@@ -2890,6 +2890,18 @@ EXPECT_EQ(90, info.senders[0].send_frame_height); } +TEST_F(WebRtcVideoChannel2Test, GetStatsReportsPreferredBitrate) { + FakeVideoSendStream* stream = AddSendStream(); + webrtc::VideoSendStream::Stats stats; + stats.preferred_media_bitrate_bps = 5; + stream->SetStats(stats); + + cricket::VideoMediaInfo info; + ASSERT_TRUE(channel_->GetStats(&info)); + ASSERT_EQ(1u, info.senders.size()); + EXPECT_EQ(5, info.senders[0].preferred_bitrate); +} + TEST_F(WebRtcVideoChannel2Test, GetStatsTracksAdaptationStats) { AddSendStream(cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs3))); @@ -3768,10 +3780,6 @@ total_max_bitrate_bps += video_streams[i].target_bitrate_bps; } } - cricket::VideoMediaInfo info; - ASSERT_TRUE(channel_->GetStats(&info)); - ASSERT_EQ(1u, info.senders.size()); - EXPECT_EQ(total_max_bitrate_bps, info.senders[0].preferred_bitrate); EXPECT_TRUE(channel_->SetVideoSend(ssrcs.front(), true, nullptr, nullptr)); }
diff --git a/webrtc/modules/video_coding/utility/simulcast_rate_allocator.cc b/webrtc/modules/video_coding/utility/simulcast_rate_allocator.cc index 7264541..f6dccf0 100644 --- a/webrtc/modules/video_coding/utility/simulcast_rate_allocator.cc +++ b/webrtc/modules/video_coding/utility/simulcast_rate_allocator.cc
@@ -29,7 +29,7 @@ if (codec_.maxBitrate) left_to_allocate = std::min(left_to_allocate, codec_.maxBitrate); - if (codec_.numberOfSimulcastStreams == 0) { + if (codec_.numberOfSimulcastStreams < 2) { // No simulcast, just set the target as this has been capped already. return std::vector<uint32_t>(1, left_to_allocate); } @@ -65,6 +65,15 @@ return allocated_bitrates_bps; } +uint32_t SimulcastRateAllocator::GetPreferedBitrate() const { + std::vector<uint32_t> rates = GetAllocation(codec_.maxBitrate); + uint32_t preferred_bitrate = 0; + for (const uint32_t& rate : rates) { + preferred_bitrate += rate; + } + return preferred_bitrate; +} + const VideoCodec& webrtc::SimulcastRateAllocator::GetCodec() const { return codec_; }
diff --git a/webrtc/modules/video_coding/utility/simulcast_rate_allocator.h b/webrtc/modules/video_coding/utility/simulcast_rate_allocator.h index fb000e2..e7ee772 100644 --- a/webrtc/modules/video_coding/utility/simulcast_rate_allocator.h +++ b/webrtc/modules/video_coding/utility/simulcast_rate_allocator.h
@@ -24,6 +24,7 @@ explicit SimulcastRateAllocator(const VideoCodec& codec); std::vector<uint32_t> GetAllocation(uint32_t bitrate_kbps) const; + uint32_t GetPreferedBitrate() const; const VideoCodec& GetCodec() const; private:
diff --git a/webrtc/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc b/webrtc/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc index 7a616d9..57fd5d2 100644 --- a/webrtc/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc +++ b/webrtc/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc
@@ -208,4 +208,32 @@ } } +TEST_F(SimulcastRateAllocatorTest, GetPreferredBitrate) { + EXPECT_EQ(codec_.maxBitrate, allocator_->GetPreferedBitrate()); +} + +TEST_F(SimulcastRateAllocatorTest, GetPreferredBitrateSimulcast) { + codec_.numberOfSimulcastStreams = 3; + codec_.maxBitrate = 999999; + codec_.simulcastStream[0].minBitrate = 10; + codec_.simulcastStream[0].targetBitrate = 100; + + codec_.simulcastStream[0].maxBitrate = 500; + codec_.simulcastStream[1].minBitrate = 50; + codec_.simulcastStream[1].targetBitrate = 500; + codec_.simulcastStream[1].maxBitrate = 1000; + + codec_.simulcastStream[2].minBitrate = 2000; + codec_.simulcastStream[2].targetBitrate = 3000; + codec_.simulcastStream[2].maxBitrate = 4000; + CreateAllocator(); + + uint32_t preferred_bitrate; + preferred_bitrate = codec_.simulcastStream[0].targetBitrate; + preferred_bitrate += codec_.simulcastStream[1].targetBitrate; + preferred_bitrate += codec_.simulcastStream[2].maxBitrate; + + EXPECT_EQ(preferred_bitrate, allocator_->GetPreferedBitrate()); +} + } // namespace webrtc
diff --git a/webrtc/video/end_to_end_tests.cc b/webrtc/video/end_to_end_tests.cc index 0bd1ec2..21707ec 100644 --- a/webrtc/video/end_to_end_tests.cc +++ b/webrtc/video/end_to_end_tests.cc
@@ -2748,6 +2748,9 @@ stats.encoder_implementation_name == test::FakeEncoder::kImplementationName; + send_stats_filled_["EncoderPreferredBitrate"] |= + stats.preferred_media_bitrate_bps > 0; + for (std::map<uint32_t, VideoSendStream::StreamStats>::const_iterator it = stats.substreams.begin(); it != stats.substreams.end(); ++it) {
diff --git a/webrtc/video/send_statistics_proxy.cc b/webrtc/video/send_statistics_proxy.cc index d47ccbd..039e039 100644 --- a/webrtc/video/send_statistics_proxy.cc +++ b/webrtc/video/send_statistics_proxy.cc
@@ -339,14 +339,17 @@ } } -void SendStatisticsProxy::SetContentType( - VideoEncoderConfig::ContentType content_type) { +void SendStatisticsProxy::OnEncoderReconfigured( + const VideoEncoderConfig& config, + uint32_t preferred_bitrate_bps) { rtc::CritScope lock(&crit_); - if (content_type_ != content_type) { + stats_.preferred_media_bitrate_bps = preferred_bitrate_bps; + + if (content_type_ != config.content_type) { uma_container_->UpdateHistograms(rtp_config_, stats_); - uma_container_.reset( - new UmaSamplesContainer(GetUmaPrefix(content_type), stats_, clock_)); - content_type_ = content_type; + uma_container_.reset(new UmaSamplesContainer( + GetUmaPrefix(config.content_type), stats_, clock_)); + content_type_ = config.content_type; } }
diff --git a/webrtc/video/send_statistics_proxy.h b/webrtc/video/send_statistics_proxy.h index 88a0e32..49f0bf3 100644 --- a/webrtc/video/send_statistics_proxy.h +++ b/webrtc/video/send_statistics_proxy.h
@@ -14,6 +14,7 @@ #include <map> #include <memory> #include <string> +#include <vector> #include "webrtc/base/criticalsection.h" #include "webrtc/base/exp_filter.h" @@ -57,8 +58,9 @@ void OnInactiveSsrc(uint32_t ssrc); // Used to indicate change in content type, which may require a change in - // how stats are collected. - void SetContentType(VideoEncoderConfig::ContentType content_type); + // how stats are collected and set the configured preferred media bitrate. + void OnEncoderReconfigured(const VideoEncoderConfig& encoder_config, + uint32_t preferred_bitrate_bps); // Used to update the encoder target rate. void OnSetEncoderTargetRate(uint32_t bitrate_bps);
diff --git a/webrtc/video/send_statistics_proxy_unittest.cc b/webrtc/video/send_statistics_proxy_unittest.cc index 4676651..f5bfaeb 100644 --- a/webrtc/video/send_statistics_proxy_unittest.cc +++ b/webrtc/video/send_statistics_proxy_unittest.cc
@@ -65,6 +65,8 @@ EXPECT_EQ(one.input_frame_rate, other.input_frame_rate); EXPECT_EQ(one.encode_frame_rate, other.encode_frame_rate); EXPECT_EQ(one.media_bitrate_bps, other.media_bitrate_bps); + EXPECT_EQ(one.preferred_media_bitrate_bps, + other.preferred_media_bitrate_bps); EXPECT_EQ(one.suspended, other.suspended); EXPECT_EQ(one.substreams.size(), other.substreams.size()); @@ -288,6 +290,17 @@ EXPECT_EQ(metrics.encode_usage_percent, stats.encode_usage_percent); } +TEST_F(SendStatisticsProxyTest, OnEncoderReconfiguredChangePreferredBitrate) { + VideoSendStream::Stats stats = statistics_proxy_->GetStats(); + EXPECT_EQ(0, stats.preferred_media_bitrate_bps); + const int kPreferredMediaBitrateBps = 50; + + VideoEncoderConfig config; + statistics_proxy_->OnEncoderReconfigured(config, kPreferredMediaBitrateBps); + stats = statistics_proxy_->GetStats(); + EXPECT_EQ(kPreferredMediaBitrateBps, stats.preferred_media_bitrate_bps); +} + TEST_F(SendStatisticsProxyTest, SwitchContentTypeUpdatesHistograms) { const int kWidth = 640; const int kHeight = 480; @@ -295,13 +308,15 @@ for (int i = 0; i < kMinRequiredSamples; ++i) statistics_proxy_->OnIncomingFrame(kWidth, kHeight); - // No switch, stats not should be updated. - statistics_proxy_->SetContentType( - VideoEncoderConfig::ContentType::kRealtimeVideo); + // No switch, stats should not be updated. + VideoEncoderConfig config; + config.content_type = VideoEncoderConfig::ContentType::kRealtimeVideo; + statistics_proxy_->OnEncoderReconfigured(config, 50); EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.InputWidthInPixels")); // Switch to screenshare, real-time stats should be updated. - statistics_proxy_->SetContentType(VideoEncoderConfig::ContentType::kScreen); + config.content_type = VideoEncoderConfig::ContentType::kScreen; + statistics_proxy_->OnEncoderReconfigured(config, 50); EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InputWidthInPixels")); } @@ -538,7 +553,9 @@ proxy->RtcpPacketTypesCounterUpdated(kSecondSsrc, counters); // Changing content type causes histograms to be reported. - statistics_proxy_->SetContentType(VideoEncoderConfig::ContentType::kScreen); + VideoEncoderConfig config; + config.content_type = VideoEncoderConfig::ContentType::kScreen; + statistics_proxy_->OnEncoderReconfigured(config, 50); EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.NackPacketsReceivedPerMinute")); @@ -633,7 +650,9 @@ proxy->DataCountersUpdated(rtx_counters, kSecondRtxSsrc); // Changing content type causes histograms to be reported. - statistics_proxy_->SetContentType(VideoEncoderConfig::ContentType::kScreen); + VideoEncoderConfig config; + config.content_type = VideoEncoderConfig::ContentType::kScreen; + statistics_proxy_->OnEncoderReconfigured(config, 50); EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.BitrateSentInKbps")); EXPECT_EQ(1,
diff --git a/webrtc/video/video_send_stream.cc b/webrtc/video/video_send_stream.cc index c998272..259e828 100644 --- a/webrtc/video/video_send_stream.cc +++ b/webrtc/video/video_send_stream.cc
@@ -163,6 +163,7 @@ ss << "encode_usage_perc: " << encode_usage_percent << ", "; ss << "target_bps: " << target_media_bitrate_bps << ", "; ss << "media_bps: " << media_bitrate_bps << ", "; + ss << "preferred_media_bitrate_bps: " << preferred_media_bitrate_bps << ", "; ss << "suspended: " << (suspended ? "true" : "false") << ", "; ss << "bw_adapted: " << (bw_limited_resolution ? "true" : "false"); ss << '}';
diff --git a/webrtc/video/vie_encoder.cc b/webrtc/video/vie_encoder.cc index febcf42..8c3ca04 100644 --- a/webrtc/video/vie_encoder.cc +++ b/webrtc/video/vie_encoder.cc
@@ -189,6 +189,27 @@ } // namespace +class ViEEncoder::ConfigureEncoderTask : public rtc::QueuedTask { + public: + ConfigureEncoderTask(ViEEncoder* vie_encoder, + VideoEncoderConfig config, + size_t max_data_payload_length) + : vie_encoder_(vie_encoder), + config_(std::move(config)), + max_data_payload_length_(max_data_payload_length) {} + + private: + bool Run() override { + vie_encoder_->ConfigureEncoderOnTaskQueue(std::move(config_), + max_data_payload_length_); + return true; + } + + ViEEncoder* const vie_encoder_; + VideoEncoderConfig config_; + size_t max_data_payload_length_; +}; + class ViEEncoder::EncodeTask : public rtc::QueuedTask { public: EncodeTask(const VideoFrame& frame, @@ -282,7 +303,9 @@ : shutdown_event_(true /* manual_reset */, false), number_of_cores_(number_of_cores), source_proxy_(new VideoSourceProxy(this)), + sink_(nullptr), settings_(settings), + codec_type_(PayloadNameToCodecType(settings.payload_name)), vp_(VideoProcessing::Create()), video_sender_(Clock::GetRealTimeClock(), this, this), overuse_detector_(Clock::GetRealTimeClock(), @@ -296,6 +319,7 @@ module_process_thread_(nullptr), encoder_config_(), encoder_start_bitrate_bps_(0), + max_data_payload_length_(0), last_observed_bitrate_bps_(0), encoder_paused_and_dropped_frame_(false), has_received_sli_(false), @@ -374,41 +398,35 @@ void ViEEncoder::ConfigureEncoder(VideoEncoderConfig config, size_t max_data_payload_length) { - VideoCodec video_codec = VideoEncoderConfigToVideoCodec( - config, settings_.payload_name, settings_.payload_type); - LOG(LS_INFO) << "ConfigureEncoder: " << config.ToString(); - std::vector<VideoStream> 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; + encoder_queue_.PostTask( + std::unique_ptr<rtc::QueuedTask>(new ConfigureEncoderTask( + this, std::move(config), max_data_payload_length))); } -void ViEEncoder::ConfigureEncoderInternal(const VideoCodec& video_codec, - size_t max_data_payload_length, - std::vector<VideoStream> stream, - int min_transmit_bitrate) { +void ViEEncoder::ConfigureEncoderOnTaskQueue(VideoEncoderConfig config, + size_t max_data_payload_length) { RTC_DCHECK_RUN_ON(&encoder_queue_); - RTC_DCHECK_GE(encoder_start_bitrate_bps_, 0); RTC_DCHECK(sink_); + LOG(LS_INFO) << "ConfigureEncoderOnTaskQueue"; + + max_data_payload_length_ = max_data_payload_length; + encoder_config_ = std::move(config); + + VideoCodec video_codec = VideoEncoderConfigToVideoCodec( + encoder_config_, settings_.payload_name, settings_.payload_type); // Setting target width and height for VPM. RTC_CHECK_EQ(VPM_OK, vp_->SetTargetResolution(video_codec.width, video_codec.height, video_codec.maxFramerate)); - encoder_config_ = video_codec; - encoder_config_.startBitrate = encoder_start_bitrate_bps_ / 1000; - encoder_config_.startBitrate = - std::max(encoder_config_.startBitrate, video_codec.minBitrate); - encoder_config_.startBitrate = - std::min(encoder_config_.startBitrate, video_codec.maxBitrate); + video_codec.startBitrate = + std::max(encoder_start_bitrate_bps_ / 1000, video_codec.minBitrate); + video_codec.startBitrate = + std::min(video_codec.startBitrate, video_codec.maxBitrate); bool success = video_sender_.RegisterSendCodec( - &encoder_config_, number_of_cores_, + &video_codec, number_of_cores_, static_cast<uint32_t>(max_data_payload_length)) == VCM_OK; if (!success) { @@ -416,24 +434,14 @@ RTC_DCHECK(success); } + rate_allocator_.reset(new SimulcastRateAllocator(video_codec)); if (stats_proxy_) { - VideoEncoderConfig::ContentType content_type = - VideoEncoderConfig::ContentType::kRealtimeVideo; - switch (video_codec.mode) { - case kRealtimeVideo: - content_type = VideoEncoderConfig::ContentType::kRealtimeVideo; - break; - case kScreensharing: - content_type = VideoEncoderConfig::ContentType::kScreen; - break; - default: - RTC_NOTREACHED(); - break; - } - stats_proxy_->SetContentType(content_type); + stats_proxy_->OnEncoderReconfigured(encoder_config_, + rate_allocator_->GetPreferedBitrate()); } - sink_->OnEncoderConfigurationChanged(stream, min_transmit_bitrate); + sink_->OnEncoderConfigurationChanged( + encoder_config_.streams, encoder_config_.min_transmit_bitrate_bps); } void ViEEncoder::OnFrame(const VideoFrame& video_frame) { @@ -537,7 +545,7 @@ overuse_detector_.FrameCaptured(video_frame, time_when_posted_in_ms); - if (encoder_config_.codecType == webrtc::kVideoCodecVP8) { + if (codec_type_ == webrtc::kVideoCodecVP8) { webrtc::CodecSpecificInfo codec_specific_info; codec_specific_info.codecType = webrtc::kVideoCodecVP8;
diff --git a/webrtc/video/vie_encoder.h b/webrtc/video/vie_encoder.h index 15fd9cf..4196844 100644 --- a/webrtc/video/vie_encoder.h +++ b/webrtc/video/vie_encoder.h
@@ -23,6 +23,7 @@ #include "webrtc/common_types.h" #include "webrtc/media/base/videosinkinterface.h" #include "webrtc/modules/video_coding/include/video_coding_defines.h" +#include "webrtc/modules/video_coding/utility/simulcast_rate_allocator.h" #include "webrtc/modules/video_coding/video_coding_impl.h" #include "webrtc/modules/video_processing/include/video_processing.h" #include "webrtc/system_wrappers/include/atomic32.h" @@ -97,13 +98,12 @@ int64_t round_trip_time_ms); private: + class ConfigureEncoderTask; class EncodeTask; class VideoSourceProxy; - void ConfigureEncoderInternal(const VideoCodec& video_codec, - size_t max_data_payload_length, - std::vector<VideoStream> stream, - int min_transmit_bitrate); + void ConfigureEncoderOnTaskQueue(VideoEncoderConfig config, + size_t max_data_payload_length); // Implements VideoSinkInterface. void OnFrame(const VideoFrame& video_frame) override; @@ -136,6 +136,7 @@ const std::unique_ptr<VideoSourceProxy> source_proxy_; EncoderSink* sink_; const VideoSendStream::Config::EncoderSettings settings_; + const VideoCodecType codec_type_; const std::unique_ptr<VideoProcessing> vp_; vcm::VideoSender video_sender_ ACCESS_ON(&encoder_queue_); @@ -151,9 +152,15 @@ // of ViEEncoder are called on the same thread. rtc::ThreadChecker thread_checker_; - VideoCodec encoder_config_ ACCESS_ON(&encoder_queue_); + VideoEncoderConfig encoder_config_ ACCESS_ON(&encoder_queue_); + // TODO(sprang): Change |rate_allocator_| to be a codec type + // agnostic interface. It is currently VP8 simulcast specific if more than + // one layer is specified. + std::unique_ptr<SimulcastRateAllocator> rate_allocator_ + ACCESS_ON(&encoder_queue_); - int encoder_start_bitrate_bps_ ACCESS_ON(&encoder_queue_); + uint32_t encoder_start_bitrate_bps_ ACCESS_ON(&encoder_queue_); + size_t max_data_payload_length_ ACCESS_ON(&encoder_queue_); uint32_t last_observed_bitrate_bps_ ACCESS_ON(&encoder_queue_); bool encoder_paused_and_dropped_frame_ ACCESS_ON(&encoder_queue_); bool has_received_sli_ ACCESS_ON(&encoder_queue_);
diff --git a/webrtc/video_send_stream.h b/webrtc/video_send_stream.h index e987784..7ac4c37 100644 --- a/webrtc/video_send_stream.h +++ b/webrtc/video_send_stream.h
@@ -15,6 +15,7 @@ #include <string> #include <utility> #include <vector> +#include <utility> #include "webrtc/base/platform_file.h" #include "webrtc/common_types.h" @@ -55,8 +56,14 @@ int encode_frame_rate = 0; int avg_encode_time_ms = 0; int encode_usage_percent = 0; + // Bitrate the encoder is currently configured to use due to bandwidth + // limitations. int target_media_bitrate_bps = 0; + // Bitrate the encoder is actually producing. int media_bitrate_bps = 0; + // Media bitrate this VideoSendStream is configured to prefer if there are + // no bandwidth limitations. + int preferred_media_bitrate_bps = 0; bool suspended = false; bool bw_limited_resolution = false; std::map<uint32_t, StreamStats> substreams;