Revert "[M120 Migration]Fix for crash during chrome exit"
[platform/framework/web/chromium-efl.git] / media / filters / video_cadence_estimator_unittest.cc
1 // Copyright 2015 The Chromium Authors
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 <math.h>
8 #include <stddef.h>
9
10 #include <memory>
11
12 #include "base/numerics/safe_conversions.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/test/scoped_feature_list.h"
17 #include "base/time/time.h"
18 #include "media/base/media_switches.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 namespace media {
22
23 // See VideoCadenceEstimator header for more details.
24 constexpr auto kMinimumAcceptableTimeBetweenGlitches = base::Seconds(8);
25
26 // Slows down the given |fps| according to NTSC field reduction standards; see
27 // http://en.wikipedia.org/wiki/Frame_rate#Digital_video_and_television
28 static double NTSC(double fps) {
29   return fps / 1.001;
30 }
31
32 static base::TimeDelta Interval(double hertz) {
33   return base::Seconds(1.0 / hertz);
34 }
35
36 std::vector<int> CreateCadenceFromString(const std::string& cadence) {
37   CHECK_EQ('[', cadence.front());
38   CHECK_EQ(']', cadence.back());
39
40   std::vector<int> result;
41   for (const std::string& token :
42        base::SplitString(cadence.substr(1, cadence.length() - 2),
43                          ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
44     int cadence_value = 0;
45     CHECK(base::StringToInt(token, &cadence_value)) << token;
46     result.push_back(cadence_value);
47   }
48
49   return result;
50 }
51
52 static void VerifyCadenceVectorWithCustomDeviationAndDrift(
53     VideoCadenceEstimator* estimator,
54     double frame_hertz,
55     double render_hertz,
56     base::TimeDelta deviation,
57     base::TimeDelta acceptable_drift,
58     const std::string& expected_cadence) {
59   SCOPED_TRACE(base::StringPrintf("Checking %.03f fps into %0.03f", frame_hertz,
60                                   render_hertz));
61
62   const std::vector<int> expected_cadence_vector =
63       CreateCadenceFromString(expected_cadence);
64
65   estimator->Reset();
66   const bool cadence_changed = estimator->UpdateCadenceEstimate(
67       Interval(render_hertz), Interval(frame_hertz), deviation,
68       acceptable_drift);
69   EXPECT_EQ(cadence_changed, estimator->has_cadence());
70   EXPECT_EQ(expected_cadence_vector.empty(), !estimator->has_cadence());
71
72   // Nothing further to test.
73   if (expected_cadence_vector.empty() || !estimator->has_cadence())
74     return;
75
76   EXPECT_EQ(expected_cadence_vector.size(),
77             estimator->cadence_size_for_testing());
78
79   // Spot two cycles of the cadence.
80   for (size_t i = 0; i < expected_cadence_vector.size() * 2; ++i) {
81     ASSERT_EQ(expected_cadence_vector[i % expected_cadence_vector.size()],
82               estimator->GetCadenceForFrame(i));
83   }
84 }
85
86 static void VerifyCadenceVectorWithCustomDrift(
87     VideoCadenceEstimator* estimator,
88     double frame_hertz,
89     double render_hertz,
90     base::TimeDelta acceptable_drift,
91     const std::string& expected_cadence) {
92   VerifyCadenceVectorWithCustomDeviationAndDrift(
93       estimator, frame_hertz, render_hertz, base::TimeDelta(), acceptable_drift,
94       expected_cadence);
95 }
96
97 static void VerifyCadenceVectorWithCustomDeviation(
98     VideoCadenceEstimator* estimator,
99     double frame_hertz,
100     double render_hertz,
101     base::TimeDelta deviation,
102     const std::string& expected_cadence) {
103   const base::TimeDelta acceptable_drift =
104       std::max(Interval(frame_hertz) / 2, Interval(render_hertz));
105   VerifyCadenceVectorWithCustomDeviationAndDrift(
106       estimator, frame_hertz, render_hertz, deviation, acceptable_drift,
107       expected_cadence);
108 }
109
110 static void VerifyCadenceVector(VideoCadenceEstimator* estimator,
111                                 double frame_hertz,
112                                 double render_hertz,
113                                 const std::string& expected_cadence) {
114   const base::TimeDelta acceptable_drift =
115       std::max(Interval(frame_hertz) / 2, Interval(render_hertz));
116   VerifyCadenceVectorWithCustomDeviationAndDrift(
117       estimator, frame_hertz, render_hertz, base::TimeDelta(), acceptable_drift,
118       expected_cadence);
119 }
120
121 // Spot check common display and frame rate pairs for correctness.
122 TEST(VideoCadenceEstimatorTest, CadenceCalculations) {
123   VideoCadenceEstimator estimator(kMinimumAcceptableTimeBetweenGlitches);
124   estimator.set_cadence_hysteresis_threshold_for_testing(base::TimeDelta());
125
126   const std::string kEmptyCadence = "[]";
127   VerifyCadenceVector(&estimator, 1, NTSC(60), "[60]");
128
129   VerifyCadenceVector(&estimator, 24, 60, "[3:2]");
130   VerifyCadenceVector(&estimator, NTSC(24), 60, "[3:2]");
131   VerifyCadenceVector(&estimator, 24, NTSC(60), "[3:2]");
132
133   VerifyCadenceVector(&estimator, 25, 60, "[2:3:2:3:2]");
134   VerifyCadenceVector(&estimator, NTSC(25), 60, "[2:3:2:3:2]");
135   VerifyCadenceVector(&estimator, 25, NTSC(60), "[2:3:2:3:2]");
136
137   VerifyCadenceVector(&estimator, 30, 60, "[2]");
138   VerifyCadenceVector(&estimator, NTSC(30), 60, "[2]");
139   VerifyCadenceVector(&estimator, 29.5, 60, kEmptyCadence);
140
141   VerifyCadenceVector(&estimator, 50, 60, "[1:1:2:1:1]");
142   VerifyCadenceVector(&estimator, NTSC(50), 60, "[1:1:2:1:1]");
143   VerifyCadenceVector(&estimator, 50, NTSC(60), "[1:1:2:1:1]");
144
145   VerifyCadenceVector(&estimator, NTSC(60), 60, "[1]");
146   VerifyCadenceVector(&estimator, 60, NTSC(60), "[1]");
147
148   VerifyCadenceVector(&estimator, 120, 60, "[1:0]");
149   VerifyCadenceVector(&estimator, NTSC(120), 60, "[1:0]");
150   VerifyCadenceVector(&estimator, 120, NTSC(60), "[1:0]");
151
152   // Test cases for cadence below 1.
153   VerifyCadenceVector(&estimator, 120, 24, "[1:0:0:0:0]");
154   VerifyCadenceVector(&estimator, 120, 48, "[1:0:0:1:0]");
155   VerifyCadenceVector(&estimator, 120, 72, "[1:0:1:0:1]");
156   VerifyCadenceVector(&estimator, 90, 60, "[1:0:1]");
157
158   // 50Hz is common in the EU.
159   VerifyCadenceVector(&estimator, NTSC(24), 50, kEmptyCadence);
160   VerifyCadenceVector(&estimator, 24, 50, kEmptyCadence);
161
162   VerifyCadenceVector(&estimator, NTSC(25), 50, "[2]");
163   VerifyCadenceVector(&estimator, 25, 50, "[2]");
164
165   VerifyCadenceVector(&estimator, NTSC(30), 50, "[2:1:2]");
166   VerifyCadenceVector(&estimator, 30, 50, "[2:1:2]");
167
168   VerifyCadenceVector(&estimator, NTSC(60), 50, kEmptyCadence);
169   VerifyCadenceVector(&estimator, 60, 50, kEmptyCadence);
170
171 }
172
173 // Check the extreme case that max_acceptable_drift is larger than
174 // minimum_time_until_max_drift.
175 TEST(VideoCadenceEstimatorTest, CadenceCalculationWithLargeDrift) {
176   VideoCadenceEstimator estimator(kMinimumAcceptableTimeBetweenGlitches);
177   estimator.set_cadence_hysteresis_threshold_for_testing(base::TimeDelta());
178
179   base::TimeDelta drift = base::Hours(1);
180   VerifyCadenceVectorWithCustomDrift(&estimator, 1, NTSC(60), drift, "[60]");
181
182   VerifyCadenceVectorWithCustomDrift(&estimator, 30, 60, drift, "[2]");
183   VerifyCadenceVectorWithCustomDrift(&estimator, NTSC(30), 60, drift, "[2]");
184   VerifyCadenceVectorWithCustomDrift(&estimator, 30, NTSC(60), drift, "[2]");
185
186   VerifyCadenceVectorWithCustomDrift(&estimator, 25, 60, drift, "[2]");
187   VerifyCadenceVectorWithCustomDrift(&estimator, NTSC(25), 60, drift, "[2]");
188   VerifyCadenceVectorWithCustomDrift(&estimator, 25, NTSC(60), drift, "[2]");
189
190   // Test cases for cadence below 1.
191   VerifyCadenceVectorWithCustomDrift(&estimator, 120, 24, drift, "[1]");
192   VerifyCadenceVectorWithCustomDrift(&estimator, 120, 48, drift, "[1]");
193   VerifyCadenceVectorWithCustomDrift(&estimator, 120, 72, drift, "[1]");
194   VerifyCadenceVectorWithCustomDrift(&estimator, 90, 60, drift, "[1]");
195 }
196
197 TEST(VideoCadenceEstimatorTest, SimpleCadenceTest) {
198   bool simple_cadence = VideoCadenceEstimator::HasSimpleCadence(
199       Interval(60), Interval(30), kMinimumAcceptableTimeBetweenGlitches);
200   // 60 Hz screen with 30 FPS video should be considered a simple cadence.
201   EXPECT_TRUE(simple_cadence);
202   simple_cadence = VideoCadenceEstimator::HasSimpleCadence(
203       Interval(60), Interval(24), kMinimumAcceptableTimeBetweenGlitches);
204   EXPECT_FALSE(simple_cadence);
205 }
206
207 // Check the case that the estimator excludes variable FPS case from Cadence.
208 TEST(VideoCadenceEstimatorTest, CadenceCalculationWithLargeDeviation) {
209   VideoCadenceEstimator estimator(kMinimumAcceptableTimeBetweenGlitches);
210   estimator.set_cadence_hysteresis_threshold_for_testing(base::TimeDelta());
211
212   const base::TimeDelta deviation = base::Milliseconds(30);
213   VerifyCadenceVectorWithCustomDeviation(&estimator, 1, 60, deviation, "[]");
214   VerifyCadenceVectorWithCustomDeviation(&estimator, 30, 60, deviation, "[]");
215   VerifyCadenceVectorWithCustomDeviation(&estimator, 25, 60, deviation, "[]");
216
217   // Test cases for cadence with low refresh rate.
218   VerifyCadenceVectorWithCustomDeviation(&estimator, 60, 12, deviation,
219                                          "[1:0:0:0:0]");
220 }
221
222 TEST(VideoCadenceEstimatorTest, CadenceVariesWithAcceptableDrift) {
223   VideoCadenceEstimator estimator(kMinimumAcceptableTimeBetweenGlitches);
224   estimator.set_cadence_hysteresis_threshold_for_testing(base::TimeDelta());
225
226   const base::TimeDelta render_interval = Interval(NTSC(60));
227   const base::TimeDelta frame_interval = Interval(120);
228
229   base::TimeDelta acceptable_drift = frame_interval / 2;
230   EXPECT_FALSE(estimator.UpdateCadenceEstimate(
231       render_interval, frame_interval, base::TimeDelta(), acceptable_drift));
232   EXPECT_FALSE(estimator.has_cadence());
233
234   // Increasing the acceptable drift should be result in more permissive
235   // detection of cadence.
236   acceptable_drift = render_interval;
237   EXPECT_TRUE(estimator.UpdateCadenceEstimate(
238       render_interval, frame_interval, base::TimeDelta(), acceptable_drift));
239   EXPECT_TRUE(estimator.has_cadence());
240   EXPECT_EQ("[1:0]", estimator.GetCadenceForTesting());
241 }
242
243 TEST(VideoCadenceEstimatorTest, CadenceVariesWithAcceptableGlitchTime) {
244   VideoCadenceEstimator estimator(kMinimumAcceptableTimeBetweenGlitches);
245   estimator.set_cadence_hysteresis_threshold_for_testing(base::TimeDelta());
246
247   const base::TimeDelta render_interval = Interval(NTSC(60));
248   const base::TimeDelta frame_interval = Interval(120);
249   const base::TimeDelta acceptable_drift = frame_interval / 2;
250
251   EXPECT_FALSE(estimator.UpdateCadenceEstimate(
252       render_interval, frame_interval, base::TimeDelta(), acceptable_drift));
253   EXPECT_FALSE(estimator.has_cadence());
254
255   // Decreasing the acceptable glitch time should be result in more permissive
256   // detection of cadence.
257   VideoCadenceEstimator permissive_estimator(
258       kMinimumAcceptableTimeBetweenGlitches / 2);
259   permissive_estimator.set_cadence_hysteresis_threshold_for_testing(
260       base::TimeDelta());
261   EXPECT_TRUE(permissive_estimator.UpdateCadenceEstimate(
262       render_interval, frame_interval, base::TimeDelta(), acceptable_drift));
263   EXPECT_TRUE(permissive_estimator.has_cadence());
264   EXPECT_EQ("[1:0]", permissive_estimator.GetCadenceForTesting());
265 }
266
267 TEST(VideoCadenceEstimatorTest, CadenceHystersisPreventsOscillation) {
268   VideoCadenceEstimator estimator(kMinimumAcceptableTimeBetweenGlitches);
269
270   const base::TimeDelta render_interval = Interval(30);
271   const base::TimeDelta frame_interval = Interval(60);
272   const base::TimeDelta acceptable_drift = frame_interval / 2;
273   estimator.set_cadence_hysteresis_threshold_for_testing(render_interval * 2);
274
275   // Cadence hysteresis should prevent the cadence from taking effect yet.
276   EXPECT_FALSE(estimator.UpdateCadenceEstimate(
277       render_interval, frame_interval, base::TimeDelta(), acceptable_drift));
278   EXPECT_FALSE(estimator.has_cadence());
279
280   // A second call should exceed cadence hysteresis and take into effect.
281   EXPECT_TRUE(estimator.UpdateCadenceEstimate(
282       render_interval, frame_interval, base::TimeDelta(), acceptable_drift));
283   EXPECT_TRUE(estimator.has_cadence());
284
285   // One bad interval shouldn't cause cadence to drop
286   EXPECT_FALSE(
287       estimator.UpdateCadenceEstimate(render_interval, frame_interval * 0.75,
288                                       base::TimeDelta(), acceptable_drift));
289   EXPECT_TRUE(estimator.has_cadence());
290
291   // Resumption of cadence should clear bad interval count.
292   EXPECT_FALSE(estimator.UpdateCadenceEstimate(
293       render_interval, frame_interval, base::TimeDelta(), acceptable_drift));
294   EXPECT_TRUE(estimator.has_cadence());
295
296   // So one more bad interval shouldn't cause cadence to drop
297   EXPECT_FALSE(
298       estimator.UpdateCadenceEstimate(render_interval, frame_interval * 0.75,
299                                       base::TimeDelta(), acceptable_drift));
300   EXPECT_TRUE(estimator.has_cadence());
301
302   // Two bad intervals should.
303   EXPECT_TRUE(
304       estimator.UpdateCadenceEstimate(render_interval, frame_interval * 0.75,
305                                       base::TimeDelta(), acceptable_drift));
306   EXPECT_FALSE(estimator.has_cadence());
307 }
308
309 void VerifyCadenceSequence(VideoCadenceEstimator* estimator,
310                            double frame_rate,
311                            double display_rate,
312                            std::vector<int> expected_cadence) {
313   SCOPED_TRACE(base::StringPrintf("Checking %.03f fps into %0.03f", frame_rate,
314                                   display_rate));
315
316   const base::TimeDelta render_interval = Interval(display_rate);
317   const base::TimeDelta frame_interval = Interval(frame_rate);
318   const base::TimeDelta acceptable_drift =
319       frame_interval < render_interval ? render_interval : frame_interval;
320   const base::TimeDelta test_runtime = base::Seconds(10 * 60);
321   const int test_frames = base::ClampFloor(test_runtime / frame_interval);
322
323   estimator->Reset();
324   EXPECT_TRUE(estimator->UpdateCadenceEstimate(
325       render_interval, frame_interval, base::TimeDelta(), acceptable_drift));
326   EXPECT_TRUE(estimator->has_cadence());
327   for (auto i = 0u; i < expected_cadence.size(); i++) {
328     ASSERT_EQ(expected_cadence[i], estimator->GetCadenceForFrame(i))
329         << " i=" << i;
330   }
331
332   int total_display_cycles = 0;
333   for (int i = 0; i < test_frames; i++) {
334     total_display_cycles += estimator->GetCadenceForFrame(i);
335     base::TimeDelta drift =
336         (total_display_cycles * render_interval) - ((i + 1) * frame_interval);
337     EXPECT_LE(drift.magnitude(), acceptable_drift)
338         << " i=" << i << " time=" << (total_display_cycles * render_interval);
339     if (drift.magnitude() > acceptable_drift)
340       break;
341   }
342 }
343
344 }  // namespace media