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

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

Powered by Google App Engine
This is Rietveld 408576698