Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(197)

Side by Side Diff: media/filters/video_cadence_estimator.cc

Issue 1021943002: Introduce cadence based VideoRendererAlgorithm. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix frame expiry; add test. Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 // To prevent oscillation in and out of cadence or between cadence values, we
13 // require some time to elapse before a cadence switch is accepted.
14 const int kMinimumCadenceDurationMs = 100;
15
16 VideoCadenceEstimator::VideoCadenceEstimator(
17 base::TimeDelta minimum_time_until_glitch)
18 : cadence_hysteresis_threshold_(
19 base::TimeDelta::FromMilliseconds(kMinimumCadenceDurationMs)),
20 minimum_time_until_glitch_(minimum_time_until_glitch) {
21 Reset();
22 }
23
24 VideoCadenceEstimator::~VideoCadenceEstimator() {
25 }
26
27 void VideoCadenceEstimator::Reset() {
28 cadence_ = fractional_cadence_ = 0;
29 pending_cadence_ = pending_fractional_cadence_ = 0;
30 render_intervals_cadence_held_ = 0;
31 }
32
33 bool VideoCadenceEstimator::UpdateCadenceEstimate(
34 base::TimeDelta render_interval,
35 base::TimeDelta frame_duration,
36 base::TimeDelta max_acceptable_drift) {
37 DCHECK_GT(render_interval, base::TimeDelta());
38 DCHECK_GT(frame_duration, base::TimeDelta());
39
40 base::TimeDelta time_until_cadence_glitch;
41 base::TimeDelta time_until_fractional_cadence_glitch;
42
43 // See if the clamped cadence fits acceptable thresholds for exhausting drift.
44 int new_cadence = 0, new_fractional_cadence = 0;
45 if (CalculateCadence(render_interval, frame_duration, max_acceptable_drift,
46 false, &new_cadence, &time_until_cadence_glitch)) {
47 DCHECK(new_cadence);
48 } else if (CalculateCadence(render_interval, frame_duration,
49 max_acceptable_drift, true,
50 &new_fractional_cadence,
51 &time_until_fractional_cadence_glitch)) {
52 new_cadence = 1;
53 DCHECK(new_fractional_cadence);
54 }
55
56 // Nothing changed, so do nothing.
57 if (new_cadence == cadence_ &&
58 new_fractional_cadence == fractional_cadence_) {
59 // Clear cadence hold to pending values from accumulating incorrectly.
60 render_intervals_cadence_held_ = 0;
61 return false;
62 }
63
64 // Wait until enough render intervals have elapsed before accepting the
65 // cadence change. Prevents oscillation of the cadence selection.
66 bool update_pending_cadence = true;
67 if ((new_cadence == pending_cadence_ &&
68 new_fractional_cadence == pending_fractional_cadence_) ||
69 cadence_hysteresis_threshold_ <= render_interval) {
70 if (++render_intervals_cadence_held_ * render_interval >=
71 cadence_hysteresis_threshold_) {
72 DVLOG(1) << "Cadence switch: (" << cadence_ << ", " << fractional_cadence_
73 << ") -> (" << new_cadence << ", " << new_fractional_cadence
74 << ") :: (" << time_until_cadence_glitch << ", "
75 << time_until_fractional_cadence_glitch << ")";
76
77 cadence_ = new_cadence;
78 fractional_cadence_ = new_fractional_cadence;
79 return true;
80 }
81
82 update_pending_cadence = false;
83 }
84
85 DVLOG(2) << "Hysteresis prevented cadence switch: (" << cadence_ << ", "
86 << fractional_cadence_ << ") -> (" << new_cadence << ", "
87 << new_fractional_cadence << ") :: (" << time_until_cadence_glitch
88 << ", " << time_until_fractional_cadence_glitch << ")";
89
90 if (update_pending_cadence) {
91 pending_cadence_ = new_cadence;
92 pending_fractional_cadence_ = new_fractional_cadence;
93 render_intervals_cadence_held_ = 1;
94 }
95
96 return false;
97 }
98
99 bool VideoCadenceEstimator::CalculateCadence(
100 base::TimeDelta render_interval,
101 base::TimeDelta frame_duration,
102 base::TimeDelta max_acceptable_drift,
103 bool fractional,
104 int* cadence,
105 base::TimeDelta* time_until_glitch) {
106 // The perfect cadence is the number of render intervals per frame, while the
107 // clamped cadence is the nearest matching integer cadence.
108 //
109 // Fractional cadence is checked to see if we have a cadence which would look
110 // best if we consistently drop the same frames.
111 //
112 // As mentioned in the introduction, |perfect_cadence| is the ratio of the
113 // frame duration to render interval length; while |clamped_cadence| is the
114 // nearest integer value to |perfect_cadence|. When computing a fractional
115 // cadence (1/|perfect_cadence|), |fractional| must be set to true to ensure
116 // the rendered and actual frame durations are computed correctly.
117 const double perfect_cadence =
118 fractional ? render_interval.InSecondsF() / frame_duration.InSecondsF()
119 : frame_duration.InSecondsF() / render_interval.InSecondsF();
120 const int clamped_cadence = perfect_cadence + 0.5;
121 if (!clamped_cadence)
122 return false;
123
124 // Calculate the drift in microseconds for each frame we render at cadence
125 // instead of for its real duration.
126 const base::TimeDelta rendered_frame_duration =
127 fractional ? render_interval : clamped_cadence * render_interval;
128
129 // When computing a fractional drift, we render the first of |clamped_cadence|
130 // frames and drop |clamped_cadence| - 1 frames. To make the calculations
131 // below work we need to project out the timestamp of the frame which would be
132 // rendered after accounting for those |clamped_cadence| frames.
133 const base::TimeDelta actual_frame_duration =
134 fractional ? clamped_cadence * frame_duration : frame_duration;
135 if (rendered_frame_duration == actual_frame_duration) {
136 *cadence = clamped_cadence;
137 return true;
138 }
139
140 // Compute how long it'll take to exhaust the drift using |clamped_cadence|.
141 const double duration_delta = std::abs(
miu 2015/04/30 21:57:07 nit: Instead of std::abs((expr).InMicroseconds()),
DaleCurtis 2015/04/30 22:03:52 Done.
142 (rendered_frame_duration - actual_frame_duration).InMicroseconds());
143 const int64 frames_until_drift_exhausted =
144 std::ceil(max_acceptable_drift.InMicroseconds() / duration_delta);
145 *time_until_glitch = rendered_frame_duration * frames_until_drift_exhausted;
146
147 if (*time_until_glitch >= minimum_time_until_glitch_) {
148 *cadence = clamped_cadence;
149 return true;
150 }
151
152 return false;
153 }
154
155 int VideoCadenceEstimator::GetCadenceForFrame(int index) const {
156 DCHECK(has_cadence());
157 DCHECK_GE(index, 0);
158
159 if (fractional_cadence_)
160 return index % fractional_cadence_ == 0 ? 1 : 0;
161
162 return cadence_;
163 }
164
165 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/video_cadence_estimator.h ('k') | media/filters/video_cadence_estimator_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698