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 22 matching lines...) Expand all Loading... |
33 void QualityScaler::Init(int low_qp_threshold, | 33 void QualityScaler::Init(int low_qp_threshold, |
34 int high_qp_threshold, | 34 int high_qp_threshold, |
35 bool use_framerate_reduction, | 35 bool use_framerate_reduction, |
36 int initial_bitrate_kbps, | 36 int initial_bitrate_kbps, |
37 int width, | 37 int width, |
38 int height) { | 38 int height) { |
39 ClearSamples(); | 39 ClearSamples(); |
40 low_qp_threshold_ = low_qp_threshold; | 40 low_qp_threshold_ = low_qp_threshold; |
41 high_qp_threshold_ = high_qp_threshold; | 41 high_qp_threshold_ = high_qp_threshold; |
42 use_framerate_reduction_ = use_framerate_reduction; | 42 use_framerate_reduction_ = use_framerate_reduction; |
| 43 downscale_shift_ = 0; |
| 44 const int init_width = width; |
| 45 const int init_height = height; |
43 // TODO(glaznev): Investigate using thresholds for other resolutions | 46 // TODO(glaznev): Investigate using thresholds for other resolutions |
44 // or threshold tables. | 47 // or threshold tables. |
45 if (initial_bitrate_kbps > 0 && | 48 if (initial_bitrate_kbps > 0 && |
46 initial_bitrate_kbps < kHdBitrateThresholdKbps) { | 49 initial_bitrate_kbps < kHdBitrateThresholdKbps) { |
47 // Start scaling to roughly VGA. | 50 // Start scaling to roughly VGA. |
48 while (width * height > kHdResolutionThreshold) { | 51 while (width * height > kHdResolutionThreshold) { |
49 ++downscale_shift_; | 52 ++downscale_shift_; |
50 width /= 2; | 53 width /= 2; |
51 height /= 2; | 54 height /= 2; |
52 } | 55 } |
53 } | 56 } |
54 res_.width = width; | 57 UpdateTargetResolution(init_width, init_height); |
55 res_.height = height; | |
56 target_framerate_ = -1; | 58 target_framerate_ = -1; |
57 } | 59 } |
58 | 60 |
59 void QualityScaler::SetMinResolution(int min_width, int min_height) { | 61 void QualityScaler::SetMinResolution(int min_width, int min_height) { |
60 min_width_ = min_width; | 62 min_width_ = min_width; |
61 min_height_ = min_height; | 63 min_height_ = min_height; |
62 } | 64 } |
63 | 65 |
64 // Report framerate(fps) to estimate # of samples. | 66 // Report framerate(fps) to estimate # of samples. |
65 void QualityScaler::ReportFramerate(int framerate) { | 67 void QualityScaler::ReportFramerate(int framerate) { |
66 num_samples_ = static_cast<size_t>( | 68 num_samples_ = static_cast<size_t>( |
67 kMeasureSeconds * (framerate < kMinFps ? kMinFps : framerate)); | 69 kMeasureSeconds * (framerate < kMinFps ? kMinFps : framerate)); |
68 framerate_ = framerate; | 70 framerate_ = framerate; |
69 } | 71 } |
70 | 72 |
71 void QualityScaler::ReportQP(int qp) { | 73 void QualityScaler::ReportQP(int qp) { |
72 framedrop_percent_.AddSample(0); | 74 framedrop_percent_.AddSample(0); |
73 average_qp_.AddSample(qp); | 75 average_qp_.AddSample(qp); |
74 } | 76 } |
75 | 77 |
76 void QualityScaler::ReportDroppedFrame() { | 78 void QualityScaler::ReportDroppedFrame() { |
77 framedrop_percent_.AddSample(100); | 79 framedrop_percent_.AddSample(100); |
78 } | 80 } |
79 | 81 |
80 void QualityScaler::OnEncodeFrame(const VideoFrame& frame) { | 82 void QualityScaler::OnEncodeFrame(const VideoFrame& frame) { |
81 // Should be set through InitEncode -> Should be set by now. | 83 // Should be set through InitEncode -> Should be set by now. |
82 assert(low_qp_threshold_ >= 0); | 84 assert(low_qp_threshold_ >= 0); |
83 assert(num_samples_ > 0); | 85 assert(num_samples_ > 0); |
84 res_.width = frame.width(); | |
85 res_.height = frame.height(); | |
86 | 86 |
87 // Update scale factor. | 87 // Update scale factor. |
88 int avg_drop = 0; | 88 int avg_drop = 0; |
89 int avg_qp = 0; | 89 int avg_qp = 0; |
90 | 90 |
91 // When encoder consistently overshoots, framerate reduction and spatial | 91 // When encoder consistently overshoots, framerate reduction and spatial |
92 // resizing will be triggered to get a smoother video. | 92 // resizing will be triggered to get a smoother video. |
93 if ((framedrop_percent_.GetAverage(num_samples_, &avg_drop) && | 93 if ((framedrop_percent_.GetAverage(num_samples_, &avg_drop) && |
94 avg_drop >= kFramedropPercentThreshold) || | 94 avg_drop >= kFramedropPercentThreshold) || |
95 (average_qp_.GetAverage(num_samples_, &avg_qp) && | 95 (average_qp_.GetAverage(num_samples_, &avg_qp) && |
(...skipping 14 matching lines...) Expand all Loading... |
110 } else if (average_qp_.GetAverage(num_samples_, &avg_qp) && | 110 } else if (average_qp_.GetAverage(num_samples_, &avg_qp) && |
111 avg_qp <= low_qp_threshold_) { | 111 avg_qp <= low_qp_threshold_) { |
112 if (use_framerate_reduction_ && framerate_down_) { | 112 if (use_framerate_reduction_ && framerate_down_) { |
113 target_framerate_ = -1; | 113 target_framerate_ = -1; |
114 framerate_down_ = false; | 114 framerate_down_ = false; |
115 ClearSamples(); | 115 ClearSamples(); |
116 } else { | 116 } else { |
117 AdjustScale(true); | 117 AdjustScale(true); |
118 } | 118 } |
119 } | 119 } |
120 | 120 UpdateTargetResolution(frame.width(), frame.height()); |
121 assert(downscale_shift_ >= 0); | |
122 for (int shift = downscale_shift_; | |
123 shift > 0 && (res_.width / 2 >= min_width_) && | |
124 (res_.height / 2 >= min_height_); | |
125 --shift) { | |
126 res_.width /= 2; | |
127 res_.height /= 2; | |
128 } | |
129 } | 121 } |
130 | 122 |
131 QualityScaler::Resolution QualityScaler::GetScaledResolution() const { | 123 QualityScaler::Resolution QualityScaler::GetScaledResolution() const { |
132 return res_; | 124 return res_; |
133 } | 125 } |
134 | 126 |
135 int QualityScaler::GetTargetFramerate() const { | 127 int QualityScaler::GetTargetFramerate() const { |
136 return target_framerate_; | 128 return target_framerate_; |
137 } | 129 } |
138 | 130 |
139 const VideoFrame& QualityScaler::GetScaledFrame(const VideoFrame& frame) { | 131 const VideoFrame& QualityScaler::GetScaledFrame(const VideoFrame& frame) { |
140 Resolution res = GetScaledResolution(); | 132 Resolution res = GetScaledResolution(); |
141 if (res.width == frame.width()) | 133 if (res.width == frame.width()) |
142 return frame; | 134 return frame; |
143 | 135 |
144 scaler_.Set(frame.width(), frame.height(), res.width, res.height, kI420, | 136 scaler_.Set(frame.width(), frame.height(), res.width, res.height, kI420, |
145 kI420, kScaleBox); | 137 kI420, kScaleBox); |
146 if (scaler_.Scale(frame, &scaled_frame_) != 0) | 138 if (scaler_.Scale(frame, &scaled_frame_) != 0) |
147 return frame; | 139 return frame; |
148 | 140 |
149 scaled_frame_.set_ntp_time_ms(frame.ntp_time_ms()); | 141 scaled_frame_.set_ntp_time_ms(frame.ntp_time_ms()); |
150 scaled_frame_.set_timestamp(frame.timestamp()); | 142 scaled_frame_.set_timestamp(frame.timestamp()); |
151 scaled_frame_.set_render_time_ms(frame.render_time_ms()); | 143 scaled_frame_.set_render_time_ms(frame.render_time_ms()); |
152 | 144 |
153 return scaled_frame_; | 145 return scaled_frame_; |
154 } | 146 } |
155 | 147 |
| 148 void QualityScaler::UpdateTargetResolution(int frame_width, int frame_height) { |
| 149 assert(downscale_shift_ >= 0); |
| 150 res_.width = frame_width; |
| 151 res_.height = frame_height; |
| 152 for (int shift = downscale_shift_; |
| 153 shift > 0 && (res_.width / 2 >= min_width_) && |
| 154 (res_.height / 2 >= min_height_); |
| 155 --shift) { |
| 156 res_.width /= 2; |
| 157 res_.height /= 2; |
| 158 } |
| 159 } |
| 160 |
156 void QualityScaler::ClearSamples() { | 161 void QualityScaler::ClearSamples() { |
157 framedrop_percent_.Reset(); | 162 framedrop_percent_.Reset(); |
158 average_qp_.Reset(); | 163 average_qp_.Reset(); |
159 } | 164 } |
160 | 165 |
161 void QualityScaler::AdjustScale(bool up) { | 166 void QualityScaler::AdjustScale(bool up) { |
162 downscale_shift_ += up ? -1 : 1; | 167 downscale_shift_ += up ? -1 : 1; |
163 if (downscale_shift_ < 0) | 168 if (downscale_shift_ < 0) |
164 downscale_shift_ = 0; | 169 downscale_shift_ = 0; |
165 ClearSamples(); | 170 ClearSamples(); |
166 } | 171 } |
167 | 172 |
168 } // namespace webrtc | 173 } // namespace webrtc |
OLD | NEW |