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

Unified 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 evaluation order. Created 5 years, 8 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 side-by-side diff with in-line comments
Download patch
« 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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/filters/video_cadence_estimator.cc
diff --git a/media/filters/video_cadence_estimator.cc b/media/filters/video_cadence_estimator.cc
new file mode 100644
index 0000000000000000000000000000000000000000..57b71b4392a9363afeb18fdd537d30cf1b00bd28
--- /dev/null
+++ b/media/filters/video_cadence_estimator.cc
@@ -0,0 +1,167 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/filters/video_cadence_estimator.h"
+
+#include <algorithm>
+#include <limits>
+
+namespace media {
+
+// To prevent oscillation in and out of cadence or between cadence values, we
+// require some time to elapse before a cadence switch is accepted.
+const int kMinimumCadenceDurationMs = 100;
+
+VideoCadenceEstimator::VideoCadenceEstimator(
+ base::TimeDelta minimum_time_until_glitch)
+ : cadence_hysteresis_threshold_(
+ base::TimeDelta::FromMilliseconds(kMinimumCadenceDurationMs)),
+ minimum_time_until_glitch_(minimum_time_until_glitch) {
+ Reset();
+}
+
+VideoCadenceEstimator::~VideoCadenceEstimator() {
+}
+
+void VideoCadenceEstimator::Reset() {
+ cadence_ = fractional_cadence_ = 0;
+ pending_cadence_ = pending_fractional_cadence_ = 0;
+ render_intervals_cadence_held_ = 0;
+}
+
+bool VideoCadenceEstimator::UpdateCadenceEstimate(
+ base::TimeDelta render_interval,
+ base::TimeDelta frame_duration,
+ base::TimeDelta max_acceptable_drift) {
+ DCHECK_GT(render_interval, base::TimeDelta());
+ DCHECK_GT(frame_duration, base::TimeDelta());
+
+ base::TimeDelta time_until_cadence_glitch;
+ base::TimeDelta time_until_fractional_cadence_glitch;
+
+ // See if the clamped cadence fits acceptable thresholds for exhausting drift.
+ int new_cadence = 0, new_fractional_cadence = 0;
+ if (CalculateCadence(render_interval, frame_duration, max_acceptable_drift,
+ false, &new_cadence, &time_until_cadence_glitch)) {
+ DCHECK(new_cadence);
+ } else if (CalculateCadence(render_interval, frame_duration,
+ max_acceptable_drift, true,
+ &new_fractional_cadence,
+ &time_until_fractional_cadence_glitch)) {
+ new_cadence = 1;
+ DCHECK(new_fractional_cadence);
+ }
+
+ // Nothing changed, so do nothing.
+ if (new_cadence == cadence_ &&
+ new_fractional_cadence == fractional_cadence_) {
+ // Clear cadence hold to pending values from accumulating incorrectly.
+ render_intervals_cadence_held_ = 0;
+ return false;
+ }
+
+ // Wait until enough render intervals have elapsed before accepting the
+ // cadence change. Prevents oscillation of the cadence selection.
+ bool update_pending_cadence = true;
+ if ((new_cadence == pending_cadence_ &&
+ new_fractional_cadence == pending_fractional_cadence_) ||
+ cadence_hysteresis_threshold_ <= render_interval) {
+ if (++render_intervals_cadence_held_ * render_interval >=
+ cadence_hysteresis_threshold_) {
+ DVLOG(1) << "Cadence switch: (" << cadence_ << ", " << fractional_cadence_
+ << ") -> (" << new_cadence << ", " << new_fractional_cadence
+ << ") :: (" << time_until_cadence_glitch << ", "
+ << time_until_fractional_cadence_glitch << ")";
+
+ cadence_ = new_cadence;
+ fractional_cadence_ = new_fractional_cadence;
+ return true;
+ }
+
+ update_pending_cadence = false;
+ }
+
+ DVLOG(2) << "Hysteresis prevented cadence switch: (" << cadence_ << ", "
+ << fractional_cadence_ << ") -> (" << new_cadence << ", "
+ << new_fractional_cadence << ") :: (" << time_until_cadence_glitch
+ << ", " << time_until_fractional_cadence_glitch << ")";
+
+ if (update_pending_cadence) {
+ pending_cadence_ = new_cadence;
+ pending_fractional_cadence_ = new_fractional_cadence;
+ render_intervals_cadence_held_ = 1;
+ }
+
+ return false;
+}
+
+bool VideoCadenceEstimator::CalculateCadence(
+ base::TimeDelta render_interval,
+ base::TimeDelta frame_duration,
+ base::TimeDelta max_acceptable_drift,
+ bool fractional,
+ int* cadence,
+ base::TimeDelta* time_until_glitch) {
+ // The perfect cadence is the number of render intervals per frame, while the
+ // clamped cadence is the nearest matching integer cadence.
+ //
+ // Fractional cadence is checked to see if we have a cadence which would look
+ // best if we consistently drop the same frames.
+ //
+ // As mentioned in the introduction, |perfect_cadence| is the ratio of the
+ // frame duration to render interval length; while |clamped_cadence| is the
+ // nearest integer value to |perfect_cadence|. When computing a fractional
+ // cadence (1/|perfect_cadence|), |fractional| must be set to true to ensure
+ // the rendered and actual frame durations are computed correctly.
+ const double perfect_cadence =
+ fractional ? render_interval.InSecondsF() / frame_duration.InSecondsF()
+ : frame_duration.InSecondsF() / render_interval.InSecondsF();
+ const int clamped_cadence = perfect_cadence + 0.5;
+ if (!clamped_cadence)
+ return false;
+
+ // Calculate the drift in microseconds for each frame we render at cadence
+ // instead of for its real duration.
+ const base::TimeDelta rendered_frame_duration =
+ fractional ? render_interval : clamped_cadence * render_interval;
+
+ // When computing a fractional drift, we render the first of |clamped_cadence|
+ // frames and drop |clamped_cadence| - 1 frames. To make the calculations
+ // below work we need to project out the timestamp of the frame which would be
+ // rendered after accounting for those |clamped_cadence| frames.
+ const base::TimeDelta actual_frame_duration =
+ fractional ? clamped_cadence * frame_duration : frame_duration;
+ if (rendered_frame_duration == actual_frame_duration) {
+ *cadence = clamped_cadence;
+ return true;
+ }
+
+ // Compute how long it'll take to exhaust the drift using |clamped_cadence|.
+ const double duration_delta =
+ (rendered_frame_duration - actual_frame_duration)
+ .magnitude()
+ .InMicroseconds();
+ const int64 frames_until_drift_exhausted =
+ std::ceil(max_acceptable_drift.InMicroseconds() / duration_delta);
+ *time_until_glitch = rendered_frame_duration * frames_until_drift_exhausted;
+
+ if (*time_until_glitch >= minimum_time_until_glitch_) {
+ *cadence = clamped_cadence;
+ return true;
+ }
+
+ return false;
+}
+
+int VideoCadenceEstimator::GetCadenceForFrame(int index) const {
+ DCHECK(has_cadence());
+ DCHECK_GE(index, 0);
+
+ if (fractional_cadence_)
+ return index % fractional_cadence_ == 0 ? 1 : 0;
+
+ return cadence_;
+}
+
+} // namespace media
« 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