OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 #include "webrtc/modules/video_coding/utility/quality_scaler.h" | 10 #include "webrtc/modules/video_coding/utility/quality_scaler.h" |
(...skipping 12 matching lines...) Expand all Loading... |
23 static const int kMinDownscaleDimension = 140; | 23 static const int kMinDownscaleDimension = 140; |
24 // Initial resolutions corresponding to a bitrate. Aa bit above their actual | 24 // Initial resolutions corresponding to a bitrate. Aa bit above their actual |
25 // values to permit near-VGA and near-QVGA resolutions to use the same | 25 // values to permit near-VGA and near-QVGA resolutions to use the same |
26 // mechanism. | 26 // mechanism. |
27 static const int kVgaBitrateThresholdKbps = 500; | 27 static const int kVgaBitrateThresholdKbps = 500; |
28 static const int kVgaNumPixels = 700 * 500; // 640x480 | 28 static const int kVgaNumPixels = 700 * 500; // 640x480 |
29 static const int kQvgaBitrateThresholdKbps = 250; | 29 static const int kQvgaBitrateThresholdKbps = 250; |
30 static const int kQvgaNumPixels = 400 * 300; // 320x240 | 30 static const int kQvgaNumPixels = 400 * 300; // 320x240 |
31 } // namespace | 31 } // namespace |
32 | 32 |
33 QualityScaler::QualityScaler() | 33 QualityScaler::QualityScaler() : low_qp_threshold_(-1) {} |
34 : low_qp_threshold_(-1), framerate_down_(false) {} | |
35 | 34 |
36 void QualityScaler::Init(int low_qp_threshold, | 35 void QualityScaler::Init(int low_qp_threshold, |
37 int high_qp_threshold, | 36 int high_qp_threshold, |
38 bool use_framerate_reduction, | |
39 int initial_bitrate_kbps, | 37 int initial_bitrate_kbps, |
40 int width, | 38 int width, |
41 int height, | 39 int height, |
42 int fps) { | 40 int fps) { |
43 ClearSamples(); | 41 ClearSamples(); |
44 low_qp_threshold_ = low_qp_threshold; | 42 low_qp_threshold_ = low_qp_threshold; |
45 high_qp_threshold_ = high_qp_threshold; | 43 high_qp_threshold_ = high_qp_threshold; |
46 use_framerate_reduction_ = use_framerate_reduction; | |
47 downscale_shift_ = 0; | 44 downscale_shift_ = 0; |
48 // Use a faster window for upscaling initially (but be more graceful later). | 45 // Use a faster window for upscaling initially (but be more graceful later). |
49 // This enables faster initial rampups without risking strong up-down | 46 // This enables faster initial rampups without risking strong up-down |
50 // behavior later. | 47 // behavior later. |
51 measure_seconds_upscale_ = kMeasureSecondsFastUpscale; | 48 measure_seconds_upscale_ = kMeasureSecondsFastUpscale; |
52 const int init_width = width; | 49 const int init_width = width; |
53 const int init_height = height; | 50 const int init_height = height; |
54 if (initial_bitrate_kbps > 0) { | 51 if (initial_bitrate_kbps > 0) { |
55 int init_num_pixels = width * height; | 52 int init_num_pixels = width * height; |
56 if (initial_bitrate_kbps < kVgaBitrateThresholdKbps) | 53 if (initial_bitrate_kbps < kVgaBitrateThresholdKbps) |
57 init_num_pixels = kVgaNumPixels; | 54 init_num_pixels = kVgaNumPixels; |
58 if (initial_bitrate_kbps < kQvgaBitrateThresholdKbps) | 55 if (initial_bitrate_kbps < kQvgaBitrateThresholdKbps) |
59 init_num_pixels = kQvgaNumPixels; | 56 init_num_pixels = kQvgaNumPixels; |
60 while (width * height > init_num_pixels) { | 57 while (width * height > init_num_pixels) { |
61 ++downscale_shift_; | 58 ++downscale_shift_; |
62 width /= 2; | 59 width /= 2; |
63 height /= 2; | 60 height /= 2; |
64 } | 61 } |
65 } | 62 } |
66 UpdateTargetResolution(init_width, init_height); | 63 UpdateTargetResolution(init_width, init_height); |
67 ReportFramerate(fps); | 64 ReportFramerate(fps); |
68 target_framerate_ = -1; | |
69 } | 65 } |
70 | 66 |
71 // Report framerate(fps) to estimate # of samples. | 67 // Report framerate(fps) to estimate # of samples. |
72 void QualityScaler::ReportFramerate(int framerate) { | 68 void QualityScaler::ReportFramerate(int framerate) { |
73 framerate_ = framerate; | 69 framerate_ = framerate; |
74 UpdateSampleCounts(); | 70 UpdateSampleCounts(); |
75 } | 71 } |
76 | 72 |
77 void QualityScaler::ReportQP(int qp) { | 73 void QualityScaler::ReportQP(int qp) { |
78 framedrop_percent_.AddSample(0); | 74 framedrop_percent_.AddSample(0); |
79 average_qp_downscale_.AddSample(qp); | 75 average_qp_downscale_.AddSample(qp); |
80 average_qp_upscale_.AddSample(qp); | 76 average_qp_upscale_.AddSample(qp); |
81 } | 77 } |
82 | 78 |
83 void QualityScaler::ReportDroppedFrame() { | 79 void QualityScaler::ReportDroppedFrame() { |
84 framedrop_percent_.AddSample(100); | 80 framedrop_percent_.AddSample(100); |
85 } | 81 } |
86 | 82 |
87 void QualityScaler::OnEncodeFrame(const VideoFrame& frame) { | 83 void QualityScaler::OnEncodeFrame(const VideoFrame& frame) { |
88 // Should be set through InitEncode -> Should be set by now. | 84 // Should be set through InitEncode -> Should be set by now. |
89 assert(low_qp_threshold_ >= 0); | 85 assert(low_qp_threshold_ >= 0); |
90 assert(num_samples_upscale_ > 0); | 86 assert(num_samples_upscale_ > 0); |
91 assert(num_samples_downscale_ > 0); | 87 assert(num_samples_downscale_ > 0); |
92 | 88 |
93 // Update scale factor. | 89 // Update scale factor. |
94 int avg_drop = 0; | 90 int avg_drop = 0; |
95 int avg_qp = 0; | 91 int avg_qp = 0; |
96 | 92 |
97 // When encoder consistently overshoots, framerate reduction and spatial | |
98 // resizing will be triggered to get a smoother video. | |
99 if ((framedrop_percent_.GetAverage(num_samples_downscale_, &avg_drop) && | 93 if ((framedrop_percent_.GetAverage(num_samples_downscale_, &avg_drop) && |
100 avg_drop >= kFramedropPercentThreshold) || | 94 avg_drop >= kFramedropPercentThreshold) || |
101 (average_qp_downscale_.GetAverage(num_samples_downscale_, &avg_qp) && | 95 (average_qp_downscale_.GetAverage(num_samples_downscale_, &avg_qp) && |
102 avg_qp > high_qp_threshold_)) { | 96 avg_qp > high_qp_threshold_)) { |
103 // Reducing frame rate before spatial resolution change. | 97 AdjustScale(false); |
104 // Reduce frame rate only when it is above a certain number. | |
105 // Only one reduction is allowed for now. | |
106 // TODO(jackychen): Allow more than one framerate reduction. | |
107 if (use_framerate_reduction_ && !framerate_down_ && framerate_ >= 20) { | |
108 target_framerate_ = framerate_ / 2; | |
109 framerate_down_ = true; | |
110 // If frame rate has been updated, clear the buffer. We don't want | |
111 // spatial resolution to change right after frame rate change. | |
112 ClearSamples(); | |
113 } else { | |
114 AdjustScale(false); | |
115 } | |
116 } else if (average_qp_upscale_.GetAverage(num_samples_upscale_, &avg_qp) && | 98 } else if (average_qp_upscale_.GetAverage(num_samples_upscale_, &avg_qp) && |
117 avg_qp <= low_qp_threshold_) { | 99 avg_qp <= low_qp_threshold_) { |
118 if (use_framerate_reduction_ && framerate_down_) { | 100 AdjustScale(true); |
119 target_framerate_ = -1; | |
120 framerate_down_ = false; | |
121 ClearSamples(); | |
122 } else { | |
123 AdjustScale(true); | |
124 } | |
125 } | 101 } |
126 UpdateTargetResolution(frame.width(), frame.height()); | 102 UpdateTargetResolution(frame.width(), frame.height()); |
127 } | 103 } |
128 | 104 |
129 QualityScaler::Resolution QualityScaler::GetScaledResolution() const { | 105 QualityScaler::Resolution QualityScaler::GetScaledResolution() const { |
130 return res_; | 106 return res_; |
131 } | 107 } |
132 | 108 |
133 int QualityScaler::GetTargetFramerate() const { | |
134 return target_framerate_; | |
135 } | |
136 | |
137 const VideoFrame& QualityScaler::GetScaledFrame(const VideoFrame& frame) { | 109 const VideoFrame& QualityScaler::GetScaledFrame(const VideoFrame& frame) { |
138 Resolution res = GetScaledResolution(); | 110 Resolution res = GetScaledResolution(); |
139 if (res.width == frame.width()) | 111 if (res.width == frame.width()) |
140 return frame; | 112 return frame; |
141 | 113 |
142 scaler_.Set(frame.width(), frame.height(), res.width, res.height, kI420, | 114 scaler_.Set(frame.width(), frame.height(), res.width, res.height, kI420, |
143 kI420, kScaleBox); | 115 kI420, kScaleBox); |
144 if (scaler_.Scale(frame, &scaled_frame_) != 0) | 116 if (scaler_.Scale(frame, &scaled_frame_) != 0) |
145 return frame; | 117 return frame; |
146 | 118 |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
189 downscale_shift_ = 0; | 161 downscale_shift_ = 0; |
190 if (!up) { | 162 if (!up) { |
191 // Hit first downscale, start using a slower threshold for going up. | 163 // Hit first downscale, start using a slower threshold for going up. |
192 measure_seconds_upscale_ = kMeasureSecondsUpscale; | 164 measure_seconds_upscale_ = kMeasureSecondsUpscale; |
193 UpdateSampleCounts(); | 165 UpdateSampleCounts(); |
194 } | 166 } |
195 ClearSamples(); | 167 ClearSamples(); |
196 } | 168 } |
197 | 169 |
198 } // namespace webrtc | 170 } // namespace webrtc |
OLD | NEW |