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-Original-Commit-Position: refs/heads/master@{#14431}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: a48ddb763695dd6742fdcb6f0e5fa4f9818595e7
diff --git a/media/engine/webrtcvideoengine2.cc b/media/engine/webrtcvideoengine2.cc
index a9e5225..5176c11 100644
--- a/media/engine/webrtcvideoengine2.cc
+++ b/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/media/engine/webrtcvideoengine2_unittest.cc b/media/engine/webrtcvideoengine2_unittest.cc
index c81fd88..955fd35 100644
--- a/media/engine/webrtcvideoengine2_unittest.cc
+++ b/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/modules/video_coding/utility/simulcast_rate_allocator.cc b/modules/video_coding/utility/simulcast_rate_allocator.cc
index 7264541..f6dccf0 100644
--- a/modules/video_coding/utility/simulcast_rate_allocator.cc
+++ b/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/modules/video_coding/utility/simulcast_rate_allocator.h b/modules/video_coding/utility/simulcast_rate_allocator.h
index fb000e2..e7ee772 100644
--- a/modules/video_coding/utility/simulcast_rate_allocator.h
+++ b/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/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc b/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc
index 7a616d9..57fd5d2 100644
--- a/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc
+++ b/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/video/end_to_end_tests.cc b/video/end_to_end_tests.cc
index 0bd1ec2..21707ec 100644
--- a/video/end_to_end_tests.cc
+++ b/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/video/send_statistics_proxy.cc b/video/send_statistics_proxy.cc
index d47ccbd..039e039 100644
--- a/video/send_statistics_proxy.cc
+++ b/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/video/send_statistics_proxy.h b/video/send_statistics_proxy.h
index 88a0e32..49f0bf3 100644
--- a/video/send_statistics_proxy.h
+++ b/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/video/send_statistics_proxy_unittest.cc b/video/send_statistics_proxy_unittest.cc
index 4676651..f5bfaeb 100644
--- a/video/send_statistics_proxy_unittest.cc
+++ b/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/video/video_send_stream.cc b/video/video_send_stream.cc
index c998272..259e828 100644
--- a/video/video_send_stream.cc
+++ b/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/video/vie_encoder.cc b/video/vie_encoder.cc
index febcf42..8c3ca04 100644
--- a/video/vie_encoder.cc
+++ b/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/video/vie_encoder.h b/video/vie_encoder.h
index 15fd9cf..4196844 100644
--- a/video/vie_encoder.h
+++ b/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/video_send_stream.h b/video_send_stream.h
index e987784..7ac4c37 100644
--- a/video_send_stream.h
+++ b/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;