Chromium Code Reviews| Index: content/common/gpu/media/rendering_helper.cc |
| diff --git a/content/common/gpu/media/rendering_helper.cc b/content/common/gpu/media/rendering_helper.cc |
| index 6693f5f07dd5a2cb2b983ea5d289d1a1dc7b835c..618fdc91e5031911de683c982cdb19caeb15cdf8 100644 |
| --- a/content/common/gpu/media/rendering_helper.cc |
| +++ b/content/common/gpu/media/rendering_helper.cc |
| @@ -76,7 +76,7 @@ VideoFrameTexture::~VideoFrameTexture() { |
| } |
| RenderingHelper::RenderedVideo::RenderedVideo() |
| - : last_frame_rendered(false), is_flushing(false), frames_to_drop(0) { |
| + : is_flushing(false), frames_to_drop(0) { |
| } |
| RenderingHelper::RenderedVideo::~RenderedVideo() { |
| @@ -302,7 +302,8 @@ void RenderingHelper::Initialize(const RenderingHelperParams& params, |
| glEnableVertexAttribArray(tc_location); |
| glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, kTextureCoords); |
| - done->Signal(); |
| + gl_surface_->GetVSyncProvider()->GetVSyncParameters(base::Bind( |
| + &RenderingHelper::UpdateVSyncParameters, base::Unretained(this), done)); |
|
piman
2014/10/16 21:13:29
Can you document why Unretained is safe?
Owen Lin
2014/10/20 08:48:42
Done.
|
| } |
| void RenderingHelper::UnInitialize(base::WaitableEvent* done) { |
| @@ -396,28 +397,18 @@ void RenderingHelper::QueueVideoFrame( |
| RenderedVideo* video = &videos_[window_id]; |
| DCHECK(!video->is_flushing); |
| - // Start the rendering task when getting the first frame. |
| - if (scheduled_render_time_.is_null() && |
| - (frame_duration_ != base::TimeDelta())) { |
| - scheduled_render_time_ = base::TimeTicks::Now(); |
| - message_loop_->PostTask(FROM_HERE, render_task_.callback()); |
| - } |
| + video->pending_frames.push(video_frame); |
| - if (video->frames_to_drop > 0) { |
| + if (video->frames_to_drop > 0 && video->pending_frames.size() > 1) { |
| --video->frames_to_drop; |
| - return; |
| - } |
| - |
| - // Pop the last frame if it has been rendered. |
| - if (video->last_frame_rendered) { |
| - // When last_frame_rendered is true, we should have only one pending frame. |
| - // Since we are going to have a new frame, we can release the pending one. |
| - DCHECK(video->pending_frames.size() == 1); |
| video->pending_frames.pop(); |
| - video->last_frame_rendered = false; |
| } |
| - video->pending_frames.push(video_frame); |
| + // Schedules the first RenderContent() if need. |
| + if (scheduled_render_time_.is_null()) { |
| + scheduled_render_time_ = base::TimeTicks::Now(); |
| + message_loop_->PostTask(FROM_HERE, render_task_.callback()); |
| + } |
| } |
| void RenderingHelper::RenderTexture(uint32 texture_target, uint32 texture_id) { |
| @@ -515,10 +506,11 @@ void RenderingHelper::Flush(size_t window_id) { |
| void RenderingHelper::RenderContent() { |
| CHECK_EQ(base::MessageLoop::current(), message_loop_); |
| - scheduled_render_time_ += frame_duration_; |
| - base::TimeDelta delay = scheduled_render_time_ - base::TimeTicks::Now(); |
| - message_loop_->PostDelayedTask( |
| - FROM_HERE, render_task_.callback(), std::max(delay, base::TimeDelta())); |
| + // Update the VSync params. |
| + gl_surface_->GetVSyncProvider()->GetVSyncParameters( |
| + base::Bind(&RenderingHelper::UpdateVSyncParameters, |
| + base::Unretained(this), |
|
piman
2014/10/16 21:13:28
Can you document why Unretained is safe?
Owen Lin
2014/10/20 08:48:42
Done.
|
| + static_cast<base::WaitableEvent*>(NULL))); |
| glUniform1i(glGetUniformLocation(program_, "tex_flip"), 1); |
| @@ -526,35 +518,36 @@ void RenderingHelper::RenderContent() { |
| // after this vector falls out of scope at the end of this method. We need |
| // to keep references to them until after SwapBuffers() call below. |
| std::vector<scoped_refptr<VideoFrameTexture> > frames_to_be_returned; |
| - |
| + bool need_swap_buffer = false; |
| if (render_as_thumbnails_) { |
| // In render_as_thumbnails_ mode, we render the FBO content on the |
| // screen instead of the decoded textures. |
| GLSetViewPort(videos_[0].render_area); |
| RenderTexture(GL_TEXTURE_2D, thumbnails_texture_id_); |
| + need_swap_buffer = true; |
| } else { |
| for (size_t i = 0; i < videos_.size(); ++i) { |
| RenderedVideo* video = &videos_[i]; |
| if (video->pending_frames.empty()) |
| continue; |
| + need_swap_buffer = true; |
| scoped_refptr<VideoFrameTexture> frame = video->pending_frames.front(); |
| GLSetViewPort(video->render_area); |
| RenderTexture(frame->texture_target(), frame->texture_id()); |
| - if (video->last_frame_rendered) |
| - ++video->frames_to_drop; |
| - |
| if (video->pending_frames.size() > 1 || video->is_flushing) { |
| frames_to_be_returned.push_back(video->pending_frames.front()); |
| video->pending_frames.pop(); |
| - video->last_frame_rendered = false; |
| } else { |
| - video->last_frame_rendered = true; |
| + ++video->frames_to_drop; |
| } |
| } |
| } |
| - gl_surface_->SwapBuffers(); |
| + if (need_swap_buffer) |
| + gl_surface_->SwapBuffers(); |
| + |
| + ScheduleNextRenderContent(); |
| } |
| // Helper function for the LayoutRenderingAreas(). The |lengths| are the |
| @@ -610,4 +603,50 @@ void RenderingHelper::LayoutRenderingAreas( |
| videos_[i].render_area = gfx::Rect(x, y, w, h); |
| } |
| } |
| + |
| +void RenderingHelper::UpdateVSyncParameters(base::WaitableEvent* done, |
| + const base::TimeTicks timebase, |
| + const base::TimeDelta interval) { |
| + vsync_timebase_ = timebase; |
| + vsync_interval_ = interval; |
| + |
| + if (done) |
| + done->Signal(); |
| +} |
| + |
| +void RenderingHelper::DropOneFrameForAllVideos() { |
| + for (size_t i = 0; i < videos_.size(); ++i) { |
| + RenderedVideo* video = &videos_[i]; |
|
piman
2014/10/16 21:13:28
nit: for (RenderedVideo& video : videos_) {
Owen Lin
2014/10/20 08:48:42
Done. Thanks
|
| + if (video->pending_frames.empty()) |
| + continue; |
| + |
| + if (video->pending_frames.size() > 1 || video->is_flushing) { |
| + video->pending_frames.pop(); |
| + } else { |
| + ++video->frames_to_drop; |
| + } |
| + } |
| +} |
| + |
| +void RenderingHelper::ScheduleNextRenderContent() { |
| + scheduled_render_time_ += frame_duration_; |
| + |
| + // Schedules the next RenderContent() at latest VSYNC before the |
| + // |scheuled_render_time_|. |
|
piman
2014/10/16 21:13:28
nit: typo scheduled_render_time_
Owen Lin
2014/10/20 08:48:42
Done.
|
| + base::TimeTicks now = base::TimeTicks::Now(); |
| + base::TimeTicks target = |
| + std::max(now, scheduled_render_time_ - vsync_interval_); |
| + |
| + while (vsync_timebase_ < target) |
| + vsync_timebase_ += vsync_interval_; |
|
piman
2014/10/16 21:13:28
vsync_timebase_ may not be close to the current ti
Owen Lin
2014/10/20 08:48:42
Thanks.
|
| + |
| + // When the rendering falls behind, drops frames. |
| + while (scheduled_render_time_ < vsync_timebase_) { |
| + scheduled_render_time_ += frame_duration_; |
| + DropOneFrameForAllVideos(); |
| + } |
| + |
| + message_loop_->PostDelayedTask( |
| + FROM_HERE, render_task_.callback(), vsync_timebase_ - now); |
| +} |
| } // namespace content |