1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef MEDIA_BLINK_VIDEO_FRAME_COMPOSITOR_H_
6 #define MEDIA_BLINK_VIDEO_FRAME_COMPOSITOR_H_
8 #include "base/callback.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/synchronization/lock.h"
12 #include "base/time/tick_clock.h"
13 #include "base/timer/timer.h"
14 #include "cc/layers/video_frame_provider.h"
15 #include "media/base/media_export.h"
16 #include "media/base/video_renderer_sink.h"
17 #include "ui/gfx/geometry/size.h"
22 // VideoFrameCompositor acts as a bridge between the media and cc layers for
23 // rendering video frames. I.e. a media::VideoRenderer will talk to this class
24 // from the media side, while a cc::VideoFrameProvider::Client will talk to it
27 // This class is responsible for requesting new frames from a video renderer in
28 // response to requests from the VFP::Client. Since the VFP::Client may stop
29 // issuing requests in response to visibility changes it is also responsible for
30 // ensuring the "freshness" of the current frame for programmatic frame
31 // requests; e.g., Canvas.drawImage() requests
33 // This class is also responsible for detecting frames dropped by the compositor
34 // after rendering and signaling that information to a RenderCallback. It
35 // detects frames not dropped by verifying each GetCurrentFrame() is followed
36 // by a PutCurrentFrame() before the next UpdateCurrentFrame() call.
38 // VideoRenderSink::RenderCallback implementations must call Start() and Stop()
39 // once new frames are expected or are no longer expected to be ready; this data
40 // is relayed to the compositor to avoid extraneous callbacks.
42 // VideoFrameCompositor is also responsible for pumping UpdateCurrentFrame()
43 // callbacks in the background when |client_| has decided to suspend them.
45 // VideoFrameCompositor must live on the same thread as the compositor, though
46 // it may be constructed on any thread.
47 class MEDIA_EXPORT VideoFrameCompositor
48 : public VideoRendererSink
,
49 NON_EXPORTED_BASE(public cc::VideoFrameProvider
) {
51 // |compositor_task_runner| is the task runner on which this class will live,
52 // though it may be constructed on any thread.
54 // |natural_size_changed_cb| is run with the new natural size of the video
55 // frame whenever a change in natural size is detected. It is not called the
56 // first time UpdateCurrentFrame() is called. Run on the same thread as the
57 // caller of UpdateCurrentFrame().
59 // |opacity_changed_cb| is run when a change in opacity is detected. It *is*
60 // called the first time UpdateCurrentFrame() is called. Run on the same
61 // thread as the caller of UpdateCurrentFrame().
63 // TODO(dalecurtis): Investigate the inconsistency between the callbacks with
64 // respect to why we don't call |natural_size_changed_cb| on the first frame.
65 // I suspect it was for historical reasons that no longer make sense.
67 const scoped_refptr
<base::SingleThreadTaskRunner
>& compositor_task_runner
,
68 const base::Callback
<void(gfx::Size
)>& natural_size_changed_cb
,
69 const base::Callback
<void(bool)>& opacity_changed_cb
);
71 // Destruction must happen on the compositor thread; Stop() must have been
72 // called before destruction starts.
73 ~VideoFrameCompositor() override
;
75 // cc::VideoFrameProvider implementation. These methods must be called on the
76 // |compositor_task_runner_|.
77 void SetVideoFrameProviderClient(
78 cc::VideoFrameProvider::Client
* client
) override
;
79 bool UpdateCurrentFrame(base::TimeTicks deadline_min
,
80 base::TimeTicks deadline_max
) override
;
81 bool HasCurrentFrame() override
;
82 scoped_refptr
<VideoFrame
> GetCurrentFrame() override
;
83 void PutCurrentFrame() override
;
85 // VideoRendererSink implementation. These methods must be called from the
86 // same thread (typically the media thread).
87 void Start(RenderCallback
* callback
) override
;
89 void PaintFrameUsingOldRenderingPath(
90 const scoped_refptr
<VideoFrame
>& frame
) override
;
92 // Returns |current_frame_| if |client_| is set. If no |client_| is set,
93 // |is_background_rendering_| is true, and |callback_| is set, it requests a
94 // new frame from |callback_|, using the elapsed time between calls to this
95 // function as the render interval; defaulting to 16.6ms if no prior calls
96 // have been made. A cap of 250Hz (4ms) is in place to prevent clients from
97 // accidentally (or intentionally) spamming the rendering pipeline.
99 // This method is primarily to facilitate canvas and WebGL based applications
100 // where the <video> tag is invisible (possibly not even in the DOM) and thus
101 // does not receive a |client_|. In this case, frame acquisition is driven by
102 // the frequency of canvas or WebGL paints requested via JavaScript.
103 scoped_refptr
<VideoFrame
> GetCurrentFrameAndUpdateIfStale();
105 void set_tick_clock_for_testing(scoped_ptr
<base::TickClock
> tick_clock
) {
106 tick_clock_
= tick_clock
.Pass();
109 void clear_current_frame_for_testing() { current_frame_
= nullptr; }
111 // Enables or disables background rendering. If |enabled|, |timeout| is the
112 // amount of time to wait after the last Render() call before starting the
113 // background rendering mode. Note, this can not disable the background
114 // rendering call issues when a sink is started.
115 void set_background_rendering_for_testing(bool enabled
) {
116 background_rendering_enabled_
= enabled
;
120 // Called on the compositor thread in response to Start() or Stop() calls;
121 // must be used to change |rendering_| state.
122 void OnRendererStateUpdate(bool new_state
);
124 // Handles setting of |current_frame_| and fires |natural_size_changed_cb_|
125 // and |opacity_changed_cb_| when the frame properties changes.
126 bool ProcessNewFrame(const scoped_refptr
<VideoFrame
>& frame
);
128 // Called by |background_rendering_timer_| when enough time elapses where we
129 // haven't seen a Render() call.
130 void BackgroundRender();
132 // If |callback_| is available, calls Render() with the provided properties.
133 // Updates |is_background_rendering_|, |last_interval_|, and resets
134 // |background_rendering_timer_|. Ensures that natural size and opacity
135 // changes are correctly fired. Returns true if there's a new frame available
136 // via GetCurrentFrame().
137 bool CallRender(base::TimeTicks deadline_min
,
138 base::TimeTicks deadline_max
,
139 bool background_rendering
);
141 scoped_refptr
<base::SingleThreadTaskRunner
> compositor_task_runner_
;
142 scoped_ptr
<base::TickClock
> tick_clock_
;
144 // These callbacks are executed on the compositor thread.
145 const base::Callback
<void(gfx::Size
)> natural_size_changed_cb_
;
146 const base::Callback
<void(bool)> opacity_changed_cb_
;
148 // Allows tests to disable the background rendering task.
149 bool background_rendering_enabled_
;
151 // Manages UpdateCurrentFrame() callbacks if |client_| has stopped sending
152 // them for various reasons. Runs on |compositor_task_runner_| and is reset
153 // after each successful UpdateCurrentFrame() call.
154 base::Timer background_rendering_timer_
;
156 // These values are only set and read on the compositor thread.
157 cc::VideoFrameProvider::Client
* client_
;
158 scoped_refptr
<VideoFrame
> current_frame_
;
160 bool rendered_last_frame_
;
161 bool is_background_rendering_
;
162 bool new_background_frame_
;
163 base::TimeDelta last_interval_
;
164 base::TimeTicks last_background_render_
;
166 // These values are updated and read from the media and compositor threads.
168 VideoRendererSink::RenderCallback
* callback_
;
170 DISALLOW_COPY_AND_ASSIGN(VideoFrameCompositor
);
175 #endif // MEDIA_BLINK_VIDEO_FRAME_COMPOSITOR_H_