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