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::AtLeast;
     30 using ::testing::InSequence;
     31 using ::testing::Invoke;
     32 using ::testing::NiceMock;
     33 using ::testing::NotNull;
     34 using ::testing::Return;
     35 using ::testing::SaveArg;
     36 using ::testing::StrictMock;
     37 
     38 namespace media {
     39 
     40 ACTION_P(RunClosure, closure) {
     41   closure.Run();
     42 }
     43 
     44 MATCHER_P(HasTimestamp, ms, "") {
     45   *result_listener << "has timestamp " << arg->timestamp().InMilliseconds();
     46   return arg->timestamp().InMilliseconds() == ms;
     47 }
     48 
     49 // Arbitrary value. Has to be larger to cover any timestamp value used in tests.
     50 static const int kVideoDurationInMs = 1000;
     51 
     52 class VideoRendererImplTest : public ::testing::Test {
     53  public:
     54   VideoRendererImplTest()
     55       : decoder_(new MockVideoDecoder()),
     56         demuxer_stream_(DemuxerStream::VIDEO) {
     57     ScopedVector<VideoDecoder> decoders;
     58     decoders.push_back(decoder_);
     59 
     60     renderer_.reset(
     61         new VideoRendererImpl(message_loop_.message_loop_proxy(),
     62                               decoders.Pass(),
     63                               media::SetDecryptorReadyCB(),
     64                               base::Bind(&StrictMock<MockDisplayCB>::Display,
     65                                          base::Unretained(&mock_display_cb_)),
     66                               true));
     67 
     68     demuxer_stream_.set_video_decoder_config(TestVideoConfig::Normal());
     69 
     70     // We expect these to be called but we don't care how/when.
     71     EXPECT_CALL(demuxer_stream_, Read(_)).WillRepeatedly(
     72         RunCallback<0>(DemuxerStream::kOk,
     73                        scoped_refptr<DecoderBuffer>(new DecoderBuffer(0))));
     74     EXPECT_CALL(*decoder_, Stop())
     75         .WillRepeatedly(Invoke(this, &VideoRendererImplTest::StopRequested));
     76     EXPECT_CALL(statistics_cb_object_, OnStatistics(_))
     77         .Times(AnyNumber());
     78     EXPECT_CALL(*this, OnTimeUpdate(_))
     79         .Times(AnyNumber());
     80   }
     81 
     82   virtual ~VideoRendererImplTest() {}
     83 
     84   // Callbacks passed into Initialize().
     85   MOCK_METHOD1(OnTimeUpdate, void(base::TimeDelta));
     86 
     87   void Initialize() {
     88     InitializeWithLowDelay(false);
     89   }
     90 
     91   void InitializeWithLowDelay(bool low_delay) {
     92     // Monitor decodes from the decoder.
     93     EXPECT_CALL(*decoder_, Decode(_, _))
     94         .WillRepeatedly(Invoke(this, &VideoRendererImplTest::DecodeRequested));
     95 
     96     EXPECT_CALL(*decoder_, Reset(_))
     97         .WillRepeatedly(Invoke(this, &VideoRendererImplTest::FlushRequested));
     98 
     99     InSequence s;
    100 
    101     // Set playback rate before anything else happens.
    102     renderer_->SetPlaybackRate(1.0f);
    103 
    104     // Initialize, we shouldn't have any reads.
    105     InitializeRenderer(PIPELINE_OK, low_delay);
    106   }
    107 
    108   void InitializeRenderer(PipelineStatus expected, bool low_delay) {
    109     SCOPED_TRACE(base::StringPrintf("InitializeRenderer(%d)", expected));
    110     WaitableMessageLoopEvent event;
    111     CallInitialize(event.GetPipelineStatusCB(), low_delay, expected);
    112     event.RunAndWaitForStatus(expected);
    113   }
    114 
    115   void CallInitialize(const PipelineStatusCB& status_cb,
    116                       bool low_delay,
    117                       PipelineStatus decoder_status) {
    118     EXPECT_CALL(*decoder_, Initialize(_, _, _, _)).WillOnce(
    119         DoAll(SaveArg<3>(&output_cb_), RunCallback<2>(decoder_status)));
    120     renderer_->Initialize(
    121         &demuxer_stream_,
    122         low_delay,
    123         status_cb,
    124         base::Bind(&MockStatisticsCB::OnStatistics,
    125                    base::Unretained(&statistics_cb_object_)),
    126         base::Bind(&VideoRendererImplTest::OnTimeUpdate,
    127                    base::Unretained(this)),
    128         ended_event_.GetClosure(),
    129         error_event_.GetPipelineStatusCB(),
    130         base::Bind(&VideoRendererImplTest::GetTime, base::Unretained(this)),
    131         base::Bind(&VideoRendererImplTest::GetDuration,
    132                    base::Unretained(this)));
    133   }
    134 
    135   void Play() {
    136     SCOPED_TRACE("Play()");
    137     WaitableMessageLoopEvent event;
    138     renderer_->Play(event.GetClosure());
    139     event.RunAndWait();
    140   }
    141 
    142   void Preroll(int timestamp_ms, PipelineStatus expected) {
    143     SCOPED_TRACE(base::StringPrintf("Preroll(%d, %d)", timestamp_ms, expected));
    144     WaitableMessageLoopEvent event;
    145     renderer_->Preroll(
    146         base::TimeDelta::FromMilliseconds(timestamp_ms),
    147         event.GetPipelineStatusCB());
    148     event.RunAndWaitForStatus(expected);
    149   }
    150 
    151   void Flush() {
    152     SCOPED_TRACE("Flush()");
    153     WaitableMessageLoopEvent event;
    154     renderer_->Flush(event.GetClosure());
    155     event.RunAndWait();
    156   }
    157 
    158   void Stop() {
    159     SCOPED_TRACE("Stop()");
    160     WaitableMessageLoopEvent event;
    161     renderer_->Stop(event.GetClosure());
    162     event.RunAndWait();
    163   }
    164 
    165   void Shutdown() {
    166     Flush();
    167     Stop();
    168   }
    169 
    170   // Parses a string representation of video frames and generates corresponding
    171   // VideoFrame objects in |decode_results_|.
    172   //
    173   // Syntax:
    174   //   nn - Queue a decoder buffer with timestamp nn * 1000us
    175   //   abort - Queue an aborted read
    176   //   error - Queue a decoder error
    177   //
    178   // Examples:
    179   //   A clip that is four frames long: "0 10 20 30"
    180   //   A clip that has a decode error: "60 70 error"
    181   void QueueFrames(const std::string& str) {
    182     std::vector<std::string> tokens;
    183     base::SplitString(str, ' ', &tokens);
    184     for (size_t i = 0; i < tokens.size(); ++i) {
    185       if (tokens[i] == "abort") {
    186         scoped_refptr<VideoFrame> null_frame;
    187         decode_results_.push_back(
    188             std::make_pair(VideoDecoder::kAborted, null_frame));
    189         continue;
    190       }
    191 
    192       if (tokens[i] == "error") {
    193         scoped_refptr<VideoFrame> null_frame;
    194         decode_results_.push_back(
    195             std::make_pair(VideoDecoder::kDecodeError, null_frame));
    196         continue;
    197       }
    198 
    199       int timestamp_in_ms = 0;
    200       if (base::StringToInt(tokens[i], &timestamp_in_ms)) {
    201         gfx::Size natural_size = TestVideoConfig::NormalCodedSize();
    202         scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame(
    203             VideoFrame::YV12,
    204             natural_size,
    205             gfx::Rect(natural_size),
    206             natural_size,
    207             base::TimeDelta::FromMilliseconds(timestamp_in_ms));
    208         decode_results_.push_back(std::make_pair(VideoDecoder::kOk, frame));
    209         continue;
    210       }
    211 
    212       CHECK(false) << "Unrecognized decoder buffer token: " << tokens[i];
    213     }
    214   }
    215 
    216   bool IsReadPending() {
    217     return !decode_cb_.is_null();
    218   }
    219 
    220   void WaitForError(PipelineStatus expected) {
    221     SCOPED_TRACE(base::StringPrintf("WaitForError(%d)", expected));
    222     error_event_.RunAndWaitForStatus(expected);
    223   }
    224 
    225   void WaitForEnded() {
    226     SCOPED_TRACE("WaitForEnded()");
    227     ended_event_.RunAndWait();
    228   }
    229 
    230   void WaitForPendingRead() {
    231     SCOPED_TRACE("WaitForPendingRead()");
    232     if (!decode_cb_.is_null())
    233       return;
    234 
    235     DCHECK(wait_for_pending_decode_cb_.is_null());
    236 
    237     WaitableMessageLoopEvent event;
    238     wait_for_pending_decode_cb_ = event.GetClosure();
    239     event.RunAndWait();
    240 
    241     DCHECK(!decode_cb_.is_null());
    242     DCHECK(wait_for_pending_decode_cb_.is_null());
    243   }
    244 
    245   void SatisfyPendingRead() {
    246     CHECK(!decode_cb_.is_null());
    247     CHECK(!decode_results_.empty());
    248 
    249     // Post tasks for OutputCB and DecodeCB.
    250     scoped_refptr<VideoFrame> frame = decode_results_.front().second;
    251     if (frame)
    252       message_loop_.PostTask(FROM_HERE, base::Bind(output_cb_, frame));
    253     message_loop_.PostTask(
    254         FROM_HERE, base::Bind(base::ResetAndReturn(&decode_cb_),
    255                               decode_results_.front().first));
    256     decode_results_.pop_front();
    257   }
    258 
    259   void SatisfyPendingReadWithEndOfStream() {
    260     DCHECK(!decode_cb_.is_null());
    261 
    262     // Return EOS buffer to trigger EOS frame.
    263     EXPECT_CALL(demuxer_stream_, Read(_))
    264         .WillOnce(RunCallback<0>(DemuxerStream::kOk,
    265                                  DecoderBuffer::CreateEOSBuffer()));
    266 
    267     // Satify pending |decode_cb_| to trigger a new DemuxerStream::Read().
    268     message_loop_.PostTask(
    269         FROM_HERE,
    270         base::Bind(base::ResetAndReturn(&decode_cb_), VideoDecoder::kOk));
    271 
    272     WaitForPendingRead();
    273 
    274     message_loop_.PostTask(
    275         FROM_HERE,
    276         base::Bind(base::ResetAndReturn(&decode_cb_), VideoDecoder::kOk));
    277   }
    278 
    279   void AdvanceTimeInMs(int time_ms) {
    280     DCHECK_EQ(&message_loop_, base::MessageLoop::current());
    281     base::AutoLock l(lock_);
    282     time_ += base::TimeDelta::FromMilliseconds(time_ms);
    283     DCHECK_LE(time_.InMicroseconds(), GetDuration().InMicroseconds());
    284   }
    285 
    286  protected:
    287   // Fixture members.
    288   scoped_ptr<VideoRendererImpl> renderer_;
    289   MockVideoDecoder* decoder_;  // Owned by |renderer_|.
    290   NiceMock<MockDemuxerStream> demuxer_stream_;
    291   MockStatisticsCB statistics_cb_object_;
    292 
    293   // Use StrictMock<T> to catch missing/extra display callbacks.
    294   class MockDisplayCB {
    295    public:
    296     MOCK_METHOD1(Display, void(const scoped_refptr<VideoFrame>&));
    297   };
    298   StrictMock<MockDisplayCB> mock_display_cb_;
    299 
    300  private:
    301   base::TimeDelta GetTime() {
    302     base::AutoLock l(lock_);
    303     return time_;
    304   }
    305 
    306   base::TimeDelta GetDuration() {
    307     return base::TimeDelta::FromMilliseconds(kVideoDurationInMs);
    308   }
    309 
    310   void DecodeRequested(const scoped_refptr<DecoderBuffer>& buffer,
    311                        const VideoDecoder::DecodeCB& decode_cb) {
    312     DCHECK_EQ(&message_loop_, base::MessageLoop::current());
    313     CHECK(decode_cb_.is_null());
    314     decode_cb_ = decode_cb;
    315 
    316     // Wake up WaitForPendingRead() if needed.
    317     if (!wait_for_pending_decode_cb_.is_null())
    318       base::ResetAndReturn(&wait_for_pending_decode_cb_).Run();
    319 
    320     if (decode_results_.empty())
    321       return;
    322 
    323     SatisfyPendingRead();
    324   }
    325 
    326   void FlushRequested(const base::Closure& callback) {
    327     DCHECK_EQ(&message_loop_, base::MessageLoop::current());
    328     decode_results_.clear();
    329     if (!decode_cb_.is_null()) {
    330       QueueFrames("abort");
    331       SatisfyPendingRead();
    332     }
    333 
    334     message_loop_.PostTask(FROM_HERE, callback);
    335   }
    336 
    337   void StopRequested() {
    338     DCHECK_EQ(&message_loop_, base::MessageLoop::current());
    339     decode_results_.clear();
    340     if (!decode_cb_.is_null()) {
    341       QueueFrames("abort");
    342       SatisfyPendingRead();
    343     }
    344   }
    345 
    346   base::MessageLoop message_loop_;
    347 
    348   // Used to protect |time_|.
    349   base::Lock lock_;
    350   base::TimeDelta time_;
    351 
    352   // Used for satisfying reads.
    353   VideoDecoder::OutputCB output_cb_;
    354   VideoDecoder::DecodeCB decode_cb_;
    355   base::TimeDelta next_frame_timestamp_;
    356 
    357   WaitableMessageLoopEvent error_event_;
    358   WaitableMessageLoopEvent ended_event_;
    359 
    360   // Run during DecodeRequested() to unblock WaitForPendingRead().
    361   base::Closure wait_for_pending_decode_cb_;
    362 
    363   std::deque<std::pair<
    364       VideoDecoder::Status, scoped_refptr<VideoFrame> > > decode_results_;
    365 
    366   DISALLOW_COPY_AND_ASSIGN(VideoRendererImplTest);
    367 };
    368 
    369 TEST_F(VideoRendererImplTest, DoNothing) {
    370   // Test that creation and deletion doesn't depend on calls to Initialize()
    371   // and/or Stop().
    372 }
    373 
    374 TEST_F(VideoRendererImplTest, StopWithoutInitialize) {
    375   Stop();
    376 }
    377 
    378 TEST_F(VideoRendererImplTest, Initialize) {
    379   Initialize();
    380   Shutdown();
    381 }
    382 
    383 TEST_F(VideoRendererImplTest, InitializeAndPreroll) {
    384   Initialize();
    385   QueueFrames("0 10 20 30");
    386   EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(0)));
    387   Preroll(0, PIPELINE_OK);
    388   Shutdown();
    389 }
    390 
    391 static void ExpectNotCalled(PipelineStatus) {
    392   base::debug::StackTrace stack;
    393   ADD_FAILURE() << "Expected callback not to be called\n" << stack.ToString();
    394 }
    395 
    396 TEST_F(VideoRendererImplTest, StopWhileInitializing) {
    397   CallInitialize(base::Bind(&ExpectNotCalled), false, PIPELINE_OK);
    398   Stop();
    399 
    400   // ~VideoRendererImpl() will CHECK() if we left anything initialized.
    401 }
    402 
    403 TEST_F(VideoRendererImplTest, StopWhileFlushing) {
    404   Initialize();
    405   renderer_->Flush(base::Bind(&ExpectNotCalled, PIPELINE_OK));
    406   Stop();
    407 
    408   // ~VideoRendererImpl() will CHECK() if we left anything initialized.
    409 }
    410 
    411 TEST_F(VideoRendererImplTest, Play) {
    412   Initialize();
    413   QueueFrames("0 10 20 30");
    414   EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(0)));
    415   Preroll(0, PIPELINE_OK);
    416   Play();
    417   Shutdown();
    418 }
    419 
    420 TEST_F(VideoRendererImplTest, EndOfStream_ClipDuration) {
    421   Initialize();
    422   QueueFrames("0 10 20 30");
    423   EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(0)));
    424   Preroll(0, PIPELINE_OK);
    425   Play();
    426 
    427   // Next frame has timestamp way past duration. Its timestamp will be adjusted
    428   // to match the duration of the video.
    429   QueueFrames(base::IntToString(kVideoDurationInMs + 1000));
    430   SatisfyPendingRead();
    431   WaitForPendingRead();
    432 
    433   // Queue the end of stream frame and wait for the last frame to be rendered.
    434   SatisfyPendingReadWithEndOfStream();
    435 
    436   EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(kVideoDurationInMs)));
    437   AdvanceTimeInMs(kVideoDurationInMs);
    438   WaitForEnded();
    439 
    440   Shutdown();
    441 }
    442 
    443 TEST_F(VideoRendererImplTest, DecodeError_Playing) {
    444   Initialize();
    445   QueueFrames("0 10 20 30");
    446   EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(0)));
    447   Preroll(0, PIPELINE_OK);
    448   Play();
    449 
    450   QueueFrames("error");
    451   SatisfyPendingRead();
    452   WaitForError(PIPELINE_ERROR_DECODE);
    453   Shutdown();
    454 }
    455 
    456 TEST_F(VideoRendererImplTest, DecodeError_DuringPreroll) {
    457   Initialize();
    458   QueueFrames("error");
    459   Preroll(0, PIPELINE_ERROR_DECODE);
    460   Shutdown();
    461 }
    462 
    463 TEST_F(VideoRendererImplTest, Preroll_Exact) {
    464   Initialize();
    465   QueueFrames("50 60 70 80 90");
    466 
    467   EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(60)));
    468   Preroll(60, PIPELINE_OK);
    469   Shutdown();
    470 }
    471 
    472 TEST_F(VideoRendererImplTest, Preroll_RightBefore) {
    473   Initialize();
    474   QueueFrames("50 60 70 80 90");
    475 
    476   EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(50)));
    477   Preroll(59, PIPELINE_OK);
    478   Shutdown();
    479 }
    480 
    481 TEST_F(VideoRendererImplTest, Preroll_RightAfter) {
    482   Initialize();
    483   QueueFrames("50 60 70 80 90");
    484 
    485   EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(60)));
    486   Preroll(61, PIPELINE_OK);
    487   Shutdown();
    488 }
    489 
    490 TEST_F(VideoRendererImplTest, Preroll_LowDelay) {
    491   // In low-delay mode only one frame is required to finish preroll.
    492   InitializeWithLowDelay(true);
    493   QueueFrames("0");
    494 
    495   EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(0)));
    496   Preroll(0, PIPELINE_OK);
    497   Play();
    498 
    499   QueueFrames("10");
    500   SatisfyPendingRead();
    501 
    502   WaitableMessageLoopEvent event;
    503   EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(10)))
    504       .WillOnce(RunClosure(event.GetClosure()));
    505   AdvanceTimeInMs(10);
    506   event.RunAndWait();
    507 
    508   Shutdown();
    509 }
    510 
    511 TEST_F(VideoRendererImplTest, PlayAfterPreroll) {
    512   Initialize();
    513   QueueFrames("0 10 20 30");
    514   EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(0)));
    515   Preroll(0, PIPELINE_OK);
    516   Play();
    517 
    518   // Check that there is an outstanding Read() request.
    519   EXPECT_TRUE(IsReadPending());
    520 
    521   Shutdown();
    522 }
    523 
    524 TEST_F(VideoRendererImplTest, Rebuffer) {
    525   Initialize();
    526   QueueFrames("0 10 20 30");
    527   EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(0)));
    528   Preroll(0, PIPELINE_OK);
    529   Play();
    530 
    531   // Advance time past prerolled time drain the ready frame queue.
    532   AdvanceTimeInMs(50);
    533   WaitForPendingRead();
    534 
    535   // Simulate a Preroll/Play rebuffer sequence.
    536   WaitableMessageLoopEvent event;
    537   renderer_->Preroll(kNoTimestamp(),
    538                      event.GetPipelineStatusCB());
    539 
    540   // Queue enough frames to satisfy preroll.
    541   QueueFrames("40 50 60 70");
    542   SatisfyPendingRead();
    543 
    544   // TODO(scherkus): We shouldn't display the next ready frame in a rebuffer
    545   // situation, see http://crbug.com/365516
    546   EXPECT_CALL(mock_display_cb_, Display(_)).Times(AtLeast(1));
    547 
    548   event.RunAndWaitForStatus(PIPELINE_OK);
    549 
    550   Play();
    551 
    552   Shutdown();
    553 }
    554 
    555 TEST_F(VideoRendererImplTest, Rebuffer_AlreadyHaveEnoughFrames) {
    556   Initialize();
    557   QueueFrames("0 10 20 30");
    558   EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(0)));
    559   Preroll(0, PIPELINE_OK);
    560 
    561   // Queue an extra frame so that we'll have enough frames to satisfy
    562   // preroll even after the first frame is painted.
    563   QueueFrames("40");
    564   SatisfyPendingRead();
    565   Play();
    566 
    567   // Simulate a Preroll/Play rebuffer sequence.
    568   //
    569   // TODO(scherkus): We shouldn't display the next ready frame in a rebuffer
    570   // situation, see http://crbug.com/365516
    571   EXPECT_CALL(mock_display_cb_, Display(_)).Times(AtLeast(1));
    572 
    573   WaitableMessageLoopEvent event;
    574   renderer_->Preroll(kNoTimestamp(),
    575                      event.GetPipelineStatusCB());
    576 
    577   event.RunAndWaitForStatus(PIPELINE_OK);
    578 
    579   Play();
    580 
    581   Shutdown();
    582 }
    583 
    584 // Verify that a late decoder response doesn't break invariants in the renderer.
    585 TEST_F(VideoRendererImplTest, StopDuringOutstandingRead) {
    586   Initialize();
    587   QueueFrames("0 10 20 30");
    588   EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(0)));
    589   Preroll(0, PIPELINE_OK);
    590   Play();
    591 
    592   // Check that there is an outstanding Read() request.
    593   EXPECT_TRUE(IsReadPending());
    594 
    595   WaitableMessageLoopEvent event;
    596   renderer_->Stop(event.GetClosure());
    597   event.RunAndWait();
    598 }
    599 
    600 TEST_F(VideoRendererImplTest, VideoDecoder_InitFailure) {
    601   InSequence s;
    602   InitializeRenderer(DECODER_ERROR_NOT_SUPPORTED, false);
    603   Stop();
    604 }
    605 
    606 }  // namespace media
    607