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/ref_counted.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/synchronization/lock.h"
12 #include "base/threading/thread_checker.h"
13 #include "base/time/default_tick_clock.h"
14 #include "media/base/buffering_state.h"
15 #include "media/base/cdm_context.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 "media/base/text_track.h"
22 #include "media/base/video_rotation.h"
23 #include "ui/gfx/geometry/size.h"
26 class SingleThreadTaskRunner
;
35 class TextTrackConfig
;
36 class TimeDeltaInterpolator
;
39 // Metadata describing a pipeline once it has been initialized.
40 struct PipelineMetadata
{
42 : has_audio(false), has_video(false), video_rotation(VIDEO_ROTATION_0
) {}
46 gfx::Size natural_size
;
47 VideoRotation video_rotation
;
48 base::Time timeline_offset
;
51 typedef base::Callback
<void(PipelineMetadata
)> PipelineMetadataCB
;
53 // Pipeline runs the media pipeline. Filters are created and called on the
54 // task runner injected into this object. Pipeline works like a state
55 // machine to perform asynchronous initialization, pausing, seeking and playing.
57 // Here's a state diagram that describes the lifetime of this object.
59 // [ *Created ] [ Any State ]
60 // | Start() | Stop() / SetError()
62 // [ InitXXX (for each filter) ] [ Stopping ]
65 // [ Playing ] <-- [ Seeking ] [ Stopped ]
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
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
80 class MEDIA_EXPORT Pipeline
: public DemuxerHost
{
82 // Used to paint VideoFrame.
83 typedef base::Callback
<void(const scoped_refptr
<VideoFrame
>&)> PaintCB
;
85 // Constructs a media pipeline that will execute on |task_runner|.
86 Pipeline(const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
,
90 // Build a pipeline to using the given |demuxer| and |renderer| to construct
91 // a filter chain, executing |seek_cb| when the initial seek has completed.
93 // The following permanent callbacks will be executed as follows up until
94 // Stop() has completed:
95 // |ended_cb| will be executed whenever the media reaches the end.
96 // |error_cb| will be executed whenever an error occurs but hasn't been
97 // reported already through another callback.
98 // |metadata_cb| will be executed when the content duration, container video
99 // size, start time, and whether the content has audio and/or
100 // video in supported formats are known.
101 // |buffering_state_cb| will be executed whenever there are changes in the
102 // overall buffering state of the pipeline.
103 // |paint_cb| will be executed whenever there is a VideoFrame to be painted.
104 // It's safe to call this callback from any thread.
105 // |duration_change_cb| optional callback that will be executed whenever the
106 // presentation duration changes.
107 // |add_text_track_cb| will be executed whenever a text track is added.
108 // |waiting_for_decryption_key_cb| will be executed whenever the key needed
109 // to decrypt the stream is not available.
110 // It is an error to call this method after the pipeline has already started.
111 void Start(Demuxer
* demuxer
,
112 scoped_ptr
<Renderer
> renderer
,
113 const base::Closure
& ended_cb
,
114 const PipelineStatusCB
& error_cb
,
115 const PipelineStatusCB
& seek_cb
,
116 const PipelineMetadataCB
& metadata_cb
,
117 const BufferingStateCB
& buffering_state_cb
,
118 const PaintCB
& paint_cb
,
119 const base::Closure
& duration_change_cb
,
120 const AddTextTrackCB
& add_text_track_cb
,
121 const base::Closure
& waiting_for_decryption_key_cb
);
123 // Asynchronously stops the pipeline, executing |stop_cb| when the pipeline
124 // teardown has completed.
126 // Stop() must complete before destroying the pipeline. It it permissible to
127 // call Stop() at any point during the lifetime of the pipeline.
129 // It is safe to delete the pipeline during the execution of |stop_cb|.
130 void Stop(const base::Closure
& stop_cb
);
132 // Attempt to seek to the position specified by time. |seek_cb| will be
133 // executed when the all filters in the pipeline have processed the seek.
135 // Clients are expected to call GetMediaTime() to check whether the seek
138 // It is an error to call this method if the pipeline has not started.
139 void Seek(base::TimeDelta time
, const PipelineStatusCB
& seek_cb
);
141 // Returns true if the pipeline has been started via Start(). If IsRunning()
142 // returns true, it is expected that Stop() will be called before destroying
144 bool IsRunning() const;
146 // Gets the current playback rate of the pipeline. When the pipeline is
147 // started, the playback rate will be 0.0f. A rate of 1.0f indicates
148 // that the pipeline is rendering the media at the standard rate. Valid
149 // values for playback rate are >= 0.0f.
150 float GetPlaybackRate() const;
152 // Attempt to adjust the playback rate. Setting a playback rate of 0.0f pauses
153 // all rendering of the media. A rate of 1.0f indicates a normal playback
154 // rate. Values for the playback rate must be greater than or equal to 0.0f.
156 // TODO(scherkus): What about maximum rate? Does HTML5 specify a max?
157 void SetPlaybackRate(float playback_rate
);
159 // Gets the current volume setting being used by the audio renderer. When
160 // the pipeline is started, this value will be 1.0f. Valid values range
161 // from 0.0f to 1.0f.
162 float GetVolume() const;
164 // Attempt to set the volume of the audio renderer. Valid values for volume
165 // range from 0.0f (muted) to 1.0f (full volume). This value affects all
166 // channels proportionately for multi-channel audio streams.
167 void SetVolume(float volume
);
169 // Returns the current media playback time, which progresses from 0 until
170 // GetMediaDuration().
171 base::TimeDelta
GetMediaTime() const;
173 // Get approximate time ranges of buffered media.
174 Ranges
<base::TimeDelta
> GetBufferedTimeRanges() const;
176 // Get the duration of the media in microseconds. If the duration has not
177 // been determined yet, then returns 0.
178 base::TimeDelta
GetMediaDuration() const;
180 // Return true if loading progress has been made since the last time this
181 // method was called.
182 bool DidLoadingProgress();
184 // Gets the current pipeline statistics.
185 PipelineStatistics
GetStatistics() const;
187 void SetCdm(CdmContext
* cdm_context
, const CdmAttachedCB
& cdm_attached_cb
);
189 void SetErrorForTesting(PipelineStatus status
);
190 bool HasWeakPtrsForTesting() const;
193 FRIEND_TEST_ALL_PREFIXES(PipelineTest
, GetBufferedTimeRanges
);
194 FRIEND_TEST_ALL_PREFIXES(PipelineTest
, EndedCallback
);
195 FRIEND_TEST_ALL_PREFIXES(PipelineTest
, AudioStreamShorterThanVideo
);
196 friend class MediaLog
;
198 // Pipeline states, as described above.
209 // Updates |state_|. All state transitions should use this call.
210 void SetState(State next_state
);
212 static const char* GetStateString(State state
);
213 State
GetNextState() const;
215 // Helper method that runs & resets |seek_cb_| and resets |seek_timestamp_|
216 // and |seek_pending_|.
219 // DemuxerHost implementaion.
220 void AddBufferedTimeRange(base::TimeDelta start
,
221 base::TimeDelta end
) override
;
222 void SetDuration(base::TimeDelta duration
) override
;
223 void OnDemuxerError(PipelineStatus error
) override
;
224 void AddTextStream(DemuxerStream
* text_stream
,
225 const TextTrackConfig
& config
) override
;
226 void RemoveTextStream(DemuxerStream
* text_stream
) override
;
228 // Callback executed when a rendering error happened, initiating the teardown
230 void OnError(PipelineStatus error
);
232 // Callback executed by filters to update statistics.
233 void OnUpdateStatistics(const PipelineStatistics
& stats
);
235 // The following "task" methods correspond to the public methods, but these
236 // methods are run as the result of posting a task to the Pipeline's
240 // Stops and destroys all filters, placing the pipeline in the kStopped state.
241 void StopTask(const base::Closure
& stop_cb
);
243 // Carries out stopping and destroying all filters, placing the pipeline in
244 // the kStopped state.
245 void ErrorChangedTask(PipelineStatus error
);
247 // Carries out notifying filters that the playback rate has changed.
248 void PlaybackRateChangedTask(float playback_rate
);
250 // Carries out notifying filters that the volume has changed.
251 void VolumeChangedTask(float volume
);
253 // Carries out notifying filters that we are seeking to a new timestamp.
254 void SeekTask(base::TimeDelta time
, const PipelineStatusCB
& seek_cb
);
256 // Carries out setting the |cdm_context| in |renderer_|, and then fires
257 // |cdm_attached_cb| with the result. If |renderer_| is null,
258 // |cdm_attached_cb| will be fired immediately with true, and |cdm_context|
259 // will be set in |renderer_| later when |renderer_| is created.
260 void SetCdmTask(CdmContext
* cdm_context
,
261 const CdmAttachedCB
& cdm_attached_cb
);
263 // Callbacks executed when a renderer has ended.
264 void OnRendererEnded();
265 void OnTextRendererEnded();
266 void RunEndedCallbackIfNeeded();
268 scoped_ptr
<TextRenderer
> CreateTextRenderer();
270 // Carries out adding a new text stream to the text renderer.
271 void AddTextStreamTask(DemuxerStream
* text_stream
,
272 const TextTrackConfig
& config
);
274 // Carries out removing a text stream from the text renderer.
275 void RemoveTextStreamTask(DemuxerStream
* text_stream
);
277 // Callbacks executed when a text track is added.
278 void OnAddTextTrack(const TextTrackConfig
& config
,
279 const AddTextTrackDoneCB
& done_cb
);
281 // Kicks off initialization for each media object, executing |done_cb| with
282 // the result when completed.
283 void InitializeDemuxer(const PipelineStatusCB
& done_cb
);
284 void InitializeRenderer(const PipelineStatusCB
& done_cb
);
286 void StateTransitionTask(PipelineStatus status
);
288 // Initiates an asynchronous pause-flush-seek-preroll call sequence
289 // executing |done_cb| with the final status when completed.
290 void DoSeek(base::TimeDelta seek_timestamp
, const PipelineStatusCB
& done_cb
);
292 // Initiates an asynchronous pause-flush-stop call sequence executing
293 // |done_cb| when completed.
294 void DoStop(const PipelineStatusCB
& done_cb
);
295 void OnStopCompleted(PipelineStatus status
);
297 void ReportMetadata();
299 void BufferingStateChanged(BufferingState new_buffering_state
);
301 // Task runner used to execute pipeline tasks.
302 scoped_refptr
<base::SingleThreadTaskRunner
> task_runner_
;
304 // MediaLog to which to log events.
305 scoped_refptr
<MediaLog
> media_log_
;
307 // Lock used to serialize access for the following data members.
308 mutable base::Lock lock_
;
310 // Whether or not the pipeline is running.
313 // Amount of available buffered data as reported by |demuxer_|.
314 Ranges
<base::TimeDelta
> buffered_time_ranges_
;
316 // True when AddBufferedTimeRange() has been called more recently than
317 // DidLoadingProgress().
318 bool did_loading_progress_
;
320 // Current volume level (from 0.0f to 1.0f). This value is set immediately
321 // via SetVolume() and a task is dispatched on the task runner to notify the
325 // Current playback rate (>= 0.0f). This value is set immediately via
326 // SetPlaybackRate() and a task is dispatched on the task runner to notify
328 float playback_rate_
;
330 // Current duration as reported by |demuxer_|.
331 base::TimeDelta duration_
;
333 // Status of the pipeline. Initialized to PIPELINE_OK which indicates that
334 // the pipeline is operating correctly. Any other value indicates that the
335 // pipeline is stopped or is stopping. Clients can call the Stop() method to
336 // reset the pipeline state, and restore this to PIPELINE_OK.
337 PipelineStatus status_
;
339 // The following data members are only accessed by tasks posted to
342 // Member that tracks the current state.
345 // The timestamp to start playback from after starting/seeking has completed.
346 base::TimeDelta start_timestamp_
;
348 // Whether we've received the audio/video/text ended events.
349 bool renderer_ended_
;
350 bool text_renderer_ended_
;
352 // Temporary callback used for Start() and Seek().
353 PipelineStatusCB seek_cb_
;
355 // Temporary callback used for Stop().
356 base::Closure stop_cb_
;
358 // Permanent callbacks passed in via Start().
359 base::Closure ended_cb_
;
360 PipelineStatusCB error_cb_
;
361 PipelineMetadataCB metadata_cb_
;
362 BufferingStateCB buffering_state_cb_
;
364 base::Closure duration_change_cb_
;
365 AddTextTrackCB add_text_track_cb_
;
366 base::Closure waiting_for_decryption_key_cb_
;
368 // Holds the initialized demuxer. Used for seeking. Owned by client.
371 // Holds the initialized renderers. Used for setting the volume,
372 // playback rate, and determining when playback has finished.
373 scoped_ptr
<Renderer
> renderer_
;
374 scoped_ptr
<TextRenderer
> text_renderer_
;
376 PipelineStatistics statistics_
;
378 scoped_ptr
<SerialRunner
> pending_callbacks_
;
380 // CdmContext to be used to decrypt (and decode) encrypted stream in this
381 // pipeline. Non-null only when SetCdm() is called and the pipeline has not
382 // been started. Then during Start(), this value will be set on |renderer_|.
383 CdmContext
* pending_cdm_context_
;
385 base::ThreadChecker thread_checker_
;
387 // NOTE: Weak pointers must be invalidated before all other member variables.
388 base::WeakPtrFactory
<Pipeline
> weak_factory_
;
390 DISALLOW_COPY_AND_ASSIGN(Pipeline
);
395 #endif // MEDIA_BASE_PIPELINE_H_