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.
5 #ifndef MEDIA_BASE_PIPELINE_H_
6 #define MEDIA_BASE_PIPELINE_H_
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 "media/base/video_rotation.h"
23 #include "ui/gfx/size.h"
26 class SingleThreadTaskRunner
;
32 class FilterCollection
;
35 class TextTrackConfig
;
36 class TimeDeltaInterpolator
;
40 // Metadata describing a pipeline once it has been initialized.
41 struct PipelineMetadata
{
43 : has_audio(false), has_video(false), video_rotation(VIDEO_ROTATION_0
) {}
47 gfx::Size natural_size
;
48 VideoRotation video_rotation
;
49 base::Time timeline_offset
;
52 typedef base::Callback
<void(PipelineMetadata
)> PipelineMetadataCB
;
54 // Pipeline runs the media pipeline. Filters are created and called on the
55 // task runner injected into this object. Pipeline works like a state
56 // machine to perform asynchronous initialization, pausing, seeking and playing.
58 // Here's a state diagram that describes the lifetime of this object.
60 // [ *Created ] [ Any State ]
61 // | Start() | Stop() / SetError()
63 // [ InitXXX (for each filter) ] [ Stopping ]
66 // [ Playing ] <-- [ Seeking ] [ Stopped ]
71 // Initialization is a series of state transitions from "Created" through each
72 // filter initialization state. When all filter initialization states have
73 // completed, we are implicitly in a "Paused" state. At that point we simulate
74 // a Seek() to the beginning of the media to give filters a chance to preroll.
75 // From then on the normal Seek() transitions are carried out and we start
78 // If any error ever happens, this object will transition to the "Error" state
79 // from any state. If Stop() is ever called, this object will transition to
81 class MEDIA_EXPORT Pipeline
: public DemuxerHost
{
83 // Constructs a media pipeline that will execute on |task_runner|.
84 Pipeline(const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
,
88 // Build a pipeline to using the given filter collection to construct a filter
89 // chain, executing |seek_cb| when the initial seek has completed.
91 // |filter_collection| must be a complete collection containing a demuxer,
92 // audio/video decoders, and audio/video renderers. Failing to do so will
95 // The following permanent callbacks will be executed as follows up until
96 // Stop() has completed:
97 // |ended_cb| will be executed whenever the media reaches the end.
98 // |error_cb| will be executed whenever an error occurs but hasn't been
99 // reported already through another callback.
100 // |metadata_cb| will be executed when the content duration, container video
101 // size, start time, and whether the content has audio and/or
102 // video in supported formats are known.
103 // |buffering_state_cb| will be executed whenever there are changes in the
104 // overall buffering state of the pipeline.
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 BufferingStateCB
& buffering_state_cb
,
114 const base::Closure
& duration_change_cb
);
116 // Asynchronously stops the pipeline, executing |stop_cb| when the pipeline
117 // teardown has completed.
119 // Stop() must complete before destroying the pipeline. It it permissible to
120 // call Stop() at any point during the lifetime of the pipeline.
122 // It is safe to delete the pipeline during the execution of |stop_cb|.
123 void Stop(const base::Closure
& stop_cb
);
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.
128 // Clients are expected to call GetMediaTime() to check whether the seek
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
);
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
137 bool IsRunning() const;
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;
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.
149 // TODO(scherkus): What about maximum rate? Does HTML5 specify a max?
150 void SetPlaybackRate(float playback_rate
);
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;
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
);
162 // Returns the current media playback time, which progresses from 0 until
163 // GetMediaDuration().
164 base::TimeDelta
GetMediaTime() const;
166 // Get approximate time ranges of buffered media.
167 Ranges
<base::TimeDelta
> GetBufferedTimeRanges() const;
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;
173 // Return true if loading progress has been made since the last time this
174 // method was called.
175 bool DidLoadingProgress();
177 // Gets the current pipeline statistics.
178 PipelineStatistics
GetStatistics() const;
180 void set_underflow_disabled_for_testing(bool disabled
) {
181 underflow_disabled_for_testing_
= disabled
;
183 void SetTimeDeltaInterpolatorForTesting(TimeDeltaInterpolator
* interpolator
);
184 void SetErrorForTesting(PipelineStatus status
);
187 FRIEND_TEST_ALL_PREFIXES(PipelineTest
, GetBufferedTimeRanges
);
188 FRIEND_TEST_ALL_PREFIXES(PipelineTest
, EndedCallback
);
189 FRIEND_TEST_ALL_PREFIXES(PipelineTest
, AudioStreamShorterThanVideo
);
190 friend class MediaLog
;
192 // Pipeline states, as described above.
204 // Updates |state_|. All state transitions should use this call.
205 void SetState(State next_state
);
207 static const char* GetStateString(State state
);
208 State
GetNextState() const;
210 // Helper method that runs & resets |seek_cb_| and resets |seek_timestamp_|
211 // and |seek_pending_|.
214 // DemuxerHost implementaion.
215 virtual void AddBufferedTimeRange(base::TimeDelta start
,
216 base::TimeDelta end
) OVERRIDE
;
217 virtual void SetDuration(base::TimeDelta duration
) OVERRIDE
;
218 virtual void OnDemuxerError(PipelineStatus error
) OVERRIDE
;
219 virtual void AddTextStream(DemuxerStream
* text_stream
,
220 const TextTrackConfig
& config
) OVERRIDE
;
221 virtual void RemoveTextStream(DemuxerStream
* text_stream
) OVERRIDE
;
223 // Initiates teardown sequence in response to a runtime error.
225 // Safe to call from any thread.
226 void SetError(PipelineStatus error
);
228 // Callbacks executed when a renderer has ended.
229 void OnAudioRendererEnded();
230 void OnVideoRendererEnded();
231 void OnTextRendererEnded();
233 // Callback executed by filters to update statistics.
234 void OnUpdateStatistics(const PipelineStatistics
& stats
);
236 // Callback executed by audio renderer to update clock time.
237 void OnAudioTimeUpdate(base::TimeDelta time
, base::TimeDelta max_time
);
239 // Callback executed by video renderer to update clock time.
240 void OnVideoTimeUpdate(base::TimeDelta max_time
);
242 // The following "task" methods correspond to the public methods, but these
243 // methods are run as the result of posting a task to the Pipeline's
247 // Stops and destroys all filters, placing the pipeline in the kStopped state.
248 void StopTask(const base::Closure
& stop_cb
);
250 // Carries out stopping and destroying all filters, placing the pipeline in
251 // the kStopped state.
252 void ErrorChangedTask(PipelineStatus error
);
254 // Carries out notifying filters that the playback rate has changed.
255 void PlaybackRateChangedTask(float playback_rate
);
257 // Carries out notifying filters that the volume has changed.
258 void VolumeChangedTask(float volume
);
260 // Carries out notifying filters that we are seeking to a new timestamp.
261 void SeekTask(base::TimeDelta time
, const PipelineStatusCB
& seek_cb
);
263 // Handles audio/video/text ended logic and running |ended_cb_|.
264 void DoAudioRendererEnded();
265 void DoVideoRendererEnded();
266 void DoTextRendererEnded();
267 void RunEndedCallbackIfNeeded();
269 // Carries out adding a new text stream to the text renderer.
270 void AddTextStreamTask(DemuxerStream
* text_stream
,
271 const TextTrackConfig
& config
);
273 // Carries out removing a text stream from the text renderer.
274 void RemoveTextStreamTask(DemuxerStream
* text_stream
);
276 // Kicks off initialization for each media object, executing |done_cb| with
277 // the result when completed.
278 void InitializeDemuxer(const PipelineStatusCB
& done_cb
);
279 void InitializeAudioRenderer(const PipelineStatusCB
& done_cb
);
280 void InitializeVideoRenderer(const PipelineStatusCB
& done_cb
);
282 // Kicks off destroying filters. Called by StopTask() and ErrorChangedTask().
283 // When we start to tear down the pipeline, we will consider two cases:
284 // 1. when pipeline has not been initialized, we will transit to stopping
286 // 2. when pipeline has been initialized, we will first transit to pausing
287 // => flushing => stopping => stopped state.
288 // This will remove the race condition during stop between filters.
289 void TearDownPipeline();
291 // Compute the time corresponding to a byte offset.
292 base::TimeDelta
TimeForByteOffset_Locked(int64 byte_offset
) const;
294 void OnStateTransition(PipelineStatus status
);
295 void StateTransitionTask(PipelineStatus status
);
297 // Initiates an asynchronous pause-flush-seek-preroll call sequence
298 // executing |done_cb| with the final status when completed.
299 void DoSeek(base::TimeDelta seek_timestamp
, const PipelineStatusCB
& done_cb
);
301 // Initiates an asynchronous pause-flush-stop call sequence executing
302 // |done_cb| when completed.
303 void DoStop(const PipelineStatusCB
& done_cb
);
304 void OnStopCompleted(PipelineStatus status
);
306 // Collection of callback methods and helpers for tracking changes in
307 // buffering state and transition from paused/underflow states and playing
310 // While in the kPlaying state:
311 // - A waiting to non-waiting transition indicates preroll has completed
312 // and StartPlayback() should be called
313 // - A non-waiting to waiting transition indicates underflow has occurred
314 // and PausePlayback() should be called
315 void BufferingStateChanged(BufferingState
* buffering_state
,
316 BufferingState new_buffering_state
);
317 bool WaitingForEnoughData() const;
318 void PausePlayback();
319 void StartPlayback();
321 void PauseClockAndStopTicking_Locked();
322 void StartClockIfWaitingForTimeUpdate_Locked();
324 // Task runner used to execute pipeline tasks.
325 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner_
;
327 // MediaLog to which to log events.
328 scoped_refptr
<MediaLog
> media_log_
;
330 // Lock used to serialize access for the following data members.
331 mutable base::Lock lock_
;
333 // Whether or not the pipeline is running.
336 // Amount of available buffered data as reported by |demuxer_|.
337 Ranges
<base::TimeDelta
> buffered_time_ranges_
;
339 // True when AddBufferedTimeRange() has been called more recently than
340 // DidLoadingProgress().
341 bool did_loading_progress_
;
343 // Current volume level (from 0.0f to 1.0f). This value is set immediately
344 // via SetVolume() and a task is dispatched on the task runner to notify the
348 // Current playback rate (>= 0.0f). This value is set immediately via
349 // SetPlaybackRate() and a task is dispatched on the task runner to notify
351 float playback_rate_
;
353 // Current duration as reported by |demuxer_|.
354 base::TimeDelta duration_
;
356 // base::TickClock used by |interpolator_|.
357 base::DefaultTickClock default_tick_clock_
;
359 // Tracks the most recent media time update and provides interpolated values
360 // as playback progresses.
361 scoped_ptr
<TimeDeltaInterpolator
> interpolator_
;
363 enum InterpolationState
{
364 // Audio (if present) is not rendering. Time isn't being interpolated.
365 INTERPOLATION_STOPPED
,
367 // Audio (if present) is rendering. Time isn't being interpolated.
368 INTERPOLATION_WAITING_FOR_AUDIO_TIME_UPDATE
,
370 // Audio (if present) is rendering. Time is being interpolated.
371 INTERPOLATION_STARTED
,
374 InterpolationState interpolation_state_
;
376 // Status of the pipeline. Initialized to PIPELINE_OK which indicates that
377 // the pipeline is operating correctly. Any other value indicates that the
378 // pipeline is stopped or is stopping. Clients can call the Stop() method to
379 // reset the pipeline state, and restore this to PIPELINE_OK.
380 PipelineStatus status_
;
382 // The following data members are only accessed by tasks posted to
385 // Member that tracks the current state.
388 // The timestamp to start playback from after starting/seeking has completed.
389 base::TimeDelta start_timestamp_
;
391 // Whether we've received the audio/video/text ended events.
396 BufferingState audio_buffering_state_
;
397 BufferingState video_buffering_state_
;
399 // Temporary callback used for Start() and Seek().
400 PipelineStatusCB seek_cb_
;
402 // Temporary callback used for Stop().
403 base::Closure stop_cb_
;
405 // Permanent callbacks passed in via Start().
406 base::Closure ended_cb_
;
407 PipelineStatusCB error_cb_
;
408 PipelineMetadataCB metadata_cb_
;
409 BufferingStateCB buffering_state_cb_
;
410 base::Closure duration_change_cb_
;
412 // Contains the demuxer and renderers to use when initializing.
413 scoped_ptr
<FilterCollection
> filter_collection_
;
415 // Holds the initialized demuxer. Used for seeking. Owned by client.
418 // Holds the initialized renderers. Used for setting the volume,
419 // playback rate, and determining when playback has finished.
420 scoped_ptr
<AudioRenderer
> audio_renderer_
;
421 scoped_ptr
<VideoRenderer
> video_renderer_
;
422 scoped_ptr
<TextRenderer
> text_renderer_
;
424 // Renderer-provided time source used to control playback.
425 TimeSource
* time_source_
;
427 PipelineStatistics statistics_
;
429 scoped_ptr
<SerialRunner
> pending_callbacks_
;
431 bool underflow_disabled_for_testing_
;
433 base::ThreadChecker thread_checker_
;
435 DISALLOW_COPY_AND_ASSIGN(Pipeline
);
440 #endif // MEDIA_BASE_PIPELINE_H_