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

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: Comments. 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 *cadence = 0;
107 *time_until_glitch = base::TimeDelta();
108
109 // The perfect cadence is the number of render intervals per frame, while the
110 // clamped cadence is the nearest matching integer cadence.
111 //
112 // Fractional cadence is checked to see if we have a cadence which would look
113 // best if we consistently drop the same frames.
114 //
115 // As mentioned in the introduction, |perfect_cadence| is the ratio of the
116 // frame duration to render interval length; while |clamped_cadence| is the
117 // nearest integer value to |perfect_cadence|. When computing a fractional
118 // cadence (1/|perfect_cadence|), |fractional| must be set to true to ensure
119 // the rendered and actual frame durations are computed correctly.
120 const double perfect_cadence =
121 fractional ? render_interval.InSecondsF() / frame_duration.InSecondsF()
122 : frame_duration.InSecondsF() / render_interval.InSecondsF();
123 const int clamped_cadence = perfect_cadence + 0.5;
124 if (!clamped_cadence)
125 return false;
126
127 // Calculate the drift in microseconds for each frame we render at cadence
128 // instead of for its real duration.
129 const base::TimeDelta rendered_frame_duration =
130 fractional ? render_interval : clamped_cadence * render_interval;
131
132 // When computing a fractional drift, we render the first of |clamped_cadence|
133 // frames and drop |clamped_cadence| - 1 frames. To make the calculations
134 // below work we need to project out the timestamp of the frame which would be
135 // rendered after accounting for those |clamped_cadence| frames.
136 const base::TimeDelta actual_frame_duration =
137 fractional ? clamped_cadence * frame_duration : frame_duration;
138 if (rendered_frame_duration == actual_frame_duration) {
139 *cadence = clamped_cadence;
140 return true;
141 }
142
143 // Compute how long it'll take to exhaust the drift using |clamped_cadence|.
144 const double duration_delta = std::abs(
145 (rendered_frame_duration - actual_frame_duration).InMicroseconds());
146 const int64 frames_until_drift_exhausted =
147 std::ceil(max_acceptable_drift.InMicroseconds() / duration_delta);
148 *time_until_glitch = rendered_frame_duration * frames_until_drift_exhausted;
149
150 if (*time_until_glitch >= minimum_time_until_glitch_) {
151 *cadence = clamped_cadence;
152 return true;
153 }
154
155 return false;
156 }
157
158 int VideoCadenceEstimator::GetCadenceForFrame(int index) const {
159 DCHECK(has_cadence());
160 DCHECK_GE(index, 0);
161
162 if (fractional_cadence_)
163 return index % fractional_cadence_ == 0 ? 1 : 0;
164
165 return cadence_;
166 }
167
168 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698