summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorqiangchen <qiangchen@chromium.org>2015-09-04 11:43:09 -0700
committerCommit bot <commit-bot@chromium.org>2015-09-04 18:43:45 +0000
commitfe54fc3265fc227211c32be5c798e75c58b661eb (patch)
treec73cf1b3e43cbfda1544c6395988b2f40242f949 /media
parentc68e7f17624ce2cfac7474a6963dcd78b3335e05 (diff)
downloadchromium_src-fe54fc3265fc227211c32be5c798e75c58b661eb.zip
chromium_src-fe54fc3265fc227211c32be5c798e75c58b661eb.tar.gz
chromium_src-fe54fc3265fc227211c32be5c798e75c58b661eb.tar.bz2
Cadence Estimator Enhancement
Support up to 5-frame Cadence estimate. Review URL: https://codereview.chromium.org/1293273003 Cr-Commit-Position: refs/heads/master@{#347450}
Diffstat (limited to 'media')
-rw-r--r--media/filters/video_cadence_estimator.cc200
-rw-r--r--media/filters/video_cadence_estimator.h78
-rw-r--r--media/filters/video_cadence_estimator_unittest.cc58
-rw-r--r--media/filters/video_renderer_algorithm_unittest.cc48
4 files changed, 168 insertions, 216 deletions
diff --git a/media/filters/video_cadence_estimator.cc b/media/filters/video_cadence_estimator.cc
index bad4fd0..fbbe836 100644
--- a/media/filters/video_cadence_estimator.cc
+++ b/media/filters/video_cadence_estimator.cc
@@ -5,6 +5,7 @@
#include "media/filters/video_cadence_estimator.h"
#include <algorithm>
+#include <cmath>
#include <iterator>
#include <limits>
#include <string>
@@ -25,6 +26,42 @@ static void HistogramCadenceChangeCount(int cadence_changes) {
kCadenceChangeMax);
}
+// Construct a Cadence vector, a vector of integers satisfying the following
+// conditions:
+// 1. Size is |n|.
+// 2. Sum of entries is |k|.
+// 3. Each entry is in {|k|/|n|, |k|/|n| + 1}.
+// 4. Distribution of |k|/|n| and |k|/|n| + 1 is as even as possible.
+VideoCadenceEstimator::Cadence ConstructCadence(int k, int n) {
+ const int quotient = k / n;
+ std::vector<int> output(n, 0);
+
+ // Fill the vector entries with |quotient| or |quotient + 1|, and make sure
+ // the two values are distributed as evenly as possible.
+ int target_accumulate = 0;
+ int actual_accumulate = 0;
+ for (int i = 0; i < n; ++i) {
+ // After each loop
+ // target_accumulate = (i + 1) * k
+ // actual_accumulate = \sum_{j = 0}^i {n * V[j]} where V is output vector
+ // We want to make actual_accumulate as close to target_accumulate as
+ // possible.
+ // One exception is that in case k < n, we always want the vector to start
+ // with 1 to make sure the first frame is always rendered.
+ // (To avoid float calculation, we use scaled version of accumulated count)
+ target_accumulate += k;
+ const int target_current = target_accumulate - actual_accumulate;
+ if ((i == 0 && k < n) || target_current * 2 >= n * (quotient * 2 + 1)) {
+ output[i] = quotient + 1;
+ } else {
+ output[i] = quotient;
+ }
+ actual_accumulate += output[i] * n;
+ }
+
+ return output;
+}
+
VideoCadenceEstimator::VideoCadenceEstimator(
base::TimeDelta minimum_time_until_max_drift)
: cadence_hysteresis_threshold_(
@@ -116,109 +153,58 @@ VideoCadenceEstimator::Cadence VideoCadenceEstimator::CalculateCadence(
base::TimeDelta frame_duration,
base::TimeDelta max_acceptable_drift,
base::TimeDelta* time_until_max_drift) const {
- // See if we can find a cadence which fits the data.
- Cadence result;
- if (CalculateOneFrameCadence(render_interval, frame_duration,
- max_acceptable_drift, &result,
- time_until_max_drift)) {
- DCHECK_EQ(1u, result.size());
- } else if (CalculateFractionalCadence(render_interval, frame_duration,
- max_acceptable_drift, &result,
- time_until_max_drift)) {
- DCHECK(!result.empty());
- } else if (CalculateOneFrameCadence(render_interval, frame_duration * 2,
- max_acceptable_drift, &result,
- time_until_max_drift)) {
- // By finding cadence for double the frame duration, we're saying there
- // exist two integers a and b, where a > b and a + b = |result|; this
- // matches all patterns which regularly have half a frame per render
- // interval; i.e. 24fps in 60hz.
- DCHECK_EQ(1u, result.size());
-
- // While we may find a two pattern cadence, sometimes one extra frame
- // duration is enough to allow a match for 1-frame cadence if the
- // |time_until_max_drift| was on the edge.
- //
- // All 2-frame cadence values should be odd, so we can detect this and fall
- // back to 1-frame cadence when this occurs.
- if (result[0] & 1) {
- result[0] = std::ceil(result[0] / 2.0);
- result.push_back(result[0] - 1);
- } else {
- result[0] /= 2;
- }
- }
- return result;
-}
+ DCHECK_LT(max_acceptable_drift, minimum_time_until_max_drift_);
-bool VideoCadenceEstimator::CalculateOneFrameCadence(
- base::TimeDelta render_interval,
- base::TimeDelta frame_duration,
- base::TimeDelta max_acceptable_drift,
- Cadence* cadence,
- base::TimeDelta* time_until_max_drift) const {
- DCHECK(cadence->empty());
-
- // The perfect cadence is the number of render intervals per frame, while the
- // clamped cadence is the nearest matching integer value.
- //
- // 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|.
+ // The perfect cadence is the number of render intervals per frame.
const double perfect_cadence =
frame_duration.InSecondsF() / render_interval.InSecondsF();
- const int clamped_cadence = perfect_cadence + 0.5;
- if (!clamped_cadence)
- return false;
- // For cadence based rendering the actual frame duration is just the frame
- // duration, while the |rendered_frame_duration| is how long the frame would
- // be displayed for if we rendered it |clamped_cadence| times.
- const base::TimeDelta rendered_frame_duration =
- clamped_cadence * render_interval;
- if (!IsAcceptableCadence(rendered_frame_duration, frame_duration,
- max_acceptable_drift, time_until_max_drift)) {
- return false;
+ // We want to construct a cadence pattern to approximate the perfect cadence
+ // while ensuring error doesn't accumulate too quickly.
+ const double drift_ratio = max_acceptable_drift.InSecondsF() /
+ minimum_time_until_max_drift_.InSecondsF();
+ const double minimum_acceptable_cadence =
+ perfect_cadence / (1.0 + drift_ratio);
+ const double maximum_acceptable_cadence =
+ perfect_cadence / (1.0 - drift_ratio);
+
+ // We've arbitrarily chosen the maximum allowable cadence length as 5. It's
+ // proven sufficient to support most standard frame and render rates, while
+ // being small enough that small frame and render timing errors don't render
+ // it useless.
+ const int kMaxCadenceSize = 5;
+
+ double best_error = 0;
+ int best_n = 0;
+ int best_k = 0;
+ for (int n = 1; n <= kMaxCadenceSize; ++n) {
+ // A cadence pattern only exists if there exists an integer K such that K/N
+ // is between |minimum_acceptable_cadence| and |maximum_acceptable_cadence|.
+ // The best pattern is the one with the smallest error over time relative to
+ // the |perfect_cadence|.
+ if (std::floor(minimum_acceptable_cadence * n) <
+ std::floor(maximum_acceptable_cadence * n)) {
+ const int k = round(perfect_cadence * n);
+
+ const double error = std::fabs(1.0 - perfect_cadence * n / k);
+
+ // Prefer the shorter cadence pattern unless a longer one "significantly"
+ // reduces the error.
+ if (!best_n || error < best_error * 0.99) {
+ best_error = error;
+ best_k = k;
+ best_n = n;
+ }
+ }
}
- cadence->push_back(clamped_cadence);
- return true;
-}
-
-bool VideoCadenceEstimator::CalculateFractionalCadence(
- base::TimeDelta render_interval,
- base::TimeDelta frame_duration,
- base::TimeDelta max_acceptable_drift,
- Cadence* cadence,
- base::TimeDelta* time_until_max_drift) const {
- DCHECK(cadence->empty());
-
- // Fractional cadence allows us to see if we have a cadence which would look
- // best if we consistently drop the same frames.
- //
- // In this case, the perfect cadence is the number of frames per render
- // interval, while the clamped cadence is the nearest integer value.
- const double perfect_cadence =
- render_interval.InSecondsF() / frame_duration.InSecondsF();
- const int clamped_cadence = perfect_cadence + 0.5;
- if (!clamped_cadence)
- return false;
+ if (!best_n) return Cadence();
- // For fractional cadence, the rendered duration of each frame is just the
- // render interval. While the actual frame duration is the total duration of
- // all the frames we would end up dropping during that time.
- const base::TimeDelta actual_frame_duration =
- clamped_cadence * frame_duration;
- if (!IsAcceptableCadence(render_interval, actual_frame_duration,
- max_acceptable_drift, time_until_max_drift)) {
- return false;
- }
+ // If we've found a solution.
+ Cadence best_result = ConstructCadence(best_k, best_n);
+ *time_until_max_drift = max_acceptable_drift / best_error;
- // Fractional cadence means we render the first of |clamped_cadence| frames
- // and drop |clamped_cadence| - 1 frames.
- cadence->insert(cadence->begin(), clamped_cadence, 0);
- (*cadence)[0] = 1;
- return true;
+ return best_result;
}
std::string VideoCadenceEstimator::CadenceToString(
@@ -234,28 +220,4 @@ std::string VideoCadenceEstimator::CadenceToString(
return os.str();
}
-bool VideoCadenceEstimator::IsAcceptableCadence(
- base::TimeDelta rendered_frame_duration,
- base::TimeDelta actual_frame_duration,
- base::TimeDelta max_acceptable_drift,
- base::TimeDelta* time_until_max_drift) const {
- if (rendered_frame_duration == actual_frame_duration)
- return true;
-
- // Compute how long it'll take to exhaust the drift if frames are rendered for
- // |rendered_frame_duration| instead of |actual_frame_duration|.
- 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);
-
- // If the time until a frame would be repeated or dropped is greater than our
- // limit of acceptability, the cadence is acceptable.
- *time_until_max_drift =
- rendered_frame_duration * frames_until_drift_exhausted;
- return *time_until_max_drift >= minimum_time_until_max_drift_;
-}
-
} // namespace media
diff --git a/media/filters/video_cadence_estimator.h b/media/filters/video_cadence_estimator.h
index 89b2436..b1a79e6 100644
--- a/media/filters/video_cadence_estimator.h
+++ b/media/filters/video_cadence_estimator.h
@@ -17,8 +17,8 @@ namespace media {
// durations over time.
//
// Cadence is the ideal repeating frame pattern for a group of frames; currently
-// VideoCadenceEstimator supports 1-frame ([N]), 2-frame ([3:2]), and N-frame
-// fractional ([1:0:...:0]) cadences. Details on what this means are below.
+// VideoCadenceEstimator supports N-frame ([a1:a2:..:aN]) cadences where N <= 5.
+// Details on what this means are below.
//
// The perfect cadence of a set of frames is the ratio of the frame duration to
// render interval length. I.e. for 30fps in 60Hz the cadence would be (1/30) /
@@ -38,37 +38,33 @@ namespace media {
// shortening or lengthening the actual rendered frame duration. Doing so
// ensures each frame gets an optimal amount of display time.
//
+// For N-frame cadence, the idea is similar, we just round the perfect cadence
+// to some K/N, where K is an integer, and distribute [floor(K/N), floor(K/N)+1]
+// into the cadence vector as evenly as possible. For example, 23.97fps in
+// 60Hz, the perfect cadence is 2.50313, we can round it to 2.5 = 5/2, and we
+// can then construct the cadence vector as [2:3].
+//
// The delta between the perfect cadence and the rounded cadence leads to drift
// over time of the actual VideoFrame timestamp relative to its rendered time,
// so we perform some calculations to ensure we only use a cadence when it will
// take some time to drift an undesirable amount; see CalculateCadence() for
// details on how this calculation is made.
//
-// 2-frame cadence is an extension of 1-frame cadence. Consider the case of
-// 24fps in 60Hz, which has a perfect cadence of 2.5; rounding up to a cadence
-// of 3 would cause drift to accumulate unusably fast. A better approximation
-// of this cadence would be [3:2].
-//
-// Fractional cadence is a special case of N-frame cadence which can be used
-// when the frame duration is shorter than the render interval; e.g. 120fps in
-// 60Hz. In this case, the first frame in each group of N frames is displayed
-// once, while the next N - 1 frames are dropped; i.e. the cadence is of the
-// form [1:0:..:0]. Using the previous example N = 120/60 = 2, which means the
-// cadence would be [1:0]. See CalculateFractionalCadence() for more details.
-//
// In practice this works out to the following for common setups if we use
// cadence based selection:
//
// 29.5fps in 60Hz, ~17ms max drift => exhausted in ~1 second.
// 29.9fps in 60Hz, ~17ms max drift => exhausted in ~16.4 seconds.
-// 24fps in 60Hz, ~21ms max drift => exhausted in ~0.15 seconds.
-// 25fps in 60Hz, 20ms max drift => exhausted in ~4.0 seconds.
-// 59.9fps in 60Hz, ~8.3ms max drift => exhausted in ~8.2 seconds.
+// 24fps in 59.9Hz, ~21ms max drift => exhausted in ~12.6 seconds.
+// 24.9fps in 60Hz, ~20ms max drift => exhausted in ~4.0 seconds.
+// 59.9fps in 60Hz, ~8.3ms max drift => exhausted in ~8.2 seconds.
// 24.9fps in 50Hz, ~20ms max drift => exhausted in ~20.5 seconds.
-// 120fps in 59.9Hz, ~8.3ms max drift => exhausted in ~8.2 seconds.
+// 120fps in 59.9Hz, ~8.3ms max drift => exhausted in ~8.2 seconds.
//
class MEDIA_EXPORT VideoCadenceEstimator {
public:
+ using Cadence = std::vector<int>;
+
// As mentioned in the introduction, the determination of whether to clamp to
// a given cadence is based on how long it takes before a frame would have to
// be dropped or repeated to compensate for reaching the maximum acceptable
@@ -116,54 +112,20 @@ class MEDIA_EXPORT VideoCadenceEstimator {
std::string GetCadenceForTesting() const { return CadenceToString(cadence_); }
private:
- using Cadence = std::vector<int>;
-
- // Attempts to find a 1-frame, 2-frame, or N-frame fractional cadence; returns
- // the cadence vector if cadence is found and sets |time_until_max_drift| for
- // the computed cadence.
+ // Attempts to find an N-frame cadence. Returns the cadence vector if cadence
+ // is found and sets |time_until_max_drift| for the computed cadence. If
+ // multiple cadences satisfying the max drift constraint exist, we are going
+ // to return the one with largest |time_until_max_drift|.
+ // For details on the math and algorithm, see https://goo.gl/QK0vbz
Cadence CalculateCadence(base::TimeDelta render_interval,
base::TimeDelta frame_duration,
base::TimeDelta max_acceptable_drift,
base::TimeDelta* time_until_max_drift) const;
- // Calculates the clamped cadence for the given |render_interval| and
- // |frame_duration|, then calculates how long that cadence can be used before
- // exhausting |max_acceptable_drift|. If the time until exhaustion is greater
- // than |minimum_time_until_max_drift_|, returns true and sets |cadence| to
- // the clamped cadence. If the clamped cadence is unusable, |cadence| will be
- // set to zero.
- //
- // Sets |time_until_max_drift| to the computed glitch time. Set to zero if
- // the clamped cadence is unusable.
- bool CalculateOneFrameCadence(base::TimeDelta render_interval,
- base::TimeDelta frame_duration,
- base::TimeDelta max_acceptable_drift,
- Cadence* cadence,
- base::TimeDelta* time_until_max_drift) const;
-
- // Similar to CalculateCadence() except it tries to find the ideal number of
- // frames which can fit into a |render_interval|; which means doing the same
- // calculations as CalculateCadence() but with the ratio of |render_interval|
- // to |frame_duration| instead of the other way around.
- bool CalculateFractionalCadence(base::TimeDelta render_interval,
- base::TimeDelta frame_duration,
- base::TimeDelta max_acceptable_drift,
- Cadence* cadence,
- base::TimeDelta* time_until_max_drift) const;
-
// Converts a cadence vector into a human readable string of the form
- // "[a, b, ..., z]".
+ // "[a: b: ...: z]".
std::string CadenceToString(const Cadence& cadence) const;
- // Returns true if the drift of the rendered frame duration versus its actual
- // frame duration take longer than |minimum_time_until_max_drift_| to exhaust
- // |max_acceptable_drift|. |time_until_max_drift| is set to how long it will
- // take before a glitch (frame drop or repeat occurs).
- bool IsAcceptableCadence(base::TimeDelta rendered_frame_duration,
- base::TimeDelta actual_frame_duration,
- base::TimeDelta max_acceptable_drift,
- base::TimeDelta* time_until_max_drift) const;
-
// The approximate best N-frame cadence for all frames seen thus far; updated
// by UpdateCadenceEstimate(). Empty when no cadence has been detected.
Cadence cadence_;
diff --git a/media/filters/video_cadence_estimator_unittest.cc b/media/filters/video_cadence_estimator_unittest.cc
index 845bb3a..a5e498c 100644
--- a/media/filters/video_cadence_estimator_unittest.cc
+++ b/media/filters/video_cadence_estimator_unittest.cc
@@ -51,16 +51,20 @@ static void VerifyCadenceVector(VideoCadenceEstimator* estimator,
CreateCadenceFromString(expected_cadence);
estimator->Reset();
- const base::TimeDelta acceptable_drift = Interval(frame_hertz) / 2;
+ const base::TimeDelta acceptable_drift = std::max(Interval(frame_hertz) / 2,
+ Interval(render_hertz));
const bool cadence_changed = estimator->UpdateCadenceEstimate(
Interval(render_hertz), Interval(frame_hertz), acceptable_drift);
EXPECT_EQ(cadence_changed, estimator->has_cadence());
EXPECT_EQ(expected_cadence_vector.empty(), !estimator->has_cadence());
// Nothing further to test.
- if (expected_cadence_vector.empty())
+ if (expected_cadence_vector.empty() || !estimator->has_cadence())
return;
+ EXPECT_EQ(expected_cadence_vector.size(),
+ estimator->cadence_size_for_testing());
+
// Spot two cycles of the cadence.
for (size_t i = 0; i < expected_cadence_vector.size() * 2; ++i) {
ASSERT_EQ(expected_cadence_vector[i % expected_cadence_vector.size()],
@@ -75,30 +79,50 @@ TEST(VideoCadenceEstimatorTest, CadenceCalculations) {
estimator.set_cadence_hysteresis_threshold_for_testing(base::TimeDelta());
const std::string kEmptyCadence = "[]";
+ VerifyCadenceVector(&estimator, 1, NTSC(60), "[60]");
+
VerifyCadenceVector(&estimator, 24, 60, "[3:2]");
VerifyCadenceVector(&estimator, NTSC(24), 60, "[3:2]");
+ VerifyCadenceVector(&estimator, 24, NTSC(60), "[3:2]");
+
+ VerifyCadenceVector(&estimator, 25, 60, "[2:3:2:3:2]");
+ VerifyCadenceVector(&estimator, NTSC(25), 60, "[2:3:2:3:2]");
+ VerifyCadenceVector(&estimator, 25, NTSC(60), "[2:3:2:3:2]");
- VerifyCadenceVector(&estimator, 25, 60, kEmptyCadence);
- VerifyCadenceVector(&estimator, NTSC(30), 60, "[2]");
VerifyCadenceVector(&estimator, 30, 60, "[2]");
- VerifyCadenceVector(&estimator, 50, 60, kEmptyCadence);
+ VerifyCadenceVector(&estimator, NTSC(30), 60, "[2]");
+ VerifyCadenceVector(&estimator, 29.5, 60, kEmptyCadence);
+
+ VerifyCadenceVector(&estimator, 50, 60, "[1:1:2:1:1]");
+ VerifyCadenceVector(&estimator, NTSC(50), 60, "[1:1:2:1:1]");
+ VerifyCadenceVector(&estimator, 50, NTSC(60), "[1:1:2:1:1]");
+
VerifyCadenceVector(&estimator, NTSC(60), 60, "[1]");
+ VerifyCadenceVector(&estimator, 60, NTSC(60), "[1]");
+
VerifyCadenceVector(&estimator, 120, 60, "[1:0]");
+ VerifyCadenceVector(&estimator, NTSC(120), 60, "[1:0]");
+ VerifyCadenceVector(&estimator, 120, NTSC(60), "[1:0]");
+
+ // Test cases for cadence below 1.
VerifyCadenceVector(&estimator, 120, 24, "[1:0:0:0:0]");
+ VerifyCadenceVector(&estimator, 120, 48, "[1:0:0:1:0]");
+ VerifyCadenceVector(&estimator, 120, 72, "[1:0:1:0:1]");
+ VerifyCadenceVector(&estimator, 90, 60, "[1:0:1]");
// 50Hz is common in the EU.
VerifyCadenceVector(&estimator, NTSC(24), 50, kEmptyCadence);
VerifyCadenceVector(&estimator, 24, 50, kEmptyCadence);
+
VerifyCadenceVector(&estimator, NTSC(25), 50, "[2]");
VerifyCadenceVector(&estimator, 25, 50, "[2]");
- VerifyCadenceVector(&estimator, NTSC(30), 50, kEmptyCadence);
- VerifyCadenceVector(&estimator, 30, 50, kEmptyCadence);
+
+ VerifyCadenceVector(&estimator, NTSC(30), 50, "[2:1:2]");
+ VerifyCadenceVector(&estimator, 30, 50, "[2:1:2]");
+
VerifyCadenceVector(&estimator, NTSC(60), 50, kEmptyCadence);
VerifyCadenceVector(&estimator, 60, 50, kEmptyCadence);
- VerifyCadenceVector(&estimator, 25, NTSC(60), kEmptyCadence);
- VerifyCadenceVector(&estimator, 120, NTSC(60), kEmptyCadence);
- VerifyCadenceVector(&estimator, 1, NTSC(60), "[60]");
}
TEST(VideoCadenceEstimatorTest, CadenceVariesWithAcceptableDrift) {
@@ -187,18 +211,4 @@ TEST(VideoCadenceEstimatorTest, CadenceHystersisPreventsOscillation) {
EXPECT_FALSE(estimator->has_cadence());
}
-TEST(VideoCadenceEstimatorTest, TwoFrameCadenceIsActuallyOneFrame) {
- VideoCadenceEstimator estimator(
- base::TimeDelta::FromSeconds(kMinimumAcceptableTimeBetweenGlitchesSecs));
- estimator.set_cadence_hysteresis_threshold_for_testing(base::TimeDelta());
-
- const base::TimeDelta render_interval =
- base::TimeDelta::FromMicroseconds(16715);
- const base::TimeDelta frame_duration =
- base::TimeDelta::FromMicroseconds(33360);
-
- EXPECT_TRUE(estimator.UpdateCadenceEstimate(render_interval, frame_duration,
- frame_duration / 2));
-}
-
} // namespace media
diff --git a/media/filters/video_renderer_algorithm_unittest.cc b/media/filters/video_renderer_algorithm_unittest.cc
index 0df3f4e..ba29b4f 100644
--- a/media/filters/video_renderer_algorithm_unittest.cc
+++ b/media/filters/video_renderer_algorithm_unittest.cc
@@ -102,9 +102,28 @@ class VideoRendererAlgorithmTest : public testing::Test {
return algorithm_.cadence_estimator_.has_cadence();
}
- bool IsUsingFractionalCadence() const {
- return is_using_cadence() &&
- !algorithm_.cadence_estimator_.GetCadenceForFrame(1);
+ bool IsCadenceBelowOne() const {
+ if (!is_using_cadence())
+ return false;
+
+ size_t size = algorithm_.cadence_estimator_.cadence_size_for_testing();
+ for (size_t i = 0; i < size; ++i) {
+ if (!algorithm_.cadence_estimator_.GetCadenceForFrame(i))
+ return true;
+ }
+
+ return false;
+ }
+
+ double CadenceValue() const {
+ int num_render_intervals = 0;
+ size_t size = algorithm_.cadence_estimator_.cadence_size_for_testing();
+ for (size_t i = 0; i < size; ++i) {
+ num_render_intervals +=
+ algorithm_.cadence_estimator_.GetCadenceForFrame(i);
+ }
+
+ return (num_render_intervals + 0.0) / size;
}
size_t frames_queued() const { return algorithm_.frame_queue_.size(); }
@@ -222,16 +241,15 @@ class VideoRendererAlgorithmTest : public testing::Test {
ASSERT_NEAR(GetUsableFrameCount(deadline_max),
algorithm_.EffectiveFramesQueued(),
fresh_algorithm ? 0 : 1);
- } else if (is_using_cadence() && !IsUsingFractionalCadence()) {
+ } else if (is_using_cadence() && !IsCadenceBelowOne()) {
// If there was no glitch in the last render, the two queue sizes should
// be off by exactly one frame; i.e., the current frame doesn't count.
if (!last_render_had_glitch() && fresh_algorithm)
ASSERT_EQ(frames_queued() - 1, algorithm_.EffectiveFramesQueued());
- } else if (IsUsingFractionalCadence()) {
+ } else if (IsCadenceBelowOne()) {
// The frame estimate should be off by at most one frame.
const size_t estimated_frames_queued =
- frames_queued() /
- algorithm_.cadence_estimator_.cadence_size_for_testing();
+ std::floor(frames_queued() * CadenceValue());
ASSERT_NEAR(algorithm_.EffectiveFramesQueued(), estimated_frames_queued,
1);
}
@@ -1013,10 +1031,10 @@ TEST_F(VideoRendererAlgorithmTest, FilmCadence) {
TEST_F(VideoRendererAlgorithmTest, CadenceCalculations) {
ASSERT_EQ("[3:2]", GetCadence(24, 60));
ASSERT_EQ("[3:2]", GetCadence(NTSC(24), 60));
- ASSERT_EQ("[]", GetCadence(25, 60));
+ ASSERT_EQ("[2:3:2:3:2]", GetCadence(25, 60));
ASSERT_EQ("[2]", GetCadence(NTSC(30), 60));
ASSERT_EQ("[2]", GetCadence(30, 60));
- ASSERT_EQ("[]", GetCadence(50, 60));
+ ASSERT_EQ("[1:1:2:1:1]", GetCadence(50, 60));
ASSERT_EQ("[1]", GetCadence(NTSC(60), 60));
ASSERT_EQ("[1:0]", GetCadence(120, 60));
@@ -1025,12 +1043,12 @@ TEST_F(VideoRendererAlgorithmTest, CadenceCalculations) {
ASSERT_EQ("[]", GetCadence(24, 50));
ASSERT_EQ("[2]", GetCadence(NTSC(25), 50));
ASSERT_EQ("[2]", GetCadence(25, 50));
- ASSERT_EQ("[]", GetCadence(NTSC(30), 50));
- ASSERT_EQ("[]", GetCadence(30, 50));
+ ASSERT_EQ("[2:1:2]", GetCadence(NTSC(30), 50));
+ ASSERT_EQ("[2:1:2]", GetCadence(30, 50));
ASSERT_EQ("[]", GetCadence(NTSC(60), 50));
ASSERT_EQ("[]", GetCadence(60, 50));
- ASSERT_EQ("[]", GetCadence(25, NTSC(60)));
+ ASSERT_EQ("[2:3:2:3:2]", GetCadence(25, NTSC(60)));
ASSERT_EQ("[1:0]", GetCadence(120, NTSC(60)));
ASSERT_EQ("[60]", GetCadence(1, NTSC(60)));
}
@@ -1162,9 +1180,9 @@ TEST_F(VideoRendererAlgorithmTest, VariableFrameRateCadence) {
TickGenerator frame_tg(base::TimeTicks(), NTSC(30));
TickGenerator display_tg(tick_clock_->NowTicks(), 60);
- const double kTestRates[] = {1.0, 2, 0.215, 0.5, 1.0};
- const bool kTestRateHasCadence[arraysize(kTestRates)] = {
- true, true, false, true, true};
+ const double kTestRates[] = {1.0, 2, 0.215, 0.5, 1.0, 3.15};
+ const bool kTestRateHasCadence[arraysize(kTestRates)] = {true, true, true,
+ true, true, false};
for (size_t i = 0; i < arraysize(kTestRates); ++i) {
const double playback_rate = kTestRates[i];