diff options
author | dalecurtis <dalecurtis@chromium.org> | 2015-04-29 01:31:01 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-04-29 08:31:43 +0000 |
commit | 6523d600339aad86efcf1c238152e833c248dae5 (patch) | |
tree | 505c14a911e4afc30f2f0d5d83918f39bd0dbfae /media | |
parent | 3c2ba0ab093e303f5ae04ed8a88c94c19b9e26ff (diff) | |
download | chromium_src-6523d600339aad86efcf1c238152e833c248dae5.zip chromium_src-6523d600339aad86efcf1c238152e833c248dae5.tar.gz chromium_src-6523d600339aad86efcf1c238152e833c248dae5.tar.bz2 |
Introduce NullVideoSink for test classes.
Similar to NullAudioSink, but I decided not to use FakeAudioWorker
as a generic fake worker since it adds more complexity then we need
for the video renderer sink interface. I also didn't want to add
pause support or stop callback support to it.
BUG=473424
TEST=new unittest, forthcoming pipeline changes.
Review URL: https://codereview.chromium.org/1116473002
Cr-Commit-Position: refs/heads/master@{#327450}
Diffstat (limited to 'media')
-rw-r--r-- | media/base/BUILD.gn | 3 | ||||
-rw-r--r-- | media/base/null_video_sink.cc | 101 | ||||
-rw-r--r-- | media/base/null_video_sink.h | 93 | ||||
-rw-r--r-- | media/base/null_video_sink_unittest.cc | 147 | ||||
-rw-r--r-- | media/media.gyp | 3 | ||||
-rw-r--r-- | media/renderers/video_renderer_impl_unittest.cc | 60 | ||||
-rw-r--r-- | media/test/pipeline_integration_test_base.cc | 18 | ||||
-rw-r--r-- | media/test/pipeline_integration_test_base.h | 17 |
8 files changed, 392 insertions, 50 deletions
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn index 8a50fbe..f8f3c69 100644 --- a/media/base/BUILD.gn +++ b/media/base/BUILD.gn @@ -121,6 +121,8 @@ source_set("base") { "media_switches.h", "multi_channel_resampler.cc", "multi_channel_resampler.h", + "null_video_sink.cc", + "null_video_sink.h", "pipeline.cc", "pipeline.h", "pipeline_status.h", @@ -374,6 +376,7 @@ source_set("unittests") { "gmock_callback_support_unittest.cc", "key_systems_unittest.cc", "multi_channel_resampler_unittest.cc", + "null_video_sink_unittest.cc", "pipeline_unittest.cc", "ranges_unittest.cc", "run_all_unittests.cc", diff --git a/media/base/null_video_sink.cc b/media/base/null_video_sink.cc new file mode 100644 index 0000000..214c499 --- /dev/null +++ b/media/base/null_video_sink.cc @@ -0,0 +1,101 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/base/null_video_sink.h" + +#include "base/bind.h" +#include "base/callback_helpers.h" +#include "base/location.h" +#include "base/single_thread_task_runner.h" + +namespace media { + +NullVideoSink::NullVideoSink( + bool clockless, + base::TimeDelta interval, + const NewFrameCB& new_frame_cb, + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) + : clockless_(clockless), + interval_(interval), + new_frame_cb_(new_frame_cb), + task_runner_(task_runner), + started_(false), + callback_(nullptr), + tick_clock_(&default_tick_clock_) { +} + +NullVideoSink::~NullVideoSink() { + DCHECK(!started_); +} + +void NullVideoSink::Start(RenderCallback* callback) { + DCHECK(task_runner_->BelongsToCurrentThread()); + DCHECK(!started_); + callback_ = callback; + started_ = true; + last_now_ = current_render_time_ = tick_clock_->NowTicks(); + cancelable_worker_.Reset( + base::Bind(&NullVideoSink::CallRender, base::Unretained(this))); + task_runner_->PostTask(FROM_HERE, cancelable_worker_.callback()); +} + +void NullVideoSink::Stop() { + DCHECK(task_runner_->BelongsToCurrentThread()); + cancelable_worker_.Cancel(); + started_ = false; + if (!stop_cb_.is_null()) + base::ResetAndReturn(&stop_cb_).Run(); +} + +void NullVideoSink::CallRender() { + DCHECK(task_runner_->BelongsToCurrentThread()); + DCHECK(started_); + + const base::TimeTicks end_of_interval = current_render_time_ + interval_; + if (current_render_time_ > pause_end_time_) { + scoped_refptr<VideoFrame> new_frame = + callback_->Render(current_render_time_, end_of_interval); + const bool is_new_frame = new_frame != last_frame_; + last_frame_ = new_frame; + if (is_new_frame) + new_frame_cb_.Run(new_frame); + } + + current_render_time_ += interval_; + + if (clockless_) { + task_runner_->PostTask(FROM_HERE, cancelable_worker_.callback()); + return; + } + + // Recompute now to compensate for the cost of Render(). + const base::TimeTicks now = tick_clock_->NowTicks(); + base::TimeDelta delay = current_render_time_ - now; + + // If we're behind, find the next nearest on time interval. + if (delay < base::TimeDelta()) + delay += interval_ * (-delay / interval_ + 1); + current_render_time_ = now + delay; + + // The tick clock is frozen in this case, so clamp delay to the interval time. + // We still want the interval passed to Render() to grow, but we also don't + // want the delay used here to increase slowly over time. + if (last_now_ == now && delay > interval_) + delay = interval_; + last_now_ = now; + + task_runner_->PostDelayedTask(FROM_HERE, cancelable_worker_.callback(), + delay); +} + +void NullVideoSink::PaintFrameUsingOldRenderingPath( + const scoped_refptr<VideoFrame>& frame) { + new_frame_cb_.Run(frame); +} + +void NullVideoSink::PauseRenderCallbacks(base::TimeTicks pause_until) { + pause_end_time_ = pause_until; +} + +} // namespace media diff --git a/media/base/null_video_sink.h b/media/base/null_video_sink.h new file mode 100644 index 0000000..b4c0ac7 --- /dev/null +++ b/media/base/null_video_sink.h @@ -0,0 +1,93 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_AUDIO_NULL_VIDEO_SINK_H_ +#define MEDIA_AUDIO_NULL_VIDEO_SINK_H_ + +#include "base/cancelable_callback.h" +#include "base/md5.h" +#include "base/memory/scoped_ptr.h" +#include "base/time/default_tick_clock.h" +#include "base/time/tick_clock.h" +#include "media/base/video_renderer_sink.h" + +namespace base { +class SingleThreadTaskRunner; +} + +namespace media { + +class MEDIA_EXPORT NullVideoSink : NON_EXPORTED_BASE(public VideoRendererSink) { + public: + using NewFrameCB = base::Callback<void(const scoped_refptr<VideoFrame>&)>; + + // Periodically calls |callback| every |interval| on |task_runner| once the + // sink has been started. If |clockless| is true, the RenderCallback will + // be called back to back by repeated post tasks. Optionally, if specified, + // |new_frame_cb| will be called for each new frame received. + NullVideoSink(bool clockless, + base::TimeDelta interval, + const NewFrameCB& new_frame_cb, + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner); + ~NullVideoSink() override; + + // VideoRendererSink implementation. + void Start(RenderCallback* callback) override; + void Stop() override; + void PaintFrameUsingOldRenderingPath( + const scoped_refptr<VideoFrame>& frame) override; + + // Allows tests to simulate suspension of Render() callbacks. + void PauseRenderCallbacks(base::TimeTicks pause_until); + + void set_tick_clock_for_testing(base::TickClock* tick_clock) { + tick_clock_ = tick_clock; + } + + // Sets |stop_cb_|, which will be fired when Stop() is called. + void set_stop_cb(const base::Closure& stop_cb) { + stop_cb_ = stop_cb; + } + + private: + // Task that periodically calls Render() to consume video data. + void CallRender(); + + const bool clockless_; + const base::TimeDelta interval_; + const NewFrameCB new_frame_cb_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + + bool started_; + RenderCallback* callback_; + + // Manages cancellation of periodic Render() callback task. + base::CancelableClosure cancelable_worker_; + + // Used to determine when a new frame is received. + scoped_refptr<VideoFrame> last_frame_; + + // Used to determine the interval given to RenderCallback::Render() as well as + // to maintain stable periodicity of callbacks. + base::TimeTicks current_render_time_; + + // Used to suspend Render() callbacks to |callback_| for some time. + base::TimeTicks pause_end_time_; + + // Allow for an injectable tick clock for testing. + base::DefaultTickClock default_tick_clock_; + base::TimeTicks last_now_; + + // If specified, used instead of |default_tick_clock_|. + base::TickClock* tick_clock_; + + // If set, called when Stop() is called. + base::Closure stop_cb_; + + DISALLOW_COPY_AND_ASSIGN(NullVideoSink); +}; + +} // namespace media + +#endif // MEDIA_AUDIO_NULL_VIDEO_SINK_H_ diff --git a/media/base/null_video_sink_unittest.cc b/media/base/null_video_sink_unittest.cc new file mode 100644 index 0000000..f2412e5 --- /dev/null +++ b/media/base/null_video_sink_unittest.cc @@ -0,0 +1,147 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/bind.h" +#include "base/callback_helpers.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/test/simple_test_tick_clock.h" +#include "media/base/null_video_sink.h" +#include "media/base/test_helpers.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; +using testing::DoAll; +using testing::Return; + +namespace media { + +ACTION_P(RunClosure, closure) { + closure.Run(); +} + +class NullVideoSinkTest : public testing::Test, + public VideoRendererSink::RenderCallback { + public: + NullVideoSinkTest() { + // Never use null TimeTicks since they have special connotations. + tick_clock_.Advance(base::TimeDelta::FromMicroseconds(12345)); + } + ~NullVideoSinkTest() override {} + + scoped_ptr<NullVideoSink> ConstructSink(bool clockless, + base::TimeDelta interval) { + scoped_ptr<NullVideoSink> new_sink(new NullVideoSink( + clockless, interval, + base::Bind(&NullVideoSinkTest::FrameReceived, base::Unretained(this)), + message_loop_.task_runner())); + new_sink->set_tick_clock_for_testing(&tick_clock_); + return new_sink; + } + + scoped_refptr<VideoFrame> CreateFrame(base::TimeDelta timestamp) { + const gfx::Size natural_size(8, 8); + return VideoFrame::CreateFrame(VideoFrame::YV12, natural_size, + gfx::Rect(natural_size), natural_size, + timestamp); + } + + // VideoRendererSink::RenderCallback implementation. + MOCK_METHOD2(Render, + scoped_refptr<VideoFrame>(base::TimeTicks, base::TimeTicks)); + MOCK_METHOD0(OnFrameDropped, void()); + + MOCK_METHOD1(FrameReceived, void(const scoped_refptr<VideoFrame>&)); + + protected: + base::MessageLoop message_loop_; + base::SimpleTestTickClock tick_clock_; + + DISALLOW_COPY_AND_ASSIGN(NullVideoSinkTest); +}; + +TEST_F(NullVideoSinkTest, BasicFunctionality) { + const base::TimeDelta kInterval = base::TimeDelta::FromMilliseconds(25); + + scoped_ptr<NullVideoSink> sink = ConstructSink(false, kInterval); + scoped_refptr<VideoFrame> test_frame = CreateFrame(base::TimeDelta()); + + // The sink shouldn't have to be started to use the paint method. + EXPECT_CALL(*this, FrameReceived(test_frame)); + sink->PaintFrameUsingOldRenderingPath(test_frame); + + { + SCOPED_TRACE("Waiting for sink startup."); + sink->Start(this); + const base::TimeTicks current_time = tick_clock_.NowTicks(); + const base::TimeTicks current_interval_end = current_time + kInterval; + EXPECT_CALL(*this, Render(current_time, current_interval_end)) + .WillOnce(Return(test_frame)); + WaitableMessageLoopEvent event; + EXPECT_CALL(*this, FrameReceived(test_frame)) + .WillOnce(RunClosure(event.GetClosure())); + event.RunAndWait(); + } + + // A second call returning the same frame should not result in a new call to + // FrameReceived(). + { + SCOPED_TRACE("Waiting for second render call."); + WaitableMessageLoopEvent event; + EXPECT_CALL(*this, Render(_, _)) + .WillOnce(Return(test_frame)) + .WillOnce(Return(nullptr)); + EXPECT_CALL(*this, FrameReceived(test_frame)).Times(0); + EXPECT_CALL(*this, FrameReceived(scoped_refptr<VideoFrame>())) + .WillOnce(RunClosure(event.GetClosure())); + event.RunAndWait(); + } + + { + SCOPED_TRACE("Waiting for stop event."); + WaitableMessageLoopEvent event; + sink->set_stop_cb(event.GetClosure()); + sink->Stop(); + event.RunAndWait(); + } +} + +TEST_F(NullVideoSinkTest, ClocklessFunctionality) { + // Construct the sink with a huge interval, it should still complete quickly. + const base::TimeDelta interval = base::TimeDelta::FromSeconds(10); + scoped_ptr<NullVideoSink> sink = ConstructSink(true, interval); + + scoped_refptr<VideoFrame> test_frame = CreateFrame(base::TimeDelta()); + sink->Start(this); + + EXPECT_CALL(*this, FrameReceived(test_frame)).Times(1); + EXPECT_CALL(*this, FrameReceived(scoped_refptr<VideoFrame>())).Times(1); + + const int kTestRuns = 6; + const base::TimeTicks now = base::TimeTicks::Now(); + const base::TimeTicks current_time = tick_clock_.NowTicks(); + + // Use a RunLoop instead of WaitableMessageLoopEvent() since it will only quit + // the loop when it's idle, instead of quitting immediately which is required + // when clockless playback is enabled (otherwise the loop is never idle). + base::RunLoop run_loop; + for (int i = 0; i < kTestRuns; ++i) { + if (i < kTestRuns - 1) { + EXPECT_CALL(*this, Render(current_time + i * interval, + current_time + (i + 1) * interval)) + .WillOnce(Return(test_frame)); + } else { + EXPECT_CALL(*this, Render(current_time + i * interval, + current_time + (i + 1) * interval)) + .WillOnce(DoAll(RunClosure(run_loop.QuitClosure()), Return(nullptr))); + } + } + + run_loop.Run(); + ASSERT_LT(base::TimeTicks::Now() - now, kTestRuns * interval); + sink->Stop(); +} + +} diff --git a/media/media.gyp b/media/media.gyp index e4518de..327c01c 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -332,6 +332,8 @@ 'base/media_win.cc', 'base/multi_channel_resampler.cc', 'base/multi_channel_resampler.h', + 'base/null_video_sink.cc', + 'base/null_video_sink.h', 'base/pipeline.cc', 'base/pipeline.h', 'base/pipeline_status.h', @@ -1211,6 +1213,7 @@ 'base/mac/video_frame_mac_unittests.cc', 'base/media_file_checker_unittest.cc', 'base/multi_channel_resampler_unittest.cc', + 'base/null_video_sink_unittest.cc', 'base/pipeline_unittest.cc', 'base/ranges_unittest.cc', 'base/run_all_unittests.cc', diff --git a/media/renderers/video_renderer_impl_unittest.cc b/media/renderers/video_renderer_impl_unittest.cc index 86f767f..9203d69 100644 --- a/media/renderers/video_renderer_impl_unittest.cc +++ b/media/renderers/video_renderer_impl_unittest.cc @@ -19,6 +19,7 @@ #include "media/base/gmock_callback_support.h" #include "media/base/limits.h" #include "media/base/mock_filters.h" +#include "media/base/null_video_sink.h" #include "media/base/test_helpers.h" #include "media/base/video_frame.h" #include "media/renderers/video_renderer_impl.h" @@ -53,11 +54,19 @@ class VideoRendererImplTest : public ::testing::Test { ScopedVector<VideoDecoder> decoders; decoders.push_back(decoder_); - renderer_.reset(new VideoRendererImpl(message_loop_.message_loop_proxy(), - &mock_cb_, - decoders.Pass(), true, - new MediaLog())); + // Since the Underflow test needs a render interval shorter than the frame + // duration, use 120Hz (which makes each interval is < 10ms; ~9.9ms). + null_video_sink_.reset(new NullVideoSink( + false, base::TimeDelta::FromSecondsD(1.0 / 120), + base::Bind(&MockCB::FrameReceived, base::Unretained(&mock_cb_)), + message_loop_.task_runner())); + + renderer_.reset(new VideoRendererImpl( + message_loop_.message_loop_proxy(), null_video_sink_.get(), + decoders.Pass(), true, new MediaLog())); + renderer_->SetTickClockForTesting(scoped_ptr<base::TickClock>(tick_clock_)); + null_video_sink_->set_tick_clock_for_testing(tick_clock_); // Start wallclock time at a non-zero value. AdvanceWallclockTimeInMs(12345); @@ -265,19 +274,16 @@ class VideoRendererImplTest : public ::testing::Test { NiceMock<MockDemuxerStream> demuxer_stream_; // Use StrictMock<T> to catch missing/extra callbacks. - // TODO(dalecurtis): Mocks won't be useful for the new rendering path, we'll - // need fake callback generators like we have for the audio path. - // http://crbug.com/473424 - class MockCB : public VideoRendererSink { + class MockCB { public: - MOCK_METHOD1(Start, void(VideoRendererSink::RenderCallback*)); - MOCK_METHOD0(Stop, void()); - MOCK_METHOD1(PaintFrameUsingOldRenderingPath, - void(const scoped_refptr<VideoFrame>&)); + MOCK_METHOD1(FrameReceived, void(const scoped_refptr<VideoFrame>&)); MOCK_METHOD1(BufferingStateChange, void(BufferingState)); }; StrictMock<MockCB> mock_cb_; + // Must be destroyed before |renderer_| since they share |tick_clock_|. + scoped_ptr<NullVideoSink> null_video_sink_; + private: base::TimeTicks GetWallClockTime(base::TimeDelta time) { base::AutoLock l(lock_); @@ -355,7 +361,7 @@ TEST_F(VideoRendererImplTest, Initialize) { TEST_F(VideoRendererImplTest, InitializeAndStartPlayingFrom) { Initialize(); QueueFrames("0 10 20 30"); - EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(0))); + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(0))); EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); StartPlayingFrom(0); Destroy(); @@ -369,7 +375,7 @@ TEST_F(VideoRendererImplTest, DestroyWhileInitializing) { TEST_F(VideoRendererImplTest, DestroyWhileFlushing) { Initialize(); QueueFrames("0 10 20 30"); - EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(0))); + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(0))); EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); StartPlayingFrom(0); EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING)); @@ -380,7 +386,7 @@ TEST_F(VideoRendererImplTest, DestroyWhileFlushing) { TEST_F(VideoRendererImplTest, Play) { Initialize(); QueueFrames("0 10 20 30"); - EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(0))); + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(0))); EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); StartPlayingFrom(0); Destroy(); @@ -399,10 +405,12 @@ TEST_F(VideoRendererImplTest, FlushWithNothingBuffered) { TEST_F(VideoRendererImplTest, DecodeError_Playing) { Initialize(); QueueFrames("0 10 20 30"); - EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(0))); + 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); @@ -420,7 +428,7 @@ TEST_F(VideoRendererImplTest, StartPlayingFrom_Exact) { Initialize(); QueueFrames("50 60 70 80 90"); - EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(60))); + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(60))); EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); StartPlayingFrom(60); Destroy(); @@ -430,7 +438,7 @@ TEST_F(VideoRendererImplTest, StartPlayingFrom_RightBefore) { Initialize(); QueueFrames("50 60 70 80 90"); - EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(50))); + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(50))); EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); StartPlayingFrom(59); Destroy(); @@ -440,7 +448,7 @@ TEST_F(VideoRendererImplTest, StartPlayingFrom_RightAfter) { Initialize(); QueueFrames("50 60 70 80 90"); - EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(60))); + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(60))); EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); StartPlayingFrom(61); Destroy(); @@ -452,7 +460,7 @@ TEST_F(VideoRendererImplTest, StartPlayingFrom_LowDelay) { QueueFrames("0"); // Expect some amount of have enough/nothing due to only requiring one frame. - EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(0))); + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(0))); EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)) .Times(AnyNumber()); EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING)) @@ -463,7 +471,7 @@ TEST_F(VideoRendererImplTest, StartPlayingFrom_LowDelay) { SatisfyPendingRead(); WaitableMessageLoopEvent event; - EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(10))) + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(10))) .WillOnce(RunClosure(event.GetClosure())); AdvanceTimeInMs(10); event.RunAndWait(); @@ -475,7 +483,7 @@ TEST_F(VideoRendererImplTest, StartPlayingFrom_LowDelay) { TEST_F(VideoRendererImplTest, DestroyDuringOutstandingRead) { Initialize(); QueueFrames("0 10 20 30"); - EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(0))); + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(0))); EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); StartPlayingFrom(0); @@ -496,7 +504,7 @@ TEST_F(VideoRendererImplTest, Underflow) { { WaitableMessageLoopEvent event; - EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(0))); + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(0))); EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)) .WillOnce(RunClosure(event.GetClosure())); StartPlayingFrom(0); @@ -509,11 +517,11 @@ TEST_F(VideoRendererImplTest, Underflow) { { SCOPED_TRACE("Waiting for frame drops"); WaitableMessageLoopEvent event; - EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(10))) + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(10))) .Times(0); - EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(20))) + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(20))) .Times(0); - EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(30))) + EXPECT_CALL(mock_cb_, FrameReceived(HasTimestamp(30))) .WillOnce(RunClosure(event.GetClosure())); AdvanceTimeInMs(31); event.RunAndWait(); diff --git a/media/test/pipeline_integration_test_base.cc b/media/test/pipeline_integration_test_base.cc index c17431a..5217925 100644 --- a/media/test/pipeline_integration_test_base.cc +++ b/media/test/pipeline_integration_test_base.cc @@ -35,9 +35,6 @@ namespace media { const char kNullVideoHash[] = "d41d8cd98f00b204e9800998ecf8427e"; const char kNullAudioHash[] = "0.00,0.00,0.00,0.00,0.00,0.00,"; -MockVideoRendererSink::MockVideoRendererSink() {} -MockVideoRendererSink::~MockVideoRendererSink() {} - PipelineIntegrationTestBase::PipelineIntegrationTestBase() : hashing_enabled_(false), clockless_playback_(false), @@ -240,14 +237,17 @@ scoped_ptr<Renderer> PipelineIntegrationTestBase::CreateRenderer() { new FFmpegVideoDecoder(message_loop_.message_loop_proxy())); #endif - EXPECT_CALL(video_sink_, PaintFrameUsingOldRenderingPath(_)) - .WillRepeatedly( - Invoke(this, &PipelineIntegrationTestBase::OnVideoFramePaint)); + // Simulate a 60Hz rendering sink. + video_sink_.reset(new NullVideoSink( + clockless_playback_, base::TimeDelta::FromSecondsD(1.0 / 60), + base::Bind(&PipelineIntegrationTestBase::OnVideoFramePaint, + base::Unretained(this)), + message_loop_.task_runner())); // Disable frame dropping if hashing is enabled. - scoped_ptr<VideoRenderer> video_renderer( - new VideoRendererImpl(message_loop_.message_loop_proxy(), &video_sink_, - video_decoders.Pass(), false, new MediaLog())); + scoped_ptr<VideoRenderer> video_renderer(new VideoRendererImpl( + message_loop_.message_loop_proxy(), video_sink_.get(), + video_decoders.Pass(), false, new MediaLog())); if (!clockless_playback_) { audio_sink_ = new NullAudioSink(message_loop_.message_loop_proxy()); diff --git a/media/test/pipeline_integration_test_base.h b/media/test/pipeline_integration_test_base.h index aa41337..efbffea 100644 --- a/media/test/pipeline_integration_test_base.h +++ b/media/test/pipeline_integration_test_base.h @@ -12,6 +12,7 @@ #include "media/base/audio_hardware_config.h" #include "media/base/demuxer.h" #include "media/base/media_keys.h" +#include "media/base/null_video_sink.h" #include "media/base/pipeline.h" #include "media/base/text_track.h" #include "media/base/text_track_config.h" @@ -45,20 +46,6 @@ class DummyTickClock : public base::TickClock { base::TimeTicks now_; }; -// TODO(dalecurtis): Mocks won't be useful for the new rendering path, we'll -// need fake callback generators like we have for the audio path. -// http://crbug.com/473424 -class MockVideoRendererSink : public VideoRendererSink { - public: - MockVideoRendererSink(); - ~MockVideoRendererSink() override; - - MOCK_METHOD1(Start, void(VideoRendererSink::RenderCallback*)); - MOCK_METHOD0(Stop, void()); - MOCK_METHOD1(PaintFrameUsingOldRenderingPath, - void(const scoped_refptr<VideoFrame>&)); -}; - // Integration tests for Pipeline. Real demuxers, real decoders, and // base renderer implementations are used to verify pipeline functionality. The // renderers used in these tests rely heavily on the AudioRendererBase & @@ -119,7 +106,7 @@ class PipelineIntegrationTestBase { scoped_ptr<Pipeline> pipeline_; scoped_refptr<NullAudioSink> audio_sink_; scoped_refptr<ClocklessAudioSink> clockless_audio_sink_; - testing::NiceMock<MockVideoRendererSink> video_sink_; + scoped_ptr<NullVideoSink> video_sink_; bool ended_; PipelineStatus pipeline_status_; Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb_; |