Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "media/filters/video_cadence_estimator.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <limits> | |
| 9 | |
| 10 namespace media { | |
| 11 | |
| 12 VideoCadenceEstimator::VideoCadenceEstimator( | |
| 13 base::TimeDelta minimum_time_until_glitch) | |
| 14 : cadence_hysteresis_enabled_(true), | |
| 15 minimum_time_until_glitch_(minimum_time_until_glitch) { | |
| 16 Reset(); | |
| 17 } | |
| 18 | |
| 19 VideoCadenceEstimator::~VideoCadenceEstimator() { | |
| 20 } | |
| 21 | |
| 22 void VideoCadenceEstimator::Reset() { | |
| 23 cadence_ = fractional_cadence_ = 0; | |
| 24 previous_cadence_ = previous_fractional_cadence_ = 0; | |
| 25 render_intervals_cadence_held_ = 0; | |
| 26 } | |
| 27 | |
| 28 bool VideoCadenceEstimator::UpdateCadenceEstimate( | |
| 29 base::TimeDelta render_interval, | |
| 30 base::TimeDelta frame_duration, | |
| 31 base::TimeDelta max_acceptable_drift) { | |
| 32 DCHECK_GT(render_interval, base::TimeDelta()); | |
| 33 DCHECK_GT(frame_duration, base::TimeDelta()); | |
| 34 | |
| 35 base::TimeDelta time_until_cadence_glitch; | |
| 36 base::TimeDelta time_until_fractional_cadence_glitch; | |
|
xhwang
2015/04/28 16:01:08
It seems these two are only for logging? Can we ju
DaleCurtis
2015/04/28 21:45:24
No, because we need both values for the log messag
xhwang
2015/04/28 22:17:39
Acknowledged.
| |
| 37 | |
| 38 // See if the clamped cadence fits acceptable thresholds for exhausting drift. | |
| 39 int new_cadence = 0, new_fractional_cadence = 0; | |
| 40 if (CalculateCadence(render_interval, frame_duration, max_acceptable_drift, | |
| 41 false, &new_cadence, &time_until_cadence_glitch)) { | |
|
xhwang
2015/04/28 16:01:08
DCHECK(new_cadence)?
DaleCurtis
2015/04/28 21:45:24
Done.
| |
| 42 } else if (CalculateCadence(render_interval, frame_duration, | |
| 43 max_acceptable_drift, true, | |
| 44 &new_fractional_cadence, | |
| 45 &time_until_fractional_cadence_glitch)) { | |
| 46 new_cadence = 1; | |
| 47 } | |
| 48 | |
| 49 // Nothing changed, so do nothing. | |
| 50 if (new_cadence == cadence_ && | |
| 51 new_fractional_cadence == fractional_cadence_) { | |
| 52 render_intervals_cadence_held_ = 0; | |
|
xhwang
2015/04/28 16:01:08
The comment says
132 // ... |render_intervals
DaleCurtis
2015/04/28 21:45:24
This prevents the previous cadence values from acc
| |
| 53 return false; | |
| 54 } | |
| 55 | |
| 56 if (!cadence_hysteresis_enabled_) { | |
| 57 cadence_ = new_cadence; | |
| 58 fractional_cadence_ = new_fractional_cadence; | |
| 59 return true; | |
| 60 } | |
| 61 | |
| 62 // Wait until enough render intervals have elapsed before accepting the | |
| 63 // cadence change. Prevents oscillation of the cadence selection. | |
| 64 if (new_cadence == previous_cadence_ && | |
|
xhwang
2015/04/28 16:01:08
|previous_cadence| is really a |pending_cadence_|
DaleCurtis
2015/04/28 21:45:24
Done.
| |
| 65 new_fractional_cadence == previous_fractional_cadence_) { | |
| 66 if (++render_intervals_cadence_held_ * render_interval >= | |
|
xhwang
2015/04/28 16:01:08
note: render_interval can be different every time
DaleCurtis
2015/04/28 21:45:24
Yup.
| |
| 67 base::TimeDelta::FromMilliseconds(kMinimumCadenceDurationMs)) { | |
| 68 DVLOG(1) << "Cadence switch: (" << cadence_ << ", " << fractional_cadence_ | |
| 69 << ") -> (" << new_cadence << ", " << new_fractional_cadence | |
| 70 << ") :: (" << time_until_cadence_glitch << ", " | |
| 71 << time_until_fractional_cadence_glitch << ")"; | |
| 72 | |
| 73 cadence_ = new_cadence; | |
| 74 fractional_cadence_ = new_fractional_cadence; | |
| 75 return true; | |
| 76 } else { | |
| 77 DVLOG(2) << "Hysteresis prevented cadence switch: (" << cadence_ << ", " | |
| 78 << fractional_cadence_ << ") -> (" << new_cadence << ", " | |
| 79 << new_fractional_cadence << ") :: (" | |
| 80 << time_until_cadence_glitch << ", " | |
| 81 << time_until_fractional_cadence_glitch << ")"; | |
|
xhwang
2015/04/28 16:01:08
nit: just return false here, so that you don't nee
DaleCurtis
2015/04/28 21:45:24
Done.
| |
| 82 } | |
| 83 } else { | |
| 84 previous_cadence_ = new_cadence; | |
| 85 previous_fractional_cadence_ = new_fractional_cadence; | |
| 86 render_intervals_cadence_held_ = 1; | |
|
xhwang
2015/04/28 16:01:08
If in the extreme case where cadence estimation os
DaleCurtis
2015/04/28 21:45:24
2.5 is pretty unlikely to clamp to 2 or 3, it exha
xhwang
2015/04/28 22:17:39
Acknowledged.
| |
| 87 } | |
| 88 | |
| 89 return false; | |
| 90 } | |
| 91 | |
| 92 bool VideoCadenceEstimator::CalculateCadence( | |
| 93 base::TimeDelta render_interval, | |
| 94 base::TimeDelta frame_duration, | |
| 95 base::TimeDelta max_acceptable_drift, | |
| 96 bool fractional, | |
| 97 int* cadence, | |
| 98 base::TimeDelta* time_until_glitch) { | |
| 99 *cadence = 0; | |
| 100 *time_until_glitch = base::TimeDelta(); | |
|
xhwang
2015/04/28 16:01:08
DCHECK instead of set?
DaleCurtis
2015/04/28 21:45:24
No, I want to clear them every time.
xhwang
2015/04/28 22:17:39
hmm, wondering why? The caller already initializes
DaleCurtis
2015/04/29 00:11:12
Actually, they don't need to be initialized here a
| |
| 101 | |
| 102 // The perfect cadence is the number of render intervals per frame, while the | |
| 103 // clamped cadence is the nearest matching integer cadence. | |
| 104 // | |
| 105 // Fractional cadence is checked to see if we have a cadence which would look | |
| 106 // best if we consistently drop the same frames. | |
| 107 // | |
| 108 // As mentioned in the introduction, |perfect_cadence| is the ratio of the | |
| 109 // frame duration to render interval length; while |clamped_cadence| is the | |
| 110 // nearest integer value to |perfect_cadence|. When computing a fractional | |
| 111 // cadence (1/|perfect_cadence|), |fractional| must be set to true to ensure | |
| 112 // the rendered and actual frame durations are computed correctly. | |
| 113 const double perfect_cadence = | |
| 114 fractional ? render_interval.InSecondsF() / frame_duration.InSecondsF() | |
| 115 : frame_duration.InSecondsF() / render_interval.InSecondsF(); | |
| 116 const int clamped_cadence = perfect_cadence + 0.5; | |
| 117 if (!clamped_cadence) | |
| 118 return false; | |
| 119 | |
| 120 // Calculate the drift in microseconds for each frame we render at cadence | |
| 121 // instead of for its real duration. | |
| 122 const base::TimeDelta rendered_frame_duration = | |
| 123 fractional ? render_interval : clamped_cadence * render_interval; | |
| 124 | |
| 125 // When computing a fractional drift, we render the first of |clamped_cadence| | |
| 126 // frames and drop |clamped_cadence| - 1 frames. To make the calculations | |
| 127 // below work we need to project out the timestamp of the frame which would be | |
| 128 // rendered after accounting for those |clamped_cadence| frames. | |
|
xhwang
2015/04/28 16:01:08
We are checking "fractional ?" in 3 places in this
DaleCurtis
2015/04/28 21:45:24
The math is already tricky, I'd rather not duplica
xhwang
2015/04/28 22:17:39
For me I have to read this function twice, one wit
DaleCurtis
2015/04/29 00:11:11
l.136, l.148 would end up in a third function with
| |
| 129 const base::TimeDelta actual_frame_duration = | |
| 130 fractional ? clamped_cadence * frame_duration : frame_duration; | |
| 131 if (rendered_frame_duration == actual_frame_duration) { | |
| 132 *cadence = clamped_cadence; | |
| 133 return true; | |
| 134 } | |
| 135 | |
| 136 // Compute how long it'll take to exhaust the drift using |clamped_cadence|. | |
| 137 const double duration_delta = std::abs( | |
| 138 (rendered_frame_duration - actual_frame_duration).InMicroseconds()); | |
| 139 const int64 frames_until_drift_exhausted = | |
| 140 std::ceil(max_acceptable_drift.InMicroseconds() / duration_delta); | |
| 141 *time_until_glitch = rendered_frame_duration * frames_until_drift_exhausted; | |
| 142 | |
| 143 if (*time_until_glitch >= minimum_time_until_glitch_) { | |
| 144 *cadence = clamped_cadence; | |
| 145 return true; | |
| 146 } | |
| 147 | |
| 148 return false; | |
| 149 } | |
| 150 | |
| 151 int VideoCadenceEstimator::GetCadenceForFrame(int index) const { | |
| 152 DCHECK(has_cadence()); | |
| 153 DCHECK_GE(index, 0); | |
| 154 | |
| 155 if (fractional_cadence_) | |
| 156 return index % fractional_cadence_ == 0 ? 1 : 0; | |
| 157 | |
| 158 return cadence_; | |
| 159 } | |
| 160 | |
| 161 } // namespace media | |
| OLD | NEW |