| 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..a5b23dfec88fe5b2f7e781ae8adbd043f961d2b0 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;
|
| +
|
| 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,7 +64,7 @@ VideoFrameCompositor::~VideoFrameCompositor() {
|
| client_->StopUsingProvider();
|
| }
|
|
|
| -void VideoFrameCompositor::OnRendererStateUpdate() {
|
| +void VideoFrameCompositor::OnRendererStateUpdate(bool stop_if_not_rendering) {
|
| DCHECK(compositor_task_runner_->BelongsToCurrentThread());
|
| if (!client_)
|
| return;
|
| @@ -62,18 +73,18 @@ void VideoFrameCompositor::OnRendererStateUpdate() {
|
| 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_) {
|
| + } else if (!rendering_ && stop_if_not_rendering) {
|
| 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,7 @@ void VideoFrameCompositor::SetVideoFrameProviderClient(
|
| if (client_)
|
| client_->StopUsingProvider();
|
| client_ = client;
|
| - OnRendererStateUpdate();
|
| + OnRendererStateUpdate(false);
|
| }
|
|
|
| scoped_refptr<VideoFrame> VideoFrameCompositor::GetCurrentFrame() {
|
| @@ -93,41 +104,77 @@ 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;
|
| +
|
| + // 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;
|
| + 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(!rendering_);
|
| + DCHECK(!callback_);
|
| +
|
| callback_ = callback;
|
| rendering_ = true;
|
| + current_frame_ = nullptr;
|
| 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");
|
| // 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(rendering_);
|
| + DCHECK(callback_);
|
| +
|
| callback_ = nullptr;
|
| rendering_ = false;
|
| + current_frame_ = nullptr;
|
| compositor_task_runner_->PostTask(
|
| FROM_HERE, base::Bind(&VideoFrameCompositor::OnRendererStateUpdate,
|
| - base::Unretained(this)));
|
| + base::Unretained(this), true));
|
| }
|
|
|
| void VideoFrameCompositor::PaintFrameUsingOldRenderingPath(
|
|
|