SimulcastEncoderAdapter, don't start streams without enough bitrate
Currently a bug in InitEncode() sets all stream initially to active.
This CL actually bases the active-flag on available start bitrate.
Bug: webrtc:9747
Change-Id: If197b0c69376d96c717f2a391fba8108895018f3
Reviewed-on: https://webrtc-review.googlesource.com/99960
Commit-Queue: Erik Språng <sprang@webrtc.org>
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24711}
diff --git a/media/engine/simulcast_encoder_adapter.cc b/media/engine/simulcast_encoder_adapter.cc
index 5827fc5..30da68e 100644
--- a/media/engine/simulcast_encoder_adapter.cc
+++ b/media/engine/simulcast_encoder_adapter.cc
@@ -208,12 +208,13 @@
for (int i = 0; i < number_of_streams; ++i) {
VideoCodec stream_codec;
uint32_t start_bitrate_kbps = start_bitrates[i];
+ const bool send_stream = start_bitrate_kbps > 0;
if (!doing_simulcast) {
stream_codec = codec_;
stream_codec.numberOfSimulcastStreams = 1;
} else {
// Cap start bitrate to the min bitrate in order to avoid strange codec
- // behavior. Since sending sending will be false, this should not matter.
+ // behavior. Since sending will be false, this should not matter.
start_bitrate_kbps =
std::max(codec_.simulcastStream[i].minBitrate, start_bitrate_kbps);
bool highest_resolution_stream = (i == (number_of_streams - 1));
@@ -251,7 +252,7 @@
encoder->RegisterEncodeCompleteCallback(callback.get());
streaminfos_.emplace_back(std::move(encoder), std::move(callback),
stream_codec.width, stream_codec.height,
- start_bitrate_kbps > 0);
+ send_stream);
if (i != 0) {
implementation_name += ", ";
diff --git a/media/engine/simulcast_encoder_adapter_unittest.cc b/media/engine/simulcast_encoder_adapter_unittest.cc
index 8ab73834..5b7d185 100644
--- a/media/engine/simulcast_encoder_adapter_unittest.cc
+++ b/media/engine/simulcast_encoder_adapter_unittest.cc
@@ -513,6 +513,10 @@
kVideoCodecVP8);
rate_allocator_.reset(new SimulcastRateAllocator(codec_));
adapter_->RegisterEncodeCompleteCallback(this);
+ const uint32_t target_bitrate =
+ 1000 * (codec_.simulcastStream[0].targetBitrate +
+ codec_.simulcastStream[1].targetBitrate +
+ codec_.simulcastStream[2].minBitrate);
// Input data.
rtc::scoped_refptr<VideoFrameBuffer> buffer(I420Buffer::Create(1280, 720));
@@ -522,6 +526,9 @@
// Encode with three streams.
EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
VerifyCodecSettings();
+ adapter_->SetRateAllocation(
+ rate_allocator_->GetAllocation(target_bitrate, 30), 30);
+
std::vector<MockVideoEncoder*> original_encoders =
helper_->factory()->encoders();
ASSERT_EQ(3u, original_encoders.size());
@@ -546,6 +553,8 @@
codec_.height /= 2;
codec_.numberOfSimulcastStreams = 2;
EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
+ adapter_->SetRateAllocation(
+ rate_allocator_->GetAllocation(target_bitrate, 30), 30);
std::vector<MockVideoEncoder*> new_encoders = helper_->factory()->encoders();
ASSERT_EQ(2u, new_encoders.size());
ASSERT_EQ(original_encoders[0], new_encoders[0]);
@@ -567,6 +576,8 @@
codec_.height /= 2;
codec_.numberOfSimulcastStreams = 1;
EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
+ adapter_->SetRateAllocation(
+ rate_allocator_->GetAllocation(target_bitrate, 30), 30);
new_encoders = helper_->factory()->encoders();
ASSERT_EQ(1u, new_encoders.size());
ASSERT_EQ(original_encoders[0], new_encoders[0]);
@@ -583,6 +594,8 @@
codec_.height *= 4;
codec_.numberOfSimulcastStreams = 3;
EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
+ adapter_->SetRateAllocation(
+ rate_allocator_->GetAllocation(target_bitrate, 30), 30);
new_encoders = helper_->factory()->encoders();
ASSERT_EQ(3u, new_encoders.size());
// The first encoder is reused.
@@ -902,5 +915,38 @@
ref_codec.qpMax = kLowMaxQp;
VerifyCodec(ref_codec, 0);
}
+
+TEST_F(TestSimulcastEncoderAdapterFake, ActivatesCorrectStreamsInInitEncode) {
+ // Set up common settings for three streams.
+ SimulcastTestFixtureImpl::DefaultSettings(
+ &codec_, static_cast<const int*>(kTestTemporalLayerProfile),
+ kVideoCodecVP8);
+ rate_allocator_.reset(new SimulcastRateAllocator(codec_));
+ adapter_->RegisterEncodeCompleteCallback(this);
+
+ // Only enough start bitrate for the lowest stream.
+ ASSERT_EQ(3u, codec_.numberOfSimulcastStreams);
+ codec_.startBitrate = codec_.simulcastStream[0].targetBitrate +
+ codec_.simulcastStream[1].minBitrate - 1;
+
+ // Input data.
+ rtc::scoped_refptr<VideoFrameBuffer> buffer(I420Buffer::Create(1280, 720));
+ VideoFrame input_frame(buffer, 100, 1000, kVideoRotation_180);
+
+ // Encode with three streams.
+ EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
+ std::vector<MockVideoEncoder*> original_encoders =
+ helper_->factory()->encoders();
+ ASSERT_EQ(3u, original_encoders.size());
+ // Only first encoder will be active and called.
+ EXPECT_CALL(*original_encoders[0], Encode(_, _, _))
+ .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
+ EXPECT_CALL(*original_encoders[1], Encode(_, _, _)).Times(0);
+ EXPECT_CALL(*original_encoders[2], Encode(_, _, _)).Times(0);
+
+ std::vector<FrameType> frame_types;
+ frame_types.resize(3, kVideoFrameKey);
+ EXPECT_EQ(0, adapter_->Encode(input_frame, nullptr, &frame_types));
+}
} // namespace test
} // namespace webrtc