Calculate video padding for vp9 in the same way as for vp8
Bug: webrtc:11476
Change-Id: I8d7b5aac91868e10061605cc5043226ee916cc09
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/172722
Reviewed-by: Evan Shrubsole <eshr@google.com>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30982}
diff --git a/api/video/video_stream_encoder_interface.h b/api/video/video_stream_encoder_interface.h
index 253fb04..8e1df0f 100644
--- a/api/video/video_stream_encoder_interface.h
+++ b/api/video/video_stream_encoder_interface.h
@@ -44,6 +44,7 @@
public:
virtual void OnEncoderConfigurationChanged(
std::vector<VideoStream> streams,
+ bool is_svc,
VideoEncoderConfig::ContentType content_type,
int min_transmit_bitrate_bps) = 0;
};
diff --git a/video/video_send_stream_impl.cc b/video/video_send_stream_impl.cc
index 405de7c..bfd6216 100644
--- a/video/video_send_stream_impl.cc
+++ b/video/video_send_stream_impl.cc
@@ -58,12 +58,16 @@
// Calculate max padding bitrate for a multi layer codec.
int CalculateMaxPadBitrateBps(const std::vector<VideoStream>& streams,
+ bool is_svc,
VideoEncoderConfig::ContentType content_type,
int min_transmit_bitrate_bps,
bool pad_to_min_bitrate,
bool alr_probing) {
int pad_up_to_bitrate_bps = 0;
+ RTC_DCHECK(!is_svc || streams.size() <= 1) << "Only one stream is allowed in "
+ "SVC mode.";
+
// Filter out only the active streams;
std::vector<VideoStream> active_streams;
for (const VideoStream& stream : streams) {
@@ -71,7 +75,13 @@
active_streams.emplace_back(stream);
}
- if (active_streams.size() > 1) {
+ if (active_streams.size() > 1 || (!active_streams.empty() && is_svc)) {
+ // Simulcast or SVC is used.
+ // if SVC is used, stream bitrates should already encode svc bitrates:
+ // min_bitrate = min bitrate of a lowest svc layer.
+ // target_bitrate = sum of target bitrates of lower layers + min bitrate
+ // of the last one (as used in the calculations below).
+ // max_bitrate = sum of all active layers' max_bitrate.
if (alr_probing) {
// With alr probing, just pad to the min bitrate of the lowest stream,
// probing will handle the rest of the rampup.
@@ -471,22 +481,23 @@
void VideoSendStreamImpl::OnEncoderConfigurationChanged(
std::vector<VideoStream> streams,
+ bool is_svc,
VideoEncoderConfig::ContentType content_type,
int min_transmit_bitrate_bps) {
if (!worker_queue_->IsCurrent()) {
rtc::WeakPtr<VideoSendStreamImpl> send_stream = weak_ptr_;
- worker_queue_->PostTask([send_stream, streams, content_type,
+ worker_queue_->PostTask([send_stream, streams, is_svc, content_type,
min_transmit_bitrate_bps]() mutable {
if (send_stream) {
send_stream->OnEncoderConfigurationChanged(
- std::move(streams), content_type, min_transmit_bitrate_bps);
+ std::move(streams), is_svc, content_type, min_transmit_bitrate_bps);
}
});
return;
}
+
RTC_DCHECK_GE(config_->rtp.ssrcs.size(), streams.size());
TRACE_EVENT0("webrtc", "VideoSendStream::OnEncoderConfigurationChanged");
- RTC_DCHECK_GE(config_->rtp.ssrcs.size(), streams.size());
RTC_DCHECK_RUN_ON(worker_queue_);
const VideoCodecType codec_type =
@@ -516,14 +527,9 @@
encoder_max_bitrate_bps_);
// TODO(bugs.webrtc.org/10266): Query the VideoBitrateAllocator instead.
- if (codec_type == kVideoCodecVP9) {
- max_padding_bitrate_ = has_alr_probing_ ? streams[0].min_bitrate_bps
- : streams[0].target_bitrate_bps;
- } else {
- max_padding_bitrate_ = CalculateMaxPadBitrateBps(
- streams, content_type, min_transmit_bitrate_bps,
- config_->suspend_below_min_bitrate, has_alr_probing_);
- }
+ max_padding_bitrate_ = CalculateMaxPadBitrateBps(
+ streams, is_svc, content_type, min_transmit_bitrate_bps,
+ config_->suspend_below_min_bitrate, has_alr_probing_);
// Clear stats for disabled layers.
for (size_t i = streams.size(); i < config_->rtp.ssrcs.size(); ++i) {
diff --git a/video/video_send_stream_impl.h b/video/video_send_stream_impl.h
index 4195efc..d3f87e3 100644
--- a/video/video_send_stream_impl.h
+++ b/video/video_send_stream_impl.h
@@ -116,6 +116,7 @@
void OnEncoderConfigurationChanged(
std::vector<VideoStream> streams,
+ bool is_svc,
VideoEncoderConfig::ContentType content_type,
int min_transmit_bitrate_bps) override;
diff --git a/video/video_send_stream_impl_unittest.cc b/video/video_send_stream_impl_unittest.cc
index 2b5a90a..24519b1 100644
--- a/video/video_send_stream_impl_unittest.cc
+++ b/video/video_send_stream_impl_unittest.cc
@@ -241,7 +241,7 @@
static_cast<VideoStreamEncoderInterface::EncoderSink*>(vss_impl.get())
->OnEncoderConfigurationChanged(
- std::vector<VideoStream>{qvga_stream, vga_stream},
+ std::vector<VideoStream>{qvga_stream, vga_stream}, false,
VideoEncoderConfig::ContentType::kRealtimeVideo,
min_transmit_bitrate_bps);
vss_impl->Stop();
@@ -309,7 +309,7 @@
static_cast<VideoStreamEncoderInterface::EncoderSink*>(vss_impl.get())
->OnEncoderConfigurationChanged(
- std::vector<VideoStream>{low_stream, high_stream},
+ std::vector<VideoStream>{low_stream, high_stream}, false,
VideoEncoderConfig::ContentType::kScreen,
min_transmit_bitrate_bps);
vss_impl->Stop();
@@ -371,7 +371,7 @@
static_cast<VideoStreamEncoderInterface::EncoderSink*>(vss_impl.get())
->OnEncoderConfigurationChanged(
- std::vector<VideoStream>{low_stream, high_stream},
+ std::vector<VideoStream>{low_stream, high_stream}, false,
VideoEncoderConfig::ContentType::kRealtimeVideo,
/*min_transmit_bitrate_bps=*/0);
vss_impl->Stop();
@@ -690,7 +690,7 @@
static_cast<VideoStreamEncoderInterface::EncoderSink*>(vss_impl.get())
->OnEncoderConfigurationChanged(
- std::vector<VideoStream>{qvga_stream},
+ std::vector<VideoStream>{qvga_stream}, false,
VideoEncoderConfig::ContentType::kRealtimeVideo,
min_transmit_bitrate_bps);
@@ -816,7 +816,7 @@
// Reconfigure e.g. due to a fake frame.
static_cast<VideoStreamEncoderInterface::EncoderSink*>(vss_impl.get())
->OnEncoderConfigurationChanged(
- std::vector<VideoStream>{qvga_stream},
+ std::vector<VideoStream>{qvga_stream}, false,
VideoEncoderConfig::ContentType::kRealtimeVideo,
min_transmit_bitrate_bps);
// Still no padding because no actual frames were passed, only
@@ -893,5 +893,112 @@
ASSERT_TRUE(done.Wait(5000));
}
+TEST_F(VideoSendStreamImplTest, ConfiguresBitratesForSvcWithAlr) {
+ test_queue_.SendTask(
+ [this] {
+ const bool kSuspend = false;
+ config_.suspend_below_min_bitrate = kSuspend;
+ config_.rtp.extensions.emplace_back(
+ RtpExtension::kTransportSequenceNumberUri, 1);
+ config_.periodic_alr_bandwidth_probing = true;
+ auto vss_impl = CreateVideoSendStreamImpl(
+ kDefaultInitialBitrateBps, kDefaultBitratePriority,
+ VideoEncoderConfig::ContentType::kScreen);
+ vss_impl->Start();
+
+ // Svc
+ VideoStream stream;
+ stream.width = 1920;
+ stream.height = 1080;
+ stream.max_framerate = 30;
+ stream.min_bitrate_bps = 60000;
+ stream.target_bitrate_bps = 6000000;
+ stream.max_bitrate_bps = 1250000;
+ stream.num_temporal_layers = 2;
+ stream.max_qp = 56;
+ stream.bitrate_priority = 1;
+
+ int min_transmit_bitrate_bps = 400000;
+
+ config_.rtp.ssrcs.emplace_back(1);
+ config_.rtp.ssrcs.emplace_back(2);
+
+ EXPECT_CALL(bitrate_allocator_, AddObserver(vss_impl.get(), _))
+ .WillRepeatedly(Invoke([&](BitrateAllocatorObserver*,
+ MediaStreamAllocationConfig config) {
+ EXPECT_EQ(config.min_bitrate_bps,
+ static_cast<uint32_t>(stream.min_bitrate_bps));
+ EXPECT_EQ(config.max_bitrate_bps,
+ static_cast<uint32_t>(stream.max_bitrate_bps));
+ if (config.pad_up_bitrate_bps != 0) {
+ EXPECT_EQ(config.pad_up_bitrate_bps,
+ static_cast<uint32_t>(min_transmit_bitrate_bps));
+ }
+ EXPECT_EQ(config.enforce_min_bitrate, !kSuspend);
+ }));
+
+ static_cast<VideoStreamEncoderInterface::EncoderSink*>(vss_impl.get())
+ ->OnEncoderConfigurationChanged(
+ std::vector<VideoStream>{stream}, true,
+ VideoEncoderConfig::ContentType::kScreen,
+ min_transmit_bitrate_bps);
+ vss_impl->Stop();
+ },
+ RTC_FROM_HERE);
+}
+
+TEST_F(VideoSendStreamImplTest, ConfiguresBitratesForSvcNoAlr) {
+ test_queue_.SendTask(
+ [this] {
+ const bool kSuspend = false;
+ config_.suspend_below_min_bitrate = kSuspend;
+ config_.rtp.extensions.emplace_back(
+ RtpExtension::kTransportSequenceNumberUri, 1);
+ config_.periodic_alr_bandwidth_probing = false;
+ auto vss_impl = CreateVideoSendStreamImpl(
+ kDefaultInitialBitrateBps, kDefaultBitratePriority,
+ VideoEncoderConfig::ContentType::kScreen);
+ vss_impl->Start();
+
+ // Svc
+ VideoStream stream;
+ stream.width = 1920;
+ stream.height = 1080;
+ stream.max_framerate = 30;
+ stream.min_bitrate_bps = 60000;
+ stream.target_bitrate_bps = 6000000;
+ stream.max_bitrate_bps = 1250000;
+ stream.num_temporal_layers = 2;
+ stream.max_qp = 56;
+ stream.bitrate_priority = 1;
+
+ int min_transmit_bitrate_bps = 400000;
+
+ config_.rtp.ssrcs.emplace_back(1);
+ config_.rtp.ssrcs.emplace_back(2);
+
+ EXPECT_CALL(bitrate_allocator_, AddObserver(vss_impl.get(), _))
+ .WillRepeatedly(Invoke([&](BitrateAllocatorObserver*,
+ MediaStreamAllocationConfig config) {
+ EXPECT_EQ(config.min_bitrate_bps,
+ static_cast<uint32_t>(stream.min_bitrate_bps));
+ EXPECT_EQ(config.max_bitrate_bps,
+ static_cast<uint32_t>(stream.max_bitrate_bps));
+ if (config.pad_up_bitrate_bps != 0) {
+ EXPECT_EQ(config.pad_up_bitrate_bps,
+ static_cast<uint32_t>(stream.target_bitrate_bps));
+ }
+ EXPECT_EQ(config.enforce_min_bitrate, !kSuspend);
+ }));
+
+ static_cast<VideoStreamEncoderInterface::EncoderSink*>(vss_impl.get())
+ ->OnEncoderConfigurationChanged(
+ std::vector<VideoStream>{stream}, true,
+ VideoEncoderConfig::ContentType::kScreen,
+ min_transmit_bitrate_bps);
+ vss_impl->Stop();
+ },
+ RTC_FROM_HERE);
+}
} // namespace internal
} // namespace webrtc
diff --git a/video/video_stream_encoder.cc b/video/video_stream_encoder.cc
index 8252cb2..4ad9a52 100644
--- a/video/video_stream_encoder.cc
+++ b/video/video_stream_encoder.cc
@@ -516,18 +516,6 @@
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) {
- // Lower max bitrate to the level codec actually can produce.
- streams[0].max_bitrate_bps =
- std::min(streams[0].max_bitrate_bps,
- SvcRateAllocator::GetMaxBitrate(codec).bps<int>());
- streams[0].min_bitrate_bps = codec.spatialLayers[0].minBitrate * 1000;
- // target_bitrate_bps specifies the maximum padding bitrate.
- streams[0].target_bitrate_bps =
- SvcRateAllocator::GetPaddingBitrate(codec).bps<int>();
- }
-
char log_stream_buf[4 * 1024];
rtc::SimpleStringBuilder log_stream(log_stream_buf);
log_stream << "ReconfigureEncoder:\n";
@@ -717,8 +705,26 @@
pending_encoder_reconfiguration_ = false;
+ bool is_svc = false;
+ // Set min_bitrate_bps, max_bitrate_bps, and max padding bit rate for VP9
+ // and leave only one stream containing all necessary information.
+ if (encoder_config_.codec_type == kVideoCodecVP9) {
+ // Lower max bitrate to the level codec actually can produce.
+ streams[0].max_bitrate_bps =
+ std::min(streams[0].max_bitrate_bps,
+ SvcRateAllocator::GetMaxBitrate(codec).bps<int>());
+ streams[0].min_bitrate_bps = codec.spatialLayers[0].minBitrate * 1000;
+ // target_bitrate_bps specifies the maximum padding bitrate.
+ streams[0].target_bitrate_bps =
+ SvcRateAllocator::GetPaddingBitrate(codec).bps<int>();
+ streams[0].width = streams.back().width;
+ streams[0].height = streams.back().height;
+ is_svc = codec.VP9()->numberOfSpatialLayers > 1;
+ streams.resize(1);
+ }
+
sink_->OnEncoderConfigurationChanged(
- std::move(streams), encoder_config_.content_type,
+ std::move(streams), is_svc, encoder_config_.content_type,
encoder_config_.min_transmit_bitrate_bps);
resource_adaptation_processor_->ConfigureQualityScaler(info);
diff --git a/video/video_stream_encoder_unittest.cc b/video/video_stream_encoder_unittest.cc
index 934bf09..bb85776 100644
--- a/video/video_stream_encoder_unittest.cc
+++ b/video/video_stream_encoder_unittest.cc
@@ -1141,6 +1141,7 @@
void OnEncoderConfigurationChanged(
std::vector<VideoStream> streams,
+ bool is_svc,
VideoEncoderConfig::ContentType content_type,
int min_transmit_bitrate_bps) override {
rtc::CritScope lock(&crit_);