Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2012 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 #ifndef MEDIA_BASE_PIPELINE_H_
      6 #define MEDIA_BASE_PIPELINE_H_
      7 
      8 #include "base/gtest_prod_util.h"
      9 #include "base/memory/weak_ptr.h"
     10 #include "base/synchronization/lock.h"
     11 #include "base/threading/thread_checker.h"
     12 #include "base/time/default_tick_clock.h"
     13 #include "media/base/buffering_state.h"
     14 #include "media/base/demuxer.h"
     15 #include "media/base/media_export.h"
     16 #include "media/base/pipeline_status.h"
     17 #include "media/base/ranges.h"
     18 #include "media/base/serial_runner.h"
     19 #include "media/base/text_track.h"
     20 #include "media/base/video_rotation.h"
     21 #include "ui/gfx/size.h"
     22 
     23 namespace base {
     24 class SingleThreadTaskRunner;
     25 class TimeDelta;
     26 }
     27 
     28 namespace media {
     29 
     30 class MediaLog;
     31 class Renderer;
     32 class TextRenderer;
     33 class TextTrackConfig;
     34 class TimeDeltaInterpolator;
     35 
     36 // Metadata describing a pipeline once it has been initialized.
     37 struct PipelineMetadata {
     38   PipelineMetadata()
     39       : has_audio(false), has_video(false), video_rotation(VIDEO_ROTATION_0) {}
     40 
     41   bool has_audio;
     42   bool has_video;
     43   gfx::Size natural_size;
     44   VideoRotation video_rotation;
     45   base::Time timeline_offset;
     46 };
     47 
     48 typedef base::Callback<void(PipelineMetadata)> PipelineMetadataCB;
     49 
     50 // Pipeline runs the media pipeline.  Filters are created and called on the
     51 // task runner injected into this object. Pipeline works like a state
     52 // machine to perform asynchronous initialization, pausing, seeking and playing.
     53 //
     54 // Here's a state diagram that describes the lifetime of this object.
     55 //
     56 //   [ *Created ]                       [ Any State ]
     57 //         | Start()                         | Stop() / SetError()
     58 //         V                                 V
     59 //   [ InitXXX (for each filter) ]      [ Stopping ]
     60 //         |                                 |
     61 //         V                                 V
     62 //   [ Playing ] <-- [ Seeking ]        [ Stopped ]
     63 //         |               ^
     64 //         `---------------'
     65 //              Seek()
     66 //
     67 // Initialization is a series of state transitions from "Created" through each
     68 // filter initialization state.  When all filter initialization states have
     69 // completed, we are implicitly in a "Paused" state.  At that point we simulate
     70 // a Seek() to the beginning of the media to give filters a chance to preroll.
     71 // From then on the normal Seek() transitions are carried out and we start
     72 // playing the media.
     73 //
     74 // If any error ever happens, this object will transition to the "Error" state
     75 // from any state. If Stop() is ever called, this object will transition to
     76 // "Stopped" state.
     77 class MEDIA_EXPORT Pipeline : public DemuxerHost {
     78  public:
     79   // Constructs a media pipeline that will execute on |task_runner|.
     80   Pipeline(const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
     81            MediaLog* media_log);
     82   virtual ~Pipeline();
     83 
     84   // Build a pipeline to using the given |demuxer| and |renderer| to construct
     85   // a filter chain, executing |seek_cb| when the initial seek has completed.
     86   //
     87   // The following permanent callbacks will be executed as follows up until
     88   // Stop() has completed:
     89   //   |ended_cb| will be executed whenever the media reaches the end.
     90   //   |error_cb| will be executed whenever an error occurs but hasn't been
     91   //              reported already through another callback.
     92   //   |metadata_cb| will be executed when the content duration, container video
     93   //                 size, start time, and whether the content has audio and/or
     94   //                 video in supported formats are known.
     95   //   |buffering_state_cb| will be executed whenever there are changes in the
     96   //                        overall buffering state of the pipeline.
     97   //   |duration_change_cb| optional callback that will be executed whenever the
     98   //                        presentation duration changes.
     99   //   |add_text_track_cb| will be executed whenever a text track is added.
    100   // It is an error to call this method after the pipeline has already started.
    101   void Start(Demuxer* demuxer,
    102              scoped_ptr<Renderer> renderer,
    103              const base::Closure& ended_cb,
    104              const PipelineStatusCB& error_cb,
    105              const PipelineStatusCB& seek_cb,
    106              const PipelineMetadataCB& metadata_cb,
    107              const BufferingStateCB& buffering_state_cb,
    108              const base::Closure& duration_change_cb,
    109              const AddTextTrackCB& add_text_track_cb);
    110 
    111   // Asynchronously stops the pipeline, executing |stop_cb| when the pipeline
    112   // teardown has completed.
    113   //
    114   // Stop() must complete before destroying the pipeline. It it permissible to
    115   // call Stop() at any point during the lifetime of the pipeline.
    116   //
    117   // It is safe to delete the pipeline during the execution of |stop_cb|.
    118   void Stop(const base::Closure& stop_cb);
    119 
    120   // Attempt to seek to the position specified by time.  |seek_cb| will be
    121   // executed when the all filters in the pipeline have processed the seek.
    122   //
    123   // Clients are expected to call GetMediaTime() to check whether the seek
    124   // succeeded.
    125   //
    126   // It is an error to call this method if the pipeline has not started.
    127   void Seek(base::TimeDelta time, const PipelineStatusCB& seek_cb);
    128 
    129   // Returns true if the pipeline has been started via Start().  If IsRunning()
    130   // returns true, it is expected that Stop() will be called before destroying
    131   // the pipeline.
    132   bool IsRunning() const;
    133 
    134   // Gets the current playback rate of the pipeline.  When the pipeline is
    135   // started, the playback rate will be 0.0f.  A rate of 1.0f indicates
    136   // that the pipeline is rendering the media at the standard rate.  Valid
    137   // values for playback rate are >= 0.0f.
    138   float GetPlaybackRate() const;
    139 
    140   // Attempt to adjust the playback rate. Setting a playback rate of 0.0f pauses
    141   // all rendering of the media.  A rate of 1.0f indicates a normal playback
    142   // rate.  Values for the playback rate must be greater than or equal to 0.0f.
    143   //
    144   // TODO(scherkus): What about maximum rate?  Does HTML5 specify a max?
    145   void SetPlaybackRate(float playback_rate);
    146 
    147   // Gets the current volume setting being used by the audio renderer.  When
    148   // the pipeline is started, this value will be 1.0f.  Valid values range
    149   // from 0.0f to 1.0f.
    150   float GetVolume() const;
    151 
    152   // Attempt to set the volume of the audio renderer.  Valid values for volume
    153   // range from 0.0f (muted) to 1.0f (full volume).  This value affects all
    154   // channels proportionately for multi-channel audio streams.
    155   void SetVolume(float volume);
    156 
    157   // Returns the current media playback time, which progresses from 0 until
    158   // GetMediaDuration().
    159   base::TimeDelta GetMediaTime() const;
    160 
    161   // Get approximate time ranges of buffered media.
    162   Ranges<base::TimeDelta> GetBufferedTimeRanges() const;
    163 
    164   // Get the duration of the media in microseconds.  If the duration has not
    165   // been determined yet, then returns 0.
    166   base::TimeDelta GetMediaDuration() const;
    167 
    168   // Return true if loading progress has been made since the last time this
    169   // method was called.
    170   bool DidLoadingProgress();
    171 
    172   // Gets the current pipeline statistics.
    173   PipelineStatistics GetStatistics() const;
    174 
    175   void SetErrorForTesting(PipelineStatus status);
    176   bool HasWeakPtrsForTesting() const;
    177 
    178  private:
    179   FRIEND_TEST_ALL_PREFIXES(PipelineTest, GetBufferedTimeRanges);
    180   FRIEND_TEST_ALL_PREFIXES(PipelineTest, EndedCallback);
    181   FRIEND_TEST_ALL_PREFIXES(PipelineTest, AudioStreamShorterThanVideo);
    182   friend class MediaLog;
    183 
    184   // Pipeline states, as described above.
    185   enum State {
    186     kCreated,
    187     kInitDemuxer,
    188     kInitRenderer,
    189     kSeeking,
    190     kPlaying,
    191     kStopping,
    192     kStopped,
    193   };
    194 
    195   // Updates |state_|. All state transitions should use this call.
    196   void SetState(State next_state);
    197 
    198   static const char* GetStateString(State state);
    199   State GetNextState() const;
    200 
    201   // Helper method that runs & resets |seek_cb_| and resets |seek_timestamp_|
    202   // and |seek_pending_|.
    203   void FinishSeek();
    204 
    205   // DemuxerHost implementaion.
    206   virtual void AddBufferedTimeRange(base::TimeDelta start,
    207                                     base::TimeDelta end) OVERRIDE;
    208   virtual void SetDuration(base::TimeDelta duration) OVERRIDE;
    209   virtual void OnDemuxerError(PipelineStatus error) OVERRIDE;
    210   virtual void AddTextStream(DemuxerStream* text_stream,
    211                              const TextTrackConfig& config) OVERRIDE;
    212   virtual void RemoveTextStream(DemuxerStream* text_stream) OVERRIDE;
    213 
    214   // Callback executed when a rendering error happened, initiating the teardown
    215   // sequence.
    216   void OnError(PipelineStatus error);
    217 
    218   // Callback executed by filters to update statistics.
    219   void OnUpdateStatistics(const PipelineStatistics& stats);
    220 
    221   // The following "task" methods correspond to the public methods, but these
    222   // methods are run as the result of posting a task to the Pipeline's
    223   // task runner.
    224   void StartTask();
    225 
    226   // Stops and destroys all filters, placing the pipeline in the kStopped state.
    227   void StopTask(const base::Closure& stop_cb);
    228 
    229   // Carries out stopping and destroying all filters, placing the pipeline in
    230   // the kStopped state.
    231   void ErrorChangedTask(PipelineStatus error);
    232 
    233   // Carries out notifying filters that the playback rate has changed.
    234   void PlaybackRateChangedTask(float playback_rate);
    235 
    236   // Carries out notifying filters that the volume has changed.
    237   void VolumeChangedTask(float volume);
    238 
    239   // Carries out notifying filters that we are seeking to a new timestamp.
    240   void SeekTask(base::TimeDelta time, const PipelineStatusCB& seek_cb);
    241 
    242   // Callbacks executed when a renderer has ended.
    243   void OnRendererEnded();
    244   void OnTextRendererEnded();
    245   void RunEndedCallbackIfNeeded();
    246 
    247   scoped_ptr<TextRenderer> CreateTextRenderer();
    248 
    249   // Carries out adding a new text stream to the text renderer.
    250   void AddTextStreamTask(DemuxerStream* text_stream,
    251                          const TextTrackConfig& config);
    252 
    253   // Carries out removing a text stream from the text renderer.
    254   void RemoveTextStreamTask(DemuxerStream* text_stream);
    255 
    256   // Callbacks executed when a text track is added.
    257   void OnAddTextTrack(const TextTrackConfig& config,
    258                       const AddTextTrackDoneCB& done_cb);
    259 
    260   // Kicks off initialization for each media object, executing |done_cb| with
    261   // the result when completed.
    262   void InitializeDemuxer(const PipelineStatusCB& done_cb);
    263   void InitializeRenderer(const base::Closure& done_cb);
    264 
    265   void OnStateTransition(PipelineStatus status);
    266   void StateTransitionTask(PipelineStatus status);
    267 
    268   // Initiates an asynchronous pause-flush-seek-preroll call sequence
    269   // executing |done_cb| with the final status when completed.
    270   void DoSeek(base::TimeDelta seek_timestamp, const PipelineStatusCB& done_cb);
    271 
    272   // Initiates an asynchronous pause-flush-stop call sequence executing
    273   // |done_cb| when completed.
    274   void DoStop(const PipelineStatusCB& done_cb);
    275   void OnStopCompleted(PipelineStatus status);
    276 
    277   void ReportMetadata();
    278 
    279   void BufferingStateChanged(BufferingState new_buffering_state);
    280 
    281   // Task runner used to execute pipeline tasks.
    282   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
    283 
    284   // MediaLog to which to log events.
    285   scoped_refptr<MediaLog> media_log_;
    286 
    287   // Lock used to serialize access for the following data members.
    288   mutable base::Lock lock_;
    289 
    290   // Whether or not the pipeline is running.
    291   bool running_;
    292 
    293   // Amount of available buffered data as reported by |demuxer_|.
    294   Ranges<base::TimeDelta> buffered_time_ranges_;
    295 
    296   // True when AddBufferedTimeRange() has been called more recently than
    297   // DidLoadingProgress().
    298   bool did_loading_progress_;
    299 
    300   // Current volume level (from 0.0f to 1.0f).  This value is set immediately
    301   // via SetVolume() and a task is dispatched on the task runner to notify the
    302   // filters.
    303   float volume_;
    304 
    305   // Current playback rate (>= 0.0f).  This value is set immediately via
    306   // SetPlaybackRate() and a task is dispatched on the task runner to notify
    307   // the filters.
    308   float playback_rate_;
    309 
    310   // Current duration as reported by |demuxer_|.
    311   base::TimeDelta duration_;
    312 
    313   // Status of the pipeline.  Initialized to PIPELINE_OK which indicates that
    314   // the pipeline is operating correctly. Any other value indicates that the
    315   // pipeline is stopped or is stopping.  Clients can call the Stop() method to
    316   // reset the pipeline state, and restore this to PIPELINE_OK.
    317   PipelineStatus status_;
    318 
    319   // The following data members are only accessed by tasks posted to
    320   // |task_runner_|.
    321 
    322   bool is_initialized_;
    323 
    324   // Member that tracks the current state.
    325   State state_;
    326 
    327   // The timestamp to start playback from after starting/seeking has completed.
    328   base::TimeDelta start_timestamp_;
    329 
    330   // Whether we've received the audio/video/text ended events.
    331   bool renderer_ended_;
    332   bool text_renderer_ended_;
    333 
    334   // Temporary callback used for Start() and Seek().
    335   PipelineStatusCB seek_cb_;
    336 
    337   // Temporary callback used for Stop().
    338   base::Closure stop_cb_;
    339 
    340   // Permanent callbacks passed in via Start().
    341   base::Closure ended_cb_;
    342   PipelineStatusCB error_cb_;
    343   PipelineMetadataCB metadata_cb_;
    344   BufferingStateCB buffering_state_cb_;
    345   base::Closure duration_change_cb_;
    346   AddTextTrackCB add_text_track_cb_;
    347 
    348   // Holds the initialized demuxer. Used for seeking. Owned by client.
    349   Demuxer* demuxer_;
    350 
    351   // Holds the initialized renderers. Used for setting the volume,
    352   // playback rate, and determining when playback has finished.
    353   scoped_ptr<Renderer> renderer_;
    354   scoped_ptr<TextRenderer> text_renderer_;
    355 
    356   PipelineStatistics statistics_;
    357 
    358   scoped_ptr<SerialRunner> pending_callbacks_;
    359 
    360   base::ThreadChecker thread_checker_;
    361 
    362   // NOTE: Weak pointers must be invalidated before all other member variables.
    363   base::WeakPtrFactory<Pipeline> weak_factory_;
    364 
    365   DISALLOW_COPY_AND_ASSIGN(Pipeline);
    366 };
    367 
    368 }  // namespace media
    369 
    370 #endif  // MEDIA_BASE_PIPELINE_H_
    371