Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(339)

Side by Side Diff: remoting/protocol/webrtc_frame_scheduler_simple.cc

Issue 2616213002: Fix WebrtcVideoStream to handle failed capture requests. (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698