OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 // Implementation notes: This needs to work on a variety of hardware | 5 // Implementation notes: This needs to work on a variety of hardware |
6 // configurations where the speed of the CPU and GPU greatly affect overall | 6 // configurations where the speed of the CPU and GPU greatly affect overall |
7 // performance. Spanning several threads, the process of capturing has been | 7 // performance. Spanning several threads, the process of capturing has been |
8 // split up into four conceptual stages: | 8 // split up into four conceptual stages: |
9 // | 9 // |
10 // 1. Reserve Buffer: Before a frame can be captured, a slot in the consumer's | 10 // 1. Reserve Buffer: Before a frame can be captured, a slot in the consumer's |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
96 | 96 |
97 namespace content { | 97 namespace content { |
98 | 98 |
99 namespace { | 99 namespace { |
100 | 100 |
101 const int kMinFrameWidth = 2; | 101 const int kMinFrameWidth = 2; |
102 const int kMinFrameHeight = 2; | 102 const int kMinFrameHeight = 2; |
103 const int kMaxFramesInFlight = 2; | 103 const int kMaxFramesInFlight = 2; |
104 const int kMaxSnapshotsInFlight = 1; | 104 const int kMaxSnapshotsInFlight = 1; |
105 | 105 |
| 106 // This value controls how many redundant, timer-base captures occur when the |
| 107 // content is static. Redundantly capturing the same frame allows iterative |
| 108 // quality enhancement, and also allows the buffer to fill in "buffered mode". |
| 109 // |
| 110 // TODO(nick): Controlling this here is a hack and a layering violation, since |
| 111 // it's a strategy specific to the WebRTC consumer, and probably just papers |
| 112 // over some frame dropping and quality bugs. It should either be controlled at |
| 113 // a higher level, or else redundant frame generation should be pushed down |
| 114 // further into the WebRTC encoding stack. |
| 115 const int kNumRedundantCapturesOfStaticContent = 200; |
| 116 |
106 // TODO(nick): Remove this once frame subscription is supported on Aura and | 117 // TODO(nick): Remove this once frame subscription is supported on Aura and |
107 // Linux. | 118 // Linux. |
108 #if (defined(OS_WIN) || defined(OS_MACOSX)) && !defined(USE_AURA) | 119 #if (defined(OS_WIN) || defined(OS_MACOSX)) && !defined(USE_AURA) |
109 const bool kAcceleratedSubscriberIsSupported = true; | 120 const bool kAcceleratedSubscriberIsSupported = true; |
110 #else | 121 #else |
111 const bool kAcceleratedSubscriberIsSupported = false; | 122 const bool kAcceleratedSubscriberIsSupported = false; |
112 #endif | 123 #endif |
113 | 124 |
114 typedef base::Callback<void(base::Time, bool)> DeliverFrameCallback; | 125 typedef base::Callback<void(base::Time, bool)> DeliverFrameCallback; |
115 | 126 |
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
412 | 423 |
413 DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliveryLog); | 424 DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliveryLog); |
414 }; | 425 }; |
415 | 426 |
416 CaptureOracle::CaptureOracle(media::VideoCaptureDevice::EventHandler* consumer, | 427 CaptureOracle::CaptureOracle(media::VideoCaptureDevice::EventHandler* consumer, |
417 base::TimeDelta capture_period) | 428 base::TimeDelta capture_period) |
418 : capture_period_(capture_period), | 429 : capture_period_(capture_period), |
419 consumer_(consumer), | 430 consumer_(consumer), |
420 frame_number_(0), | 431 frame_number_(0), |
421 is_started_(false), | 432 is_started_(false), |
422 sampler_(capture_period_, kAcceleratedSubscriberIsSupported) {} | 433 sampler_(capture_period_, kAcceleratedSubscriberIsSupported, |
| 434 kNumRedundantCapturesOfStaticContent) {} |
423 | 435 |
424 bool CaptureOracle::ObserveEventAndDecideCapture( | 436 bool CaptureOracle::ObserveEventAndDecideCapture( |
425 Event event, | 437 Event event, |
426 scoped_refptr<media::VideoFrame>* storage, | 438 scoped_refptr<media::VideoFrame>* storage, |
427 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback* callback) { | 439 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback* callback) { |
428 base::AutoLock guard(lock_); | 440 base::AutoLock guard(lock_); |
429 | 441 |
430 if (!consumer_ || !is_started_) | 442 if (!consumer_ || !is_started_) |
431 return false; // Capture is stopped. | 443 return false; // Capture is stopped. |
432 | 444 |
(...skipping 813 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1246 void WebContentsVideoCaptureDevice::DeAllocate() { | 1258 void WebContentsVideoCaptureDevice::DeAllocate() { |
1247 impl_->DeAllocate(); | 1259 impl_->DeAllocate(); |
1248 } | 1260 } |
1249 | 1261 |
1250 const media::VideoCaptureDevice::Name& | 1262 const media::VideoCaptureDevice::Name& |
1251 WebContentsVideoCaptureDevice::device_name() { | 1263 WebContentsVideoCaptureDevice::device_name() { |
1252 return device_name_; | 1264 return device_name_; |
1253 } | 1265 } |
1254 | 1266 |
1255 SmoothEventSampler::SmoothEventSampler(base::TimeDelta capture_period, | 1267 SmoothEventSampler::SmoothEventSampler(base::TimeDelta capture_period, |
1256 bool events_are_reliable) | 1268 bool events_are_reliable, |
| 1269 int redundant_capture_goal) |
1257 : events_are_reliable_(events_are_reliable), | 1270 : events_are_reliable_(events_are_reliable), |
1258 capture_period_(capture_period) {} | 1271 capture_period_(capture_period), |
| 1272 redundant_capture_goal_(redundant_capture_goal), |
| 1273 last_sample_count_(0) {} |
1259 | 1274 |
1260 bool SmoothEventSampler::AddEventAndConsiderSampling(base::Time now) { | 1275 bool SmoothEventSampler::AddEventAndConsiderSampling(base::Time now) { |
1261 current_event_ = now; | 1276 current_event_ = now; |
1262 | 1277 |
1263 // If we've never sampled, then the choice is obvious. | 1278 // If we've never sampled, then the choice is obvious. |
1264 if (last_sample_.is_null()) | 1279 if (last_sample_count_ == 0) |
1265 return true; | 1280 return true; |
1266 | 1281 |
1267 // TODO(nick): Actually track the effective frame rate here, and use an | 1282 // TODO(nick): Actually track the effective frame rate here, and use an |
1268 // uncertainty window based on that (half seems like a reasonable choice). E.g | 1283 // uncertainty window based on that (half seems like a reasonable choice). E.g |
1269 // if content is updating every 16.6ms, and we're hoping to sampling every | 1284 // if content is updating every 16.6ms, and we're hoping to sampling every |
1270 // 100ms, then we might consider sampling events no sooner than (100ms - | 1285 // 100ms, then we might consider sampling events no sooner than (100ms - |
1271 // 8.3ms) from the last sample. | 1286 // 8.3ms) from the last sample. |
1272 base::TimeDelta uncertainty_window = capture_period_ / 10; | 1287 base::TimeDelta uncertainty_window = capture_period_ / 10; |
1273 | 1288 |
1274 base::TimeDelta interval = current_event_ - last_sample_; | 1289 base::TimeDelta interval = current_event_ - last_sample_; |
1275 return interval >= (capture_period_ - uncertainty_window); | 1290 return interval >= (capture_period_ - uncertainty_window); |
1276 } | 1291 } |
1277 | 1292 |
1278 void SmoothEventSampler::RecordSample() { | 1293 void SmoothEventSampler::RecordSample() { |
1279 if (!current_event_.is_null()) | 1294 if (!current_event_.is_null()) { |
| 1295 last_sample_count_ = 0; |
1280 last_sample_ = current_event_; | 1296 last_sample_ = current_event_; |
| 1297 } |
| 1298 last_sample_count_++; |
1281 current_event_ = base::Time(); | 1299 current_event_ = base::Time(); |
1282 } | 1300 } |
1283 | 1301 |
1284 bool SmoothEventSampler::IsOverdueForSamplingAt(base::Time now) const { | 1302 bool SmoothEventSampler::IsOverdueForSamplingAt(base::Time now) const { |
1285 if (last_sample_.is_null()) | 1303 if (last_sample_count_ == 0) |
1286 return true; // Definitely old and dirty. | 1304 return true; // Definitely old and dirty. |
1287 | 1305 |
1288 // If we don't get events on compositor updates on this platform, then we | 1306 // If we don't get events on compositor updates on this platform, then we |
1289 // don't reliably know whether we're dirty. | 1307 // don't reliably know whether we're dirty. |
1290 if (events_are_reliable_) { | 1308 if (events_are_reliable_) { |
1291 if (current_event_.is_null()) | 1309 if (current_event_.is_null() && |
| 1310 last_sample_count_ >= redundant_capture_goal_) { |
1292 return false; // Not dirty. | 1311 return false; // Not dirty. |
| 1312 } |
1293 } | 1313 } |
1294 | 1314 |
1295 // If we're dirty but not yet old, then we've recently gotten updates, so we | 1315 // If we're dirty but not yet old, then we've recently gotten updates, so we |
1296 // won't request a sample just yet. | 1316 // won't request a sample just yet. |
1297 base::TimeDelta dirty_interval = now - last_sample_; | 1317 base::TimeDelta dirty_interval = now - last_sample_; |
1298 if (dirty_interval < capture_period_ * 2) | 1318 if (dirty_interval < capture_period_ * 2) |
1299 return false; | 1319 return false; |
1300 else | 1320 else |
1301 return true; | 1321 return true; |
1302 } | 1322 } |
1303 | 1323 |
1304 base::Time SmoothEventSampler::GetLastSampledEvent() { | 1324 base::Time SmoothEventSampler::GetLastSampledEvent() { |
1305 return last_sample_; | 1325 return last_sample_; |
1306 } | 1326 } |
1307 | 1327 |
1308 } // namespace content | 1328 } // namespace content |
OLD | NEW |