diff --git a/modules/congestion_controller/goog_cc/goog_cc_network_control_unittest.cc b/modules/congestion_controller/goog_cc/goog_cc_network_control_unittest.cc index c12681c5c5..33550d2a51 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_network_control_unittest.cc +++ b/modules/congestion_controller/goog_cc/goog_cc_network_control_unittest.cc @@ -568,22 +568,21 @@ DataRate AverageBitrateAfterCrossInducedLoss(std::string name) { } TEST_F(GoogCcNetworkControllerTest, - NoLossBasedRecoversSlowerAfterCrossInducedLoss) { + LossBasedRecoversFasterAfterCrossInducedLoss) { // This test acts as a reference for the test below, showing that without the // trial, we have worse behavior. - DataRate average_bitrate = + DataRate average_bitrate_without_loss_based = AverageBitrateAfterCrossInducedLoss("googcc_unit/no_cross_loss_based"); - RTC_DCHECK_LE(average_bitrate, DataRate::KilobitsPerSec(625)); -} -TEST_F(GoogCcNetworkControllerTest, - LossBasedRecoversFasterAfterCrossInducedLoss) { // We recover bitrate better when subject to loss spikes from cross traffic // when loss based controller is used. ScopedFieldTrials trial("WebRTC-Bwe-LossBasedControl/Enabled/"); - DataRate average_bitrate = + SetUp(); + DataRate average_bitrate_with_loss_based = AverageBitrateAfterCrossInducedLoss("googcc_unit/cross_loss_based"); - RTC_DCHECK_GE(average_bitrate, DataRate::KilobitsPerSec(725)); + + EXPECT_GE(average_bitrate_with_loss_based, + average_bitrate_without_loss_based * 1.1); } TEST_F(GoogCcNetworkControllerTest, LossBasedEstimatorCapsRateAtModerateLoss) { @@ -698,7 +697,7 @@ TEST_F(GoogCcNetworkControllerTest, DetectsHighRateInSafeResetTrial) { {s.CreateSimulationNode(NetworkSimulationConfig())}); s.CreateVideoStream(route->forward(), VideoStreamConfig()); // Allow the controller to stabilize. - s.RunFor(TimeDelta::Millis(1000)); + s.RunFor(TimeDelta::Millis(2000)); EXPECT_NEAR(client->send_bandwidth().kbps(), kInitialLinkCapacity.kbps(), 50); s.ChangeRoute(route->forward(), {new_net}); // Allow new settings to propagate, but not probes to be received. diff --git a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc index d52d779712..e5fef541d6 100644 --- a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc +++ b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc @@ -68,9 +68,6 @@ constexpr uint32_t kVp832ByteAlign = 32u; constexpr int kRtpTicksPerSecond = 90000; constexpr int kRtpTicksPerMs = kRtpTicksPerSecond / 1000; -constexpr double kLowRateFactor = 1.0; -constexpr double kHighRateFactor = 2.0; - // VP8 denoiser states. enum denoiserState : uint32_t { kDenoiserOff, @@ -82,15 +79,6 @@ enum denoiserState : uint32_t { kDenoiserOnAdaptive }; -// These settings correspond to the settings in vpx_codec_enc_cfg. -struct Vp8RateSettings { - uint32_t rc_undershoot_pct; - uint32_t rc_overshoot_pct; - uint32_t rc_buf_sz; - uint32_t rc_buf_optimal_sz; - uint32_t rc_dropframe_thresh; -}; - // Greatest common divisior int GCD(int a, int b) { int c = a % b; @@ -102,56 +90,6 @@ int GCD(int a, int b) { return b; } -uint32_t Interpolate(uint32_t low, - uint32_t high, - double bandwidth_headroom_factor) { - RTC_DCHECK_GE(bandwidth_headroom_factor, kLowRateFactor); - RTC_DCHECK_LE(bandwidth_headroom_factor, kHighRateFactor); - - // |factor| is between 0.0 and 1.0. - const double factor = bandwidth_headroom_factor - kLowRateFactor; - - return static_cast(((1.0 - factor) * low) + (factor * high) + 0.5); -} - -Vp8RateSettings GetRateSettings(double bandwidth_headroom_factor) { - static const Vp8RateSettings low_settings{1000u, 0u, 100u, 30u, 40u}; - static const Vp8RateSettings high_settings{100u, 15u, 1000u, 600u, 5u}; - - if (bandwidth_headroom_factor <= kLowRateFactor) { - return low_settings; - } else if (bandwidth_headroom_factor >= kHighRateFactor) { - return high_settings; - } - - Vp8RateSettings settings; - settings.rc_undershoot_pct = - Interpolate(low_settings.rc_undershoot_pct, - high_settings.rc_undershoot_pct, bandwidth_headroom_factor); - settings.rc_overshoot_pct = - Interpolate(low_settings.rc_overshoot_pct, high_settings.rc_overshoot_pct, - bandwidth_headroom_factor); - settings.rc_buf_sz = - Interpolate(low_settings.rc_buf_sz, high_settings.rc_buf_sz, - bandwidth_headroom_factor); - settings.rc_buf_optimal_sz = - Interpolate(low_settings.rc_buf_optimal_sz, - high_settings.rc_buf_optimal_sz, bandwidth_headroom_factor); - settings.rc_dropframe_thresh = - Interpolate(low_settings.rc_dropframe_thresh, - high_settings.rc_dropframe_thresh, bandwidth_headroom_factor); - return settings; -} - -void UpdateRateSettings(vpx_codec_enc_cfg_t* config, - const Vp8RateSettings& new_settings) { - config->rc_undershoot_pct = new_settings.rc_undershoot_pct; - config->rc_overshoot_pct = new_settings.rc_overshoot_pct; - config->rc_buf_sz = new_settings.rc_buf_sz; - config->rc_buf_optimal_sz = new_settings.rc_buf_optimal_sz; - config->rc_dropframe_thresh = new_settings.rc_dropframe_thresh; -} - static_assert(Vp8EncoderConfig::TemporalLayerConfig::kMaxPeriodicity == VPX_TS_MAX_PERIODICITY, "Vp8EncoderConfig::kMaxPeriodicity must be kept in sync with the " @@ -407,14 +345,6 @@ void LibvpxVp8Encoder::SetRates(const RateControlParameters& parameters) { UpdateVpxConfiguration(stream_idx); - if (rate_control_settings_.Vp8DynamicRateSettings()) { - // Tweak rate control settings based on available network headroom. - UpdateRateSettings( - &vpx_configs_[i], - GetRateSettings(parameters.bandwidth_allocation.bps() / - parameters.bitrate.get_sum_bps())); - } - vpx_codec_err_t err = libvpx_->codec_enc_config_set(&encoders_[i], &vpx_configs_[i]); if (err != VPX_CODEC_OK) { diff --git a/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc b/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc index cc6189701b..3d04bb1dc1 100644 --- a/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc +++ b/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc @@ -190,68 +190,6 @@ TEST_F(TestVp8Impl, SetRates) { bitrate_allocation, static_cast(codec_settings_.maxFramerate))); } -TEST_F(TestVp8Impl, DynamicSetRates) { - test::ScopedFieldTrials field_trials( - "WebRTC-VideoRateControl/vp8_dynamic_rate:true/"); - auto* const vpx = new NiceMock(); - LibvpxVp8Encoder encoder((std::unique_ptr(vpx)), - VP8Encoder::Settings()); - EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, - encoder.InitEncode(&codec_settings_, - VideoEncoder::Settings(kCapabilities, 1, 1000))); - - const uint32_t kBitrateBps = 300000; - VideoEncoder::RateControlParameters rate_settings; - rate_settings.bitrate.SetBitrate(0, 0, kBitrateBps); - rate_settings.framerate_fps = - static_cast(codec_settings_.maxFramerate); - - // Set rates with no headroom. - rate_settings.bandwidth_allocation = DataRate::BitsPerSec(kBitrateBps); - EXPECT_CALL( - *vpx, - codec_enc_config_set( - _, AllOf(Field(&vpx_codec_enc_cfg_t::rc_target_bitrate, - kBitrateBps / 1000), - Field(&vpx_codec_enc_cfg_t::rc_undershoot_pct, 1000u), - Field(&vpx_codec_enc_cfg_t::rc_overshoot_pct, 0u), - Field(&vpx_codec_enc_cfg_t::rc_buf_sz, 100u), - Field(&vpx_codec_enc_cfg_t::rc_buf_optimal_sz, 30u), - Field(&vpx_codec_enc_cfg_t::rc_dropframe_thresh, 40u)))) - .WillOnce(Return(VPX_CODEC_OK)); - encoder.SetRates(rate_settings); - - // Set rates with max headroom. - rate_settings.bandwidth_allocation = DataRate::BitsPerSec(kBitrateBps * 2); - EXPECT_CALL( - *vpx, codec_enc_config_set( - _, AllOf(Field(&vpx_codec_enc_cfg_t::rc_target_bitrate, - kBitrateBps / 1000), - Field(&vpx_codec_enc_cfg_t::rc_undershoot_pct, 100u), - Field(&vpx_codec_enc_cfg_t::rc_overshoot_pct, 15u), - Field(&vpx_codec_enc_cfg_t::rc_buf_sz, 1000u), - Field(&vpx_codec_enc_cfg_t::rc_buf_optimal_sz, 600u), - Field(&vpx_codec_enc_cfg_t::rc_dropframe_thresh, 5u)))) - .WillOnce(Return(VPX_CODEC_OK)); - encoder.SetRates(rate_settings); - - // Set rates with headroom half way. - rate_settings.bandwidth_allocation = - DataRate::BitsPerSec((3 * kBitrateBps) / 2); - EXPECT_CALL( - *vpx, - codec_enc_config_set( - _, AllOf(Field(&vpx_codec_enc_cfg_t::rc_target_bitrate, - kBitrateBps / 1000), - Field(&vpx_codec_enc_cfg_t::rc_undershoot_pct, 550u), - Field(&vpx_codec_enc_cfg_t::rc_overshoot_pct, 8u), - Field(&vpx_codec_enc_cfg_t::rc_buf_sz, 550u), - Field(&vpx_codec_enc_cfg_t::rc_buf_optimal_sz, 315u), - Field(&vpx_codec_enc_cfg_t::rc_dropframe_thresh, 23u)))) - .WillOnce(Return(VPX_CODEC_OK)); - encoder.SetRates(rate_settings); -} - TEST_F(TestVp8Impl, EncodeFrameAndRelease) { EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Release()); EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, diff --git a/modules/video_coding/codecs/vp9/vp9_impl.cc b/modules/video_coding/codecs/vp9/vp9_impl.cc index c11f67c8e4..4024baa0f1 100644 --- a/modules/video_coding/codecs/vp9/vp9_impl.cc +++ b/modules/video_coding/codecs/vp9/vp9_impl.cc @@ -56,9 +56,6 @@ uint8_t kUpdBufIdx[4] = {0, 0, 1, 0}; // Maximum allowed PID difference for differnet per-layer frame-rate case. const int kMaxAllowedPidDiff = 30; -constexpr double kLowRateFactor = 1.0; -constexpr double kHighRateFactor = 2.0; - // TODO(ilink): Tune these thresholds further. // Selected using ConverenceMotion_1280_720_50.yuv clip. // No toggling observed on any link capacity from 100-2000kbps. @@ -68,15 +65,6 @@ constexpr double kHighRateFactor = 2.0; constexpr int kLowVp9QpThreshold = 149; constexpr int kHighVp9QpThreshold = 205; -// These settings correspond to the settings in vpx_codec_enc_cfg. -struct Vp9RateSettings { - uint32_t rc_undershoot_pct; - uint32_t rc_overshoot_pct; - uint32_t rc_buf_sz; - uint32_t rc_buf_optimal_sz; - uint32_t rc_dropframe_thresh; -}; - // Only positive speeds, range for real-time coding currently is: 5 - 8. // Lower means slower/better quality, higher means fastest/lower quality. int GetCpuSpeed(int width, int height) { @@ -168,56 +156,6 @@ std::pair GetActiveLayers( return {0, 0}; } -uint32_t Interpolate(uint32_t low, - uint32_t high, - double bandwidth_headroom_factor) { - RTC_DCHECK_GE(bandwidth_headroom_factor, kLowRateFactor); - RTC_DCHECK_LE(bandwidth_headroom_factor, kHighRateFactor); - - // |factor| is between 0.0 and 1.0. - const double factor = bandwidth_headroom_factor - kLowRateFactor; - - return static_cast(((1.0 - factor) * low) + (factor * high) + 0.5); -} - -Vp9RateSettings GetRateSettings(double bandwidth_headroom_factor) { - static const Vp9RateSettings low_settings{100u, 0u, 100u, 33u, 40u}; - static const Vp9RateSettings high_settings{50u, 50u, 1000u, 700u, 5u}; - - if (bandwidth_headroom_factor <= kLowRateFactor) { - return low_settings; - } else if (bandwidth_headroom_factor >= kHighRateFactor) { - return high_settings; - } - - Vp9RateSettings settings; - settings.rc_undershoot_pct = - Interpolate(low_settings.rc_undershoot_pct, - high_settings.rc_undershoot_pct, bandwidth_headroom_factor); - settings.rc_overshoot_pct = - Interpolate(low_settings.rc_overshoot_pct, high_settings.rc_overshoot_pct, - bandwidth_headroom_factor); - settings.rc_buf_sz = - Interpolate(low_settings.rc_buf_sz, high_settings.rc_buf_sz, - bandwidth_headroom_factor); - settings.rc_buf_optimal_sz = - Interpolate(low_settings.rc_buf_optimal_sz, - high_settings.rc_buf_optimal_sz, bandwidth_headroom_factor); - settings.rc_dropframe_thresh = - Interpolate(low_settings.rc_dropframe_thresh, - high_settings.rc_dropframe_thresh, bandwidth_headroom_factor); - return settings; -} - -void UpdateRateSettings(vpx_codec_enc_cfg_t* config, - const Vp9RateSettings& new_settings) { - config->rc_undershoot_pct = new_settings.rc_undershoot_pct; - config->rc_overshoot_pct = new_settings.rc_overshoot_pct; - config->rc_buf_sz = new_settings.rc_buf_sz; - config->rc_buf_optimal_sz = new_settings.rc_buf_optimal_sz; - config->rc_dropframe_thresh = new_settings.rc_dropframe_thresh; -} - std::unique_ptr CreateVp9ScalabilityStructure( const VideoCodec& codec) { int num_spatial_layers = codec.VP9().numberOfSpatialLayers; @@ -364,9 +302,6 @@ VP9EncoderImpl::VP9EncoderImpl(const cricket::VideoCodec& codec, trusted_rate_controller_( RateControlSettings::ParseFromKeyValueConfig(&trials) .LibvpxVp9TrustedRateController()), - dynamic_rate_settings_( - RateControlSettings::ParseFromKeyValueConfig(&trials) - .Vp9DynamicRateSettings()), layer_buffering_(false), full_superframe_drop_(true), first_frame_in_picture_(true), @@ -586,13 +521,6 @@ void VP9EncoderImpl::SetRates(const RateControlParameters& parameters) { codec_.maxFramerate = static_cast(parameters.framerate_fps + 0.5); - if (dynamic_rate_settings_) { - // Tweak rate control settings based on available network headroom. - UpdateRateSettings( - config_, GetRateSettings(parameters.bandwidth_allocation.bps() / - parameters.bitrate.get_sum_bps())); - } - bool res = SetSvcRates(parameters.bitrate); RTC_DCHECK(res) << "Failed to set new bitrate allocation"; config_changed_ = true; diff --git a/modules/video_coding/codecs/vp9/vp9_impl.h b/modules/video_coding/codecs/vp9/vp9_impl.h index 7ba6a1baba..14c3ca8ccc 100644 --- a/modules/video_coding/codecs/vp9/vp9_impl.h +++ b/modules/video_coding/codecs/vp9/vp9_impl.h @@ -132,7 +132,6 @@ class VP9EncoderImpl : public VP9Encoder { InterLayerPredMode inter_layer_pred_; bool external_ref_control_; const bool trusted_rate_controller_; - const bool dynamic_rate_settings_; bool layer_buffering_; const bool full_superframe_drop_; vpx_svc_frame_drop_t svc_drop_frame_; diff --git a/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc b/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc index 259524f181..24d7c58bcd 100644 --- a/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc +++ b/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc @@ -35,6 +35,9 @@ constexpr uint32_t kLegacyScreenshareMaxBitrateKbps = 1000; // Bitrates for upper simulcast screenshare layer. constexpr uint32_t kSimulcastScreenshareMinBitrateKbps = 600; constexpr uint32_t kSimulcastScreenshareMaxBitrateKbps = 1250; +// Default video hysteresis factor: allocatable bitrate for next layer must +// exceed 20% of min setting in order to be initially turned on. +const double kDefaultHysteresis = 1.2; class MockTemporalLayers : public Vp8FrameBufferController { public: @@ -229,6 +232,7 @@ TEST_F(SimulcastRateAllocatorTest, SingleSimulcastBelowMin) { TEST_F(SimulcastRateAllocatorTest, SignalsBwLimited) { // Enough to enable all layers. const int kVeryBigBitrate = 100000; + // With simulcast, use the min bitrate from the ss spec instead of the global. SetupCodec3SL3TL({true, true, true}); CreateAllocator(); @@ -240,10 +244,13 @@ TEST_F(SimulcastRateAllocatorTest, SignalsBwLimited) { EXPECT_TRUE(GetAllocation(codec_.simulcastStream[0].targetBitrate + codec_.simulcastStream[1].minBitrate) .is_bw_limited()); - EXPECT_FALSE(GetAllocation(codec_.simulcastStream[0].targetBitrate + - codec_.simulcastStream[1].targetBitrate + - codec_.simulcastStream[2].minBitrate) - .is_bw_limited()); + EXPECT_FALSE( + GetAllocation( + codec_.simulcastStream[0].targetBitrate + + codec_.simulcastStream[1].targetBitrate + + static_cast( + codec_.simulcastStream[2].minBitrate * kDefaultHysteresis + 0.5)) + .is_bw_limited()); EXPECT_FALSE(GetAllocation(kVeryBigBitrate).is_bw_limited()); } @@ -339,20 +346,23 @@ TEST_F(SimulcastRateAllocatorTest, OneToThreeStreams) { ExpectEqual(expected, GetAllocation(bitrate)); } + uint32_t kMinInitialRateTwoLayers = + codec_.simulcastStream[0].targetBitrate + + static_cast(codec_.simulcastStream[1].minBitrate * + kDefaultHysteresis); { // Bitrate above target for first stream, but below min for the next one. - const uint32_t bitrate = codec_.simulcastStream[0].targetBitrate + - codec_.simulcastStream[1].minBitrate - 1; + const uint32_t bitrate = kMinInitialRateTwoLayers - 1; uint32_t expected[] = {bitrate, 0, 0}; ExpectEqual(expected, GetAllocation(bitrate)); } { // Just enough for two streams. - const uint32_t bitrate = codec_.simulcastStream[0].targetBitrate + - codec_.simulcastStream[1].minBitrate; - uint32_t expected[] = {codec_.simulcastStream[0].targetBitrate, - codec_.simulcastStream[1].minBitrate, 0}; + const uint32_t bitrate = kMinInitialRateTwoLayers; + uint32_t expected[] = { + codec_.simulcastStream[0].targetBitrate, + kMinInitialRateTwoLayers - codec_.simulcastStream[0].targetBitrate, 0}; ExpectEqual(expected, GetAllocation(bitrate)); } @@ -365,11 +375,15 @@ TEST_F(SimulcastRateAllocatorTest, OneToThreeStreams) { ExpectEqual(expected, GetAllocation(bitrate)); } + uint32_t kMinInitialRateThreeLayers = + codec_.simulcastStream[0].targetBitrate + + codec_.simulcastStream[1].targetBitrate + + static_cast(codec_.simulcastStream[2].minBitrate * + kDefaultHysteresis); { // First two streams maxed out, but not enough for third. Nowhere to put // remaining bits. - const uint32_t bitrate = codec_.simulcastStream[0].maxBitrate + - codec_.simulcastStream[1].maxBitrate + 499; + const uint32_t bitrate = kMinInitialRateThreeLayers - 1; uint32_t expected[] = {codec_.simulcastStream[0].targetBitrate, codec_.simulcastStream[1].maxBitrate, 0}; ExpectEqual(expected, GetAllocation(bitrate)); @@ -377,12 +391,12 @@ TEST_F(SimulcastRateAllocatorTest, OneToThreeStreams) { { // Just enough for all three streams. - const uint32_t bitrate = codec_.simulcastStream[0].targetBitrate + - codec_.simulcastStream[1].targetBitrate + - codec_.simulcastStream[2].minBitrate; - uint32_t expected[] = {codec_.simulcastStream[0].targetBitrate, - codec_.simulcastStream[1].targetBitrate, - codec_.simulcastStream[2].minBitrate}; + const uint32_t bitrate = kMinInitialRateThreeLayers; + uint32_t expected[] = { + codec_.simulcastStream[0].targetBitrate, + codec_.simulcastStream[1].targetBitrate, + static_cast(codec_.simulcastStream[2].minBitrate * + kDefaultHysteresis)}; ExpectEqual(expected, GetAllocation(bitrate)); } diff --git a/rtc_base/experiments/rate_control_settings.cc b/rtc_base/experiments/rate_control_settings.cc index 71c2eb1985..6766db62c3 100644 --- a/rtc_base/experiments/rate_control_settings.cc +++ b/rtc_base/experiments/rate_control_settings.cc @@ -75,21 +75,19 @@ constexpr char VideoRateControlConfig::kKey[]; std::unique_ptr VideoRateControlConfig::Parser() { // The empty comments ensures that each pair is on a separate line. return StructParametersParser::Create( - "pacing_factor", &pacing_factor, // - "alr_probing", &alr_probing, // - "vp8_qp_max", &vp8_qp_max, // - "vp8_min_pixels", &vp8_min_pixels, // - "trust_vp8", &trust_vp8, // - "trust_vp9", &trust_vp9, // - "video_hysteresis", &video_hysteresis, // - "screenshare_hysteresis", &screenshare_hysteresis, // - "probe_max_allocation", &probe_max_allocation, // - "bitrate_adjuster", &bitrate_adjuster, // - "adjuster_use_headroom", &adjuster_use_headroom, // - "vp8_s0_boost", &vp8_s0_boost, // - "vp8_base_heavy_tl3_alloc", &vp8_base_heavy_tl3_alloc, // - "vp8_dynamic_rate", &vp8_dynamic_rate, // - "vp9_dynamic_rate", &vp9_dynamic_rate); + "pacing_factor", &pacing_factor, // + "alr_probing", &alr_probing, // + "vp8_qp_max", &vp8_qp_max, // + "vp8_min_pixels", &vp8_min_pixels, // + "trust_vp8", &trust_vp8, // + "trust_vp9", &trust_vp9, // + "video_hysteresis", &video_hysteresis, // + "screenshare_hysteresis", &screenshare_hysteresis, // + "probe_max_allocation", &probe_max_allocation, // + "bitrate_adjuster", &bitrate_adjuster, // + "adjuster_use_headroom", &adjuster_use_headroom, // + "vp8_s0_boost", &vp8_s0_boost, // + "vp8_base_heavy_tl3_alloc", &vp8_base_heavy_tl3_alloc); } RateControlSettings::RateControlSettings( @@ -182,18 +180,10 @@ bool RateControlSettings::Vp8BoostBaseLayerQuality() const { return video_config_.vp8_s0_boost; } -bool RateControlSettings::Vp8DynamicRateSettings() const { - return video_config_.vp8_dynamic_rate; -} - bool RateControlSettings::LibvpxVp9TrustedRateController() const { return video_config_.trust_vp9; } -bool RateControlSettings::Vp9DynamicRateSettings() const { - return video_config_.vp9_dynamic_rate; -} - double RateControlSettings::GetSimulcastHysteresisFactor( VideoCodecMode mode) const { if (mode == VideoCodecMode::kScreensharing) { diff --git a/rtc_base/experiments/rate_control_settings.h b/rtc_base/experiments/rate_control_settings.h index 6898bf6dd3..db7f1cd136 100644 --- a/rtc_base/experiments/rate_control_settings.h +++ b/rtc_base/experiments/rate_control_settings.h @@ -36,18 +36,16 @@ struct VideoRateControlConfig { bool alr_probing = false; absl::optional vp8_qp_max; absl::optional vp8_min_pixels; - bool trust_vp8 = false; - bool trust_vp9 = false; - double video_hysteresis = 1.0; + bool trust_vp8 = true; + bool trust_vp9 = true; + double video_hysteresis = 1.2; // Default to 35% hysteresis for simulcast screenshare. double screenshare_hysteresis = 1.35; bool probe_max_allocation = true; - bool bitrate_adjuster = false; - bool adjuster_use_headroom = false; - bool vp8_s0_boost = true; + bool bitrate_adjuster = true; + bool adjuster_use_headroom = true; + bool vp8_s0_boost = false; bool vp8_base_heavy_tl3_alloc = false; - bool vp8_dynamic_rate = false; - bool vp9_dynamic_rate = false; std::unique_ptr Parser(); }; diff --git a/rtc_base/experiments/rate_control_settings_unittest.cc b/rtc_base/experiments/rate_control_settings_unittest.cc index b769c46a04..8d722722e4 100644 --- a/rtc_base/experiments/rate_control_settings_unittest.cc +++ b/rtc_base/experiments/rate_control_settings_unittest.cc @@ -99,15 +99,15 @@ TEST(RateControlSettingsTest, DoesNotGetTooSmallLibvpxVp8MinPixelValue) { TEST(RateControlSettingsTest, LibvpxTrustedRateController) { const RateControlSettings settings_before = RateControlSettings::ParseFromFieldTrials(); - EXPECT_FALSE(settings_before.LibvpxVp8TrustedRateController()); - EXPECT_FALSE(settings_before.LibvpxVp9TrustedRateController()); + EXPECT_TRUE(settings_before.LibvpxVp8TrustedRateController()); + EXPECT_TRUE(settings_before.LibvpxVp9TrustedRateController()); test::ScopedFieldTrials field_trials( - "WebRTC-VideoRateControl/trust_vp8:1,trust_vp9:1/"); + "WebRTC-VideoRateControl/trust_vp8:0,trust_vp9:0/"); const RateControlSettings settings_after = RateControlSettings::ParseFromFieldTrials(); - EXPECT_TRUE(settings_after.LibvpxVp8TrustedRateController()); - EXPECT_TRUE(settings_after.LibvpxVp9TrustedRateController()); + EXPECT_FALSE(settings_after.LibvpxVp8TrustedRateController()); + EXPECT_FALSE(settings_after.LibvpxVp9TrustedRateController()); } TEST(RateControlSettingsTest, Vp8BaseHeavyTl3RateAllocationLegacyKey) { @@ -154,10 +154,10 @@ TEST(RateControlSettingsTest, GetSimulcastHysteresisFactor) { RateControlSettings::ParseFromFieldTrials(); EXPECT_DOUBLE_EQ(settings_before.GetSimulcastHysteresisFactor( VideoCodecMode::kRealtimeVideo), - 1.0); + 1.2); EXPECT_DOUBLE_EQ(settings_before.GetSimulcastHysteresisFactor( VideoEncoderConfig::ContentType::kRealtimeVideo), - 1.0); + 1.2); EXPECT_DOUBLE_EQ(settings_before.GetSimulcastHysteresisFactor( VideoCodecMode::kScreensharing), 1.35); @@ -167,16 +167,16 @@ TEST(RateControlSettingsTest, GetSimulcastHysteresisFactor) { test::ScopedFieldTrials field_trials( "WebRTC-VideoRateControl/" - "video_hysteresis:1.2,screenshare_hysteresis:1.4/"); + "video_hysteresis:1.0,screenshare_hysteresis:1.4/"); const RateControlSettings settings_after = RateControlSettings::ParseFromFieldTrials(); EXPECT_DOUBLE_EQ(settings_after.GetSimulcastHysteresisFactor( VideoCodecMode::kRealtimeVideo), - 1.2); + 1.0); EXPECT_DOUBLE_EQ(settings_after.GetSimulcastHysteresisFactor( VideoEncoderConfig::ContentType::kRealtimeVideo), - 1.2); + 1.0); EXPECT_DOUBLE_EQ(settings_after.GetSimulcastHysteresisFactor( VideoCodecMode::kScreensharing), 1.4); @@ -196,16 +196,16 @@ TEST(RateControlSettingsTest, TriggerProbeOnMaxAllocatedBitrateChange) { } TEST(RateControlSettingsTest, UseEncoderBitrateAdjuster) { - // Should be off by default. - EXPECT_FALSE( + // Should be on by default. + EXPECT_TRUE( RateControlSettings::ParseFromFieldTrials().UseEncoderBitrateAdjuster()); { - // Can be turned on via field trial. + // Can be turned off via field trial. test::ScopedFieldTrials field_trials( - "WebRTC-VideoRateControl/bitrate_adjuster:true/"); - EXPECT_TRUE(RateControlSettings::ParseFromFieldTrials() - .UseEncoderBitrateAdjuster()); + "WebRTC-VideoRateControl/bitrate_adjuster:false/"); + EXPECT_FALSE(RateControlSettings::ParseFromFieldTrials() + .UseEncoderBitrateAdjuster()); } } diff --git a/rtc_base/experiments/stable_target_rate_experiment_unittest.cc b/rtc_base/experiments/stable_target_rate_experiment_unittest.cc index 71e757d68c..dbd841840d 100644 --- a/rtc_base/experiments/stable_target_rate_experiment_unittest.cc +++ b/rtc_base/experiments/stable_target_rate_experiment_unittest.cc @@ -19,7 +19,7 @@ TEST(StableBweExperimentTest, Default) { StableTargetRateExperiment config = StableTargetRateExperiment::ParseFromFieldTrials(); EXPECT_FALSE(config.IsEnabled()); - EXPECT_EQ(config.GetVideoHysteresisFactor(), 1.0); + EXPECT_EQ(config.GetVideoHysteresisFactor(), 1.2); EXPECT_EQ(config.GetScreenshareHysteresisFactor(), 1.35); } @@ -30,7 +30,7 @@ TEST(StableBweExperimentTest, EnabledNoHysteresis) { StableTargetRateExperiment config = StableTargetRateExperiment::ParseFromFieldTrials(); EXPECT_TRUE(config.IsEnabled()); - EXPECT_EQ(config.GetVideoHysteresisFactor(), 1.0); + EXPECT_EQ(config.GetVideoHysteresisFactor(), 1.2); EXPECT_EQ(config.GetScreenshareHysteresisFactor(), 1.35); } diff --git a/test/fake_encoder.cc b/test/fake_encoder.cc index 8fd2f6d0a6..814be280ec 100644 --- a/test/fake_encoder.cc +++ b/test/fake_encoder.cc @@ -276,6 +276,17 @@ const char* FakeEncoder::kImplementationName = "fake_encoder"; VideoEncoder::EncoderInfo FakeEncoder::GetEncoderInfo() const { EncoderInfo info; info.implementation_name = kImplementationName; + MutexLock lock(&mutex_); + for (int sid = 0; sid < config_.numberOfSimulcastStreams; ++sid) { + int number_of_temporal_layers = + config_.simulcastStream[sid].numberOfTemporalLayers; + info.fps_allocation[sid].clear(); + for (int tid = 0; tid < number_of_temporal_layers; ++tid) { + // {1/4, 1/2, 1} allocation for num layers = 3. + info.fps_allocation[sid].push_back(255 / + (number_of_temporal_layers - tid)); + } + } return info; } diff --git a/test/scenario/stats_collection_unittest.cc b/test/scenario/stats_collection_unittest.cc index 7f27eaeaf8..17f0e3a656 100644 --- a/test/scenario/stats_collection_unittest.cc +++ b/test/scenario/stats_collection_unittest.cc @@ -87,7 +87,7 @@ TEST(ScenarioAnalyzerTest, PsnrIsLowWhenNetworkIsBad) { EXPECT_NEAR(stats.call.stats().target_rate.Mean().kbps(), 75, 50); EXPECT_NEAR(stats.video_send.stats().media_bitrate.Mean().kbps(), 100, 50); EXPECT_NEAR(stats.video_receive.stats().resolution.Mean(), 180, 10); - EXPECT_NEAR(stats.audio_receive.stats().jitter_buffer.Mean().ms(), 200, 150); + EXPECT_NEAR(stats.audio_receive.stats().jitter_buffer.Mean().ms(), 250, 150); } TEST(ScenarioAnalyzerTest, CountsCapturedButNotRendered) { diff --git a/video/video_send_stream_impl.cc b/video/video_send_stream_impl.cc index 665fe09169..ee4301862d 100644 --- a/video/video_send_stream_impl.cc +++ b/video/video_send_stream_impl.cc @@ -49,6 +49,13 @@ static constexpr int64_t kMaxVbaThrottleTimeMs = 500; constexpr TimeDelta kEncoderTimeOut = TimeDelta::Seconds(2); +// When send-side BWE is used a stricter 1.1x pacing factor is used, rather than +// the 2.5x which is used with receive-side BWE. Provides a more careful +// bandwidth rampup with less risk of overshoots causing adverse effects like +// packet loss. Not used for receive side BWE, since there we lack the probing +// feature and so may result in too slow initial rampup. +static constexpr double kStrictPacingMultiplier = 1.1; + bool TransportSeqNumExtensionConfigured(const VideoSendStream::Config& config) { const std::vector& extensions = config.rtp.extensions; return absl::c_any_of(extensions, [](const RtpExtension& ext) { @@ -175,7 +182,7 @@ bool SameStreamsEnabled(const VideoBitrateAllocation& lhs, } // namespace PacingConfig::PacingConfig() - : pacing_factor("factor", PacedSender::kDefaultPaceMultiplier), + : pacing_factor("factor", kStrictPacingMultiplier), max_pacing_delay("max_delay", TimeDelta::Millis(PacedSender::kMaxQueueLengthMs)) { ParseFieldTrial({&pacing_factor, &max_pacing_delay}, diff --git a/video/video_send_stream_impl_unittest.cc b/video/video_send_stream_impl_unittest.cc index 795b181d63..ee303b4eac 100644 --- a/video/video_send_stream_impl_unittest.cc +++ b/video/video_send_stream_impl_unittest.cc @@ -997,8 +997,16 @@ TEST_F(VideoSendStreamImplTest, ConfiguresBitratesForSvc) { const bool using_alr = test_config.alr || test_config.screenshare; // If ALR is used, pads only to min bitrate as rampup is handled by // probing. Otherwise target_bitrate contains the padding target. + const RateControlSettings trials = + RateControlSettings::ParseFromFieldTrials(); int expected_padding = - using_alr ? stream.min_bitrate_bps : stream.target_bitrate_bps; + using_alr + ? stream.min_bitrate_bps + : static_cast(stream.target_bitrate_bps * + trials.GetSimulcastHysteresisFactor( + test_config.screenshare + ? VideoCodecMode::kScreensharing + : VideoCodecMode::kRealtimeVideo)); // Min padding bitrate may override padding target. expected_padding = std::max(expected_padding, test_config.min_padding_bitrate_bps); diff --git a/video/video_send_stream_tests.cc b/video/video_send_stream_tests.cc index 300c4ac34e..c26041e4ff 100644 --- a/video/video_send_stream_tests.cc +++ b/video/video_send_stream_tests.cc @@ -3847,7 +3847,7 @@ class ContentSwitchTest : public test::SendTest { auto internal_send_peer = test::VideoSendStreamPeer(send_stream_); float pacing_factor = internal_send_peer.GetPacingFactorOverride().value_or(0.0f); - float expected_pacing_factor = PacedSender::kDefaultPaceMultiplier; + float expected_pacing_factor = 1.1; // Strict pacing factor. if (send_stream_->GetStats().content_type == webrtc::VideoContentType::SCREENSHARE) { expected_pacing_factor = 1.0f; // Currently used pacing factor in ALR. diff --git a/video/video_stream_encoder.cc b/video/video_stream_encoder.cc index d261ae075f..df7e09bf3e 100644 --- a/video/video_stream_encoder.cc +++ b/video/video_stream_encoder.cc @@ -1161,6 +1161,15 @@ void VideoStreamEncoder::SetEncoderRates( bool rate_control_changed = (!last_encoder_rate_settings_.has_value() || last_encoder_rate_settings_->rate_control != rate_settings.rate_control); + // For layer allocation signal we care only about the target bitrate (not the + // adjusted one) and the target fps. + bool layer_allocation_changed = + !last_encoder_rate_settings_.has_value() || + last_encoder_rate_settings_->rate_control.target_bitrate != + rate_settings.rate_control.target_bitrate || + last_encoder_rate_settings_->rate_control.framerate_fps != + rate_settings.rate_control.framerate_fps; + if (last_encoder_rate_settings_ != rate_settings) { last_encoder_rate_settings_ = rate_settings; } @@ -1191,9 +1200,10 @@ void VideoStreamEncoder::SetEncoderRates( rate_settings.rate_control.bitrate, static_cast(rate_settings.rate_control.framerate_fps + 0.5)); stream_resource_manager_.SetEncoderRates(rate_settings.rate_control); - if (settings_.allocation_cb_type == - VideoStreamEncoderSettings::BitrateAllocationCallbackType:: - kVideoLayersAllocation) { + if (layer_allocation_changed && + settings_.allocation_cb_type == + VideoStreamEncoderSettings::BitrateAllocationCallbackType:: + kVideoLayersAllocation) { sink_->OnVideoLayersAllocationUpdated(CreateVideoLayersAllocation( send_codec_, rate_settings.rate_control, encoder_->GetEncoderInfo())); } diff --git a/video/video_stream_encoder_unittest.cc b/video/video_stream_encoder_unittest.cc index 0d34c01080..cb73fac842 100644 --- a/video/video_stream_encoder_unittest.cc +++ b/video/video_stream_encoder_unittest.cc @@ -844,7 +844,7 @@ class VideoStreamEncoderTest : public ::testing::Test { VideoEncoder::EncoderInfo GetEncoderInfo() const override { MutexLock lock(&local_mutex_); - EncoderInfo info; + EncoderInfo info = FakeEncoder::GetEncoderInfo(); if (initialized_ == EncoderState::kInitialized) { if (quality_scaling_) { info.scaling_settings = VideoEncoder::ScalingSettings( @@ -4017,10 +4017,8 @@ TEST_F(VideoStreamEncoderTest, ReportsVideoBitrateAllocation) { EXPECT_EQ(sink_.GetLastVideoBitrateAllocation(), expected_bitrate); EXPECT_EQ(sink_.number_of_bitrate_allocations(), 1); - VideoBitrateAllocation bitrate_allocation = - fake_encoder_.GetAndResetLastRateControlSettings()->bitrate; // Check that encoder has been updated too, not just allocation observer. - EXPECT_EQ(bitrate_allocation.get_sum_bps(), kLowTargetBitrateBps); + EXPECT_TRUE(fake_encoder_.GetAndResetLastRateControlSettings().has_value()); AdvanceTime(TimeDelta::Seconds(1) / kDefaultFps); // VideoBitrateAllocation not updated on second frame. @@ -4065,19 +4063,18 @@ TEST_F(VideoStreamEncoderTest, ReportsVideoLayersAllocationForV8Simulcast) { ASSERT_EQ(last_layer_allocation.active_spatial_layers.size(), 1u); VideoBitrateAllocation bitrate_allocation = - fake_encoder_.GetAndResetLastRateControlSettings()->bitrate; + fake_encoder_.GetAndResetLastRateControlSettings()->target_bitrate; // Check that encoder has been updated too, not just allocation observer. EXPECT_EQ(bitrate_allocation.get_sum_bps(), kLowTargetBitrateBps); AdvanceTime(TimeDelta::Seconds(1) / kDefaultFps); - // VideoLayersAllocation might be updated if frame rate change. + // VideoLayersAllocation might be updated if frame rate changes. int number_of_layers_allocation = 1; const int64_t start_time_ms = CurrentTimeMs(); while (CurrentTimeMs() - start_time_ms < 10 * kProcessIntervalMs) { video_source_.IncomingCapturedFrame( CreateFrame(CurrentTimeMs(), codec_width_, codec_height_)); WaitForEncodedFrame(CurrentTimeMs()); - AdvanceTime(TimeDelta::Millis(1) / kDefaultFps); if (number_of_layers_allocation != sink_.number_of_layers_allocations()) { number_of_layers_allocation = sink_.number_of_layers_allocations(); VideoLayersAllocation new_allocation = @@ -5592,10 +5589,20 @@ TEST_F(VideoStreamEncoderTest, DropsFramesWhenEncoderOvershoots) { // of video, verify number of drops. Rate needs to be slightly changed in // order to force the rate to be reconfigured. double overshoot_factor = 2.0; - if (RateControlSettings::ParseFromFieldTrials().UseEncoderBitrateAdjuster()) { + const RateControlSettings trials = + RateControlSettings::ParseFromFieldTrials(); + if (trials.UseEncoderBitrateAdjuster()) { // With bitrate adjuster, when need to overshoot even more to trigger - // frame dropping. - overshoot_factor *= 2; + // frame dropping since the adjuter will try to just lower the target + // bitrate rather than drop frames. If network headroom can be used, it + // doesn't push back as hard so we don't need quite as much overshoot. + // These numbers are unfortunately a bit magical but there's not trivial + // way to algebraically infer them. + if (trials.BitrateAdjusterCanUseNetworkHeadroom()) { + overshoot_factor = 2.4; + } else { + overshoot_factor = 4.0; + } } fake_encoder_.SimulateOvershoot(overshoot_factor); video_stream_encoder_->OnBitrateUpdatedAndWaitForManagedResources(