Unstable BWE due to improper bit rate padding for VP9.

Bug: webrtc:9345
Change-Id: I5b1e0b4ed7a8c1d0b942b09433017cac6d53c64b
Reviewed-on: https://webrtc-review.googlesource.com/79000
Commit-Queue: Michael Horowitz <mhoro@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23496}
This commit is contained in:
“Michael 2018-06-01 14:09:19 -05:00 committed by Commit Bot
parent a7087e37f1
commit 277a656263
6 changed files with 62 additions and 9 deletions

View File

@ -14,6 +14,7 @@
#include <cmath>
#include <vector>
#include "modules/video_coding/codecs/vp9/svc_rate_allocator.h"
#include "modules/video_coding/include/video_codec_interface.h"
namespace webrtc {
@ -63,6 +64,7 @@ std::vector<SpatialLayer> ConfigureSvcNormalVideo(size_t input_width,
num_spatial_layers =
std::min({num_spatial_layers, num_layers_fit_horz, num_layers_fit_vert});
float top_fraction = 0.;
for (size_t sl_idx = 0; sl_idx < num_spatial_layers; ++sl_idx) {
SpatialLayer spatial_layer = {0};
spatial_layer.width = input_width >> (num_spatial_layers - sl_idx - 1);
@ -77,17 +79,24 @@ std::vector<SpatialLayer> ConfigureSvcNormalVideo(size_t input_width,
// TODO(ssilkin): Add to the comment PSNR/SSIM we get at encoding certain
// video to min/max bitrate specified by those formulas.
const size_t num_pixels = spatial_layer.width * spatial_layer.height;
const size_t min_bitrate =
int min_bitrate =
static_cast<int>((600. * std::sqrt(num_pixels) - 95000.) / 1000.);
spatial_layer.minBitrate = std::max(min_bitrate, kMinVp9SvcBitrateKbps);
min_bitrate = std::max(min_bitrate, 0);
spatial_layer.minBitrate =
std::max(static_cast<size_t>(min_bitrate), kMinVp9SvcBitrateKbps);
spatial_layer.maxBitrate =
static_cast<int>((1.6 * num_pixels + 50 * 1000) / 1000);
spatial_layer.targetBitrate =
(spatial_layer.maxBitrate + spatial_layer.minBitrate) / 2;
(spatial_layer.minBitrate + spatial_layer.maxBitrate) / 2;
spatial_layers.push_back(spatial_layer);
top_fraction += std::pow(kSpatialLayeringRateScalingFactor, sl_idx);
}
// Compute spatial_layers[num_spatial_layers - 1].targetBitrate, which is
// used to set max_padding_bitrate_. Set max_padding_bitrate_ equal to the
// minimum total bit rate required to support all spatial layers.
spatial_layers[num_spatial_layers - 1].targetBitrate =
static_cast<unsigned int>(
spatial_layers[num_spatial_layers - 1].minBitrate * top_fraction);
return spatial_layers;
}

View File

@ -18,10 +18,8 @@
namespace webrtc {
namespace {
const float kSpatialLayeringRateScalingFactor = 0.55f;
const float kTemporalLayeringRateScalingFactor = 0.55f;
} // namespace
SvcRateAllocator::SvcRateAllocator(const VideoCodec& codec) : codec_(codec) {
RTC_DCHECK_EQ(codec.codecType, kVideoCodecVP9);

View File

@ -20,6 +20,9 @@
namespace webrtc {
extern const float kSpatialLayeringRateScalingFactor;
extern const float kTemporalLayeringRateScalingFactor;
class SvcRateAllocator : public VideoBitrateAllocator {
public:
explicit SvcRateAllocator(const VideoCodec& codec);

View File

@ -813,6 +813,20 @@ TEST_F(FullStackTest, VP9KSVC_3SL_Low) {
std::vector<SpatialLayer>(), false};
RunTest(simulcast);
}
TEST_F(FullStackTest, VP9KSVC_3SL_Medium_Network_Restricted) {
VideoQualityTest::Params simulcast;
simulcast.call.send_side_bwe = true;
simulcast.video[0] = kSvcVp9Video;
simulcast.analyzer = {"vp9ksvc_3sl_medium_network_restricted", 0.0, 0.0,
kFullStackTestDurationSecs};
simulcast.ss[0] = {
std::vector<VideoStream>(), 0, 3, 1, InterLayerPredMode::kOnKeyPic,
std::vector<SpatialLayer>(), false};
simulcast.pipe.link_capacity_kbps = 1000;
RunTest(simulcast);
}
#endif // !defined(RTC_DISABLE_VP9)
// Android bots can't handle FullHD, so disable the test.

View File

@ -633,8 +633,15 @@ void VideoSendStreamImpl::OnEncoderConfigurationChanged(
encoder_max_bitrate_bps_ =
std::max(static_cast<uint32_t>(encoder_min_bitrate_bps_),
encoder_max_bitrate_bps_);
max_padding_bitrate_ = CalculateMaxPadBitrateBps(
streams, min_transmit_bitrate_bps, config_->suspend_below_min_bitrate);
const VideoCodecType codec_type =
PayloadStringToCodecType(config_->rtp.payload_name);
if (codec_type == kVideoCodecVP9) {
max_padding_bitrate_ = streams[0].target_bitrate_bps;
} else {
max_padding_bitrate_ = CalculateMaxPadBitrateBps(
streams, min_transmit_bitrate_bps, config_->suspend_below_min_bitrate);
}
// Clear stats for disabled layers.
for (size_t i = streams.size(); i < config_->rtp.ssrcs.size(); ++i) {

View File

@ -514,6 +514,28 @@ void VideoStreamEncoder::ReconfigureEncoder() {
RTC_LOG(LS_ERROR) << "Failed to create encoder configuration.";
}
// Set min_bitrate_bps, max_bitrate_bps, and max padding bit rate for VP9.
if (encoder_config_.codec_type == kVideoCodecVP9) {
RTC_DCHECK_EQ(1U, streams.size());
int max_encoder_bitrate_kbps = 0;
for (int i = 0; i < codec.VP9()->numberOfSpatialLayers; ++i) {
max_encoder_bitrate_kbps += codec.spatialLayers[i].maxBitrate;
}
// Lower max bitrate to the level codec actually can produce.
streams[0].max_bitrate_bps =
std::min(streams[0].max_bitrate_bps, max_encoder_bitrate_kbps * 1000);
streams[0].min_bitrate_bps = codec.spatialLayers[0].minBitrate * 1000;
// Pass along the value of maximum padding bit rate from
// spatialLayers[].targetBitrate to streams[0].target_bitrate_bps.
// TODO(ssilkin): There should be some margin between max padding bitrate
// and max encoder bitrate. With the current logic they can be equal.
streams[0].target_bitrate_bps =
std::min(static_cast<unsigned int>(streams[0].max_bitrate_bps),
codec.spatialLayers[codec.VP9()->numberOfSpatialLayers - 1]
.targetBitrate *
1000);
}
codec.startBitrate =
std::max(encoder_start_bitrate_bps_ / 1000, codec.minBitrate);
codec.startBitrate = std::min(codec.startBitrate, codec.maxBitrate);