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}
This commit is contained in:
Per 2016-09-29 11:48:50 +02:00
parent fd0d426692
commit a48ddb7636
13 changed files with 161 additions and 73 deletions

View File

@ -2152,15 +2152,6 @@ VideoSenderInfo WebRtcVideoChannel2::WebRtcVideoSendStream::GetVideoSenderInfo(
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 @@ VideoSenderInfo WebRtcVideoChannel2::WebRtcVideoSendStream::GetVideoSenderInfo(
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;

View File

@ -2890,6 +2890,18 @@ TEST_F(WebRtcVideoChannel2Test, GetStatsReportsUpperResolution) {
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 @@ class WebRtcVideoChannel2SimulcastTest : public testing::Test {
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));
}

View File

@ -29,7 +29,7 @@ std::vector<uint32_t> webrtc::SimulcastRateAllocator::GetAllocation(
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 @@ std::vector<uint32_t> webrtc::SimulcastRateAllocator::GetAllocation(
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_;
}

View File

@ -24,6 +24,7 @@ class SimulcastRateAllocator {
explicit SimulcastRateAllocator(const VideoCodec& codec);
std::vector<uint32_t> GetAllocation(uint32_t bitrate_kbps) const;
uint32_t GetPreferedBitrate() const;
const VideoCodec& GetCodec() const;
private:

View File

@ -208,4 +208,32 @@ TEST_F(SimulcastRateAllocatorTest, OneToThreeStreams) {
}
}
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

View File

@ -2748,6 +2748,9 @@ TEST_F(EndToEndTest, GetStats) {
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) {

View File

@ -339,14 +339,17 @@ void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms(
}
}
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;
}
}

View File

@ -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 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver,
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);

View File

@ -65,6 +65,8 @@ class SendStatisticsProxyTest : public ::testing::Test {
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 @@ TEST_F(SendStatisticsProxyTest, OnEncodedFrameTimeMeasured) {
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 @@ TEST_F(SendStatisticsProxyTest, SwitchContentTypeUpdatesHistograms) {
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 @@ TEST_F(SendStatisticsProxyTest, ResetsRtcpCountersOnContentChange) {
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 @@ TEST_F(SendStatisticsProxyTest, ResetsRtpCountersOnContentChange) {
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,

View File

@ -163,6 +163,7 @@ std::string VideoSendStream::Stats::ToString(int64_t time_ms) const {
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 << '}';

View File

@ -189,6 +189,27 @@ CpuOveruseOptions GetCpuOveruseOptions(bool full_overuse_time) {
} // 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 @@ ViEEncoder::ViEEncoder(uint32_t number_of_cores,
: 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 @@ ViEEncoder::ViEEncoder(uint32_t number_of_cores,
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::SetStartBitrate(int start_bitrate_bps) {
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 @@ void ViEEncoder::ConfigureEncoderInternal(const VideoCodec& video_codec,
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 @@ void ViEEncoder::EncodeVideoFrame(const VideoFrame& video_frame,
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;

View File

@ -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 @@ class ViEEncoder : public rtc::VideoSinkInterface<VideoFrame>,
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 @@ class ViEEncoder : public rtc::VideoSinkInterface<VideoFrame>,
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 @@ class ViEEncoder : public rtc::VideoSinkInterface<VideoFrame>,
// 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_);

View File

@ -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 @@ class VideoSendStream {
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;