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
23namespace base {
24class MessageLoopProxy;
25class TimeDelta;
26}
27
28namespace media {
29
30class Clock;
31class FilterCollection;
32class MediaLog;
33class TextRenderer;
34class TextTrackConfig;
35class 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.
68class 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