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_
8 #include "base/gtest_prod_util.h"
9 #include "base/memory/weak_ptr.h"
10 #include "base/synchronization/lock.h"
11 #include "base/threading/thread_checker.h"
12 #include "base/time/default_tick_clock.h"
13 #include "media/base/buffering_state.h"
14 #include "media/base/demuxer.h"
15 #include "media/base/media_export.h"
16 #include "media/base/pipeline_status.h"
17 #include "media/base/ranges.h"
18 #include "media/base/serial_runner.h"
19 #include "media/base/text_track.h"
20 #include "media/base/video_rotation.h"
21 #include "ui/gfx/size.h"
24 class SingleThreadTaskRunner;
33 class TextTrackConfig;
34 class TimeDeltaInterpolator;
36 // Metadata describing a pipeline once it has been initialized.
37 struct PipelineMetadata {
39 : has_audio(false), has_video(false), video_rotation(VIDEO_ROTATION_0) {}
43 gfx::Size natural_size;
44 VideoRotation video_rotation;
45 base::Time timeline_offset;
48 typedef base::Callback<void(PipelineMetadata)> PipelineMetadataCB;
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.
54 // Here's a state diagram that describes the lifetime of this object.
56 // [ *Created ] [ Any State ]
57 // | Start() | Stop() / SetError()
59 // [ InitXXX (for each filter) ] [ Stopping ]
62 // [ Playing ] <-- [ Seeking ] [ Stopped ]
67 // Initialization is a series of state transitions from "Created" through each
68 // filter initialization state. When all filter initialization states have
69 // completed, we are implicitly in a "Paused" state. At that point we simulate
70 // a Seek() to the beginning of the media to give filters a chance to preroll.
71 // From then on the normal Seek() transitions are carried out and we start
74 // If any error ever happens, this object will transition to the "Error" state
75 // from any state. If Stop() is ever called, this object will transition to
77 class MEDIA_EXPORT Pipeline : public DemuxerHost {
79 // Constructs a media pipeline that will execute on |task_runner|.
80 Pipeline(const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
84 // Build a pipeline to using the given |demuxer| and |renderer| to construct
85 // a filter chain, executing |seek_cb| when the initial seek has completed.
87 // The following permanent callbacks will be executed as follows up until
88 // Stop() has completed:
89 // |ended_cb| will be executed whenever the media reaches the end.
90 // |error_cb| will be executed whenever an error occurs but hasn't been
91 // reported already through another callback.
92 // |metadata_cb| will be executed when the content duration, container video
93 // size, start time, and whether the content has audio and/or
94 // video in supported formats are known.
95 // |buffering_state_cb| will be executed whenever there are changes in the
96 // overall buffering state of the pipeline.
97 // |duration_change_cb| optional callback that will be executed whenever the
98 // presentation duration changes.
99 // |add_text_track_cb| will be executed whenever a text track is added.
100 // It is an error to call this method after the pipeline has already started.
101 void Start(Demuxer* demuxer,
102 scoped_ptr<Renderer> renderer,
103 const base::Closure& ended_cb,
104 const PipelineStatusCB& error_cb,
105 const PipelineStatusCB& seek_cb,
106 const PipelineMetadataCB& metadata_cb,
107 const BufferingStateCB& buffering_state_cb,
108 const base::Closure& duration_change_cb,
109 const AddTextTrackCB& add_text_track_cb);
111 // Asynchronously stops the pipeline, executing |stop_cb| when the pipeline
112 // teardown has completed.
114 // Stop() must complete before destroying the pipeline. It it permissible to
115 // call Stop() at any point during the lifetime of the pipeline.
117 // It is safe to delete the pipeline during the execution of |stop_cb|.
118 void Stop(const base::Closure& stop_cb);
120 // Attempt to seek to the position specified by time. |seek_cb| will be
121 // executed when the all filters in the pipeline have processed the seek.
123 // Clients are expected to call GetMediaTime() to check whether the seek
126 // It is an error to call this method if the pipeline has not started.
127 void Seek(base::TimeDelta time, const PipelineStatusCB& seek_cb);
129 // Returns true if the pipeline has been started via Start(). If IsRunning()
130 // returns true, it is expected that Stop() will be called before destroying
132 bool IsRunning() const;
134 // Gets the current playback rate of the pipeline. When the pipeline is
135 // started, the playback rate will be 0.0f. A rate of 1.0f indicates
136 // that the pipeline is rendering the media at the standard rate. Valid
137 // values for playback rate are >= 0.0f.
138 float GetPlaybackRate() const;
140 // Attempt to adjust the playback rate. Setting a playback rate of 0.0f pauses
141 // all rendering of the media. A rate of 1.0f indicates a normal playback
142 // rate. Values for the playback rate must be greater than or equal to 0.0f.
144 // TODO(scherkus): What about maximum rate? Does HTML5 specify a max?
145 void SetPlaybackRate(float playback_rate);
147 // Gets the current volume setting being used by the audio renderer. When
148 // the pipeline is started, this value will be 1.0f. Valid values range
149 // from 0.0f to 1.0f.
150 float GetVolume() const;
152 // Attempt to set the volume of the audio renderer. Valid values for volume
153 // range from 0.0f (muted) to 1.0f (full volume). This value affects all
154 // channels proportionately for multi-channel audio streams.
155 void SetVolume(float volume);
157 // Returns the current media playback time, which progresses from 0 until
158 // GetMediaDuration().
159 base::TimeDelta GetMediaTime() const;
161 // Get approximate time ranges of buffered media.
162 Ranges<base::TimeDelta> GetBufferedTimeRanges() const;
164 // Get the duration of the media in microseconds. If the duration has not
165 // been determined yet, then returns 0.
166 base::TimeDelta GetMediaDuration() const;
168 // Return true if loading progress has been made since the last time this
169 // method was called.
170 bool DidLoadingProgress();
172 // Gets the current pipeline statistics.
173 PipelineStatistics GetStatistics() const;
175 void SetErrorForTesting(PipelineStatus status);
176 bool HasWeakPtrsForTesting() const;
179 FRIEND_TEST_ALL_PREFIXES(PipelineTest, GetBufferedTimeRanges);
180 FRIEND_TEST_ALL_PREFIXES(PipelineTest, EndedCallback);
181 FRIEND_TEST_ALL_PREFIXES(PipelineTest, AudioStreamShorterThanVideo);
182 friend class MediaLog;
184 // Pipeline states, as described above.
195 // Updates |state_|. All state transitions should use this call.
196 void SetState(State next_state);
198 static const char* GetStateString(State state);
199 State GetNextState() const;
201 // Helper method that runs & resets |seek_cb_| and resets |seek_timestamp_|
202 // and |seek_pending_|.
205 // DemuxerHost implementaion.
206 virtual void AddBufferedTimeRange(base::TimeDelta start,
207 base::TimeDelta end) OVERRIDE;
208 virtual void SetDuration(base::TimeDelta duration) OVERRIDE;
209 virtual void OnDemuxerError(PipelineStatus error) OVERRIDE;
210 virtual void AddTextStream(DemuxerStream* text_stream,
211 const TextTrackConfig& config) OVERRIDE;
212 virtual void RemoveTextStream(DemuxerStream* text_stream) OVERRIDE;
214 // Callback executed when a rendering error happened, initiating the teardown
216 void OnError(PipelineStatus error);
218 // Callback executed by filters to update statistics.
219 void OnUpdateStatistics(const PipelineStatistics& stats);
221 // The following "task" methods correspond to the public methods, but these
222 // methods are run as the result of posting a task to the Pipeline's
226 // Stops and destroys all filters, placing the pipeline in the kStopped state.
227 void StopTask(const base::Closure& stop_cb);
229 // Carries out stopping and destroying all filters, placing the pipeline in
230 // the kStopped state.
231 void ErrorChangedTask(PipelineStatus error);
233 // Carries out notifying filters that the playback rate has changed.
234 void PlaybackRateChangedTask(float playback_rate);
236 // Carries out notifying filters that the volume has changed.
237 void VolumeChangedTask(float volume);
239 // Carries out notifying filters that we are seeking to a new timestamp.
240 void SeekTask(base::TimeDelta time, const PipelineStatusCB& seek_cb);
242 // Callbacks executed when a renderer has ended.
243 void OnRendererEnded();
244 void OnTextRendererEnded();
245 void RunEndedCallbackIfNeeded();
247 scoped_ptr<TextRenderer> CreateTextRenderer();
249 // Carries out adding a new text stream to the text renderer.
250 void AddTextStreamTask(DemuxerStream* text_stream,
251 const TextTrackConfig& config);
253 // Carries out removing a text stream from the text renderer.
254 void RemoveTextStreamTask(DemuxerStream* text_stream);
256 // Callbacks executed when a text track is added.
257 void OnAddTextTrack(const TextTrackConfig& config,
258 const AddTextTrackDoneCB& done_cb);
260 // Kicks off initialization for each media object, executing |done_cb| with
261 // the result when completed.
262 void InitializeDemuxer(const PipelineStatusCB& done_cb);
263 void InitializeRenderer(const base::Closure& done_cb);
265 void OnStateTransition(PipelineStatus status);
266 void StateTransitionTask(PipelineStatus status);
268 // Initiates an asynchronous pause-flush-seek-preroll call sequence
269 // executing |done_cb| with the final status when completed.
270 void DoSeek(base::TimeDelta seek_timestamp, const PipelineStatusCB& done_cb);
272 // Initiates an asynchronous pause-flush-stop call sequence executing
273 // |done_cb| when completed.
274 void DoStop(const PipelineStatusCB& done_cb);
275 void OnStopCompleted(PipelineStatus status);
277 void ReportMetadata();
279 void BufferingStateChanged(BufferingState new_buffering_state);
281 // Task runner used to execute pipeline tasks.
282 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
284 // MediaLog to which to log events.
285 scoped_refptr<MediaLog> media_log_;
287 // Lock used to serialize access for the following data members.
288 mutable base::Lock lock_;
290 // Whether or not the pipeline is running.
293 // Amount of available buffered data as reported by |demuxer_|.
294 Ranges<base::TimeDelta> buffered_time_ranges_;
296 // True when AddBufferedTimeRange() has been called more recently than
297 // DidLoadingProgress().
298 bool did_loading_progress_;
300 // Current volume level (from 0.0f to 1.0f). This value is set immediately
301 // via SetVolume() and a task is dispatched on the task runner to notify the
305 // Current playback rate (>= 0.0f). This value is set immediately via
306 // SetPlaybackRate() and a task is dispatched on the task runner to notify
308 float playback_rate_;
310 // Current duration as reported by |demuxer_|.
311 base::TimeDelta duration_;
313 // Status of the pipeline. Initialized to PIPELINE_OK which indicates that
314 // the pipeline is operating correctly. Any other value indicates that the
315 // pipeline is stopped or is stopping. Clients can call the Stop() method to
316 // reset the pipeline state, and restore this to PIPELINE_OK.
317 PipelineStatus status_;
319 // The following data members are only accessed by tasks posted to
322 bool is_initialized_;
324 // Member that tracks the current state.
327 // The timestamp to start playback from after starting/seeking has completed.
328 base::TimeDelta start_timestamp_;
330 // Whether we've received the audio/video/text ended events.
331 bool renderer_ended_;
332 bool text_renderer_ended_;
334 // Temporary callback used for Start() and Seek().
335 PipelineStatusCB seek_cb_;
337 // Temporary callback used for Stop().
338 base::Closure stop_cb_;
340 // Permanent callbacks passed in via Start().
341 base::Closure ended_cb_;
342 PipelineStatusCB error_cb_;
343 PipelineMetadataCB metadata_cb_;
344 BufferingStateCB buffering_state_cb_;
345 base::Closure duration_change_cb_;
346 AddTextTrackCB add_text_track_cb_;
348 // Holds the initialized demuxer. Used for seeking. Owned by client.
351 // Holds the initialized renderers. Used for setting the volume,
352 // playback rate, and determining when playback has finished.
353 scoped_ptr<Renderer> renderer_;
354 scoped_ptr<TextRenderer> text_renderer_;
356 PipelineStatistics statistics_;
358 scoped_ptr<SerialRunner> pending_callbacks_;
360 base::ThreadChecker thread_checker_;
362 // NOTE: Weak pointers must be invalidated before all other member variables.
363 base::WeakPtrFactory<Pipeline> weak_factory_;
365 DISALLOW_COPY_AND_ASSIGN(Pipeline);
370 #endif // MEDIA_BASE_PIPELINE_H_