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( |