OLD | NEW |
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/animated_content_sampler.h" | 5 #include "media/capture/content/animated_content_sampler.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 namespace media { | 9 namespace media { |
10 | 10 |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
153 base::TimeDelta::FromMilliseconds(kMaxObservationWindowMillis); | 153 base::TimeDelta::FromMilliseconds(kMaxObservationWindowMillis); |
154 while ((event_time - observations_.front().event_time) > threshold) | 154 while ((event_time - observations_.front().event_time) > threshold) |
155 observations_.pop_front(); | 155 observations_.pop_front(); |
156 } | 156 } |
157 | 157 |
158 gfx::Rect AnimatedContentSampler::ElectMajorityDamageRect() const { | 158 gfx::Rect AnimatedContentSampler::ElectMajorityDamageRect() const { |
159 // This is an derivative of the Boyer-Moore Majority Vote Algorithm where each | 159 // This is an derivative of the Boyer-Moore Majority Vote Algorithm where each |
160 // pixel in a candidate gets one vote, as opposed to each candidate getting | 160 // pixel in a candidate gets one vote, as opposed to each candidate getting |
161 // one vote. | 161 // one vote. |
162 const gfx::Rect* candidate = NULL; | 162 const gfx::Rect* candidate = NULL; |
163 int64 votes = 0; | 163 int64_t votes = 0; |
164 for (ObservationFifo::const_iterator i = observations_.begin(); | 164 for (ObservationFifo::const_iterator i = observations_.begin(); |
165 i != observations_.end(); ++i) { | 165 i != observations_.end(); ++i) { |
166 DCHECK_GT(i->damage_rect.size().GetArea(), 0); | 166 DCHECK_GT(i->damage_rect.size().GetArea(), 0); |
167 if (votes == 0) { | 167 if (votes == 0) { |
168 candidate = &(i->damage_rect); | 168 candidate = &(i->damage_rect); |
169 votes = candidate->size().GetArea(); | 169 votes = candidate->size().GetArea(); |
170 } else if (i->damage_rect == *candidate) { | 170 } else if (i->damage_rect == *candidate) { |
171 votes += i->damage_rect.size().GetArea(); | 171 votes += i->damage_rect.size().GetArea(); |
172 } else { | 172 } else { |
173 votes -= i->damage_rect.size().GetArea(); | 173 votes -= i->damage_rect.size().GetArea(); |
(...skipping 10 matching lines...) Expand all Loading... |
184 base::TimeTicks event_time, | 184 base::TimeTicks event_time, |
185 gfx::Rect* rect, | 185 gfx::Rect* rect, |
186 base::TimeDelta* period) const { | 186 base::TimeDelta* period) const { |
187 const gfx::Rect elected_rect = ElectMajorityDamageRect(); | 187 const gfx::Rect elected_rect = ElectMajorityDamageRect(); |
188 if (elected_rect.IsEmpty()) | 188 if (elected_rect.IsEmpty()) |
189 return false; // There is no regular animation present. | 189 return false; // There is no regular animation present. |
190 | 190 |
191 // Scan |observations_|, gathering metrics about the ones having a damage Rect | 191 // Scan |observations_|, gathering metrics about the ones having a damage Rect |
192 // equivalent to the |elected_rect|. Along the way, break early whenever the | 192 // equivalent to the |elected_rect|. Along the way, break early whenever the |
193 // event times reveal a non-animating period. | 193 // event times reveal a non-animating period. |
194 int64 num_pixels_damaged_in_all = 0; | 194 int64_t num_pixels_damaged_in_all = 0; |
195 int64 num_pixels_damaged_in_chosen = 0; | 195 int64_t num_pixels_damaged_in_chosen = 0; |
196 base::TimeDelta sum_frame_durations; | 196 base::TimeDelta sum_frame_durations; |
197 size_t count_frame_durations = 0; | 197 size_t count_frame_durations = 0; |
198 base::TimeTicks first_event_time; | 198 base::TimeTicks first_event_time; |
199 base::TimeTicks last_event_time; | 199 base::TimeTicks last_event_time; |
200 for (ObservationFifo::const_reverse_iterator i = observations_.rbegin(); | 200 for (ObservationFifo::const_reverse_iterator i = observations_.rbegin(); |
201 i != observations_.rend(); ++i) { | 201 i != observations_.rend(); ++i) { |
202 const int area = i->damage_rect.size().GetArea(); | 202 const int area = i->damage_rect.size().GetArea(); |
203 num_pixels_damaged_in_all += area; | 203 num_pixels_damaged_in_all += area; |
204 if (i->damage_rect != elected_rect) | 204 if (i->damage_rect != elected_rect) |
205 continue; | 205 continue; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 const base::TimeTicks ideal_timestamp = frame_timestamp_ + sampling_period_; | 241 const base::TimeTicks ideal_timestamp = frame_timestamp_ + sampling_period_; |
242 | 242 |
243 // Account for two main sources of drift: 1) The clock drift of the system | 243 // Account for two main sources of drift: 1) The clock drift of the system |
244 // clock relative to the video hardware, which affects the event times; and | 244 // clock relative to the video hardware, which affects the event times; and |
245 // 2) The small error introduced by this frame timestamp rewriting, as it is | 245 // 2) The small error introduced by this frame timestamp rewriting, as it is |
246 // based on averaging over recent events. | 246 // based on averaging over recent events. |
247 // | 247 // |
248 // TODO(miu): This is similar to the ClockSmoother in | 248 // TODO(miu): This is similar to the ClockSmoother in |
249 // media/base/audio_shifter.cc. Consider refactor-and-reuse here. | 249 // media/base/audio_shifter.cc. Consider refactor-and-reuse here. |
250 const base::TimeDelta drift = ideal_timestamp - event_time; | 250 const base::TimeDelta drift = ideal_timestamp - event_time; |
251 const int64 correct_over_num_frames = | 251 const int64_t correct_over_num_frames = |
252 base::TimeDelta::FromMilliseconds(kDriftCorrectionMillis) / | 252 base::TimeDelta::FromMilliseconds(kDriftCorrectionMillis) / |
253 sampling_period_; | 253 sampling_period_; |
254 DCHECK_GT(correct_over_num_frames, 0); | 254 DCHECK_GT(correct_over_num_frames, 0); |
255 | 255 |
256 return ideal_timestamp - drift / correct_over_num_frames; | 256 return ideal_timestamp - drift / correct_over_num_frames; |
257 } | 257 } |
258 | 258 |
259 // static | 259 // static |
260 base::TimeDelta AnimatedContentSampler::ComputeSamplingPeriod( | 260 base::TimeDelta AnimatedContentSampler::ComputeSamplingPeriod( |
261 base::TimeDelta animation_period, | 261 base::TimeDelta animation_period, |
262 base::TimeDelta target_sampling_period, | 262 base::TimeDelta target_sampling_period, |
263 base::TimeDelta min_capture_period) { | 263 base::TimeDelta min_capture_period) { |
264 // If the animation rate is unknown, return the ideal sampling period. | 264 // If the animation rate is unknown, return the ideal sampling period. |
265 if (animation_period == base::TimeDelta()) { | 265 if (animation_period == base::TimeDelta()) { |
266 return std::max(target_sampling_period, min_capture_period); | 266 return std::max(target_sampling_period, min_capture_period); |
267 } | 267 } |
268 | 268 |
269 // Determine whether subsampling is needed. If so, compute the sampling | 269 // Determine whether subsampling is needed. If so, compute the sampling |
270 // period corresponding to the sampling rate is the closest integer division | 270 // period corresponding to the sampling rate is the closest integer division |
271 // of the animation frame rate to the target sampling rate. | 271 // of the animation frame rate to the target sampling rate. |
272 // | 272 // |
273 // For example, consider a target sampling rate of 30 FPS and an animation | 273 // For example, consider a target sampling rate of 30 FPS and an animation |
274 // rate of 42 FPS. Possible sampling rates would be 42/1 = 42, 42/2 = 21, | 274 // rate of 42 FPS. Possible sampling rates would be 42/1 = 42, 42/2 = 21, |
275 // 42/3 = 14, and so on. Of these candidates, 21 FPS is closest to 30. | 275 // 42/3 = 14, and so on. Of these candidates, 21 FPS is closest to 30. |
276 base::TimeDelta sampling_period; | 276 base::TimeDelta sampling_period; |
277 if (animation_period < target_sampling_period) { | 277 if (animation_period < target_sampling_period) { |
278 const int64 ratio = target_sampling_period / animation_period; | 278 const int64_t ratio = target_sampling_period / animation_period; |
279 const double target_fps = 1.0 / target_sampling_period.InSecondsF(); | 279 const double target_fps = 1.0 / target_sampling_period.InSecondsF(); |
280 const double animation_fps = 1.0 / animation_period.InSecondsF(); | 280 const double animation_fps = 1.0 / animation_period.InSecondsF(); |
281 if (std::abs(animation_fps / ratio - target_fps) < | 281 if (std::abs(animation_fps / ratio - target_fps) < |
282 std::abs(animation_fps / (ratio + 1) - target_fps)) { | 282 std::abs(animation_fps / (ratio + 1) - target_fps)) { |
283 sampling_period = ratio * animation_period; | 283 sampling_period = ratio * animation_period; |
284 } else { | 284 } else { |
285 sampling_period = (ratio + 1) * animation_period; | 285 sampling_period = (ratio + 1) * animation_period; |
286 } | 286 } |
287 } else { | 287 } else { |
288 sampling_period = animation_period; | 288 sampling_period = animation_period; |
289 } | 289 } |
290 return std::max(sampling_period, min_capture_period); | 290 return std::max(sampling_period, min_capture_period); |
291 } | 291 } |
292 | 292 |
293 } // namespace media | 293 } // namespace media |
OLD | NEW |