/* * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/video_coding/utility/bandwidth_quality_scaler.h" #include #include #include "rtc_base/checks.h" #include "rtc_base/event.h" #include "rtc_base/experiments/encoder_info_settings.h" #include "rtc_base/task_queue_for_test.h" #include "rtc_base/time_utils.h" #include "test/field_trial.h" #include "test/gtest.h" namespace webrtc { namespace { constexpr int kFramerateFps = 30; constexpr int kDefaultBitrateStateUpdateIntervalSeconds = 5; constexpr int kDefaultEncodeDeltaTimeMs = 33; // 1/30(s) => 33(ms) } // namespace class FakeBandwidthQualityScalerHandler : public BandwidthQualityScalerUsageHandlerInterface { public: ~FakeBandwidthQualityScalerHandler() override = default; void OnReportUsageBandwidthHigh() override { adapt_down_event_count_++; event_.Set(); } void OnReportUsageBandwidthLow() override { adapt_up_event_count_++; event_.Set(); } rtc::Event event_; int adapt_up_event_count_ = 0; int adapt_down_event_count_ = 0; }; class BandwidthQualityScalerUnderTest : public BandwidthQualityScaler { public: explicit BandwidthQualityScalerUnderTest( BandwidthQualityScalerUsageHandlerInterface* handler) : BandwidthQualityScaler(handler) {} int GetBitrateStateUpdateIntervalMs() { return this->kBitrateStateUpdateInterval.ms() + 200; } }; class BandwidthQualityScalerTest : public ::testing::Test, public ::testing::WithParamInterface { protected: enum ScaleDirection { kKeepScaleNormalBandwidth, kKeepScaleAboveMaxBandwidth, kKeepScaleUnderMinBandwidth, }; enum FrameType { kKeyFrame, kNormalFrame, kNormalFrame_Overuse, kNormalFrame_Underuse, }; struct FrameConfig { FrameConfig(int frame_num, FrameType frame_type, int actual_width, int actual_height) : frame_num(frame_num), frame_type(frame_type), actual_width(actual_width), actual_height(actual_height) {} int frame_num; FrameType frame_type; int actual_width; int actual_height; }; BandwidthQualityScalerTest() : scoped_field_trial_(GetParam()), task_queue_("BandwidthQualityScalerTestQueue"), handler_(std::make_unique()) { task_queue_.SendTask( [this] { bandwidth_quality_scaler_ = std::unique_ptr( new BandwidthQualityScalerUnderTest(handler_.get())); bandwidth_quality_scaler_->SetResolutionBitrateLimits( EncoderInfoSettings:: GetDefaultSinglecastBitrateLimitsWhenQpIsUntrusted()); // Only for testing. Set first_timestamp_ in RateStatistics to 0. bandwidth_quality_scaler_->ReportEncodeInfo(0, 0, 0, 0); }); } ~BandwidthQualityScalerTest() { task_queue_.SendTask([this] { bandwidth_quality_scaler_ = nullptr; }); } int GetFrameSizeBytes( const FrameConfig& config, const VideoEncoder::ResolutionBitrateLimits& bitrate_limits) { int scale = 8 * kFramerateFps; switch (config.frame_type) { case FrameType::kKeyFrame: { // 4 is experimental value. Based on the test, the number of bytes of // the key frame is about four times of the normal frame return bitrate_limits.max_bitrate_bps * 4 / scale; } case FrameType::kNormalFrame_Overuse: { return bitrate_limits.max_bitrate_bps * 3 / 2 / scale; } case FrameType::kNormalFrame_Underuse: { return bitrate_limits.min_start_bitrate_bps * 3 / 4 / scale; } case FrameType::kNormalFrame: { return (bitrate_limits.max_bitrate_bps + bitrate_limits.min_start_bitrate_bps) / 2 / scale; } } return -1; } absl::optional GetDefaultSuitableBitrateLimit(int frame_size_pixels) { return EncoderInfoSettings:: GetSinglecastBitrateLimitForResolutionWhenQpIsUntrusted( frame_size_pixels, EncoderInfoSettings:: GetDefaultSinglecastBitrateLimitsWhenQpIsUntrusted()); } void TriggerBandwidthQualityScalerTest( const std::vector& frame_configs) { task_queue_.SendTask( [frame_configs, this] { RTC_CHECK(!frame_configs.empty()); int total_frame_nums = 0; for (const FrameConfig& frame_config : frame_configs) { total_frame_nums += frame_config.frame_num; } EXPECT_EQ(kFramerateFps * kDefaultBitrateStateUpdateIntervalSeconds, total_frame_nums); uint32_t time_send_to_scaler_ms_ = rtc::TimeMillis(); for (size_t i = 0; i < frame_configs.size(); ++i) { const FrameConfig& config = frame_configs[i]; absl::optional suitable_bitrate = GetDefaultSuitableBitrateLimit( config.actual_width * config.actual_height); EXPECT_TRUE(suitable_bitrate); for (int j = 0; j <= config.frame_num; ++j) { time_send_to_scaler_ms_ += kDefaultEncodeDeltaTimeMs; int frame_size_bytes = GetFrameSizeBytes(config, suitable_bitrate.value()); RTC_CHECK(frame_size_bytes > 0); bandwidth_quality_scaler_->ReportEncodeInfo( frame_size_bytes, time_send_to_scaler_ms_, config.actual_width, config.actual_height); } } }); } test::ScopedFieldTrials scoped_field_trial_; TaskQueueForTest task_queue_; std::unique_ptr bandwidth_quality_scaler_; std::unique_ptr handler_; }; INSTANTIATE_TEST_SUITE_P( FieldTrials, BandwidthQualityScalerTest, ::testing::Values("WebRTC-Video-BandwidthQualityScalerSettings/" "bitrate_state_update_interval_s_:1/", "WebRTC-Video-BandwidthQualityScalerSettings/" "bitrate_state_update_interval_s_:2/")); TEST_P(BandwidthQualityScalerTest, AllNormalFrame_640x360) { const std::vector frame_configs{ FrameConfig(150, FrameType::kNormalFrame, 640, 360)}; TriggerBandwidthQualityScalerTest(frame_configs); // When resolution is 640*360, experimental working bitrate range is // [500000,800000] bps. Encoded bitrate is 654253, so it falls in the range // without any operation(up/down). EXPECT_FALSE(handler_->event_.Wait( bandwidth_quality_scaler_->GetBitrateStateUpdateIntervalMs())); EXPECT_EQ(0, handler_->adapt_down_event_count_); EXPECT_EQ(0, handler_->adapt_up_event_count_); } TEST_P(BandwidthQualityScalerTest, AllNoramlFrame_AboveMaxBandwidth_640x360) { const std::vector frame_configs{ FrameConfig(150, FrameType::kNormalFrame_Overuse, 640, 360)}; TriggerBandwidthQualityScalerTest(frame_configs); // When resolution is 640*360, experimental working bitrate range is // [500000,800000] bps. Encoded bitrate is 1208000 > 800000 * 0.95, so it // triggers adapt_up_event_count_. EXPECT_TRUE(handler_->event_.Wait( bandwidth_quality_scaler_->GetBitrateStateUpdateIntervalMs())); EXPECT_EQ(0, handler_->adapt_down_event_count_); EXPECT_EQ(1, handler_->adapt_up_event_count_); } TEST_P(BandwidthQualityScalerTest, AllNormalFrame_Underuse_640x360) { const std::vector frame_configs{ FrameConfig(150, FrameType::kNormalFrame_Underuse, 640, 360)}; TriggerBandwidthQualityScalerTest(frame_configs); // When resolution is 640*360, experimental working bitrate range is // [500000,800000] bps. Encoded bitrate is 377379 < 500000 * 0.8, so it // triggers adapt_down_event_count_. EXPECT_TRUE(handler_->event_.Wait( bandwidth_quality_scaler_->GetBitrateStateUpdateIntervalMs())); EXPECT_EQ(1, handler_->adapt_down_event_count_); EXPECT_EQ(0, handler_->adapt_up_event_count_); } TEST_P(BandwidthQualityScalerTest, FixedFrameTypeTest1_640x360) { const std::vector frame_configs{ FrameConfig(5, FrameType::kNormalFrame_Underuse, 640, 360), FrameConfig(110, FrameType::kNormalFrame, 640, 360), FrameConfig(20, FrameType::kNormalFrame_Overuse, 640, 360), FrameConfig(15, FrameType::kKeyFrame, 640, 360), }; TriggerBandwidthQualityScalerTest(frame_configs); // When resolution is 640*360, experimental working bitrate range is // [500000,800000] bps. Encoded bitrate is 1059462 > 800000 * 0.95, so it // triggers adapt_up_event_count_. EXPECT_TRUE(handler_->event_.Wait( bandwidth_quality_scaler_->GetBitrateStateUpdateIntervalMs())); EXPECT_EQ(0, handler_->adapt_down_event_count_); EXPECT_EQ(1, handler_->adapt_up_event_count_); } TEST_P(BandwidthQualityScalerTest, FixedFrameTypeTest2_640x360) { const std::vector frame_configs{ FrameConfig(10, FrameType::kNormalFrame_Underuse, 640, 360), FrameConfig(50, FrameType::kNormalFrame, 640, 360), FrameConfig(5, FrameType::kKeyFrame, 640, 360), FrameConfig(85, FrameType::kNormalFrame_Overuse, 640, 360), }; TriggerBandwidthQualityScalerTest(frame_configs); // When resolution is 640*360, experimental working bitrate range is // [500000,800000] bps. Encoded bitrate is 1059462 > 800000 * 0.95, so it // triggers adapt_up_event_count_. EXPECT_TRUE(handler_->event_.Wait( bandwidth_quality_scaler_->GetBitrateStateUpdateIntervalMs())); EXPECT_EQ(0, handler_->adapt_down_event_count_); EXPECT_EQ(1, handler_->adapt_up_event_count_); } } // namespace webrtc