diff options
author | dalecurtis <dalecurtis@chromium.org> | 2015-04-15 14:14:40 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-04-15 21:15:25 +0000 |
commit | 45a3c93f745eabf6c1b1cbdac87ed4350a919e76 (patch) | |
tree | 719f8b62792e5e4f59d8bf9fa45eba3327ebcd98 /media/renderers | |
parent | 7ed1f876f6f4d79ac074b25f2066d514603aa18d (diff) | |
download | chromium_src-45a3c93f745eabf6c1b1cbdac87ed4350a919e76.zip chromium_src-45a3c93f745eabf6c1b1cbdac87ed4350a919e76.tar.gz chromium_src-45a3c93f745eabf6c1b1cbdac87ed4350a919e76.tar.bz2 |
Prime the landing pad for the new video rendering pipeline.
This is not a functional change, it only updates the interfaces and
call sites in preparation for switching to a vsync based video
rendering pipeline.
Some notes:
- Plumbs a VideoRendererSink into the the rendering pipeline; similar to
how we have an AudioRendererSink.
- A couple VideoRendererSink mocks are introduced which will be short
lived. Like audio, we will need fakes which can pump consumption tasks.
- The "PaintCB" callback has been temporarily placed on the new sink
interface such that in the field experiments can be run comparing the
performance of the video rendering approaches.
- Finally nukes Player_X11 since setting up a vsync renderer just for
unused tool code isn't worth the effort.
- Since compositor callbacks may stop due to visibility changes, the
new VideoRendererImpl will use a countdown timer to pump video playback
as frames expire; expired frames will not count as dropped.
- Since canvas/WebGL requires frame updates in the background a new
method has been added to VideoFrameCompositor to return the current
frame if it was updated with 250ms, or to request a new one and return
the updated one.
Subsequent work:
- sunnyps@ will be switching VideoFrameProviderClientImpl over to using
a BeginFrameObserver, which will ultimately drive the Render() callbacks.
- dalecurtis@ will land the VideoRendererAlgorithm which powers the new
rendering pipeline.
BUG=439548
TEST=everything works as is.
Review URL: https://codereview.chromium.org/1053113002
Cr-Commit-Position: refs/heads/master@{#325306}
Diffstat (limited to 'media/renderers')
-rw-r--r-- | media/renderers/default_renderer_factory.cc | 8 | ||||
-rw-r--r-- | media/renderers/default_renderer_factory.h | 4 | ||||
-rw-r--r-- | media/renderers/renderer_impl.cc | 4 | ||||
-rw-r--r-- | media/renderers/renderer_impl.h | 2 | ||||
-rw-r--r-- | media/renderers/renderer_impl_unittest.cc | 11 | ||||
-rw-r--r-- | media/renderers/video_renderer_impl.cc | 20 | ||||
-rw-r--r-- | media/renderers/video_renderer_impl.h | 11 | ||||
-rw-r--r-- | media/renderers/video_renderer_impl_unittest.cc | 45 |
8 files changed, 66 insertions, 39 deletions
diff --git a/media/renderers/default_renderer_factory.cc b/media/renderers/default_renderer_factory.cc index 81162d3..0ec129a 100644 --- a/media/renderers/default_renderer_factory.cc +++ b/media/renderers/default_renderer_factory.cc @@ -38,7 +38,8 @@ DefaultRendererFactory::~DefaultRendererFactory() { // TODO(xhwang): Use RendererConfig to customize what decoders we use. scoped_ptr<Renderer> DefaultRendererFactory::CreateRenderer( const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, - AudioRendererSink* audio_renderer_sink) { + AudioRendererSink* audio_renderer_sink, + VideoRendererSink* video_renderer_sink) { DCHECK(audio_renderer_sink); // Create our audio decoders and renderer. @@ -75,8 +76,9 @@ scoped_ptr<Renderer> DefaultRendererFactory::CreateRenderer( video_decoders.push_back(new FFmpegVideoDecoder(media_task_runner)); #endif - scoped_ptr<VideoRenderer> video_renderer(new VideoRendererImpl( - media_task_runner, video_decoders.Pass(), true, media_log_)); + scoped_ptr<VideoRenderer> video_renderer( + new VideoRendererImpl(media_task_runner, video_renderer_sink, + video_decoders.Pass(), true, media_log_)); // Create renderer. return scoped_ptr<Renderer>(new RendererImpl( diff --git a/media/renderers/default_renderer_factory.h b/media/renderers/default_renderer_factory.h index 0827992..05cf2b1 100644 --- a/media/renderers/default_renderer_factory.h +++ b/media/renderers/default_renderer_factory.h @@ -15,6 +15,7 @@ class AudioHardwareConfig; class AudioRendererSink; class GpuVideoAcceleratorFactories; class MediaLog; +class VideoRendererSink; // The default factory class for creating RendererImpl. class MEDIA_EXPORT DefaultRendererFactory : public RendererFactory { @@ -27,7 +28,8 @@ class MEDIA_EXPORT DefaultRendererFactory : public RendererFactory { scoped_ptr<Renderer> CreateRenderer( const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, - AudioRendererSink* audio_renderer_sink) final; + AudioRendererSink* audio_renderer_sink, + VideoRendererSink* video_renderer_sink) final; private: scoped_refptr<MediaLog> media_log_; diff --git a/media/renderers/renderer_impl.cc b/media/renderers/renderer_impl.cc index ac80216..62caf9d 100644 --- a/media/renderers/renderer_impl.cc +++ b/media/renderers/renderer_impl.cc @@ -81,7 +81,6 @@ void RendererImpl::Initialize( const PipelineStatusCB& init_cb, const StatisticsCB& statistics_cb, const BufferingStateCB& buffering_state_cb, - const PaintCB& paint_cb, const base::Closure& ended_cb, const PipelineStatusCB& error_cb, const base::Closure& waiting_for_decryption_key_cb) { @@ -91,7 +90,6 @@ void RendererImpl::Initialize( DCHECK(!init_cb.is_null()); DCHECK(!statistics_cb.is_null()); DCHECK(!buffering_state_cb.is_null()); - DCHECK(!paint_cb.is_null()); DCHECK(!ended_cb.is_null()); DCHECK(!error_cb.is_null()); DCHECK(demuxer_stream_provider->GetStream(DemuxerStream::AUDIO) || @@ -100,7 +98,6 @@ void RendererImpl::Initialize( demuxer_stream_provider_ = demuxer_stream_provider; statistics_cb_ = statistics_cb; buffering_state_cb_ = buffering_state_cb; - paint_cb_ = paint_cb; ended_cb_ = ended_cb; error_cb_ = error_cb; init_cb_ = init_cb; @@ -337,7 +334,6 @@ void RendererImpl::InitializeVideoRenderer() { base::Bind(&RendererImpl::OnUpdateStatistics, weak_this_), base::Bind(&RendererImpl::OnBufferingStateChanged, weak_this_, &video_buffering_state_), - base::ResetAndReturn(&paint_cb_), base::Bind(&RendererImpl::OnVideoRendererEnded, weak_this_), base::Bind(&RendererImpl::OnError, weak_this_), base::Bind(&RendererImpl::GetWallClockTime, base::Unretained(this)), diff --git a/media/renderers/renderer_impl.h b/media/renderers/renderer_impl.h index feb6920..3f90271 100644 --- a/media/renderers/renderer_impl.h +++ b/media/renderers/renderer_impl.h @@ -48,7 +48,6 @@ class MEDIA_EXPORT RendererImpl : public Renderer { const PipelineStatusCB& init_cb, const StatisticsCB& statistics_cb, const BufferingStateCB& buffering_state_cb, - const PaintCB& paint_cb, const base::Closure& ended_cb, const PipelineStatusCB& error_cb, const base::Closure& waiting_for_decryption_key_cb) final; @@ -140,7 +139,6 @@ class MEDIA_EXPORT RendererImpl : public Renderer { base::Closure ended_cb_; PipelineStatusCB error_cb_; BufferingStateCB buffering_state_cb_; - PaintCB paint_cb_; base::Closure waiting_for_decryption_key_cb_; // Temporary callback used for Initialize() and Flush(). diff --git a/media/renderers/renderer_impl_unittest.cc b/media/renderers/renderer_impl_unittest.cc index 75fc050..9fcefe4 100644 --- a/media/renderers/renderer_impl_unittest.cc +++ b/media/renderers/renderer_impl_unittest.cc @@ -49,7 +49,6 @@ class RendererImplTest : public ::testing::Test { MOCK_METHOD1(OnError, void(PipelineStatus)); MOCK_METHOD1(OnUpdateStatistics, void(const PipelineStatistics&)); MOCK_METHOD1(OnBufferingStateChange, void(BufferingState)); - MOCK_METHOD1(OnVideoFramePaint, void(const scoped_refptr<VideoFrame>&)); MOCK_METHOD0(OnWaitingForDecryptionKey, void()); private: @@ -98,9 +97,9 @@ class RendererImplTest : public ::testing::Test { // Sets up expectations to allow the video renderer to initialize. void SetVideoRendererInitializeExpectations(PipelineStatus status) { EXPECT_CALL(*video_renderer_, - Initialize(video_stream_.get(), _, _, _, _, _, _, _, _, _)) + Initialize(video_stream_.get(), _, _, _, _, _, _, _, _)) .WillOnce(DoAll(SaveArg<4>(&video_buffering_state_cb_), - SaveArg<6>(&video_ended_cb_), RunCallback<1>(status))); + SaveArg<5>(&video_ended_cb_), RunCallback<1>(status))); } void InitializeAndExpect(PipelineStatus start_status) { @@ -122,8 +121,6 @@ class RendererImplTest : public ::testing::Test { base::Unretained(&callbacks_)), base::Bind(&CallbackHelper::OnBufferingStateChange, base::Unretained(&callbacks_)), - base::Bind(&CallbackHelper::OnVideoFramePaint, - base::Unretained(&callbacks_)), base::Bind(&CallbackHelper::OnEnded, base::Unretained(&callbacks_)), base::Bind(&CallbackHelper::OnError, base::Unretained(&callbacks_)), base::Bind(&CallbackHelper::OnWaitingForDecryptionKey, @@ -475,10 +472,10 @@ TEST_F(RendererImplTest, ErrorDuringInitialize) { // Force an audio error to occur during video renderer initialization. EXPECT_CALL(*video_renderer_, - Initialize(video_stream_.get(), _, _, _, _, _, _, _, _, _)) + Initialize(video_stream_.get(), _, _, _, _, _, _, _, _)) .WillOnce(DoAll(AudioError(&audio_error_cb_, PIPELINE_ERROR_DECODE), SaveArg<4>(&video_buffering_state_cb_), - SaveArg<6>(&video_ended_cb_), + SaveArg<5>(&video_ended_cb_), RunCallback<1>(PIPELINE_OK))); InitializeAndExpect(PIPELINE_ERROR_DECODE); diff --git a/media/renderers/video_renderer_impl.cc b/media/renderers/video_renderer_impl.cc index 627ada6..3e0698f 100644 --- a/media/renderers/video_renderer_impl.cc +++ b/media/renderers/video_renderer_impl.cc @@ -22,10 +22,12 @@ namespace media { VideoRendererImpl::VideoRendererImpl( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, + VideoRendererSink* sink, ScopedVector<VideoDecoder> decoders, bool drop_frames, const scoped_refptr<MediaLog>& media_log) : task_runner_(task_runner), + sink_(sink), video_frame_stream_( new VideoFrameStream(task_runner, decoders.Pass(), media_log)), low_delay_(false), @@ -106,7 +108,6 @@ void VideoRendererImpl::Initialize( const SetDecryptorReadyCB& set_decryptor_ready_cb, const StatisticsCB& statistics_cb, const BufferingStateCB& buffering_state_cb, - const PaintCB& paint_cb, const base::Closure& ended_cb, const PipelineStatusCB& error_cb, const WallClockTimeCB& wall_clock_time_cb, @@ -118,7 +119,6 @@ void VideoRendererImpl::Initialize( DCHECK(!init_cb.is_null()); DCHECK(!statistics_cb.is_null()); DCHECK(!buffering_state_cb.is_null()); - DCHECK(!paint_cb.is_null()); DCHECK(!ended_cb.is_null()); DCHECK(!wall_clock_time_cb.is_null()); DCHECK_EQ(kUninitialized, state_); @@ -131,7 +131,8 @@ void VideoRendererImpl::Initialize( statistics_cb_ = statistics_cb; buffering_state_cb_ = buffering_state_cb; - paint_cb_ = paint_cb, + paint_cb_ = base::Bind(&VideoRendererSink::PaintFrameUsingOldRenderingPath, + base::Unretained(sink_)); ended_cb_ = ended_cb; error_cb_ = error_cb; wall_clock_time_cb_ = wall_clock_time_cb; @@ -143,6 +144,19 @@ void VideoRendererImpl::Initialize( set_decryptor_ready_cb, statistics_cb, waiting_for_decryption_key_cb); } +scoped_refptr<VideoFrame> VideoRendererImpl::Render( + base::TimeTicks deadline_min, + base::TimeTicks deadline_max) { + // TODO(dalecurtis): Hook this up to the new VideoRendererAlgorithm. + NOTIMPLEMENTED(); + return nullptr; +} + +void VideoRendererImpl::OnFrameDropped() { + // TODO(dalecurtis): Hook this up to the new VideoRendererAlgorithm. + NOTIMPLEMENTED(); +} + void VideoRendererImpl::CreateVideoThread() { // This may fail and cause a crash if there are too many threads created in // the current process. See http://crbug.com/443291 diff --git a/media/renderers/video_renderer_impl.h b/media/renderers/video_renderer_impl.h index 33938dc..7eb9814 100644 --- a/media/renderers/video_renderer_impl.h +++ b/media/renderers/video_renderer_impl.h @@ -21,6 +21,7 @@ #include "media/base/video_decoder.h" #include "media/base/video_frame.h" #include "media/base/video_renderer.h" +#include "media/base/video_renderer_sink.h" #include "media/filters/decoder_stream.h" namespace base { @@ -36,6 +37,7 @@ namespace media { // ready for rendering. class MEDIA_EXPORT VideoRendererImpl : public VideoRenderer, + public NON_EXPORTED_BASE(VideoRendererSink::RenderCallback), public base::PlatformThread::Delegate { public: // |decoders| contains the VideoDecoders to use when initializing. @@ -47,6 +49,7 @@ class MEDIA_EXPORT VideoRendererImpl // Setting |drop_frames_| to true causes the renderer to drop expired frames. VideoRendererImpl( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, + VideoRendererSink* sink, ScopedVector<VideoDecoder> decoders, bool drop_frames, const scoped_refptr<MediaLog>& media_log); @@ -58,7 +61,6 @@ class MEDIA_EXPORT VideoRendererImpl const SetDecryptorReadyCB& set_decryptor_ready_cb, const StatisticsCB& statistics_cb, const BufferingStateCB& buffering_state_cb, - const PaintCB& paint_cb, const base::Closure& ended_cb, const PipelineStatusCB& error_cb, const WallClockTimeCB& wall_clock_time_cb, @@ -72,6 +74,11 @@ class MEDIA_EXPORT VideoRendererImpl void SetTickClockForTesting(scoped_ptr<base::TickClock> tick_clock); + // VideoRendererSink::RenderCallback implementation. + scoped_refptr<VideoFrame> Render(base::TimeTicks deadline_min, + base::TimeTicks deadline_max) override; + void OnFrameDropped() override; + private: // Creates a dedicated |thread_| for video rendering. void CreateVideoThread(); @@ -118,6 +125,8 @@ class MEDIA_EXPORT VideoRendererImpl scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + VideoRendererSink* const sink_; + // Used for accessing data members. base::Lock lock_; diff --git a/media/renderers/video_renderer_impl_unittest.cc b/media/renderers/video_renderer_impl_unittest.cc index df5c9d3..86f767f 100644 --- a/media/renderers/video_renderer_impl_unittest.cc +++ b/media/renderers/video_renderer_impl_unittest.cc @@ -54,6 +54,7 @@ class VideoRendererImplTest : public ::testing::Test { decoders.push_back(decoder_); renderer_.reset(new VideoRendererImpl(message_loop_.message_loop_proxy(), + &mock_cb_, decoders.Pass(), true, new MediaLog())); renderer_->SetTickClockForTesting(scoped_ptr<base::TickClock>(tick_clock_)); @@ -108,7 +109,6 @@ class VideoRendererImplTest : public ::testing::Test { base::Unretained(this)), base::Bind(&StrictMock<MockCB>::BufferingStateChange, base::Unretained(&mock_cb_)), - base::Bind(&StrictMock<MockCB>::Display, base::Unretained(&mock_cb_)), ended_event_.GetClosure(), error_event_.GetPipelineStatusCB(), base::Bind(&VideoRendererImplTest::GetWallClockTime, base::Unretained(this)), @@ -265,9 +265,15 @@ class VideoRendererImplTest : public ::testing::Test { NiceMock<MockDemuxerStream> demuxer_stream_; // Use StrictMock<T> to catch missing/extra callbacks. - class MockCB { + // 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 { public: - MOCK_METHOD1(Display, void(const scoped_refptr<VideoFrame>&)); + MOCK_METHOD1(Start, void(VideoRendererSink::RenderCallback*)); + MOCK_METHOD0(Stop, void()); + MOCK_METHOD1(PaintFrameUsingOldRenderingPath, + void(const scoped_refptr<VideoFrame>&)); MOCK_METHOD1(BufferingStateChange, void(BufferingState)); }; StrictMock<MockCB> mock_cb_; @@ -349,7 +355,7 @@ TEST_F(VideoRendererImplTest, Initialize) { TEST_F(VideoRendererImplTest, InitializeAndStartPlayingFrom) { Initialize(); QueueFrames("0 10 20 30"); - EXPECT_CALL(mock_cb_, Display(HasTimestamp(0))); + EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(0))); EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); StartPlayingFrom(0); Destroy(); @@ -363,7 +369,7 @@ TEST_F(VideoRendererImplTest, DestroyWhileInitializing) { TEST_F(VideoRendererImplTest, DestroyWhileFlushing) { Initialize(); QueueFrames("0 10 20 30"); - EXPECT_CALL(mock_cb_, Display(HasTimestamp(0))); + EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(0))); EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); StartPlayingFrom(0); EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING)); @@ -374,7 +380,7 @@ TEST_F(VideoRendererImplTest, DestroyWhileFlushing) { TEST_F(VideoRendererImplTest, Play) { Initialize(); QueueFrames("0 10 20 30"); - EXPECT_CALL(mock_cb_, Display(HasTimestamp(0))); + EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(0))); EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); StartPlayingFrom(0); Destroy(); @@ -393,7 +399,7 @@ TEST_F(VideoRendererImplTest, FlushWithNothingBuffered) { TEST_F(VideoRendererImplTest, DecodeError_Playing) { Initialize(); QueueFrames("0 10 20 30"); - EXPECT_CALL(mock_cb_, Display(HasTimestamp(0))); + EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(0))); EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); StartPlayingFrom(0); @@ -414,7 +420,7 @@ TEST_F(VideoRendererImplTest, StartPlayingFrom_Exact) { Initialize(); QueueFrames("50 60 70 80 90"); - EXPECT_CALL(mock_cb_, Display(HasTimestamp(60))); + EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(60))); EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); StartPlayingFrom(60); Destroy(); @@ -424,7 +430,7 @@ TEST_F(VideoRendererImplTest, StartPlayingFrom_RightBefore) { Initialize(); QueueFrames("50 60 70 80 90"); - EXPECT_CALL(mock_cb_, Display(HasTimestamp(50))); + EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(50))); EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); StartPlayingFrom(59); Destroy(); @@ -434,7 +440,7 @@ TEST_F(VideoRendererImplTest, StartPlayingFrom_RightAfter) { Initialize(); QueueFrames("50 60 70 80 90"); - EXPECT_CALL(mock_cb_, Display(HasTimestamp(60))); + EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(60))); EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); StartPlayingFrom(61); Destroy(); @@ -446,7 +452,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_, Display(HasTimestamp(0))); + EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(0))); EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)) .Times(AnyNumber()); EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING)) @@ -457,7 +463,7 @@ TEST_F(VideoRendererImplTest, StartPlayingFrom_LowDelay) { SatisfyPendingRead(); WaitableMessageLoopEvent event; - EXPECT_CALL(mock_cb_, Display(HasTimestamp(10))) + EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(10))) .WillOnce(RunClosure(event.GetClosure())); AdvanceTimeInMs(10); event.RunAndWait(); @@ -469,7 +475,7 @@ TEST_F(VideoRendererImplTest, StartPlayingFrom_LowDelay) { TEST_F(VideoRendererImplTest, DestroyDuringOutstandingRead) { Initialize(); QueueFrames("0 10 20 30"); - EXPECT_CALL(mock_cb_, Display(HasTimestamp(0))); + EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(0))); EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)); StartPlayingFrom(0); @@ -490,7 +496,7 @@ TEST_F(VideoRendererImplTest, Underflow) { { WaitableMessageLoopEvent event; - EXPECT_CALL(mock_cb_, Display(HasTimestamp(0))); + EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(0))); EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH)) .WillOnce(RunClosure(event.GetClosure())); StartPlayingFrom(0); @@ -503,16 +509,19 @@ TEST_F(VideoRendererImplTest, Underflow) { { SCOPED_TRACE("Waiting for frame drops"); WaitableMessageLoopEvent event; - EXPECT_CALL(mock_cb_, Display(HasTimestamp(10))).Times(0); - EXPECT_CALL(mock_cb_, Display(HasTimestamp(20))).Times(0); - EXPECT_CALL(mock_cb_, Display(HasTimestamp(30))) + EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(10))) + .Times(0); + EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(20))) + .Times(0); + EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(30))) .WillOnce(RunClosure(event.GetClosure())); AdvanceTimeInMs(31); event.RunAndWait(); Mock::VerifyAndClearExpectations(&mock_cb_); } - // Advance time more, such that a new frame should have been displayed by now. + // 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; |