diff --git a/media/engine/simulcast.cc b/media/engine/simulcast.cc index 215ad9889a..c42e1dcae2 100644 --- a/media/engine/simulcast.cc +++ b/media/engine/simulcast.cc @@ -25,6 +25,9 @@ namespace cricket { namespace { +constexpr char kUseBaseHeavyVP8TL3RateAllocationFieldTrial[] = + "WebRTC-UseBaseHeavyVP8TL3RateAllocation"; + // Limits for legacy conference screensharing mode. Currently used for the // lower of the two simulcast streams. constexpr int kScreenshareDefaultTl0BitrateKbps = 200; @@ -257,15 +260,16 @@ std::vector GetNormalSimulcastLayers( layers[s].target_bitrate_bps = FindSimulcastTargetBitrateBps(width, height); int num_temporal_layers = DefaultNumberOfTemporalLayers(s, false); if (s == 0) { - // If alternative number temporal layers is selected, adjust the + // If alternative temporal rate allocation is selected, adjust the // bitrate of the lowest simulcast stream so that absolute bitrate for // the base temporal layer matches the bitrate for the base temporal // layer with the default 3 simulcast streams. Otherwise we risk a // higher threshold for receiving a feed at all. float rate_factor = 1.0; if (num_temporal_layers == 3) { - if (webrtc::field_trial::IsEnabled("WebRTC-UseShortVP8TL3Pattern")) { - // Shortened pattern increases TL0 bitrate from 40% to 60%. + if (webrtc::field_trial::IsEnabled( + kUseBaseHeavyVP8TL3RateAllocationFieldTrial)) { + // Base heavy allocation increases TL0 bitrate from 40% to 60%. rate_factor = 0.4 / 0.6; } } else { @@ -341,7 +345,8 @@ std::vector GetScreenshareLayers( webrtc::SimulcastRateAllocator::GetTemporalRateAllocation( num_temporal_layers, 0)); } else if (DefaultNumberOfTemporalLayers(1, true) != 3 || - webrtc::field_trial::IsEnabled("WebRTC-UseShortVP8TL3Pattern")) { + webrtc::field_trial::IsEnabled( + kUseBaseHeavyVP8TL3RateAllocationFieldTrial)) { // Experimental temporal layer mode used, use increased max bitrate. max_bitrate_bps = kScreenshareHighStreamMaxBitrateBps; using_boosted_bitrate = true; diff --git a/media/engine/simulcast_unittest.cc b/media/engine/simulcast_unittest.cc index f8d6e4db93..f416368697 100644 --- a/media/engine/simulcast_unittest.cc +++ b/media/engine/simulcast_unittest.cc @@ -108,6 +108,29 @@ TEST(SimulcastTest, GetConfig) { EXPECT_FALSE(streams[2].bitrate_priority); } +TEST(SimulcastTest, GetConfigWithBaseHeavyVP8TL3RateAllocation) { + test::ScopedFieldTrials field_trials( + "WebRTC-UseBaseHeavyVP8TL3RateAllocation/Enabled/"); + + const std::vector kExpected = GetSimulcastBitrates720p(); + + const size_t kMaxLayers = 3; + std::vector streams = cricket::GetSimulcastConfig( + kMaxLayers, 1280, 720, kMaxBitrateBps, kBitratePriority, kQpMax, kMaxFps, + !kScreenshare); + + EXPECT_EQ(kExpected[0].min_bitrate_bps, streams[0].min_bitrate_bps); + EXPECT_EQ(static_cast(0.4 * kExpected[0].target_bitrate_bps / 0.6), + streams[0].target_bitrate_bps); + EXPECT_EQ(static_cast(0.4 * kExpected[0].max_bitrate_bps / 0.6), + streams[0].max_bitrate_bps); + for (size_t i = 1; i < streams.size(); ++i) { + EXPECT_EQ(kExpected[i].min_bitrate_bps, streams[i].min_bitrate_bps); + EXPECT_EQ(kExpected[i].target_bitrate_bps, streams[i].target_bitrate_bps); + EXPECT_EQ(kExpected[i].max_bitrate_bps, streams[i].max_bitrate_bps); + } +} + TEST(SimulcastTest, GetConfigWithLimitedMaxLayers) { const size_t kMaxLayers = 2; std::vector streams = cricket::GetSimulcastConfig( @@ -221,7 +244,7 @@ TEST(SimulcastTest, SimulcastScreenshareMaxBitrateAdjustedForResolution) { constexpr int kScreenshareHighStreamMinBitrateBps = 600000; constexpr int kScreenshareHighStreamMaxBitrateBps = 1250000; - constexpr int kMaxBirate960_540 = 900000; + constexpr int kMaxBitrate960_540 = 900000; // Normal case, max bitrate not limited by resolution. const size_t kMaxLayers = 2; @@ -238,7 +261,7 @@ TEST(SimulcastTest, SimulcastScreenshareMaxBitrateAdjustedForResolution) { kBitratePriority, kQpMax, kMaxFps, kScreenshare); EXPECT_EQ(kMaxLayers, streams.size()); - EXPECT_EQ(streams[1].max_bitrate_bps, kMaxBirate960_540); + EXPECT_EQ(streams[1].max_bitrate_bps, kMaxBitrate960_540); EXPECT_EQ(streams[1].min_bitrate_bps, kScreenshareHighStreamMinBitrateBps); EXPECT_GE(streams[1].max_bitrate_bps, streams[1].min_bitrate_bps); diff --git a/modules/video_coding/utility/simulcast_rate_allocator.cc b/modules/video_coding/utility/simulcast_rate_allocator.cc index 2666a16593..41b490f444 100644 --- a/modules/video_coding/utility/simulcast_rate_allocator.cc +++ b/modules/video_coding/utility/simulcast_rate_allocator.cc @@ -32,7 +32,7 @@ static const float {0.25f, 0.4f, 0.6f, 1.0f} // 4 layers {25%, 15%, 20%, 40%} }; -static const float kShort3TlRateAllocation[kMaxTemporalStreams] = { +static const float kBaseHeavy3TlRateAllocation[kMaxTemporalStreams] = { 0.6f, 0.8f, 1.0f, 1.0f // 3 layers {60%, 20%, 20%} }; @@ -74,8 +74,8 @@ float SimulcastRateAllocator::GetTemporalRateAllocation(int num_layers, RTC_CHECK_GE(temporal_id, 0); RTC_CHECK_LT(temporal_id, num_layers); if (num_layers == 3 && - field_trial::IsEnabled("WebRTC-UseShortVP8TL3Pattern")) { - return kShort3TlRateAllocation[temporal_id]; + field_trial::IsEnabled("WebRTC-UseBaseHeavyVP8TL3RateAllocation")) { + return kBaseHeavy3TlRateAllocation[temporal_id]; } return kLayerRateAllocation[num_layers - 1][temporal_id]; } diff --git a/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc b/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc index 332c4b83b8..05d881e407 100644 --- a/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc +++ b/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc @@ -17,6 +17,7 @@ #include "modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h" +#include "test/field_trial.h" #include "test/gmock.h" #include "test/gtest.h" @@ -91,32 +92,45 @@ class SimulcastRateAllocatorTest : public ::testing::TestWithParam { allocator_.reset(new SimulcastRateAllocator(codec_)); } - void SetupCodecThreeSimulcastStreams( - const std::vector& active_streams) { - size_t num_streams = 3; - RTC_DCHECK_GE(active_streams.size(), num_streams); - SetupCodecTwoSimulcastStreams(active_streams); - codec_.numberOfSimulcastStreams = num_streams; - codec_.simulcastStream[2].minBitrate = 2000; - codec_.simulcastStream[2].targetBitrate = 3000; + void SetupCodec3SL3TL(const std::vector& active_streams) { + const size_t num_simulcast_layers = 3; + RTC_DCHECK_GE(active_streams.size(), num_simulcast_layers); + SetupCodec2SL3TL(active_streams); + codec_.numberOfSimulcastStreams = num_simulcast_layers; + codec_.simulcastStream[2].numberOfTemporalLayers = 3; codec_.simulcastStream[2].maxBitrate = 4000; + codec_.simulcastStream[2].targetBitrate = 3000; + codec_.simulcastStream[2].minBitrate = 2000; codec_.simulcastStream[2].active = active_streams[2]; } - void SetupCodecTwoSimulcastStreams(const std::vector& active_streams) { - size_t num_streams = 2; - RTC_DCHECK_GE(active_streams.size(), num_streams); - codec_.numberOfSimulcastStreams = num_streams; - codec_.maxBitrate = 0; - codec_.simulcastStream[0].minBitrate = 10; - codec_.simulcastStream[0].targetBitrate = 100; - codec_.simulcastStream[0].maxBitrate = 500; - codec_.simulcastStream[1].minBitrate = 50; - codec_.simulcastStream[1].targetBitrate = 500; + void SetupCodec2SL3TL(const std::vector& active_streams) { + const size_t num_simulcast_layers = 2; + RTC_DCHECK_GE(active_streams.size(), num_simulcast_layers); + SetupCodec1SL3TL(active_streams); + codec_.numberOfSimulcastStreams = num_simulcast_layers; + codec_.simulcastStream[1].numberOfTemporalLayers = 3; codec_.simulcastStream[1].maxBitrate = 1000; - for (size_t i = 0; i < num_streams; ++i) { - codec_.simulcastStream[i].active = active_streams[i]; - } + codec_.simulcastStream[1].targetBitrate = 500; + codec_.simulcastStream[1].minBitrate = 50; + codec_.simulcastStream[1].active = active_streams[1]; + } + + void SetupCodec1SL3TL(const std::vector& active_streams) { + const size_t num_simulcast_layers = 2; + RTC_DCHECK_GE(active_streams.size(), num_simulcast_layers); + SetupCodec3TL(); + codec_.numberOfSimulcastStreams = num_simulcast_layers; + codec_.simulcastStream[0].numberOfTemporalLayers = 3; + codec_.simulcastStream[0].maxBitrate = 500; + codec_.simulcastStream[0].targetBitrate = 100; + codec_.simulcastStream[0].minBitrate = 10; + codec_.simulcastStream[0].active = active_streams[0]; + } + + void SetupCodec3TL() { + codec_.maxBitrate = 0; + codec_.VP8()->numberOfTemporalLayers = 3; } VideoBitrateAllocation GetAllocation(uint32_t target_bitrate) { @@ -219,6 +233,37 @@ TEST_F(SimulcastRateAllocatorTest, SingleSimulcastWithinLimits) { } } +TEST_F(SimulcastRateAllocatorTest, Regular3TLTemporalRateAllocation) { + SetupCodec3SL3TL({true, true, true}); + CreateAllocator(); + + const VideoBitrateAllocation alloc = GetAllocation(kMinBitrateKbps); + // 40/20/40. + EXPECT_EQ(static_cast(0.4 * kMinBitrateKbps), + alloc.GetBitrate(0, 0) / 1000); + EXPECT_EQ(static_cast(0.2 * kMinBitrateKbps), + alloc.GetBitrate(0, 1) / 1000); + EXPECT_EQ(static_cast(0.4 * kMinBitrateKbps), + alloc.GetBitrate(0, 2) / 1000); +} + +TEST_F(SimulcastRateAllocatorTest, BaseHeavy3TLTemporalRateAllocation) { + test::ScopedFieldTrials field_trials( + "WebRTC-UseBaseHeavyVP8TL3RateAllocation/Enabled/"); + + SetupCodec3SL3TL({true, true, true}); + CreateAllocator(); + + const VideoBitrateAllocation alloc = GetAllocation(kMinBitrateKbps); + // 60/20/20. + EXPECT_EQ(static_cast(0.6 * kMinBitrateKbps), + alloc.GetBitrate(0, 0) / 1000); + EXPECT_EQ(static_cast(0.2 * kMinBitrateKbps), + alloc.GetBitrate(0, 1) / 1000); + EXPECT_EQ(static_cast(0.2 * kMinBitrateKbps), + alloc.GetBitrate(0, 2) / 1000); +} + TEST_F(SimulcastRateAllocatorTest, SingleSimulcastInactive) { codec_.numberOfSimulcastStreams = 1; codec_.simulcastStream[0].minBitrate = kMinBitrateKbps; @@ -234,8 +279,7 @@ TEST_F(SimulcastRateAllocatorTest, SingleSimulcastInactive) { } TEST_F(SimulcastRateAllocatorTest, OneToThreeStreams) { - const std::vector active_streams(3, true); - SetupCodecThreeSimulcastStreams(active_streams); + SetupCodec3SL3TL({true, true, true}); CreateAllocator(); { @@ -326,8 +370,7 @@ TEST_F(SimulcastRateAllocatorTest, OneToThreeStreams) { // If three simulcast streams that are all inactive, none of them should be // allocated bitrate. TEST_F(SimulcastRateAllocatorTest, ThreeStreamsInactive) { - const std::vector active_streams(3, false); - SetupCodecThreeSimulcastStreams(active_streams); + SetupCodec3SL3TL({false, false, false}); CreateAllocator(); // Just enough to allocate the min. @@ -352,8 +395,7 @@ TEST_F(SimulcastRateAllocatorTest, ThreeStreamsInactive) { // If there are two simulcast streams, we expect the high active stream to be // allocated as if it is a single active stream. TEST_F(SimulcastRateAllocatorTest, TwoStreamsLowInactive) { - const std::vector active_streams({false, true}); - SetupCodecTwoSimulcastStreams(active_streams); + SetupCodec2SL3TL({false, true}); CreateAllocator(); const uint32_t kActiveStreamMinBitrate = codec_.simulcastStream[1].minBitrate; @@ -385,8 +427,7 @@ TEST_F(SimulcastRateAllocatorTest, TwoStreamsLowInactive) { // If there are two simulcast streams, we expect the low active stream to be // allocated as if it is a single active stream. TEST_F(SimulcastRateAllocatorTest, TwoStreamsHighInactive) { - const std::vector active_streams({true, false}); - SetupCodecTwoSimulcastStreams(active_streams); + SetupCodec2SL3TL({true, false}); CreateAllocator(); const uint32_t kActiveStreamMinBitrate = codec_.simulcastStream[0].minBitrate; @@ -419,8 +460,7 @@ TEST_F(SimulcastRateAllocatorTest, TwoStreamsHighInactive) { // other two streams should be allocated bitrate the same as if they are two // active simulcast streams. TEST_F(SimulcastRateAllocatorTest, ThreeStreamsMiddleInactive) { - const std::vector active_streams({true, false, true}); - SetupCodecThreeSimulcastStreams(active_streams); + SetupCodec3SL3TL({true, false, true}); CreateAllocator(); {