Commit b3a547e7 authored by dalecurtis's avatar dalecurtis Committed by Commit bot

Implement support for 2-pattern cadence.

An N pattern cadence is simply figuring out if N times the
frame duration has an integer cadence (M) relative to the
render interval, then figuring out how to distribute N
values such that sum(x1 + x2 + x3 ... xN) == M.

I haven't dug through our discussion on how to compute this
for N > 2, but for N == 2, it's simple to just use
x1 == ceil(M/2), x2 == floor(M/2)

This change refactors the main function in VideoCadenceEstimator
into smaller pieces (an original review request :) in order to
reuse them for detecting 2-pattern cadence.

BUG=439548
TEST=all unit tests still pass, 3:2 cadence tests pass.

Review URL: https://codereview.chromium.org/1125893002

Cr-Commit-Position: refs/heads/master@{#329813}
parent f936368a
This diff is collapsed.
This diff is collapsed.
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "media/filters/video_cadence_estimator.h" #include "media/filters/video_cadence_estimator.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -22,33 +24,47 @@ static base::TimeDelta Interval(double hertz) { ...@@ -22,33 +24,47 @@ static base::TimeDelta Interval(double hertz) {
return base::TimeDelta::FromSecondsD(1.0 / hertz); return base::TimeDelta::FromSecondsD(1.0 / hertz);
} }
static void VerifyCadence(VideoCadenceEstimator* estimator, std::vector<int> CreateCadenceFromString(const std::string& cadence) {
double frame_hertz, std::vector<std::string> tokens;
double render_hertz, CHECK_EQ('[', cadence[0]);
int expected_cadence) { CHECK_EQ(']', cadence[cadence.length() - 1]);
base::SplitString(cadence.substr(1, cadence.length() - 2), ':', &tokens);
std::vector<int> result;
for (const auto& token : tokens) {
int cadence_value = 0;
CHECK(base::StringToInt(token, &cadence_value)) << token;
result.push_back(cadence_value);
}
return result;
}
static void VerifyCadenceVector(VideoCadenceEstimator* estimator,
double frame_hertz,
double render_hertz,
const std::string& expected_cadence) {
SCOPED_TRACE(base::StringPrintf("Checking %.03f fps into %0.03f", frame_hertz, SCOPED_TRACE(base::StringPrintf("Checking %.03f fps into %0.03f", frame_hertz,
render_hertz)); render_hertz));
const std::vector<int> expected_cadence_vector =
CreateCadenceFromString(expected_cadence);
estimator->Reset(); estimator->Reset();
const base::TimeDelta acceptable_drift = Interval(frame_hertz) / 2; const base::TimeDelta acceptable_drift = Interval(frame_hertz) / 2;
const bool cadence_changed = estimator->UpdateCadenceEstimate( const bool cadence_changed = estimator->UpdateCadenceEstimate(
Interval(render_hertz), Interval(frame_hertz), acceptable_drift); Interval(render_hertz), Interval(frame_hertz), acceptable_drift);
EXPECT_EQ(cadence_changed, estimator->has_cadence()); EXPECT_EQ(cadence_changed, estimator->has_cadence());
EXPECT_EQ(!!expected_cadence, estimator->has_cadence()); EXPECT_EQ(expected_cadence_vector.empty(), !estimator->has_cadence());
// Nothing further to test. // Nothing further to test.
if (!expected_cadence) if (expected_cadence_vector.empty())
return; return;
// Spot check a few frame indices. // Spot two cycles of the cadence.
if (frame_hertz <= render_hertz) { for (size_t i = 0; i < expected_cadence_vector.size() * 2; ++i) {
EXPECT_EQ(expected_cadence, estimator->GetCadenceForFrame(0)); ASSERT_EQ(expected_cadence_vector[i % expected_cadence_vector.size()],
EXPECT_EQ(expected_cadence, estimator->GetCadenceForFrame(1)); estimator->GetCadenceForFrame(i));
EXPECT_EQ(expected_cadence, estimator->GetCadenceForFrame(2));
} else {
EXPECT_EQ(1, estimator->GetCadenceForFrame(0));
EXPECT_EQ(0, estimator->GetCadenceForFrame(1));
EXPECT_EQ(1, estimator->GetCadenceForFrame(expected_cadence));
EXPECT_EQ(0, estimator->GetCadenceForFrame(expected_cadence + 1));
} }
} }
...@@ -58,28 +74,31 @@ TEST(VideoCadenceEstimatorTest, CadenceCalculations) { ...@@ -58,28 +74,31 @@ TEST(VideoCadenceEstimatorTest, CadenceCalculations) {
base::TimeDelta::FromSeconds(kMinimumAcceptableTimeBetweenGlitchesSecs)); base::TimeDelta::FromSeconds(kMinimumAcceptableTimeBetweenGlitchesSecs));
estimator.set_cadence_hysteresis_threshold_for_testing(base::TimeDelta()); estimator.set_cadence_hysteresis_threshold_for_testing(base::TimeDelta());
VerifyCadence(&estimator, 24, 60, 0); const std::string kEmptyCadence = "[]";
VerifyCadence(&estimator, NTSC(24), 60, 0); VerifyCadenceVector(&estimator, 24, 60, "[3:2]");
VerifyCadence(&estimator, 25, 60, 0); VerifyCadenceVector(&estimator, NTSC(24), 60, "[3:2]");
VerifyCadence(&estimator, NTSC(30), 60, 2);
VerifyCadence(&estimator, 30, 60, 2); VerifyCadenceVector(&estimator, 25, 60, kEmptyCadence);
VerifyCadence(&estimator, 50, 60, 0); VerifyCadenceVector(&estimator, NTSC(30), 60, "[2]");
VerifyCadence(&estimator, NTSC(60), 60, 1); VerifyCadenceVector(&estimator, 30, 60, "[2]");
VerifyCadence(&estimator, 120, 60, 2); VerifyCadenceVector(&estimator, 50, 60, kEmptyCadence);
VerifyCadenceVector(&estimator, NTSC(60), 60, "[1]");
VerifyCadenceVector(&estimator, 120, 60, "[1:0]");
VerifyCadenceVector(&estimator, 120, 24, "[1:0:0:0:0]");
// 50Hz is common in the EU. // 50Hz is common in the EU.
VerifyCadence(&estimator, NTSC(24), 50, 0); VerifyCadenceVector(&estimator, NTSC(24), 50, kEmptyCadence);
VerifyCadence(&estimator, 24, 50, 0); VerifyCadenceVector(&estimator, 24, 50, kEmptyCadence);
VerifyCadence(&estimator, NTSC(25), 50, 2); VerifyCadenceVector(&estimator, NTSC(25), 50, "[2]");
VerifyCadence(&estimator, 25, 50, 2); VerifyCadenceVector(&estimator, 25, 50, "[2]");
VerifyCadence(&estimator, NTSC(30), 50, 0); VerifyCadenceVector(&estimator, NTSC(30), 50, kEmptyCadence);
VerifyCadence(&estimator, 30, 50, 0); VerifyCadenceVector(&estimator, 30, 50, kEmptyCadence);
VerifyCadence(&estimator, NTSC(60), 50, 0); VerifyCadenceVector(&estimator, NTSC(60), 50, kEmptyCadence);
VerifyCadence(&estimator, 60, 50, 0); VerifyCadenceVector(&estimator, 60, 50, kEmptyCadence);
VerifyCadence(&estimator, 25, NTSC(60), 0); VerifyCadenceVector(&estimator, 25, NTSC(60), kEmptyCadence);
VerifyCadence(&estimator, 120, NTSC(60), 0); VerifyCadenceVector(&estimator, 120, NTSC(60), kEmptyCadence);
VerifyCadence(&estimator, 1, NTSC(60), 60); VerifyCadenceVector(&estimator, 1, NTSC(60), "[60]");
} }
TEST(VideoCadenceEstimatorTest, CadenceVariesWithAcceptableDrift) { TEST(VideoCadenceEstimatorTest, CadenceVariesWithAcceptableDrift) {
...@@ -101,7 +120,7 @@ TEST(VideoCadenceEstimatorTest, CadenceVariesWithAcceptableDrift) { ...@@ -101,7 +120,7 @@ TEST(VideoCadenceEstimatorTest, CadenceVariesWithAcceptableDrift) {
EXPECT_TRUE(estimator.UpdateCadenceEstimate(render_interval, frame_interval, EXPECT_TRUE(estimator.UpdateCadenceEstimate(render_interval, frame_interval,
acceptable_drift)); acceptable_drift));
EXPECT_TRUE(estimator.has_cadence()); EXPECT_TRUE(estimator.has_cadence());
EXPECT_EQ(2, estimator.get_cadence_for_testing()); EXPECT_EQ("[1:0]", estimator.GetCadenceForTesting());
} }
TEST(VideoCadenceEstimatorTest, CadenceVariesWithAcceptableGlitchTime) { TEST(VideoCadenceEstimatorTest, CadenceVariesWithAcceptableGlitchTime) {
...@@ -125,7 +144,7 @@ TEST(VideoCadenceEstimatorTest, CadenceVariesWithAcceptableGlitchTime) { ...@@ -125,7 +144,7 @@ TEST(VideoCadenceEstimatorTest, CadenceVariesWithAcceptableGlitchTime) {
EXPECT_TRUE(estimator->UpdateCadenceEstimate(render_interval, frame_interval, EXPECT_TRUE(estimator->UpdateCadenceEstimate(render_interval, frame_interval,
acceptable_drift)); acceptable_drift));
EXPECT_TRUE(estimator->has_cadence()); EXPECT_TRUE(estimator->has_cadence());
EXPECT_EQ(2, estimator->get_cadence_for_testing()); EXPECT_EQ("[1:0]", estimator->GetCadenceForTesting());
} }
TEST(VideoCadenceEstimatorTest, CadenceHystersisPreventsOscillation) { TEST(VideoCadenceEstimatorTest, CadenceHystersisPreventsOscillation) {
......
...@@ -94,10 +94,12 @@ scoped_refptr<VideoFrame> VideoRendererAlgorithm::Render( ...@@ -94,10 +94,12 @@ scoped_refptr<VideoFrame> VideoRendererAlgorithm::Render(
base::TimeDelta selected_frame_drift; base::TimeDelta selected_frame_drift;
// Step 4: Attempt to find the best frame by cadence. // Step 4: Attempt to find the best frame by cadence.
bool was_frame_selected_by_cadence = false;
int cadence_overage = 0; int cadence_overage = 0;
int frame_to_render = int frame_to_render =
FindBestFrameByCadence(first_frame_ ? nullptr : &cadence_overage); FindBestFrameByCadence(first_frame_ ? nullptr : &cadence_overage);
if (frame_to_render >= 0) { if (frame_to_render >= 0) {
was_frame_selected_by_cadence = true;
selected_frame_drift = selected_frame_drift =
CalculateAbsoluteDriftForFrame(deadline_min, frame_to_render); CalculateAbsoluteDriftForFrame(deadline_min, frame_to_render);
} }
...@@ -121,7 +123,12 @@ scoped_refptr<VideoFrame> VideoRendererAlgorithm::Render( ...@@ -121,7 +123,12 @@ scoped_refptr<VideoFrame> VideoRendererAlgorithm::Render(
} }
if (frame_to_render >= 0) { if (frame_to_render >= 0) {
cadence_overage = 0; if (was_frame_selected_by_cadence) {
cadence_overage = 0;
was_frame_selected_by_cadence = false;
DVLOG(2) << "Overriding frame selected by cadence because of drift: "
<< selected_frame_drift;
}
selected_frame_drift = selected_frame_drift =
CalculateAbsoluteDriftForFrame(deadline_min, frame_to_render); CalculateAbsoluteDriftForFrame(deadline_min, frame_to_render);
} }
...@@ -132,7 +139,10 @@ scoped_refptr<VideoFrame> VideoRendererAlgorithm::Render( ...@@ -132,7 +139,10 @@ scoped_refptr<VideoFrame> VideoRendererAlgorithm::Render(
// selection is going to be bad because it means no suitable frame has any // selection is going to be bad because it means no suitable frame has any
// coverage of the deadline interval. // coverage of the deadline interval.
if (frame_to_render < 0 || selected_frame_drift > max_acceptable_drift_) { if (frame_to_render < 0 || selected_frame_drift > max_acceptable_drift_) {
cadence_overage = 0; if (was_frame_selected_by_cadence) {
cadence_overage = 0;
was_frame_selected_by_cadence = false;
}
frame_to_render = FindBestFrameByDrift(deadline_min, &selected_frame_drift); frame_to_render = FindBestFrameByDrift(deadline_min, &selected_frame_drift);
} }
...@@ -189,11 +199,14 @@ scoped_refptr<VideoFrame> VideoRendererAlgorithm::Render( ...@@ -189,11 +199,14 @@ scoped_refptr<VideoFrame> VideoRendererAlgorithm::Render(
} }
} }
// Increment the frame counter for all frames removed after the last
// rendered frame.
cadence_frame_counter_ += frame_to_render - last_frame_index_;
frame_queue_.erase(frame_queue_.begin(), frame_queue_.erase(frame_queue_.begin(),
frame_queue_.begin() + frame_to_render); frame_queue_.begin() + frame_to_render);
} }
if (last_render_had_glitch_) { if (last_render_had_glitch_ && !first_frame_) {
DVLOG(2) << "Deadline: [" << deadline_min.ToInternalValue() << ", " DVLOG(2) << "Deadline: [" << deadline_min.ToInternalValue() << ", "
<< deadline_max.ToInternalValue() << deadline_max.ToInternalValue()
<< "], Interval: " << render_interval_.InMicroseconds() << "], Interval: " << render_interval_.InMicroseconds()
...@@ -215,6 +228,14 @@ scoped_refptr<VideoFrame> VideoRendererAlgorithm::Render( ...@@ -215,6 +228,14 @@ scoped_refptr<VideoFrame> VideoRendererAlgorithm::Render(
deadline_min >= frame_queue_.front().start_time - render_interval_ / 2) { deadline_min >= frame_queue_.front().start_time - render_interval_ / 2) {
frame_queue_.front().render_count += cadence_overage + 1; frame_queue_.front().render_count += cadence_overage + 1;
frame_queue_.front().drop_count += cadence_overage; frame_queue_.front().drop_count += cadence_overage;
// Once we reach a glitch in our cadence sequence, reset the base frame
// number used for defining the cadence sequence.
if (!was_frame_selected_by_cadence && cadence_estimator_.has_cadence()) {
cadence_frame_counter_ = 0;
UpdateCadenceForFrames();
}
first_frame_ = false; first_frame_ = false;
} }
...@@ -235,8 +256,9 @@ size_t VideoRendererAlgorithm::RemoveExpiredFrames(base::TimeTicks deadline) { ...@@ -235,8 +256,9 @@ size_t VideoRendererAlgorithm::RemoveExpiredFrames(base::TimeTicks deadline) {
// Finds and removes all frames which are too old to be used; I.e., the end of // Finds and removes all frames which are too old to be used; I.e., the end of
// their render interval is further than |max_acceptable_drift_| from the // their render interval is further than |max_acceptable_drift_| from the
// given |deadline|. // given |deadline|. We also always expire anything inserted before the last
size_t frames_to_expire = 0; // rendered frame.
size_t frames_to_expire = last_frame_index_;
const base::TimeTicks minimum_start_time = const base::TimeTicks minimum_start_time =
deadline - max_acceptable_drift_ - average_frame_duration_; deadline - max_acceptable_drift_ - average_frame_duration_;
for (; frames_to_expire < frame_queue_.size() - 1; ++frames_to_expire) { for (; frames_to_expire < frame_queue_.size() - 1; ++frames_to_expire) {
...@@ -247,6 +269,7 @@ size_t VideoRendererAlgorithm::RemoveExpiredFrames(base::TimeTicks deadline) { ...@@ -247,6 +269,7 @@ size_t VideoRendererAlgorithm::RemoveExpiredFrames(base::TimeTicks deadline) {
if (!frames_to_expire) if (!frames_to_expire)
return 0; return 0;
cadence_frame_counter_ += frames_to_expire - last_frame_index_;
frame_queue_.erase(frame_queue_.begin(), frame_queue_.erase(frame_queue_.begin(),
frame_queue_.begin() + frames_to_expire); frame_queue_.begin() + frames_to_expire);
...@@ -282,6 +305,7 @@ void VideoRendererAlgorithm::Reset() { ...@@ -282,6 +305,7 @@ void VideoRendererAlgorithm::Reset() {
cadence_estimator_.Reset(); cadence_estimator_.Reset();
frame_duration_calculator_.Reset(); frame_duration_calculator_.Reset();
first_frame_ = true; first_frame_ = true;
cadence_frame_counter_ = 0;
// Default to ATSC IS/191 recommendations for maximum acceptable drift before // Default to ATSC IS/191 recommendations for maximum acceptable drift before
// we have enough frames to base the maximum on frame duration. // we have enough frames to base the maximum on frame duration.
...@@ -474,6 +498,7 @@ bool VideoRendererAlgorithm::UpdateFrameStatistics() { ...@@ -474,6 +498,7 @@ bool VideoRendererAlgorithm::UpdateFrameStatistics() {
if (!cadence_changed) if (!cadence_changed)
return true; return true;
cadence_frame_counter_ = 0;
UpdateCadenceForFrames(); UpdateCadenceForFrames();
// Thus far there appears to be no need for special 3:2 considerations, the // Thus far there appears to be no need for special 3:2 considerations, the
...@@ -489,7 +514,8 @@ void VideoRendererAlgorithm::UpdateCadenceForFrames() { ...@@ -489,7 +514,8 @@ void VideoRendererAlgorithm::UpdateCadenceForFrames() {
// cadence selection. // cadence selection.
frame_queue_[i].ideal_render_count = frame_queue_[i].ideal_render_count =
cadence_estimator_.has_cadence() cadence_estimator_.has_cadence()
? cadence_estimator_.GetCadenceForFrame(i - last_frame_index_) ? cadence_estimator_.GetCadenceForFrame(cadence_frame_counter_ +
(i - last_frame_index_))
: 0; : 0;
} }
} }
......
...@@ -189,7 +189,8 @@ class MEDIA_EXPORT VideoRendererAlgorithm { ...@@ -189,7 +189,8 @@ class MEDIA_EXPORT VideoRendererAlgorithm {
bool UpdateFrameStatistics(); bool UpdateFrameStatistics();
// Updates the ideal render count for all frames in |frame_queue_| based on // Updates the ideal render count for all frames in |frame_queue_| based on
// the cadence returned by |cadence_estimator_|. // the cadence returned by |cadence_estimator_|. Cadence is assigned based
// on |frame_counter_|.
void UpdateCadenceForFrames(); void UpdateCadenceForFrames();
// If |cadence_estimator_| has detected a valid cadence, attempts to find the // If |cadence_estimator_| has detected a valid cadence, attempts to find the
...@@ -292,6 +293,13 @@ class MEDIA_EXPORT VideoRendererAlgorithm { ...@@ -292,6 +293,13 @@ class MEDIA_EXPORT VideoRendererAlgorithm {
// until the first frame has reached its presentation time. // until the first frame has reached its presentation time.
bool first_frame_; bool first_frame_;
// The frame number of the last rendered frame; incremented for every frame
// rendered and every frame dropped or expired since the last rendered frame.
//
// Given to |cadence_estimator_| when assigning cadence values to the
// ReadyFrameQueue. Cleared when a new cadence is detected.
uint64_t cadence_frame_counter_;
DISALLOW_COPY_AND_ASSIGN(VideoRendererAlgorithm); DISALLOW_COPY_AND_ASSIGN(VideoRendererAlgorithm);
}; };
......
...@@ -109,7 +109,7 @@ class VideoRendererAlgorithmTest : public testing::Test { ...@@ -109,7 +109,7 @@ class VideoRendererAlgorithmTest : public testing::Test {
size_t frames_queued() const { return algorithm_.frame_queue_.size(); } size_t frames_queued() const { return algorithm_.frame_queue_.size(); }
int GetCadence(double frame_rate, double display_rate) { std::string GetCadence(double frame_rate, double display_rate) {
TickGenerator display_tg(tick_clock_->NowTicks(), display_rate); TickGenerator display_tg(tick_clock_->NowTicks(), display_rate);
TickGenerator frame_tg(base::TimeTicks(), frame_rate); TickGenerator frame_tg(base::TimeTicks(), frame_rate);
time_source_.StartTicking(); time_source_.StartTicking();
...@@ -122,7 +122,8 @@ class VideoRendererAlgorithmTest : public testing::Test { ...@@ -122,7 +122,8 @@ class VideoRendererAlgorithmTest : public testing::Test {
EXPECT_TRUE(RenderAndStep(&display_tg, &frames_dropped)); EXPECT_TRUE(RenderAndStep(&display_tg, &frames_dropped));
// Store cadence before reseting the algorithm. // Store cadence before reseting the algorithm.
const int cadence = algorithm_.cadence_estimator_.get_cadence_for_testing(); const std::string cadence =
algorithm_.cadence_estimator_.GetCadenceForTesting();
time_source_.StopTicking(); time_source_.StopTicking();
algorithm_.Reset(); algorithm_.Reset();
return cadence; return cadence;
...@@ -230,7 +231,7 @@ class VideoRendererAlgorithmTest : public testing::Test { ...@@ -230,7 +231,7 @@ class VideoRendererAlgorithmTest : public testing::Test {
// The frame estimate should be off by at most one frame. // The frame estimate should be off by at most one frame.
const size_t estimated_frames_queued = const size_t estimated_frames_queued =
frames_queued() / frames_queued() /
algorithm_.cadence_estimator_.get_cadence_for_testing(); algorithm_.cadence_estimator_.cadence_size_for_testing();
ASSERT_NEAR(algorithm_.EffectiveFramesQueued(), estimated_frames_queued, ASSERT_NEAR(algorithm_.EffectiveFramesQueued(), estimated_frames_queued,
1); 1);
} }
...@@ -888,10 +889,10 @@ TEST_F(VideoRendererAlgorithmTest, BestFrameByFractionalCadence) { ...@@ -888,10 +889,10 @@ TEST_F(VideoRendererAlgorithmTest, BestFrameByFractionalCadence) {
} }
} }
// Verify a 3:2 frame pattern for 23.974fps in 60Hz; doubles as a test for best // Verify a 3:2 frame pattern for 23.974fps and 24fps in 60Hz.
// frame by coverage.
TEST_F(VideoRendererAlgorithmTest, FilmCadence) { TEST_F(VideoRendererAlgorithmTest, FilmCadence) {
const double kTestRates[] = {NTSC(24), 24}; const double kTestRates[] = {NTSC(24), 24};
disable_cadence_hysteresis();
for (double frame_rate : kTestRates) { for (double frame_rate : kTestRates) {
scoped_refptr<VideoFrame> current_frame; scoped_refptr<VideoFrame> current_frame;
...@@ -916,7 +917,7 @@ TEST_F(VideoRendererAlgorithmTest, FilmCadence) { ...@@ -916,7 +917,7 @@ TEST_F(VideoRendererAlgorithmTest, FilmCadence) {
} }
current_frame = frame; current_frame = frame;
ASSERT_FALSE(is_using_cadence()); ASSERT_TRUE(is_using_cadence());
}); });
if (HasFatalFailure()) if (HasFatalFailure())
...@@ -926,28 +927,28 @@ TEST_F(VideoRendererAlgorithmTest, FilmCadence) { ...@@ -926,28 +927,28 @@ TEST_F(VideoRendererAlgorithmTest, FilmCadence) {
// Spot check common display and frame rate pairs for correctness. // Spot check common display and frame rate pairs for correctness.
TEST_F(VideoRendererAlgorithmTest, CadenceCalculations) { TEST_F(VideoRendererAlgorithmTest, CadenceCalculations) {
ASSERT_FALSE(GetCadence(24, 60)); ASSERT_EQ("[3:2]", GetCadence(24, 60));
ASSERT_FALSE(GetCadence(NTSC(24), 60)); ASSERT_EQ("[3:2]", GetCadence(NTSC(24), 60));
ASSERT_FALSE(GetCadence(25, 60)); ASSERT_EQ("[]", GetCadence(25, 60));
ASSERT_EQ(2, GetCadence(NTSC(30), 60)); ASSERT_EQ("[2]", GetCadence(NTSC(30), 60));
ASSERT_EQ(2, GetCadence(30, 60)); ASSERT_EQ("[2]", GetCadence(30, 60));
ASSERT_FALSE(GetCadence(50, 60)); ASSERT_EQ("[]", GetCadence(50, 60));
ASSERT_EQ(1, GetCadence(NTSC(60), 60)); ASSERT_EQ("[1]", GetCadence(NTSC(60), 60));
ASSERT_EQ(2, GetCadence(120, 60)); ASSERT_EQ("[1:0]", GetCadence(120, 60));
// 50Hz is common in the EU. // 50Hz is common in the EU.
ASSERT_FALSE(GetCadence(NTSC(24), 50)); ASSERT_EQ("[]", GetCadence(NTSC(24), 50));
ASSERT_FALSE(GetCadence(24, 50)); ASSERT_EQ("[]", GetCadence(24, 50));
ASSERT_EQ(2, GetCadence(NTSC(25), 50)); ASSERT_EQ("[2]", GetCadence(NTSC(25), 50));
ASSERT_EQ(2, GetCadence(25, 50)); ASSERT_EQ("[2]", GetCadence(25, 50));
ASSERT_FALSE(GetCadence(NTSC(30), 50)); ASSERT_EQ("[]", GetCadence(NTSC(30), 50));
ASSERT_FALSE(GetCadence(30, 50)); ASSERT_EQ("[]", GetCadence(30, 50));
ASSERT_FALSE(GetCadence(NTSC(60), 50)); ASSERT_EQ("[]", GetCadence(NTSC(60), 50));
ASSERT_FALSE(GetCadence(60, 50)); ASSERT_EQ("[]", GetCadence(60, 50));
ASSERT_FALSE(GetCadence(25, NTSC(60))); ASSERT_EQ("[]", GetCadence(25, NTSC(60)));
ASSERT_EQ(2, GetCadence(120, NTSC(60))); ASSERT_EQ("[1:0]", GetCadence(120, NTSC(60)));
ASSERT_EQ(60, GetCadence(1, NTSC(60))); ASSERT_EQ("[60]", GetCadence(1, NTSC(60)));
} }
TEST_F(VideoRendererAlgorithmTest, RemoveExpiredFrames) { TEST_F(VideoRendererAlgorithmTest, RemoveExpiredFrames) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment