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.
4
5#include <utility>
6
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/timer/timer.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/filters/video_renderer_impl.h"
25#include "testing/gtest/include/gtest/gtest.h"
26
27using ::testing::_;
28using ::testing::AnyNumber;
29using ::testing::Invoke;
30using ::testing::NiceMock;
31using ::testing::Return;
32using ::testing::SaveArg;
33using ::testing::StrictMock;
34
35namespace media {
36
37ACTION_P(RunClosure, closure) {
38  closure.Run();
39}
40
41MATCHER_P(HasTimestamp, ms, "") {
42  *result_listener << "has timestamp " << arg->timestamp().InMilliseconds();
43  return arg->timestamp().InMilliseconds() == ms;
44}
45
46class VideoRendererImplTest : public ::testing::Test {
47 public:
48  VideoRendererImplTest()
49      : decoder_(new MockVideoDecoder()),
50        demuxer_stream_(DemuxerStream::VIDEO) {
51    ScopedVector<VideoDecoder> decoders;
52    decoders.push_back(decoder_);
53
54    renderer_.reset(new VideoRendererImpl(
55        message_loop_.message_loop_proxy(),
56        decoders.Pass(),
57        media::SetDecryptorReadyCB(),
58        base::Bind(&StrictMock<MockCB>::Display, base::Unretained(&mock_cb_)),
59        true,
60        new MediaLog()));
61
62    demuxer_stream_.set_video_decoder_config(TestVideoConfig::Normal());
63
64    // We expect these to be called but we don't care how/when.
65    EXPECT_CALL(demuxer_stream_, Read(_)).WillRepeatedly(
66        RunCallback<0>(DemuxerStream::kOk,
67                       scoped_refptr<DecoderBuffer>(new DecoderBuffer(0))));
68  }
69
70  virtual ~VideoRendererImplTest() {}
71
72  void Initialize() {
73    InitializeWithLowDelay(false);
74  }
75
76  void InitializeWithLowDelay(bool low_delay) {
77    // Monitor decodes from the decoder.
78    EXPECT_CALL(*decoder_, Decode(_, _))
79        .WillRepeatedly(Invoke(this, &VideoRendererImplTest::DecodeRequested));
80
81    EXPECT_CALL(*decoder_, Reset(_))
82        .WillRepeatedly(Invoke(this, &VideoRendererImplTest::FlushRequested));
83
84    // Initialize, we shouldn't have any reads.
85    InitializeRenderer(PIPELINE_OK, low_delay);
86  }
87
88  void InitializeRenderer(PipelineStatus expected, bool low_delay) {
89    SCOPED_TRACE(base::StringPrintf("InitializeRenderer(%d)", expected));
90    WaitableMessageLoopEvent event;
91    CallInitialize(event.GetPipelineStatusCB(), low_delay, expected);
92    event.RunAndWaitForStatus(expected);
93  }
94
95  void CallInitialize(const PipelineStatusCB& status_cb,
96                      bool low_delay,
97                      PipelineStatus decoder_status) {
98    EXPECT_CALL(*decoder_, Initialize(_, _, _, _)).WillOnce(
99        DoAll(SaveArg<3>(&output_cb_), RunCallback<2>(decoder_status)));
100    renderer_->Initialize(
101        &demuxer_stream_,
102        low_delay,
103        status_cb,
104        base::Bind(&VideoRendererImplTest::OnStatisticsUpdate,
105                   base::Unretained(this)),
106        base::Bind(&StrictMock<MockCB>::BufferingStateChange,
107                   base::Unretained(&mock_cb_)),
108        ended_event_.GetClosure(),
109        error_event_.GetPipelineStatusCB(),
110        base::Bind(&VideoRendererImplTest::GetTime, base::Unretained(this)));
111  }
112
113  void StartPlayingFrom(int milliseconds) {
114    SCOPED_TRACE(base::StringPrintf("StartPlayingFrom(%d)", milliseconds));
115    renderer_->StartPlayingFrom(
116        base::TimeDelta::FromMilliseconds(milliseconds));
117    message_loop_.RunUntilIdle();
118  }
119
120  void Flush() {
121    SCOPED_TRACE("Flush()");
122    WaitableMessageLoopEvent event;
123    renderer_->Flush(event.GetClosure());
124    event.RunAndWait();
125  }
126
127  void Destroy() {
128    SCOPED_TRACE("Destroy()");
129    renderer_.reset();
130    message_loop_.RunUntilIdle();
131  }
132
133  // Parses a string representation of video frames and generates corresponding
134  // VideoFrame objects in |decode_results_|.
135  //
136  // Syntax:
137  //   nn - Queue a decoder buffer with timestamp nn * 1000us
138  //   abort - Queue an aborted read
139  //   error - Queue a decoder error
140  //
141  // Examples:
142  //   A clip that is four frames long: "0 10 20 30"
143  //   A clip that has a decode error: "60 70 error"
144  void QueueFrames(const std::string& str) {
145    std::vector<std::string> tokens;
146    base::SplitString(str, ' ', &tokens);
147    for (size_t i = 0; i < tokens.size(); ++i) {
148      if (tokens[i] == "abort") {
149        scoped_refptr<VideoFrame> null_frame;
150        decode_results_.push_back(
151            std::make_pair(VideoDecoder::kAborted, null_frame));
152        continue;
153      }
154
155      if (tokens[i] == "error") {
156        scoped_refptr<VideoFrame> null_frame;
157        decode_results_.push_back(
158            std::make_pair(VideoDecoder::kDecodeError, null_frame));
159        continue;
160      }
161
162      int timestamp_in_ms = 0;
163      if (base::StringToInt(tokens[i], &timestamp_in_ms)) {
164        gfx::Size natural_size = TestVideoConfig::NormalCodedSize();
165        scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame(
166            VideoFrame::YV12,
167            natural_size,
168            gfx::Rect(natural_size),
169            natural_size,
170            base::TimeDelta::FromMilliseconds(timestamp_in_ms));
171        decode_results_.push_back(std::make_pair(VideoDecoder::kOk, frame));
172        continue;
173      }
174
175      CHECK(false) << "Unrecognized decoder buffer token: " << tokens[i];
176    }
177  }
178
179  bool IsReadPending() {
180    return !decode_cb_.is_null();
181  }
182
183  void WaitForError(PipelineStatus expected) {
184    SCOPED_TRACE(base::StringPrintf("WaitForError(%d)", expected));
185    error_event_.RunAndWaitForStatus(expected);
186  }
187
188  void WaitForEnded() {
189    SCOPED_TRACE("WaitForEnded()");
190    ended_event_.RunAndWait();
191  }
192
193  void WaitForPendingRead() {
194    SCOPED_TRACE("WaitForPendingRead()");
195    if (!decode_cb_.is_null())
196      return;
197
198    DCHECK(wait_for_pending_decode_cb_.is_null());
199
200    WaitableMessageLoopEvent event;
201    wait_for_pending_decode_cb_ = event.GetClosure();
202    event.RunAndWait();
203
204    DCHECK(!decode_cb_.is_null());
205    DCHECK(wait_for_pending_decode_cb_.is_null());
206  }
207
208  void SatisfyPendingRead() {
209    CHECK(!decode_cb_.is_null());
210    CHECK(!decode_results_.empty());
211
212    // Post tasks for OutputCB and DecodeCB.
213    scoped_refptr<VideoFrame> frame = decode_results_.front().second;
214    if (frame.get())
215      message_loop_.PostTask(FROM_HERE, base::Bind(output_cb_, frame));
216    message_loop_.PostTask(
217        FROM_HERE, base::Bind(base::ResetAndReturn(&decode_cb_),
218                              decode_results_.front().first));
219    decode_results_.pop_front();
220  }
221
222  void SatisfyPendingReadWithEndOfStream() {
223    DCHECK(!decode_cb_.is_null());
224
225    // Return EOS buffer to trigger EOS frame.
226    EXPECT_CALL(demuxer_stream_, Read(_))
227        .WillOnce(RunCallback<0>(DemuxerStream::kOk,
228                                 DecoderBuffer::CreateEOSBuffer()));
229
230    // Satify pending |decode_cb_| to trigger a new DemuxerStream::Read().
231    message_loop_.PostTask(
232        FROM_HERE,
233        base::Bind(base::ResetAndReturn(&decode_cb_), VideoDecoder::kOk));
234
235    WaitForPendingRead();
236
237    message_loop_.PostTask(
238        FROM_HERE,
239        base::Bind(base::ResetAndReturn(&decode_cb_), VideoDecoder::kOk));
240  }
241
242  void AdvanceTimeInMs(int time_ms) {
243    DCHECK_EQ(&message_loop_, base::MessageLoop::current());
244    base::AutoLock l(lock_);
245    time_ += base::TimeDelta::FromMilliseconds(time_ms);
246  }
247
248 protected:
249  // Fixture members.
250  scoped_ptr<VideoRendererImpl> renderer_;
251  MockVideoDecoder* decoder_;  // Owned by |renderer_|.
252  NiceMock<MockDemuxerStream> demuxer_stream_;
253
254  // Use StrictMock<T> to catch missing/extra callbacks.
255  class MockCB {
256   public:
257    MOCK_METHOD1(Display, void(const scoped_refptr<VideoFrame>&));
258    MOCK_METHOD1(BufferingStateChange, void(BufferingState));
259  };
260  StrictMock<MockCB> mock_cb_;
261
262 private:
263  base::TimeDelta GetTime() {
264    base::AutoLock l(lock_);
265    return time_;
266  }
267
268  void DecodeRequested(const scoped_refptr<DecoderBuffer>& buffer,
269                       const VideoDecoder::DecodeCB& decode_cb) {
270    DCHECK_EQ(&message_loop_, base::MessageLoop::current());
271    CHECK(decode_cb_.is_null());
272    decode_cb_ = decode_cb;
273
274    // Wake up WaitForPendingRead() if needed.
275    if (!wait_for_pending_decode_cb_.is_null())
276      base::ResetAndReturn(&wait_for_pending_decode_cb_).Run();
277
278    if (decode_results_.empty())
279      return;
280
281    SatisfyPendingRead();
282  }
283
284  void FlushRequested(const base::Closure& callback) {
285    DCHECK_EQ(&message_loop_, base::MessageLoop::current());
286    decode_results_.clear();
287    if (!decode_cb_.is_null()) {
288      QueueFrames("abort");
289      SatisfyPendingRead();
290    }
291
292    message_loop_.PostTask(FROM_HERE, callback);
293  }
294
295  void OnStatisticsUpdate(const PipelineStatistics& stats) {}
296
297  base::MessageLoop message_loop_;
298
299  // Used to protect |time_|.
300  base::Lock lock_;
301  base::TimeDelta time_;
302
303  // Used for satisfying reads.
304  VideoDecoder::OutputCB output_cb_;
305  VideoDecoder::DecodeCB decode_cb_;
306  base::TimeDelta next_frame_timestamp_;
307
308  WaitableMessageLoopEvent error_event_;
309  WaitableMessageLoopEvent ended_event_;
310
311  // Run during DecodeRequested() to unblock WaitForPendingRead().
312  base::Closure wait_for_pending_decode_cb_;
313
314  std::deque<std::pair<
315      VideoDecoder::Status, scoped_refptr<VideoFrame> > > decode_results_;
316
317  DISALLOW_COPY_AND_ASSIGN(VideoRendererImplTest);
318};
319
320TEST_F(VideoRendererImplTest, DoNothing) {
321  // Test that creation and deletion doesn't depend on calls to Initialize()
322  // and/or Destroy().
323}
324
325TEST_F(VideoRendererImplTest, DestroyWithoutInitialize) {
326  Destroy();
327}
328
329TEST_F(VideoRendererImplTest, Initialize) {
330  Initialize();
331  Destroy();
332}
333
334TEST_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();
341}
342
343TEST_F(VideoRendererImplTest, DestroyWhileInitializing) {
344  CallInitialize(NewExpectedStatusCB(PIPELINE_ERROR_ABORT), false, PIPELINE_OK);
345  Destroy();
346}
347
348TEST_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();
357}
358
359TEST_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();
366}
367
368TEST_F(VideoRendererImplTest, FlushWithNothingBuffered) {
369  Initialize();
370  StartPlayingFrom(0);
371
372  // We shouldn't expect a buffering state change since we never reached
373  // BUFFERING_HAVE_ENOUGH.
374  Flush();
375  Destroy();
376}
377
378TEST_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);
384
385  QueueFrames("error");
386  SatisfyPendingRead();
387  WaitForError(PIPELINE_ERROR_DECODE);
388  Destroy();
389}
390
391TEST_F(VideoRendererImplTest, DecodeError_DuringStartPlayingFrom) {
392  Initialize();
393  QueueFrames("error");
394  StartPlayingFrom(0);
395  Destroy();
396}
397
398TEST_F(VideoRendererImplTest, StartPlayingFrom_Exact) {
399  Initialize();
400  QueueFrames("50 60 70 80 90");
401
402  EXPECT_CALL(mock_cb_, Display(HasTimestamp(60)));
403  EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
404  StartPlayingFrom(60);
405  Destroy();
406}
407
408TEST_F(VideoRendererImplTest, StartPlayingFrom_RightBefore) {
409  Initialize();
410  QueueFrames("50 60 70 80 90");
411
412  EXPECT_CALL(mock_cb_, Display(HasTimestamp(50)));
413  EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
414  StartPlayingFrom(59);
415  Destroy();
416}
417
418TEST_F(VideoRendererImplTest, StartPlayingFrom_RightAfter) {
419  Initialize();
420  QueueFrames("50 60 70 80 90");
421
422  EXPECT_CALL(mock_cb_, Display(HasTimestamp(60)));
423  EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
424  StartPlayingFrom(61);
425  Destroy();
426}
427
428TEST_F(VideoRendererImplTest, StartPlayingFrom_LowDelay) {
429  // In low-delay mode only one frame is required to finish preroll.
430  InitializeWithLowDelay(true);
431  QueueFrames("0");
432
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);
440
441  QueueFrames("10");
442  SatisfyPendingRead();
443
444  WaitableMessageLoopEvent event;
445  EXPECT_CALL(mock_cb_, Display(HasTimestamp(10)))
446      .WillOnce(RunClosure(event.GetClosure()));
447  AdvanceTimeInMs(10);
448  event.RunAndWait();
449
450  Destroy();
451}
452
453// Verify that a late decoder response doesn't break invariants in the renderer.
454TEST_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);
460
461  // Check that there is an outstanding Read() request.
462  EXPECT_TRUE(IsReadPending());
463
464  Destroy();
465}
466
467TEST_F(VideoRendererImplTest, VideoDecoder_InitFailure) {
468  InitializeRenderer(DECODER_ERROR_NOT_SUPPORTED, false);
469  Destroy();
470}
471
472TEST_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);
478
479  // Advance time slightly. Frames should be dropped and we should NOT signal
480  // having nothing.
481  AdvanceTimeInMs(100);
482
483  // Advance time more. Now we should signal having nothing.
484  {
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();
491  }
492
493  // Receiving end of stream should signal having enough.
494  {
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();
501  }
502
503  WaitForEnded();
504  Destroy();
505}
506
507}  // namespace media
508