Chromium Code Reviews| Index: media/renderers/video_renderer_impl_unittest.cc |
| diff --git a/media/renderers/video_renderer_impl_unittest.cc b/media/renderers/video_renderer_impl_unittest.cc |
| index 9203d69ec664d4a43d18470b5c00d02cba5edd81..0f47ab57b085763dd61dbdf869e5531c52fd71fc 100644 |
| --- a/media/renderers/video_renderer_impl_unittest.cc |
| +++ b/media/renderers/video_renderer_impl_unittest.cc |
| @@ -36,6 +36,9 @@ using ::testing::StrictMock; |
| namespace media { |
| +// Threshold for Render() callbacks used for testing; should not be zero. |
| +static const int kTestBackgroundRenderTimeoutMs = 25; |
| + |
| ACTION_P(RunClosure, closure) { |
| closure.Run(); |
| } |
| @@ -45,7 +48,10 @@ MATCHER_P(HasTimestamp, ms, "") { |
| return arg->timestamp().InMilliseconds() == ms; |
| } |
| -class VideoRendererImplTest : public ::testing::Test { |
| +// TODO(dalecurtis): Switch this to TestWithValues() and TEST_P() to get both |
| +// paths tested. |
| + |
| +class VideoRendererImplTest : public testing::TestWithParam<bool> { |
| public: |
| VideoRendererImplTest() |
| : tick_clock_(new base::SimpleTestTickClock()), |
| @@ -64,10 +70,14 @@ class VideoRendererImplTest : public ::testing::Test { |
| renderer_.reset(new VideoRendererImpl( |
| message_loop_.message_loop_proxy(), null_video_sink_.get(), |
| decoders.Pass(), true, new MediaLog())); |
| - |
| + if (GetParam()) |
| + renderer_->enable_new_video_renderer_for_testing(); |
| renderer_->SetTickClockForTesting(scoped_ptr<base::TickClock>(tick_clock_)); |
| null_video_sink_->set_tick_clock_for_testing(tick_clock_); |
| + // Disable background rendering for tests by default. |
| + renderer_->SetBackgroundRenderingForTesting(false, base::TimeDelta()); |
| + |
| // Start wallclock time at a non-zero value. |
| AdvanceWallclockTimeInMs(12345); |
| @@ -145,6 +155,11 @@ class VideoRendererImplTest : public ::testing::Test { |
| message_loop_.RunUntilIdle(); |
| } |
| + void SuspendRenderCallbacks() { |
| + null_video_sink_->pause_callbacks(base::TimeTicks() + |
| + base::TimeDelta::Max()); |
| + } |
| + |
| // Parses a string representation of video frames and generates corresponding |
| // VideoFrame objects in |decode_results_|. |
| // |
| @@ -266,6 +281,10 @@ class VideoRendererImplTest : public ::testing::Test { |
| time_ += base::TimeDelta::FromMilliseconds(time_ms); |
| } |
| + bool has_ended() const { |
| + return ended_event_.is_signaled(); |
| + } |
| + |
| protected: |
| // Fixture members. |
| scoped_ptr<VideoRendererImpl> renderer_; |
| @@ -344,21 +363,21 @@ class VideoRendererImplTest : public ::testing::Test { |
| DISALLOW_COPY_AND_ASSIGN(VideoRendererImplTest); |
| }; |
| -TEST_F(VideoRendererImplTest, DoNothing) { |
| +TEST_P(VideoRendererImplTest, DoNothing) { |
| // Test that creation and deletion doesn't depend on calls to Initialize() |
| // and/or Destroy(). |
| } |
| -TEST_F(VideoRendererImplTest, DestroyWithoutInitialize) { |
| +TEST_P(VideoRendererImplTest, DestroyWithoutInitialize) { |
| Destroy(); |
| } |
| -TEST_F(VideoRendererImplTest, Initialize) { |
| +TEST_P(VideoRendererImplTest, Initialize) { |
| Initialize(); |
| Destroy(); |
| } |
| -TEST_F(VideoRendererImplTest, InitializeAndStartPlayingFrom) { |
| +TEST_P(VideoRendererImplTest, InitializeAndStartPlayingFrom) { |
| Initialize(); |
| QueueFrames("0 10 20 30"); |
| EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(0))); |
| @@ -367,12 +386,12 @@ TEST_F(VideoRendererImplTest, InitializeAndStartPlayingFrom) { |
| Destroy(); |
| } |
| -TEST_F(VideoRendererImplTest, DestroyWhileInitializing) { |
| +TEST_P(VideoRendererImplTest, DestroyWhileInitializing) { |
| CallInitialize(NewExpectedStatusCB(PIPELINE_ERROR_ABORT), false, PIPELINE_OK); |
| Destroy(); |
| } |
| -TEST_F(VideoRendererImplTest, DestroyWhileFlushing) { |
| +TEST_P(VideoRendererImplTest, DestroyWhileFlushing) { |
| Initialize(); |
| QueueFrames("0 10 20 30"); |
| EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(0))); |
| @@ -383,7 +402,7 @@ TEST_F(VideoRendererImplTest, DestroyWhileFlushing) { |
| Destroy(); |
| } |
| -TEST_F(VideoRendererImplTest, Play) { |
| +TEST_P(VideoRendererImplTest, Play) { |
| Initialize(); |
| QueueFrames("0 10 20 30"); |
| EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(0))); |
| @@ -392,7 +411,7 @@ TEST_F(VideoRendererImplTest, Play) { |
| Destroy(); |
| } |
| -TEST_F(VideoRendererImplTest, FlushWithNothingBuffered) { |
| +TEST_P(VideoRendererImplTest, FlushWithNothingBuffered) { |
| Initialize(); |
| StartPlayingFrom(0); |
| @@ -402,29 +421,27 @@ TEST_F(VideoRendererImplTest, FlushWithNothingBuffered) { |
| Destroy(); |
| } |
| -TEST_F(VideoRendererImplTest, DecodeError_Playing) { |
| +TEST_P(VideoRendererImplTest, DecodeError_Playing) { |
| Initialize(); |
| QueueFrames("0 10 20 30"); |
| EXPECT_CALL(mock_cb_, FrameReceived(_)).Times(testing::AtLeast(1)); |
| EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); |
| StartPlayingFrom(0); |
| - WaitForPendingRead(); |
| - |
| QueueFrames("error"); |
| SatisfyPendingRead(); |
| WaitForError(PIPELINE_ERROR_DECODE); |
| Destroy(); |
| } |
| -TEST_F(VideoRendererImplTest, DecodeError_DuringStartPlayingFrom) { |
| +TEST_P(VideoRendererImplTest, DecodeError_DuringStartPlayingFrom) { |
| Initialize(); |
| QueueFrames("error"); |
| StartPlayingFrom(0); |
| Destroy(); |
| } |
| -TEST_F(VideoRendererImplTest, StartPlayingFrom_Exact) { |
| +TEST_P(VideoRendererImplTest, StartPlayingFrom_Exact) { |
| Initialize(); |
| QueueFrames("50 60 70 80 90"); |
| @@ -434,7 +451,7 @@ TEST_F(VideoRendererImplTest, StartPlayingFrom_Exact) { |
| Destroy(); |
| } |
| -TEST_F(VideoRendererImplTest, StartPlayingFrom_RightBefore) { |
| +TEST_P(VideoRendererImplTest, StartPlayingFrom_RightBefore) { |
| Initialize(); |
| QueueFrames("50 60 70 80 90"); |
| @@ -444,7 +461,7 @@ TEST_F(VideoRendererImplTest, StartPlayingFrom_RightBefore) { |
| Destroy(); |
| } |
| -TEST_F(VideoRendererImplTest, StartPlayingFrom_RightAfter) { |
| +TEST_P(VideoRendererImplTest, StartPlayingFrom_RightAfter) { |
| Initialize(); |
| QueueFrames("50 60 70 80 90"); |
| @@ -454,7 +471,7 @@ TEST_F(VideoRendererImplTest, StartPlayingFrom_RightAfter) { |
| Destroy(); |
| } |
| -TEST_F(VideoRendererImplTest, StartPlayingFrom_LowDelay) { |
| +TEST_P(VideoRendererImplTest, StartPlayingFrom_LowDelay) { |
| // In low-delay mode only one frame is required to finish preroll. |
| InitializeWithLowDelay(true); |
| QueueFrames("0"); |
| @@ -470,6 +487,7 @@ TEST_F(VideoRendererImplTest, StartPlayingFrom_LowDelay) { |
| QueueFrames("10"); |
| SatisfyPendingRead(); |
| + renderer_->OnTimeStateChanged(true); |
| WaitableMessageLoopEvent event; |
| EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(10))) |
| .WillOnce(RunClosure(event.GetClosure())); |
| @@ -480,7 +498,7 @@ TEST_F(VideoRendererImplTest, StartPlayingFrom_LowDelay) { |
| } |
| // Verify that a late decoder response doesn't break invariants in the renderer. |
| -TEST_F(VideoRendererImplTest, DestroyDuringOutstandingRead) { |
| +TEST_P(VideoRendererImplTest, DestroyDuringOutstandingRead) { |
| Initialize(); |
| QueueFrames("0 10 20 30"); |
| EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(0))); |
| @@ -493,12 +511,12 @@ TEST_F(VideoRendererImplTest, DestroyDuringOutstandingRead) { |
| Destroy(); |
| } |
| -TEST_F(VideoRendererImplTest, VideoDecoder_InitFailure) { |
| +TEST_P(VideoRendererImplTest, VideoDecoder_InitFailure) { |
| InitializeRenderer(DECODER_ERROR_NOT_SUPPORTED, false); |
| Destroy(); |
| } |
| -TEST_F(VideoRendererImplTest, Underflow) { |
| +TEST_P(VideoRendererImplTest, Underflow) { |
| Initialize(); |
| QueueFrames("0 10 20 30"); |
| @@ -512,6 +530,8 @@ TEST_F(VideoRendererImplTest, Underflow) { |
| Mock::VerifyAndClearExpectations(&mock_cb_); |
| } |
| + renderer_->OnTimeStateChanged(true); |
| + |
| // Advance time slightly, but enough to exceed the duration of the last frame. |
| // Frames should be dropped and we should NOT signal having nothing. |
| { |
| @@ -554,4 +574,145 @@ TEST_F(VideoRendererImplTest, Underflow) { |
| Destroy(); |
| } |
| +// Tests the case where the video started in the background and never received |
| +// any Render() calls and time never started progressing (so the sink should be |
| +// stopped immediately). |
| +TEST_P(VideoRendererImplTest, BackgroundRenderingStopsAfterFirstFrame) { |
| + // This test is only for the new rendering path. |
| + if (!GetParam()) |
| + return; |
| + |
| + // By default, tests disable background rendering, so enable it now and give |
| + // a short, but non-zero, timeout. |
| + renderer_->SetBackgroundRenderingForTesting( |
| + true, base::TimeDelta::FromMilliseconds(kTestBackgroundRenderTimeoutMs)); |
| + |
| + InitializeWithLowDelay(true); |
| + QueueFrames("0"); |
| + |
| + EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); |
| + |
| + // Pause callbacks forever, but don't start the sink. Ended should not fire. |
| + SuspendRenderCallbacks(); |
| + StartPlayingFrom(0); |
| + EXPECT_TRUE(IsReadPending()); |
| + SatisfyPendingReadWithEndOfStream(); |
| + |
| + { |
| + SCOPED_TRACE("Waiting for sink to stop."); |
| + WaitableMessageLoopEvent event; |
| + null_video_sink_->set_stop_callback(event.GetClosure()); |
| + event.RunAndWait(); |
| + } |
| + |
| + EXPECT_FALSE(has_ended()); |
| + Destroy(); |
| +} |
| + |
| +// Tests the case where the video started in the background and never received |
| +// any Render() calls, but time is progressing. |
| +TEST_P(VideoRendererImplTest, BackgroundRenderingNeverStarted) { |
| + // This test is only for the new rendering path. |
| + if (!GetParam()) |
| + return; |
| + |
| + // By default, tests disable background rendering, so enable it now and give |
| + // a short, but non-zero, timeout. |
| + renderer_->SetBackgroundRenderingForTesting( |
| + true, base::TimeDelta::FromMilliseconds(kTestBackgroundRenderTimeoutMs)); |
| + |
| + Initialize(); |
| + QueueFrames("0 10 20 30"); |
| + |
| + EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); |
| + |
| + // Start the sink and pause callbacks forever. |
| + renderer_->OnTimeStateChanged(true); |
| + SuspendRenderCallbacks(); |
| + StartPlayingFrom(0); |
| + AdvanceTimeInMs(41); |
| + |
| + // Eventually background rendering should request new buffers and at that |
| + // point fire the ended event if rendering has completed. |
| + WaitForPendingRead(); |
| + SatisfyPendingReadWithEndOfStream(); |
| + WaitForEnded(); |
| + Destroy(); |
| +} |
| + |
| +// Tests the case where the video started in the background and never received |
| +// any Render() calls, but time is progressing and there's only a single frame |
| +// in the video. |
| +TEST_P(VideoRendererImplTest, BackgroundRenderingNeverStartedSingleFrame) { |
| + // This test is only for the new rendering path. |
| + if (!GetParam()) |
| + return; |
| + |
| + // By default, tests disable background rendering, so enable it now and give |
| + // a short, but non-zero, timeout. |
| + renderer_->SetBackgroundRenderingForTesting( |
| + true, base::TimeDelta::FromMilliseconds(kTestBackgroundRenderTimeoutMs)); |
| + |
| + Initialize(); |
| + QueueFrames("0"); |
| + |
| + EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); |
| + |
| + // Start the sink and pause callbacks forever. |
| + renderer_->OnTimeStateChanged(true); |
| + SuspendRenderCallbacks(); |
| + StartPlayingFrom(0); |
| + |
| + // Eventually background rendering should request new buffers and at that |
| + // point fire the ended event if rendering has completed. |
| + WaitForPendingRead(); |
| + SatisfyPendingReadWithEndOfStream(); |
| + WaitForEnded(); |
| + Destroy(); |
| +} |
| + |
| +// Tests the case where the video started and received a single Render() call, |
| +// then the video was put into the background. |
| +TEST_P(VideoRendererImplTest, BackgroundRenderingRenderStartedThenStopped) { |
| + // This test is only for the new rendering path. |
| + if (!GetParam()) |
| + return; |
| + |
| + // By default, tests disable background rendering, so enable it now and give |
| + // a short, but non-zero, timeout. |
| + renderer_->SetBackgroundRenderingForTesting( |
| + true, base::TimeDelta::FromMilliseconds(kTestBackgroundRenderTimeoutMs)); |
| + |
| + Initialize(); |
| + QueueFrames("0 10 20 30"); |
| + |
| + // Start the sink and wait for the first callback. |
| + { |
| + WaitableMessageLoopEvent event; |
| + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(0))); |
| + EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)) |
| + .WillOnce(RunClosure(event.GetClosure())); |
| + StartPlayingFrom(0); |
| + event.RunAndWait(); |
| + Mock::VerifyAndClearExpectations(&mock_cb_); |
| + } |
| + |
| + renderer_->OnTimeStateChanged(true); |
| + |
| + // Suspend all future callbacks and synthetically advance the media time. |
| + SuspendRenderCallbacks(); |
| + AdvanceTimeInMs(41); |
| + |
| + // Eventually background rendering should request new buffers and at that |
| + // point fire the ended event if rendering has completed. |
| + WaitForPendingRead(); |
| + SatisfyPendingReadWithEndOfStream(); |
| + WaitForEnded(); |
| + Destroy(); |
| +} |
| + |
| +INSTANTIATE_TEST_CASE_P(VideoRendererImplTest, |
| + VideoRendererImplTest, |
| + testing::Bool()); |
|
xhwang
2015/04/29 06:51:55
For better test names, use different prefix for di
DaleCurtis
2015/04/30 03:49:37
Done.
|
| + |
| } // namespace media |