blob: d28052e28defbfd2d4f14c7e3107d4e62b203bc7 [file] [log] [blame]
/*
* 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 <memory>
#include <string>
#include "api/units/time_delta.h"
#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 TimeDelta kDefaultBitrateStateUpdateInterval = TimeDelta::Seconds(5);
constexpr TimeDelta kDefaultEncodeTime = TimeDelta::Seconds(1) / kFramerateFps;
} // 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<std::string> {
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<FakeBandwidthQualityScalerHandler>()) {
task_queue_.SendTask(
[this] {
bandwidth_quality_scaler_ =
std::unique_ptr<BandwidthQualityScalerUnderTest>(
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<VideoEncoder::ResolutionBitrateLimits>
GetDefaultSuitableBitrateLimit(int frame_size_pixels) {
return EncoderInfoSettings::
GetSinglecastBitrateLimitForResolutionWhenQpIsUntrusted(
frame_size_pixels,
EncoderInfoSettings::
GetDefaultSinglecastBitrateLimitsWhenQpIsUntrusted());
}
void TriggerBandwidthQualityScalerTest(
const std::vector<FrameConfig>& 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 * kDefaultBitrateStateUpdateInterval.seconds(),
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<VideoEncoder::ResolutionBitrateLimits>
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_ += kDefaultEncodeTime.ms();
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<BandwidthQualityScalerUnderTest> bandwidth_quality_scaler_;
std::unique_ptr<FakeBandwidthQualityScalerHandler> 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<FrameConfig> 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(TimeDelta::Millis(
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<FrameConfig> 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(TimeDelta::Millis(
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<FrameConfig> 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(TimeDelta::Millis(
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<FrameConfig> 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(TimeDelta::Millis(
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<FrameConfig> 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(TimeDelta::Millis(
bandwidth_quality_scaler_->GetBitrateStateUpdateIntervalMs())));
EXPECT_EQ(0, handler_->adapt_down_event_count_);
EXPECT_EQ(1, handler_->adapt_up_event_count_);
}
} // namespace webrtc