webrtc_m130/modules/video_coding/utility/bandwidth_quality_scaler_unittest.cc
Shuhai Peng f270770679 video: Implement bandwidth based scaler
The |slice_qp_detla| reported by the hardware is not credible, which
causing the quality scaler cannot work properly,the resolution cannot
be adjusted correctly.

To fix this issue, this CL implements a bandwidth scaler which is used
for adjust resolution, this scaler will be used when QP based quality
scaler is not working due to untrusted QP reported by HW AVC encoder.

Bug: webrtc:12942
Change-Id: I2fc5f07a5400ec7e5ead2c2c502faee84d7f2a76
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/228860
Reviewed-by: Erik Språng <sprang@webrtc.org>
Reviewed-by: Evan Shrubsole <eshr@google.com>
Commit-Queue: Erik Språng <sprang@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#35120}
2021-09-29 10:39:27 +00:00

280 lines
10 KiB
C++

/*
* Copyright 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 "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<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);
},
RTC_FROM_HERE);
}
~BandwidthQualityScalerTest() {
task_queue_.SendTask([this] { bandwidth_quality_scaler_ = nullptr; },
RTC_FROM_HERE);
}
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 * 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<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_ += 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);
}
}
},
RTC_FROM_HERE);
}
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(
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(
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(
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(
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(
bandwidth_quality_scaler_->GetBitrateStateUpdateIntervalMs()));
EXPECT_EQ(0, handler_->adapt_down_event_count_);
EXPECT_EQ(1, handler_->adapt_up_event_count_);
}
} // namespace webrtc