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