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