pipeline.h revision 0de6073388f4e2780db8536178b129cd8f6ab386
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 SingleThreadTaskRunner;
25class TimeDelta;
26}
27
28namespace media {
29
30class Clock;
31class FilterCollection;
32class MediaLog;
33class TextRenderer;
34class TextTrackConfig;
35class VideoRenderer;
36
37// Metadata describing a pipeline once it has been initialized.
38struct PipelineMetadata {
39  PipelineMetadata() : has_audio(false), has_video(false) {}
40
41  bool has_audio;
42  bool has_video;
43  gfx::Size natural_size;
44  base::Time timeline_offset;
45};
46
47typedef base::Callback<void(PipelineMetadata)> PipelineMetadataCB;
48
49// Pipeline runs the media pipeline.  Filters are created and called on the
50// task runner injected into this object. Pipeline works like a state
51// machine to perform asynchronous initialization, pausing, seeking and playing.
52//
53// Here's a state diagram that describes the lifetime of this object.
54//
55//   [ *Created ]                       [ Any State ]
56//         | Start()                         | Stop() / SetError()
57//         V                                 V
58//   [ InitXXX (for each filter) ]      [ Stopping ]
59//         |                                 |
60//         V                                 V
61//   [ InitPreroll ]                    [ Stopped ]
62//         |
63//         V
64//   [ Starting ] <-- [ Seeking ]
65//         |               ^
66//         V               |
67//   [ Started ] ----------'
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.
80class 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();
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() const;
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    kStarting,
198    kStarted,
199    kStopping,
200    kStopped,
201  };
202
203  // Updates |state_|. All state transitions should use this call.
204  void SetState(State next_state);
205
206  static const char* GetStateString(State state);
207  State GetNextState() const;
208
209  // Helper method that runs & resets |seek_cb_| and resets |seek_timestamp_|
210  // and |seek_pending_|.
211  void FinishSeek();
212
213  // DemuxerHost implementaion.
214  virtual void AddBufferedTimeRange(base::TimeDelta start,
215                                    base::TimeDelta end) OVERRIDE;
216  virtual void SetDuration(base::TimeDelta duration) OVERRIDE;
217  virtual void OnDemuxerError(PipelineStatus error) OVERRIDE;
218  virtual void AddTextStream(DemuxerStream* text_stream,
219                             const TextTrackConfig& config) OVERRIDE;
220  virtual void RemoveTextStream(DemuxerStream* text_stream) OVERRIDE;
221
222  // Initiates teardown sequence in response to a runtime error.
223  //
224  // Safe to call from any thread.
225  void SetError(PipelineStatus error);
226
227  // Callbacks executed when a renderer has ended.
228  void OnAudioRendererEnded();
229  void OnVideoRendererEnded();
230  void OnTextRendererEnded();
231
232  // Callback executed by filters to update statistics.
233  void OnUpdateStatistics(const PipelineStatistics& stats);
234
235  // Callback executed by audio renderer to update clock time.
236  void OnAudioTimeUpdate(base::TimeDelta time, base::TimeDelta max_time);
237
238  // Callback executed by video renderer to update clock time.
239  void OnVideoTimeUpdate(base::TimeDelta max_time);
240
241  // The following "task" methods correspond to the public methods, but these
242  // methods are run as the result of posting a task to the Pipeline's
243  // task runner.
244  void StartTask();
245
246  // Stops and destroys all filters, placing the pipeline in the kStopped state.
247  void StopTask(const base::Closure& stop_cb);
248
249  // Carries out stopping and destroying all filters, placing the pipeline in
250  // the kStopped state.
251  void ErrorChangedTask(PipelineStatus error);
252
253  // Carries out notifying filters that the playback rate has changed.
254  void PlaybackRateChangedTask(float playback_rate);
255
256  // Carries out notifying filters that the volume has changed.
257  void VolumeChangedTask(float volume);
258
259  // Carries out notifying filters that we are seeking to a new timestamp.
260  void SeekTask(base::TimeDelta time, const PipelineStatusCB& seek_cb);
261
262  // Handles audio/video/text ended logic and running |ended_cb_|.
263  void DoAudioRendererEnded();
264  void DoVideoRendererEnded();
265  void DoTextRendererEnded();
266  void RunEndedCallbackIfNeeded();
267
268  // Carries out adding a new text stream to the text renderer.
269  void AddTextStreamTask(DemuxerStream* text_stream,
270                         const TextTrackConfig& config);
271
272  // Carries out removing a text stream from the text renderer.
273  void RemoveTextStreamTask(DemuxerStream* text_stream);
274
275  // Kicks off initialization for each media object, executing |done_cb| with
276  // the result when completed.
277  void InitializeDemuxer(const PipelineStatusCB& done_cb);
278  void InitializeAudioRenderer(const PipelineStatusCB& done_cb);
279  void InitializeVideoRenderer(const PipelineStatusCB& done_cb);
280
281  // Kicks off destroying filters. Called by StopTask() and ErrorChangedTask().
282  // When we start to tear down the pipeline, we will consider two cases:
283  // 1. when pipeline has not been initialized, we will transit to stopping
284  // state first.
285  // 2. when pipeline has been initialized, we will first transit to pausing
286  // => flushing => stopping => stopped state.
287  // This will remove the race condition during stop between filters.
288  void TearDownPipeline();
289
290  // Compute the time corresponding to a byte offset.
291  base::TimeDelta TimeForByteOffset_Locked(int64 byte_offset) const;
292
293  void OnStateTransition(PipelineStatus status);
294  void StateTransitionTask(PipelineStatus status);
295
296  // Initiates an asynchronous preroll call sequence executing |done_cb|
297  // with the final status when completed.
298  void DoInitialPreroll(const PipelineStatusCB& done_cb);
299
300  // Initiates an asynchronous pause-flush-seek-preroll call sequence
301  // executing |done_cb| with the final status when completed.
302  //
303  // TODO(scherkus): Prerolling should be separate from seeking so we can report
304  // finer grained ready states (HAVE_CURRENT_DATA vs. HAVE_FUTURE_DATA)
305  // indepentent from seeking.
306  void DoSeek(base::TimeDelta seek_timestamp, const PipelineStatusCB& done_cb);
307
308  // Updates playback rate and volume and initiates an asynchronous play call
309  // sequence executing |done_cb| with the final status when completed.
310  void DoPlay(const PipelineStatusCB& done_cb);
311
312  // Initiates an asynchronous pause-flush-stop call sequence executing
313  // |done_cb| when completed.
314  void DoStop(const PipelineStatusCB& done_cb);
315  void OnStopCompleted(PipelineStatus status);
316
317  void OnAudioUnderflow();
318
319  void StartClockIfWaitingForTimeUpdate_Locked();
320
321  // Task runner used to execute pipeline tasks.
322  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
323
324  // MediaLog to which to log events.
325  scoped_refptr<MediaLog> media_log_;
326
327  // Lock used to serialize access for the following data members.
328  mutable base::Lock lock_;
329
330  // Whether or not the pipeline is running.
331  bool running_;
332
333  // Amount of available buffered data as reported by |demuxer_|.
334  Ranges<base::TimeDelta> buffered_time_ranges_;
335
336  // True when AddBufferedTimeRange() has been called more recently than
337  // DidLoadingProgress().
338  mutable bool did_loading_progress_;
339
340  // Current volume level (from 0.0f to 1.0f).  This value is set immediately
341  // via SetVolume() and a task is dispatched on the task runner to notify the
342  // filters.
343  float volume_;
344
345  // Current playback rate (>= 0.0f).  This value is set immediately via
346  // SetPlaybackRate() and a task is dispatched on the task runner to notify
347  // the filters.
348  float playback_rate_;
349
350  // base::TickClock used by |clock_|.
351  base::DefaultTickClock default_tick_clock_;
352
353  // Reference clock.  Keeps track of current playback time.  Uses system
354  // clock and linear interpolation, but can have its time manually set
355  // by filters.
356  scoped_ptr<Clock> clock_;
357
358  // If this value is set to true, then |clock_| is paused and we are waiting
359  // for an update of the clock greater than or equal to the elapsed time to
360  // start the clock.
361  bool waiting_for_clock_update_;
362
363  // Status of the pipeline.  Initialized to PIPELINE_OK which indicates that
364  // the pipeline is operating correctly. Any other value indicates that the
365  // pipeline is stopped or is stopping.  Clients can call the Stop() method to
366  // reset the pipeline state, and restore this to PIPELINE_OK.
367  PipelineStatus status_;
368
369  // The following data members are only accessed by tasks posted to
370  // |task_runner_|.
371
372  // Member that tracks the current state.
373  State state_;
374
375  // Whether we've received the audio/video/text ended events.
376  bool audio_ended_;
377  bool video_ended_;
378  bool text_ended_;
379
380  // Temporary callback used for Start() and Seek().
381  PipelineStatusCB seek_cb_;
382
383  // Temporary callback used for Stop().
384  base::Closure stop_cb_;
385
386  // Permanent callbacks passed in via Start().
387  base::Closure ended_cb_;
388  PipelineStatusCB error_cb_;
389  PipelineMetadataCB metadata_cb_;
390  base::Closure preroll_completed_cb_;
391  base::Closure duration_change_cb_;
392
393  // Contains the demuxer and renderers to use when initializing.
394  scoped_ptr<FilterCollection> filter_collection_;
395
396  // Holds the initialized demuxer. Used for seeking. Owned by client.
397  Demuxer* demuxer_;
398
399  // Holds the initialized renderers. Used for setting the volume,
400  // playback rate, and determining when playback has finished.
401  scoped_ptr<AudioRenderer> audio_renderer_;
402  scoped_ptr<VideoRenderer> video_renderer_;
403  scoped_ptr<TextRenderer> text_renderer_;
404
405  PipelineStatistics statistics_;
406
407  // Time of pipeline creation; is non-zero only until the pipeline first
408  // reaches "kStarted", at which point it is used & zeroed out.
409  base::TimeTicks creation_time_;
410
411  scoped_ptr<SerialRunner> pending_callbacks_;
412
413  base::ThreadChecker thread_checker_;
414
415  DISALLOW_COPY_AND_ASSIGN(Pipeline);
416};
417
418}  // namespace media
419
420#endif  // MEDIA_BASE_PIPELINE_H_
421