Commit cba851a9 authored by Thomas Guilbert's avatar Thomas Guilbert Committed by Commit Bot

Add OnFramePresentedCB to VideoFrameCompositor

This CL adds a new callback to VideoFrameCompositor. A client can now
set a callback, to be notified whenever a new frame has been presented
for composition.

This will be used to ultimately fulfill callbacks registered through the
new <video>.requestAnimationFrame API.

Bug: 1012063
Change-Id: If7c9e4192db03b81a9040219bedec70e38241509
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1887743
Commit-Queue: Thomas Guilbert <tguilbert@chromium.org>
Reviewed-by: default avatarDale Curtis <dalecurtis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#710641}
parent b44b1028
...@@ -216,7 +216,8 @@ void VideoFrameCompositor::PaintSingleFrame(scoped_refptr<VideoFrame> frame, ...@@ -216,7 +216,8 @@ void VideoFrameCompositor::PaintSingleFrame(scoped_refptr<VideoFrame> frame,
std::move(frame), repaint_duplicate_frame)); std::move(frame), repaint_duplicate_frame));
return; return;
} }
if (ProcessNewFrame(std::move(frame), repaint_duplicate_frame) && if (ProcessNewFrame(std::move(frame), tick_clock_->NowTicks(),
repaint_duplicate_frame) &&
IsClientSinkAvailable()) { IsClientSinkAvailable()) {
client_->DidReceiveFrame(); client_->DidReceiveFrame();
} }
...@@ -258,7 +259,14 @@ void VideoFrameCompositor::SetOnNewProcessedFrameCallback( ...@@ -258,7 +259,14 @@ void VideoFrameCompositor::SetOnNewProcessedFrameCallback(
new_processed_frame_cb_ = std::move(cb); new_processed_frame_cb_ = std::move(cb);
} }
void VideoFrameCompositor::SetOnFramePresentedCallback(
OnNewFramePresentedCB present_cb) {
DCHECK(task_runner_->BelongsToCurrentThread());
new_presented_frame_cb_ = std::move(present_cb);
}
bool VideoFrameCompositor::ProcessNewFrame(scoped_refptr<VideoFrame> frame, bool VideoFrameCompositor::ProcessNewFrame(scoped_refptr<VideoFrame> frame,
base::TimeTicks presentation_time,
bool repaint_duplicate_frame) { bool repaint_duplicate_frame) {
DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(task_runner_->BelongsToCurrentThread());
...@@ -274,7 +282,15 @@ bool VideoFrameCompositor::ProcessNewFrame(scoped_refptr<VideoFrame> frame, ...@@ -274,7 +282,15 @@ bool VideoFrameCompositor::ProcessNewFrame(scoped_refptr<VideoFrame> frame,
SetCurrentFrame(std::move(frame)); SetCurrentFrame(std::move(frame));
if (new_processed_frame_cb_) if (new_processed_frame_cb_)
std::move(new_processed_frame_cb_).Run(base::TimeTicks::Now()); std::move(new_processed_frame_cb_).Run(tick_clock_->NowTicks());
if (new_presented_frame_cb_) {
std::move(new_presented_frame_cb_)
.Run(GetCurrentFrame(), tick_clock_->NowTicks(), presentation_time,
presentation_counter_);
}
++presentation_counter_;
return true; return true;
} }
...@@ -327,7 +343,7 @@ bool VideoFrameCompositor::CallRender(base::TimeTicks deadline_min, ...@@ -327,7 +343,7 @@ bool VideoFrameCompositor::CallRender(base::TimeTicks deadline_min,
const bool new_frame = ProcessNewFrame( const bool new_frame = ProcessNewFrame(
callback_->Render(deadline_min, deadline_max, background_rendering), callback_->Render(deadline_min, deadline_max, background_rendering),
false); deadline_min, false);
// We may create a new frame here with background rendering, but the provider // We may create a new frame here with background rendering, but the provider
// has no way of knowing that a new frame had been processed, so keep track of // has no way of knowing that a new frame had been processed, so keep track of
......
...@@ -63,6 +63,12 @@ class MEDIA_BLINK_EXPORT VideoFrameCompositor : public VideoRendererSink, ...@@ -63,6 +63,12 @@ class MEDIA_BLINK_EXPORT VideoFrameCompositor : public VideoRendererSink,
// Used to report back the time when the new frame has been processed. // Used to report back the time when the new frame has been processed.
using OnNewProcessedFrameCB = base::OnceCallback<void(base::TimeTicks)>; using OnNewProcessedFrameCB = base::OnceCallback<void(base::TimeTicks)>;
using OnNewFramePresentedCB =
base::OnceCallback<void(scoped_refptr<VideoFrame> presented_frame,
base::TimeTicks presentation_time,
base::TimeTicks expected_presentation_time,
uint32_t presentation_counter)>;
// |task_runner| is the task runner on which this class will live, // |task_runner| is the task runner on which this class will live,
// though it may be constructed on any thread. // though it may be constructed on any thread.
VideoFrameCompositor( VideoFrameCompositor(
...@@ -126,6 +132,8 @@ class MEDIA_BLINK_EXPORT VideoFrameCompositor : public VideoRendererSink, ...@@ -126,6 +132,8 @@ class MEDIA_BLINK_EXPORT VideoFrameCompositor : public VideoRendererSink,
// Must be called on the compositor thread. // Must be called on the compositor thread.
virtual void SetOnNewProcessedFrameCallback(OnNewProcessedFrameCB cb); virtual void SetOnNewProcessedFrameCallback(OnNewProcessedFrameCB cb);
void SetOnFramePresentedCallback(OnNewFramePresentedCB present_cb);
// Updates the rotation information for frames given to |submitter_|. // Updates the rotation information for frames given to |submitter_|.
void UpdateRotation(VideoRotation rotation); void UpdateRotation(VideoRotation rotation);
...@@ -172,6 +180,7 @@ class MEDIA_BLINK_EXPORT VideoFrameCompositor : public VideoRendererSink, ...@@ -172,6 +180,7 @@ class MEDIA_BLINK_EXPORT VideoFrameCompositor : public VideoRendererSink,
// Handles setting of |current_frame_|. // Handles setting of |current_frame_|.
bool ProcessNewFrame(scoped_refptr<VideoFrame> frame, bool ProcessNewFrame(scoped_refptr<VideoFrame> frame,
base::TimeTicks presentation_time,
bool repaint_duplicate_frame); bool repaint_duplicate_frame);
void SetCurrentFrame(scoped_refptr<VideoFrame> frame); void SetCurrentFrame(scoped_refptr<VideoFrame> frame);
...@@ -215,6 +224,7 @@ class MEDIA_BLINK_EXPORT VideoFrameCompositor : public VideoRendererSink, ...@@ -215,6 +224,7 @@ class MEDIA_BLINK_EXPORT VideoFrameCompositor : public VideoRendererSink,
base::TimeTicks last_background_render_; base::TimeTicks last_background_render_;
OnNewProcessedFrameCB new_processed_frame_cb_; OnNewProcessedFrameCB new_processed_frame_cb_;
OnNewFramePresentedCB new_presented_frame_cb_;
cc::UpdateSubmissionStateCB update_submission_state_callback_; cc::UpdateSubmissionStateCB update_submission_state_callback_;
// Set on the compositor thread, but also read on the media thread. Lock is // Set on the compositor thread, but also read on the media thread. Lock is
...@@ -227,6 +237,8 @@ class MEDIA_BLINK_EXPORT VideoFrameCompositor : public VideoRendererSink, ...@@ -227,6 +237,8 @@ class MEDIA_BLINK_EXPORT VideoFrameCompositor : public VideoRendererSink,
VideoRendererSink::RenderCallback* callback_ GUARDED_BY(callback_lock_) = VideoRendererSink::RenderCallback* callback_ GUARDED_BY(callback_lock_) =
nullptr; nullptr;
uint32_t presentation_counter_ = 0u;
// AutoOpenCloseEvent for begin/end events. // AutoOpenCloseEvent for begin/end events.
std::unique_ptr<base::trace_event::AutoOpenCloseEvent<kTracingCategory>> std::unique_ptr<base::trace_event::AutoOpenCloseEvent<kTracingCategory>>
auto_open_close_; auto_open_close_;
......
...@@ -99,6 +99,11 @@ class VideoFrameCompositorTest : public VideoRendererSink::RenderCallback, ...@@ -99,6 +99,11 @@ class VideoFrameCompositorTest : public VideoRendererSink::RenderCallback,
VideoFrameCompositor* compositor() { return compositor_.get(); } VideoFrameCompositor* compositor() { return compositor_.get(); }
VideoFrameCompositor::OnNewFramePresentedCB GetNewFramePresentedCB() {
return base::BindOnce(&VideoFrameCompositorTest::OnNewFramePresented,
base::Unretained(this));
}
protected: protected:
bool IsSurfaceLayerForVideoEnabled() { return GetParam(); } bool IsSurfaceLayerForVideoEnabled() { return GetParam(); }
...@@ -137,6 +142,19 @@ class VideoFrameCompositorTest : public VideoRendererSink::RenderCallback, ...@@ -137,6 +142,19 @@ class VideoFrameCompositorTest : public VideoRendererSink::RenderCallback,
compositor()->PutCurrentFrame(); compositor()->PutCurrentFrame();
} }
void OnNewFramePresented(scoped_refptr<VideoFrame> presented_frame,
base::TimeTicks presentation_time,
base::TimeTicks expected_presentation_time,
uint32_t presentation_counter) {
last_presentation_counter_ = presentation_counter;
last_presented_frame_ = presented_frame;
EXPECT_NE(presentation_time, base::TimeTicks());
EXPECT_NE(expected_presentation_time, base::TimeTicks());
}
uint32_t last_presentation_counter_ = 0u;
scoped_refptr<VideoFrame> last_presented_frame_;
base::TimeDelta preferred_render_interval_; base::TimeDelta preferred_render_interval_;
base::SimpleTestTickClock tick_clock_; base::SimpleTestTickClock tick_clock_;
StrictMock<MockWebVideoFrameSubmitter>* submitter_; StrictMock<MockWebVideoFrameSubmitter>* submitter_;
...@@ -190,6 +208,48 @@ TEST_P(VideoFrameCompositorTest, PaintSingleFrame) { ...@@ -190,6 +208,48 @@ TEST_P(VideoFrameCompositorTest, PaintSingleFrame) {
EXPECT_EQ(1, submitter_->did_receive_frame_count()); EXPECT_EQ(1, submitter_->did_receive_frame_count());
} }
TEST_P(VideoFrameCompositorTest, RenderFiresPrensentationCallback) {
// Advance the clock so we can differentiate between base::TimeTicks::Now()
// and base::TimeTicks().
tick_clock_.Advance(base::TimeDelta::FromSeconds(1));
scoped_refptr<VideoFrame> opaque_frame = CreateOpaqueFrame();
EXPECT_CALL(*this, Render(_, _, true)).WillRepeatedly(Return(opaque_frame));
compositor()->SetOnFramePresentedCallback(GetNewFramePresentedCB());
StartVideoRendererSink();
StopVideoRendererSink(true);
EXPECT_EQ(last_presented_frame_, opaque_frame);
}
TEST_P(VideoFrameCompositorTest, MultiplePresentationCallbacks) {
// Advance the clock so we can differentiate between base::TimeTicks::Now()
// and base::TimeTicks().
tick_clock_.Advance(base::TimeDelta::FromSeconds(1));
scoped_refptr<VideoFrame> opaque_frame_1 = CreateOpaqueFrame();
scoped_refptr<VideoFrame> opaque_frame_2 = CreateOpaqueFrame();
scoped_refptr<VideoFrame> opaque_frame_3 = CreateOpaqueFrame();
// Set a dummy value to be overriden.
constexpr uint32_t kStartValue = 12345;
last_presentation_counter_ = kStartValue;
compositor()->SetOnFramePresentedCallback(GetNewFramePresentedCB());
compositor()->PaintSingleFrame(opaque_frame_1);
EXPECT_NE(last_presentation_counter_, kStartValue);
EXPECT_EQ(last_presented_frame_, opaque_frame_1);
// Callbacks are one-shot, and shouldn't change the values we last received.
compositor()->PaintSingleFrame(opaque_frame_2);
EXPECT_EQ(last_presented_frame_, opaque_frame_1);
// The presentation counter should have gone up twice.
uint32_t temp_counter = last_presentation_counter_;
compositor()->SetOnFramePresentedCallback(GetNewFramePresentedCB());
compositor()->PaintSingleFrame(opaque_frame_3);
EXPECT_EQ(last_presented_frame_, opaque_frame_3);
EXPECT_EQ(last_presentation_counter_, temp_counter + 2);
}
TEST_P(VideoFrameCompositorTest, VideoRendererSinkFrameDropped) { TEST_P(VideoFrameCompositorTest, VideoRendererSinkFrameDropped) {
scoped_refptr<VideoFrame> opaque_frame = CreateOpaqueFrame(); scoped_refptr<VideoFrame> opaque_frame = CreateOpaqueFrame();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment