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

Side by Side Diff: media/filters/video_renderer_algorithm_unittest.cc

Issue 1021943002: Introduce cadence based VideoRendererAlgorithm. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Comments. Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
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 <cmath>
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/test/simple_test_tick_clock.h"
11 #include "media/base/video_frame_pool.h"
12 #include "media/base/wall_clock_time_source.h"
13 #include "media/filters/video_renderer_algorithm.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace media {
17
18 // Slows down the given |fps| according to NTSC field reduction standards; see
19 // http://en.wikipedia.org/wiki/Frame_rate#Digital_video_and_television
20 static double NTSC(double fps) {
21 return fps / 1.001;
22 }
23
24 // Helper class for generating TimeTicks in a sequence according to a frequency.
25 class TickGenerator {
26 public:
27 TickGenerator(base::TimeTicks base_timestamp, double hertz)
28 : tick_count_(0),
29 hertz_(hertz),
30 microseconds_per_tick_(base::Time::kMicrosecondsPerSecond / hertz),
31 base_time_(base_timestamp) {}
32
33 base::TimeDelta interval(int tick_count) const {
34 return base::TimeDelta::FromMicroseconds(tick_count *
35 microseconds_per_tick_);
36 }
37
38 base::TimeTicks current() const { return base_time_ + interval(tick_count_); }
39 base::TimeTicks step() { return step(1); }
40 base::TimeTicks step(int n) {
41 tick_count_ += n;
42 return current();
43 }
44
45 double hertz() const { return hertz_; }
46
47 void Reset(base::TimeTicks base_timestamp) {
48 base_time_ = base_timestamp;
49 tick_count_ = 0;
50 }
51
52 private:
53 // Track a tick count and seconds per tick value to ensure we don't drift too
54 // far due to accumulated errors during testing.
55 int64_t tick_count_;
56 const double hertz_;
57 const double microseconds_per_tick_;
58 base::TimeTicks base_time_;
59
60 DISALLOW_COPY_AND_ASSIGN(TickGenerator);
61 };
62
63 class VideoRendererAlgorithmTest : public testing::Test {
64 public:
65 VideoRendererAlgorithmTest()
66 : tick_clock_(new base::SimpleTestTickClock()),
67 algorithm_(base::Bind(&WallClockTimeSource::GetWallClockTime,
68 base::Unretained(&time_source_))) {
69 // Always start the TickClock at a non-zero value since null values have
70 // special connotations.
71 tick_clock_->Advance(base::TimeDelta::FromMicroseconds(10000));
72 time_source_.SetTickClockForTesting(
73 scoped_ptr<base::TickClock>(tick_clock_));
74 }
75 ~VideoRendererAlgorithmTest() override {}
76
77 scoped_refptr<VideoFrame> CreateFrame(base::TimeDelta timestamp) {
78 const gfx::Size natural_size(8, 8);
79 return frame_pool_.CreateFrame(VideoFrame::YV12, natural_size,
80 gfx::Rect(natural_size), natural_size,
81 timestamp);
82 }
83
84 base::TimeDelta minimum_glitch_time() const {
85 return base::TimeDelta::FromSeconds(
86 VideoRendererAlgorithm::kMinimumAcceptableTimeBetweenGlitchesSecs);
87 }
88
89 base::TimeDelta max_acceptable_drift() const {
90 return algorithm_.max_acceptable_drift_;
91 }
92
93 void disable_cadence_hysteresis() {
94 algorithm_.cadence_estimator_.set_cadence_hysteresis_threshold_for_testing(
95 base::TimeDelta());
96 }
97
98 bool last_render_had_glitch() const {
99 return algorithm_.last_render_had_glitch_;
100 }
101
102 bool is_using_cadence() const {
103 return algorithm_.cadence_estimator_.has_cadence();
104 }
105
106 bool IsUsingFractionalCadence() const {
107 return is_using_cadence() &&
108 !algorithm_.cadence_estimator_.GetCadenceForFrame(1);
109 }
110
111 size_t frames_queued() const { return algorithm_.frame_queue_.size(); }
112
113 int GetCadence(double frame_rate, double display_rate) {
114 TickGenerator display_tg(tick_clock_->NowTicks(), display_rate);
115 TickGenerator frame_tg(base::TimeTicks(), frame_rate);
116 time_source_.StartTicking();
117
118 // Enqueue enough frames for cadence detection.
119 size_t frames_dropped = 0;
120 disable_cadence_hysteresis();
121 algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(0)));
122 algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(1)));
123 EXPECT_TRUE(algorithm_.Render(display_tg.current(), display_tg.step(),
124 &frames_dropped));
125
126 // Store cadence before reseting the algorithm.
127 const int cadence = algorithm_.cadence_estimator_.get_cadence_for_testing();
128 time_source_.StopTicking();
129 algorithm_.Reset();
130 return cadence;
131 }
132
133 base::TimeDelta CalculateAbsoluteDriftForFrame(base::TimeTicks deadline_min,
134 int frame_index) {
135 return algorithm_.CalculateAbsoluteDriftForFrame(deadline_min, frame_index);
136 }
137
138 bool DriftOfLastRenderWasWithinTolerance(base::TimeTicks deadline_min) {
139 return CalculateAbsoluteDriftForFrame(deadline_min, 0) <=
140 algorithm_.max_acceptable_drift_;
141 }
142
143 // Allows tests to run a Render() loop with sufficient frames for the various
144 // rendering modes. Upon each Render() |render_test_func| will be called with
145 // the rendered frame and the number of frames dropped.
146 template <typename OnRenderCallback>
147 void RunFramePumpTest(bool reset,
148 TickGenerator* frame_tg,
149 TickGenerator* display_tg,
150 OnRenderCallback render_test_func) {
151 SCOPED_TRACE(base::StringPrintf("Rendering %.03f fps into %0.03f",
152 frame_tg->hertz(), display_tg->hertz()));
153 tick_clock_->Advance(display_tg->current() - tick_clock_->NowTicks());
154 time_source_.StartTicking();
155
156 const bool fresh_algorithm = !algorithm_.have_rendered_frames_;
157
158 base::TimeDelta last_frame_timestamp = kNoTimestamp();
159 bool should_use_cadence = false;
160 int glitch_count = 0;
161 const base::TimeTicks start_time = tick_clock_->NowTicks();
162 while (tick_clock_->NowTicks() - start_time < minimum_glitch_time()) {
163 while (algorithm_.EffectiveFramesQueued() < 3 ||
164 frame_tg->current() - time_source_.CurrentMediaTime() <
165 base::TimeTicks()) {
166 algorithm_.EnqueueFrame(
167 CreateFrame(frame_tg->current() - base::TimeTicks()));
168 frame_tg->step();
169 }
170
171 size_t frames_dropped = 0;
172 const base::TimeTicks deadline_min = display_tg->current();
173 const base::TimeTicks deadline_max = display_tg->step();
174 scoped_refptr<VideoFrame> frame =
175 algorithm_.Render(deadline_min, deadline_max, &frames_dropped);
176
177 render_test_func(frame, frames_dropped);
178 tick_clock_->Advance(display_tg->current() - tick_clock_->NowTicks());
179
180 if (HasFatalFailure())
181 return;
182
183 // Render() should always return a frame within drift tolerances.
184 ASSERT_TRUE(DriftOfLastRenderWasWithinTolerance(deadline_min));
185
186 // If we have a frame, the timestamps should always be monotonically
187 // increasing.
188 if (frame) {
189 if (last_frame_timestamp != kNoTimestamp())
190 ASSERT_LE(last_frame_timestamp, frame->timestamp());
191 else
192 last_frame_timestamp = frame->timestamp();
193 }
194
195 // Only verify certain properties for fresh instances.
196 if (fresh_algorithm) {
197 ASSERT_NEAR(frame_tg->interval(1).InMicroseconds(),
198 algorithm_.average_frame_duration().InMicroseconds(), 1);
199
200 if (is_using_cadence() && last_render_had_glitch())
201 ++glitch_count;
202
203 // Once cadence starts, it should never stop for the current set of
204 // tests.
205 if (is_using_cadence())
206 should_use_cadence = true;
207 ASSERT_EQ(is_using_cadence(), should_use_cadence);
208 }
209
210 // When there are no frames, we're not using cadence based selection, or a
211 // frame is under cadence the two queue size reports should be equal to
212 // the number of usable frames; i.e. those frames whose end time was not
213 // within the last render interval.
214 if (!is_using_cadence() || !frames_queued() ||
215 GetCurrentFrameDisplayCount() < GetCurrentFrameIdealDisplayCount()) {
216 ASSERT_EQ(GetUsableFrameCount(deadline_max),
217 algorithm_.EffectiveFramesQueued());
218 } else if (is_using_cadence() && !IsUsingFractionalCadence()) {
219 // If there was no glitch in the last render, the two queue sizes should
220 // be off by exactly one frame; i.e., the current frame doesn't count.
221 if (!last_render_had_glitch())
222 ASSERT_EQ(frames_queued() - 1, algorithm_.EffectiveFramesQueued());
223 } else if (IsUsingFractionalCadence()) {
224 // The frame estimate should be off by at most one frame.
225 const size_t estimated_frames_queued =
226 frames_queued() /
227 algorithm_.cadence_estimator_.get_cadence_for_testing();
228 ASSERT_NEAR(algorithm_.EffectiveFramesQueued(), estimated_frames_queued,
229 1);
230 }
231 }
232
233 // When using cadence, the glitch count should be at most one for when
234 // rendering for the less than minimum_glitch_time().
235 if (fresh_algorithm && is_using_cadence())
236 ASSERT_LE(glitch_count, 1);
237
238 time_source_.StopTicking();
239 if (reset) {
240 algorithm_.Reset();
241 time_source_.SetMediaTime(base::TimeDelta());
242 }
243 }
244
245 int FindBestFrameByCoverage(base::TimeTicks deadline_min,
246 base::TimeTicks deadline_max,
247 int* second_best) {
248 return algorithm_.FindBestFrameByCoverage(deadline_min, deadline_max,
249 second_best);
250 }
251
252 int FindBestFrameByDrift(base::TimeTicks deadline_min,
253 base::TimeDelta* selected_frame_drift) {
254 return algorithm_.FindBestFrameByDrift(deadline_min, selected_frame_drift);
255 }
256
257 int GetCurrentFrameDropCount() const {
258 DCHECK_GT(frames_queued(), 0u);
259 return algorithm_.frame_queue_[algorithm_.last_frame_index_].drop_count;
260 }
261
262 int GetCurrentFrameDisplayCount() const {
263 DCHECK_GT(frames_queued(), 0u);
264 return algorithm_.frame_queue_[algorithm_.last_frame_index_].render_count;
265 }
266
267 int GetCurrentFrameIdealDisplayCount() const {
268 DCHECK_GT(frames_queued(), 0u);
269 return algorithm_.frame_queue_[algorithm_.last_frame_index_]
270 .ideal_render_count;
271 }
272
273 int AccountForMissedIntervals(base::TimeTicks deadline_min,
274 base::TimeTicks deadline_max) {
275 algorithm_.AccountForMissedIntervals(deadline_min, deadline_max);
276 return frames_queued() ? GetCurrentFrameDisplayCount() : -1;
277 }
278
279 size_t GetUsableFrameCount(base::TimeTicks deadline_max) {
280 if (is_using_cadence())
281 return frames_queued();
282
283 for (size_t i = 0; i < frames_queued(); ++i)
284 if (algorithm_.EndTimeForFrame(i) > deadline_max)
285 return frames_queued() - i;
286 return 0;
287 }
288
289 protected:
290 VideoFramePool frame_pool_;
291 WallClockTimeSource time_source_;
292 base::SimpleTestTickClock* tick_clock_; // Owned by |time_source_|.
293 VideoRendererAlgorithm algorithm_;
294
295 private:
296 DISALLOW_COPY_AND_ASSIGN(VideoRendererAlgorithmTest);
297 };
298
299 TEST_F(VideoRendererAlgorithmTest, Empty) {
300 TickGenerator tg(tick_clock_->NowTicks(), 50);
301 size_t frames_dropped = 0;
302 EXPECT_EQ(0u, frames_queued());
303 EXPECT_FALSE(algorithm_.Render(tg.current(), tg.step(), &frames_dropped));
304 EXPECT_EQ(0u, frames_dropped);
305 EXPECT_EQ(0u, frames_queued());
306 EXPECT_NE(base::TimeDelta(), max_acceptable_drift());
307 }
308
309 TEST_F(VideoRendererAlgorithmTest, Reset) {
310 TickGenerator tg(tick_clock_->NowTicks(), 50);
311 algorithm_.EnqueueFrame(CreateFrame(tg.interval(0)));
312 EXPECT_EQ(1u, frames_queued());
313 EXPECT_NE(base::TimeDelta(), max_acceptable_drift());
314 algorithm_.Reset();
315 EXPECT_EQ(0u, frames_queued());
316 EXPECT_NE(base::TimeDelta(), max_acceptable_drift());
317 }
318
319 TEST_F(VideoRendererAlgorithmTest, AccountForMissingIntervals) {
320 TickGenerator tg(tick_clock_->NowTicks(), 50);
321 time_source_.StartTicking();
322
323 // Disable hysteresis since AccountForMissingIntervals() only affects cadence
324 // based rendering.
325 disable_cadence_hysteresis();
326
327 // Simulate Render() called before any frames are present.
328 EXPECT_EQ(-1, AccountForMissedIntervals(tg.current(), tg.step()));
329
330 algorithm_.EnqueueFrame(CreateFrame(tg.interval(0)));
331 algorithm_.EnqueueFrame(CreateFrame(tg.interval(1)));
332 algorithm_.EnqueueFrame(CreateFrame(tg.interval(2)));
333 algorithm_.EnqueueFrame(CreateFrame(tg.interval(3)));
334
335 // Simulate Render() called before any frames have been rendered.
336 EXPECT_EQ(0, AccountForMissedIntervals(tg.current(), tg.step()));
337
338 // Render one frame (several are in the past and will be dropped).
339 base::TimeTicks deadline_min = tg.current();
340 base::TimeTicks deadline_max = tg.step();
341 size_t frames_dropped = 0;
342 scoped_refptr<VideoFrame> frame =
343 algorithm_.Render(deadline_min, deadline_max, &frames_dropped);
344 ASSERT_TRUE(frame);
345 EXPECT_EQ(tg.interval(2), frame->timestamp());
346 EXPECT_EQ(2u, frames_dropped);
347
348 ASSERT_EQ(1, GetCurrentFrameDisplayCount());
349
350 // Now calling AccountForMissingIntervals with an interval which overlaps the
351 // previous should do nothing.
352 deadline_min += tg.interval(1) / 2;
353 deadline_max += tg.interval(1) / 2;
354 EXPECT_EQ(1, AccountForMissedIntervals(deadline_min, deadline_max));
355
356 // Steping by 1.5 intervals, is not enough to increase the count.
357 deadline_min += tg.interval(1);
358 deadline_max += tg.interval(1);
359 EXPECT_EQ(1, AccountForMissedIntervals(deadline_min, deadline_max));
360
361 // Calling it after a full skipped interval should increase the count by 1 for
362 // each skipped interval.
363 tg.step();
364 EXPECT_EQ(2, AccountForMissedIntervals(tg.current(), tg.step()));
365
366 // 4 because [tg.current(), tg.step()] now represents 2 additional intervals.
367 EXPECT_EQ(4, AccountForMissedIntervals(tg.current(), tg.step()));
368
369 // Frame should be way over cadence and no good frames remain, so last frame
370 // should be returned.
371 frame = algorithm_.Render(tg.current(), tg.step(), &frames_dropped);
372 ASSERT_TRUE(frame);
373 EXPECT_EQ(tg.interval(3), frame->timestamp());
374 EXPECT_EQ(0u, frames_dropped);
375 }
376
377 TEST_F(VideoRendererAlgorithmTest, OnLastFrameDropped) {
378 TickGenerator frame_tg(base::TimeTicks(), 25);
379 TickGenerator display_tg(tick_clock_->NowTicks(), 50);
380 time_source_.StartTicking();
381
382 // Disable hysteresis since OnLastFrameDropped() only affects cadence based
383 // rendering.
384 disable_cadence_hysteresis();
385
386 algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(0)));
387 algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(1)));
388 algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(2)));
389
390 // Render one frame (several are in the past and will be dropped).
391 size_t frames_dropped = 0;
392 scoped_refptr<VideoFrame> frame = algorithm_.Render(
393 display_tg.current(), display_tg.step(), &frames_dropped);
394 ASSERT_TRUE(frame);
395 EXPECT_EQ(frame_tg.interval(0), frame->timestamp());
396 EXPECT_EQ(0u, frames_dropped);
397
398 // The frame should have its display count decremented once it's reported as
399 // dropped.
400 ASSERT_EQ(1, GetCurrentFrameDisplayCount());
401 ASSERT_EQ(0, GetCurrentFrameDropCount());
402 algorithm_.OnLastFrameDropped();
403 ASSERT_EQ(1, GetCurrentFrameDisplayCount());
404 ASSERT_EQ(1, GetCurrentFrameDropCount());
405
406 // Render the frame again and then force another drop.
407 frame = algorithm_.Render(display_tg.current(), display_tg.step(),
408 &frames_dropped);
409 ASSERT_TRUE(frame);
410 EXPECT_EQ(frame_tg.interval(0), frame->timestamp());
411 EXPECT_EQ(0u, frames_dropped);
412
413 ASSERT_EQ(2, GetCurrentFrameDisplayCount());
414 ASSERT_EQ(1, GetCurrentFrameDropCount());
415 algorithm_.OnLastFrameDropped();
416 ASSERT_EQ(2, GetCurrentFrameDisplayCount());
417 ASSERT_EQ(2, GetCurrentFrameDropCount());
418
419 // The next Render() call should now count this frame as dropped.
420 frame = algorithm_.Render(display_tg.current(), display_tg.step(),
421 &frames_dropped);
422 ASSERT_TRUE(frame);
423 EXPECT_EQ(frame_tg.interval(1), frame->timestamp());
424 EXPECT_EQ(1u, frames_dropped);
425 ASSERT_EQ(1, GetCurrentFrameDisplayCount());
426 ASSERT_EQ(0, GetCurrentFrameDropCount());
427
428 // Rendering again should result in the same frame being displayed.
429 frame = algorithm_.Render(display_tg.current(), display_tg.step(),
430 &frames_dropped);
431 ASSERT_TRUE(frame);
432 EXPECT_EQ(frame_tg.interval(1), frame->timestamp());
433 EXPECT_EQ(0u, frames_dropped);
434
435 // In this case, the drop count is less than the display count, so the frame
436 // should not be counted as dropped.
437 ASSERT_EQ(2, GetCurrentFrameDisplayCount());
438 ASSERT_EQ(0, GetCurrentFrameDropCount());
439 algorithm_.OnLastFrameDropped();
440 ASSERT_EQ(2, GetCurrentFrameDisplayCount());
441 ASSERT_EQ(1, GetCurrentFrameDropCount());
442
443 // The third frame should be rendered correctly now and the previous frame not
444 // counted as having been dropped.
445 frame = algorithm_.Render(display_tg.current(), display_tg.step(),
446 &frames_dropped);
447 ASSERT_TRUE(frame);
448 EXPECT_EQ(frame_tg.interval(2), frame->timestamp());
449 EXPECT_EQ(0u, frames_dropped);
450 }
451
452 TEST_F(VideoRendererAlgorithmTest, EffectiveFramesQueued) {
453 TickGenerator frame_tg(base::TimeTicks(), 50);
454 TickGenerator display_tg(tick_clock_->NowTicks(), 25);
455
456 // Disable hysteresis since EffectiveFramesQueued() is tested as part of the
457 // normal frame pump tests when cadence is not present.
458 disable_cadence_hysteresis();
459
460 EXPECT_EQ(0u, algorithm_.EffectiveFramesQueued());
461 time_source_.StartTicking();
462
463 algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(0)));
464 EXPECT_EQ(1u, algorithm_.EffectiveFramesQueued());
465
466 algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(1)));
467 EXPECT_EQ(2u, algorithm_.EffectiveFramesQueued());
468
469 algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(2)));
470 EXPECT_EQ(3u, algorithm_.EffectiveFramesQueued());
471
472 algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(3)));
473 EXPECT_EQ(4u, algorithm_.EffectiveFramesQueued());
474 EXPECT_EQ(4u, frames_queued());
475
476 // Render one frame which will detect cadence...
477 size_t frames_dropped = 0;
478 scoped_refptr<VideoFrame> frame = algorithm_.Render(
479 display_tg.current(), display_tg.step(), &frames_dropped);
480 ASSERT_TRUE(frame);
481 EXPECT_EQ(frame_tg.interval(0), frame->timestamp());
482 EXPECT_EQ(0u, frames_dropped);
483
484 // Fractional cadence should be detected and the count will decrease.
485 ASSERT_TRUE(is_using_cadence());
486 EXPECT_EQ(1u, algorithm_.EffectiveFramesQueued());
487 EXPECT_EQ(4u, frames_queued());
488
489 // Dropping the last rendered frame should do nothing, since the last frame
490 // is already excluded from the count if it has a display count of 1.
491 algorithm_.OnLastFrameDropped();
492 EXPECT_EQ(1u, algorithm_.EffectiveFramesQueued());
493 }
494
495 TEST_F(VideoRendererAlgorithmTest, EffectiveFramesQueuedWithoutCadence) {
496 TickGenerator tg(tick_clock_->NowTicks(), 60);
497
498 EXPECT_EQ(0u, algorithm_.EffectiveFramesQueued());
499 time_source_.StartTicking();
500
501 algorithm_.EnqueueFrame(CreateFrame(tg.interval(0)));
502 EXPECT_EQ(1u, algorithm_.EffectiveFramesQueued());
503
504 algorithm_.EnqueueFrame(CreateFrame(tg.interval(1)));
505 EXPECT_EQ(2u, algorithm_.EffectiveFramesQueued());
506
507 algorithm_.EnqueueFrame(CreateFrame(tg.interval(2)));
508 EXPECT_EQ(3u, algorithm_.EffectiveFramesQueued());
509
510 algorithm_.EnqueueFrame(CreateFrame(tg.interval(3)));
511 EXPECT_EQ(4u, algorithm_.EffectiveFramesQueued());
512 EXPECT_EQ(4u, frames_queued());
513
514 // Issue a render call that should drop the first two frames and mark the 3rd
515 // as consumed.
516 tg.step(2);
517 size_t frames_dropped = 0;
518 scoped_refptr<VideoFrame> frame =
519 algorithm_.Render(tg.current(), tg.step(), &frames_dropped);
520 ASSERT_FALSE(is_using_cadence());
521 ASSERT_TRUE(frame);
522 EXPECT_EQ(2u, frames_dropped);
523 EXPECT_EQ(tg.interval(2), frame->timestamp());
524 EXPECT_EQ(1u, algorithm_.EffectiveFramesQueued());
525 EXPECT_EQ(2u, frames_queued());
526
527 // Rendering one more frame should return 0 effective frames queued.
528 frame = algorithm_.Render(tg.current(), tg.step(), &frames_dropped);
529 ASSERT_FALSE(is_using_cadence());
530 ASSERT_TRUE(frame);
531 EXPECT_EQ(0u, frames_dropped);
532 EXPECT_EQ(tg.interval(3), frame->timestamp());
533 EXPECT_EQ(0u, algorithm_.EffectiveFramesQueued());
534 EXPECT_EQ(1u, frames_queued());
535 }
536
537 // The maximum acceptable drift should be updated once we have two frames.
538 TEST_F(VideoRendererAlgorithmTest, AcceptableDriftUpdated) {
539 TickGenerator tg(tick_clock_->NowTicks(), 50);
540
541 size_t frames_dropped = 0;
542 const base::TimeDelta original_drift = max_acceptable_drift();
543 algorithm_.EnqueueFrame(CreateFrame(tg.interval(0)));
544 EXPECT_EQ(1u, frames_queued());
545 EXPECT_TRUE(algorithm_.Render(tg.current(), tg.step(), &frames_dropped));
546 EXPECT_EQ(original_drift, max_acceptable_drift());
547
548 // Time must be ticking to get wall clock times for frames.
549 time_source_.StartTicking();
550
551 algorithm_.EnqueueFrame(CreateFrame(tg.interval(1)));
552 EXPECT_EQ(2u, frames_queued());
553 EXPECT_TRUE(algorithm_.Render(tg.current(), tg.step(), &frames_dropped));
554 EXPECT_NE(original_drift, max_acceptable_drift());
555 }
556
557 // Verifies behavior when time stops.
558 TEST_F(VideoRendererAlgorithmTest, TimeIsStopped) {
559 TickGenerator tg(tick_clock_->NowTicks(), 50);
560
561 // Prior to rendering the first frame, the algorithm should always return the
562 // first available frame.
563 size_t frames_dropped = 0;
564 algorithm_.EnqueueFrame(CreateFrame(tg.interval(0)));
565 EXPECT_EQ(1u, frames_queued());
566 scoped_refptr<VideoFrame> frame =
567 algorithm_.Render(tg.current(), tg.step(), &frames_dropped);
568 ASSERT_TRUE(frame);
569 EXPECT_EQ(tg.interval(0), frame->timestamp());
570 EXPECT_EQ(0u, frames_dropped);
571 EXPECT_EQ(1u, frames_queued());
572 EXPECT_EQ(1u, algorithm_.EffectiveFramesQueued());
573
574 // The same timestamp should be returned after time starts.
575 tick_clock_->Advance(tg.interval(1));
576 time_source_.StartTicking();
577 frame = algorithm_.Render(tg.current(), tg.step(), &frames_dropped);
578 ASSERT_TRUE(frame);
579 EXPECT_EQ(tg.interval(0), frame->timestamp());
580 EXPECT_EQ(0u, frames_dropped);
581 EXPECT_EQ(1u, frames_queued());
582 EXPECT_EQ(1u, algorithm_.EffectiveFramesQueued());
583
584 // Ensure the next suitable frame is vended as time advances.
585 algorithm_.EnqueueFrame(CreateFrame(tg.interval(1)));
586 EXPECT_EQ(2u, frames_queued());
587 EXPECT_EQ(2u, algorithm_.EffectiveFramesQueued());
588 frame = algorithm_.Render(tg.current(), tg.step(), &frames_dropped);
589 ASSERT_TRUE(frame);
590 EXPECT_EQ(tg.interval(1), frame->timestamp());
591 EXPECT_EQ(0u, frames_dropped);
592 EXPECT_EQ(1u, frames_queued());
593 EXPECT_EQ(0u, algorithm_.EffectiveFramesQueued());
594
595 // Once time stops ticking, any further frames shouldn't be returned, even if
596 // the interval requested more closely matches.
597 algorithm_.EnqueueFrame(CreateFrame(tg.interval(2)));
598 time_source_.StopTicking();
599 frame = algorithm_.Render(tg.current(), tg.step(), &frames_dropped);
600 ASSERT_TRUE(frame);
601 EXPECT_EQ(tg.interval(1), frame->timestamp());
602 EXPECT_EQ(0u, frames_dropped);
603 EXPECT_EQ(2u, frames_queued());
604 EXPECT_EQ(2u, algorithm_.EffectiveFramesQueued());
605 }
606
607 // Verify frames inserted out of order end up in the right spot and are rendered
608 // according to the API contract.
609 TEST_F(VideoRendererAlgorithmTest, SortedFrameQueue) {
610 TickGenerator tg(tick_clock_->NowTicks(), 50);
611
612 // Ensure frames handed in out of order before time starts ticking are sorted
613 // and returned in the correct order upon Render().
614 algorithm_.EnqueueFrame(CreateFrame(tg.interval(3)));
615 algorithm_.EnqueueFrame(CreateFrame(tg.interval(2)));
616 EXPECT_EQ(2u, frames_queued());
617 EXPECT_EQ(2u, algorithm_.EffectiveFramesQueued());
618
619 time_source_.StartTicking();
620
621 // The first call should return the earliest frame appended.
622 size_t frames_dropped = 0;
623 scoped_refptr<VideoFrame> frame =
624 algorithm_.Render(tg.current(), tg.step(), &frames_dropped);
625 EXPECT_EQ(0u, frames_dropped);
626 EXPECT_EQ(tg.interval(2), frame->timestamp());
627 EXPECT_EQ(2u, frames_queued());
628 EXPECT_EQ(2u, algorithm_.EffectiveFramesQueued());
629
630 // Since a frame has already been rendered, queuing this frame and calling
631 // Render() should result in it being dropped; even though it's a better
632 // candidate for the desired interval.
633 algorithm_.EnqueueFrame(CreateFrame(tg.interval(1)));
634 EXPECT_EQ(3u, frames_queued());
635 EXPECT_EQ(2u, algorithm_.EffectiveFramesQueued());
636 frame = algorithm_.Render(tg.current(), tg.step(), &frames_dropped);
637 EXPECT_EQ(1u, frames_dropped);
638 EXPECT_EQ(tg.interval(2), frame->timestamp());
639 EXPECT_EQ(2u, frames_queued());
640 EXPECT_EQ(2u, algorithm_.EffectiveFramesQueued());
641 }
642
643 // Run through integer cadence selection for 1, 2, 3, and 4.
644 TEST_F(VideoRendererAlgorithmTest, BestFrameByCadence) {
645 const double kTestRates[][2] = {{60, 60}, {30, 60}, {25, 75}, {25, 100}};
646
647 for (const auto& test_rate : kTestRates) {
648 disable_cadence_hysteresis();
649
650 TickGenerator frame_tg(base::TimeTicks(), test_rate[0]);
651 TickGenerator display_tg(tick_clock_->NowTicks(), test_rate[1]);
652
653 int actual_frame_pattern = 0;
654 const int desired_frame_pattern = test_rate[1] / test_rate[0];
655 scoped_refptr<VideoFrame> current_frame;
656 RunFramePumpTest(
657 true, &frame_tg, &display_tg,
658 [&current_frame, &actual_frame_pattern, desired_frame_pattern, this](
659 const scoped_refptr<VideoFrame>& frame, size_t frames_dropped) {
660 ASSERT_TRUE(frame);
661 ASSERT_EQ(0u, frames_dropped);
662
663 // Each frame should display for exactly it's desired cadence pattern.
664 if (!current_frame || current_frame == frame) {
665 actual_frame_pattern++;
666 } else {
667 ASSERT_EQ(actual_frame_pattern, desired_frame_pattern);
668 actual_frame_pattern = 1;
669 }
670
671 current_frame = frame;
672 ASSERT_TRUE(is_using_cadence());
673 });
674
675 if (HasFatalFailure())
676 return;
677 }
678 }
679
680 TEST_F(VideoRendererAlgorithmTest, BestFrameByCadenceOverdisplayed) {
681 TickGenerator frame_tg(base::TimeTicks(), 25);
682 TickGenerator display_tg(tick_clock_->NowTicks(), 50);
683 time_source_.StartTicking();
684 disable_cadence_hysteresis();
685
686 algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(0)));
687 algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(1)));
688
689 // Render frames until we've exhausted available frames and the last frame is
690 // forced to be overdisplayed.
691 for (int i = 0; i < 5; ++i) {
692 size_t frames_dropped = 0;
693 scoped_refptr<VideoFrame> frame = algorithm_.Render(
694 display_tg.current(), display_tg.step(), &frames_dropped);
695 ASSERT_TRUE(frame);
696 EXPECT_EQ(frame_tg.interval(i < 4 ? i / 2 : 1), frame->timestamp());
697 EXPECT_EQ(0u, frames_dropped);
698 ASSERT_EQ(2, GetCurrentFrameIdealDisplayCount());
699 }
700
701 // Verify last frame is above cadence (2 in this case)
702 ASSERT_EQ(GetCurrentFrameIdealDisplayCount() + 1,
703 GetCurrentFrameDisplayCount());
704 algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(2)));
705 algorithm_.EnqueueFrame(CreateFrame(frame_tg.interval(3)));
706
707 // The next frame should only be displayed once, since the previous one was
708 // overdisplayed by one frame.
709 size_t frames_dropped = 0;
710 scoped_refptr<VideoFrame> frame = algorithm_.Render(
711 display_tg.current(), display_tg.step(), &frames_dropped);
712 ASSERT_TRUE(frame);
713 EXPECT_EQ(frame_tg.interval(2), frame->timestamp());
714 EXPECT_EQ(0u, frames_dropped);
715 ASSERT_EQ(1, GetCurrentFrameIdealDisplayCount());
716
717 frame = algorithm_.Render(display_tg.current(), display_tg.step(),
718 &frames_dropped);
719 ASSERT_TRUE(frame);
720 EXPECT_EQ(frame_tg.interval(3), frame->timestamp());
721 EXPECT_EQ(0u, frames_dropped);
722 ASSERT_EQ(2, GetCurrentFrameIdealDisplayCount());
723 }
724
725 TEST_F(VideoRendererAlgorithmTest, BestFrameByCoverage) {
726 TickGenerator tg(tick_clock_->NowTicks(), 50);
727 time_source_.StartTicking();
728
729 algorithm_.EnqueueFrame(CreateFrame(tg.interval(0)));
730 algorithm_.EnqueueFrame(CreateFrame(tg.interval(1)));
731 algorithm_.EnqueueFrame(CreateFrame(tg.interval(2)));
732
733 base::TimeTicks deadline_min = tg.current();
734 base::TimeTicks deadline_max = deadline_min + tg.interval(1);
735
736 size_t frames_dropped = 0;
737 scoped_refptr<VideoFrame> frame =
738 algorithm_.Render(deadline_min, deadline_max, &frames_dropped);
739 ASSERT_TRUE(frame);
740 EXPECT_EQ(tg.interval(0), frame->timestamp());
741 EXPECT_EQ(0u, frames_dropped);
742
743 int second_best = 0;
744
745 // Coverage should be 1 for if the frame overlaps the interval entirely, no
746 // second best should be found.
747 EXPECT_EQ(0,
748 FindBestFrameByCoverage(deadline_min, deadline_max, &second_best));
749 EXPECT_EQ(-1, second_best);
750
751 // 49/51 coverage for frame 0 and frame 1 should be within tolerance such that
752 // the earlier frame should still be chosen.
753 deadline_min = tg.current() + tg.interval(1) / 2 +
754 base::TimeDelta::FromMicroseconds(250);
755 deadline_max = deadline_min + tg.interval(1);
756 EXPECT_EQ(0,
757 FindBestFrameByCoverage(deadline_min, deadline_max, &second_best));
758 EXPECT_EQ(1, second_best);
759
760 // 48/52 coverage should result in the second frame being chosen.
761 deadline_min = tg.current() + tg.interval(1) / 2 +
762 base::TimeDelta::FromMicroseconds(500);
763 deadline_max = deadline_min + tg.interval(1);
764 EXPECT_EQ(1,
765 FindBestFrameByCoverage(deadline_min, deadline_max, &second_best));
766 EXPECT_EQ(0, second_best);
767
768 // Overlapping three frames should choose the one with the most coverage and
769 // the second best should be the earliest frame.
770 deadline_min = tg.current() + tg.interval(1) / 2;
771 deadline_max = deadline_min + tg.interval(2);
772 EXPECT_EQ(1,
773 FindBestFrameByCoverage(deadline_min, deadline_max, &second_best));
774 EXPECT_EQ(0, second_best);
775
776 // Requesting coverage outside of all known frames should return -1 for both
777 // best indices.
778 deadline_min = tg.current() + tg.interval(frames_queued());
779 deadline_max = deadline_min + tg.interval(1);
780 EXPECT_EQ(-1,
781 FindBestFrameByCoverage(deadline_min, deadline_max, &second_best));
782 EXPECT_EQ(-1, second_best);
783 }
784
785 TEST_F(VideoRendererAlgorithmTest, BestFrameByDriftAndDriftCalculations) {
786 TickGenerator tg(tick_clock_->NowTicks(), 50);
787 time_source_.StartTicking();
788
789 algorithm_.EnqueueFrame(CreateFrame(tg.interval(0)));
790 algorithm_.EnqueueFrame(CreateFrame(tg.interval(1)));
791
792 size_t frames_dropped = 0;
793 scoped_refptr<VideoFrame> frame = algorithm_.Render(
794 tg.current(), tg.current() + tg.interval(1), &frames_dropped);
795 ASSERT_TRUE(frame);
796 EXPECT_EQ(tg.interval(0), frame->timestamp());
797 EXPECT_EQ(0u, frames_dropped);
798
799 base::TimeDelta zero_drift, half_drift = tg.interval(1) / 2;
800 base::TimeDelta detected_drift;
801
802 // Frame_0 overlaps the deadline, Frame_1 is a full interval away.
803 base::TimeTicks deadline = tg.current();
804 EXPECT_EQ(zero_drift, CalculateAbsoluteDriftForFrame(deadline, 0));
805 EXPECT_EQ(tg.interval(1), CalculateAbsoluteDriftForFrame(deadline, 1));
806 EXPECT_EQ(0, FindBestFrameByDrift(deadline, &detected_drift));
807 EXPECT_EQ(zero_drift, detected_drift);
808
809 // Frame_0 overlaps the deadline, Frame_1 is a half interval away.
810 deadline += half_drift;
811 EXPECT_EQ(zero_drift, CalculateAbsoluteDriftForFrame(deadline, 0));
812 EXPECT_EQ(half_drift, CalculateAbsoluteDriftForFrame(deadline, 1));
813 EXPECT_EQ(0, FindBestFrameByDrift(deadline, &detected_drift));
814 EXPECT_EQ(zero_drift, detected_drift);
815
816 // Both frames overlap the deadline.
817 deadline += half_drift;
818 EXPECT_EQ(zero_drift, CalculateAbsoluteDriftForFrame(deadline, 0));
819 EXPECT_EQ(zero_drift, CalculateAbsoluteDriftForFrame(deadline, 1));
820 EXPECT_EQ(1, FindBestFrameByDrift(deadline, &detected_drift));
821 EXPECT_EQ(zero_drift, detected_drift);
822
823 // Frame_0 is half an interval away, Frame_1 overlaps the deadline.
824 deadline += half_drift;
825 EXPECT_EQ(half_drift, CalculateAbsoluteDriftForFrame(deadline, 0));
826 EXPECT_EQ(zero_drift, CalculateAbsoluteDriftForFrame(deadline, 1));
827 EXPECT_EQ(1, FindBestFrameByDrift(deadline, &detected_drift));
828 EXPECT_EQ(zero_drift, detected_drift);
829
830 // Frame_0 is a full interval away, Frame_1 overlaps the deadline.
831 deadline += half_drift;
832 EXPECT_EQ(tg.interval(1), CalculateAbsoluteDriftForFrame(deadline, 0));
833 EXPECT_EQ(zero_drift, CalculateAbsoluteDriftForFrame(deadline, 1));
834 EXPECT_EQ(1, FindBestFrameByDrift(deadline, &detected_drift));
835 EXPECT_EQ(zero_drift, detected_drift);
836
837 // Both frames are entirely before the deadline.
838 deadline += half_drift;
839 EXPECT_EQ(tg.interval(1) + half_drift,
840 CalculateAbsoluteDriftForFrame(deadline, 0));
841 EXPECT_EQ(half_drift, CalculateAbsoluteDriftForFrame(deadline, 1));
842 EXPECT_EQ(1, FindBestFrameByDrift(deadline, &detected_drift));
843 EXPECT_EQ(half_drift, detected_drift);
844 }
845
846 // Run through fractional cadence selection for 1/2, 1/3, and 1/4.
847 TEST_F(VideoRendererAlgorithmTest, BestFrameByFractionalCadence) {
848 const double kTestRates[][2] = {{120, 60}, {72, 24}, {100, 25}};
849
850 for (const auto& test_rate : kTestRates) {
851 disable_cadence_hysteresis();
852
853 TickGenerator frame_tg(base::TimeTicks(), test_rate[0]);
854 TickGenerator display_tg(tick_clock_->NowTicks(), test_rate[1]);
855
856 const size_t desired_drop_pattern = test_rate[0] / test_rate[1] - 1;
857 scoped_refptr<VideoFrame> current_frame;
858 RunFramePumpTest(
859 true, &frame_tg, &display_tg,
860 [&current_frame, desired_drop_pattern, this](
861 const scoped_refptr<VideoFrame>& frame, size_t frames_dropped) {
862 ASSERT_TRUE(frame);
863
864 // The first frame should have zero dropped frames, but each Render()
865 // call after should drop the same number of frames based on the
866 // fractional cadence.
867 if (!current_frame)
868 ASSERT_EQ(0u, frames_dropped);
869 else
870 ASSERT_EQ(desired_drop_pattern, frames_dropped);
871
872 ASSERT_NE(current_frame, frame);
873 ASSERT_TRUE(is_using_cadence());
874 current_frame = frame;
875 });
876
877 if (HasFatalFailure())
878 return;
879 }
880 }
881
882 // Verify a 3:2 frame pattern for 23.974fps in 60Hz; doubles as a test for best
883 // frame by coverage.
884 TEST_F(VideoRendererAlgorithmTest, FilmCadence) {
885 const double kTestRates[] = {NTSC(24), 24};
886
887 for (double frame_rate : kTestRates) {
888 scoped_refptr<VideoFrame> current_frame;
889 int actual_frame_pattern = 0, desired_frame_pattern = 3;
890
891 TickGenerator frame_tg(base::TimeTicks(), frame_rate);
892 TickGenerator display_tg(tick_clock_->NowTicks(), 60);
893
894 RunFramePumpTest(
895 true, &frame_tg, &display_tg,
896 [&current_frame, &actual_frame_pattern, &desired_frame_pattern, this](
897 const scoped_refptr<VideoFrame>& frame, size_t frames_dropped) {
898 ASSERT_TRUE(frame);
899 ASSERT_EQ(0u, frames_dropped);
900
901 if (!current_frame || current_frame == frame) {
902 actual_frame_pattern++;
903 } else {
904 ASSERT_EQ(actual_frame_pattern, desired_frame_pattern);
905 actual_frame_pattern = 1;
906 desired_frame_pattern = (desired_frame_pattern == 3 ? 2 : 3);
907 }
908
909 current_frame = frame;
910 ASSERT_FALSE(is_using_cadence());
911 });
912
913 if (HasFatalFailure())
914 return;
915 }
916 }
917
918 // Spot check common display and frame rate pairs for correctness.
919 TEST_F(VideoRendererAlgorithmTest, CadenceCalculations) {
920 ASSERT_FALSE(GetCadence(24, 60));
921 ASSERT_FALSE(GetCadence(NTSC(24), 60));
922 ASSERT_FALSE(GetCadence(25, 60));
923 ASSERT_EQ(2, GetCadence(NTSC(30), 60));
924 ASSERT_EQ(2, GetCadence(30, 60));
925 ASSERT_FALSE(GetCadence(50, 60));
926 ASSERT_EQ(1, GetCadence(NTSC(60), 60));
927 ASSERT_EQ(2, GetCadence(120, 60));
928
929 // 50Hz is common in the EU.
930 ASSERT_FALSE(GetCadence(NTSC(24), 50));
931 ASSERT_FALSE(GetCadence(24, 50));
932 ASSERT_EQ(2, GetCadence(NTSC(25), 50));
933 ASSERT_EQ(2, GetCadence(25, 50));
934 ASSERT_FALSE(GetCadence(NTSC(30), 50));
935 ASSERT_FALSE(GetCadence(30, 50));
936 ASSERT_FALSE(GetCadence(NTSC(60), 50));
937 ASSERT_FALSE(GetCadence(60, 50));
938
939 ASSERT_FALSE(GetCadence(25, NTSC(60)));
940 ASSERT_EQ(2, GetCadence(120, NTSC(60)));
941 ASSERT_EQ(60, GetCadence(1, NTSC(60)));
942 }
943
944 TEST_F(VideoRendererAlgorithmTest, RemoveExpiredFrames) {
945 TickGenerator tg(tick_clock_->NowTicks(), 50);
946
947 algorithm_.EnqueueFrame(CreateFrame(tg.interval(0)));
948 ASSERT_EQ(0u, algorithm_.RemoveExpiredFrames(tg.current()));
949 EXPECT_EQ(1u, algorithm_.EffectiveFramesQueued());
950
951 time_source_.StartTicking();
952
953 size_t frames_dropped = 0;
954 scoped_refptr<VideoFrame> frame =
955 algorithm_.Render(tg.current(), tg.step(), &frames_dropped);
956 ASSERT_TRUE(frame);
957 EXPECT_EQ(tg.interval(0), frame->timestamp());
958 EXPECT_EQ(0u, frames_dropped);
959
960 algorithm_.EnqueueFrame(CreateFrame(tg.interval(1)));
961 algorithm_.EnqueueFrame(CreateFrame(tg.interval(2)));
962 algorithm_.EnqueueFrame(CreateFrame(tg.interval(3)));
963 algorithm_.EnqueueFrame(CreateFrame(tg.interval(4)));
964 EXPECT_EQ(5u, algorithm_.EffectiveFramesQueued());
965
966 tg.step(2);
967 ASSERT_EQ(2u, algorithm_.RemoveExpiredFrames(tg.current()));
968 frame = algorithm_.Render(tg.current(), tg.step(), &frames_dropped);
969 EXPECT_EQ(1u, frames_dropped);
970 EXPECT_EQ(2u, frames_queued());
971 EXPECT_EQ(1u, algorithm_.EffectiveFramesQueued());
972 ASSERT_TRUE(frame);
973 EXPECT_EQ(tg.interval(3), frame->timestamp());
974 }
975
976 TEST_F(VideoRendererAlgorithmTest, CadenceBasedTest) {
977 // Common display rates.
978 const double kDisplayRates[] = {
979 NTSC(24),
980 24,
981 NTSC(25),
982 25,
983 NTSC(30),
984 30,
985 48,
986 NTSC(50),
987 50,
988 NTSC(60),
989 60,
990 75,
991 120,
992 144,
993 };
994
995 // List of common frame rate values. Values pulled from local test media,
996 // videostack test matrix, and Wikipedia.
997 const double kTestRates[] = {
998 1, 10, 12.5, 15, NTSC(24), 24, NTSC(25), 25,
999 NTSC(30), 30, 30.12, 48, NTSC(50), 50, 58.74, NTSC(60),
1000 60, 72, 90, 100, 120, 144, 240, 300,
1001 };
1002
1003 for (double display_rate : kDisplayRates) {
1004 for (double frame_rate : kTestRates) {
1005 TickGenerator frame_tg(base::TimeTicks(), frame_rate);
1006 TickGenerator display_tg(tick_clock_->NowTicks(), display_rate);
1007 RunFramePumpTest(
1008 true, &frame_tg, &display_tg,
1009 [](const scoped_refptr<VideoFrame>& frame, size_t frames_dropped) {});
1010 if (HasFatalFailure())
1011 return;
1012 }
1013 }
1014 }
1015
1016 // Rotate through various playback rates and ensure algorithm adapts correctly.
1017 TEST_F(VideoRendererAlgorithmTest, VariableFrameRateCadence) {
1018 TickGenerator frame_tg(base::TimeTicks(), NTSC(30));
1019 TickGenerator display_tg(tick_clock_->NowTicks(), 60);
1020
1021 const double kTestRates[] = {1.0, 2, 0.215, 0.5, 1.0};
1022 const bool kTestRateHasCadence[arraysize(kTestRates)] = {
1023 true, true, false, true, true};
1024
1025 for (size_t i = 0; i < arraysize(kTestRates); ++i) {
1026 const double playback_rate = kTestRates[i];
1027 SCOPED_TRACE(base::StringPrintf("Playback Rate: %.03f", playback_rate));
1028 time_source_.SetPlaybackRate(playback_rate);
1029 RunFramePumpTest(false, &frame_tg, &display_tg,
1030 [this](const scoped_refptr<VideoFrame>& frame,
1031 size_t frames_dropped) {});
1032 if (HasFatalFailure())
1033 return;
1034
1035 ASSERT_EQ(kTestRateHasCadence[i], is_using_cadence());
1036 }
1037
1038 // TODO(dalecurtis): Is there more we can test here?
1039 }
1040
1041 // Ensures media which only expresses timestamps in milliseconds, gets the right
1042 // cadence detection.
1043 TEST_F(VideoRendererAlgorithmTest, UglyTimestampsHaveCadence) {
1044 TickGenerator display_tg(tick_clock_->NowTicks(), 60);
1045 time_source_.StartTicking();
1046
1047 // 59.94fps, timestamp deltas from https://youtu.be/byoLvAo9qjs
1048 const int kBadTimestampsMs[] = {
1049 17, 16, 17, 17, 16, 17, 17, 16, 17, 17, 17, 16, 17, 17, 16, 17, 17, 16,
1050 17, 17, 16, 17, 17, 16, 17, 17, 16, 17, 17, 17, 16, 17, 17, 16, 17, 17,
1051 16, 17, 17, 16, 17, 17, 16, 17, 17, 16, 17, 17, 16, 17, 17, 17};
1052
1053 // Run throught ~1.6 seconds worth of frames.
1054 bool cadence_detected = false;
1055 base::TimeDelta timestamp;
1056 for (size_t i = 0; i < arraysize(kBadTimestampsMs) * 2; ++i) {
1057 while (algorithm_.EffectiveFramesQueued() < 3) {
1058 algorithm_.EnqueueFrame(CreateFrame(timestamp));
1059 timestamp += base::TimeDelta::FromMilliseconds(
1060 kBadTimestampsMs[i % arraysize(kBadTimestampsMs)]);
1061 }
1062
1063 size_t frames_dropped = 0;
1064 algorithm_.Render(display_tg.current(), display_tg.step(), &frames_dropped);
1065 ASSERT_EQ(0u, frames_dropped);
1066
1067 // Cadence won't be detected immediately on this clip, but it will after
1068 // enough frames are encountered; after which it should not drop out of
1069 // cadence.
1070 if (is_using_cadence())
1071 cadence_detected = true;
1072
1073 if (cadence_detected)
1074 ASSERT_TRUE(is_using_cadence());
1075 }
1076 }
1077
1078 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698