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 |
10 #include "webrtc/modules/video_coding/utility/quality_scaler.h" | 11 #include "webrtc/modules/video_coding/utility/quality_scaler.h" |
11 | 12 |
12 namespace webrtc { | 13 namespace webrtc { |
13 | 14 |
14 namespace { | 15 namespace { |
15 static const int kMinFps = 5; | 16 static const int kMinFps = 5; |
16 // Threshold constant used until first downscale (to permit fast rampup). | 17 // Threshold constant used until first downscale (to permit fast rampup). |
17 static const int kMeasureSecondsFastUpscale = 2; | 18 static const int kMeasureSecondsFastUpscale = 2; |
18 static const int kMeasureSecondsUpscale = 5; | 19 static const int kMeasureSecondsUpscale = 5; |
19 static const int kMeasureSecondsDownscale = 5; | 20 static const int kMeasureSecondsDownscale = 5; |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
87 void QualityScaler::ReportQP(int qp) { | 88 void QualityScaler::ReportQP(int qp) { |
88 framedrop_percent_.AddSample(0); | 89 framedrop_percent_.AddSample(0); |
89 average_qp_downscale_.AddSample(qp); | 90 average_qp_downscale_.AddSample(qp); |
90 average_qp_upscale_.AddSample(qp); | 91 average_qp_upscale_.AddSample(qp); |
91 } | 92 } |
92 | 93 |
93 void QualityScaler::ReportDroppedFrame() { | 94 void QualityScaler::ReportDroppedFrame() { |
94 framedrop_percent_.AddSample(100); | 95 framedrop_percent_.AddSample(100); |
95 } | 96 } |
96 | 97 |
97 void QualityScaler::OnEncodeFrame(const VideoFrame& frame) { | 98 void QualityScaler::OnEncodeFrame(int width, int height) { |
98 // Should be set through InitEncode -> Should be set by now. | 99 // Should be set through InitEncode -> Should be set by now. |
99 assert(low_qp_threshold_ >= 0); | 100 RTC_DCHECK_GE(low_qp_threshold_, 0); |
100 assert(num_samples_upscale_ > 0); | 101 RTC_DCHECK_GT(num_samples_upscale_, 0u); |
101 assert(num_samples_downscale_ > 0); | 102 RTC_DCHECK_GT(num_samples_downscale_, 0u); |
102 | 103 |
103 // Update scale factor. | 104 // Update scale factor. |
104 int avg_drop = 0; | 105 int avg_drop = 0; |
105 int avg_qp = 0; | 106 int avg_qp = 0; |
106 | 107 |
107 if ((framedrop_percent_.GetAverage(num_samples_downscale_, &avg_drop) && | 108 if ((framedrop_percent_.GetAverage(num_samples_downscale_, &avg_drop) && |
108 avg_drop >= kFramedropPercentThreshold) || | 109 avg_drop >= kFramedropPercentThreshold) || |
109 (average_qp_downscale_.GetAverage(num_samples_downscale_, &avg_qp) && | 110 (average_qp_downscale_.GetAverage(num_samples_downscale_, &avg_qp) && |
110 avg_qp > high_qp_threshold_)) { | 111 avg_qp > high_qp_threshold_)) { |
111 AdjustScale(false); | 112 AdjustScale(false); |
112 } else if (average_qp_upscale_.GetAverage(num_samples_upscale_, &avg_qp) && | 113 } else if (average_qp_upscale_.GetAverage(num_samples_upscale_, &avg_qp) && |
113 avg_qp <= low_qp_threshold_) { | 114 avg_qp <= low_qp_threshold_) { |
114 AdjustScale(true); | 115 AdjustScale(true); |
115 } | 116 } |
116 UpdateTargetResolution(frame.width(), frame.height()); | 117 UpdateTargetResolution(width, height); |
117 } | 118 } |
118 | 119 |
119 QualityScaler::Resolution QualityScaler::GetScaledResolution() const { | 120 QualityScaler::Resolution QualityScaler::GetScaledResolution() const { |
120 return res_; | 121 return res_; |
121 } | 122 } |
122 | 123 |
123 const VideoFrame& QualityScaler::GetScaledFrame(const VideoFrame& frame) { | 124 rtc::scoped_refptr<VideoFrameBuffer> QualityScaler::GetScaledBuffer( |
| 125 const rtc::scoped_refptr<VideoFrameBuffer>& frame) { |
124 Resolution res = GetScaledResolution(); | 126 Resolution res = GetScaledResolution(); |
125 if (res.width == frame.width()) | 127 int src_width = frame->width(); |
| 128 int src_height = frame->height(); |
| 129 |
| 130 if (res.width == src_width && res.height == src_height) |
126 return frame; | 131 return frame; |
| 132 rtc::scoped_refptr<I420Buffer> scaled_buffer = |
| 133 pool_.CreateBuffer(res.width, res.height); |
127 | 134 |
128 scaler_.Set(frame.width(), frame.height(), res.width, res.height, kI420, | 135 scaled_buffer->ScaleFrom(frame); |
129 kI420, kScaleBox); | |
130 if (scaler_.Scale(frame, &scaled_frame_) != 0) | |
131 return frame; | |
132 | 136 |
133 // TODO(perkj): Refactor the scaler to not own |scaled_frame|. VideoFrame are | 137 return scaled_buffer; |
134 // just thin wrappers so instead the scaler should return a | |
135 // rtc::scoped_refptr<VideoFrameBuffer> and a new VideoFrame be created with | |
136 // the meta data from |frame|. That way we would not have to set all these | |
137 // meta data. | |
138 scaled_frame_.set_ntp_time_ms(frame.ntp_time_ms()); | |
139 scaled_frame_.set_timestamp(frame.timestamp()); | |
140 scaled_frame_.set_render_time_ms(frame.render_time_ms()); | |
141 scaled_frame_.set_rotation(frame.rotation()); | |
142 | |
143 return scaled_frame_; | |
144 } | 138 } |
145 | 139 |
146 void QualityScaler::UpdateTargetResolution(int frame_width, int frame_height) { | 140 void QualityScaler::UpdateTargetResolution(int frame_width, int frame_height) { |
147 assert(downscale_shift_ >= 0); | 141 RTC_DCHECK_GE(downscale_shift_, 0); |
148 int shifts_performed = 0; | 142 int shifts_performed = 0; |
149 for (int shift = downscale_shift_; | 143 for (int shift = downscale_shift_; |
150 shift > 0 && (frame_width / 2 >= kMinDownscaleDimension) && | 144 shift > 0 && (frame_width / 2 >= kMinDownscaleDimension) && |
151 (frame_height / 2 >= kMinDownscaleDimension); | 145 (frame_height / 2 >= kMinDownscaleDimension); |
152 --shift, ++shifts_performed) { | 146 --shift, ++shifts_performed) { |
153 frame_width /= 2; | 147 frame_width /= 2; |
154 frame_height /= 2; | 148 frame_height /= 2; |
155 } | 149 } |
156 // Clamp to number of shifts actually performed to not be stuck trying to | 150 // Clamp to number of shifts actually performed to not be stuck trying to |
157 // scale way beyond QVGA. | 151 // scale way beyond QVGA. |
(...skipping 25 matching lines...) Expand all Loading... |
183 if (downscale_shift_ < 0) | 177 if (downscale_shift_ < 0) |
184 downscale_shift_ = 0; | 178 downscale_shift_ = 0; |
185 if (!up) { | 179 if (!up) { |
186 // First downscale hit, start using a slower threshold for going up. | 180 // First downscale hit, start using a slower threshold for going up. |
187 measure_seconds_upscale_ = kMeasureSecondsUpscale; | 181 measure_seconds_upscale_ = kMeasureSecondsUpscale; |
188 UpdateSampleCounts(); | 182 UpdateSampleCounts(); |
189 } | 183 } |
190 } | 184 } |
191 | 185 |
192 } // namespace webrtc | 186 } // namespace webrtc |
OLD | NEW |