Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(324)

Unified Diff: webrtc/modules/video_coding/utility/quality_scaler.cc

Issue 2310853002: Refactor QualityScaler and MovingAverage (Closed)
Patch Set: fix build error Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webrtc/modules/video_coding/utility/quality_scaler.cc
diff --git a/webrtc/modules/video_coding/utility/quality_scaler.cc b/webrtc/modules/video_coding/utility/quality_scaler.cc
index c509e843642f2237e94fe1727749479a9523faa7..99bc6dad223bdaa58fcfcb56da6d451cf0ab0ad4 100644
--- a/webrtc/modules/video_coding/utility/quality_scaler.cc
+++ b/webrtc/modules/video_coding/utility/quality_scaler.cc
@@ -10,10 +10,12 @@
#include "webrtc/modules/video_coding/utility/quality_scaler.h"
+#include <algorithm>
+#include <cmath>
+
namespace webrtc {
namespace {
-static const int kMinFps = 5;
// Threshold constant used until first downscale (to permit fast rampup).
static const int kMeasureSecondsFastUpscale = 2;
static const int kMeasureSecondsUpscale = 5;
@@ -46,7 +48,11 @@ const int QualityScaler::kLowH264QpThreshold = 24;
const int QualityScaler::kBadH264QpThreshold = 37;
#endif
-QualityScaler::QualityScaler() : low_qp_threshold_(-1) {}
+// Default values. Should immediately get set to something more sensible.
+QualityScaler::QualityScaler()
+ : average_qp_(kMeasureSecondsUpscale * 30),
+ framedrop_percent_(kMeasureSecondsUpscale * 30),
+ low_qp_threshold_(-1) {}
void QualityScaler::Init(int low_qp_threshold,
int high_qp_threshold,
@@ -54,14 +60,15 @@ void QualityScaler::Init(int low_qp_threshold,
int width,
int height,
int fps) {
- ClearSamples();
low_qp_threshold_ = low_qp_threshold;
high_qp_threshold_ = high_qp_threshold;
downscale_shift_ = 0;
- // Use a faster window for upscaling initially (but be more graceful later).
- // This enables faster initial rampups without risking strong up-down
- // behavior later.
- measure_seconds_upscale_ = kMeasureSecondsFastUpscale;
+
+ fast_rampup_ = true;
+
+ ClearSamples();
+ ReportFramerate(fps);
+
const int init_width = width;
const int init_height = height;
if (initial_bitrate_kbps > 0) {
@@ -76,24 +83,28 @@ void QualityScaler::Init(int low_qp_threshold,
height /= 2;
}
}
-
- // Zero out width/height so they can be checked against inside
- // UpdateTargetResolution.
- res_.width = res_.height = 0;
UpdateTargetResolution(init_width, init_height);
ReportFramerate(fps);
}
// Report framerate(fps) to estimate # of samples.
void QualityScaler::ReportFramerate(int framerate) {
- framerate_ = framerate;
- UpdateSampleCounts();
+ // Use a faster window for upscaling initially.
+ // This enables faster initial rampups without risking strong up-down
+ // behavior later.
+ num_samples_upscale_ = framerate * (fast_rampup_ ? kMeasureSecondsFastUpscale
+ : kMeasureSecondsUpscale);
+ num_samples_downscale_ = framerate * kMeasureSecondsDownscale;
+
+ average_qp_ =
+ MovingAverage(std::max(num_samples_upscale_, num_samples_downscale_));
+ framedrop_percent_ =
+ MovingAverage(std::max(num_samples_upscale_, num_samples_downscale_));
}
void QualityScaler::ReportQP(int qp) {
framedrop_percent_.AddSample(0);
- average_qp_downscale_.AddSample(qp);
- average_qp_upscale_.AddSample(qp);
+ average_qp_.AddSample(qp);
}
void QualityScaler::ReportDroppedFrame() {
@@ -103,34 +114,58 @@ void QualityScaler::ReportDroppedFrame() {
void QualityScaler::OnEncodeFrame(int width, int height) {
// Should be set through InitEncode -> Should be set by now.
RTC_DCHECK_GE(low_qp_threshold_, 0);
- RTC_DCHECK_GT(num_samples_upscale_, 0u);
- RTC_DCHECK_GT(num_samples_downscale_, 0u);
-
- // Update scale factor.
- int avg_drop = 0;
- int avg_qp = 0;
-
- if ((framedrop_percent_.GetAverage(num_samples_downscale_, &avg_drop) &&
- avg_drop >= kFramedropPercentThreshold) ||
- (average_qp_downscale_.GetAverage(num_samples_downscale_, &avg_qp) &&
- avg_qp > high_qp_threshold_)) {
- AdjustScale(false);
- } else if (average_qp_upscale_.GetAverage(num_samples_upscale_, &avg_qp) &&
- avg_qp <= low_qp_threshold_) {
- AdjustScale(true);
+ if (target_res_.width != width || target_res_.height != height) {
+ UpdateTargetResolution(width, height);
+ }
+
+ // Check if we should scale down due to high frame drop.
+ const auto drop_rate = framedrop_percent_.GetAverage(num_samples_downscale_);
+ if (drop_rate && *drop_rate >= kFramedropPercentThreshold) {
+ ScaleDown();
+ return;
+ }
+
+ // Check if we should scale up or down based on QP.
+ const auto avg_qp_down = average_qp_.GetAverage(num_samples_downscale_);
+ if (avg_qp_down && *avg_qp_down > high_qp_threshold_) {
+ ScaleDown();
+ return;
+ }
+ const auto avg_qp_up = average_qp_.GetAverage(num_samples_upscale_);
+ if (avg_qp_up && *avg_qp_up <= low_qp_threshold_) {
+ // QP has been low. We want to try a higher resolution.
+ ScaleUp();
+ return;
+ }
+}
+
+void QualityScaler::ScaleUp() {
+ downscale_shift_ = std::max(0, downscale_shift_ - 1);
+ ClearSamples();
+}
+
+void QualityScaler::ScaleDown() {
+ downscale_shift_ = std::min(maximum_shift_, downscale_shift_ + 1);
+ ClearSamples();
+ // If we've scaled down, wait longer before scaling up again.
+ if (fast_rampup_) {
+ fast_rampup_ = false;
+ num_samples_upscale_ = (num_samples_upscale_ / kMeasureSecondsFastUpscale) *
+ kMeasureSecondsUpscale;
}
- UpdateTargetResolution(width, height);
}
QualityScaler::Resolution QualityScaler::GetScaledResolution() const {
- return res_;
+ const int frame_width = target_res_.width >> downscale_shift_;
+ const int frame_height = target_res_.height >> downscale_shift_;
+ return Resolution{frame_width, frame_height};
}
rtc::scoped_refptr<VideoFrameBuffer> QualityScaler::GetScaledBuffer(
const rtc::scoped_refptr<VideoFrameBuffer>& frame) {
Resolution res = GetScaledResolution();
- int src_width = frame->width();
- int src_height = frame->height();
+ const int src_width = frame->width();
+ const int src_height = frame->height();
if (res.width == src_width && res.height == src_height)
return frame;
@@ -142,50 +177,20 @@ rtc::scoped_refptr<VideoFrameBuffer> QualityScaler::GetScaledBuffer(
return scaled_buffer;
}
-void QualityScaler::UpdateTargetResolution(int frame_width, int frame_height) {
- RTC_DCHECK_GE(downscale_shift_, 0);
- int shifts_performed = 0;
- for (int shift = downscale_shift_;
- shift > 0 && (frame_width / 2 >= kMinDownscaleDimension) &&
- (frame_height / 2 >= kMinDownscaleDimension);
- --shift, ++shifts_performed) {
- frame_width /= 2;
- frame_height /= 2;
- }
- // Clamp to number of shifts actually performed to not be stuck trying to
- // scale way beyond QVGA.
- downscale_shift_ = shifts_performed;
- if (res_.width == frame_width && res_.height == frame_height) {
- // No reset done/needed, using same resolution.
- return;
+void QualityScaler::UpdateTargetResolution(int width, int height) {
+ if (width < kMinDownscaleDimension || height < kMinDownscaleDimension) {
+ maximum_shift_ = 0;
+ } else {
+ maximum_shift_ = static_cast<int>(
+ std::log2(std::min(width, height) / kMinDownscaleDimension));
}
- res_.width = frame_width;
- res_.height = frame_height;
- ClearSamples();
+ target_res_ = Resolution{width, height};
}
void QualityScaler::ClearSamples() {
framedrop_percent_.Reset();
- average_qp_downscale_.Reset();
- average_qp_upscale_.Reset();
+ average_qp_.Reset();
}
-void QualityScaler::UpdateSampleCounts() {
- num_samples_downscale_ = static_cast<size_t>(
- kMeasureSecondsDownscale * (framerate_ < kMinFps ? kMinFps : framerate_));
- num_samples_upscale_ = static_cast<size_t>(
- measure_seconds_upscale_ * (framerate_ < kMinFps ? kMinFps : framerate_));
-}
-
-void QualityScaler::AdjustScale(bool up) {
- downscale_shift_ += up ? -1 : 1;
- if (downscale_shift_ < 0)
- downscale_shift_ = 0;
- if (!up) {
- // First downscale hit, start using a slower threshold for going up.
- measure_seconds_upscale_ = kMeasureSecondsUpscale;
- UpdateSampleCounts();
- }
-}
} // namespace webrtc
« no previous file with comments | « webrtc/modules/video_coding/utility/quality_scaler.h ('k') | webrtc/modules/video_coding/utility/quality_scaler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698