From 7d687b13ed0a724eaa710a8ca31967300fc1277d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Spr=C3=A5ng?= Date: Wed, 12 Sep 2018 17:04:10 +0200 Subject: [PATCH] SimulcastEncoderAdapter, don't start streams without enough bitrate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Rasmus Brandt Cr-Commit-Position: refs/heads/master@{#24711} --- media/engine/simulcast_encoder_adapter.cc | 5 +- .../simulcast_encoder_adapter_unittest.cc | 46 +++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/media/engine/simulcast_encoder_adapter.cc b/media/engine/simulcast_encoder_adapter.cc index 5827fc5d6e..30da68ec85 100644 --- a/media/engine/simulcast_encoder_adapter.cc +++ b/media/engine/simulcast_encoder_adapter.cc @@ -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 += ", "; diff --git a/media/engine/simulcast_encoder_adapter_unittest.cc b/media/engine/simulcast_encoder_adapter_unittest.cc index 8ab7383496..5b7d185b8c 100644 --- a/media/engine/simulcast_encoder_adapter_unittest.cc +++ b/media/engine/simulcast_encoder_adapter_unittest.cc @@ -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 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 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 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(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 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 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 frame_types; + frame_types.resize(3, kVideoFrameKey); + EXPECT_EQ(0, adapter_->Encode(input_frame, nullptr, &frame_types)); +} } // namespace test } // namespace webrtc