Chromium Code Reviews| Index: media/blink/video_frame_compositor.cc |
| diff --git a/media/blink/video_frame_compositor.cc b/media/blink/video_frame_compositor.cc |
| index 90af145c7ed71fb269f1f35731f372d5756d9512..0c10f3ec66416f3f3dc8ce1372be6ac463551ca4 100644 |
| --- a/media/blink/video_frame_compositor.cc |
| +++ b/media/blink/video_frame_compositor.cc |
| @@ -6,10 +6,17 @@ |
| #include "base/bind.h" |
| #include "base/message_loop/message_loop.h" |
| +#include "base/time/default_tick_clock.h" |
| +#include "base/trace_event/trace_event.h" |
| #include "media/base/video_frame.h" |
| namespace media { |
| +// The maximum time we'll allow to elapse between Render() callbacks if there is |
| +// an external caller requesting frames via GetCurrentFrame(); i.e. there is a |
| +// canvas which frames are being copied into. |
| +static const int kStaleFrameThresholdMs = 250; |
|
xhwang
2015/04/29 22:42:03
s/static//
DaleCurtis
2015/04/30 03:49:37
Done.
|
| + |
| static bool IsOpaque(const scoped_refptr<VideoFrame>& frame) { |
| switch (frame->format()) { |
| case VideoFrame::UNKNOWN: |
| @@ -38,10 +45,14 @@ VideoFrameCompositor::VideoFrameCompositor( |
| const base::Callback<void(gfx::Size)>& natural_size_changed_cb, |
| const base::Callback<void(bool)>& opacity_changed_cb) |
| : compositor_task_runner_(compositor_task_runner), |
| + tick_clock_(new base::DefaultTickClock()), |
| natural_size_changed_cb_(natural_size_changed_cb), |
| opacity_changed_cb_(opacity_changed_cb), |
| client_(nullptr), |
| + stale_frame_threshold_( |
| + base::TimeDelta::FromMilliseconds(kStaleFrameThresholdMs)), |
| rendering_(false), |
| + rendered_last_frame_(false), |
| callback_(nullptr) { |
| } |
| @@ -53,27 +64,27 @@ VideoFrameCompositor::~VideoFrameCompositor() { |
| client_->StopUsingProvider(); |
| } |
| -void VideoFrameCompositor::OnRendererStateUpdate() { |
| +void VideoFrameCompositor::OnRendererStateUpdate(bool new_state) { |
| DCHECK(compositor_task_runner_->BelongsToCurrentThread()); |
| + DCHECK_NE(rendering_, new_state); |
| + rendering_ = new_state; |
| + |
| if (!client_) |
| return; |
| - base::AutoLock lock(lock_); |
| - if (callback_) { |
| - if (rendering_) |
| - client_->StartRendering(); |
| - |
| - // TODO(dalecurtis): This will need to request the first frame so we have |
| - // something to show, even if playback hasn't started yet. |
| - } else if (rendering_) { |
| + if (rendering_) |
| + client_->StartRendering(); |
| + else |
| client_->StopRendering(); |
| - } |
| } |
| scoped_refptr<VideoFrame> |
| VideoFrameCompositor::GetCurrentFrameAndUpdateIfStale() { |
| - // TODO(dalecurtis): Implement frame refresh when stale. |
| DCHECK(compositor_task_runner_->BelongsToCurrentThread()); |
| + const base::TimeTicks now = tick_clock_->NowTicks(); |
| + if (now - last_frame_update_time_ > stale_frame_threshold_) |
| + UpdateCurrentFrame(now, now + last_interval_); |
| + |
| return GetCurrentFrame(); |
| } |
| @@ -83,7 +94,9 @@ void VideoFrameCompositor::SetVideoFrameProviderClient( |
| if (client_) |
| client_->StopUsingProvider(); |
| client_ = client; |
| - OnRendererStateUpdate(); |
| + |
| + if (rendering_) |
| + client_->StartRendering(); |
| } |
| scoped_refptr<VideoFrame> VideoFrameCompositor::GetCurrentFrame() { |
| @@ -93,41 +106,80 @@ scoped_refptr<VideoFrame> VideoFrameCompositor::GetCurrentFrame() { |
| void VideoFrameCompositor::PutCurrentFrame() { |
| DCHECK(compositor_task_runner_->BelongsToCurrentThread()); |
| - // TODO(dalecurtis): Wire up a flag for RenderCallback::OnFrameDropped(). |
| + rendered_last_frame_ = true; |
| } |
| bool VideoFrameCompositor::UpdateCurrentFrame(base::TimeTicks deadline_min, |
| base::TimeTicks deadline_max) { |
| - // TODO(dalecurtis): Wire this up to RenderCallback::Render(). |
| + DCHECK(compositor_task_runner_->BelongsToCurrentThread()); |
| base::AutoLock lock(lock_); |
| - return false; |
| + if (!callback_) |
| + return false; |
| + |
| + DCHECK(rendering_); |
| + |
| + // If the previous frame was never rendered, let the client know. |
| + if (!rendered_last_frame_ && current_frame_) |
| + callback_->OnFrameDropped(); |
| + |
| + last_frame_update_time_ = tick_clock_->NowTicks(); |
| + last_interval_ = deadline_max - deadline_min; |
|
xhwang
2015/04/29 22:42:03
We use |last| for most member variables here, but
DaleCurtis
2015/04/30 03:49:37
Yeah it does seem odd, but I think it matches the
|
| + scoped_refptr<VideoFrame> frame = |
| + callback_->Render(deadline_min, deadline_max); |
| + |
| + // Do nothing if the current frame has already been rendered. |
| + if (current_frame_ == frame) |
| + return false; |
| + |
| + // Set the flag indicating that the current frame is unrendered, if we get a |
| + // subsequent PutCurrentFrame() call it will mark it as rendered. |
| + rendered_last_frame_ = false; |
| + |
| + if (current_frame_.get() && |
| + current_frame_->natural_size() != frame->natural_size()) { |
| + natural_size_changed_cb_.Run(frame->natural_size()); |
| + } |
| + |
| + if (!current_frame_.get() || IsOpaque(current_frame_) != IsOpaque(frame)) { |
| + opacity_changed_cb_.Run(IsOpaque(frame)); |
| + } |
| + |
| + current_frame_ = frame; |
| + return true; |
| } |
| void VideoFrameCompositor::Start(RenderCallback* callback) { |
| - NOTREACHED(); |
| - |
| + TRACE_EVENT0("media", "VideoFrameCompositor::Start"); |
| // Called from the media thread, so acquire the callback under lock before |
| // returning in case a Stop() call comes in before the PostTask is processed. |
| base::AutoLock lock(lock_); |
| + DCHECK(!callback_); |
| + |
| + // Don't clear |current_frame_| as we won't be able to recover from damage to |
| + // the video display area if an UpdateCurrentFrame() call doesn't come in |
| + // before Stop() is called again. |
| + |
| callback_ = callback; |
| - rendering_ = true; |
| compositor_task_runner_->PostTask( |
| FROM_HERE, base::Bind(&VideoFrameCompositor::OnRendererStateUpdate, |
| - base::Unretained(this))); |
| + base::Unretained(this), true)); |
| } |
| void VideoFrameCompositor::Stop() { |
| - NOTREACHED(); |
| - |
| + TRACE_EVENT0("media", "VideoFrameCompositor::Stop"); |
|
xhwang
2015/04/29 22:42:03
nit: TRACE_EVENT0("media", __FUCNTION__) if you pr
DaleCurtis
2015/04/30 03:49:37
Done.
|
| // Called from the media thread, so release the callback under lock before |
| // returning to avoid a pending UpdateCurrentFrame() call occurring before |
| // the PostTask is processed. |
| base::AutoLock lock(lock_); |
| + DCHECK(callback_); |
| + |
| + // Don't clear |current_frame_| as we won't be able to recover from damage to |
| + // the video display area. |
| + |
| callback_ = nullptr; |
| - rendering_ = false; |
| compositor_task_runner_->PostTask( |
| FROM_HERE, base::Bind(&VideoFrameCompositor::OnRendererStateUpdate, |
| - base::Unretained(this))); |
| + base::Unretained(this), false)); |
| } |
| void VideoFrameCompositor::PaintFrameUsingOldRenderingPath( |