| 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 |