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 <string>
      9 
     10 #include "base/gtest_prod_util.h"
     11 #include "base/synchronization/condition_variable.h"
     12 #include "base/synchronization/lock.h"
     13 #include "base/threading/thread_checker.h"
     14 #include "base/time/default_tick_clock.h"
     15 #include "media/base/audio_renderer.h"
     16 #include "media/base/buffering_state.h"
     17 #include "media/base/demuxer.h"
     18 #include "media/base/media_export.h"
     19 #include "media/base/pipeline_status.h"
     20 #include "media/base/ranges.h"
     21 #include "media/base/serial_runner.h"
     22 #include "ui/gfx/size.h"
     23 
     24 namespace base {
     25 class SingleThreadTaskRunner;
     26 class TimeDelta;
     27 }
     28 
     29 namespace media {
     30 
     31 class Clock;
     32 class FilterCollection;
     33 class MediaLog;
     34 class TextRenderer;
     35 class TextTrackConfig;
     36 class VideoRenderer;
     37 
     38 // Metadata describing a pipeline once it has been initialized.
     39 struct PipelineMetadata {
     40   PipelineMetadata() : has_audio(false), has_video(false) {}
     41 
     42   bool has_audio;
     43   bool has_video;
     44   gfx::Size natural_size;
     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 //   [ InitPrerolling ]                 [ Stopped ]
     63 //         |
     64 //         V
     65 //   [ Playing ] <-- [ Seeking ]
     66 //         |               ^
     67 //         `---------------'
     68 //              Seek()
     69 //
     70 // Initialization is a series of state transitions from "Created" through each
     71 // filter initialization state.  When all filter initialization states have
     72 // completed, we are implicitly in a "Paused" state.  At that point we simulate
     73 // a Seek() to the beginning of the media to give filters a chance to preroll.
     74 // From then on the normal Seek() transitions are carried out and we start
     75 // playing the media.
     76 //
     77 // If any error ever happens, this object will transition to the "Error" state
     78 // from any state. If Stop() is ever called, this object will transition to
     79 // "Stopped" state.
     80 class MEDIA_EXPORT Pipeline : public DemuxerHost {
     81  public:
     82   // Constructs a media pipeline that will execute on |task_runner|.
     83   Pipeline(const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
     84            MediaLog* media_log);
     85   virtual ~Pipeline();
     86 
     87   // Build a pipeline to using the given filter collection to construct a filter
     88   // chain, executing |seek_cb| when the initial seek/preroll has completed.
     89   //
     90   // |filter_collection| must be a complete collection containing a demuxer,
     91   // audio/video decoders, and audio/video renderers. Failing to do so will
     92   // result in a crash.
     93   //
     94   // The following permanent callbacks will be executed as follows up until
     95   // Stop() has completed:
     96   //   |ended_cb| will be executed whenever the media reaches the end.
     97   //   |error_cb| will be executed whenever an error occurs but hasn't been
     98   //              reported already through another callback.
     99   //   |metadata_cb| will be executed when the content duration, container video
    100   //                 size, start time, and whether the content has audio and/or
    101   //                 video in supported formats are known.
    102   //   |preroll_completed_cb| will be executed when all renderers have buffered
    103   //                          enough data to satisfy preroll and are ready to
    104   //                          start playback.
    105   //   |duration_change_cb| optional callback that will be executed whenever the
    106   //                        presentation duration changes.
    107   // It is an error to call this method after the pipeline has already started.
    108   void Start(scoped_ptr<FilterCollection> filter_collection,
    109              const base::Closure& ended_cb,
    110              const PipelineStatusCB& error_cb,
    111              const PipelineStatusCB& seek_cb,
    112              const PipelineMetadataCB& metadata_cb,
    113              const base::Closure& preroll_completed_cb,
    114              const base::Closure& duration_change_cb);
    115 
    116   // Asynchronously stops the pipeline, executing |stop_cb| when the pipeline
    117   // teardown has completed.
    118   //
    119   // Stop() must complete before destroying the pipeline. It it permissible to
    120   // call Stop() at any point during the lifetime of the pipeline.
    121   //
    122   // It is safe to delete the pipeline during the execution of |stop_cb|.
    123   void Stop(const base::Closure& stop_cb);
    124 
    125   // Attempt to seek to the position specified by time.  |seek_cb| will be
    126   // executed when the all filters in the pipeline have processed the seek.
    127   //
    128   // Clients are expected to call GetMediaTime() to check whether the seek
    129   // succeeded.
    130   //
    131   // It is an error to call this method if the pipeline has not started.
    132   void Seek(base::TimeDelta time, const PipelineStatusCB& seek_cb);
    133 
    134   // Returns true if the pipeline has been started via Start().  If IsRunning()
    135   // returns true, it is expected that Stop() will be called before destroying
    136   // the pipeline.
    137   bool IsRunning() const;
    138 
    139   // Gets the current playback rate of the pipeline.  When the pipeline is
    140   // started, the playback rate will be 0.0f.  A rate of 1.0f indicates
    141   // that the pipeline is rendering the media at the standard rate.  Valid
    142   // values for playback rate are >= 0.0f.
    143   float GetPlaybackRate() const;
    144 
    145   // Attempt to adjust the playback rate. Setting a playback rate of 0.0f pauses
    146   // all rendering of the media.  A rate of 1.0f indicates a normal playback
    147   // rate.  Values for the playback rate must be greater than or equal to 0.0f.
    148   //
    149   // TODO(scherkus): What about maximum rate?  Does HTML5 specify a max?
    150   void SetPlaybackRate(float playback_rate);
    151 
    152   // Gets the current volume setting being used by the audio renderer.  When
    153   // the pipeline is started, this value will be 1.0f.  Valid values range
    154   // from 0.0f to 1.0f.
    155   float GetVolume() const;
    156 
    157   // Attempt to set the volume of the audio renderer.  Valid values for volume
    158   // range from 0.0f (muted) to 1.0f (full volume).  This value affects all
    159   // channels proportionately for multi-channel audio streams.
    160   void SetVolume(float volume);
    161 
    162   // Returns the current media playback time, which progresses from 0 until
    163   // GetMediaDuration().
    164   base::TimeDelta GetMediaTime() const;
    165 
    166   // Get approximate time ranges of buffered media.
    167   Ranges<base::TimeDelta> GetBufferedTimeRanges() const;
    168 
    169   // Get the duration of the media in microseconds.  If the duration has not
    170   // been determined yet, then returns 0.
    171   base::TimeDelta GetMediaDuration() const;
    172 
    173   // Return true if loading progress has been made since the last time this
    174   // method was called.
    175   bool DidLoadingProgress();
    176 
    177   // Gets the current pipeline statistics.
    178   PipelineStatistics GetStatistics() const;
    179 
    180   void SetClockForTesting(Clock* clock);
    181   void SetErrorForTesting(PipelineStatus status);
    182 
    183  private:
    184   FRIEND_TEST_ALL_PREFIXES(PipelineTest, GetBufferedTimeRanges);
    185   FRIEND_TEST_ALL_PREFIXES(PipelineTest, EndedCallback);
    186   FRIEND_TEST_ALL_PREFIXES(PipelineTest, AudioStreamShorterThanVideo);
    187   friend class MediaLog;
    188 
    189   // Pipeline states, as described above.
    190   enum State {
    191     kCreated,
    192     kInitDemuxer,
    193     kInitAudioRenderer,
    194     kInitVideoRenderer,
    195     kInitPrerolling,
    196     kSeeking,
    197     kPlaying,
    198     kStopping,
    199     kStopped,
    200   };
    201 
    202   // Updates |state_|. All state transitions should use this call.
    203   void SetState(State next_state);
    204 
    205   static const char* GetStateString(State state);
    206   State GetNextState() const;
    207 
    208   // Helper method that runs & resets |seek_cb_| and resets |seek_timestamp_|
    209   // and |seek_pending_|.
    210   void FinishSeek();
    211 
    212   // DemuxerHost implementaion.
    213   virtual void AddBufferedTimeRange(base::TimeDelta start,
    214                                     base::TimeDelta end) OVERRIDE;
    215   virtual void SetDuration(base::TimeDelta duration) OVERRIDE;
    216   virtual void OnDemuxerError(PipelineStatus error) OVERRIDE;
    217   virtual void AddTextStream(DemuxerStream* text_stream,
    218                              const TextTrackConfig& config) OVERRIDE;
    219   virtual void RemoveTextStream(DemuxerStream* text_stream) OVERRIDE;
    220 
    221   // Initiates teardown sequence in response to a runtime error.
    222   //
    223   // Safe to call from any thread.
    224   void SetError(PipelineStatus error);
    225 
    226   // Callbacks executed when a renderer has ended.
    227   void OnAudioRendererEnded();
    228   void OnVideoRendererEnded();
    229   void OnTextRendererEnded();
    230 
    231   // Callback executed by filters to update statistics.
    232   void OnUpdateStatistics(const PipelineStatistics& stats);
    233 
    234   // Callback executed by audio renderer to update clock time.
    235   void OnAudioTimeUpdate(base::TimeDelta time, base::TimeDelta max_time);
    236 
    237   // Callback executed by video renderer to update clock time.
    238   void OnVideoTimeUpdate(base::TimeDelta max_time);
    239 
    240   // The following "task" methods correspond to the public methods, but these
    241   // methods are run as the result of posting a task to the Pipeline's
    242   // task runner.
    243   void StartTask();
    244 
    245   // Stops and destroys all filters, placing the pipeline in the kStopped state.
    246   void StopTask(const base::Closure& stop_cb);
    247 
    248   // Carries out stopping and destroying all filters, placing the pipeline in
    249   // the kStopped state.
    250   void ErrorChangedTask(PipelineStatus error);
    251 
    252   // Carries out notifying filters that the playback rate has changed.
    253   void PlaybackRateChangedTask(float playback_rate);
    254 
    255   // Carries out notifying filters that the volume has changed.
    256   void VolumeChangedTask(float volume);
    257 
    258   // Carries out notifying filters that we are seeking to a new timestamp.
    259   void SeekTask(base::TimeDelta time, const PipelineStatusCB& seek_cb);
    260 
    261   // Handles audio/video/text ended logic and running |ended_cb_|.
    262   void DoAudioRendererEnded();
    263   void DoVideoRendererEnded();
    264   void DoTextRendererEnded();
    265   void RunEndedCallbackIfNeeded();
    266 
    267   // Carries out adding a new text stream to the text renderer.
    268   void AddTextStreamTask(DemuxerStream* text_stream,
    269                          const TextTrackConfig& config);
    270 
    271   // Carries out removing a text stream from the text renderer.
    272   void RemoveTextStreamTask(DemuxerStream* text_stream);
    273 
    274   // Kicks off initialization for each media object, executing |done_cb| with
    275   // the result when completed.
    276   void InitializeDemuxer(const PipelineStatusCB& done_cb);
    277   void InitializeAudioRenderer(const PipelineStatusCB& done_cb);
    278   void InitializeVideoRenderer(const PipelineStatusCB& done_cb);
    279 
    280   // Kicks off destroying filters. Called by StopTask() and ErrorChangedTask().
    281   // When we start to tear down the pipeline, we will consider two cases:
    282   // 1. when pipeline has not been initialized, we will transit to stopping
    283   // state first.
    284   // 2. when pipeline has been initialized, we will first transit to pausing
    285   // => flushing => stopping => stopped state.
    286   // This will remove the race condition during stop between filters.
    287   void TearDownPipeline();
    288 
    289   // Compute the time corresponding to a byte offset.
    290   base::TimeDelta TimeForByteOffset_Locked(int64 byte_offset) const;
    291 
    292   void OnStateTransition(PipelineStatus status);
    293   void StateTransitionTask(PipelineStatus status);
    294 
    295   // Initiates an asynchronous preroll call sequence executing |done_cb|
    296   // with the final status when completed.
    297   void DoInitialPreroll(const PipelineStatusCB& done_cb);
    298 
    299   // Initiates an asynchronous pause-flush-seek-preroll call sequence
    300   // executing |done_cb| with the final status when completed.
    301   //
    302   // TODO(scherkus): Prerolling should be separate from seeking so we can report
    303   // finer grained ready states (HAVE_CURRENT_DATA vs. HAVE_FUTURE_DATA)
    304   // indepentent from seeking.
    305   void DoSeek(base::TimeDelta seek_timestamp, const PipelineStatusCB& done_cb);
    306 
    307   // Initiates an asynchronous pause-flush-stop call sequence executing
    308   // |done_cb| when completed.
    309   void DoStop(const PipelineStatusCB& done_cb);
    310   void OnStopCompleted(PipelineStatus status);
    311 
    312   void OnAudioUnderflow();
    313 
    314   // Collection of callback methods and helpers for tracking changes in
    315   // buffering state and transition from paused/underflow states and playing
    316   // states.
    317   //
    318   // While in the kPlaying state:
    319   //   - A waiting to non-waiting transition indicates preroll has completed
    320   //     and StartPlayback() should be called
    321   //   - A non-waiting to waiting transition indicates underflow has occurred
    322   //     and StartWaitingForEnoughData() should be called
    323   void BufferingStateChanged(BufferingState* buffering_state,
    324                              BufferingState new_buffering_state);
    325   bool WaitingForEnoughData() const;
    326   void StartWaitingForEnoughData();
    327   void StartPlayback();
    328 
    329   void PauseClockAndStopRendering_Locked();
    330   void StartClockIfWaitingForTimeUpdate_Locked();
    331 
    332   // Task runner used to execute pipeline tasks.
    333   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
    334 
    335   // MediaLog to which to log events.
    336   scoped_refptr<MediaLog> media_log_;
    337 
    338   // Lock used to serialize access for the following data members.
    339   mutable base::Lock lock_;
    340 
    341   // Whether or not the pipeline is running.
    342   bool running_;
    343 
    344   // Amount of available buffered data as reported by |demuxer_|.
    345   Ranges<base::TimeDelta> buffered_time_ranges_;
    346 
    347   // True when AddBufferedTimeRange() has been called more recently than
    348   // DidLoadingProgress().
    349   bool did_loading_progress_;
    350 
    351   // Current volume level (from 0.0f to 1.0f).  This value is set immediately
    352   // via SetVolume() and a task is dispatched on the task runner to notify the
    353   // filters.
    354   float volume_;
    355 
    356   // Current playback rate (>= 0.0f).  This value is set immediately via
    357   // SetPlaybackRate() and a task is dispatched on the task runner to notify
    358   // the filters.
    359   float playback_rate_;
    360 
    361   // base::TickClock used by |clock_|.
    362   base::DefaultTickClock default_tick_clock_;
    363 
    364   // Reference clock.  Keeps track of current playback time.  Uses system
    365   // clock and linear interpolation, but can have its time manually set
    366   // by filters.
    367   scoped_ptr<Clock> clock_;
    368 
    369   enum ClockState {
    370     // Audio (if present) is not rendering. Clock isn't playing.
    371     CLOCK_PAUSED,
    372 
    373     // Audio (if present) is rendering. Clock isn't playing.
    374     CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE,
    375 
    376     // Audio (if present) is rendering. Clock is playing.
    377     CLOCK_PLAYING,
    378   };
    379 
    380   ClockState clock_state_;
    381 
    382   // Status of the pipeline.  Initialized to PIPELINE_OK which indicates that
    383   // the pipeline is operating correctly. Any other value indicates that the
    384   // pipeline is stopped or is stopping.  Clients can call the Stop() method to
    385   // reset the pipeline state, and restore this to PIPELINE_OK.
    386   PipelineStatus status_;
    387 
    388   // The following data members are only accessed by tasks posted to
    389   // |task_runner_|.
    390 
    391   // Member that tracks the current state.
    392   State state_;
    393 
    394   // Whether we've received the audio/video/text ended events.
    395   bool audio_ended_;
    396   bool video_ended_;
    397   bool text_ended_;
    398 
    399   BufferingState audio_buffering_state_;
    400   BufferingState video_buffering_state_;
    401 
    402   // Temporary callback used for Start() and Seek().
    403   PipelineStatusCB seek_cb_;
    404 
    405   // Temporary callback used for Stop().
    406   base::Closure stop_cb_;
    407 
    408   // Permanent callbacks passed in via Start().
    409   base::Closure ended_cb_;
    410   PipelineStatusCB error_cb_;
    411   PipelineMetadataCB metadata_cb_;
    412   base::Closure preroll_completed_cb_;
    413   base::Closure duration_change_cb_;
    414 
    415   // Contains the demuxer and renderers to use when initializing.
    416   scoped_ptr<FilterCollection> filter_collection_;
    417 
    418   // Holds the initialized demuxer. Used for seeking. Owned by client.
    419   Demuxer* demuxer_;
    420 
    421   // Holds the initialized renderers. Used for setting the volume,
    422   // playback rate, and determining when playback has finished.
    423   scoped_ptr<AudioRenderer> audio_renderer_;
    424   scoped_ptr<VideoRenderer> video_renderer_;
    425   scoped_ptr<TextRenderer> text_renderer_;
    426 
    427   PipelineStatistics statistics_;
    428 
    429   // Time of pipeline creation; is non-zero only until the pipeline first
    430   // reaches "kStarted", at which point it is used & zeroed out.
    431   base::TimeTicks creation_time_;
    432 
    433   scoped_ptr<SerialRunner> pending_callbacks_;
    434 
    435   base::ThreadChecker thread_checker_;
    436 
    437   DISALLOW_COPY_AND_ASSIGN(Pipeline);
    438 };
    439 
    440 }  // namespace media
    441 
    442 #endif  // MEDIA_BASE_PIPELINE_H_
    443