Disable Enhanced Bookmark for ICS devices
[chromium-blink-merge.git] / media / renderers / video_renderer_impl_unittest.cc
blobd9cad51ea65b0f64c584220226bd2b98d4ee62d0
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 "media/base/data_buffer.h"
18 #include "media/base/gmock_callback_support.h"
19 #include "media/base/limits.h"
20 #include "media/base/mock_filters.h"
21 #include "media/base/test_helpers.h"
22 #include "media/base/video_frame.h"
23 #include "media/renderers/video_renderer_impl.h"
24 #include "testing/gtest/include/gtest/gtest.h"
26 using ::testing::_;
27 using ::testing::AnyNumber;
28 using ::testing::Invoke;
29 using ::testing::NiceMock;
30 using ::testing::Return;
31 using ::testing::SaveArg;
32 using ::testing::StrictMock;
34 namespace media {
36 ACTION_P(RunClosure, closure) {
37 closure.Run();
40 MATCHER_P(HasTimestamp, ms, "") {
41 *result_listener << "has timestamp " << arg->timestamp().InMilliseconds();
42 return arg->timestamp().InMilliseconds() == ms;
45 class VideoRendererImplTest : public ::testing::Test {
46 public:
47 VideoRendererImplTest()
48 : decoder_(new MockVideoDecoder()),
49 demuxer_stream_(DemuxerStream::VIDEO) {
50 ScopedVector<VideoDecoder> decoders;
51 decoders.push_back(decoder_);
53 renderer_.reset(new VideoRendererImpl(message_loop_.message_loop_proxy(),
54 decoders.Pass(), true,
55 new MediaLog()));
57 demuxer_stream_.set_video_decoder_config(TestVideoConfig::Normal());
59 // We expect these to be called but we don't care how/when.
60 EXPECT_CALL(demuxer_stream_, Read(_)).WillRepeatedly(
61 RunCallback<0>(DemuxerStream::kOk,
62 scoped_refptr<DecoderBuffer>(new DecoderBuffer(0))));
65 virtual ~VideoRendererImplTest() {}
67 void Initialize() {
68 InitializeWithLowDelay(false);
71 void InitializeWithLowDelay(bool low_delay) {
72 // Monitor decodes from the decoder.
73 EXPECT_CALL(*decoder_, Decode(_, _))
74 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::DecodeRequested));
76 EXPECT_CALL(*decoder_, Reset(_))
77 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::FlushRequested));
79 // Initialize, we shouldn't have any reads.
80 InitializeRenderer(PIPELINE_OK, low_delay);
83 void InitializeRenderer(PipelineStatus expected, bool low_delay) {
84 SCOPED_TRACE(base::StringPrintf("InitializeRenderer(%d)", expected));
85 WaitableMessageLoopEvent event;
86 CallInitialize(event.GetPipelineStatusCB(), low_delay, expected);
87 event.RunAndWaitForStatus(expected);
90 void CallInitialize(const PipelineStatusCB& status_cb,
91 bool low_delay,
92 PipelineStatus decoder_status) {
93 if (low_delay)
94 demuxer_stream_.set_liveness(DemuxerStream::LIVENESS_LIVE);
95 EXPECT_CALL(*decoder_, Initialize(_, _, _, _)).WillOnce(
96 DoAll(SaveArg<3>(&output_cb_), RunCallback<2>(decoder_status)));
97 EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
98 renderer_->Initialize(
99 &demuxer_stream_, status_cb, media::SetDecryptorReadyCB(),
100 base::Bind(&VideoRendererImplTest::OnStatisticsUpdate,
101 base::Unretained(this)),
102 base::Bind(&StrictMock<MockCB>::BufferingStateChange,
103 base::Unretained(&mock_cb_)),
104 base::Bind(&StrictMock<MockCB>::Display, base::Unretained(&mock_cb_)),
105 ended_event_.GetClosure(), error_event_.GetPipelineStatusCB(),
106 base::Bind(&VideoRendererImplTest::GetTime, base::Unretained(this)),
107 base::Bind(&VideoRendererImplTest::OnWaitingForDecryptionKey,
108 base::Unretained(this)));
111 void StartPlayingFrom(int milliseconds) {
112 SCOPED_TRACE(base::StringPrintf("StartPlayingFrom(%d)", milliseconds));
113 renderer_->StartPlayingFrom(
114 base::TimeDelta::FromMilliseconds(milliseconds));
115 message_loop_.RunUntilIdle();
118 void Flush() {
119 SCOPED_TRACE("Flush()");
120 WaitableMessageLoopEvent event;
121 renderer_->Flush(event.GetClosure());
122 event.RunAndWait();
125 void Destroy() {
126 SCOPED_TRACE("Destroy()");
127 renderer_.reset();
128 message_loop_.RunUntilIdle();
131 // Parses a string representation of video frames and generates corresponding
132 // VideoFrame objects in |decode_results_|.
134 // Syntax:
135 // nn - Queue a decoder buffer with timestamp nn * 1000us
136 // abort - Queue an aborted read
137 // error - Queue a decoder error
139 // Examples:
140 // A clip that is four frames long: "0 10 20 30"
141 // A clip that has a decode error: "60 70 error"
142 void QueueFrames(const std::string& str) {
143 std::vector<std::string> tokens;
144 base::SplitString(str, ' ', &tokens);
145 for (size_t i = 0; i < tokens.size(); ++i) {
146 if (tokens[i] == "abort") {
147 scoped_refptr<VideoFrame> null_frame;
148 decode_results_.push_back(
149 std::make_pair(VideoDecoder::kAborted, null_frame));
150 continue;
153 if (tokens[i] == "error") {
154 scoped_refptr<VideoFrame> null_frame;
155 decode_results_.push_back(
156 std::make_pair(VideoDecoder::kDecodeError, null_frame));
157 continue;
160 int timestamp_in_ms = 0;
161 if (base::StringToInt(tokens[i], &timestamp_in_ms)) {
162 gfx::Size natural_size = TestVideoConfig::NormalCodedSize();
163 scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame(
164 VideoFrame::YV12,
165 natural_size,
166 gfx::Rect(natural_size),
167 natural_size,
168 base::TimeDelta::FromMilliseconds(timestamp_in_ms));
169 decode_results_.push_back(std::make_pair(VideoDecoder::kOk, frame));
170 continue;
173 CHECK(false) << "Unrecognized decoder buffer token: " << tokens[i];
177 bool IsReadPending() {
178 return !decode_cb_.is_null();
181 void WaitForError(PipelineStatus expected) {
182 SCOPED_TRACE(base::StringPrintf("WaitForError(%d)", expected));
183 error_event_.RunAndWaitForStatus(expected);
186 void WaitForEnded() {
187 SCOPED_TRACE("WaitForEnded()");
188 ended_event_.RunAndWait();
191 void WaitForPendingRead() {
192 SCOPED_TRACE("WaitForPendingRead()");
193 if (!decode_cb_.is_null())
194 return;
196 DCHECK(wait_for_pending_decode_cb_.is_null());
198 WaitableMessageLoopEvent event;
199 wait_for_pending_decode_cb_ = event.GetClosure();
200 event.RunAndWait();
202 DCHECK(!decode_cb_.is_null());
203 DCHECK(wait_for_pending_decode_cb_.is_null());
206 void SatisfyPendingRead() {
207 CHECK(!decode_cb_.is_null());
208 CHECK(!decode_results_.empty());
210 // Post tasks for OutputCB and DecodeCB.
211 scoped_refptr<VideoFrame> frame = decode_results_.front().second;
212 if (frame.get())
213 message_loop_.PostTask(FROM_HERE, base::Bind(output_cb_, frame));
214 message_loop_.PostTask(
215 FROM_HERE, base::Bind(base::ResetAndReturn(&decode_cb_),
216 decode_results_.front().first));
217 decode_results_.pop_front();
220 void SatisfyPendingReadWithEndOfStream() {
221 DCHECK(!decode_cb_.is_null());
223 // Return EOS buffer to trigger EOS frame.
224 EXPECT_CALL(demuxer_stream_, Read(_))
225 .WillOnce(RunCallback<0>(DemuxerStream::kOk,
226 DecoderBuffer::CreateEOSBuffer()));
228 // Satify pending |decode_cb_| to trigger a new DemuxerStream::Read().
229 message_loop_.PostTask(
230 FROM_HERE,
231 base::Bind(base::ResetAndReturn(&decode_cb_), VideoDecoder::kOk));
233 WaitForPendingRead();
235 message_loop_.PostTask(
236 FROM_HERE,
237 base::Bind(base::ResetAndReturn(&decode_cb_), VideoDecoder::kOk));
240 void AdvanceTimeInMs(int time_ms) {
241 DCHECK_EQ(&message_loop_, base::MessageLoop::current());
242 base::AutoLock l(lock_);
243 time_ += base::TimeDelta::FromMilliseconds(time_ms);
246 protected:
247 // Fixture members.
248 scoped_ptr<VideoRendererImpl> renderer_;
249 MockVideoDecoder* decoder_; // Owned by |renderer_|.
250 NiceMock<MockDemuxerStream> demuxer_stream_;
252 // Use StrictMock<T> to catch missing/extra callbacks.
253 class MockCB {
254 public:
255 MOCK_METHOD1(Display, void(const scoped_refptr<VideoFrame>&));
256 MOCK_METHOD1(BufferingStateChange, void(BufferingState));
258 StrictMock<MockCB> mock_cb_;
260 private:
261 base::TimeDelta GetTime() {
262 base::AutoLock l(lock_);
263 return time_;
266 void DecodeRequested(const scoped_refptr<DecoderBuffer>& buffer,
267 const VideoDecoder::DecodeCB& decode_cb) {
268 DCHECK_EQ(&message_loop_, base::MessageLoop::current());
269 CHECK(decode_cb_.is_null());
270 decode_cb_ = decode_cb;
272 // Wake up WaitForPendingRead() if needed.
273 if (!wait_for_pending_decode_cb_.is_null())
274 base::ResetAndReturn(&wait_for_pending_decode_cb_).Run();
276 if (decode_results_.empty())
277 return;
279 SatisfyPendingRead();
282 void FlushRequested(const base::Closure& callback) {
283 DCHECK_EQ(&message_loop_, base::MessageLoop::current());
284 decode_results_.clear();
285 if (!decode_cb_.is_null()) {
286 QueueFrames("abort");
287 SatisfyPendingRead();
290 message_loop_.PostTask(FROM_HERE, callback);
293 void OnStatisticsUpdate(const PipelineStatistics& stats) {}
295 MOCK_METHOD0(OnWaitingForDecryptionKey, void(void));
297 base::MessageLoop message_loop_;
299 // Used to protect |time_|.
300 base::Lock lock_;
301 base::TimeDelta time_;
303 // Used for satisfying reads.
304 VideoDecoder::OutputCB output_cb_;
305 VideoDecoder::DecodeCB decode_cb_;
306 base::TimeDelta next_frame_timestamp_;
308 WaitableMessageLoopEvent error_event_;
309 WaitableMessageLoopEvent ended_event_;
311 // Run during DecodeRequested() to unblock WaitForPendingRead().
312 base::Closure wait_for_pending_decode_cb_;
314 std::deque<std::pair<
315 VideoDecoder::Status, scoped_refptr<VideoFrame> > > decode_results_;
317 DISALLOW_COPY_AND_ASSIGN(VideoRendererImplTest);
320 TEST_F(VideoRendererImplTest, DoNothing) {
321 // Test that creation and deletion doesn't depend on calls to Initialize()
322 // and/or Destroy().
325 TEST_F(VideoRendererImplTest, DestroyWithoutInitialize) {
326 Destroy();
329 TEST_F(VideoRendererImplTest, Initialize) {
330 Initialize();
331 Destroy();
334 TEST_F(VideoRendererImplTest, InitializeAndStartPlayingFrom) {
335 Initialize();
336 QueueFrames("0 10 20 30");
337 EXPECT_CALL(mock_cb_, Display(HasTimestamp(0)));
338 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
339 StartPlayingFrom(0);
340 Destroy();
343 TEST_F(VideoRendererImplTest, DestroyWhileInitializing) {
344 CallInitialize(NewExpectedStatusCB(PIPELINE_ERROR_ABORT), false, PIPELINE_OK);
345 Destroy();
348 TEST_F(VideoRendererImplTest, DestroyWhileFlushing) {
349 Initialize();
350 QueueFrames("0 10 20 30");
351 EXPECT_CALL(mock_cb_, Display(HasTimestamp(0)));
352 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
353 StartPlayingFrom(0);
354 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING));
355 renderer_->Flush(NewExpectedClosure());
356 Destroy();
359 TEST_F(VideoRendererImplTest, Play) {
360 Initialize();
361 QueueFrames("0 10 20 30");
362 EXPECT_CALL(mock_cb_, Display(HasTimestamp(0)));
363 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
364 StartPlayingFrom(0);
365 Destroy();
368 TEST_F(VideoRendererImplTest, FlushWithNothingBuffered) {
369 Initialize();
370 StartPlayingFrom(0);
372 // We shouldn't expect a buffering state change since we never reached
373 // BUFFERING_HAVE_ENOUGH.
374 Flush();
375 Destroy();
378 TEST_F(VideoRendererImplTest, DecodeError_Playing) {
379 Initialize();
380 QueueFrames("0 10 20 30");
381 EXPECT_CALL(mock_cb_, Display(HasTimestamp(0)));
382 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
383 StartPlayingFrom(0);
385 QueueFrames("error");
386 SatisfyPendingRead();
387 WaitForError(PIPELINE_ERROR_DECODE);
388 Destroy();
391 TEST_F(VideoRendererImplTest, DecodeError_DuringStartPlayingFrom) {
392 Initialize();
393 QueueFrames("error");
394 StartPlayingFrom(0);
395 Destroy();
398 TEST_F(VideoRendererImplTest, StartPlayingFrom_Exact) {
399 Initialize();
400 QueueFrames("50 60 70 80 90");
402 EXPECT_CALL(mock_cb_, Display(HasTimestamp(60)));
403 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
404 StartPlayingFrom(60);
405 Destroy();
408 TEST_F(VideoRendererImplTest, StartPlayingFrom_RightBefore) {
409 Initialize();
410 QueueFrames("50 60 70 80 90");
412 EXPECT_CALL(mock_cb_, Display(HasTimestamp(50)));
413 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
414 StartPlayingFrom(59);
415 Destroy();
418 TEST_F(VideoRendererImplTest, StartPlayingFrom_RightAfter) {
419 Initialize();
420 QueueFrames("50 60 70 80 90");
422 EXPECT_CALL(mock_cb_, Display(HasTimestamp(60)));
423 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
424 StartPlayingFrom(61);
425 Destroy();
428 TEST_F(VideoRendererImplTest, StartPlayingFrom_LowDelay) {
429 // In low-delay mode only one frame is required to finish preroll.
430 InitializeWithLowDelay(true);
431 QueueFrames("0");
433 // Expect some amount of have enough/nothing due to only requiring one frame.
434 EXPECT_CALL(mock_cb_, Display(HasTimestamp(0)));
435 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH))
436 .Times(AnyNumber());
437 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING))
438 .Times(AnyNumber());
439 StartPlayingFrom(0);
441 QueueFrames("10");
442 SatisfyPendingRead();
444 WaitableMessageLoopEvent event;
445 EXPECT_CALL(mock_cb_, Display(HasTimestamp(10)))
446 .WillOnce(RunClosure(event.GetClosure()));
447 AdvanceTimeInMs(10);
448 event.RunAndWait();
450 Destroy();
453 // Verify that a late decoder response doesn't break invariants in the renderer.
454 TEST_F(VideoRendererImplTest, DestroyDuringOutstandingRead) {
455 Initialize();
456 QueueFrames("0 10 20 30");
457 EXPECT_CALL(mock_cb_, Display(HasTimestamp(0)));
458 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
459 StartPlayingFrom(0);
461 // Check that there is an outstanding Read() request.
462 EXPECT_TRUE(IsReadPending());
464 Destroy();
467 TEST_F(VideoRendererImplTest, VideoDecoder_InitFailure) {
468 InitializeRenderer(DECODER_ERROR_NOT_SUPPORTED, false);
469 Destroy();
472 TEST_F(VideoRendererImplTest, Underflow) {
473 Initialize();
474 QueueFrames("0 10 20 30");
475 EXPECT_CALL(mock_cb_, Display(HasTimestamp(0)));
476 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
477 StartPlayingFrom(0);
479 // Advance time slightly. Frames should be dropped and we should NOT signal
480 // having nothing.
481 AdvanceTimeInMs(100);
483 // Advance time more. Now we should signal having nothing.
485 SCOPED_TRACE("Waiting for BUFFERING_HAVE_NOTHING");
486 WaitableMessageLoopEvent event;
487 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING))
488 .WillOnce(RunClosure(event.GetClosure()));
489 AdvanceTimeInMs(3000); // Must match kTimeToDeclareHaveNothing.
490 event.RunAndWait();
493 // Receiving end of stream should signal having enough.
495 SCOPED_TRACE("Waiting for BUFFERING_HAVE_ENOUGH");
496 WaitableMessageLoopEvent event;
497 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH))
498 .WillOnce(RunClosure(event.GetClosure()));
499 SatisfyPendingReadWithEndOfStream();
500 event.RunAndWait();
503 WaitForEnded();
504 Destroy();
507 } // namespace media