Split uri_beacons target from bluetooth target.
[chromium-blink-merge.git] / media / renderers / video_renderer_impl_unittest.cc
blobdf5c9d3639ed7e554747554b05a6a83fa656c061
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/test_helpers.h"
23 #include "media/base/video_frame.h"
24 #include "media/renderers/video_renderer_impl.h"
25 #include "testing/gtest/include/gtest/gtest.h"
27 using ::testing::_;
28 using ::testing::AnyNumber;
29 using ::testing::Invoke;
30 using ::testing::Mock;
31 using ::testing::NiceMock;
32 using ::testing::Return;
33 using ::testing::SaveArg;
34 using ::testing::StrictMock;
36 namespace media {
38 ACTION_P(RunClosure, closure) {
39 closure.Run();
42 MATCHER_P(HasTimestamp, ms, "") {
43 *result_listener << "has timestamp " << arg->timestamp().InMilliseconds();
44 return arg->timestamp().InMilliseconds() == ms;
47 class VideoRendererImplTest : public ::testing::Test {
48 public:
49 VideoRendererImplTest()
50 : tick_clock_(new base::SimpleTestTickClock()),
51 decoder_(new MockVideoDecoder()),
52 demuxer_stream_(DemuxerStream::VIDEO) {
53 ScopedVector<VideoDecoder> decoders;
54 decoders.push_back(decoder_);
56 renderer_.reset(new VideoRendererImpl(message_loop_.message_loop_proxy(),
57 decoders.Pass(), true,
58 new MediaLog()));
59 renderer_->SetTickClockForTesting(scoped_ptr<base::TickClock>(tick_clock_));
61 // Start wallclock time at a non-zero value.
62 AdvanceWallclockTimeInMs(12345);
64 demuxer_stream_.set_video_decoder_config(TestVideoConfig::Normal());
66 // We expect these to be called but we don't care how/when.
67 EXPECT_CALL(demuxer_stream_, Read(_)).WillRepeatedly(
68 RunCallback<0>(DemuxerStream::kOk,
69 scoped_refptr<DecoderBuffer>(new DecoderBuffer(0))));
72 virtual ~VideoRendererImplTest() {}
74 void Initialize() {
75 InitializeWithLowDelay(false);
78 void InitializeWithLowDelay(bool low_delay) {
79 // Monitor decodes from the decoder.
80 EXPECT_CALL(*decoder_, Decode(_, _))
81 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::DecodeRequested));
83 EXPECT_CALL(*decoder_, Reset(_))
84 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::FlushRequested));
86 // Initialize, we shouldn't have any reads.
87 InitializeRenderer(PIPELINE_OK, low_delay);
90 void InitializeRenderer(PipelineStatus expected, bool low_delay) {
91 SCOPED_TRACE(base::StringPrintf("InitializeRenderer(%d)", expected));
92 WaitableMessageLoopEvent event;
93 CallInitialize(event.GetPipelineStatusCB(), low_delay, expected);
94 event.RunAndWaitForStatus(expected);
97 void CallInitialize(const PipelineStatusCB& status_cb,
98 bool low_delay,
99 PipelineStatus decoder_status) {
100 if (low_delay)
101 demuxer_stream_.set_liveness(DemuxerStream::LIVENESS_LIVE);
102 EXPECT_CALL(*decoder_, Initialize(_, _, _, _)).WillOnce(
103 DoAll(SaveArg<3>(&output_cb_), RunCallback<2>(decoder_status)));
104 EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
105 renderer_->Initialize(
106 &demuxer_stream_, status_cb, media::SetDecryptorReadyCB(),
107 base::Bind(&VideoRendererImplTest::OnStatisticsUpdate,
108 base::Unretained(this)),
109 base::Bind(&StrictMock<MockCB>::BufferingStateChange,
110 base::Unretained(&mock_cb_)),
111 base::Bind(&StrictMock<MockCB>::Display, base::Unretained(&mock_cb_)),
112 ended_event_.GetClosure(), error_event_.GetPipelineStatusCB(),
113 base::Bind(&VideoRendererImplTest::GetWallClockTime,
114 base::Unretained(this)),
115 base::Bind(&VideoRendererImplTest::OnWaitingForDecryptionKey,
116 base::Unretained(this)));
119 void StartPlayingFrom(int milliseconds) {
120 SCOPED_TRACE(base::StringPrintf("StartPlayingFrom(%d)", milliseconds));
121 renderer_->StartPlayingFrom(
122 base::TimeDelta::FromMilliseconds(milliseconds));
123 message_loop_.RunUntilIdle();
126 void Flush() {
127 SCOPED_TRACE("Flush()");
128 WaitableMessageLoopEvent event;
129 renderer_->Flush(event.GetClosure());
130 event.RunAndWait();
133 void Destroy() {
134 SCOPED_TRACE("Destroy()");
135 renderer_.reset();
136 message_loop_.RunUntilIdle();
139 // Parses a string representation of video frames and generates corresponding
140 // VideoFrame objects in |decode_results_|.
142 // Syntax:
143 // nn - Queue a decoder buffer with timestamp nn * 1000us
144 // abort - Queue an aborted read
145 // error - Queue a decoder error
147 // Examples:
148 // A clip that is four frames long: "0 10 20 30"
149 // A clip that has a decode error: "60 70 error"
150 void QueueFrames(const std::string& str) {
151 std::vector<std::string> tokens;
152 base::SplitString(str, ' ', &tokens);
153 for (size_t i = 0; i < tokens.size(); ++i) {
154 if (tokens[i] == "abort") {
155 scoped_refptr<VideoFrame> null_frame;
156 decode_results_.push_back(
157 std::make_pair(VideoDecoder::kAborted, null_frame));
158 continue;
161 if (tokens[i] == "error") {
162 scoped_refptr<VideoFrame> null_frame;
163 decode_results_.push_back(
164 std::make_pair(VideoDecoder::kDecodeError, null_frame));
165 continue;
168 int timestamp_in_ms = 0;
169 if (base::StringToInt(tokens[i], &timestamp_in_ms)) {
170 gfx::Size natural_size = TestVideoConfig::NormalCodedSize();
171 scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame(
172 VideoFrame::YV12,
173 natural_size,
174 gfx::Rect(natural_size),
175 natural_size,
176 base::TimeDelta::FromMilliseconds(timestamp_in_ms));
177 decode_results_.push_back(std::make_pair(VideoDecoder::kOk, frame));
178 continue;
181 CHECK(false) << "Unrecognized decoder buffer token: " << tokens[i];
185 bool IsReadPending() {
186 return !decode_cb_.is_null();
189 void WaitForError(PipelineStatus expected) {
190 SCOPED_TRACE(base::StringPrintf("WaitForError(%d)", expected));
191 error_event_.RunAndWaitForStatus(expected);
194 void WaitForEnded() {
195 SCOPED_TRACE("WaitForEnded()");
196 ended_event_.RunAndWait();
199 void WaitForPendingRead() {
200 SCOPED_TRACE("WaitForPendingRead()");
201 if (!decode_cb_.is_null())
202 return;
204 DCHECK(wait_for_pending_decode_cb_.is_null());
206 WaitableMessageLoopEvent event;
207 wait_for_pending_decode_cb_ = event.GetClosure();
208 event.RunAndWait();
210 DCHECK(!decode_cb_.is_null());
211 DCHECK(wait_for_pending_decode_cb_.is_null());
214 void SatisfyPendingRead() {
215 CHECK(!decode_cb_.is_null());
216 CHECK(!decode_results_.empty());
218 // Post tasks for OutputCB and DecodeCB.
219 scoped_refptr<VideoFrame> frame = decode_results_.front().second;
220 if (frame.get())
221 message_loop_.PostTask(FROM_HERE, base::Bind(output_cb_, frame));
222 message_loop_.PostTask(
223 FROM_HERE, base::Bind(base::ResetAndReturn(&decode_cb_),
224 decode_results_.front().first));
225 decode_results_.pop_front();
228 void SatisfyPendingReadWithEndOfStream() {
229 DCHECK(!decode_cb_.is_null());
231 // Return EOS buffer to trigger EOS frame.
232 EXPECT_CALL(demuxer_stream_, Read(_))
233 .WillOnce(RunCallback<0>(DemuxerStream::kOk,
234 DecoderBuffer::CreateEOSBuffer()));
236 // Satify pending |decode_cb_| to trigger a new DemuxerStream::Read().
237 message_loop_.PostTask(
238 FROM_HERE,
239 base::Bind(base::ResetAndReturn(&decode_cb_), VideoDecoder::kOk));
241 WaitForPendingRead();
243 message_loop_.PostTask(
244 FROM_HERE,
245 base::Bind(base::ResetAndReturn(&decode_cb_), VideoDecoder::kOk));
248 void AdvanceWallclockTimeInMs(int time_ms) {
249 DCHECK_EQ(&message_loop_, base::MessageLoop::current());
250 base::AutoLock l(lock_);
251 tick_clock_->Advance(base::TimeDelta::FromMilliseconds(time_ms));
254 void AdvanceTimeInMs(int time_ms) {
255 DCHECK_EQ(&message_loop_, base::MessageLoop::current());
256 base::AutoLock l(lock_);
257 time_ += base::TimeDelta::FromMilliseconds(time_ms);
260 protected:
261 // Fixture members.
262 scoped_ptr<VideoRendererImpl> renderer_;
263 base::SimpleTestTickClock* tick_clock_; // Owned by |renderer_|.
264 MockVideoDecoder* decoder_; // Owned by |renderer_|.
265 NiceMock<MockDemuxerStream> demuxer_stream_;
267 // Use StrictMock<T> to catch missing/extra callbacks.
268 class MockCB {
269 public:
270 MOCK_METHOD1(Display, void(const scoped_refptr<VideoFrame>&));
271 MOCK_METHOD1(BufferingStateChange, void(BufferingState));
273 StrictMock<MockCB> mock_cb_;
275 private:
276 base::TimeTicks GetWallClockTime(base::TimeDelta time) {
277 base::AutoLock l(lock_);
278 return tick_clock_->NowTicks() + (time - time_);
281 void DecodeRequested(const scoped_refptr<DecoderBuffer>& buffer,
282 const VideoDecoder::DecodeCB& decode_cb) {
283 DCHECK_EQ(&message_loop_, base::MessageLoop::current());
284 CHECK(decode_cb_.is_null());
285 decode_cb_ = decode_cb;
287 // Wake up WaitForPendingRead() if needed.
288 if (!wait_for_pending_decode_cb_.is_null())
289 base::ResetAndReturn(&wait_for_pending_decode_cb_).Run();
291 if (decode_results_.empty())
292 return;
294 SatisfyPendingRead();
297 void FlushRequested(const base::Closure& callback) {
298 DCHECK_EQ(&message_loop_, base::MessageLoop::current());
299 decode_results_.clear();
300 if (!decode_cb_.is_null()) {
301 QueueFrames("abort");
302 SatisfyPendingRead();
305 message_loop_.PostTask(FROM_HERE, callback);
308 void OnStatisticsUpdate(const PipelineStatistics& stats) {}
310 MOCK_METHOD0(OnWaitingForDecryptionKey, void(void));
312 base::MessageLoop message_loop_;
314 // Used to protect |time_|.
315 base::Lock lock_;
316 base::TimeDelta time_;
318 // Used for satisfying reads.
319 VideoDecoder::OutputCB output_cb_;
320 VideoDecoder::DecodeCB decode_cb_;
321 base::TimeDelta next_frame_timestamp_;
323 WaitableMessageLoopEvent error_event_;
324 WaitableMessageLoopEvent ended_event_;
326 // Run during DecodeRequested() to unblock WaitForPendingRead().
327 base::Closure wait_for_pending_decode_cb_;
329 std::deque<std::pair<
330 VideoDecoder::Status, scoped_refptr<VideoFrame> > > decode_results_;
332 DISALLOW_COPY_AND_ASSIGN(VideoRendererImplTest);
335 TEST_F(VideoRendererImplTest, DoNothing) {
336 // Test that creation and deletion doesn't depend on calls to Initialize()
337 // and/or Destroy().
340 TEST_F(VideoRendererImplTest, DestroyWithoutInitialize) {
341 Destroy();
344 TEST_F(VideoRendererImplTest, Initialize) {
345 Initialize();
346 Destroy();
349 TEST_F(VideoRendererImplTest, InitializeAndStartPlayingFrom) {
350 Initialize();
351 QueueFrames("0 10 20 30");
352 EXPECT_CALL(mock_cb_, Display(HasTimestamp(0)));
353 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
354 StartPlayingFrom(0);
355 Destroy();
358 TEST_F(VideoRendererImplTest, DestroyWhileInitializing) {
359 CallInitialize(NewExpectedStatusCB(PIPELINE_ERROR_ABORT), false, PIPELINE_OK);
360 Destroy();
363 TEST_F(VideoRendererImplTest, DestroyWhileFlushing) {
364 Initialize();
365 QueueFrames("0 10 20 30");
366 EXPECT_CALL(mock_cb_, Display(HasTimestamp(0)));
367 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
368 StartPlayingFrom(0);
369 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING));
370 renderer_->Flush(NewExpectedClosure());
371 Destroy();
374 TEST_F(VideoRendererImplTest, Play) {
375 Initialize();
376 QueueFrames("0 10 20 30");
377 EXPECT_CALL(mock_cb_, Display(HasTimestamp(0)));
378 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
379 StartPlayingFrom(0);
380 Destroy();
383 TEST_F(VideoRendererImplTest, FlushWithNothingBuffered) {
384 Initialize();
385 StartPlayingFrom(0);
387 // We shouldn't expect a buffering state change since we never reached
388 // BUFFERING_HAVE_ENOUGH.
389 Flush();
390 Destroy();
393 TEST_F(VideoRendererImplTest, DecodeError_Playing) {
394 Initialize();
395 QueueFrames("0 10 20 30");
396 EXPECT_CALL(mock_cb_, Display(HasTimestamp(0)));
397 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
398 StartPlayingFrom(0);
400 QueueFrames("error");
401 SatisfyPendingRead();
402 WaitForError(PIPELINE_ERROR_DECODE);
403 Destroy();
406 TEST_F(VideoRendererImplTest, DecodeError_DuringStartPlayingFrom) {
407 Initialize();
408 QueueFrames("error");
409 StartPlayingFrom(0);
410 Destroy();
413 TEST_F(VideoRendererImplTest, StartPlayingFrom_Exact) {
414 Initialize();
415 QueueFrames("50 60 70 80 90");
417 EXPECT_CALL(mock_cb_, Display(HasTimestamp(60)));
418 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
419 StartPlayingFrom(60);
420 Destroy();
423 TEST_F(VideoRendererImplTest, StartPlayingFrom_RightBefore) {
424 Initialize();
425 QueueFrames("50 60 70 80 90");
427 EXPECT_CALL(mock_cb_, Display(HasTimestamp(50)));
428 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
429 StartPlayingFrom(59);
430 Destroy();
433 TEST_F(VideoRendererImplTest, StartPlayingFrom_RightAfter) {
434 Initialize();
435 QueueFrames("50 60 70 80 90");
437 EXPECT_CALL(mock_cb_, Display(HasTimestamp(60)));
438 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
439 StartPlayingFrom(61);
440 Destroy();
443 TEST_F(VideoRendererImplTest, StartPlayingFrom_LowDelay) {
444 // In low-delay mode only one frame is required to finish preroll.
445 InitializeWithLowDelay(true);
446 QueueFrames("0");
448 // Expect some amount of have enough/nothing due to only requiring one frame.
449 EXPECT_CALL(mock_cb_, Display(HasTimestamp(0)));
450 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH))
451 .Times(AnyNumber());
452 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING))
453 .Times(AnyNumber());
454 StartPlayingFrom(0);
456 QueueFrames("10");
457 SatisfyPendingRead();
459 WaitableMessageLoopEvent event;
460 EXPECT_CALL(mock_cb_, Display(HasTimestamp(10)))
461 .WillOnce(RunClosure(event.GetClosure()));
462 AdvanceTimeInMs(10);
463 event.RunAndWait();
465 Destroy();
468 // Verify that a late decoder response doesn't break invariants in the renderer.
469 TEST_F(VideoRendererImplTest, DestroyDuringOutstandingRead) {
470 Initialize();
471 QueueFrames("0 10 20 30");
472 EXPECT_CALL(mock_cb_, Display(HasTimestamp(0)));
473 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
474 StartPlayingFrom(0);
476 // Check that there is an outstanding Read() request.
477 EXPECT_TRUE(IsReadPending());
479 Destroy();
482 TEST_F(VideoRendererImplTest, VideoDecoder_InitFailure) {
483 InitializeRenderer(DECODER_ERROR_NOT_SUPPORTED, false);
484 Destroy();
487 TEST_F(VideoRendererImplTest, Underflow) {
488 Initialize();
489 QueueFrames("0 10 20 30");
492 WaitableMessageLoopEvent event;
493 EXPECT_CALL(mock_cb_, Display(HasTimestamp(0)));
494 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH))
495 .WillOnce(RunClosure(event.GetClosure()));
496 StartPlayingFrom(0);
497 event.RunAndWait();
498 Mock::VerifyAndClearExpectations(&mock_cb_);
501 // Advance time slightly, but enough to exceed the duration of the last frame.
502 // Frames should be dropped and we should NOT signal having nothing.
504 SCOPED_TRACE("Waiting for frame drops");
505 WaitableMessageLoopEvent event;
506 EXPECT_CALL(mock_cb_, Display(HasTimestamp(10))).Times(0);
507 EXPECT_CALL(mock_cb_, Display(HasTimestamp(20))).Times(0);
508 EXPECT_CALL(mock_cb_, Display(HasTimestamp(30)))
509 .WillOnce(RunClosure(event.GetClosure()));
510 AdvanceTimeInMs(31);
511 event.RunAndWait();
512 Mock::VerifyAndClearExpectations(&mock_cb_);
515 // Advance time more, such that a new frame should have been displayed by now.
517 SCOPED_TRACE("Waiting for BUFFERING_HAVE_NOTHING");
518 WaitableMessageLoopEvent event;
519 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING))
520 .WillOnce(RunClosure(event.GetClosure()));
521 AdvanceWallclockTimeInMs(9);
522 event.RunAndWait();
523 Mock::VerifyAndClearExpectations(&mock_cb_);
526 // Receiving end of stream should signal having enough.
528 SCOPED_TRACE("Waiting for BUFFERING_HAVE_ENOUGH");
529 WaitableMessageLoopEvent event;
530 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH))
531 .WillOnce(RunClosure(event.GetClosure()));
532 SatisfyPendingReadWithEndOfStream();
533 event.RunAndWait();
536 WaitForEnded();
537 Destroy();
540 } // namespace media