Home | History | Annotate | Download | only in filters
      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 
     27 using ::testing::_;
     28 using ::testing::AnyNumber;
     29 using ::testing::Invoke;
     30 using ::testing::NiceMock;
     31 using ::testing::Return;
     32 using ::testing::SaveArg;
     33 using ::testing::StrictMock;
     34 
     35 namespace media {
     36 
     37 ACTION_P(RunClosure, closure) {
     38   closure.Run();
     39 }
     40 
     41 MATCHER_P(HasTimestamp, ms, "") {
     42   *result_listener << "has timestamp " << arg->timestamp().InMilliseconds();
     43   return arg->timestamp().InMilliseconds() == ms;
     44 }
     45 
     46 class 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 
    320 TEST_F(VideoRendererImplTest, DoNothing) {
    321   // Test that creation and deletion doesn't depend on calls to Initialize()
    322   // and/or Destroy().
    323 }
    324 
    325 TEST_F(VideoRendererImplTest, DestroyWithoutInitialize) {
    326   Destroy();
    327 }
    328 
    329 TEST_F(VideoRendererImplTest, Initialize) {
    330   Initialize();
    331   Destroy();
    332 }
    333 
    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();
    341 }
    342 
    343 TEST_F(VideoRendererImplTest, DestroyWhileInitializing) {
    344   CallInitialize(NewExpectedStatusCB(PIPELINE_ERROR_ABORT), false, PIPELINE_OK);
    345   Destroy();
    346 }
    347 
    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();
    357 }
    358 
    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();
    366 }
    367 
    368 TEST_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 
    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);
    384 
    385   QueueFrames("error");
    386   SatisfyPendingRead();
    387   WaitForError(PIPELINE_ERROR_DECODE);
    388   Destroy();
    389 }
    390 
    391 TEST_F(VideoRendererImplTest, DecodeError_DuringStartPlayingFrom) {
    392   Initialize();
    393   QueueFrames("error");
    394   StartPlayingFrom(0);
    395   Destroy();
    396 }
    397 
    398 TEST_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 
    408 TEST_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 
    418 TEST_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 
    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");
    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.
    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);
    460 
    461   // Check that there is an outstanding Read() request.
    462   EXPECT_TRUE(IsReadPending());
    463 
    464   Destroy();
    465 }
    466 
    467 TEST_F(VideoRendererImplTest, VideoDecoder_InitFailure) {
    468   InitializeRenderer(DECODER_ERROR_NOT_SUPPORTED, false);
    469   Destroy();
    470 }
    471 
    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);
    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