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