• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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.
4 
5 // Delegate calls from WebCore::MediaPlayerPrivate to Chrome's video player.
6 // It contains PipelineImpl which is the actual media player pipeline, it glues
7 // the media player pipeline, data source, audio renderer and renderer.
8 // PipelineImpl would creates multiple threads and access some public methods
9 // of this class, so we need to be extra careful about concurrent access of
10 // methods and members.
11 //
12 // WebMediaPlayerImpl works with multiple objects, the most important ones are:
13 //
14 // media::PipelineImpl
15 //   The media playback pipeline.
16 //
17 // WebVideoRenderer
18 //   Video renderer object.
19 //
20 // WebMediaPlayerImpl::Proxy
21 //   Proxies methods calls from the media pipeline to WebKit.
22 //
23 // WebKit::WebMediaPlayerClient
24 //   WebKit client of this media player object.
25 //
26 // The following diagram shows the relationship of these objects:
27 //   (note: ref-counted reference is marked by a "r".)
28 //
29 // WebMediaPlayerImpl ------> PipelineImpl
30 //    |            ^               | r
31 //    |            |               v
32 //    |            |        WebVideoRenderer
33 //    |            |          ^ r
34 //    |            |          |
35 //    |      r     |    r     |
36 //    .------>   Proxy  <-----.
37 //    |
38 //    |
39 //    v
40 // WebMediaPlayerClient
41 //
42 // Notice that Proxy and WebVideoRenderer are referencing each other. This
43 // interdependency has to be treated carefully.
44 //
45 // Other issues:
46 // During tear down of the whole browser or a tab, the DOM tree may not be
47 // destructed nicely, and there will be some dangling media threads trying to
48 // the main thread, so we need this class to listen to destruction event of the
49 // main thread and cleanup the media threads when the even is received. Also
50 // at destruction of this class we will need to unhook it from destruction event
51 // list of the main thread.
52 
53 #ifndef WEBKIT_GLUE_WEBMEDIAPLAYER_IMPL_H_
54 #define WEBKIT_GLUE_WEBMEDIAPLAYER_IMPL_H_
55 
56 #include "base/memory/ref_counted.h"
57 #include "base/memory/scoped_ptr.h"
58 #include "base/message_loop.h"
59 #include "base/threading/thread.h"
60 #include "base/synchronization/lock.h"
61 #include "base/synchronization/waitable_event.h"
62 #include "media/base/filters.h"
63 #include "media/base/message_loop_factory.h"
64 #include "media/base/pipeline.h"
65 #include "skia/ext/platform_canvas.h"
66 #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayer.h"
67 #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayerClient.h"
68 #include "ui/gfx/rect.h"
69 #include "ui/gfx/size.h"
70 #include "webkit/glue/media/web_data_source.h"
71 
72 class GURL;
73 
74 namespace WebKit {
75 class WebFrame;
76 }
77 
78 namespace webkit_glue {
79 
80 class MediaResourceLoaderBridgeFactory;
81 class WebVideoRenderer;
82 
83 class WebMediaPlayerImpl : public WebKit::WebMediaPlayer,
84                            public MessageLoop::DestructionObserver {
85  public:
86   // A proxy class that dispatches method calls from the media pipeline to
87   // WebKit. Since there are multiple threads in the media pipeline and there's
88   // need for the media pipeline to call to WebKit, e.g. repaint requests,
89   // initialization events, etc, we have this class to bridge all method calls
90   // from the media pipeline on different threads and serialize these calls
91   // on the render thread.
92   // Because of the nature of this object that it works with different threads,
93   // it is made ref-counted.
94   class Proxy : public base::RefCountedThreadSafe<Proxy> {
95    public:
96     Proxy(MessageLoop* render_loop,
97           WebMediaPlayerImpl* webmediaplayer);
98 
99     // Methods for Filter -> WebMediaPlayerImpl communication.
100     void Repaint();
101     void SetVideoRenderer(scoped_refptr<WebVideoRenderer> video_renderer);
102     WebDataSourceBuildObserverHack* GetBuildObserver();
103 
104     // Methods for WebMediaPlayerImpl -> Filter communication.
105     void Paint(SkCanvas* canvas, const gfx::Rect& dest_rect);
106     void SetSize(const gfx::Rect& rect);
107     void Detach();
108     void GetCurrentFrame(scoped_refptr<media::VideoFrame>* frame_out);
109     void PutCurrentFrame(scoped_refptr<media::VideoFrame> frame);
110     bool HasSingleOrigin();
111     void AbortDataSources();
112 
113     // Methods for PipelineImpl -> WebMediaPlayerImpl communication.
114     void PipelineInitializationCallback(media::PipelineStatus status);
115     void PipelineSeekCallback(media::PipelineStatus status);
116     void PipelineEndedCallback(media::PipelineStatus status);
117     void PipelineErrorCallback(media::PipelineStatus error);
118     void NetworkEventCallback(media::PipelineStatus status);
119 
120     // Returns the message loop used by the proxy.
message_loop()121     MessageLoop* message_loop() { return render_loop_; }
122 
123    private:
124     friend class base::RefCountedThreadSafe<Proxy>;
125 
126     virtual ~Proxy();
127 
128     // Adds a data source to data_sources_.
129     void AddDataSource(WebDataSource* data_source);
130 
131     // Invoke |webmediaplayer_| to perform a repaint.
132     void RepaintTask();
133 
134     // Notify |webmediaplayer_| that initialization has finished.
135     void PipelineInitializationTask(media::PipelineStatus status);
136 
137     // Notify |webmediaplayer_| that a seek has finished.
138     void PipelineSeekTask(media::PipelineStatus status);
139 
140     // Notify |webmediaplayer_| that the media has ended.
141     void PipelineEndedTask(media::PipelineStatus status);
142 
143     // Notify |webmediaplayer_| that a pipeline error has occurred during
144     // playback.
145     void PipelineErrorTask(media::PipelineStatus error);
146 
147     // Notify |webmediaplayer_| that there's a network event.
148     void NetworkEventTask(media::PipelineStatus status);
149 
150     // The render message loop where WebKit lives.
151     MessageLoop* render_loop_;
152     WebMediaPlayerImpl* webmediaplayer_;
153 
154     base::Lock data_sources_lock_;
155     typedef std::list<scoped_refptr<WebDataSource> > DataSourceList;
156     DataSourceList data_sources_;
157     scoped_ptr<WebDataSourceBuildObserverHack> build_observer_;
158 
159     scoped_refptr<WebVideoRenderer> video_renderer_;
160 
161     base::Lock lock_;
162     int outstanding_repaints_;
163   };
164 
165   // Construct a WebMediaPlayerImpl with reference to the client, and media
166   // filter collection. By providing the filter collection the implementor can
167   // provide more specific media filters that does resource loading and
168   // rendering. |collection| should contain filter factories for:
169   // 1. Data source
170   // 2. Audio renderer
171   // 3. Video renderer (optional)
172   //
173   // There are some default filters provided by this method:
174   // 1. FFmpeg demuxer
175   // 2. FFmpeg audio decoder
176   // 3. FFmpeg video decoder
177   // 4. Video renderer
178   // 5. Null audio renderer
179   // The video renderer provided by this class is using the graphics context
180   // provided by WebKit to perform renderering. The simple data source does
181   // resource loading by loading the whole resource object into memory. Null
182   // audio renderer is a fake audio device that plays silence. Provider of the
183   // |collection| can override the default filters by adding extra filters to
184   // |collection| before calling this method.
185   //
186   // Callers must call |Initialize()| before they can use the object.
187   WebMediaPlayerImpl(WebKit::WebMediaPlayerClient* client,
188                      media::FilterCollection* collection,
189                      media::MessageLoopFactory* message_loop_factory);
190   virtual ~WebMediaPlayerImpl();
191 
192   // Finalizes initialization of the object.
193   bool Initialize(
194       WebKit::WebFrame* frame,
195       bool use_simple_data_source,
196       scoped_refptr<WebVideoRenderer> web_video_renderer);
197 
198   virtual void load(const WebKit::WebURL& url);
199   virtual void cancelLoad();
200 
201   // Playback controls.
202   virtual void play();
203   virtual void pause();
204   virtual bool supportsFullscreen() const;
205   virtual bool supportsSave() const;
206   virtual void seek(float seconds);
207   virtual void setEndTime(float seconds);
208   virtual void setRate(float rate);
209   virtual void setVolume(float volume);
210   virtual void setVisible(bool visible);
211   virtual void setPreload(WebKit::WebMediaPlayer::Preload preload);
212   virtual bool totalBytesKnown();
213   virtual const WebKit::WebTimeRanges& buffered();
214   virtual float maxTimeSeekable() const;
215 
216   // Methods for painting.
217   virtual void setSize(const WebKit::WebSize& size);
218 
219   virtual void paint(WebKit::WebCanvas* canvas, const WebKit::WebRect& rect);
220 
221   // True if the loaded media has a playable video/audio track.
222   virtual bool hasVideo() const;
223   virtual bool hasAudio() const;
224 
225   // Dimensions of the video.
226   virtual WebKit::WebSize naturalSize() const;
227 
228   // Getters of playback state.
229   virtual bool paused() const;
230   virtual bool seeking() const;
231   virtual float duration() const;
232   virtual float currentTime() const;
233 
234   // Get rate of loading the resource.
235   virtual int32 dataRate() const;
236 
237   // Internal states of loading and network.
238   // TODO(hclam): Ask the pipeline about the state rather than having reading
239   // them from members which would cause race conditions.
240   virtual WebKit::WebMediaPlayer::NetworkState networkState() const;
241   virtual WebKit::WebMediaPlayer::ReadyState readyState() const;
242 
243   virtual unsigned long long bytesLoaded() const;
244   virtual unsigned long long totalBytes() const;
245 
246   virtual bool hasSingleSecurityOrigin() const;
247   virtual WebKit::WebMediaPlayer::MovieLoadType movieLoadType() const;
248 
249   virtual unsigned decodedFrameCount() const;
250   virtual unsigned droppedFrameCount() const;
251   virtual unsigned audioDecodedByteCount() const;
252   virtual unsigned videoDecodedByteCount() const;
253 
254   virtual WebKit::WebVideoFrame* getCurrentFrame();
255   virtual void putCurrentFrame(WebKit::WebVideoFrame* web_video_frame);
256 
257   // As we are closing the tab or even the browser, |main_loop_| is destroyed
258   // even before this object gets destructed, so we need to know when
259   // |main_loop_| is being destroyed and we can stop posting repaint task
260   // to it.
261   virtual void WillDestroyCurrentMessageLoop();
262 
263   void Repaint();
264 
265   void OnPipelineInitialize(media::PipelineStatus status);
266 
267   void OnPipelineSeek(media::PipelineStatus status);
268 
269   void OnPipelineEnded(media::PipelineStatus status);
270 
271   void OnPipelineError(media::PipelineStatus error);
272 
273   void OnNetworkEvent(media::PipelineStatus status);
274 
275  private:
276   // Helpers that set the network/ready state and notifies the client if
277   // they've changed.
278   void SetNetworkState(WebKit::WebMediaPlayer::NetworkState state);
279   void SetReadyState(WebKit::WebMediaPlayer::ReadyState state);
280 
281   // Destroy resources held.
282   void Destroy();
283 
284   // Getter method to |client_|.
285   WebKit::WebMediaPlayerClient* GetClient();
286 
287   // TODO(hclam): get rid of these members and read from the pipeline directly.
288   WebKit::WebMediaPlayer::NetworkState network_state_;
289   WebKit::WebMediaPlayer::ReadyState ready_state_;
290 
291   // Keep a list of buffered time ranges.
292   WebKit::WebTimeRanges buffered_;
293 
294   // Message loops for posting tasks between Chrome's main thread. Also used
295   // for DCHECKs so methods calls won't execute in the wrong thread.
296   MessageLoop* main_loop_;
297 
298   // A collection of filters.
299   scoped_ptr<media::FilterCollection> filter_collection_;
300 
301   // The actual pipeline and the thread it runs on.
302   scoped_refptr<media::Pipeline> pipeline_;
303 
304   scoped_ptr<media::MessageLoopFactory> message_loop_factory_;
305 
306   // Playback state.
307   //
308   // TODO(scherkus): we have these because Pipeline favours the simplicity of a
309   // single "playback rate" over worrying about paused/stopped etc...  It forces
310   // all clients to manage the pause+playback rate externally, but is that
311   // really a bad thing?
312   //
313   // TODO(scherkus): since SetPlaybackRate(0) is asynchronous and we don't want
314   // to hang the render thread during pause(), we record the time at the same
315   // time we pause and then return that value in currentTime().  Otherwise our
316   // clock can creep forward a little bit while the asynchronous
317   // SetPlaybackRate(0) is being executed.
318   bool paused_;
319   bool seeking_;
320   float playback_rate_;
321   base::TimeDelta paused_time_;
322 
323   WebKit::WebMediaPlayerClient* client_;
324 
325   scoped_refptr<Proxy> proxy_;
326 
327 #if WEBKIT_USING_CG
328   scoped_ptr<skia::PlatformCanvas> skia_canvas_;
329 #endif
330 
331   DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerImpl);
332 };
333 
334 }  // namespace webkit_glue
335 
336 #endif  // WEBKIT_GLUE_WEBMEDIAPLAYER_IMPL_H_
337