OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "remoting/protocol/webrtc_frame_scheduler_simple.h" | 5 #include "remoting/protocol/webrtc_frame_scheduler_simple.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "remoting/protocol/frame_stats.h" | 9 #include "remoting/protocol/frame_stats.h" |
10 #include "remoting/protocol/webrtc_dummy_video_encoder.h" | 10 #include "remoting/protocol/webrtc_dummy_video_encoder.h" |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
77 int bandwidth_kbps, | 77 int bandwidth_kbps, |
78 base::TimeTicks now) { | 78 base::TimeTicks now) { |
79 while (!bandwidth_samples_.empty() && | 79 while (!bandwidth_samples_.empty() && |
80 now - bandwidth_samples_.front().first > kBandwidthAveragingInterval) { | 80 now - bandwidth_samples_.front().first > kBandwidthAveragingInterval) { |
81 bandwidth_samples_sum_ -= bandwidth_samples_.front().second; | 81 bandwidth_samples_sum_ -= bandwidth_samples_.front().second; |
82 bandwidth_samples_.pop(); | 82 bandwidth_samples_.pop(); |
83 } | 83 } |
84 | 84 |
85 bandwidth_samples_.push(std::make_pair(now, bandwidth_kbps)); | 85 bandwidth_samples_.push(std::make_pair(now, bandwidth_kbps)); |
86 bandwidth_samples_sum_ += bandwidth_kbps; | 86 bandwidth_samples_sum_ += bandwidth_kbps; |
87 | |
88 UpdateTargetBitrate(); | |
87 } | 89 } |
88 | 90 |
89 int WebrtcFrameSchedulerSimple::EncoderBitrateFilter::GetTargetBitrateKbps( | 91 void WebrtcFrameSchedulerSimple::EncoderBitrateFilter::SetFrameSize( |
90 webrtc::DesktopSize size, | 92 webrtc::DesktopSize size) { |
91 base::TimeTicks now) { | 93 minimum_bitrate_ = |
92 DCHECK(!bandwidth_samples_.empty()); | 94 static_cast<int64_t>(kVp8MinimumTargetBitrateKbpsPerMegapixel) * |
95 size.width() * size.height() / 1000000LL; | |
96 | |
97 UpdateTargetBitrate(); | |
98 } | |
99 | |
100 int WebrtcFrameSchedulerSimple::EncoderBitrateFilter::GetTargetBitrateKbps() | |
101 const { | |
102 DCHECK_GT(current_target_bitrate_, 0); | |
103 return current_target_bitrate_; | |
104 } | |
105 | |
106 void WebrtcFrameSchedulerSimple::EncoderBitrateFilter::UpdateTargetBitrate() { | |
107 if (bandwidth_samples_.empty()) { | |
108 return; | |
109 } | |
93 | 110 |
94 // TODO(sergeyu): This logic is applicable only to VP8. Reconsider it for | 111 // TODO(sergeyu): This logic is applicable only to VP8. Reconsider it for |
joedow
2017/01/09 20:00:28
Should this TODO move up with the VP8 constant or
Sergey Ulanov
2017/01/09 22:24:06
Done.
| |
95 // VP9. | 112 // VP9. |
96 int bandwidth_estimate = bandwidth_samples_sum_ / bandwidth_samples_.size(); | 113 int bandwidth_estimate = bandwidth_samples_sum_ / bandwidth_samples_.size(); |
97 int minimum_bitrate = | 114 int target_bitrate = std::max(minimum_bitrate_, bandwidth_estimate); |
98 static_cast<int64_t>(kVp8MinimumTargetBitrateKbpsPerMegapixel) * | |
99 size.width() * size.height() / 1000000LL; | |
100 int target_bitrate = std::max(minimum_bitrate, bandwidth_estimate); | |
101 | 115 |
102 // Update encoder bitrate only when it changes by more than 30%. This is | 116 // Update encoder bitrate only when it changes by more than 30%. This is |
103 // necessary because the encoder resets internal state when it's reconfigured | 117 // necessary because the encoder resets internal state when it's reconfigured |
104 // and this causes visible drop in quality. | 118 // and this causes visible drop in quality. |
105 if (current_target_bitrate_ == 0 || | 119 if (current_target_bitrate_ == 0 || |
106 std::abs(target_bitrate - current_target_bitrate_) > | 120 std::abs(target_bitrate - current_target_bitrate_) > |
107 current_target_bitrate_ * kEncoderBitrateChangePercentage / 100) { | 121 current_target_bitrate_ * kEncoderBitrateChangePercentage / 100) { |
108 current_target_bitrate_ = target_bitrate; | 122 current_target_bitrate_ = target_bitrate; |
109 } | 123 } |
110 return current_target_bitrate_; | |
111 } | 124 } |
112 | 125 |
113 WebrtcFrameSchedulerSimple::WebrtcFrameSchedulerSimple() | 126 WebrtcFrameSchedulerSimple::WebrtcFrameSchedulerSimple() |
114 : pacing_bucket_(LeakyBucket::kUnlimitedDepth, 0), | 127 : pacing_bucket_(LeakyBucket::kUnlimitedDepth, 0), |
115 frame_processing_delay_us_(kStatsWindow), | 128 frame_processing_delay_us_(kStatsWindow), |
116 updated_region_area_(kStatsWindow), | 129 updated_region_area_(kStatsWindow), |
117 weak_factory_(this) {} | 130 weak_factory_(this) {} |
118 | 131 |
119 WebrtcFrameSchedulerSimple::~WebrtcFrameSchedulerSimple() {} | 132 WebrtcFrameSchedulerSimple::~WebrtcFrameSchedulerSimple() {} |
120 | 133 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
152 DCHECK(thread_checker_.CalledOnValidThread()); | 165 DCHECK(thread_checker_.CalledOnValidThread()); |
153 | 166 |
154 paused_ = pause; | 167 paused_ = pause; |
155 if (paused_) { | 168 if (paused_) { |
156 capture_timer_.Stop(); | 169 capture_timer_.Stop(); |
157 } else { | 170 } else { |
158 ScheduleNextFrame(base::TimeTicks::Now()); | 171 ScheduleNextFrame(base::TimeTicks::Now()); |
159 } | 172 } |
160 } | 173 } |
161 | 174 |
162 bool WebrtcFrameSchedulerSimple::GetEncoderFrameParams( | 175 bool WebrtcFrameSchedulerSimple::OnFrameCaptured( |
163 const webrtc::DesktopFrame& frame, | 176 const webrtc::DesktopFrame* frame, |
164 WebrtcVideoEncoder::FrameParams* params_out) { | 177 WebrtcVideoEncoder::FrameParams* params_out) { |
165 DCHECK(thread_checker_.CalledOnValidThread()); | 178 DCHECK(thread_checker_.CalledOnValidThread()); |
166 | 179 |
167 base::TimeTicks now = base::TimeTicks::Now(); | 180 base::TimeTicks now = base::TimeTicks::Now(); |
168 | 181 |
169 if (frame.updated_region().is_empty() && !top_off_is_active_ && | 182 if ((!frame || frame->updated_region().is_empty()) && !top_off_is_active_ && |
170 !key_frame_request_) { | 183 !key_frame_request_) { |
171 frame_pending_ = false; | 184 frame_pending_ = false; |
172 ScheduleNextFrame(now); | 185 ScheduleNextFrame(now); |
173 return false; | 186 return false; |
174 } | 187 } |
175 | 188 |
176 params_out->bitrate_kbps = | 189 if (frame) { |
177 encoder_bitrate_.GetTargetBitrateKbps(frame.size(), now); | 190 encoder_bitrate_.SetFrameSize(frame->size()); |
191 } | |
178 | 192 |
193 params_out->bitrate_kbps = encoder_bitrate_.GetTargetBitrateKbps(); | |
179 params_out->duration = kTargetFrameInterval; | 194 params_out->duration = kTargetFrameInterval; |
180 params_out->key_frame = key_frame_request_; | 195 params_out->key_frame = key_frame_request_; |
181 key_frame_request_ = false; | 196 key_frame_request_ = false; |
182 | 197 |
183 params_out->vpx_min_quantizer = 10; | 198 params_out->vpx_min_quantizer = 10; |
184 | 199 |
185 int64_t updated_area = params_out->key_frame | 200 int64_t updated_area = 0; |
186 ? frame.size().width() * frame.size().height() | 201 if (frame) { |
187 : GetRegionArea(frame.updated_region()); | 202 updated_area = params_out->key_frame |
203 ? frame->size().width() * frame->size().height() | |
204 : GetRegionArea(frame->updated_region()); | |
205 } | |
188 | 206 |
189 // If bandwidth is being underutilized then libvpx is likely to choose the | 207 // If bandwidth is being underutilized then libvpx is likely to choose the |
190 // minimum allowed quantizer value, which means that encoded frame size may be | 208 // minimum allowed quantizer value, which means that encoded frame size may |
191 // significantly bigger than the bandwidth allows. Detect this case and set | 209 // be significantly bigger than the bandwidth allows. Detect this case and set |
192 // vpx_min_quantizer to 60. The quality will be topped off later. | 210 // vpx_min_quantizer to 60. The quality will be topped off later. |
193 if (updated_area - updated_region_area_.Max() > kBigFrameThresholdPixels) { | 211 if (updated_area - updated_region_area_.Max() > kBigFrameThresholdPixels) { |
194 int expected_frame_size = updated_area * | 212 int expected_frame_size = |
195 kEstimatedBytesPerMegapixel / kPixelsPerMegapixel; | 213 updated_area * kEstimatedBytesPerMegapixel / kPixelsPerMegapixel; |
196 base::TimeDelta expected_send_delay = base::TimeDelta::FromMicroseconds( | 214 base::TimeDelta expected_send_delay = base::TimeDelta::FromMicroseconds( |
197 base::Time::kMicrosecondsPerSecond * expected_frame_size / | 215 base::Time::kMicrosecondsPerSecond * expected_frame_size / |
198 pacing_bucket_.rate()); | 216 pacing_bucket_.rate()); |
199 if (expected_send_delay > kTargetFrameInterval) | 217 if (expected_send_delay > kTargetFrameInterval) { |
200 params_out->vpx_min_quantizer = 60; | 218 params_out->vpx_min_quantizer = 60; |
219 } | |
201 } | 220 } |
202 | 221 |
203 updated_region_area_.Record(updated_area); | 222 updated_region_area_.Record(updated_area); |
204 | 223 |
205 params_out->vpx_max_quantizer = 63; | 224 params_out->vpx_max_quantizer = 63; |
206 | 225 |
207 params_out->clear_active_map = !top_off_is_active_; | 226 params_out->clear_active_map = !top_off_is_active_; |
208 | 227 |
209 return true; | 228 return true; |
210 } | 229 } |
211 | 230 |
212 void WebrtcFrameSchedulerSimple::OnFrameEncoded( | 231 void WebrtcFrameSchedulerSimple::OnFrameEncoded( |
213 const WebrtcVideoEncoder::EncodedFrame& encoded_frame, | 232 const WebrtcVideoEncoder::EncodedFrame* encoded_frame, |
214 const webrtc::EncodedImageCallback::Result& send_result, | |
215 HostFrameStats* frame_stats) { | 233 HostFrameStats* frame_stats) { |
216 DCHECK(thread_checker_.CalledOnValidThread()); | 234 DCHECK(thread_checker_.CalledOnValidThread()); |
217 DCHECK(frame_pending_); | 235 DCHECK(frame_pending_); |
218 frame_pending_ = false; | 236 frame_pending_ = false; |
219 | 237 |
220 base::TimeTicks now = base::TimeTicks::Now(); | 238 base::TimeTicks now = base::TimeTicks::Now(); |
221 | 239 |
222 if (frame_stats) { | 240 if (frame_stats) { |
223 // Calculate |send_pending_delay| before refilling |pacing_bucket_|. | 241 // Calculate |send_pending_delay| before refilling |pacing_bucket_|. |
224 frame_stats->send_pending_delay = | 242 frame_stats->send_pending_delay = |
225 std::max(base::TimeDelta(), pacing_bucket_.GetEmptyTime() - now); | 243 std::max(base::TimeDelta(), pacing_bucket_.GetEmptyTime() - now); |
226 } | 244 } |
227 | 245 |
228 pacing_bucket_.RefillOrSpill(encoded_frame.data.size(), now); | 246 if (!encoded_frame || encoded_frame->data.empty()) { |
229 | |
230 if (encoded_frame.data.empty()) { | |
231 top_off_is_active_ = false; | 247 top_off_is_active_ = false; |
232 } else { | 248 } else { |
249 pacing_bucket_.RefillOrSpill(encoded_frame->data.size(), now); | |
250 | |
233 frame_processing_delay_us_.Record( | 251 frame_processing_delay_us_.Record( |
234 (now - last_capture_started_time_).InMicroseconds()); | 252 (now - last_capture_started_time_).InMicroseconds()); |
235 | 253 |
236 // Top-off until the target quantizer value is reached. | 254 // Top-off until the target quantizer value is reached. |
237 top_off_is_active_ = encoded_frame.quantizer > kTargetQuantizerForVp8TopOff; | 255 top_off_is_active_ = |
256 encoded_frame->quantizer > kTargetQuantizerForVp8TopOff; | |
238 } | 257 } |
239 | 258 |
240 ScheduleNextFrame(now); | 259 ScheduleNextFrame(now); |
241 | 260 |
242 if (frame_stats) { | 261 if (frame_stats) { |
243 frame_stats->rtt_estimate = rtt_estimate_; | 262 frame_stats->rtt_estimate = rtt_estimate_; |
244 frame_stats->bandwidth_estimate_kbps = pacing_bucket_.rate() * 8 / 1000; | 263 frame_stats->bandwidth_estimate_kbps = pacing_bucket_.rate() * 8 / 1000; |
245 } | 264 } |
246 } | 265 } |
247 | 266 |
(...skipping 11 matching lines...) Expand all Loading... | |
259 base::TimeDelta::FromMicroseconds(frame_processing_delay_us_.Max()); | 278 base::TimeDelta::FromMicroseconds(frame_processing_delay_us_.Max()); |
260 base::TimeTicks target_capture_time = | 279 base::TimeTicks target_capture_time = |
261 pacing_bucket_.GetEmptyTime() - expected_processing_time; | 280 pacing_bucket_.GetEmptyTime() - expected_processing_time; |
262 | 281 |
263 // Cap interval between frames to kTargetFrameInterval. | 282 // Cap interval between frames to kTargetFrameInterval. |
264 if (!last_capture_started_time_.is_null()) { | 283 if (!last_capture_started_time_.is_null()) { |
265 target_capture_time = std::max( | 284 target_capture_time = std::max( |
266 target_capture_time, last_capture_started_time_ + kTargetFrameInterval); | 285 target_capture_time, last_capture_started_time_ + kTargetFrameInterval); |
267 } | 286 } |
268 | 287 |
269 if (target_capture_time < now) | 288 if (target_capture_time < now) { |
270 target_capture_time = now; | 289 target_capture_time = now; |
290 } | |
271 | 291 |
272 capture_timer_.Start(FROM_HERE, target_capture_time - now, | 292 capture_timer_.Start(FROM_HERE, target_capture_time - now, |
273 base::Bind(&WebrtcFrameSchedulerSimple::CaptureNextFrame, | 293 base::Bind(&WebrtcFrameSchedulerSimple::CaptureNextFrame, |
274 base::Unretained(this))); | 294 base::Unretained(this))); |
275 } | 295 } |
276 | 296 |
277 void WebrtcFrameSchedulerSimple::CaptureNextFrame() { | 297 void WebrtcFrameSchedulerSimple::CaptureNextFrame() { |
278 DCHECK(thread_checker_.CalledOnValidThread()); | 298 DCHECK(thread_checker_.CalledOnValidThread()); |
279 DCHECK(!frame_pending_); | 299 DCHECK(!frame_pending_); |
280 last_capture_started_time_ = base::TimeTicks::Now(); | 300 last_capture_started_time_ = base::TimeTicks::Now(); |
281 frame_pending_ = true; | 301 frame_pending_ = true; |
282 capture_callback_.Run(); | 302 capture_callback_.Run(); |
283 } | 303 } |
284 | 304 |
285 } // namespace protocol | 305 } // namespace protocol |
286 } // namespace remoting | 306 } // namespace remoting |
OLD | NEW |