| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 "content/browser/renderer_host/media/video_capture_oracle.h" | 5 #include "content/browser/renderer_host/media/video_capture_oracle.h" |
| 6 | 6 |
| 7 #include "base/debug/trace_event.h" | 7 #include "base/debug/trace_event.h" |
| 8 | 8 |
| 9 namespace content { | 9 namespace content { |
| 10 | 10 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 VideoCaptureOracle::VideoCaptureOracle(base::TimeDelta capture_period, | 26 VideoCaptureOracle::VideoCaptureOracle(base::TimeDelta capture_period, |
| 27 bool events_are_reliable) | 27 bool events_are_reliable) |
| 28 : capture_period_(capture_period), | 28 : capture_period_(capture_period), |
| 29 frame_number_(0), | 29 frame_number_(0), |
| 30 last_delivered_frame_number_(0), | 30 last_delivered_frame_number_(0), |
| 31 sampler_(capture_period_, | 31 sampler_(capture_period_, |
| 32 events_are_reliable, | 32 events_are_reliable, |
| 33 kNumRedundantCapturesOfStaticContent) {} | 33 kNumRedundantCapturesOfStaticContent) {} |
| 34 | 34 |
| 35 bool VideoCaptureOracle::ObserveEventAndDecideCapture( | 35 bool VideoCaptureOracle::ObserveEventAndDecideCapture( |
| 36 Event event, | 36 Event event, |
| 37 base::Time event_time) { | 37 base::TimeTicks event_time) { |
| 38 // Record |event| and decide whether it's a good time to capture. | 38 // Record |event| and decide whether it's a good time to capture. |
| 39 const bool content_is_dirty = (event == kCompositorUpdate || | 39 const bool content_is_dirty = (event == kCompositorUpdate || |
| 40 event == kSoftwarePaint); | 40 event == kSoftwarePaint); |
| 41 bool should_sample; | 41 bool should_sample; |
| 42 if (content_is_dirty) { | 42 if (content_is_dirty) { |
| 43 frame_number_++; | 43 frame_number_++; |
| 44 should_sample = sampler_.AddEventAndConsiderSampling(event_time); | 44 should_sample = sampler_.AddEventAndConsiderSampling(event_time); |
| 45 } else { | 45 } else { |
| 46 should_sample = sampler_.IsOverdueForSamplingAt(event_time); | 46 should_sample = sampler_.IsOverdueForSamplingAt(event_time); |
| 47 } | 47 } |
| 48 return should_sample; | 48 return should_sample; |
| 49 } | 49 } |
| 50 | 50 |
| 51 int VideoCaptureOracle::RecordCapture() { | 51 int VideoCaptureOracle::RecordCapture() { |
| 52 sampler_.RecordSample(); | 52 sampler_.RecordSample(); |
| 53 return frame_number_; | 53 return frame_number_; |
| 54 } | 54 } |
| 55 | 55 |
| 56 bool VideoCaptureOracle::CompleteCapture(int frame_number, | 56 bool VideoCaptureOracle::CompleteCapture(int frame_number, |
| 57 base::Time timestamp) { | 57 base::TimeTicks timestamp) { |
| 58 // Drop frame if previous frame number is higher or we're trying to deliver | 58 // Drop frame if previous frame number is higher or we're trying to deliver |
| 59 // a frame with the same timestamp. | 59 // a frame with the same timestamp. |
| 60 if (last_delivered_frame_number_ > frame_number || | 60 if (last_delivered_frame_number_ > frame_number || |
| 61 last_delivered_frame_timestamp_ == timestamp) { | 61 last_delivered_frame_timestamp_ == timestamp) { |
| 62 LOG(ERROR) << "Frame with same timestamp or out of order delivery. " | 62 LOG(ERROR) << "Frame with same timestamp or out of order delivery. " |
| 63 << "Dropping frame."; | 63 << "Dropping frame."; |
| 64 return false; | 64 return false; |
| 65 } | 65 } |
| 66 | 66 |
| 67 if (last_delivered_frame_timestamp_ > timestamp) { | 67 if (last_delivered_frame_timestamp_ > timestamp) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 81 int redundant_capture_goal) | 81 int redundant_capture_goal) |
| 82 : events_are_reliable_(events_are_reliable), | 82 : events_are_reliable_(events_are_reliable), |
| 83 capture_period_(capture_period), | 83 capture_period_(capture_period), |
| 84 redundant_capture_goal_(redundant_capture_goal), | 84 redundant_capture_goal_(redundant_capture_goal), |
| 85 token_bucket_capacity_(capture_period + capture_period / 2), | 85 token_bucket_capacity_(capture_period + capture_period / 2), |
| 86 overdue_sample_count_(0), | 86 overdue_sample_count_(0), |
| 87 token_bucket_(token_bucket_capacity_) { | 87 token_bucket_(token_bucket_capacity_) { |
| 88 DCHECK_GT(capture_period_.InMicroseconds(), 0); | 88 DCHECK_GT(capture_period_.InMicroseconds(), 0); |
| 89 } | 89 } |
| 90 | 90 |
| 91 bool SmoothEventSampler::AddEventAndConsiderSampling(base::Time event_time) { | 91 bool SmoothEventSampler::AddEventAndConsiderSampling( |
| 92 base::TimeTicks event_time) { |
| 92 DCHECK(!event_time.is_null()); | 93 DCHECK(!event_time.is_null()); |
| 93 | 94 |
| 94 // Add tokens to the bucket based on advancement in time. Then, re-bound the | 95 // Add tokens to the bucket based on advancement in time. Then, re-bound the |
| 95 // number of tokens in the bucket. Overflow occurs when there is too much | 96 // number of tokens in the bucket. Overflow occurs when there is too much |
| 96 // time between events (a common case), or when RecordSample() is not being | 97 // time between events (a common case), or when RecordSample() is not being |
| 97 // called often enough (a bug). On the other hand, if RecordSample() is being | 98 // called often enough (a bug). On the other hand, if RecordSample() is being |
| 98 // called too often (e.g., as a reaction to IsOverdueForSamplingAt()), the | 99 // called too often (e.g., as a reaction to IsOverdueForSamplingAt()), the |
| 99 // bucket will underflow. | 100 // bucket will underflow. |
| 100 if (!current_event_.is_null()) { | 101 if (!current_event_.is_null()) { |
| 101 if (current_event_ < event_time) { | 102 if (current_event_ < event_time) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 130 } | 131 } |
| 131 bool is_paused = overdue_sample_count_ == redundant_capture_goal_; | 132 bool is_paused = overdue_sample_count_ == redundant_capture_goal_; |
| 132 | 133 |
| 133 VLOG_IF(0, !was_paused && is_paused) | 134 VLOG_IF(0, !was_paused && is_paused) |
| 134 << "Tab content unchanged for " << redundant_capture_goal_ | 135 << "Tab content unchanged for " << redundant_capture_goal_ |
| 135 << " frames; capture will halt until content changes."; | 136 << " frames; capture will halt until content changes."; |
| 136 VLOG_IF(0, was_paused && !is_paused) | 137 VLOG_IF(0, was_paused && !is_paused) |
| 137 << "Content changed; capture will resume."; | 138 << "Content changed; capture will resume."; |
| 138 } | 139 } |
| 139 | 140 |
| 140 bool SmoothEventSampler::IsOverdueForSamplingAt(base::Time event_time) const { | 141 bool SmoothEventSampler::IsOverdueForSamplingAt(base::TimeTicks event_time) |
| 142 const { |
| 141 DCHECK(!event_time.is_null()); | 143 DCHECK(!event_time.is_null()); |
| 142 | 144 |
| 143 // If we don't get events on compositor updates on this platform, then we | 145 // If we don't get events on compositor updates on this platform, then we |
| 144 // don't reliably know whether we're dirty. | 146 // don't reliably know whether we're dirty. |
| 145 if (events_are_reliable_) { | 147 if (events_are_reliable_) { |
| 146 if (!HasUnrecordedEvent() && | 148 if (!HasUnrecordedEvent() && |
| 147 overdue_sample_count_ >= redundant_capture_goal_) { | 149 overdue_sample_count_ >= redundant_capture_goal_) { |
| 148 return false; // Not dirty. | 150 return false; // Not dirty. |
| 149 } | 151 } |
| 150 } | 152 } |
| 151 | 153 |
| 154 if (last_sample_.is_null()) |
| 155 return true; |
| 156 |
| 152 // If we're dirty but not yet old, then we've recently gotten updates, so we | 157 // If we're dirty but not yet old, then we've recently gotten updates, so we |
| 153 // won't request a sample just yet. | 158 // won't request a sample just yet. |
| 154 base::TimeDelta dirty_interval = event_time - last_sample_; | 159 base::TimeDelta dirty_interval = event_time - last_sample_; |
| 155 if (dirty_interval < capture_period_ * 4) | 160 if (dirty_interval < capture_period_ * 4) |
| 156 return false; | 161 return false; |
| 157 else | 162 else |
| 158 return true; | 163 return true; |
| 159 } | 164 } |
| 160 | 165 |
| 161 bool SmoothEventSampler::HasUnrecordedEvent() const { | 166 bool SmoothEventSampler::HasUnrecordedEvent() const { |
| 162 return !current_event_.is_null() && current_event_ != last_sample_; | 167 return !current_event_.is_null() && current_event_ != last_sample_; |
| 163 } | 168 } |
| 164 | 169 |
| 165 } // namespace content | 170 } // namespace content |
| OLD | NEW |