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}
This commit is contained in:
Erik Språng 2018-09-12 17:04:10 +02:00 committed by Commit Bot
parent 21c663820f
commit 7d687b13ed
2 changed files with 49 additions and 2 deletions

View File

@ -208,12 +208,13 @@ int SimulcastEncoderAdapter::InitEncode(const VideoCodec* inst,
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 @@ int SimulcastEncoderAdapter::InitEncode(const VideoCodec* inst,
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 += ", ";

View File

@ -513,6 +513,10 @@ TEST_F(TestSimulcastEncoderAdapterFake, ReusesEncodersInOrder) {
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 @@ TEST_F(TestSimulcastEncoderAdapterFake, ReusesEncodersInOrder) {
// 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 @@ TEST_F(TestSimulcastEncoderAdapterFake, ReusesEncodersInOrder) {
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 @@ TEST_F(TestSimulcastEncoderAdapterFake, ReusesEncodersInOrder) {
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 @@ TEST_F(TestSimulcastEncoderAdapterFake, ReusesEncodersInOrder) {
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 @@ TEST_F(TestSimulcastEncoderAdapterFake, DoesNotAlterMaxQpForScreenshare) {
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