Activate/deactivate VP9 spatial layers.
* Stop encoding spatial layers S(n >= N) if application deactivates spatial layer N by setting RTCRtpEncodingParameters.active = false. * Move calculation of padding bitrate to SvcRateAllocator class. * Pad up to minimum required bitrate of base layer if ALR probing is enabled. Bug: webrtc:9350 Change-Id: I398284c943d43348def535c83263fc234c9767fa Reviewed-on: https://webrtc-review.googlesource.com/c/113240 Reviewed-by: Erik Språng <sprang@webrtc.org> Reviewed-by: Stefan Holmer <stefan@webrtc.org> Commit-Queue: Sergey Silkin <ssilkin@webrtc.org> Cr-Commit-Position: refs/heads/master@{#25945}
This commit is contained in:
parent
b47ccc38e7
commit
8b9b5f98db
@ -1989,7 +1989,9 @@ WebRtcVideoChannel::WebRtcVideoSendStream::CreateVideoEncoderConfig(
|
||||
RTC_DCHECK_GE(rtp_parameters_.encodings.size(),
|
||||
encoder_config.number_of_streams);
|
||||
RTC_DCHECK_GT(encoder_config.number_of_streams, 0);
|
||||
encoder_config.simulcast_layers.resize(encoder_config.number_of_streams);
|
||||
|
||||
// Copy all provided constraints.
|
||||
encoder_config.simulcast_layers.resize(rtp_parameters_.encodings.size());
|
||||
for (size_t i = 0; i < encoder_config.simulcast_layers.size(); ++i) {
|
||||
encoder_config.simulcast_layers[i].active =
|
||||
rtp_parameters_.encodings[i].active;
|
||||
@ -2701,7 +2703,7 @@ std::vector<webrtc::VideoStream> EncoderStreamFactory::CreateEncoderStreams(
|
||||
RTC_DCHECK_EQ(1, encoder_config.number_of_streams);
|
||||
}
|
||||
RTC_DCHECK_GT(encoder_config.number_of_streams, 0);
|
||||
RTC_DCHECK_EQ(encoder_config.simulcast_layers.size(),
|
||||
RTC_DCHECK_GE(encoder_config.simulcast_layers.size(),
|
||||
encoder_config.number_of_streams);
|
||||
std::vector<webrtc::VideoStream> layers;
|
||||
|
||||
|
||||
@ -3112,6 +3112,38 @@ TEST_F(Vp9SettingsTest, MultipleSsrcsEnablesSvc) {
|
||||
EXPECT_TRUE(channel_->SetVideoSend(ssrcs[0], nullptr, nullptr));
|
||||
}
|
||||
|
||||
TEST_F(Vp9SettingsTest, AllEncodingParametersCopied) {
|
||||
cricket::VideoSendParameters send_parameters;
|
||||
send_parameters.codecs.push_back(GetEngineCodec("VP9"));
|
||||
ASSERT_TRUE(channel_->SetSendParameters(send_parameters));
|
||||
|
||||
const size_t kNumSpatialLayers = 3;
|
||||
std::vector<uint32_t> ssrcs = MAKE_VECTOR(kSsrcs3);
|
||||
|
||||
FakeVideoSendStream* stream =
|
||||
AddSendStream(CreateSimStreamParams("cname", ssrcs));
|
||||
|
||||
webrtc::RtpParameters parameters = channel_->GetRtpSendParameters(ssrcs[0]);
|
||||
ASSERT_EQ(kNumSpatialLayers, parameters.encodings.size());
|
||||
ASSERT_TRUE(parameters.encodings[0].active);
|
||||
ASSERT_TRUE(parameters.encodings[1].active);
|
||||
ASSERT_TRUE(parameters.encodings[2].active);
|
||||
// Invert value to verify copying.
|
||||
parameters.encodings[1].active = false;
|
||||
EXPECT_TRUE(channel_->SetRtpSendParameters(ssrcs[0], parameters).ok());
|
||||
|
||||
webrtc::VideoEncoderConfig encoder_config = stream->GetEncoderConfig().Copy();
|
||||
|
||||
// number_of_streams should be 1 since all spatial layers are sent on the
|
||||
// same SSRC. But encoding parameters of all layers is supposed to be copied
|
||||
// and stored in simulcast_layers[].
|
||||
EXPECT_EQ(1u, encoder_config.number_of_streams);
|
||||
EXPECT_EQ(encoder_config.simulcast_layers.size(), kNumSpatialLayers);
|
||||
EXPECT_TRUE(encoder_config.simulcast_layers[0].active);
|
||||
EXPECT_FALSE(encoder_config.simulcast_layers[1].active);
|
||||
EXPECT_TRUE(encoder_config.simulcast_layers[2].active);
|
||||
}
|
||||
|
||||
class Vp9SettingsTestWithFieldTrial : public Vp9SettingsTest {
|
||||
public:
|
||||
explicit Vp9SettingsTestWithFieldTrial(const char* field_trials)
|
||||
|
||||
@ -15,7 +15,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
|
||||
#include "modules/video_coding/codecs/vp9/svc_rate_allocator.h"
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
@ -47,6 +46,7 @@ std::vector<SpatialLayer> ConfigureSvcScreenSharing(size_t input_width,
|
||||
spatial_layer.maxBitrate =
|
||||
static_cast<int>(kMaxScreenSharingLayerBitrateKbps[sl_idx]);
|
||||
spatial_layer.targetBitrate = spatial_layer.maxBitrate;
|
||||
spatial_layer.active = true;
|
||||
spatial_layers.push_back(spatial_layer);
|
||||
}
|
||||
|
||||
@ -70,13 +70,13 @@ 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);
|
||||
spatial_layer.height = input_height >> (num_spatial_layers - sl_idx - 1);
|
||||
spatial_layer.maxFramerate = max_framerate_fps;
|
||||
spatial_layer.numberOfTemporalLayers = num_temporal_layers;
|
||||
spatial_layer.active = true;
|
||||
|
||||
// minBitrate and maxBitrate formulas were derived from
|
||||
// subjective-quality data to determing bit rates below which video
|
||||
@ -96,14 +96,8 @@ std::vector<SpatialLayer> ConfigureSvcNormalVideo(size_t input_width,
|
||||
spatial_layer.targetBitrate =
|
||||
(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;
|
||||
}
|
||||
|
||||
|
||||
@ -23,8 +23,85 @@ namespace webrtc {
|
||||
const float kSpatialLayeringRateScalingFactor = 0.55f;
|
||||
const float kTemporalLayeringRateScalingFactor = 0.55f;
|
||||
|
||||
static size_t GetNumActiveSpatialLayers(const VideoCodec& codec) {
|
||||
RTC_DCHECK_EQ(codec.codecType, kVideoCodecVP9);
|
||||
RTC_DCHECK_GT(codec.VP9().numberOfSpatialLayers, 0u);
|
||||
|
||||
size_t num_spatial_layers = 0;
|
||||
for (; num_spatial_layers < codec.VP9().numberOfSpatialLayers;
|
||||
++num_spatial_layers) {
|
||||
if (!codec.spatialLayers[num_spatial_layers].active) {
|
||||
// TODO(bugs.webrtc.org/9350): Deactivation of middle layer is not
|
||||
// implemented. For now deactivation of a VP9 layer deactivates all
|
||||
// layers above the deactivated one.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return num_spatial_layers;
|
||||
}
|
||||
|
||||
static bool AdjustAndVerify(const VideoCodec& codec,
|
||||
std::vector<size_t>* spatial_layer_bitrate_bps) {
|
||||
bool enough_bitrate = true;
|
||||
size_t excess_rate = 0;
|
||||
for (size_t sl_idx = 0;
|
||||
sl_idx < spatial_layer_bitrate_bps->size() && enough_bitrate; ++sl_idx) {
|
||||
RTC_DCHECK_GT(codec.spatialLayers[sl_idx].maxBitrate, 0);
|
||||
RTC_DCHECK_GE(codec.spatialLayers[sl_idx].maxBitrate,
|
||||
codec.spatialLayers[sl_idx].minBitrate);
|
||||
|
||||
const size_t min_bitrate_bps =
|
||||
codec.spatialLayers[sl_idx].minBitrate * 1000;
|
||||
const size_t max_bitrate_bps =
|
||||
codec.spatialLayers[sl_idx].maxBitrate * 1000;
|
||||
|
||||
spatial_layer_bitrate_bps->at(sl_idx) += excess_rate;
|
||||
if (spatial_layer_bitrate_bps->at(sl_idx) < max_bitrate_bps) {
|
||||
excess_rate = 0;
|
||||
} else {
|
||||
excess_rate = spatial_layer_bitrate_bps->at(sl_idx) - max_bitrate_bps;
|
||||
spatial_layer_bitrate_bps->at(sl_idx) = max_bitrate_bps;
|
||||
}
|
||||
|
||||
size_t bitrate_bps = spatial_layer_bitrate_bps->at(sl_idx);
|
||||
enough_bitrate = (bitrate_bps >= min_bitrate_bps);
|
||||
}
|
||||
|
||||
return enough_bitrate;
|
||||
}
|
||||
|
||||
static std::vector<size_t> SplitBitrate(size_t num_layers,
|
||||
size_t total_bitrate,
|
||||
float rate_scaling_factor) {
|
||||
std::vector<size_t> bitrates;
|
||||
|
||||
double denominator = 0.0;
|
||||
for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) {
|
||||
denominator += std::pow(rate_scaling_factor, layer_idx);
|
||||
}
|
||||
|
||||
double numerator = std::pow(rate_scaling_factor, num_layers - 1);
|
||||
for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) {
|
||||
bitrates.push_back(numerator * total_bitrate / denominator);
|
||||
numerator /= rate_scaling_factor;
|
||||
}
|
||||
|
||||
const size_t sum = std::accumulate(bitrates.begin(), bitrates.end(), 0);
|
||||
// Ensure the sum of split bitrates doesn't exceed the total bitrate.
|
||||
RTC_DCHECK_LE(sum, total_bitrate);
|
||||
|
||||
// Keep the sum of split bitrates equal to the total bitrate by adding bits,
|
||||
// which were lost due to rounding, to the latest layer.
|
||||
bitrates.back() += total_bitrate - sum;
|
||||
|
||||
return bitrates;
|
||||
}
|
||||
|
||||
SvcRateAllocator::SvcRateAllocator(const VideoCodec& codec) : codec_(codec) {
|
||||
RTC_DCHECK_EQ(codec.codecType, kVideoCodecVP9);
|
||||
RTC_DCHECK_GT(codec.VP9().numberOfSpatialLayers, 0u);
|
||||
RTC_DCHECK_GT(codec.VP9().numberOfTemporalLayers, 0u);
|
||||
}
|
||||
|
||||
VideoBitrateAllocation SvcRateAllocator::GetAllocation(
|
||||
@ -36,24 +113,27 @@ VideoBitrateAllocation SvcRateAllocator::GetAllocation(
|
||||
|
||||
if (codec_.spatialLayers[0].targetBitrate == 0) {
|
||||
// Delegate rate distribution to VP9 encoder wrapper if bitrate thresholds
|
||||
// are not initialized.
|
||||
// are not set.
|
||||
VideoBitrateAllocation bitrate_allocation;
|
||||
bitrate_allocation.SetBitrate(0, 0, total_bitrate_bps);
|
||||
return bitrate_allocation;
|
||||
} else if (codec_.mode == VideoCodecMode::kRealtimeVideo) {
|
||||
return GetAllocationNormalVideo(total_bitrate_bps);
|
||||
}
|
||||
|
||||
size_t num_spatial_layers = GetNumActiveSpatialLayers(codec_);
|
||||
if (num_spatial_layers == 0) {
|
||||
return VideoBitrateAllocation(); // All layers are deactivated.
|
||||
}
|
||||
|
||||
if (codec_.mode == VideoCodecMode::kRealtimeVideo) {
|
||||
return GetAllocationNormalVideo(total_bitrate_bps, num_spatial_layers);
|
||||
} else {
|
||||
return GetAllocationScreenSharing(total_bitrate_bps);
|
||||
return GetAllocationScreenSharing(total_bitrate_bps, num_spatial_layers);
|
||||
}
|
||||
}
|
||||
|
||||
VideoBitrateAllocation SvcRateAllocator::GetAllocationNormalVideo(
|
||||
uint32_t total_bitrate_bps) const {
|
||||
size_t num_spatial_layers = codec_.VP9().numberOfSpatialLayers;
|
||||
RTC_CHECK(num_spatial_layers > 0);
|
||||
size_t num_temporal_layers = codec_.VP9().numberOfTemporalLayers;
|
||||
RTC_CHECK(num_temporal_layers > 0);
|
||||
|
||||
uint32_t total_bitrate_bps,
|
||||
size_t num_spatial_layers) const {
|
||||
std::vector<size_t> spatial_layer_bitrate_bps;
|
||||
|
||||
// Distribute total bitrate across spatial layers. If there is not enough
|
||||
@ -65,7 +145,8 @@ VideoBitrateAllocation SvcRateAllocator::GetAllocationNormalVideo(
|
||||
SplitBitrate(num_spatial_layers, total_bitrate_bps,
|
||||
kSpatialLayeringRateScalingFactor);
|
||||
|
||||
const bool enough_bitrate = AdjustAndVerify(&spatial_layer_bitrate_bps);
|
||||
const bool enough_bitrate =
|
||||
AdjustAndVerify(codec_, &spatial_layer_bitrate_bps);
|
||||
if (enough_bitrate || num_spatial_layers == 1) {
|
||||
break;
|
||||
}
|
||||
@ -73,6 +154,7 @@ VideoBitrateAllocation SvcRateAllocator::GetAllocationNormalVideo(
|
||||
|
||||
VideoBitrateAllocation bitrate_allocation;
|
||||
|
||||
const size_t num_temporal_layers = codec_.VP9().numberOfTemporalLayers;
|
||||
for (size_t sl_idx = 0; sl_idx < num_spatial_layers; ++sl_idx) {
|
||||
std::vector<size_t> temporal_layer_bitrate_bps =
|
||||
SplitBitrate(num_temporal_layers, spatial_layer_bitrate_bps[sl_idx],
|
||||
@ -102,41 +184,9 @@ VideoBitrateAllocation SvcRateAllocator::GetAllocationNormalVideo(
|
||||
return bitrate_allocation;
|
||||
}
|
||||
|
||||
bool SvcRateAllocator::AdjustAndVerify(
|
||||
std::vector<size_t>* spatial_layer_bitrate_bps) const {
|
||||
bool enough_bitrate = true;
|
||||
size_t excess_rate = 0;
|
||||
for (size_t sl_idx = 0;
|
||||
sl_idx < spatial_layer_bitrate_bps->size() && enough_bitrate; ++sl_idx) {
|
||||
RTC_DCHECK_GT(codec_.spatialLayers[sl_idx].maxBitrate, 0);
|
||||
RTC_DCHECK_GE(codec_.spatialLayers[sl_idx].maxBitrate,
|
||||
codec_.spatialLayers[sl_idx].minBitrate);
|
||||
|
||||
const size_t min_bitrate_bps =
|
||||
codec_.spatialLayers[sl_idx].minBitrate * 1000;
|
||||
const size_t max_bitrate_bps =
|
||||
codec_.spatialLayers[sl_idx].maxBitrate * 1000;
|
||||
|
||||
spatial_layer_bitrate_bps->at(sl_idx) += excess_rate;
|
||||
if (spatial_layer_bitrate_bps->at(sl_idx) < max_bitrate_bps) {
|
||||
excess_rate = 0;
|
||||
} else {
|
||||
excess_rate = spatial_layer_bitrate_bps->at(sl_idx) - max_bitrate_bps;
|
||||
spatial_layer_bitrate_bps->at(sl_idx) = max_bitrate_bps;
|
||||
}
|
||||
|
||||
enough_bitrate = (spatial_layer_bitrate_bps->at(sl_idx) >= min_bitrate_bps);
|
||||
}
|
||||
|
||||
return enough_bitrate;
|
||||
}
|
||||
|
||||
VideoBitrateAllocation SvcRateAllocator::GetAllocationScreenSharing(
|
||||
uint32_t total_bitrate_bps) const {
|
||||
const size_t num_spatial_layers = codec_.VP9().numberOfSpatialLayers;
|
||||
RTC_CHECK(num_spatial_layers > 0);
|
||||
RTC_CHECK_EQ(codec_.VP9().numberOfTemporalLayers, 1U);
|
||||
|
||||
uint32_t total_bitrate_bps,
|
||||
size_t num_spatial_layers) const {
|
||||
VideoBitrateAllocation bitrate_allocation;
|
||||
|
||||
// Add next layer after bitrate of previous layer has reached its maximum.
|
||||
@ -160,32 +210,43 @@ VideoBitrateAllocation SvcRateAllocator::GetAllocationScreenSharing(
|
||||
return bitrate_allocation;
|
||||
}
|
||||
|
||||
std::vector<size_t> SvcRateAllocator::SplitBitrate(
|
||||
size_t num_layers,
|
||||
size_t total_bitrate,
|
||||
float rate_scaling_factor) const {
|
||||
std::vector<size_t> bitrates;
|
||||
uint32_t SvcRateAllocator::GetMaxBitrateBps(const VideoCodec& codec) {
|
||||
const size_t num_spatial_layers = GetNumActiveSpatialLayers(codec);
|
||||
|
||||
double denominator = 0.0;
|
||||
for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) {
|
||||
denominator += std::pow(rate_scaling_factor, layer_idx);
|
||||
uint32_t max_bitrate_kbps = 0;
|
||||
for (size_t sl_idx = 0; sl_idx < num_spatial_layers; ++sl_idx) {
|
||||
max_bitrate_kbps += codec.spatialLayers[sl_idx].maxBitrate;
|
||||
}
|
||||
|
||||
double numerator = std::pow(rate_scaling_factor, num_layers - 1);
|
||||
for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) {
|
||||
bitrates.push_back(numerator * total_bitrate / denominator);
|
||||
numerator /= rate_scaling_factor;
|
||||
if (codec.maxBitrate != 0) {
|
||||
max_bitrate_kbps = std::min(max_bitrate_kbps, codec.maxBitrate);
|
||||
}
|
||||
|
||||
const size_t sum = std::accumulate(bitrates.begin(), bitrates.end(), 0);
|
||||
// Ensure the sum of split bitrates doesn't exceed the total bitrate.
|
||||
RTC_DCHECK_LE(sum, total_bitrate);
|
||||
return max_bitrate_kbps * 1000;
|
||||
}
|
||||
|
||||
// Keep the sum of split bitrates equal to the total bitrate by adding bits,
|
||||
// which were lost due to rounding, to the latest layer.
|
||||
bitrates.back() += total_bitrate - sum;
|
||||
uint32_t SvcRateAllocator::GetPaddingBitrateBps(const VideoCodec& codec) {
|
||||
const size_t num_spatial_layers = GetNumActiveSpatialLayers(codec);
|
||||
|
||||
return bitrates;
|
||||
if (codec.mode == VideoCodecMode::kRealtimeVideo) {
|
||||
float scale_factor = 0.0;
|
||||
for (size_t sl_idx = 0; sl_idx < num_spatial_layers; ++sl_idx) {
|
||||
scale_factor += std::pow(kSpatialLayeringRateScalingFactor, sl_idx);
|
||||
}
|
||||
uint32_t min_bitrate_bps =
|
||||
codec.spatialLayers[num_spatial_layers - 1].minBitrate * 1000;
|
||||
return static_cast<uint32_t>(min_bitrate_bps * scale_factor);
|
||||
}
|
||||
|
||||
RTC_DCHECK(codec.mode == VideoCodecMode::kScreensharing);
|
||||
|
||||
uint32_t min_bitrate_kbps = 0;
|
||||
for (size_t sl_idx = 0; sl_idx < num_spatial_layers - 1; ++sl_idx) {
|
||||
min_bitrate_kbps += codec.spatialLayers[sl_idx].maxBitrate;
|
||||
}
|
||||
min_bitrate_kbps += codec.spatialLayers[num_spatial_layers - 1].minBitrate;
|
||||
|
||||
return min_bitrate_kbps * 1000;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -21,9 +21,6 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
extern const float kSpatialLayeringRateScalingFactor;
|
||||
extern const float kTemporalLayeringRateScalingFactor;
|
||||
|
||||
class SvcRateAllocator : public VideoBitrateAllocator {
|
||||
public:
|
||||
explicit SvcRateAllocator(const VideoCodec& codec);
|
||||
@ -31,15 +28,17 @@ class SvcRateAllocator : public VideoBitrateAllocator {
|
||||
VideoBitrateAllocation GetAllocation(uint32_t total_bitrate_bps,
|
||||
uint32_t framerate_fps) override;
|
||||
|
||||
static uint32_t GetMaxBitrateBps(const VideoCodec& codec);
|
||||
static uint32_t GetPaddingBitrateBps(const VideoCodec& codec);
|
||||
|
||||
private:
|
||||
VideoBitrateAllocation GetAllocationNormalVideo(
|
||||
uint32_t total_bitrate_bps) const;
|
||||
uint32_t total_bitrate_bps,
|
||||
size_t num_spatial_layers) const;
|
||||
|
||||
VideoBitrateAllocation GetAllocationScreenSharing(
|
||||
uint32_t total_bitrate_bps) const;
|
||||
std::vector<size_t> SplitBitrate(size_t num_layers,
|
||||
size_t total_bitrate,
|
||||
float rate_scaling_factor) const;
|
||||
bool AdjustAndVerify(std::vector<size_t>* spatial_layer_bitrate_bps) const;
|
||||
uint32_t total_bitrate_bps,
|
||||
size_t num_spatial_layers) const;
|
||||
|
||||
const VideoCodec codec_;
|
||||
};
|
||||
|
||||
@ -164,4 +164,89 @@ TEST(SvcRateAllocatorTest, MinBitrateToGetQualityLayer) {
|
||||
EXPECT_EQ(allocation.GetSpatialLayerSum(1) / 1000, layers[1].minBitrate);
|
||||
}
|
||||
|
||||
TEST(SvcRateAllocatorTest, DeativateLayers) {
|
||||
for (int deactivated_idx = 2; deactivated_idx >= 0; --deactivated_idx) {
|
||||
VideoCodec codec = Configure(1280, 720, 3, 1, false);
|
||||
EXPECT_LE(codec.VP9()->numberOfSpatialLayers, 3U);
|
||||
|
||||
codec.spatialLayers[deactivated_idx].active = false;
|
||||
|
||||
SvcRateAllocator allocator = SvcRateAllocator(codec);
|
||||
|
||||
VideoBitrateAllocation allocation =
|
||||
allocator.GetAllocation(10 * 1000 * 1000, 30);
|
||||
|
||||
// Ensure layers spatial_idx < deactivated_idx are activated.
|
||||
for (int spatial_idx = 0; spatial_idx < deactivated_idx; ++spatial_idx) {
|
||||
EXPECT_GT(allocation.GetSpatialLayerSum(spatial_idx), 0UL);
|
||||
}
|
||||
|
||||
// Ensure layers spatial_idx >= deactivated_idx are deactivated.
|
||||
for (int spatial_idx = deactivated_idx; spatial_idx < 3; ++spatial_idx) {
|
||||
EXPECT_EQ(allocation.GetSpatialLayerSum(spatial_idx), 0UL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SvcRateAllocatorTestParametrizedContentType
|
||||
: public testing::Test,
|
||||
public testing::WithParamInterface<bool> {
|
||||
public:
|
||||
SvcRateAllocatorTestParametrizedContentType()
|
||||
: is_screen_sharing_(GetParam()) {}
|
||||
|
||||
const bool is_screen_sharing_;
|
||||
};
|
||||
|
||||
TEST_P(SvcRateAllocatorTestParametrizedContentType, MaxBitrate) {
|
||||
VideoCodec codec = Configure(1280, 720, 3, 1, is_screen_sharing_);
|
||||
EXPECT_EQ(
|
||||
SvcRateAllocator::GetMaxBitrateBps(codec),
|
||||
(codec.spatialLayers[0].maxBitrate + codec.spatialLayers[1].maxBitrate +
|
||||
codec.spatialLayers[2].maxBitrate) *
|
||||
1000);
|
||||
|
||||
// Deactivate middle layer. This causes deactivation of top layer as well.
|
||||
codec.spatialLayers[1].active = false;
|
||||
EXPECT_EQ(SvcRateAllocator::GetMaxBitrateBps(codec),
|
||||
codec.spatialLayers[0].maxBitrate * 1000);
|
||||
}
|
||||
|
||||
TEST_P(SvcRateAllocatorTestParametrizedContentType, PaddingBitrate) {
|
||||
VideoCodec codec = Configure(1280, 720, 3, 1, is_screen_sharing_);
|
||||
SvcRateAllocator allocator = SvcRateAllocator(codec);
|
||||
|
||||
uint32_t padding_bitrate_bps = SvcRateAllocator::GetPaddingBitrateBps(codec);
|
||||
|
||||
VideoBitrateAllocation allocation =
|
||||
allocator.GetAllocation(padding_bitrate_bps, 30);
|
||||
EXPECT_GT(allocation.GetSpatialLayerSum(0), 0UL);
|
||||
EXPECT_GT(allocation.GetSpatialLayerSum(1), 0UL);
|
||||
EXPECT_GT(allocation.GetSpatialLayerSum(2), 0UL);
|
||||
|
||||
// Allocate 90% of padding bitrate. Top layer should be disabled.
|
||||
allocation = allocator.GetAllocation(9 * padding_bitrate_bps / 10, 30);
|
||||
EXPECT_GT(allocation.GetSpatialLayerSum(0), 0UL);
|
||||
EXPECT_GT(allocation.GetSpatialLayerSum(1), 0UL);
|
||||
EXPECT_EQ(allocation.GetSpatialLayerSum(2), 0UL);
|
||||
|
||||
// Deactivate top layer.
|
||||
codec.spatialLayers[2].active = false;
|
||||
|
||||
padding_bitrate_bps = SvcRateAllocator::GetPaddingBitrateBps(codec);
|
||||
allocation = allocator.GetAllocation(padding_bitrate_bps, 30);
|
||||
EXPECT_GT(allocation.GetSpatialLayerSum(0), 0UL);
|
||||
EXPECT_GT(allocation.GetSpatialLayerSum(1), 0UL);
|
||||
EXPECT_EQ(allocation.GetSpatialLayerSum(2), 0UL);
|
||||
|
||||
allocation = allocator.GetAllocation(9 * padding_bitrate_bps / 10, 30);
|
||||
EXPECT_GT(allocation.GetSpatialLayerSum(0), 0UL);
|
||||
EXPECT_EQ(allocation.GetSpatialLayerSum(1), 0UL);
|
||||
EXPECT_EQ(allocation.GetSpatialLayerSum(2), 0UL);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(_,
|
||||
SvcRateAllocatorTestParametrizedContentType,
|
||||
::testing::Bool());
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -336,12 +336,15 @@ TEST_F(TestVp9Impl, EncoderExplicitLayering) {
|
||||
(codec_settings_.spatialLayers[0].minBitrate +
|
||||
codec_settings_.spatialLayers[0].maxBitrate) /
|
||||
2;
|
||||
codec_settings_.spatialLayers[0].active = true;
|
||||
|
||||
codec_settings_.spatialLayers[1].minBitrate = 400;
|
||||
codec_settings_.spatialLayers[1].maxBitrate = 1500;
|
||||
codec_settings_.spatialLayers[1].targetBitrate =
|
||||
(codec_settings_.spatialLayers[1].minBitrate +
|
||||
codec_settings_.spatialLayers[1].maxBitrate) /
|
||||
2;
|
||||
codec_settings_.spatialLayers[1].active = true;
|
||||
|
||||
codec_settings_.spatialLayers[0].width = codec_settings_.width / 2;
|
||||
codec_settings_.spatialLayers[0].height = codec_settings_.height / 2;
|
||||
@ -1034,6 +1037,7 @@ TEST_F(TestVp9ImplFrameDropping, DifferentFrameratePerSpatialLayer) {
|
||||
codec_settings_.startBitrate;
|
||||
codec_settings_.spatialLayers[sl_idx].targetBitrate =
|
||||
codec_settings_.startBitrate;
|
||||
codec_settings_.spatialLayers[sl_idx].active = true;
|
||||
|
||||
bitrate_allocation.SetBitrate(
|
||||
sl_idx, 0, codec_settings_.spatialLayers[sl_idx].targetBitrate * 1000);
|
||||
@ -1090,6 +1094,7 @@ TEST_F(TestVp9ImplFrameDropping, LayerMaxFramerateIsCappedByCodecMaxFramerate) {
|
||||
codec_settings_.spatialLayers[0].minBitrate = codec_settings_.startBitrate;
|
||||
codec_settings_.spatialLayers[0].maxBitrate = codec_settings_.startBitrate;
|
||||
codec_settings_.spatialLayers[0].targetBitrate = codec_settings_.startBitrate;
|
||||
codec_settings_.spatialLayers[0].active = true;
|
||||
|
||||
bitrate_allocation.SetBitrate(
|
||||
0, 0, codec_settings_.spatialLayers[0].targetBitrate * 1000);
|
||||
|
||||
@ -192,6 +192,14 @@ VideoCodec VideoCodecInitializer::VideoEncoderConfigToVideoCodec(
|
||||
spatial_layers.back().minBitrate = video_codec.minBitrate;
|
||||
spatial_layers.back().maxBitrate = video_codec.maxBitrate;
|
||||
}
|
||||
|
||||
for (size_t spatial_idx = 0;
|
||||
spatial_idx < config.simulcast_layers.size() &&
|
||||
spatial_idx < spatial_layers.size();
|
||||
++spatial_idx) {
|
||||
spatial_layers[spatial_layers.size() - spatial_idx - 1].active =
|
||||
config.simulcast_layers[spatial_idx].active;
|
||||
}
|
||||
}
|
||||
|
||||
RTC_DCHECK(!spatial_layers.empty());
|
||||
|
||||
@ -313,4 +313,36 @@ TEST_F(VideoCodecInitializerTest,
|
||||
kDefaultMaxBitrateBps / 1000);
|
||||
}
|
||||
|
||||
TEST_F(VideoCodecInitializerTest, Vp9DeactivateLayers) {
|
||||
SetUpFor(VideoCodecType::kVideoCodecVP9, 3, 1, false);
|
||||
VideoStream stream = DefaultStream();
|
||||
streams_.push_back(stream);
|
||||
|
||||
config_.simulcast_layers.resize(3);
|
||||
|
||||
// Activate all layers.
|
||||
config_.simulcast_layers[0].active = true;
|
||||
config_.simulcast_layers[1].active = true;
|
||||
config_.simulcast_layers[2].active = true;
|
||||
EXPECT_TRUE(InitializeCodec());
|
||||
EXPECT_TRUE(codec_out_.spatialLayers[0].active);
|
||||
EXPECT_TRUE(codec_out_.spatialLayers[1].active);
|
||||
EXPECT_TRUE(codec_out_.spatialLayers[2].active);
|
||||
|
||||
// Deactivate top layer.
|
||||
config_.simulcast_layers[0].active = false;
|
||||
EXPECT_TRUE(InitializeCodec());
|
||||
EXPECT_TRUE(codec_out_.spatialLayers[0].active);
|
||||
EXPECT_TRUE(codec_out_.spatialLayers[1].active);
|
||||
EXPECT_FALSE(codec_out_.spatialLayers[2].active);
|
||||
|
||||
// Deactivate middle layer.
|
||||
config_.simulcast_layers[0].active = true;
|
||||
config_.simulcast_layers[1].active = false;
|
||||
EXPECT_TRUE(InitializeCodec());
|
||||
EXPECT_TRUE(codec_out_.spatialLayers[0].active);
|
||||
EXPECT_FALSE(codec_out_.spatialLayers[1].active);
|
||||
EXPECT_TRUE(codec_out_.spatialLayers[2].active);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -190,6 +190,7 @@ rtc_source_set("video_stream_encoder_impl") {
|
||||
"../common_video:common_video",
|
||||
"../modules/video_coding",
|
||||
"../modules/video_coding:video_coding_utility",
|
||||
"../modules/video_coding:webrtc_vp9_helpers",
|
||||
"../rtc_base:checks",
|
||||
"../rtc_base:criticalsection",
|
||||
"../rtc_base:logging",
|
||||
|
||||
@ -555,7 +555,8 @@ void VideoSendStreamImpl::OnEncoderConfigurationChanged(
|
||||
const VideoCodecType codec_type =
|
||||
PayloadStringToCodecType(config_->rtp.payload_name);
|
||||
if (codec_type == kVideoCodecVP9) {
|
||||
max_padding_bitrate_ = streams[0].target_bitrate_bps;
|
||||
max_padding_bitrate_ = has_alr_probing_ ? streams[0].min_bitrate_bps
|
||||
: streams[0].target_bitrate_bps;
|
||||
} else {
|
||||
max_padding_bitrate_ = CalculateMaxPadBitrateBps(
|
||||
streams, min_transmit_bitrate_bps, config_->suspend_below_min_bitrate,
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
#include "api/video/encoded_image.h"
|
||||
#include "api/video/i420_buffer.h"
|
||||
#include "api/video/video_bitrate_allocator_factory.h"
|
||||
#include "modules/video_coding/codecs/vp9/svc_rate_allocator.h"
|
||||
#include "modules/video_coding/include/video_codec_initializer.h"
|
||||
#include "modules/video_coding/include/video_coding.h"
|
||||
#include "rtc_base/arraysize.h"
|
||||
@ -550,24 +551,13 @@ void VideoStreamEncoder::ReconfigureEncoder() {
|
||||
|
||||
// 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].max_bitrate_bps = std::min<int>(
|
||||
streams[0].max_bitrate_bps, SvcRateAllocator::GetMaxBitrateBps(codec));
|
||||
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.
|
||||
// target_bitrate_bps specifies the maximum padding bitrate.
|
||||
streams[0].target_bitrate_bps =
|
||||
std::min(static_cast<unsigned int>(streams[0].max_bitrate_bps),
|
||||
codec.spatialLayers[codec.VP9()->numberOfSpatialLayers - 1]
|
||||
.targetBitrate *
|
||||
1000);
|
||||
SvcRateAllocator::GetPaddingBitrateBps(codec);
|
||||
}
|
||||
|
||||
codec.startBitrate =
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user