blob: 327748d224c59cb303fc1fbf2dec833c3814add3 [file] [log] [blame]
pbos@webrtc.orga0d78272014-09-12 11:51:47 +00001/*
2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/modules/video_coding/utility/quality_scaler.h"
12
13namespace webrtc {
14
15static const int kMinFps = 10;
16static const int kMeasureSeconds = 5;
17static const int kFramedropPercentThreshold = 60;
18static const int kLowQpThresholdDenominator = 3;
19
20QualityScaler::QualityScaler()
21 : num_samples_(0), low_qp_threshold_(-1), downscale_shift_(0) {
22}
23
24void QualityScaler::Init(int max_qp) {
25 ClearSamples();
26 downscale_shift_ = 0;
27 low_qp_threshold_ = max_qp / kLowQpThresholdDenominator ;
28}
29
30void QualityScaler::ReportFramerate(int framerate) {
31 num_samples_ = static_cast<size_t>(
32 kMeasureSeconds * (framerate < kMinFps ? kMinFps : framerate));
33}
34
35void QualityScaler::ReportEncodedFrame(int qp) {
36 average_qp_.AddSample(qp);
37 framedrop_percent_.AddSample(0);
38}
39
40void QualityScaler::ReportDroppedFrame() {
41 framedrop_percent_.AddSample(100);
42}
43
44QualityScaler::Resolution QualityScaler::GetScaledResolution(
45 const I420VideoFrame& frame) {
46 // Both of these should be set through InitEncode -> Should be set by now.
47 assert(low_qp_threshold_ >= 0);
48 assert(num_samples_ > 0);
49 // Update scale factor.
50 int avg;
51 if (framedrop_percent_.GetAverage(num_samples_, &avg) &&
52 avg >= kFramedropPercentThreshold) {
53 AdjustScale(false);
54 } else if (average_qp_.GetAverage(num_samples_, &avg) &&
55 avg <= low_qp_threshold_) {
56 AdjustScale(true);
57 }
58
59 Resolution res;
60 res.width = frame.width();
61 res.height = frame.height();
62
63 assert(downscale_shift_ >= 0);
64 for (int shift = downscale_shift_;
65 shift > 0 && res.width > 1 && res.height > 1;
66 --shift) {
67 res.width >>= 1;
68 res.height >>= 1;
69 }
70
71 return res;
72}
73
74const I420VideoFrame& QualityScaler::GetScaledFrame(
75 const I420VideoFrame& frame) {
76 Resolution res = GetScaledResolution(frame);
77 if (res.width == frame.width())
78 return frame;
79
80 scaler_.Set(frame.width(),
81 frame.height(),
82 res.width,
83 res.height,
84 kI420,
85 kI420,
86 kScaleBox);
87 if (scaler_.Scale(frame, &scaled_frame_) != 0)
88 return frame;
89
90 scaled_frame_.set_ntp_time_ms(frame.ntp_time_ms());
91 scaled_frame_.set_timestamp(frame.timestamp());
92 scaled_frame_.set_render_time_ms(frame.render_time_ms());
93
94 return scaled_frame_;
95}
96
97QualityScaler::MovingAverage::MovingAverage() : sum_(0) {
98}
99
100void QualityScaler::MovingAverage::AddSample(int sample) {
101 samples_.push_back(sample);
102 sum_ += sample;
103}
104
105bool QualityScaler::MovingAverage::GetAverage(size_t num_samples, int* avg) {
106 assert(num_samples > 0);
107 if (num_samples > samples_.size())
108 return false;
109
110 // Remove old samples.
111 while (num_samples < samples_.size()) {
112 sum_ -= samples_.front();
113 samples_.pop_front();
114 }
115
116 *avg = sum_ / static_cast<int>(num_samples);
117 return true;
118}
119
120void QualityScaler::MovingAverage::Reset() {
121 sum_ = 0;
122 samples_.clear();
123}
124
125void QualityScaler::ClearSamples() {
126 average_qp_.Reset();
127 framedrop_percent_.Reset();
128}
129
130void QualityScaler::AdjustScale(bool up) {
131 downscale_shift_ += up ? -1 : 1;
132 if (downscale_shift_ < 0)
133 downscale_shift_ = 0;
134 ClearSamples();
135}
136
137} // namespace webrtc