Home | History | Annotate | Download | only in glue
      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.
    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