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

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 // 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
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
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
OLDNEW
« no previous file with comments | « remoting/protocol/webrtc_frame_scheduler_simple.h ('k') | remoting/protocol/webrtc_video_stream.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698