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

Side by Side Diff: media/capture/content/video_capture_oracle.cc

Issue 1864813002: Tab/Desktop Capture: Use requests instead of timer-based refreshing. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@video_refresh_from_sinks
Patch Set: Fix WCVCD unit tests that test resize policies. Created 4 years, 8 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 (c) 2015 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2015 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 "media/capture/content/video_capture_oracle.h" 5 #include "media/capture/content/video_capture_oracle.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/format_macros.h" 9 #include "base/format_macros.h"
10 #include "base/numerics/safe_conversions.h" 10 #include "base/numerics/safe_conversions.h"
11 #include "base/strings/stringprintf.h" 11 #include "base/strings/stringprintf.h"
12 12
13 namespace media { 13 namespace media {
14 14
15 namespace { 15 namespace {
16 16
17 // This value controls how many redundant, timer-base captures occur when the 17 // When estimating frame durations, this is the hard upper-bound on the
18 // content is static. Redundantly capturing the same frame allows iterative 18 // estimate.
19 // quality enhancement, and also allows the buffer to fill in "buffered mode". 19 const int kUpperBoundDurationEstimateMicros = 1000000; // 1 second
Irfan 2016/04/06 19:53:05 kUpperBoundFrameDuration... ?
miu 2016/04/06 22:33:53 IMHO, adding "Frame" to this long name doesn't rea
20 //
21 // TODO(nick): Controlling this here is a hack and a layering violation, since
22 // it's a strategy specific to the WebRTC consumer, and probably just papers
23 // over some frame dropping and quality bugs. It should either be controlled at
24 // a higher level, or else redundant frame generation should be pushed down
25 // further into the WebRTC encoding stack.
26 const int kNumRedundantCapturesOfStaticContent = 200;
27 20
28 // The half-life of data points provided to the accumulator used when evaluating 21 // The half-life of data points provided to the accumulator used when evaluating
29 // the recent utilization of the buffer pool. This value is based on a 22 // the recent utilization of the buffer pool. This value is based on a
30 // simulation, and reacts quickly to change to avoid depleting the buffer pool 23 // simulation, and reacts quickly to change to avoid depleting the buffer pool
31 // (which would cause hard frame drops). 24 // (which would cause hard frame drops).
32 const int kBufferUtilizationEvaluationMicros = 200000; // 0.2 seconds 25 const int kBufferUtilizationEvaluationMicros = 200000; // 0.2 seconds
33 26
34 // The half-life of data points provided to the accumulator used when evaluating 27 // The half-life of data points provided to the accumulator used when evaluating
35 // the recent resource utilization of the consumer. The trade-off made here is 28 // the recent resource utilization of the consumer. The trade-off made here is
36 // reaction time versus over-reacting to outlier data points. 29 // reaction time versus over-reacting to outlier data points.
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
99 92
100 VideoCaptureOracle::VideoCaptureOracle( 93 VideoCaptureOracle::VideoCaptureOracle(
101 base::TimeDelta min_capture_period, 94 base::TimeDelta min_capture_period,
102 const gfx::Size& max_frame_size, 95 const gfx::Size& max_frame_size,
103 media::ResolutionChangePolicy resolution_change_policy, 96 media::ResolutionChangePolicy resolution_change_policy,
104 bool enable_auto_throttling) 97 bool enable_auto_throttling)
105 : auto_throttling_enabled_(enable_auto_throttling), 98 : auto_throttling_enabled_(enable_auto_throttling),
106 next_frame_number_(0), 99 next_frame_number_(0),
107 last_successfully_delivered_frame_number_(-1), 100 last_successfully_delivered_frame_number_(-1),
108 num_frames_pending_(0), 101 num_frames_pending_(0),
109 smoothing_sampler_(min_capture_period, 102 smoothing_sampler_(min_capture_period),
110 kNumRedundantCapturesOfStaticContent),
111 content_sampler_(min_capture_period), 103 content_sampler_(min_capture_period),
112 resolution_chooser_(max_frame_size, resolution_change_policy), 104 resolution_chooser_(max_frame_size, resolution_change_policy),
113 buffer_pool_utilization_(base::TimeDelta::FromMicroseconds( 105 buffer_pool_utilization_(base::TimeDelta::FromMicroseconds(
114 kBufferUtilizationEvaluationMicros)), 106 kBufferUtilizationEvaluationMicros)),
115 estimated_capable_area_(base::TimeDelta::FromMicroseconds( 107 estimated_capable_area_(base::TimeDelta::FromMicroseconds(
116 kConsumerCapabilityEvaluationMicros)) { 108 kConsumerCapabilityEvaluationMicros)) {
117 VLOG(1) << "Auto-throttling is " 109 VLOG(1) << "Auto-throttling is "
118 << (auto_throttling_enabled_ ? "enabled." : "disabled."); 110 << (auto_throttling_enabled_ ? "enabled." : "disabled.");
119 } 111 }
120 112
(...skipping 16 matching lines...) Expand all
137 DCHECK_LT(event, kNumEvents); 129 DCHECK_LT(event, kNumEvents);
138 if (event_time < last_event_time_[event]) { 130 if (event_time < last_event_time_[event]) {
139 LOG(WARNING) << "Event time is not monotonically non-decreasing. " 131 LOG(WARNING) << "Event time is not monotonically non-decreasing. "
140 << "Deciding not to capture this frame."; 132 << "Deciding not to capture this frame.";
141 return false; 133 return false;
142 } 134 }
143 last_event_time_[event] = event_time; 135 last_event_time_[event] = event_time;
144 136
145 bool should_sample = false; 137 bool should_sample = false;
146 duration_of_next_frame_ = base::TimeDelta(); 138 duration_of_next_frame_ = base::TimeDelta();
147 switch (event) { 139 switch (event) {
xjz 2016/04/06 17:02:28 nit: maybe just use if (event == kCompositorUpdate
miu 2016/04/06 22:33:53 I would, except for two things: 1. This forces co
148 case kCompositorUpdate: { 140 case kCompositorUpdate: {
149 smoothing_sampler_.ConsiderPresentationEvent(event_time); 141 smoothing_sampler_.ConsiderPresentationEvent(event_time);
150 const bool had_proposal = content_sampler_.HasProposal(); 142 const bool had_proposal = content_sampler_.HasProposal();
151 content_sampler_.ConsiderPresentationEvent(damage_rect, event_time); 143 content_sampler_.ConsiderPresentationEvent(damage_rect, event_time);
152 if (content_sampler_.HasProposal()) { 144 if (content_sampler_.HasProposal()) {
153 VLOG_IF(1, !had_proposal) << "Content sampler now detects animation."; 145 VLOG_IF(1, !had_proposal) << "Content sampler now detects animation.";
154 should_sample = content_sampler_.ShouldSample(); 146 should_sample = content_sampler_.ShouldSample();
155 if (should_sample) { 147 if (should_sample) {
156 event_time = content_sampler_.frame_timestamp(); 148 event_time = content_sampler_.frame_timestamp();
157 duration_of_next_frame_ = content_sampler_.sampling_period(); 149 duration_of_next_frame_ = content_sampler_.sampling_period();
158 } 150 }
159 last_time_animation_was_detected_ = event_time; 151 last_time_animation_was_detected_ = event_time;
160 } else { 152 } else {
161 VLOG_IF(1, had_proposal) << "Content sampler detects animation ended."; 153 VLOG_IF(1, had_proposal) << "Content sampler detects animation ended.";
162 should_sample = smoothing_sampler_.ShouldSample(); 154 should_sample = smoothing_sampler_.ShouldSample();
163 } 155 }
164 break; 156 break;
165 } 157 }
166 158
167 case kTimerPoll: 159 case kActiveRefreshRequest:
168 // While the timer is firing, only allow a sampling if there are none 160 case kPassiveRefreshRequest:
169 // currently in-progress.
170 if (num_frames_pending_ == 0)
171 should_sample = smoothing_sampler_.IsOverdueForSamplingAt(event_time);
172 break;
173
174 case kMouseCursorUpdate: 161 case kMouseCursorUpdate:
175 // Only allow a sampling if there are none currently in-progress. 162 // Only allow a sampling if there are none currently in-progress.
176 if (num_frames_pending_ == 0) { 163 if (num_frames_pending_ == 0) {
177 smoothing_sampler_.ConsiderPresentationEvent(event_time); 164 smoothing_sampler_.ConsiderPresentationEvent(event_time);
178 should_sample = smoothing_sampler_.ShouldSample(); 165 should_sample = smoothing_sampler_.ShouldSample();
179 } 166 }
180 break; 167 break;
168
181 case kNumEvents: 169 case kNumEvents:
182 NOTREACHED(); 170 NOTREACHED();
183 break; 171 break;
184 } 172 }
185 173
186 if (!should_sample) 174 if (!should_sample)
187 return false; 175 return false;
188 176
189 // If the exact duration of the next frame has not been determined, estimate 177 // If the exact duration of the next frame has not been determined, estimate
190 // it using the difference between the current and last frame. 178 // it using the difference between the current and last frame.
191 if (duration_of_next_frame_.is_zero()) { 179 if (duration_of_next_frame_.is_zero()) {
192 if (next_frame_number_ > 0) { 180 if (next_frame_number_ > 0) {
193 duration_of_next_frame_ = 181 duration_of_next_frame_ =
194 event_time - GetFrameTimestamp(next_frame_number_ - 1); 182 event_time - GetFrameTimestamp(next_frame_number_ - 1);
195 } 183 }
196 const base::TimeDelta upper_bound = base::TimeDelta::FromMilliseconds( 184 const base::TimeDelta upper_bound =
197 SmoothEventSampler::OVERDUE_DIRTY_THRESHOLD_MILLIS); 185 base::TimeDelta::FromMilliseconds(kUpperBoundDurationEstimateMicros);
198 duration_of_next_frame_ = 186 duration_of_next_frame_ =
199 std::max(std::min(duration_of_next_frame_, upper_bound), 187 std::max(std::min(duration_of_next_frame_, upper_bound),
200 smoothing_sampler_.min_capture_period()); 188 smoothing_sampler_.min_capture_period());
201 } 189 }
202 190
203 // Update |capture_size_| and reset all feedback signal accumulators if 191 // Update |capture_size_| and reset all feedback signal accumulators if
204 // either: 1) this is the first frame; or 2) |resolution_chooser_| has an 192 // either: 1) this is the first frame; or 2) |resolution_chooser_| has an
205 // updated capture size and sufficient time has passed since the last size 193 // updated capture size and sufficient time has passed since the last size
206 // change. 194 // change.
207 if (next_frame_number_ == 0) { 195 if (next_frame_number_ == 0) {
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
333 // Translate the utilization metric to be in terms of the capable frame area 321 // Translate the utilization metric to be in terms of the capable frame area
334 // and update the feedback accumulators. Research suggests utilization is at 322 // and update the feedback accumulators. Research suggests utilization is at
335 // most linearly proportional to area, and typically is sublinear. Either 323 // most linearly proportional to area, and typically is sublinear. Either
336 // way, the end-to-end system should converge to the right place using the 324 // way, the end-to-end system should converge to the right place using the
337 // more-conservative assumption (linear). 325 // more-conservative assumption (linear).
338 const int area_at_full_utilization = 326 const int area_at_full_utilization =
339 base::saturated_cast<int>(capture_size_.GetArea() / resource_utilization); 327 base::saturated_cast<int>(capture_size_.GetArea() / resource_utilization);
340 estimated_capable_area_.Update(area_at_full_utilization, timestamp); 328 estimated_capable_area_.Update(area_at_full_utilization, timestamp);
341 } 329 }
342 330
331 // static
332 const char* VideoCaptureOracle::EventAsString(Event event) {
333 switch (event) {
334 case kCompositorUpdate:
335 return "compositor";
336 case kActiveRefreshRequest:
337 return "active_refresh";
338 case kPassiveRefreshRequest:
339 return "passive_refresh";
340 case kMouseCursorUpdate:
341 return "mouse";
342 case kNumEvents:
343 break;
344 }
345 NOTREACHED();
346 return "unknown";
347 }
348
343 base::TimeTicks VideoCaptureOracle::GetFrameTimestamp(int frame_number) const { 349 base::TimeTicks VideoCaptureOracle::GetFrameTimestamp(int frame_number) const {
344 DCHECK(IsFrameInRecentHistory(frame_number)); 350 DCHECK(IsFrameInRecentHistory(frame_number));
345 return frame_timestamps_[frame_number % kMaxFrameTimestamps]; 351 return frame_timestamps_[frame_number % kMaxFrameTimestamps];
346 } 352 }
347 353
348 void VideoCaptureOracle::SetFrameTimestamp(int frame_number, 354 void VideoCaptureOracle::SetFrameTimestamp(int frame_number,
349 base::TimeTicks timestamp) { 355 base::TimeTicks timestamp) {
350 DCHECK(IsFrameInRecentHistory(frame_number)); 356 DCHECK(IsFrameInRecentHistory(frame_number));
351 frame_timestamps_[frame_number % kMaxFrameTimestamps] = timestamp; 357 frame_timestamps_[frame_number % kMaxFrameTimestamps] = timestamp;
352 } 358 }
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
533 // Content is not animating, so permit an immediate increase in the capture 539 // Content is not animating, so permit an immediate increase in the capture
534 // area. This allows the system to quickly improve the quality of 540 // area. This allows the system to quickly improve the quality of
535 // non-animating content (frame drops are not much of a concern). 541 // non-animating content (frame drops are not much of a concern).
536 VLOG(2) << "Proposing a " 542 VLOG(2) << "Proposing a "
537 << (100.0 * (increased_area - current_area) / current_area) 543 << (100.0 * (increased_area - current_area) / current_area)
538 << "% increase in capture area for non-animating content. :-)"; 544 << "% increase in capture area for non-animating content. :-)";
539 return increased_area; 545 return increased_area;
540 } 546 }
541 547
542 } // namespace media 548 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698