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
72class GURL;
73
74namespace WebKit {
75class WebFrame;
76}
77
78namespace webkit_glue {
79
80class MediaResourceLoaderBridgeFactory;
81class WebVideoRenderer;
82
83class 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.
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