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 af589d83112c111f28e651cf2519ffe42718cb51..8933d0a2a1ca8d270b8682daa2f31c7ce6794cc9 100644 |
| --- a/media/renderers/video_renderer_impl_unittest.cc |
| +++ b/media/renderers/video_renderer_impl_unittest.cc |
| @@ -279,6 +279,131 @@ class VideoRendererImplTest |
| return ended_event_.is_signaled(); |
| } |
| + enum class UnderflowTestType { kNormal, kLowDelay, kCantReadWithoutStalling }; |
|
xhwang
2016/04/14 21:28:00
nit: use UPPER_CASE style for enums?
|
| + void BasicUnderflowTest(UnderflowTestType type) { |
| + InitializeWithLowDelay(type == UnderflowTestType::kLowDelay); |
| + if (type == UnderflowTestType::kCantReadWithoutStalling) |
| + ON_CALL(*decoder_, CanReadWithoutStalling()).WillByDefault(Return(false)); |
| + |
| + QueueFrames("0 30 60 90"); |
| + |
| + { |
| + 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); |
| + |
| + // Advance time slightly, but enough to exceed the duration of the last |
| + // frame. |
| + // Frames should be dropped and we should NOT signal having nothing. |
| + { |
| + SCOPED_TRACE("Waiting for frame drops"); |
| + WaitableMessageLoopEvent event; |
| + |
| + // Note: Starting the TimeSource will cause the old VideoRendererImpl to |
| + // start rendering frames on its own thread, so the first frame may be |
| + // received. |
| + time_source_.StartTicking(); |
| + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(30))).Times(0); |
| + |
| + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(60))).Times(0); |
| + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(90))) |
| + .WillOnce(RunClosure(event.GetClosure())); |
| + AdvanceTimeInMs(91); |
| + |
| + event.RunAndWait(); |
| + Mock::VerifyAndClearExpectations(&mock_cb_); |
| + } |
| + |
| + // Advance time more. Now we should signal having nothing. And put |
| + // the last frame up for display. |
| + { |
| + SCOPED_TRACE("Waiting for BUFFERING_HAVE_NOTHING"); |
| + WaitableMessageLoopEvent event; |
| + EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING)) |
| + .WillOnce(RunClosure(event.GetClosure())); |
| + AdvanceTimeInMs(30); |
| + event.RunAndWait(); |
| + Mock::VerifyAndClearExpectations(&mock_cb_); |
| + } |
| + |
| + // Receiving end of stream should signal having enough. |
| + { |
| + SCOPED_TRACE("Waiting for BUFFERING_HAVE_ENOUGH"); |
| + WaitableMessageLoopEvent event; |
| + EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)) |
| + .WillOnce(RunClosure(event.GetClosure())); |
| + SatisfyPendingReadWithEndOfStream(); |
| + event.RunAndWait(); |
| + } |
| + |
| + WaitForEnded(); |
| + Destroy(); |
| + } |
| + |
| + void UnderflowRecoveryTest(UnderflowTestType type) { |
| + InitializeWithLowDelay(type == UnderflowTestType::kLowDelay); |
| + if (type == UnderflowTestType::kCantReadWithoutStalling) |
| + ON_CALL(*decoder_, CanReadWithoutStalling()).WillByDefault(Return(false)); |
| + |
| + QueueFrames("0 20 40 60"); |
| + { |
| + 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); |
| + time_source_.StartTicking(); |
| + |
| + // Advance time, this should cause have nothing to be signaled. |
| + { |
| + SCOPED_TRACE("Waiting for BUFFERING_HAVE_NOTHING"); |
| + WaitableMessageLoopEvent event; |
| + EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING)) |
| + .WillOnce(RunClosure(event.GetClosure())); |
| + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(20))).Times(1); |
| + AdvanceTimeInMs(20); |
| + event.RunAndWait(); |
| + Mock::VerifyAndClearExpectations(&mock_cb_); |
| + } |
| + |
| + AdvanceTimeInMs(59); |
| + EXPECT_EQ(3u, renderer_->frames_queued_for_testing()); |
| + time_source_.StopTicking(); |
| + renderer_->OnTimeStateChanged(false); |
| + EXPECT_EQ(0u, renderer_->frames_queued_for_testing()); |
| + ASSERT_TRUE(IsReadPending()); |
| + |
| + // Queue some frames, satisfy reads, and make sure expired frames are gone |
| + // when the renderer paints the first frame. |
| + { |
| + SCOPED_TRACE("Waiting for BUFFERING_HAVE_ENOUGH"); |
| + WaitableMessageLoopEvent event; |
| + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(80))).Times(1); |
| + EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)) |
| + .WillOnce(RunClosure(event.GetClosure())); |
| + if (type == UnderflowTestType::kNormal) |
| + QueueFrames("80 100 120 140 160"); |
| + else |
| + QueueFrames("40 60 80"); |
| + SatisfyPendingRead(); |
| + event.RunAndWait(); |
| + } |
| + |
| + Destroy(); |
| + } |
| + |
| protected: |
| // Fixture members. |
| scoped_ptr<VideoRendererImpl> renderer_; |
| @@ -543,66 +668,27 @@ TEST_F(VideoRendererImplTest, VideoDecoder_InitFailure) { |
| } |
| TEST_F(VideoRendererImplTest, Underflow) { |
| - Initialize(); |
| - QueueFrames("0 30 60 90"); |
| - |
| - { |
| - 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); |
| - |
| - // Advance time slightly, but enough to exceed the duration of the last frame. |
| - // Frames should be dropped and we should NOT signal having nothing. |
| - { |
| - SCOPED_TRACE("Waiting for frame drops"); |
| - WaitableMessageLoopEvent event; |
| - |
| - // Note: Starting the TimeSource will cause the old VideoRendererImpl to |
| - // start rendering frames on its own thread, so the first frame may be |
| - // received. |
| - time_source_.StartTicking(); |
| - EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(30))).Times(0); |
| + BasicUnderflowTest(UnderflowTestType::kNormal); |
| +} |
| - EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(60))).Times(0); |
| - EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(90))) |
| - .WillOnce(RunClosure(event.GetClosure())); |
| - AdvanceTimeInMs(91); |
| +TEST_F(VideoRendererImplTest, Underflow_LowDelay) { |
| + BasicUnderflowTest(UnderflowTestType::kLowDelay); |
| +} |
| - event.RunAndWait(); |
| - Mock::VerifyAndClearExpectations(&mock_cb_); |
| - } |
| +TEST_F(VideoRendererImplTest, Underflow_CantReadWithoutStalling) { |
| + BasicUnderflowTest(UnderflowTestType::kCantReadWithoutStalling); |
| +} |
| - // Advance time more. Now we should signal having nothing. And put |
| - // the last frame up for display. |
| - { |
| - SCOPED_TRACE("Waiting for BUFFERING_HAVE_NOTHING"); |
| - WaitableMessageLoopEvent event; |
| - EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING)) |
| - .WillOnce(RunClosure(event.GetClosure())); |
| - AdvanceTimeInMs(30); |
| - event.RunAndWait(); |
| - Mock::VerifyAndClearExpectations(&mock_cb_); |
| - } |
| +TEST_F(VideoRendererImplTest, UnderflowRecovery) { |
| + UnderflowRecoveryTest(UnderflowTestType::kNormal); |
| +} |
| - // Receiving end of stream should signal having enough. |
| - { |
| - SCOPED_TRACE("Waiting for BUFFERING_HAVE_ENOUGH"); |
| - WaitableMessageLoopEvent event; |
| - EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)) |
| - .WillOnce(RunClosure(event.GetClosure())); |
| - SatisfyPendingReadWithEndOfStream(); |
| - event.RunAndWait(); |
| - } |
| +TEST_F(VideoRendererImplTest, UnderflowRecovery_LowDelay) { |
| + UnderflowRecoveryTest(UnderflowTestType::kLowDelay); |
| +} |
| - WaitForEnded(); |
| - Destroy(); |
| +TEST_F(VideoRendererImplTest, UnderflowRecovery_CantReadWithoutStalling) { |
| + UnderflowRecoveryTest(UnderflowTestType::kCantReadWithoutStalling); |
| } |
| // Verifies that the sink is stopped after rendering the first frame if |