Elim cr-checkbox
[chromium-blink-merge.git] / media / renderers / video_renderer_impl_unittest.cc
blobe7a09efb984d2e2a1cbccc217eae4c3a7c4a63f2
1 // Copyright 2013 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.
5 #include <utility>
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/callback_helpers.h"
10 #include "base/debug/stack_trace.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/synchronization/lock.h"
17 #include "base/test/simple_test_tick_clock.h"
18 #include "media/base/data_buffer.h"
19 #include "media/base/gmock_callback_support.h"
20 #include "media/base/limits.h"
21 #include "media/base/mock_filters.h"
22 #include "media/base/null_video_sink.h"
23 #include "media/base/test_helpers.h"
24 #include "media/base/video_frame.h"
25 #include "media/base/wall_clock_time_source.h"
26 #include "media/renderers/video_renderer_impl.h"
27 #include "testing/gtest/include/gtest/gtest.h"
29 using ::testing::_;
30 using ::testing::AnyNumber;
31 using ::testing::Invoke;
32 using ::testing::Mock;
33 using ::testing::NiceMock;
34 using ::testing::Return;
35 using ::testing::SaveArg;
36 using ::testing::StrictMock;
38 namespace media {
40 ACTION_P(RunClosure, closure) {
41 closure.Run();
44 MATCHER_P(HasTimestamp, ms, "") {
45 *result_listener << "has timestamp " << arg->timestamp().InMilliseconds();
46 return arg->timestamp().InMilliseconds() == ms;
49 class VideoRendererImplTest
50 : public testing::Test {
51 public:
52 VideoRendererImplTest()
53 : tick_clock_(new base::SimpleTestTickClock()),
54 decoder_(new MockVideoDecoder()),
55 demuxer_stream_(DemuxerStream::VIDEO) {
56 ScopedVector<VideoDecoder> decoders;
57 decoders.push_back(decoder_);
59 null_video_sink_.reset(new NullVideoSink(
60 false, base::TimeDelta::FromSecondsD(1.0 / 60),
61 base::Bind(&MockCB::FrameReceived, base::Unretained(&mock_cb_)),
62 message_loop_.task_runner()));
64 renderer_.reset(new VideoRendererImpl(
65 message_loop_.task_runner(), message_loop_.task_runner().get(),
66 null_video_sink_.get(), decoders.Pass(), true,
67 nullptr, // gpu_factories
68 new MediaLog()));
69 renderer_->SetTickClockForTesting(scoped_ptr<base::TickClock>(tick_clock_));
70 null_video_sink_->set_tick_clock_for_testing(tick_clock_);
71 time_source_.set_tick_clock_for_testing(tick_clock_);
73 // Start wallclock time at a non-zero value.
74 AdvanceWallclockTimeInMs(12345);
76 demuxer_stream_.set_video_decoder_config(TestVideoConfig::Normal());
78 // We expect these to be called but we don't care how/when.
79 EXPECT_CALL(demuxer_stream_, Read(_)).WillRepeatedly(
80 RunCallback<0>(DemuxerStream::kOk,
81 scoped_refptr<DecoderBuffer>(new DecoderBuffer(0))));
84 virtual ~VideoRendererImplTest() {}
86 void Initialize() {
87 InitializeWithLowDelay(false);
90 void InitializeWithLowDelay(bool low_delay) {
91 // Monitor decodes from the decoder.
92 EXPECT_CALL(*decoder_, Decode(_, _))
93 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::DecodeRequested));
95 EXPECT_CALL(*decoder_, Reset(_))
96 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::FlushRequested));
98 // Initialize, we shouldn't have any reads.
99 InitializeRenderer(low_delay, true);
102 void InitializeRenderer(bool low_delay, bool expect_to_success) {
103 SCOPED_TRACE(
104 base::StringPrintf("InitializeRenderer(%d)", expect_to_success));
105 WaitableMessageLoopEvent event;
106 CallInitialize(event.GetPipelineStatusCB(), low_delay, expect_to_success);
107 event.RunAndWaitForStatus(expect_to_success ? PIPELINE_OK
108 : DECODER_ERROR_NOT_SUPPORTED);
111 void CallInitialize(const PipelineStatusCB& status_cb,
112 bool low_delay,
113 bool expect_to_success) {
114 if (low_delay)
115 demuxer_stream_.set_liveness(DemuxerStream::LIVENESS_LIVE);
116 EXPECT_CALL(*decoder_, Initialize(_, _, _, _))
117 .WillOnce(
118 DoAll(SaveArg<3>(&output_cb_), RunCallback<2>(expect_to_success)));
119 EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
120 renderer_->Initialize(
121 &demuxer_stream_, status_cb, media::SetDecryptorReadyCB(),
122 base::Bind(&VideoRendererImplTest::OnStatisticsUpdate,
123 base::Unretained(this)),
124 base::Bind(&StrictMock<MockCB>::BufferingStateChange,
125 base::Unretained(&mock_cb_)),
126 ended_event_.GetClosure(), error_event_.GetPipelineStatusCB(),
127 base::Bind(&WallClockTimeSource::GetWallClockTimes,
128 base::Unretained(&time_source_)),
129 base::Bind(&VideoRendererImplTest::OnWaitingForDecryptionKey,
130 base::Unretained(this)));
133 void StartPlayingFrom(int milliseconds) {
134 SCOPED_TRACE(base::StringPrintf("StartPlayingFrom(%d)", milliseconds));
135 const base::TimeDelta media_time =
136 base::TimeDelta::FromMilliseconds(milliseconds);
137 time_source_.SetMediaTime(media_time);
138 renderer_->StartPlayingFrom(media_time);
139 message_loop_.RunUntilIdle();
142 void Flush() {
143 SCOPED_TRACE("Flush()");
144 WaitableMessageLoopEvent event;
145 renderer_->Flush(event.GetClosure());
146 event.RunAndWait();
149 void Destroy() {
150 SCOPED_TRACE("Destroy()");
151 renderer_.reset();
152 message_loop_.RunUntilIdle();
155 // Parses a string representation of video frames and generates corresponding
156 // VideoFrame objects in |decode_results_|.
158 // Syntax:
159 // nn - Queue a decoder buffer with timestamp nn * 1000us
160 // abort - Queue an aborted read
161 // error - Queue a decoder error
163 // Examples:
164 // A clip that is four frames long: "0 10 20 30"
165 // A clip that has a decode error: "60 70 error"
166 void QueueFrames(const std::string& str) {
167 for (const std::string& token :
168 base::SplitString(str, " ", base::TRIM_WHITESPACE,
169 base::SPLIT_WANT_ALL)) {
170 if (token == "abort") {
171 scoped_refptr<VideoFrame> null_frame;
172 decode_results_.push_back(
173 std::make_pair(VideoDecoder::kAborted, null_frame));
174 continue;
177 if (token == "error") {
178 scoped_refptr<VideoFrame> null_frame;
179 decode_results_.push_back(
180 std::make_pair(VideoDecoder::kDecodeError, null_frame));
181 continue;
184 int timestamp_in_ms = 0;
185 if (base::StringToInt(token, &timestamp_in_ms)) {
186 gfx::Size natural_size = TestVideoConfig::NormalCodedSize();
187 scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame(
188 PIXEL_FORMAT_YV12, natural_size, gfx::Rect(natural_size),
189 natural_size, base::TimeDelta::FromMilliseconds(timestamp_in_ms));
190 decode_results_.push_back(std::make_pair(VideoDecoder::kOk, frame));
191 continue;
194 CHECK(false) << "Unrecognized decoder buffer token: " << token;
198 bool IsReadPending() {
199 return !decode_cb_.is_null();
202 void WaitForError(PipelineStatus expected) {
203 SCOPED_TRACE(base::StringPrintf("WaitForError(%d)", expected));
204 error_event_.RunAndWaitForStatus(expected);
207 void WaitForEnded() {
208 SCOPED_TRACE("WaitForEnded()");
209 ended_event_.RunAndWait();
212 void WaitForPendingRead() {
213 SCOPED_TRACE("WaitForPendingRead()");
214 if (!decode_cb_.is_null())
215 return;
217 DCHECK(wait_for_pending_decode_cb_.is_null());
219 WaitableMessageLoopEvent event;
220 wait_for_pending_decode_cb_ = event.GetClosure();
221 event.RunAndWait();
223 DCHECK(!decode_cb_.is_null());
224 DCHECK(wait_for_pending_decode_cb_.is_null());
227 void SatisfyPendingRead() {
228 CHECK(!decode_cb_.is_null());
229 CHECK(!decode_results_.empty());
231 // Post tasks for OutputCB and DecodeCB.
232 scoped_refptr<VideoFrame> frame = decode_results_.front().second;
233 if (frame.get())
234 message_loop_.PostTask(FROM_HERE, base::Bind(output_cb_, frame));
235 message_loop_.PostTask(
236 FROM_HERE, base::Bind(base::ResetAndReturn(&decode_cb_),
237 decode_results_.front().first));
238 decode_results_.pop_front();
241 void SatisfyPendingReadWithEndOfStream() {
242 DCHECK(!decode_cb_.is_null());
244 // Return EOS buffer to trigger EOS frame.
245 EXPECT_CALL(demuxer_stream_, Read(_))
246 .WillOnce(RunCallback<0>(DemuxerStream::kOk,
247 DecoderBuffer::CreateEOSBuffer()));
249 // Satify pending |decode_cb_| to trigger a new DemuxerStream::Read().
250 message_loop_.PostTask(
251 FROM_HERE,
252 base::Bind(base::ResetAndReturn(&decode_cb_), VideoDecoder::kOk));
254 WaitForPendingRead();
256 message_loop_.PostTask(
257 FROM_HERE,
258 base::Bind(base::ResetAndReturn(&decode_cb_), VideoDecoder::kOk));
261 void AdvanceWallclockTimeInMs(int time_ms) {
262 DCHECK_EQ(&message_loop_, base::MessageLoop::current());
263 base::AutoLock l(lock_);
264 tick_clock_->Advance(base::TimeDelta::FromMilliseconds(time_ms));
267 void AdvanceTimeInMs(int time_ms) {
268 DCHECK_EQ(&message_loop_, base::MessageLoop::current());
269 base::AutoLock l(lock_);
270 time_ += base::TimeDelta::FromMilliseconds(time_ms);
271 time_source_.StopTicking();
272 time_source_.SetMediaTime(time_);
273 time_source_.StartTicking();
276 bool has_ended() const {
277 return ended_event_.is_signaled();
280 protected:
281 // Fixture members.
282 scoped_ptr<VideoRendererImpl> renderer_;
283 base::SimpleTestTickClock* tick_clock_; // Owned by |renderer_|.
284 MockVideoDecoder* decoder_; // Owned by |renderer_|.
285 NiceMock<MockDemuxerStream> demuxer_stream_;
287 // Use StrictMock<T> to catch missing/extra callbacks.
288 class MockCB {
289 public:
290 MOCK_METHOD1(FrameReceived, void(const scoped_refptr<VideoFrame>&));
291 MOCK_METHOD1(BufferingStateChange, void(BufferingState));
293 StrictMock<MockCB> mock_cb_;
295 // Must be destroyed before |renderer_| since they share |tick_clock_|.
296 scoped_ptr<NullVideoSink> null_video_sink_;
298 PipelineStatistics last_pipeline_statistics_;
300 WallClockTimeSource time_source_;
302 base::MessageLoop message_loop_;
304 private:
305 void DecodeRequested(const scoped_refptr<DecoderBuffer>& buffer,
306 const VideoDecoder::DecodeCB& decode_cb) {
307 DCHECK_EQ(&message_loop_, base::MessageLoop::current());
308 CHECK(decode_cb_.is_null());
309 decode_cb_ = decode_cb;
311 // Wake up WaitForPendingRead() if needed.
312 if (!wait_for_pending_decode_cb_.is_null())
313 base::ResetAndReturn(&wait_for_pending_decode_cb_).Run();
315 if (decode_results_.empty())
316 return;
318 SatisfyPendingRead();
321 void FlushRequested(const base::Closure& callback) {
322 DCHECK_EQ(&message_loop_, base::MessageLoop::current());
323 decode_results_.clear();
324 if (!decode_cb_.is_null()) {
325 QueueFrames("abort");
326 SatisfyPendingRead();
329 message_loop_.PostTask(FROM_HERE, callback);
332 void OnStatisticsUpdate(const PipelineStatistics& stats) {
333 last_pipeline_statistics_ = stats;
336 MOCK_METHOD0(OnWaitingForDecryptionKey, void(void));
338 // Used to protect |time_|.
339 base::Lock lock_;
340 base::TimeDelta time_;
342 // Used for satisfying reads.
343 VideoDecoder::OutputCB output_cb_;
344 VideoDecoder::DecodeCB decode_cb_;
345 base::TimeDelta next_frame_timestamp_;
347 WaitableMessageLoopEvent error_event_;
348 WaitableMessageLoopEvent ended_event_;
350 // Run during DecodeRequested() to unblock WaitForPendingRead().
351 base::Closure wait_for_pending_decode_cb_;
353 std::deque<std::pair<
354 VideoDecoder::Status, scoped_refptr<VideoFrame> > > decode_results_;
356 DISALLOW_COPY_AND_ASSIGN(VideoRendererImplTest);
359 TEST_F(VideoRendererImplTest, DoNothing) {
360 // Test that creation and deletion doesn't depend on calls to Initialize()
361 // and/or Destroy().
364 TEST_F(VideoRendererImplTest, DestroyWithoutInitialize) {
365 Destroy();
368 TEST_F(VideoRendererImplTest, Initialize) {
369 Initialize();
370 Destroy();
373 TEST_F(VideoRendererImplTest, InitializeAndStartPlayingFrom) {
374 Initialize();
375 QueueFrames("0 10 20 30");
376 EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(0)));
377 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
378 StartPlayingFrom(0);
379 Destroy();
382 TEST_F(VideoRendererImplTest, InitializeAndEndOfStream) {
383 Initialize();
384 StartPlayingFrom(0);
385 WaitForPendingRead();
387 SCOPED_TRACE("Waiting for BUFFERING_HAVE_ENOUGH");
388 WaitableMessageLoopEvent event;
389 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH))
390 .WillOnce(RunClosure(event.GetClosure()));
391 SatisfyPendingReadWithEndOfStream();
392 event.RunAndWait();
394 // Firing a time state changed to true should be ignored...
395 renderer_->OnTimeStateChanged(true);
396 EXPECT_FALSE(null_video_sink_->is_started());
397 Destroy();
400 TEST_F(VideoRendererImplTest, DestroyWhileInitializing) {
401 CallInitialize(NewExpectedStatusCB(PIPELINE_ERROR_ABORT), false, PIPELINE_OK);
402 Destroy();
405 TEST_F(VideoRendererImplTest, DestroyWhileFlushing) {
406 Initialize();
407 QueueFrames("0 10 20 30");
408 EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(0)));
409 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
410 StartPlayingFrom(0);
411 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING));
412 renderer_->Flush(NewExpectedClosure());
413 Destroy();
416 TEST_F(VideoRendererImplTest, Play) {
417 Initialize();
418 QueueFrames("0 10 20 30");
419 EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(0)));
420 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
421 StartPlayingFrom(0);
422 Destroy();
425 TEST_F(VideoRendererImplTest, FlushWithNothingBuffered) {
426 Initialize();
427 StartPlayingFrom(0);
429 // We shouldn't expect a buffering state change since we never reached
430 // BUFFERING_HAVE_ENOUGH.
431 Flush();
432 Destroy();
435 TEST_F(VideoRendererImplTest, DecodeError_Playing) {
436 Initialize();
437 QueueFrames("0 10 20 30");
438 EXPECT_CALL(mock_cb_, FrameReceived(_)).Times(testing::AtLeast(1));
440 // Consider the case that rendering is faster than we setup the test event.
441 // In that case, when we run out of the frames, BUFFERING_HAVE_NOTHING will
442 // be called.
443 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
444 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING))
445 .Times(testing::AtMost(1));
447 StartPlayingFrom(0);
448 renderer_->OnTimeStateChanged(true);
449 time_source_.StartTicking();
450 AdvanceTimeInMs(10);
452 QueueFrames("error");
453 SatisfyPendingRead();
454 WaitForError(PIPELINE_ERROR_DECODE);
455 Destroy();
458 TEST_F(VideoRendererImplTest, DecodeError_DuringStartPlayingFrom) {
459 Initialize();
460 QueueFrames("error");
461 StartPlayingFrom(0);
462 Destroy();
465 TEST_F(VideoRendererImplTest, StartPlayingFrom_Exact) {
466 Initialize();
467 QueueFrames("50 60 70 80 90");
469 EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(60)));
470 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
471 StartPlayingFrom(60);
472 Destroy();
475 TEST_F(VideoRendererImplTest, StartPlayingFrom_RightBefore) {
476 Initialize();
477 QueueFrames("50 60 70 80 90");
479 EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(50)));
480 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
481 StartPlayingFrom(59);
482 Destroy();
485 TEST_F(VideoRendererImplTest, StartPlayingFrom_RightAfter) {
486 Initialize();
487 QueueFrames("50 60 70 80 90");
489 EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(60)));
490 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
491 StartPlayingFrom(61);
492 Destroy();
495 TEST_F(VideoRendererImplTest, StartPlayingFrom_LowDelay) {
496 // In low-delay mode only one frame is required to finish preroll. But frames
497 // prior to the start time will not be used.
498 InitializeWithLowDelay(true);
499 QueueFrames("0 10");
501 EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(10)));
502 // Expect some amount of have enough/nothing due to only requiring one frame.
503 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH))
504 .Times(AnyNumber());
505 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING))
506 .Times(AnyNumber());
507 StartPlayingFrom(10);
509 QueueFrames("20");
510 SatisfyPendingRead();
512 renderer_->OnTimeStateChanged(true);
513 time_source_.StartTicking();
515 WaitableMessageLoopEvent event;
516 EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(20)))
517 .WillOnce(RunClosure(event.GetClosure()));
518 AdvanceTimeInMs(20);
519 event.RunAndWait();
521 Destroy();
524 // Verify that a late decoder response doesn't break invariants in the renderer.
525 TEST_F(VideoRendererImplTest, DestroyDuringOutstandingRead) {
526 Initialize();
527 QueueFrames("0 10 20 30");
528 EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(0)));
529 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
530 StartPlayingFrom(0);
532 // Check that there is an outstanding Read() request.
533 EXPECT_TRUE(IsReadPending());
535 Destroy();
538 TEST_F(VideoRendererImplTest, VideoDecoder_InitFailure) {
539 InitializeRenderer(false, false);
540 Destroy();
543 TEST_F(VideoRendererImplTest, Underflow) {
544 Initialize();
545 QueueFrames("0 30 60 90");
548 WaitableMessageLoopEvent event;
549 EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(0)));
550 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH))
551 .WillOnce(RunClosure(event.GetClosure()));
552 StartPlayingFrom(0);
553 event.RunAndWait();
554 Mock::VerifyAndClearExpectations(&mock_cb_);
557 renderer_->OnTimeStateChanged(true);
559 // Advance time slightly, but enough to exceed the duration of the last frame.
560 // Frames should be dropped and we should NOT signal having nothing.
562 SCOPED_TRACE("Waiting for frame drops");
563 WaitableMessageLoopEvent event;
565 // Note: Starting the TimeSource will cause the old VideoRendererImpl to
566 // start rendering frames on its own thread, so the first frame may be
567 // received.
568 time_source_.StartTicking();
569 EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(30))).Times(0);
571 EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(60))).Times(0);
572 EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(90)))
573 .WillOnce(RunClosure(event.GetClosure()));
574 AdvanceTimeInMs(91);
576 event.RunAndWait();
577 Mock::VerifyAndClearExpectations(&mock_cb_);
580 // Advance time more. Now we should signal having nothing. And put
581 // the last frame up for display.
583 SCOPED_TRACE("Waiting for BUFFERING_HAVE_NOTHING");
584 WaitableMessageLoopEvent event;
585 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING))
586 .WillOnce(RunClosure(event.GetClosure()));
587 AdvanceTimeInMs(30);
588 event.RunAndWait();
589 Mock::VerifyAndClearExpectations(&mock_cb_);
592 // Receiving end of stream should signal having enough.
594 SCOPED_TRACE("Waiting for BUFFERING_HAVE_ENOUGH");
595 WaitableMessageLoopEvent event;
596 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH))
597 .WillOnce(RunClosure(event.GetClosure()));
598 SatisfyPendingReadWithEndOfStream();
599 event.RunAndWait();
602 WaitForEnded();
603 Destroy();
606 // Verifies that the sink is stopped after rendering the first frame if
607 // playback hasn't started.
608 TEST_F(VideoRendererImplTest, RenderingStopsAfterFirstFrame) {
609 InitializeWithLowDelay(true);
610 QueueFrames("0");
612 EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(0)));
613 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
616 SCOPED_TRACE("Waiting for sink to stop.");
617 WaitableMessageLoopEvent event;
619 null_video_sink_->set_background_render(true);
620 null_video_sink_->set_stop_cb(event.GetClosure());
621 StartPlayingFrom(0);
623 EXPECT_TRUE(IsReadPending());
624 SatisfyPendingReadWithEndOfStream();
626 event.RunAndWait();
629 EXPECT_FALSE(has_ended());
630 Destroy();
633 // Verifies that the sink is stopped after rendering the first frame if
634 // playback ha started.
635 TEST_F(VideoRendererImplTest, RenderingStopsAfterOneFrameWithEOS) {
636 InitializeWithLowDelay(true);
637 QueueFrames("0");
639 EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(0)));
640 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
643 SCOPED_TRACE("Waiting for sink to stop.");
644 WaitableMessageLoopEvent event;
646 null_video_sink_->set_stop_cb(event.GetClosure());
647 StartPlayingFrom(0);
648 renderer_->OnTimeStateChanged(true);
650 EXPECT_TRUE(IsReadPending());
651 SatisfyPendingReadWithEndOfStream();
652 WaitForEnded();
654 renderer_->OnTimeStateChanged(false);
655 event.RunAndWait();
658 Destroy();
661 // Tests the case where the video started and received a single Render() call,
662 // then the video was put into the background.
663 TEST_F(VideoRendererImplTest, RenderingStartedThenStopped) {
664 Initialize();
665 QueueFrames("0 30 60 90");
667 // Start the sink and wait for the first callback. Set statistics to a non
668 // zero value, once we have some decoded frames they should be overwritten.
669 last_pipeline_statistics_.video_frames_dropped = 1;
671 WaitableMessageLoopEvent event;
672 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
673 EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(0)))
674 .WillOnce(RunClosure(event.GetClosure()));
675 StartPlayingFrom(0);
676 event.RunAndWait();
677 Mock::VerifyAndClearExpectations(&mock_cb_);
678 EXPECT_EQ(0u, last_pipeline_statistics_.video_frames_dropped);
681 // Consider the case that rendering is faster than we setup the test event.
682 // In that case, when we run out of the frames, BUFFERING_HAVE_NOTHING will
683 // be called. And then during SatisfyPendingReadWithEndOfStream,
684 // BUFFER_HAVE_ENOUGH will be called again.
685 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH))
686 .Times(testing::AtMost(1));
687 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING))
688 .Times(testing::AtMost(1));
689 renderer_->OnTimeStateChanged(true);
690 time_source_.StartTicking();
692 // Suspend all future callbacks and synthetically advance the media time,
693 // because this is a background render, we won't underflow by waiting until
694 // a pending read is ready.
695 null_video_sink_->set_background_render(true);
696 AdvanceTimeInMs(91);
697 EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(90)));
698 WaitForPendingRead();
699 SatisfyPendingReadWithEndOfStream();
701 // If this wasn't background rendering mode, this would result in two frames
702 // being dropped, but since we set background render to true, none should be
703 // reported
704 EXPECT_EQ(0u, last_pipeline_statistics_.video_frames_dropped);
705 EXPECT_EQ(4u, last_pipeline_statistics_.video_frames_decoded);
707 AdvanceTimeInMs(30);
708 WaitForEnded();
709 Destroy();
712 TEST_F(VideoRendererImplTest, StartPlayingFromThenFlushThenEOS) {
713 Initialize();
714 QueueFrames("0 30 60 90");
716 WaitableMessageLoopEvent event;
717 EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(0)));
718 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH))
719 .WillOnce(RunClosure(event.GetClosure()));
720 StartPlayingFrom(0);
721 event.RunAndWait();
723 // Cycle ticking so that we get a non-null reference time.
724 time_source_.StartTicking();
725 time_source_.StopTicking();
727 // Flush and simulate a seek past EOS, where some error prevents the decoder
728 // from returning any frames.
729 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING));
730 Flush();
732 StartPlayingFrom(200);
733 WaitForPendingRead();
734 SatisfyPendingReadWithEndOfStream();
735 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
736 WaitForEnded();
737 Destroy();
740 namespace {
741 class MockGpuMemoryBufferVideoFramePool : public GpuMemoryBufferVideoFramePool {
742 public:
743 MockGpuMemoryBufferVideoFramePool(std::vector<base::Closure>* frame_ready_cbs)
744 : frame_ready_cbs_(frame_ready_cbs) {}
745 void MaybeCreateHardwareFrame(const scoped_refptr<VideoFrame>& video_frame,
746 const FrameReadyCB& frame_ready_cb) override {
747 frame_ready_cbs_->push_back(base::Bind(frame_ready_cb, video_frame));
750 private:
751 std::vector<base::Closure>* frame_ready_cbs_;
755 class VideoRendererImplAsyncAddFrameReadyTest : public VideoRendererImplTest {
756 public:
757 VideoRendererImplAsyncAddFrameReadyTest() {
758 scoped_ptr<GpuMemoryBufferVideoFramePool> gpu_memory_buffer_pool(
759 new MockGpuMemoryBufferVideoFramePool(&frame_ready_cbs_));
760 renderer_->SetGpuMemoryBufferVideoForTesting(gpu_memory_buffer_pool.Pass());
763 protected:
764 std::vector<base::Closure> frame_ready_cbs_;
767 TEST_F(VideoRendererImplAsyncAddFrameReadyTest, InitializeAndStartPlayingFrom) {
768 Initialize();
769 QueueFrames("0 10 20 30");
770 EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(0)));
771 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
772 StartPlayingFrom(0);
773 ASSERT_EQ(1u, frame_ready_cbs_.size());
775 uint32_t frame_ready_index = 0;
776 while (frame_ready_index < frame_ready_cbs_.size()) {
777 frame_ready_cbs_[frame_ready_index++].Run();
778 message_loop_.RunUntilIdle();
780 Destroy();
783 TEST_F(VideoRendererImplAsyncAddFrameReadyTest, SequenceTokenDiscardOneFrame) {
784 Initialize();
785 QueueFrames("0 10 20 30");
786 StartPlayingFrom(0);
787 Flush();
788 ASSERT_EQ(1u, frame_ready_cbs_.size());
789 // This frame will be discarded.
790 frame_ready_cbs_.front().Run();
791 Destroy();
794 } // namespace media