Upload upstream chromium 108.0.5359.1
[platform/framework/web/chromium-efl.git] / media / filters / video_renderer_algorithm_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_renderer_algorithm.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <cmath>
11 #include <tuple>
12
13 #include "base/bind.h"
14 #include "base/callback_helpers.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/test/simple_test_tick_clock.h"
18 #include "base/time/time.h"
19 #include "build/build_config.h"
20 #include "media/base/media_util.h"
21 #include "media/base/timestamp_constants.h"
22 #include "media/base/video_frame_pool.h"
23 #include "media/base/wall_clock_time_source.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 namespace media {
27
28 // Slows down the given |fps| according to NTSC field reduction standards; see
29 // http://en.wikipedia.org/wiki/Frame_rate#Digital_video_and_television
30 static double NTSC(double fps) {
31   return fps / 1.001;
32 }
33
34 // Helper class for generating TimeTicks in a sequence according to a frequency.
35 class TickGenerator {
36  public:
37   TickGenerator(base::TimeTicks base_timestamp, double hertz)
38       : tick_count_(0),
39         hertz_(hertz),
40         microseconds_per_tick_(base::Time::kMicrosecondsPerSecond / hertz),
41         base_time_(base_timestamp) {}
42
43   TickGenerator(const TickGenerator&) = delete;
44   TickGenerator& operator=(const TickGenerator&) = delete;
45
46   base::TimeDelta interval(int tick_count) const {
47     return base::Microseconds(tick_count * microseconds_per_tick_);
48   }
49
50   base::TimeTicks current() const { return base_time_ + interval(tick_count_); }
51   base::TimeTicks step() { return step(1); }
52   base::TimeTicks step(int n) {
53     tick_count_ += n;
54     return current();
55   }
56
57   double hertz() const { return hertz_; }
58
59   void Reset(base::TimeTicks base_timestamp) {
60     base_time_ = base_timestamp;
61     tick_count_ = 0;
62   }
63
64  private:
65   // Track a tick count and seconds per tick value to ensure we don't drift too
66   // far due to accumulated errors during testing.
67   int64_t tick_count_;
68   const double hertz_;
69   const double microseconds_per_tick_;
70   base::TimeTicks base_time_;
71 };
72
73 class VideoRendererAlgorithmTest : public testing::Test {
74  public:
75   VideoRendererAlgorithmTest()
76       : tick_clock_(new base::SimpleTestTickClock()),
77         algorithm_(base::BindRepeating(&WallClockTimeSource::GetWallClockTimes,
78                                        base::Unretained(&time_source_)),
79                    &media_log_) {
80     // Always start the TickClock at a non-zero value since null values have
81     // special connotations.
82     tick_clock_->Advance(base::Microseconds(10000));
83     time_source_.SetTickClockForTesting(tick_clock_.get());
84   }
85
86   VideoRendererAlgorithmTest(const VideoRendererAlgorithmTest&) = delete;
87   VideoRendererAlgorithmTest& operator=(const VideoRendererAlgorithmTest&) =
88       delete;
89
90   ~VideoRendererAlgorithmTest() override = default;
91
92   scoped_refptr<VideoFrame> CreateFrame(base::TimeDelta timestamp) {
93     const gfx::Size natural_size(8, 8);
94     return frame_pool_.CreateFrame(PIXEL_FORMAT_I420, natural_size,
95                                    gfx::Rect(natural_size), natural_size,
96                                    timestamp);
97   }
98
99   base::TimeDelta minimum_glitch_time() const {
100     return base::Seconds(
101         VideoRendererAlgorithm::kMinimumAcceptableTimeBetweenGlitchesSecs);
102   }
103
104   base::TimeDelta max_acceptable_drift() const {
105     return algorithm_.max_acceptable_drift_;
106   }
107
108   void disable_cadence_hysteresis() {
109     algorithm_.cadence_estimator_.set_cadence_hysteresis_threshold_for_testing(
110         base::TimeDelta());
111   }
112
113   bool last_render_had_glitch() const {
114     return algorithm_.last_render_had_glitch_;
115   }
116
117   bool is_using_cadence() const {
118     return algorithm_.cadence_estimator_.has_cadence();
119   }
120
121   bool IsCadenceBelowOne() const {
122     if (!is_using_cadence())
123       return false;
124
125     return algorithm_.cadence_estimator_.avg_cadence_for_testing() < 1.0;
126   }
127
128   double CadenceValue() const {
129     return algorithm_.cadence_estimator_.avg_cadence_for_testing();
130   }
131
132   size_t frames_queued() const { return algorithm_.frame_queue_.size(); }
133
134   std::string GetCadence(double frame_rate, double display_rate) {
135     TickGenerator display_tg(tick_clock_->NowTicks(), display_rate);
136     TickGenerator frame_tg(base::TimeTicks(), frame_rate);
137     time_source_.StartTicking();
138
139     // Enqueue enough frames for cadence detection.
140     size_t frames_dropped = 0;
141     disable_cadence_hysteresis();
142     algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(0)));
143     algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(1)));
144     EXPECT_TRUE(RenderAndStep(&display_tg, &frames_dropped));
145
146     // Store cadence before reseting the algorithm.
147     const std::string cadence =
148         algorithm_.cadence_estimator_.GetCadenceForTesting();
149     time_source_.StopTicking();
150     algorithm_.Reset();
151     return cadence;
152   }
153
154   base::TimeDelta CalculateAbsoluteDriftForFrame(base::TimeTicks deadline_min,
155                                                  int frame_index) {
156     return algorithm_.CalculateAbsoluteDriftForFrame(deadline_min, frame_index);
157   }
158
159   bool DriftOfLastRenderWasWithinTolerance(base::TimeTicks deadline_min) {
160     return CalculateAbsoluteDriftForFrame(deadline_min, 0) <=
161            algorithm_.max_acceptable_drift_;
162   }
163
164   scoped_refptr<VideoFrame> RenderAndStep(TickGenerator* tg,
165                                           size_t* frames_dropped) {
166     const base::TimeTicks start = tg->current();
167     const base::TimeTicks end = tg->step();
168     return algorithm_.Render(start, end, frames_dropped);
169   }
170
171   // Allows tests to run a Render() loop with sufficient frames for the various
172   // rendering modes. Upon each Render() |render_test_func| will be called with
173   // the rendered frame and the number of frames dropped.
174   template <typename OnRenderCallback>
175   void RunFramePumpTest(bool reset,
176                         TickGenerator* frame_tg,
177                         TickGenerator* display_tg,
178                         OnRenderCallback render_test_func) {
179     SCOPED_TRACE(base::StringPrintf("Rendering %.03f fps into %0.03f",
180                                     frame_tg->hertz(), display_tg->hertz()));
181     tick_clock_->Advance(display_tg->current() - tick_clock_->NowTicks());
182     time_source_.StartTicking();
183
184     const bool fresh_algorithm = !algorithm_.have_rendered_frames_;
185
186     base::TimeDelta last_start_timestamp = kNoTimestamp;
187     bool should_use_cadence = false;
188     int glitch_count = 0;
189     const base::TimeTicks start_time = tick_clock_->NowTicks();
190     while (tick_clock_->NowTicks() - start_time < minimum_glitch_time()) {
191       while (EffectiveFramesQueued() < 3 ||
192              frame_tg->current() - time_source_.CurrentMediaTime() <
193                  base::TimeTicks()) {
194         algorithm_.EnqueueFrame(
195             CreateFrame(frame_tg->current() - base::TimeTicks()));
196         frame_tg->step();
197       }
198
199       size_t frames_dropped = 0;
200       const base::TimeTicks deadline_min = display_tg->current();
201       const base::TimeTicks deadline_max = display_tg->step();
202       scoped_refptr<VideoFrame> frame =
203           algorithm_.Render(deadline_min, deadline_max, &frames_dropped);
204       EXPECT_EQ(deadline_max - deadline_min, algorithm_.render_interval());
205
206       render_test_func(frame, frames_dropped);
207       tick_clock_->Advance(display_tg->current() - tick_clock_->NowTicks());
208
209       if (HasFatalFailure())
210         return;
211
212       // Render() should always return a frame within drift tolerances.
213       ASSERT_TRUE(DriftOfLastRenderWasWithinTolerance(deadline_min));
214
215       // If we have a frame, the timestamps should always be monotonically
216       // increasing.
217       if (frame) {
218         if (last_start_timestamp != kNoTimestamp)
219           ASSERT_LE(last_start_timestamp, frame->timestamp());
220         else
221           last_start_timestamp = frame->timestamp();
222       }
223
224       // Only verify certain properties for fresh instances.
225       if (fresh_algorithm) {
226         ASSERT_NEAR(frame_tg->interval(1).InMicroseconds(),
227                     algorithm_.average_frame_duration().InMicroseconds(), 1);
228
229         if (is_using_cadence() && last_render_had_glitch())
230           ++glitch_count;
231
232         // Once cadence starts, it should never stop for the current set of
233         // tests.
234         if (is_using_cadence())
235           should_use_cadence = true;
236         ASSERT_EQ(is_using_cadence(), should_use_cadence);
237       }
238
239       // When there are no frames, we're not using cadence based selection, or a
240       // frame is under cadence the two queue size reports should be equal to
241       // the number of usable frames; i.e. those frames whose end time was not
242       // within the last render interval.
243       if (!is_using_cadence() || !frames_queued() ||
244           GetCurrentFrameDisplayCount() < GetCurrentFrameIdealDisplayCount()) {
245         ASSERT_NEAR(GetUsableFrameCount(deadline_max), EffectiveFramesQueued(),
246                     fresh_algorithm ? 0 : 1);
247       } else if (is_using_cadence() && !IsCadenceBelowOne()) {
248         // If there was no glitch in the last render, the two queue sizes should
249         // be off by exactly one frame; i.e., the current frame doesn't count.
250         if (!last_render_had_glitch() && fresh_algorithm)
251           ASSERT_EQ(frames_queued() - 1, EffectiveFramesQueued());
252       } else if (IsCadenceBelowOne()) {
253         // The frame estimate should be off by at most one frame.
254         const size_t estimated_frames_queued =
255             std::floor(frames_queued() * CadenceValue());
256         ASSERT_NEAR(EffectiveFramesQueued(), estimated_frames_queued, 1);
257       }
258     }
259
260     // When using cadence, the glitch count should be at most one for when
261     // rendering for the less than minimum_glitch_time().
262     if (fresh_algorithm && is_using_cadence())
263       ASSERT_LE(glitch_count, 1);
264
265     time_source_.StopTicking();
266     if (reset) {
267       algorithm_.Reset();
268       time_source_.SetMediaTime(base::TimeDelta());
269     }
270   }
271
272   int FindBestFrameByCoverage(base::TimeTicks deadline_min,
273                               base::TimeTicks deadline_max,
274                               int* second_best) {
275     return algorithm_.FindBestFrameByCoverage(deadline_min, deadline_max,
276                                               second_best);
277   }
278
279   int FindBestFrameByDrift(base::TimeTicks deadline_min,
280                            base::TimeDelta* selected_frame_drift) {
281     return algorithm_.FindBestFrameByDrift(deadline_min, selected_frame_drift);
282   }
283
284   int GetCurrentFrameDropCount() const {
285     DCHECK_GT(frames_queued(), 0u);
286     return algorithm_.frame_queue_.front().drop_count;
287   }
288
289   int GetCurrentFrameDisplayCount() const {
290     DCHECK_GT(frames_queued(), 0u);
291     return algorithm_.frame_queue_.front().render_count;
292   }
293
294   int GetCurrentFrameIdealDisplayCount() const {
295     DCHECK_GT(frames_queued(), 0u);
296     return algorithm_.frame_queue_.front().ideal_render_count;
297   }
298
299   int AccountForMissedIntervalsAndStep(TickGenerator* tg) {
300     const base::TimeTicks start = tg->current();
301     const base::TimeTicks end = tg->step();
302     return AccountForMissedIntervals(start, end);
303   }
304
305   int AccountForMissedIntervals(base::TimeTicks deadline_min,
306                                 base::TimeTicks deadline_max) {
307     algorithm_.AccountForMissedIntervals(deadline_min, deadline_max);
308     return frames_queued() ? GetCurrentFrameDisplayCount() : -1;
309   }
310
311   size_t GetUsableFrameCount(base::TimeTicks deadline_max) {
312     if (is_using_cadence())
313       return frames_queued();
314
315     for (size_t i = 0; i < frames_queued(); ++i)
316       if (algorithm_.frame_queue_[i].end_time > deadline_max)
317         return frames_queued() - i;
318     return 0;
319   }
320
321   size_t EffectiveFramesQueued() {
322     const size_t expected_frames_queued = algorithm_.effective_frames_queued();
323     // These values should always be in sync.
324     algorithm_.UpdateEffectiveFramesQueued();
325     EXPECT_EQ(expected_frames_queued, algorithm_.effective_frames_queued());
326     return expected_frames_queued;
327   }
328
329  protected:
330   NullMediaLog media_log_;
331   VideoFramePool frame_pool_;
332   std::unique_ptr<base::SimpleTestTickClock> tick_clock_;
333   WallClockTimeSource time_source_;
334   VideoRendererAlgorithm algorithm_;
335 };
336
337 TEST_F(VideoRendererAlgorithmTest, Empty) {
338   TickGenerator tg(tick_clock_->NowTicks(), 50);
339   size_t frames_dropped = 0;
340   EXPECT_EQ(0u, frames_queued());
341   EXPECT_FALSE(RenderAndStep(&tg, &frames_dropped));
342   EXPECT_EQ(0u, frames_dropped);
343   EXPECT_EQ(0u, frames_queued());
344   EXPECT_NE(base::TimeDelta(), max_acceptable_drift());
345 }
346
347 TEST_F(VideoRendererAlgorithmTest, Reset) {
348   TickGenerator tg(tick_clock_->NowTicks(), 50);
349   algorithm_.EnqueueFrame(CreateFrame(tg.interval(0)));
350   EXPECT_EQ(1u, frames_queued());
351   EXPECT_NE(base::TimeDelta(), max_acceptable_drift());
352   algorithm_.Reset();
353   EXPECT_EQ(0u, frames_queued());
354   EXPECT_NE(base::TimeDelta(), max_acceptable_drift());
355
356   // Enqueue a frame and render enough such that the next frame should be
357   // considered ineffective.
358   time_source_.StartTicking();
359   size_t frames_dropped = 0;
360   algorithm_.EnqueueFrame(CreateFrame(tg.interval(0)));
361   algorithm_.EnqueueFrame(CreateFrame(tg.interval(1)));
362   scoped_refptr<VideoFrame> frame = RenderAndStep(&tg, &frames_dropped);
363   ASSERT_TRUE(frame);
364   EXPECT_EQ(tg.interval(0), frame->timestamp());
365   EXPECT_EQ(0u, frames_dropped);
366   EXPECT_EQ(1u, EffectiveFramesQueued());
367
368   for (int i = 0; i < 2; ++i) {
369     frame = RenderAndStep(&tg, &frames_dropped);
370     ASSERT_TRUE(frame);
371     EXPECT_EQ(tg.interval(1), frame->timestamp());
372     EXPECT_EQ(0u, frames_dropped);
373     EXPECT_EQ(0u, EffectiveFramesQueued());
374   }
375   time_source_.StopTicking();
376
377   // After reset the new frame should still be counted as ineffective.
378   algorithm_.Reset(
379       VideoRendererAlgorithm::ResetFlag::kPreserveNextFrameEstimates);
380   algorithm_.EnqueueFrame(CreateFrame(tg.interval(2)));
381   EXPECT_EQ(0u, EffectiveFramesQueued());
382   algorithm_.EnqueueFrame(CreateFrame(tg.interval(3)));
383   ASSERT_EQ(1u, algorithm_.RemoveExpiredFrames(
384                     tg.current() + algorithm_.average_frame_duration()));
385 }
386
387 TEST_F(VideoRendererAlgorithmTest, AccountForMissingIntervals) {
388   TickGenerator tg(tick_clock_->NowTicks(), 50);
389   time_source_.StartTicking();
390
391   // Disable hysteresis since AccountForMissingIntervals() only affects cadence
392   // based rendering.
393   disable_cadence_hysteresis();
394
395   // Simulate Render() called before any frames are present.
396   EXPECT_EQ(-1, AccountForMissedIntervalsAndStep(&tg));
397
398   algorithm_.EnqueueFrame(CreateFrame(tg.interval(0)));
399   algorithm_.EnqueueFrame(CreateFrame(tg.interval(1)));
400   algorithm_.EnqueueFrame(CreateFrame(tg.interval(2)));
401   algorithm_.EnqueueFrame(CreateFrame(tg.interval(3)));
402
403   // Simulate Render() called before any frames have been rendered.
404   EXPECT_EQ(0, AccountForMissedIntervalsAndStep(&tg));
405
406   // Render one frame (several are in the past and will be dropped).
407   base::TimeTicks deadline_min = tg.current();
408   base::TimeTicks deadline_max = tg.step();
409   size_t frames_dropped = 0;
410   scoped_refptr<VideoFrame> frame =
411       algorithm_.Render(deadline_min, deadline_max, &frames_dropped);
412   ASSERT_TRUE(frame);
413   EXPECT_EQ(tg.interval(2), frame->timestamp());
414   EXPECT_EQ(2u, frames_dropped);
415
416   ASSERT_EQ(1, GetCurrentFrameDisplayCount());
417
418   // Now calling AccountForMissingIntervals with an interval which overlaps the
419   // previous should do nothing.
420   deadline_min += tg.interval(1) / 2;
421   deadline_max += tg.interval(1) / 2;
422   EXPECT_EQ(1, AccountForMissedIntervals(deadline_min, deadline_max));
423
424   // Steping by 1.5 intervals, is not enough to increase the count.
425   deadline_min += tg.interval(1);
426   deadline_max += tg.interval(1);
427   EXPECT_EQ(1, AccountForMissedIntervals(deadline_min, deadline_max));
428
429   // Calling it after a full skipped interval should increase the count by 1 for
430   // each skipped interval.
431   tg.step();
432   EXPECT_EQ(2, AccountForMissedIntervalsAndStep(&tg));
433
434   // 4 because [tg.current(), tg.step()] now represents 2 additional intervals.
435   EXPECT_EQ(4, AccountForMissedIntervalsAndStep(&tg));
436
437   // Frame should be way over cadence and no good frames remain, so last frame
438   // should be returned.
439   frame = RenderAndStep(&tg, &frames_dropped);
440   ASSERT_TRUE(frame);
441   EXPECT_EQ(tg.interval(3), frame->timestamp());
442   EXPECT_EQ(0u, frames_dropped);
443   EXPECT_EQ(1, GetCurrentFrameDisplayCount());
444
445   // Stop the time source and verify AccountForMissedIntervals() doesn't try to
446   // account for intervals from pause behavior.
447   time_source_.StopTicking();
448   frame = RenderAndStep(&tg, &frames_dropped);
449   ASSERT_TRUE(frame);
450   EXPECT_EQ(tg.interval(3), frame->timestamp());
451   EXPECT_EQ(0u, frames_dropped);
452   EXPECT_EQ(2, GetCurrentFrameDisplayCount());
453
454   tg.step(100);
455   frame = RenderAndStep(&tg, &frames_dropped);
456   ASSERT_TRUE(frame);
457   EXPECT_EQ(tg.interval(3), frame->timestamp());
458   EXPECT_EQ(0u, frames_dropped);
459   EXPECT_EQ(3, GetCurrentFrameDisplayCount());
460
461   time_source_.StartTicking();
462
463   // Now run the same test using set_time_stopped();
464   frame = RenderAndStep(&tg, &frames_dropped);
465   ASSERT_TRUE(frame);
466   EXPECT_EQ(tg.interval(3), frame->timestamp());
467   EXPECT_EQ(0u, frames_dropped);
468   EXPECT_EQ(4, GetCurrentFrameDisplayCount());
469
470   algorithm_.set_time_stopped();
471   tg.step(100);
472   frame = RenderAndStep(&tg, &frames_dropped);
473   ASSERT_TRUE(frame);
474   EXPECT_EQ(tg.interval(3), frame->timestamp());
475   EXPECT_EQ(0u, frames_dropped);
476   EXPECT_EQ(5, GetCurrentFrameDisplayCount());
477 }
478
479 TEST_F(VideoRendererAlgorithmTest, OnLastFrameDropped) {
480   TickGenerator frame_tg(base::TimeTicks(), 25);
481   TickGenerator display_tg(tick_clock_->NowTicks(), 50);
482   time_source_.StartTicking();
483
484   // Disable hysteresis since OnLastFrameDropped() only affects cadence based
485   // rendering.
486   disable_cadence_hysteresis();
487
488   algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(0)));
489   algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(1)));
490   algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(2)));
491
492   // Render one frame (several are in the past and will be dropped).
493   size_t frames_dropped = 0;
494   scoped_refptr<VideoFrame> frame = RenderAndStep(&display_tg, &frames_dropped);
495   ASSERT_TRUE(frame);
496   EXPECT_EQ(frame_tg.interval(0), frame->timestamp());
497   EXPECT_EQ(0u, frames_dropped);
498
499   // The frame should have its display count decremented once it's reported as
500   // dropped.
501   ASSERT_EQ(1, GetCurrentFrameDisplayCount());
502   ASSERT_EQ(0, GetCurrentFrameDropCount());
503   algorithm_.OnLastFrameDropped();
504   ASSERT_EQ(1, GetCurrentFrameDisplayCount());
505   ASSERT_EQ(1, GetCurrentFrameDropCount());
506
507   // Render the frame again and then force another drop.
508   frame = RenderAndStep(&display_tg, &frames_dropped);
509   ASSERT_TRUE(frame);
510   EXPECT_EQ(frame_tg.interval(0), frame->timestamp());
511   EXPECT_EQ(0u, frames_dropped);
512
513   ASSERT_EQ(2, GetCurrentFrameDisplayCount());
514   ASSERT_EQ(1, GetCurrentFrameDropCount());
515   algorithm_.OnLastFrameDropped();
516   ASSERT_EQ(2, GetCurrentFrameDisplayCount());
517   ASSERT_EQ(2, GetCurrentFrameDropCount());
518
519   // The next Render() call should now count this frame as dropped.
520   frame = RenderAndStep(&display_tg, &frames_dropped);
521   ASSERT_TRUE(frame);
522   EXPECT_EQ(frame_tg.interval(1), frame->timestamp());
523   EXPECT_EQ(1u, frames_dropped);
524   ASSERT_EQ(1, GetCurrentFrameDisplayCount());
525   ASSERT_EQ(0, GetCurrentFrameDropCount());
526
527   // Rendering again should result in the same frame being displayed.
528   frame = RenderAndStep(&display_tg, &frames_dropped);
529   ASSERT_TRUE(frame);
530   EXPECT_EQ(frame_tg.interval(1), frame->timestamp());
531   EXPECT_EQ(0u, frames_dropped);
532
533   // In this case, the drop count is less than the display count, so the frame
534   // should not be counted as dropped.
535   ASSERT_EQ(2, GetCurrentFrameDisplayCount());
536   ASSERT_EQ(0, GetCurrentFrameDropCount());
537   algorithm_.OnLastFrameDropped();
538   ASSERT_EQ(2, GetCurrentFrameDisplayCount());
539   ASSERT_EQ(1, GetCurrentFrameDropCount());
540
541   // The third frame should be rendered correctly now and the previous frame not
542   // counted as having been dropped.
543   frame = RenderAndStep(&display_tg, &frames_dropped);
544   ASSERT_TRUE(frame);
545   EXPECT_EQ(frame_tg.interval(2), frame->timestamp());
546   EXPECT_EQ(0u, frames_dropped);
547 }
548
549 TEST_F(VideoRendererAlgorithmTest, OnLastFrameDroppedFirstFrame) {
550   TickGenerator frame_tg(base::TimeTicks(), 25);
551   TickGenerator display_tg(tick_clock_->NowTicks(), 50);
552   time_source_.StartTicking();
553
554   // Disable hysteresis since OnLastFrameDropped() only affects cadence based
555   // rendering.
556   disable_cadence_hysteresis();
557
558   // Use frames in the future to simulate cases where the first frame may be
559   // renderered many times.
560   algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(5)));
561   algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(6)));
562   algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(7)));
563
564   size_t frames_dropped = 0;
565   scoped_refptr<VideoFrame> frame =
566       algorithm_.Render(base::TimeTicks(), base::TimeTicks(), &frames_dropped);
567   ASSERT_TRUE(frame);
568   EXPECT_EQ(frame_tg.interval(5), frame->timestamp());
569   EXPECT_EQ(0u, frames_dropped);
570
571   // The frame should have its drop count updated once it's reported as dropped.
572   ASSERT_EQ(1, GetCurrentFrameDisplayCount());
573   ASSERT_EQ(0, GetCurrentFrameDropCount());
574   algorithm_.OnLastFrameDropped();
575   ASSERT_EQ(1, GetCurrentFrameDisplayCount());
576   ASSERT_EQ(1, GetCurrentFrameDropCount());
577
578   // Render the frame and check counts at each step.
579   const int kLastValue = 2 * 5 + 2 - 1;  // Cadence is 2, -1 for Render() above.
580   for (int i = 0; i < kLastValue; ++i) {
581     frame = RenderAndStep(&display_tg, &frames_dropped);
582     ASSERT_TRUE(frame);
583     EXPECT_EQ(frame_tg.interval(5), frame->timestamp());
584     EXPECT_EQ(0u, frames_dropped);
585
586     ASSERT_EQ(i + 2, GetCurrentFrameDisplayCount());
587     if (i == 0) {
588       ASSERT_EQ(i + 1, GetCurrentFrameDropCount());
589       algorithm_.OnLastFrameDropped();
590       ASSERT_EQ(i + 2, GetCurrentFrameDisplayCount());
591       ASSERT_EQ(i + 2, GetCurrentFrameDropCount());
592     }
593   }
594
595   // Ensure the next frame does not pick up the overage.
596   frame = RenderAndStep(&display_tg, &frames_dropped);
597   ASSERT_TRUE(frame);
598   EXPECT_EQ(frame_tg.interval(6), frame->timestamp());
599   EXPECT_EQ(0u, frames_dropped);
600
601   ASSERT_EQ(1, GetCurrentFrameDisplayCount());
602   ASSERT_EQ(0, GetCurrentFrameDropCount());
603   algorithm_.OnLastFrameDropped();
604   ASSERT_EQ(1, GetCurrentFrameDisplayCount());
605   ASSERT_EQ(1, GetCurrentFrameDropCount());
606
607   // Stop time and verify cadence overage isn't accumulated for next frame.
608   time_source_.StopTicking();
609   for (int i = 0; i < 5; ++i) {
610     frame = RenderAndStep(&display_tg, &frames_dropped);
611     ASSERT_TRUE(frame);
612     EXPECT_EQ(frame_tg.interval(6), frame->timestamp());
613     EXPECT_EQ(0u, frames_dropped);
614
615     ASSERT_EQ(i + 2, GetCurrentFrameDisplayCount());
616     ASSERT_EQ(1, GetCurrentFrameDropCount());
617   }
618
619   time_source_.StartTicking();
620   frame = RenderAndStep(&display_tg, &frames_dropped);
621   ASSERT_TRUE(frame);
622   EXPECT_EQ(frame_tg.interval(7), frame->timestamp());
623   EXPECT_EQ(0u, frames_dropped);
624
625   ASSERT_EQ(1, GetCurrentFrameDisplayCount());
626   ASSERT_EQ(0, GetCurrentFrameDropCount());
627   algorithm_.OnLastFrameDropped();
628   ASSERT_EQ(1, GetCurrentFrameDisplayCount());
629   ASSERT_EQ(1, GetCurrentFrameDropCount());
630 }
631
632 TEST_F(VideoRendererAlgorithmTest, EffectiveFramesQueued) {
633   TickGenerator frame_tg(base::TimeTicks(), 50);
634   TickGenerator display_tg(tick_clock_->NowTicks(), 25);
635
636   // Disable hysteresis since EffectiveFramesQueued() is tested as part of the
637   // normal frame pump tests when cadence is not present.
638   disable_cadence_hysteresis();
639
640   EXPECT_EQ(0u, EffectiveFramesQueued());
641   time_source_.StartTicking();
642
643   algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(0)));
644   EXPECT_EQ(1u, EffectiveFramesQueued());
645
646   algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(1)));
647   EXPECT_EQ(2u, EffectiveFramesQueued());
648
649   algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(2)));
650   EXPECT_EQ(3u, EffectiveFramesQueued());
651
652   algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(3)));
653   EXPECT_EQ(4u, EffectiveFramesQueued());
654   EXPECT_EQ(4u, frames_queued());
655
656   // Render one frame which will detect cadence...
657   size_t frames_dropped = 0;
658   scoped_refptr<VideoFrame> frame = RenderAndStep(&display_tg, &frames_dropped);
659   ASSERT_TRUE(frame);
660   EXPECT_EQ(frame_tg.interval(0), frame->timestamp());
661   EXPECT_EQ(0u, frames_dropped);
662
663   // Fractional cadence should be detected and the count will decrease.
664   ASSERT_TRUE(is_using_cadence());
665   EXPECT_EQ(1u, EffectiveFramesQueued());
666   EXPECT_EQ(4u, frames_queued());
667
668   // Dropping the last rendered frame should do nothing, since the last frame
669   // is already excluded from the count if it has a display count of 1.
670   algorithm_.OnLastFrameDropped();
671   EXPECT_EQ(1u, EffectiveFramesQueued());
672 }
673
674 TEST_F(VideoRendererAlgorithmTest, EffectiveFramesQueuedWithoutCadence) {
675   TickGenerator tg(tick_clock_->NowTicks(), 60);
676
677   EXPECT_EQ(0u, EffectiveFramesQueued());
678   time_source_.StartTicking();
679
680   algorithm_.EnqueueFrame(CreateFrame(tg.interval(0)));
681   EXPECT_EQ(1u, EffectiveFramesQueued());
682
683   algorithm_.EnqueueFrame(CreateFrame(tg.interval(1)));
684   EXPECT_EQ(2u, EffectiveFramesQueued());
685
686   algorithm_.EnqueueFrame(CreateFrame(tg.interval(2)));
687   EXPECT_EQ(3u, EffectiveFramesQueued());
688
689   algorithm_.EnqueueFrame(CreateFrame(tg.interval(3)));
690   EXPECT_EQ(4u, EffectiveFramesQueued());
691   EXPECT_EQ(4u, frames_queued());
692   EXPECT_EQ(384, algorithm_.GetMemoryUsage());
693
694   // Issue a render call that should drop the first two frames and mark the 3rd
695   // as consumed.
696   tg.step(2);
697   size_t frames_dropped = 0;
698   scoped_refptr<VideoFrame> frame = RenderAndStep(&tg, &frames_dropped);
699   ASSERT_FALSE(is_using_cadence());
700   ASSERT_TRUE(frame);
701   EXPECT_EQ(2u, frames_dropped);
702   EXPECT_EQ(tg.interval(2), frame->timestamp());
703   EXPECT_EQ(1u, EffectiveFramesQueued());
704   EXPECT_EQ(2u, frames_queued());
705   EXPECT_EQ(192, algorithm_.GetMemoryUsage());
706
707   // Rendering one more frame should return 0 effective frames queued.
708   frame = RenderAndStep(&tg, &frames_dropped);
709   ASSERT_FALSE(is_using_cadence());
710   ASSERT_TRUE(frame);
711   EXPECT_EQ(0u, frames_dropped);
712   EXPECT_EQ(tg.interval(3), frame->timestamp());
713   EXPECT_EQ(0u, EffectiveFramesQueued());
714   EXPECT_EQ(1u, frames_queued());
715   EXPECT_EQ(96, algorithm_.GetMemoryUsage());
716 }
717
718 TEST_F(VideoRendererAlgorithmTest, EffectiveFramesQueuedWithoutFrameDropping) {
719   TickGenerator tg(tick_clock_->NowTicks(), 50);
720
721   algorithm_.disable_frame_dropping();
722
723   ASSERT_EQ(0u, EffectiveFramesQueued());
724   time_source_.StartTicking();
725
726   for (size_t i = 0; i < 3; ++i) {
727     algorithm_.EnqueueFrame(CreateFrame(tg.interval(i)));
728     EXPECT_EQ(i + 1, EffectiveFramesQueued());
729     EXPECT_EQ(i + 1, frames_queued());
730   }
731
732   // Issue a render call and verify that undropped frames remain effective.
733   tg.step(2);
734   size_t frames_dropped = 0;
735   scoped_refptr<VideoFrame> frame = RenderAndStep(&tg, &frames_dropped);
736   ASSERT_NE(nullptr, frame);
737   EXPECT_EQ(tg.interval(0), frame->timestamp());
738   EXPECT_EQ(0u, frames_dropped);
739   EXPECT_EQ(2u, EffectiveFramesQueued());
740
741   // As the next frame is consumed, the count of effective frames is
742   // decremented.
743   frame = RenderAndStep(&tg, &frames_dropped);
744   ASSERT_NE(nullptr, frame);
745   EXPECT_EQ(tg.interval(1), frame->timestamp());
746   EXPECT_EQ(0u, frames_dropped);
747   EXPECT_EQ(1u, EffectiveFramesQueued());
748 }
749
750 // The maximum acceptable drift should be updated once we have two frames.
751 TEST_F(VideoRendererAlgorithmTest, AcceptableDriftUpdated) {
752   TickGenerator tg(tick_clock_->NowTicks(), 50);
753
754   size_t frames_dropped = 0;
755   const base::TimeDelta original_drift = max_acceptable_drift();
756   algorithm_.EnqueueFrame(CreateFrame(tg.interval(0)));
757   EXPECT_EQ(1u, frames_queued());
758   EXPECT_TRUE(RenderAndStep(&tg, &frames_dropped));
759   EXPECT_EQ(original_drift, max_acceptable_drift());
760
761   // Time must be ticking to get wall clock times for frames.
762   time_source_.StartTicking();
763
764   algorithm_.EnqueueFrame(CreateFrame(tg.interval(1)));
765   EXPECT_EQ(2u, frames_queued());
766   EXPECT_TRUE(RenderAndStep(&tg, &frames_dropped));
767   EXPECT_NE(original_drift, max_acceptable_drift());
768 }
769
770 // Verifies behavior when time stops.
771 TEST_F(VideoRendererAlgorithmTest, TimeIsStopped) {
772   TickGenerator tg(tick_clock_->NowTicks(), 50);
773
774   // Prior to rendering the first frame, the algorithm should always return the
775   // first available frame.
776   size_t frames_dropped = 0;
777   algorithm_.EnqueueFrame(CreateFrame(tg.interval(0)));
778   EXPECT_EQ(1u, frames_queued());
779   scoped_refptr<VideoFrame> frame = RenderAndStep(&tg, &frames_dropped);
780   ASSERT_TRUE(frame);
781   EXPECT_EQ(tg.interval(0), frame->timestamp());
782   EXPECT_EQ(0u, frames_dropped);
783   EXPECT_EQ(1u, frames_queued());
784   EXPECT_EQ(1u, EffectiveFramesQueued());
785
786   // The same timestamp should be returned after time starts.
787   tick_clock_->Advance(tg.interval(1));
788   time_source_.StartTicking();
789   frame = RenderAndStep(&tg, &frames_dropped);
790   ASSERT_TRUE(frame);
791   EXPECT_EQ(tg.interval(0), frame->timestamp());
792   EXPECT_EQ(0u, frames_dropped);
793   EXPECT_EQ(1u, frames_queued());
794   EXPECT_EQ(1u, EffectiveFramesQueued());
795
796   // Ensure the next suitable frame is vended as time advances.
797   algorithm_.EnqueueFrame(CreateFrame(tg.interval(1)));
798   EXPECT_EQ(2u, frames_queued());
799   EXPECT_EQ(2u, EffectiveFramesQueued());
800   frame = RenderAndStep(&tg, &frames_dropped);
801   ASSERT_TRUE(frame);
802   EXPECT_EQ(tg.interval(1), frame->timestamp());
803   EXPECT_EQ(0u, frames_dropped);
804   EXPECT_EQ(1u, frames_queued());
805   EXPECT_EQ(0u, EffectiveFramesQueued());
806
807   // Once time stops ticking, any further frames shouldn't be returned, even if
808   // the interval requested more closely matches.
809   algorithm_.EnqueueFrame(CreateFrame(tg.interval(2)));
810   time_source_.StopTicking();
811   frame = RenderAndStep(&tg, &frames_dropped);
812   ASSERT_TRUE(frame);
813   EXPECT_EQ(tg.interval(1), frame->timestamp());
814   EXPECT_EQ(0u, frames_dropped);
815   EXPECT_EQ(2u, frames_queued());
816   EXPECT_EQ(1u, EffectiveFramesQueued());
817 }
818
819 // Verify frames inserted out of order end up in the right spot and are rendered
820 // according to the API contract.
821 TEST_F(VideoRendererAlgorithmTest, SortedFrameQueue) {
822   TickGenerator tg(tick_clock_->NowTicks(), 50);
823
824   // Ensure frames handed in out of order before time starts ticking are sorted
825   // and returned in the correct order upon Render().
826   algorithm_.EnqueueFrame(CreateFrame(tg.interval(3)));
827   algorithm_.EnqueueFrame(CreateFrame(tg.interval(2)));
828   EXPECT_EQ(2u, frames_queued());
829   EXPECT_EQ(2u, EffectiveFramesQueued());
830
831   time_source_.StartTicking();
832
833   // The first call should return the earliest frame appended.
834   size_t frames_dropped = 0;
835   scoped_refptr<VideoFrame> frame = RenderAndStep(&tg, &frames_dropped);
836   EXPECT_EQ(0u, frames_dropped);
837   EXPECT_EQ(tg.interval(2), frame->timestamp());
838   EXPECT_EQ(2u, frames_queued());
839   EXPECT_EQ(2u, EffectiveFramesQueued());
840
841   // Since a frame has already been rendered, queuing this frame and calling
842   // Render() should result in it being dropped; even though it's a better
843   // candidate for the desired interval.  The frame is dropped during enqueue so
844   // it won't show up in frames_queued().
845   algorithm_.EnqueueFrame(CreateFrame(tg.interval(1)));
846   EXPECT_EQ(2u, frames_queued());
847   EXPECT_EQ(2u, EffectiveFramesQueued());
848   frame = RenderAndStep(&tg, &frames_dropped);
849   EXPECT_EQ(1u, frames_dropped);
850   EXPECT_EQ(tg.interval(2), frame->timestamp());
851   EXPECT_EQ(2u, frames_queued());
852   EXPECT_EQ(2u, EffectiveFramesQueued());
853 }
854
855 // Run through integer cadence selection for 1, 2, 3, and 4.
856 TEST_F(VideoRendererAlgorithmTest, BestFrameByCadence) {
857   const double kTestRates[][2] = {{60, 60}, {30, 60}, {25, 75}, {25, 100}};
858
859   for (const auto& test_rate : kTestRates) {
860     disable_cadence_hysteresis();
861
862     TickGenerator frame_tg(base::TimeTicks(), test_rate[0]);
863     TickGenerator display_tg(tick_clock_->NowTicks(), test_rate[1]);
864
865     int actual_frame_pattern = 0;
866     const int desired_frame_pattern = test_rate[1] / test_rate[0];
867     scoped_refptr<VideoFrame> current_frame;
868     RunFramePumpTest(
869         true, &frame_tg, &display_tg,
870         [&current_frame, &actual_frame_pattern, desired_frame_pattern, this](
871             scoped_refptr<VideoFrame> frame, size_t frames_dropped) {
872           ASSERT_TRUE(frame);
873           ASSERT_EQ(0u, frames_dropped);
874
875           // Each frame should display for exactly it's desired cadence pattern.
876           if (!current_frame || current_frame == frame) {
877             actual_frame_pattern++;
878           } else {
879             ASSERT_EQ(actual_frame_pattern, desired_frame_pattern);
880             actual_frame_pattern = 1;
881           }
882
883           current_frame = frame;
884           ASSERT_TRUE(is_using_cadence());
885         });
886
887     if (HasFatalFailure())
888       return;
889   }
890 }
891
892 TEST_F(VideoRendererAlgorithmTest, BestFrameByCadenceOverdisplayed) {
893   TickGenerator frame_tg(base::TimeTicks(), 25);
894   TickGenerator display_tg(tick_clock_->NowTicks(), 50);
895   time_source_.StartTicking();
896   disable_cadence_hysteresis();
897
898   algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(0)));
899   algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(1)));
900
901   // Render frames until we've exhausted available frames and the last frame is
902   // forced to be over displayed.
903   for (int i = 0; i < 5; ++i) {
904     size_t frames_dropped = 0;
905     scoped_refptr<VideoFrame> frame =
906         RenderAndStep(&display_tg, &frames_dropped);
907     ASSERT_TRUE(frame);
908     EXPECT_EQ(frame_tg.interval(i < 4 ? i / 2 : 1), frame->timestamp());
909     EXPECT_EQ(0u, frames_dropped);
910     ASSERT_EQ(2, GetCurrentFrameIdealDisplayCount());
911   }
912
913   // Verify last frame is above cadence (2 in this case)
914   ASSERT_EQ(GetCurrentFrameIdealDisplayCount() + 1,
915             GetCurrentFrameDisplayCount());
916   algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(2)));
917   algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(3)));
918
919   // The next frame should still be displayed once, even though the previous
920   // one was displayed twice; the eventual drift reset will correct this (tested
921   // by BestFrameByCadenceOverdisplayedForDrift below).
922   size_t frames_dropped = 0;
923   scoped_refptr<VideoFrame> frame = RenderAndStep(&display_tg, &frames_dropped);
924   ASSERT_TRUE(frame);
925   EXPECT_EQ(frame_tg.interval(2), frame->timestamp());
926   EXPECT_EQ(0u, frames_dropped);
927
928   // Enqueuing a new frame should keep the correct cadence values.
929   algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(4)));
930
931   ASSERT_EQ(1, GetCurrentFrameDisplayCount());
932   ASSERT_EQ(0, GetCurrentFrameDropCount());
933   ASSERT_EQ(2, GetCurrentFrameIdealDisplayCount());
934 }
935
936 TEST_F(VideoRendererAlgorithmTest, BestFrameByCadenceOverdisplayedForDrift) {
937   // Use 24.94 to ensure drift expires pretty rapidly (8.36s in this case).
938   TickGenerator frame_tg(base::TimeTicks(), 24.94);
939   TickGenerator display_tg(tick_clock_->NowTicks(), 50);
940   time_source_.StartTicking();
941   disable_cadence_hysteresis();
942
943   scoped_refptr<VideoFrame> last_frame;
944   bool have_overdisplayed_frame = false;
945   while (!have_overdisplayed_frame) {
946     while (EffectiveFramesQueued() < 2) {
947       algorithm_.EnqueueFrame(
948           CreateFrame(frame_tg.current() - base::TimeTicks()));
949       frame_tg.step();
950     }
951
952     size_t frames_dropped = 0;
953     last_frame = RenderAndStep(&display_tg, &frames_dropped);
954     ASSERT_TRUE(last_frame);
955     ASSERT_TRUE(is_using_cadence());
956     ASSERT_EQ(0u, frames_dropped);
957     ASSERT_EQ(2, GetCurrentFrameIdealDisplayCount());
958     have_overdisplayed_frame = GetCurrentFrameDisplayCount() > 2;
959   }
960
961   ASSERT_TRUE(last_render_had_glitch());
962
963   // We've reached the point where the current frame is over displayed due to
964   // drift, the next frame should resume cadence without accounting for the
965   // overdisplayed frame.
966
967   size_t frames_dropped = 0;
968   scoped_refptr<VideoFrame> next_frame =
969       RenderAndStep(&display_tg, &frames_dropped);
970   ASSERT_EQ(0u, frames_dropped);
971   ASSERT_NE(last_frame, next_frame);
972   ASSERT_TRUE(is_using_cadence());
973   ASSERT_EQ(2, GetCurrentFrameIdealDisplayCount());
974   ASSERT_EQ(1, GetCurrentFrameDisplayCount());
975   last_frame = next_frame;
976
977   next_frame = RenderAndStep(&display_tg, &frames_dropped);
978   ASSERT_EQ(0u, frames_dropped);
979   ASSERT_EQ(last_frame, next_frame);
980   ASSERT_TRUE(is_using_cadence());
981   ASSERT_EQ(2, GetCurrentFrameIdealDisplayCount());
982   ASSERT_EQ(2, GetCurrentFrameDisplayCount());
983 }
984
985 TEST_F(VideoRendererAlgorithmTest, BestFrameByCoverage) {
986   TickGenerator tg(tick_clock_->NowTicks(), 50);
987   time_source_.StartTicking();
988
989   algorithm_.EnqueueFrame(CreateFrame(tg.interval(0)));
990   algorithm_.EnqueueFrame(CreateFrame(tg.interval(1)));
991   algorithm_.EnqueueFrame(CreateFrame(tg.interval(2)));
992
993   base::TimeTicks deadline_min = tg.current();
994   base::TimeTicks deadline_max = deadline_min + tg.interval(1);
995
996   size_t frames_dropped = 0;
997   scoped_refptr<VideoFrame> frame =
998       algorithm_.Render(deadline_min, deadline_max, &frames_dropped);
999   ASSERT_TRUE(frame);
1000   EXPECT_EQ(tg.interval(0), frame->timestamp());
1001   EXPECT_EQ(0u, frames_dropped);
1002
1003   int second_best = 0;
1004
1005   // Coverage should be 1 for if the frame overlaps the interval entirely, no
1006   // second best should be found.
1007   EXPECT_EQ(0,
1008             FindBestFrameByCoverage(deadline_min, deadline_max, &second_best));
1009   EXPECT_EQ(-1, second_best);
1010
1011   // 49/51 coverage for frame 0 and frame 1 should be within tolerance such that
1012   // the earlier frame should still be chosen.
1013   deadline_min = tg.current() + tg.interval(1) / 2 + base::Microseconds(250);
1014   deadline_max = deadline_min + tg.interval(1);
1015   EXPECT_EQ(0,
1016             FindBestFrameByCoverage(deadline_min, deadline_max, &second_best));
1017   EXPECT_EQ(1, second_best);
1018
1019   // 48/52 coverage should result in the second frame being chosen.
1020   deadline_min = tg.current() + tg.interval(1) / 2 + base::Microseconds(500);
1021   deadline_max = deadline_min + tg.interval(1);
1022   EXPECT_EQ(1,
1023             FindBestFrameByCoverage(deadline_min, deadline_max, &second_best));
1024   EXPECT_EQ(0, second_best);
1025
1026   // Overlapping three frames should choose the one with the most coverage and
1027   // the second best should be the earliest frame.
1028   deadline_min = tg.current() + tg.interval(1) / 2;
1029   deadline_max = deadline_min + tg.interval(2);
1030   EXPECT_EQ(1,
1031             FindBestFrameByCoverage(deadline_min, deadline_max, &second_best));
1032   EXPECT_EQ(0, second_best);
1033
1034   // Requesting coverage outside of all known frames should return -1 for both
1035   // best indices.
1036   deadline_min = tg.current() + tg.interval(frames_queued());
1037   deadline_max = deadline_min + tg.interval(1);
1038   EXPECT_EQ(-1,
1039             FindBestFrameByCoverage(deadline_min, deadline_max, &second_best));
1040   EXPECT_EQ(-1, second_best);
1041 }
1042
1043 TEST_F(VideoRendererAlgorithmTest, BestFrameByDriftAndDriftCalculations) {
1044   TickGenerator tg(tick_clock_->NowTicks(), 50);
1045   time_source_.StartTicking();
1046
1047   algorithm_.EnqueueFrame(CreateFrame(tg.interval(0)));
1048   algorithm_.EnqueueFrame(CreateFrame(tg.interval(1)));
1049
1050   size_t frames_dropped = 0;
1051   scoped_refptr<VideoFrame> frame = algorithm_.Render(
1052       tg.current(), tg.current() + tg.interval(1), &frames_dropped);
1053   ASSERT_TRUE(frame);
1054   EXPECT_EQ(tg.interval(0), frame->timestamp());
1055   EXPECT_EQ(0u, frames_dropped);
1056
1057   base::TimeDelta zero_drift, half_drift = tg.interval(1) / 2;
1058   base::TimeDelta detected_drift;
1059
1060   // Frame_0 overlaps the deadline, Frame_1 is a full interval away.
1061   base::TimeTicks deadline = tg.current();
1062   EXPECT_EQ(zero_drift, CalculateAbsoluteDriftForFrame(deadline, 0));
1063   EXPECT_EQ(tg.interval(1), CalculateAbsoluteDriftForFrame(deadline, 1));
1064   EXPECT_EQ(0, FindBestFrameByDrift(deadline, &detected_drift));
1065   EXPECT_EQ(zero_drift, detected_drift);
1066
1067   // Frame_0 overlaps the deadline, Frame_1 is a half interval away.
1068   deadline += half_drift;
1069   EXPECT_EQ(zero_drift, CalculateAbsoluteDriftForFrame(deadline, 0));
1070   EXPECT_EQ(half_drift, CalculateAbsoluteDriftForFrame(deadline, 1));
1071   EXPECT_EQ(0, FindBestFrameByDrift(deadline, &detected_drift));
1072   EXPECT_EQ(zero_drift, detected_drift);
1073
1074   // Both frames overlap the deadline.
1075   deadline += half_drift;
1076   EXPECT_EQ(zero_drift, CalculateAbsoluteDriftForFrame(deadline, 0));
1077   EXPECT_EQ(zero_drift, CalculateAbsoluteDriftForFrame(deadline, 1));
1078   EXPECT_EQ(1, FindBestFrameByDrift(deadline, &detected_drift));
1079   EXPECT_EQ(zero_drift, detected_drift);
1080
1081   // Frame_0 is half an interval away, Frame_1 overlaps the deadline.
1082   deadline += half_drift;
1083   EXPECT_EQ(half_drift, CalculateAbsoluteDriftForFrame(deadline, 0));
1084   EXPECT_EQ(zero_drift, CalculateAbsoluteDriftForFrame(deadline, 1));
1085   EXPECT_EQ(1, FindBestFrameByDrift(deadline, &detected_drift));
1086   EXPECT_EQ(zero_drift, detected_drift);
1087
1088   // Frame_0 is a full interval away, Frame_1 overlaps the deadline.
1089   deadline += half_drift;
1090   EXPECT_EQ(tg.interval(1), CalculateAbsoluteDriftForFrame(deadline, 0));
1091   EXPECT_EQ(zero_drift, CalculateAbsoluteDriftForFrame(deadline, 1));
1092   EXPECT_EQ(1, FindBestFrameByDrift(deadline, &detected_drift));
1093   EXPECT_EQ(zero_drift, detected_drift);
1094
1095   // Both frames are entirely before the deadline.
1096   deadline += half_drift;
1097   EXPECT_EQ(tg.interval(1) + half_drift,
1098             CalculateAbsoluteDriftForFrame(deadline, 0));
1099   EXPECT_EQ(half_drift, CalculateAbsoluteDriftForFrame(deadline, 1));
1100   EXPECT_EQ(1, FindBestFrameByDrift(deadline, &detected_drift));
1101   EXPECT_EQ(half_drift, detected_drift);
1102 }
1103
1104 // Run through fractional cadence selection for 1/2, 1/3, and 1/4.
1105 TEST_F(VideoRendererAlgorithmTest, BestFrameByFractionalCadence) {
1106   const double kTestRates[][2] = {{120, 60}, {72, 24}, {100, 25}};
1107
1108   for (const auto& test_rate : kTestRates) {
1109     disable_cadence_hysteresis();
1110
1111     TickGenerator frame_tg(base::TimeTicks(), test_rate[0]);
1112     TickGenerator display_tg(tick_clock_->NowTicks(), test_rate[1]);
1113
1114     scoped_refptr<VideoFrame> current_frame;
1115     RunFramePumpTest(true, &frame_tg, &display_tg,
1116                      [&current_frame, this](scoped_refptr<VideoFrame> frame,
1117                                             size_t frames_dropped) {
1118                        ASSERT_TRUE(frame);
1119
1120                        // We don't count frames dropped that cadence says we
1121                        // should skip.
1122                        ASSERT_EQ(0u, frames_dropped);
1123                        ASSERT_NE(current_frame, frame);
1124                        ASSERT_TRUE(is_using_cadence());
1125                        current_frame = frame;
1126                      });
1127
1128     if (HasFatalFailure())
1129       return;
1130   }
1131 }
1132
1133 // Verify a 3:2 frame pattern for 23.974fps and 24fps in 60Hz.
1134 TEST_F(VideoRendererAlgorithmTest, FilmCadence) {
1135   const double kTestRates[] = {NTSC(24), 24};
1136   disable_cadence_hysteresis();
1137
1138   for (double frame_rate : kTestRates) {
1139     scoped_refptr<VideoFrame> current_frame;
1140     int actual_frame_pattern = 0, desired_frame_pattern = 3;
1141
1142     TickGenerator frame_tg(base::TimeTicks(), frame_rate);
1143     TickGenerator display_tg(tick_clock_->NowTicks(), 60);
1144
1145     RunFramePumpTest(
1146         true, &frame_tg, &display_tg,
1147         [&current_frame, &actual_frame_pattern, &desired_frame_pattern, this](
1148             scoped_refptr<VideoFrame> frame, size_t frames_dropped) {
1149           ASSERT_TRUE(frame);
1150           ASSERT_EQ(0u, frames_dropped);
1151
1152           if (!current_frame || current_frame == frame) {
1153             actual_frame_pattern++;
1154           } else {
1155             ASSERT_EQ(actual_frame_pattern, desired_frame_pattern);
1156             actual_frame_pattern = 1;
1157             desired_frame_pattern = (desired_frame_pattern == 3 ? 2 : 3);
1158           }
1159
1160           current_frame = frame;
1161           ASSERT_TRUE(is_using_cadence());
1162         });
1163
1164     if (HasFatalFailure())
1165       return;
1166   }
1167 }
1168
1169 // Spot check common display and frame rate pairs for correctness.
1170 TEST_F(VideoRendererAlgorithmTest, CadenceCalculations) {
1171   ASSERT_EQ("[3:2]", GetCadence(24, 60));
1172   ASSERT_EQ("[3:2]", GetCadence(NTSC(24), 60));
1173   ASSERT_EQ("[2:3:2:3:2]", GetCadence(25, 60));
1174   ASSERT_EQ("[2]", GetCadence(NTSC(30), 60));
1175   ASSERT_EQ("[2]", GetCadence(30, 60));
1176   ASSERT_EQ("[1:1:2:1:1]", GetCadence(50, 60));
1177   ASSERT_EQ("[1]", GetCadence(NTSC(60), 60));
1178   ASSERT_EQ("[1:0]", GetCadence(120, 60));
1179
1180   // 50Hz is common in the EU.
1181   ASSERT_EQ("[]", GetCadence(NTSC(24), 50));
1182   ASSERT_EQ("[]", GetCadence(24, 50));
1183   ASSERT_EQ("[2]", GetCadence(NTSC(25), 50));
1184   ASSERT_EQ("[2]", GetCadence(25, 50));
1185   ASSERT_EQ("[2:1:2]", GetCadence(NTSC(30), 50));
1186   ASSERT_EQ("[2:1:2]", GetCadence(30, 50));
1187   ASSERT_EQ("[]", GetCadence(NTSC(60), 50));
1188   ASSERT_EQ("[]", GetCadence(60, 50));
1189
1190   ASSERT_EQ("[2:3:2:3:2]", GetCadence(25, NTSC(60)));
1191   ASSERT_EQ("[1:0]", GetCadence(120, NTSC(60)));
1192   ASSERT_EQ("[60]", GetCadence(1, NTSC(60)));
1193 }
1194
1195 TEST_F(VideoRendererAlgorithmTest, RemoveExpiredFramesWithoutRendering) {
1196   TickGenerator tg(tick_clock_->NowTicks(), 50);
1197
1198   // Removing expired frames before anything is enqueued should do nothing.
1199   ASSERT_EQ(0u, algorithm_.RemoveExpiredFrames(tg.current()));
1200
1201   // First verify that frames without a duration are always effective when only
1202   // one frame is present in the queue.
1203   algorithm_.EnqueueFrame(CreateFrame(tg.interval(0)));
1204   ASSERT_EQ(0u, algorithm_.RemoveExpiredFrames(tg.current()));
1205   EXPECT_EQ(1u, EffectiveFramesQueued());
1206
1207   ASSERT_EQ(0u, algorithm_.RemoveExpiredFrames(tg.current() + tg.interval(3)));
1208   EXPECT_EQ(1u, EffectiveFramesQueued());
1209
1210   algorithm_.Reset();
1211
1212   // Now try a frame with duration information, this frame should not be counted
1213   // as effective since we know the duration of it. It is not removed since we
1214   // only have one frame in the queue though.
1215   auto frame = CreateFrame(tg.interval(0));
1216   frame->metadata().frame_duration = tg.interval(1);
1217   algorithm_.EnqueueFrame(frame);
1218   ASSERT_EQ(0u, algorithm_.RemoveExpiredFrames(tg.current() + tg.interval(3)));
1219   EXPECT_EQ(0u, EffectiveFramesQueued());
1220 }
1221
1222 TEST_F(VideoRendererAlgorithmTest, RemoveExpiredFrames) {
1223   TickGenerator tg(tick_clock_->NowTicks(), 50);
1224
1225   // Removing expired frames before anything is enqueued should do nothing.
1226   ASSERT_EQ(0u, algorithm_.RemoveExpiredFrames(tg.current()));
1227
1228   algorithm_.EnqueueFrame(CreateFrame(tg.interval(0)));
1229   ASSERT_EQ(0u, algorithm_.RemoveExpiredFrames(tg.current()));
1230   EXPECT_EQ(1u, EffectiveFramesQueued());
1231
1232   time_source_.StartTicking();
1233
1234   size_t frames_dropped = 0;
1235   scoped_refptr<VideoFrame> frame = RenderAndStep(&tg, &frames_dropped);
1236   ASSERT_TRUE(frame);
1237   EXPECT_EQ(tg.interval(0), frame->timestamp());
1238   EXPECT_EQ(0u, frames_dropped);
1239
1240   algorithm_.EnqueueFrame(CreateFrame(tg.interval(1)));
1241   algorithm_.EnqueueFrame(CreateFrame(tg.interval(2)));
1242   algorithm_.EnqueueFrame(CreateFrame(tg.interval(3)));
1243   algorithm_.EnqueueFrame(CreateFrame(tg.interval(4)));
1244   EXPECT_EQ(5u, EffectiveFramesQueued());
1245
1246   tg.step(2);
1247   // Two frames are removed, one displayed frame (which should not be counted as
1248   // dropped) and one undisplayed one.
1249   ASSERT_EQ(2u, algorithm_.RemoveExpiredFrames(tg.current()));
1250   // Since we just removed the last rendered frame, OnLastFrameDropped() should
1251   // be ignored.
1252   algorithm_.OnLastFrameDropped();
1253   frame = RenderAndStep(&tg, &frames_dropped);
1254   EXPECT_EQ(0u, frames_dropped);
1255   EXPECT_EQ(2u, frames_queued());
1256   EXPECT_EQ(1u, EffectiveFramesQueued());
1257   ASSERT_TRUE(frame);
1258   EXPECT_EQ(tg.interval(3), frame->timestamp());
1259
1260   // Advance expiry enough that one frame is removed, but one remains and is
1261   // still counted as effective; the expired frame was displayed so it is not
1262   // counted as dropped.
1263   ASSERT_EQ(
1264       0u, algorithm_.RemoveExpiredFrames(tg.current() + tg.interval(1) * 0.9));
1265   EXPECT_EQ(1u, frames_queued());
1266   EXPECT_EQ(1u, EffectiveFramesQueued());
1267
1268   // Advancing expiry once more should mark the frame as ineffective.
1269   tg.step();
1270   ASSERT_EQ(0u, algorithm_.RemoveExpiredFrames(tg.current()));
1271   EXPECT_EQ(1u, frames_queued());
1272   EXPECT_EQ(0u, EffectiveFramesQueued());
1273 }
1274
1275 TEST_F(VideoRendererAlgorithmTest, RemoveExpiredFramesPartialReset) {
1276   TickGenerator tg(tick_clock_->NowTicks(), 50);
1277
1278   algorithm_.EnqueueFrame(CreateFrame(tg.interval(0)));
1279   algorithm_.EnqueueFrame(CreateFrame(tg.interval(1)));
1280   ASSERT_EQ(0u, algorithm_.RemoveExpiredFrames(tg.current()));
1281   EXPECT_EQ(2u, EffectiveFramesQueued());
1282
1283   time_source_.StartTicking();
1284
1285   // Render such that the next enqueued frame should be counting as expired.
1286   for (int i = 0; i < 3; ++i) {
1287     size_t frames_dropped = 0;
1288     scoped_refptr<VideoFrame> frame = RenderAndStep(&tg, &frames_dropped);
1289     ASSERT_TRUE(frame);
1290     EXPECT_EQ(tg.interval(std::min(i, 1)), frame->timestamp());
1291     EXPECT_EQ(0u, frames_dropped);
1292   }
1293
1294   time_source_.StopTicking();
1295   algorithm_.Reset(
1296       VideoRendererAlgorithm::ResetFlag::kPreserveNextFrameEstimates);
1297   // Skip ahead several frames to ensure EnqueueFrame() estimates correctly.
1298   algorithm_.EnqueueFrame(CreateFrame(tg.interval(5)));
1299   EXPECT_EQ(1u, EffectiveFramesQueued());
1300   ASSERT_EQ(0u, algorithm_.RemoveExpiredFrames(tg.current()));
1301   EXPECT_EQ(1u, EffectiveFramesQueued());
1302 }
1303
1304 TEST_F(VideoRendererAlgorithmTest, RemoveExpiredFramesCadence) {
1305   TickGenerator tg(tick_clock_->NowTicks(), 50);
1306   disable_cadence_hysteresis();
1307
1308   algorithm_.EnqueueFrame(CreateFrame(tg.interval(0)));
1309   algorithm_.EnqueueFrame(CreateFrame(tg.interval(1)));
1310   algorithm_.EnqueueFrame(CreateFrame(tg.interval(2)));
1311
1312   ASSERT_EQ(0u, algorithm_.RemoveExpiredFrames(tg.current()));
1313   EXPECT_EQ(3u, EffectiveFramesQueued());
1314
1315   time_source_.StartTicking();
1316
1317   size_t frames_dropped = 0;
1318   scoped_refptr<VideoFrame> frame = RenderAndStep(&tg, &frames_dropped);
1319   ASSERT_TRUE(frame);
1320   EXPECT_EQ(tg.interval(0), frame->timestamp());
1321   EXPECT_EQ(0u, frames_dropped);
1322   ASSERT_TRUE(is_using_cadence());
1323   EXPECT_EQ(2u, EffectiveFramesQueued());
1324
1325   // Advance expiry enough that some frames are removed, but one remains and is
1326   // still counted as effective.  1 undisplayed and 1 displayed frame will be
1327   // expired.
1328   ASSERT_EQ(1u, algorithm_.RemoveExpiredFrames(tg.current() + tg.interval(1) +
1329                                                max_acceptable_drift() * 1.25));
1330   EXPECT_EQ(1u, frames_queued());
1331   EXPECT_EQ(1u, EffectiveFramesQueued());
1332
1333   // Advancing expiry once more should mark the frame as ineffective.
1334   tg.step(3);
1335   ASSERT_EQ(0u, algorithm_.RemoveExpiredFrames(tg.current()));
1336   EXPECT_EQ(1u, frames_queued());
1337   EXPECT_EQ(0u, EffectiveFramesQueued());
1338 }
1339
1340 TEST_F(VideoRendererAlgorithmTest, RemoveExpiredFramesFractionalCadence) {
1341   TickGenerator frame_tg(base::TimeTicks(), 60);
1342   TickGenerator display_tg(tick_clock_->NowTicks(), 30);
1343   disable_cadence_hysteresis();
1344
1345   constexpr size_t kFrameCount = 5;
1346   for (size_t i = 0; i < kFrameCount; ++i)
1347     algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(i)));
1348
1349   ASSERT_EQ(0u, algorithm_.RemoveExpiredFrames(display_tg.current()));
1350   EXPECT_EQ(kFrameCount, EffectiveFramesQueued());
1351
1352   time_source_.StartTicking();
1353
1354   size_t frames_dropped = 0;
1355   scoped_refptr<VideoFrame> frame = RenderAndStep(&display_tg, &frames_dropped);
1356   ASSERT_TRUE(frame);
1357   EXPECT_EQ(frame_tg.interval(0), frame->timestamp());
1358   EXPECT_EQ(0u, frames_dropped);
1359   ASSERT_TRUE(is_using_cadence());
1360   EXPECT_EQ((kFrameCount - 1) / 2, EffectiveFramesQueued());
1361   EXPECT_EQ(kFrameCount, frames_queued());
1362
1363   // Advance expiry enough that some frames are removed, but one remains and is
1364   // still counted as effective.  1 undisplayed and 1 displayed frame will be
1365   // expired.
1366   ASSERT_EQ(1u, algorithm_.RemoveExpiredFrames(display_tg.current() +
1367                                                display_tg.interval(1) +
1368                                                max_acceptable_drift() * 1.25));
1369   EXPECT_EQ(1u, frames_queued());
1370   EXPECT_EQ(1u, EffectiveFramesQueued());
1371
1372   // Advancing expiry once more should mark the frame as ineffective.
1373   display_tg.step(3);
1374   ASSERT_EQ(0u, algorithm_.RemoveExpiredFrames(display_tg.current()));
1375   EXPECT_EQ(1u, frames_queued());
1376   EXPECT_EQ(0u, EffectiveFramesQueued());
1377 }
1378
1379 class VideoRendererAlgorithmCadenceTest
1380     : public VideoRendererAlgorithmTest,
1381       public ::testing::WithParamInterface<::testing::tuple<double, double>> {};
1382
1383 TEST_P(VideoRendererAlgorithmCadenceTest, CadenceTest) {
1384   double display_rate = std::get<0>(GetParam());
1385   double frame_rate = std::get<1>(GetParam());
1386
1387   TickGenerator frame_tg(base::TimeTicks(), frame_rate);
1388   TickGenerator display_tg(tick_clock_->NowTicks(), display_rate);
1389   RunFramePumpTest(
1390       true, &frame_tg, &display_tg,
1391       [](scoped_refptr<VideoFrame> frame, size_t frames_dropped) {});
1392 }
1393
1394 // Common display rates.
1395 const double kDisplayRates[] = {
1396     NTSC(24), 24, NTSC(25), 25, NTSC(30), 30,  48,
1397     NTSC(50), 50, NTSC(60), 60, 75,       120, 144,
1398 };
1399
1400 // List of common frame rate values. Values pulled from local test media,
1401 // videostack test matrix, and Wikipedia.
1402 const double kTestRates[] = {
1403     1,        10, 12.5,  15,  NTSC(24), 24,  NTSC(25), 25,
1404     NTSC(30), 30, 30.12, 48,  NTSC(50), 50,  58.74,    NTSC(60),
1405     60,       72, 90,    100, 120,      144, 240,      300,
1406 };
1407
1408 INSTANTIATE_TEST_SUITE_P(All,
1409                          VideoRendererAlgorithmCadenceTest,
1410                          ::testing::Combine(::testing::ValuesIn(kDisplayRates),
1411                                             ::testing::ValuesIn(kTestRates)));
1412
1413 // Rotate through various playback rates and ensure algorithm adapts correctly.
1414 TEST_F(VideoRendererAlgorithmTest, VariablePlaybackRateCadence) {
1415   TickGenerator frame_tg(base::TimeTicks(), NTSC(30));
1416   TickGenerator display_tg(tick_clock_->NowTicks(), 60);
1417
1418   const double kPlaybackRates[] = {1.0, 2, 0.215, 0.5, 1.0, 3.15};
1419   const bool kTestRateHasCadence[std::size(kPlaybackRates)] = {
1420       true, true, true, true, true, false};
1421
1422   for (size_t i = 0; i < std::size(kPlaybackRates); ++i) {
1423     const double playback_rate = kPlaybackRates[i];
1424     SCOPED_TRACE(base::StringPrintf("Playback Rate: %.03f", playback_rate));
1425     time_source_.SetPlaybackRate(playback_rate);
1426     RunFramePumpTest(
1427         false, &frame_tg, &display_tg,
1428         [](scoped_refptr<VideoFrame> frame, size_t frames_dropped) {});
1429     if (HasFatalFailure())
1430       return;
1431
1432     ASSERT_EQ(kTestRateHasCadence[i], is_using_cadence());
1433   }
1434
1435   // TODO(dalecurtis): Is there more we can test here?
1436 }
1437
1438 // Ensures media which only expresses timestamps in milliseconds, gets the right
1439 // cadence detection.
1440 TEST_F(VideoRendererAlgorithmTest, UglyTimestampsHaveCadence) {
1441   TickGenerator display_tg(tick_clock_->NowTicks(), 60);
1442   time_source_.StartTicking();
1443
1444   // 59.94fps, timestamp deltas from https://youtu.be/byoLvAo9qjs
1445   const int kBadTimestampsMs[] = {
1446       17, 16, 17, 17, 16, 17, 17, 16, 17, 17, 17, 16, 17, 17, 16, 17, 17, 16,
1447       17, 17, 16, 17, 17, 16, 17, 17, 16, 17, 17, 17, 16, 17, 17, 16, 17, 17,
1448       16, 17, 17, 16, 17, 17, 16, 17, 17, 16, 17, 17, 16, 17, 17, 17};
1449
1450   // Run throught ~1.6 seconds worth of frames.
1451   bool cadence_detected = false;
1452   base::TimeDelta timestamp;
1453   for (size_t i = 0; i < std::size(kBadTimestampsMs) * 2; ++i) {
1454     while (EffectiveFramesQueued() < 3) {
1455       algorithm_.EnqueueFrame(CreateFrame(timestamp));
1456       timestamp +=
1457           base::Milliseconds(kBadTimestampsMs[i % std::size(kBadTimestampsMs)]);
1458     }
1459
1460     size_t frames_dropped = 0;
1461     RenderAndStep(&display_tg, &frames_dropped);
1462     ASSERT_EQ(0u, frames_dropped);
1463
1464     // Cadence won't be detected immediately on this clip, but it will after
1465     // enough frames are encountered; after which it should not drop out of
1466     // cadence.
1467     if (is_using_cadence())
1468       cadence_detected = true;
1469
1470     if (cadence_detected)
1471       ASSERT_TRUE(is_using_cadence());
1472   }
1473 }
1474
1475 // Ensures media with variable frame rate should not be applied with Cadence.
1476 TEST_F(VideoRendererAlgorithmTest, VariableFrameRateNoCadence) {
1477   TickGenerator display_tg(tick_clock_->NowTicks(), 60);
1478   time_source_.StartTicking();
1479
1480   const int kBadTimestampsMs[] = {200,  200,  200,  200,  200,  1000,
1481                                   1000, 1000, 1000, 200,  200,  200,
1482                                   200,  200,  1000, 1000, 1000, 1000};
1483
1484   // Run throught ~10 seconds worth of frames.
1485   bool cadence_detected = false;
1486   bool cadence_turned_off = false;
1487   base::TimeDelta timestamp;
1488   for (size_t i = 0; i < std::size(kBadTimestampsMs);) {
1489     while (EffectiveFramesQueued() < 3) {
1490       algorithm_.EnqueueFrame(CreateFrame(timestamp));
1491       timestamp +=
1492           base::Milliseconds(kBadTimestampsMs[i % std::size(kBadTimestampsMs)]);
1493       ++i;
1494     }
1495
1496     size_t frames_dropped = 0;
1497     RenderAndStep(&display_tg, &frames_dropped);
1498     ASSERT_EQ(0u, frames_dropped);
1499
1500     // Cadence would be detected during the first second, and then
1501     // it should be off due to variable FPS detection, and then for this
1502     // sample, it should never be on.
1503     if (is_using_cadence())
1504       cadence_detected = true;
1505
1506     if (cadence_detected) {
1507       if (!is_using_cadence())
1508         cadence_turned_off = true;
1509     }
1510
1511     if (cadence_turned_off) {
1512       ASSERT_FALSE(is_using_cadence());
1513     }
1514   }
1515
1516   // Make sure Cadence is turned off somewhen, not always on.
1517   ASSERT_TRUE(cadence_turned_off);
1518 }
1519
1520 TEST_F(VideoRendererAlgorithmTest, EnqueueFrames) {
1521   TickGenerator tg(base::TimeTicks(), 50);
1522   time_source_.StartTicking();
1523
1524   EXPECT_EQ(0u, frames_queued());
1525   scoped_refptr<VideoFrame> frame_1 = CreateFrame(tg.interval(0));
1526   algorithm_.EnqueueFrame(frame_1);
1527   EXPECT_EQ(1u, frames_queued());
1528
1529   // Enqueuing a frame with the same timestamp should always be dropped.
1530   scoped_refptr<VideoFrame> frame_2 = CreateFrame(tg.interval(0));
1531   algorithm_.EnqueueFrame(frame_2);
1532   EXPECT_EQ(1u, frames_queued());
1533
1534   size_t frames_dropped = 0;
1535   scoped_refptr<VideoFrame> rendered_frame =
1536       RenderAndStep(&tg, &frames_dropped);
1537   EXPECT_EQ(1u, frames_queued());
1538   EXPECT_EQ(frame_1, rendered_frame);
1539   EXPECT_EQ(1, GetCurrentFrameDisplayCount());
1540
1541   // The replaced frame should count as dropped.
1542   EXPECT_EQ(1u, frames_dropped);
1543
1544   // Trying to replace frame_1 with frame_2 should do nothing.
1545   algorithm_.EnqueueFrame(frame_2);
1546   EXPECT_EQ(1u, frames_queued());
1547
1548   rendered_frame = RenderAndStep(&tg, &frames_dropped);
1549   EXPECT_EQ(1u, frames_queued());
1550   EXPECT_EQ(frame_1, rendered_frame);
1551   EXPECT_EQ(1u, frames_dropped);
1552   EXPECT_EQ(2, GetCurrentFrameDisplayCount());
1553
1554   // Trying to add a frame < 1 ms after the last frame should drop the frame.
1555   algorithm_.EnqueueFrame(CreateFrame(base::Microseconds(999)));
1556   rendered_frame = RenderAndStep(&tg, &frames_dropped);
1557   EXPECT_EQ(1u, frames_queued());
1558   EXPECT_EQ(frame_1, rendered_frame);
1559   EXPECT_EQ(1u, frames_dropped);
1560   EXPECT_EQ(3, GetCurrentFrameDisplayCount());
1561
1562   scoped_refptr<VideoFrame> frame_3 = CreateFrame(tg.interval(1));
1563   algorithm_.EnqueueFrame(frame_3);
1564   EXPECT_EQ(2u, frames_queued());
1565
1566   // Trying to add a frame < 1 ms before the last frame should drop the frame.
1567   algorithm_.EnqueueFrame(
1568       CreateFrame(tg.interval(1) - base::Microseconds(999)));
1569   rendered_frame = RenderAndStep(&tg, &frames_dropped);
1570   EXPECT_EQ(1u, frames_queued());
1571   EXPECT_EQ(frame_3, rendered_frame);
1572   EXPECT_EQ(1u, frames_dropped);
1573   EXPECT_EQ(1, GetCurrentFrameDisplayCount());
1574 }
1575
1576 TEST_F(VideoRendererAlgorithmTest, CadenceForFutureFrames) {
1577   TickGenerator tg(base::TimeTicks(), 50);
1578   time_source_.StartTicking();
1579
1580   disable_cadence_hysteresis();
1581
1582   algorithm_.EnqueueFrame(CreateFrame(tg.interval(10)));
1583   algorithm_.EnqueueFrame(CreateFrame(tg.interval(11)));
1584   algorithm_.EnqueueFrame(CreateFrame(tg.interval(12)));
1585   EXPECT_EQ(3u, frames_queued());
1586
1587   // Call Render() a few times to increment the render count.
1588   for (int i = 0; i < 10; ++i) {
1589     size_t frames_dropped = 0;
1590     scoped_refptr<VideoFrame> rendered_frame =
1591         RenderAndStep(&tg, &frames_dropped);
1592     EXPECT_EQ(3u, frames_queued());
1593     EXPECT_EQ(tg.interval(10), rendered_frame->timestamp());
1594     ASSERT_TRUE(is_using_cadence());
1595   }
1596
1597   // Add some noise to the tick generator so it our first frame
1598   // doesn't line up evenly on a deadline.
1599   tg.Reset(tg.current() + base::Milliseconds(5));
1600
1601   // We're now at the first frame, cadence should be one, so
1602   // it should only be displayed once.
1603   size_t frames_dropped = 0;
1604   scoped_refptr<VideoFrame> rendered_frame =
1605       RenderAndStep(&tg, &frames_dropped);
1606   EXPECT_EQ(3u, frames_queued());
1607   EXPECT_EQ(tg.interval(10), rendered_frame->timestamp());
1608   ASSERT_TRUE(is_using_cadence());
1609
1610   // Then the next frame should be displayed.
1611   rendered_frame = RenderAndStep(&tg, &frames_dropped);
1612   EXPECT_EQ(2u, frames_queued());
1613   EXPECT_EQ(tg.interval(11), rendered_frame->timestamp());
1614   ASSERT_TRUE(is_using_cadence());
1615
1616   // Finally the last frame.
1617   rendered_frame = RenderAndStep(&tg, &frames_dropped);
1618   EXPECT_EQ(1u, frames_queued());
1619   EXPECT_EQ(tg.interval(12), rendered_frame->timestamp());
1620   ASSERT_TRUE(is_using_cadence());
1621 }
1622
1623 TEST_F(VideoRendererAlgorithmTest, InfiniteDurationMetadata) {
1624   TickGenerator tg(tick_clock_->NowTicks(), 50);
1625
1626   auto frame = CreateFrame(kInfiniteDuration);
1627   frame->metadata().frame_duration = tg.interval(1);
1628   algorithm_.EnqueueFrame(frame);
1629
1630   // This should not crash or fail.
1631   size_t frames_dropped = 0;
1632   frame = RenderAndStep(&tg, &frames_dropped);
1633   EXPECT_TRUE(algorithm_.average_frame_duration().is_zero());
1634 }
1635
1636 TEST_F(VideoRendererAlgorithmTest, UsesFrameDuration) {
1637   TickGenerator tg(tick_clock_->NowTicks(), 50);
1638
1639   auto frame = CreateFrame(tg.interval(0));
1640   frame->metadata().frame_duration = tg.interval(1);
1641   algorithm_.EnqueueFrame(frame);
1642
1643   // This should not crash or fail.
1644   size_t frames_dropped = 0;
1645   frame = RenderAndStep(&tg, &frames_dropped);
1646   EXPECT_EQ(tg.interval(1), algorithm_.average_frame_duration());
1647
1648   // Add a bunch of normal frames and then one with a 3s duration.
1649   constexpr base::TimeDelta kLongDuration = base::Seconds(3);
1650   for (int i = 1; i < 4; ++i) {
1651     frame = CreateFrame(tg.interval(i));
1652     frame->metadata().frame_duration = i == 3 ? kLongDuration : tg.interval(1);
1653     algorithm_.EnqueueFrame(frame);
1654   }
1655
1656   frame = RenderAndStep(&tg, &frames_dropped);
1657   EXPECT_EQ(tg.interval(1), algorithm_.average_frame_duration());
1658   EXPECT_EQ(algorithm_.last_frame_end_time(),
1659             base::TimeTicks() + kLongDuration + tg.interval(1) * 3);
1660 }
1661
1662 // Check that VideoRendererAlgorithm correctly sets WALLCLOCK_FRAME_DURATION
1663 // for each frame.
1664 TEST_F(VideoRendererAlgorithmTest, WallClockDurationMetadataSet) {
1665   int playback_rate = 4;
1666   int frame_count = 10;
1667   TickGenerator tg(tick_clock_->NowTicks(), 25);
1668
1669   time_source_.SetPlaybackRate(playback_rate);
1670   auto intended_duration = tg.interval(1) / playback_rate;
1671
1672   for (int i = 0; i < frame_count; i++) {
1673     auto frame = CreateFrame(tg.interval(i));
1674     frame->metadata().frame_duration = tg.interval(1);
1675     algorithm_.EnqueueFrame(frame);
1676   }
1677
1678   for (int i = 0; i < frame_count; i++) {
1679     size_t frames_dropped = 0;
1680     auto frame = RenderAndStep(&tg, &frames_dropped);
1681
1682     SCOPED_TRACE(base::StringPrintf("Frame #%d", i));
1683
1684     EXPECT_EQ(*frame->metadata().wallclock_frame_duration, intended_duration);
1685     EXPECT_EQ(algorithm_.average_frame_duration(), intended_duration);
1686   }
1687 }
1688
1689 }  // namespace media