Add default downscale threshold to QualityScaler.
Prevents downscaling below 160x90 or 90x160 to gain more quality. BUG=4625 R=mflodman@webrtc.org Review URL: https://codereview.webrtc.org/1160403004. Cr-Commit-Position: refs/heads/master@{#9480}
This commit is contained in:
parent
2ee2439a1f
commit
6a688f5265
@ -583,7 +583,7 @@ int VP8EncoderImpl::InitEncode(const VideoCodec* inst,
|
||||
}
|
||||
|
||||
rps_.Init();
|
||||
quality_scaler_.Init(codec_.qpMax / kDefaultLowQpDenominator);
|
||||
quality_scaler_.Init(codec_.qpMax / QualityScaler::kDefaultLowQpDenominator);
|
||||
quality_scaler_.ReportFramerate(codec_.maxFramerate);
|
||||
|
||||
return InitAndSetControlSettings();
|
||||
|
@ -15,9 +15,10 @@
|
||||
#include "webrtc/modules/video_coding/utility/include/moving_average.h"
|
||||
|
||||
namespace webrtc {
|
||||
const int kDefaultLowQpDenominator = 3;
|
||||
class QualityScaler {
|
||||
public:
|
||||
static const int kDefaultLowQpDenominator;
|
||||
static const int kDefaultMinDownscaleDimension;
|
||||
struct Resolution {
|
||||
int width;
|
||||
int height;
|
||||
|
@ -15,9 +15,17 @@ static const int kMinFps = 10;
|
||||
static const int kMeasureSeconds = 5;
|
||||
static const int kFramedropPercentThreshold = 60;
|
||||
|
||||
const int QualityScaler::kDefaultLowQpDenominator = 3;
|
||||
// Note that this is the same for width and height to permit 120x90 in both
|
||||
// portrait and landscape mode.
|
||||
const int QualityScaler::kDefaultMinDownscaleDimension = 90;
|
||||
|
||||
QualityScaler::QualityScaler()
|
||||
: num_samples_(0), low_qp_threshold_(-1), downscale_shift_(0),
|
||||
min_width_(0), min_height_(0) {
|
||||
: num_samples_(0),
|
||||
low_qp_threshold_(-1),
|
||||
downscale_shift_(0),
|
||||
min_width_(kDefaultMinDownscaleDimension),
|
||||
min_height_(kDefaultMinDownscaleDimension) {
|
||||
}
|
||||
|
||||
void QualityScaler::Init(int low_qp_threshold) {
|
||||
@ -68,18 +76,13 @@ QualityScaler::Resolution QualityScaler::GetScaledResolution(
|
||||
|
||||
assert(downscale_shift_ >= 0);
|
||||
for (int shift = downscale_shift_;
|
||||
shift > 0 && res.width > 1 && res.height > 1;
|
||||
shift > 0 && (res.width >> 1 >= min_width_) &&
|
||||
(res.height >> 1 >= min_height_);
|
||||
--shift) {
|
||||
res.width >>= 1;
|
||||
res.height >>= 1;
|
||||
}
|
||||
|
||||
// Set this limitation for VP8 HW encoder to avoid crash.
|
||||
if (min_width_ > 0 && res.width * res.height < min_width_ * min_height_) {
|
||||
res.width = min_width_;
|
||||
res.height = min_height_;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -31,11 +31,11 @@ class QualityScalerTest : public ::testing::Test {
|
||||
QualityScalerTest() {
|
||||
input_frame_.CreateEmptyFrame(
|
||||
kWidth, kHeight, kWidth, kHalfWidth, kHalfWidth);
|
||||
qs_.Init(kMaxQp / kDefaultLowQpDenominator);
|
||||
qs_.Init(kMaxQp / QualityScaler::kDefaultLowQpDenominator);
|
||||
qs_.ReportFramerate(kFramerate);
|
||||
}
|
||||
|
||||
void TriggerScale(ScaleDirection scale_direction) {
|
||||
bool TriggerScale(ScaleDirection scale_direction) {
|
||||
int initial_width = qs_.GetScaledResolution(input_frame_).width;
|
||||
for (int i = 0; i < kFramerate * kNumSeconds; ++i) {
|
||||
switch (scale_direction) {
|
||||
@ -48,10 +48,10 @@ class QualityScalerTest : public ::testing::Test {
|
||||
}
|
||||
|
||||
if (qs_.GetScaledResolution(input_frame_).width != initial_width)
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
FAIL() << "No downscale within " << kNumSeconds << " seconds.";
|
||||
return false;
|
||||
}
|
||||
|
||||
void ExpectOriginalFrame() {
|
||||
@ -70,6 +70,11 @@ class QualityScalerTest : public ::testing::Test {
|
||||
|
||||
void DoesNotDownscaleFrameDimensions(int width, int height);
|
||||
|
||||
void DownscaleEndsAt(int input_width,
|
||||
int input_height,
|
||||
int end_width,
|
||||
int end_height);
|
||||
|
||||
QualityScaler qs_;
|
||||
VideoFrame input_frame_;
|
||||
};
|
||||
@ -85,7 +90,8 @@ TEST_F(QualityScalerTest, ReportsOriginalResolutionInitially) {
|
||||
}
|
||||
|
||||
TEST_F(QualityScalerTest, DownscalesAfterContinuousFramedrop) {
|
||||
TriggerScale(kScaleDown);
|
||||
EXPECT_TRUE(TriggerScale(kScaleDown)) << "No downscale within " << kNumSeconds
|
||||
<< " seconds.";
|
||||
QualityScaler::Resolution res = qs_.GetScaledResolution(input_frame_);
|
||||
EXPECT_LT(res.width, input_frame_.width());
|
||||
EXPECT_LT(res.height, input_frame_.height());
|
||||
@ -130,8 +136,9 @@ void QualityScalerTest::ContinuouslyDownscalesByHalfDimensionsAndBackUp() {
|
||||
int min_dimension = initial_min_dimension;
|
||||
int current_shift = 0;
|
||||
// Drop all frames to force-trigger downscaling.
|
||||
while (min_dimension > 16) {
|
||||
TriggerScale(kScaleDown);
|
||||
while (min_dimension >= 2 * QualityScaler::kDefaultMinDownscaleDimension) {
|
||||
EXPECT_TRUE(TriggerScale(kScaleDown)) << "No downscale within "
|
||||
<< kNumSeconds << " seconds.";
|
||||
QualityScaler::Resolution res = qs_.GetScaledResolution(input_frame_);
|
||||
min_dimension = res.width < res.height ? res.width : res.height;
|
||||
++current_shift;
|
||||
@ -142,7 +149,8 @@ void QualityScalerTest::ContinuouslyDownscalesByHalfDimensionsAndBackUp() {
|
||||
|
||||
// Make sure we can scale back with good-quality frames.
|
||||
while (min_dimension < initial_min_dimension) {
|
||||
TriggerScale(kScaleUp);
|
||||
EXPECT_TRUE(TriggerScale(kScaleUp)) << "No upscale within " << kNumSeconds
|
||||
<< " seconds.";
|
||||
QualityScaler::Resolution res = qs_.GetScaledResolution(input_frame_);
|
||||
min_dimension = res.width < res.height ? res.width : res.height;
|
||||
--current_shift;
|
||||
@ -195,4 +203,72 @@ TEST_F(QualityScalerTest, DoesNotDownscaleFrom1Px) {
|
||||
DoesNotDownscaleFrameDimensions(1, 1);
|
||||
}
|
||||
|
||||
TEST_F(QualityScalerTest, DoesNotDownscaleBelow2xDefaultMinDimensionsWidth) {
|
||||
DoesNotDownscaleFrameDimensions(
|
||||
2 * QualityScaler::kDefaultMinDownscaleDimension - 1, 1000);
|
||||
}
|
||||
|
||||
TEST_F(QualityScalerTest, DoesNotDownscaleBelow2xDefaultMinDimensionsHeight) {
|
||||
DoesNotDownscaleFrameDimensions(
|
||||
1000, 2 * QualityScaler::kDefaultMinDownscaleDimension - 1);
|
||||
}
|
||||
|
||||
void QualityScalerTest::DownscaleEndsAt(int input_width,
|
||||
int input_height,
|
||||
int end_width,
|
||||
int end_height) {
|
||||
// Create a frame with 2x expected end width/height to verify that we can
|
||||
// scale down to expected end width/height.
|
||||
input_frame_.CreateEmptyFrame(input_width, input_height, input_width,
|
||||
(input_width + 1) / 2, (input_width + 1) / 2);
|
||||
|
||||
int last_width = input_width;
|
||||
int last_height = input_height;
|
||||
// Drop all frames to force-trigger downscaling.
|
||||
while (true) {
|
||||
TriggerScale(kScaleDown);
|
||||
QualityScaler::Resolution res = qs_.GetScaledResolution(input_frame_);
|
||||
if (last_width == res.width) {
|
||||
EXPECT_EQ(last_height, res.height);
|
||||
EXPECT_EQ(end_width, res.width);
|
||||
EXPECT_EQ(end_height, res.height);
|
||||
break;
|
||||
}
|
||||
last_width = res.width;
|
||||
last_height = res.height;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(QualityScalerTest, DefaultDownscalesTo160x90) {
|
||||
DownscaleEndsAt(320, 180, 160, 90);
|
||||
}
|
||||
|
||||
TEST_F(QualityScalerTest, DefaultDownscalesTo90x160) {
|
||||
DownscaleEndsAt(180, 320, 90, 160);
|
||||
}
|
||||
|
||||
TEST_F(QualityScalerTest, DefaultDownscalesFrom1280x720To160x90) {
|
||||
DownscaleEndsAt(1280, 720, 160, 90);
|
||||
}
|
||||
|
||||
TEST_F(QualityScalerTest, DefaultDoesntDownscaleBelow160x90) {
|
||||
DownscaleEndsAt(320 - 1, 180 - 1, 320 - 1, 180 - 1);
|
||||
}
|
||||
|
||||
TEST_F(QualityScalerTest, DefaultDoesntDownscaleBelow90x160) {
|
||||
DownscaleEndsAt(180 - 1, 320 - 1, 180 - 1, 320 - 1);
|
||||
}
|
||||
|
||||
TEST_F(QualityScalerTest, RespectsMinResolutionWidth) {
|
||||
// Should end at 200x100, as width can't go lower.
|
||||
qs_.SetMinResolution(200, 10);
|
||||
DownscaleEndsAt(1600, 800, 200, 100);
|
||||
}
|
||||
|
||||
TEST_F(QualityScalerTest, RespectsMinResolutionHeight) {
|
||||
// Should end at 100x200, as height can't go lower.
|
||||
qs_.SetMinResolution(10, 200);
|
||||
DownscaleEndsAt(800, 1600, 100, 200);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
Loading…
Reference in New Issue
Block a user