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 23 namespace base { 24 class MessageLoopProxy; 25 class TimeDelta; 26 } 27 28 namespace media { 29 30 class Clock; 31 class FilterCollection; 32 class MediaLog; 33 class TextRenderer; 34 class TextTrackConfig; 35 class VideoRenderer; 36 37 // Pipeline runs the media pipeline. Filters are created and called on the 38 // message loop injected into this object. Pipeline works like a state 39 // machine to perform asynchronous initialization, pausing, seeking and playing. 40 // 41 // Here's a state diagram that describes the lifetime of this object. 42 // 43 // [ *Created ] [ Any State ] 44 // | Start() | Stop() / SetError() 45 // V V 46 // [ InitXXX (for each filter) ] [ Stopping ] 47 // | | 48 // V V 49 // [ InitPreroll ] [ Stopped ] 50 // | 51 // V 52 // [ Starting ] <-- [ Seeking ] 53 // | ^ 54 // V | 55 // [ Started ] ----------' 56 // Seek() 57 // 58 // Initialization is a series of state transitions from "Created" through each 59 // filter initialization state. When all filter initialization states have 60 // completed, we are implicitly in a "Paused" state. At that point we simulate 61 // a Seek() to the beginning of the media to give filters a chance to preroll. 62 // From then on the normal Seek() transitions are carried out and we start 63 // playing the media. 64 // 65 // If any error ever happens, this object will transition to the "Error" state 66 // from any state. If Stop() is ever called, this object will transition to 67 // "Stopped" state. 68 class MEDIA_EXPORT Pipeline : public DemuxerHost { 69 public: 70 // Buffering states the pipeline transitions between during playback. 71 // kHaveMetadata: 72 // Indicates that the following things are known: 73 // content duration, natural size, start time, and whether the content has 74 // audio and/or video in supported formats. 75 // kPrerollCompleted: 76 // All renderers have buffered enough data to satisfy preroll and are ready 77 // to start playback. 78 enum BufferingState { 79 kHaveMetadata, 80 kPrerollCompleted, 81 }; 82 83 typedef base::Callback<void(BufferingState)> BufferingStateCB; 84 85 // Constructs a media pipeline that will execute on |message_loop|. 86 Pipeline(const scoped_refptr<base::MessageLoopProxy>& message_loop, 87 MediaLog* media_log); 88 virtual ~Pipeline(); 89 90 // Build a pipeline to using the given filter collection to construct a filter 91 // chain, executing |seek_cb| when the initial seek/preroll has completed. 92 // 93 // |filter_collection| must be a complete collection containing a demuxer, 94 // audio/video decoders, and audio/video renderers. Failing to do so will 95 // result in a crash. 96 // 97 // The following permanent callbacks will be executed as follows up until 98 // Stop() has completed: 99 // |ended_cb| will be executed whenever the media reaches the end. 100 // |error_cb| will be executed whenever an error occurs but hasn't 101 // been reported already through another callback. 102 // |buffering_state_cb| Optional callback that will be executed whenever the 103 // pipeline's buffering state changes. 104 // |duration_change_cb| Optional callback that will be executed whenever the 105 // presentation duration changes. 106 // It is an error to call this method after the pipeline has already started. 107 void Start(scoped_ptr<FilterCollection> filter_collection, 108 const base::Closure& ended_cb, 109 const PipelineStatusCB& error_cb, 110 const PipelineStatusCB& seek_cb, 111 const BufferingStateCB& buffering_state_cb, 112 const base::Closure& duration_change_cb); 113 114 // Asynchronously stops the pipeline, executing |stop_cb| when the pipeline 115 // teardown has completed. 116 // 117 // Stop() must complete before destroying the pipeline. It it permissible to 118 // call Stop() at any point during the lifetime of the pipeline. 119 // 120 // It is safe to delete the pipeline during the execution of |stop_cb|. 121 void Stop(const base::Closure& stop_cb); 122 123 // Attempt to seek to the position specified by time. |seek_cb| will be 124 // executed when the all filters in the pipeline have processed the seek. 125 // 126 // Clients are expected to call GetMediaTime() to check whether the seek 127 // succeeded. 128 // 129 // It is an error to call this method if the pipeline has not started. 130 void Seek(base::TimeDelta time, const PipelineStatusCB& seek_cb); 131 132 // Returns true if the pipeline has been started via Start(). If IsRunning() 133 // returns true, it is expected that Stop() will be called before destroying 134 // the pipeline. 135 bool IsRunning() const; 136 137 // Returns true if the media has audio. 138 bool HasAudio() const; 139 140 // Returns true if the media has video. 141 bool HasVideo() const; 142 143 // Gets the current playback rate of the pipeline. When the pipeline is 144 // started, the playback rate will be 0.0f. A rate of 1.0f indicates 145 // that the pipeline is rendering the media at the standard rate. Valid 146 // values for playback rate are >= 0.0f. 147 float GetPlaybackRate() const; 148 149 // Attempt to adjust the playback rate. Setting a playback rate of 0.0f pauses 150 // all rendering of the media. A rate of 1.0f indicates a normal playback 151 // rate. Values for the playback rate must be greater than or equal to 0.0f. 152 // 153 // TODO(scherkus): What about maximum rate? Does HTML5 specify a max? 154 void SetPlaybackRate(float playback_rate); 155 156 // Gets the current volume setting being used by the audio renderer. When 157 // the pipeline is started, this value will be 1.0f. Valid values range 158 // from 0.0f to 1.0f. 159 float GetVolume() const; 160 161 // Attempt to set the volume of the audio renderer. Valid values for volume 162 // range from 0.0f (muted) to 1.0f (full volume). This value affects all 163 // channels proportionately for multi-channel audio streams. 164 void SetVolume(float volume); 165 166 // Returns the current media playback time, which progresses from 0 until 167 // GetMediaDuration(). 168 base::TimeDelta GetMediaTime() const; 169 170 // Get approximate time ranges of buffered media. 171 Ranges<base::TimeDelta> GetBufferedTimeRanges(); 172 173 // Get the duration of the media in microseconds. If the duration has not 174 // been determined yet, then returns 0. 175 base::TimeDelta GetMediaDuration() const; 176 177 // Get the total size of the media file. If the size has not yet been 178 // determined or can not be determined, this value is 0. 179 int64 GetTotalBytes() const; 180 181 // Gets the natural size of the video output in pixel units. If there is no 182 // video or the video has not been rendered yet, the width and height will 183 // be 0. 184 void GetNaturalVideoSize(gfx::Size* out_size) const; 185 186 // Return true if loading progress has been made since the last time this 187 // method was called. 188 bool DidLoadingProgress() const; 189 190 // Gets the current pipeline statistics. 191 PipelineStatistics GetStatistics() const; 192 193 void SetClockForTesting(Clock* clock); 194 void SetErrorForTesting(PipelineStatus status); 195 196 private: 197 FRIEND_TEST_ALL_PREFIXES(PipelineTest, GetBufferedTimeRanges); 198 FRIEND_TEST_ALL_PREFIXES(PipelineTest, DisableAudioRenderer); 199 FRIEND_TEST_ALL_PREFIXES(PipelineTest, DisableAudioRendererDuringInit); 200 FRIEND_TEST_ALL_PREFIXES(PipelineTest, EndedCallback); 201 FRIEND_TEST_ALL_PREFIXES(PipelineTest, AudioStreamShorterThanVideo); 202 friend class MediaLog; 203 204 // Pipeline states, as described above. 205 enum State { 206 kCreated, 207 kInitDemuxer, 208 kInitAudioRenderer, 209 kInitVideoRenderer, 210 kInitPrerolling, 211 kSeeking, 212 kStarting, 213 kStarted, 214 kStopping, 215 kStopped, 216 }; 217 218 // Updates |state_|. All state transitions should use this call. 219 void SetState(State next_state); 220 221 static const char* GetStateString(State state); 222 State GetNextState() const; 223 224 // Helper method that runs & resets |seek_cb_| and resets |seek_timestamp_| 225 // and |seek_pending_|. 226 void FinishSeek(); 227 228 // DataSourceHost (by way of DemuxerHost) implementation. 229 virtual void SetTotalBytes(int64 total_bytes) OVERRIDE; 230 virtual void AddBufferedByteRange(int64 start, int64 end) OVERRIDE; 231 virtual void AddBufferedTimeRange(base::TimeDelta start, 232 base::TimeDelta end) OVERRIDE; 233 234 // DemuxerHost implementaion. 235 virtual void SetDuration(base::TimeDelta duration) OVERRIDE; 236 virtual void OnDemuxerError(PipelineStatus error) OVERRIDE; 237 virtual void AddTextStream(DemuxerStream* text_stream, 238 const TextTrackConfig& config) OVERRIDE; 239 virtual void RemoveTextStream(DemuxerStream* text_stream) OVERRIDE; 240 241 // Initiates teardown sequence in response to a runtime error. 242 // 243 // Safe to call from any thread. 244 void SetError(PipelineStatus error); 245 246 // Callback executed when the natural size of the video has changed. 247 void OnNaturalVideoSizeChanged(const gfx::Size& size); 248 249 // Callbacks executed when a renderer has ended. 250 void OnAudioRendererEnded(); 251 void OnVideoRendererEnded(); 252 void OnTextRendererEnded(); 253 254 // Callback executed by filters to update statistics. 255 void OnUpdateStatistics(const PipelineStatistics& stats); 256 257 // Callback executed by audio renderer when it has been disabled. 258 void OnAudioDisabled(); 259 260 // Callback executed by audio renderer to update clock time. 261 void OnAudioTimeUpdate(base::TimeDelta time, base::TimeDelta max_time); 262 263 // Callback executed by video renderer to update clock time. 264 void OnVideoTimeUpdate(base::TimeDelta max_time); 265 266 // The following "task" methods correspond to the public methods, but these 267 // methods are run as the result of posting a task to the PipelineInternal's 268 // message loop. 269 void StartTask(scoped_ptr<FilterCollection> filter_collection, 270 const base::Closure& ended_cb, 271 const PipelineStatusCB& error_cb, 272 const PipelineStatusCB& seek_cb, 273 const BufferingStateCB& buffering_state_cb, 274 const base::Closure& duration_change_cb); 275 276 // Stops and destroys all filters, placing the pipeline in the kStopped state. 277 void StopTask(const base::Closure& stop_cb); 278 279 // Carries out stopping and destroying all filters, placing the pipeline in 280 // the kStopped state. 281 void ErrorChangedTask(PipelineStatus error); 282 283 // Carries out notifying filters that the playback rate has changed. 284 void PlaybackRateChangedTask(float playback_rate); 285 286 // Carries out notifying filters that the volume has changed. 287 void VolumeChangedTask(float volume); 288 289 // Carries out notifying filters that we are seeking to a new timestamp. 290 void SeekTask(base::TimeDelta time, const PipelineStatusCB& seek_cb); 291 292 // Handles audio/video/text ended logic and running |ended_cb_|. 293 void DoAudioRendererEnded(); 294 void DoVideoRendererEnded(); 295 void DoTextRendererEnded(); 296 void RunEndedCallbackIfNeeded(); 297 298 // Carries out disabling the audio renderer. 299 void AudioDisabledTask(); 300 301 // Carries out adding a new text stream to the text renderer. 302 void AddTextStreamTask(DemuxerStream* text_stream, 303 const TextTrackConfig& config); 304 305 // Carries out removing a text stream from the text renderer. 306 void RemoveTextStreamTask(DemuxerStream* text_stream); 307 308 // Kicks off initialization for each media object, executing |done_cb| with 309 // the result when completed. 310 void InitializeDemuxer(const PipelineStatusCB& done_cb); 311 void InitializeAudioRenderer(const PipelineStatusCB& done_cb); 312 void InitializeVideoRenderer(const PipelineStatusCB& done_cb); 313 314 // Kicks off destroying filters. Called by StopTask() and ErrorChangedTask(). 315 // When we start to tear down the pipeline, we will consider two cases: 316 // 1. when pipeline has not been initialized, we will transit to stopping 317 // state first. 318 // 2. when pipeline has been initialized, we will first transit to pausing 319 // => flushing => stopping => stopped state. 320 // This will remove the race condition during stop between filters. 321 void TearDownPipeline(); 322 323 // Compute the time corresponding to a byte offset. 324 base::TimeDelta TimeForByteOffset_Locked(int64 byte_offset) const; 325 326 void OnStateTransition(PipelineStatus status); 327 void StateTransitionTask(PipelineStatus status); 328 329 // Initiates an asynchronous preroll call sequence executing |done_cb| 330 // with the final status when completed. 331 void DoInitialPreroll(const PipelineStatusCB& done_cb); 332 333 // Initiates an asynchronous pause-flush-seek-preroll call sequence 334 // executing |done_cb| with the final status when completed. 335 // 336 // TODO(scherkus): Prerolling should be separate from seeking so we can report 337 // finer grained ready states (HAVE_CURRENT_DATA vs. HAVE_FUTURE_DATA) 338 // indepentent from seeking. 339 void DoSeek(base::TimeDelta seek_timestamp, const PipelineStatusCB& done_cb); 340 341 // Updates playback rate and volume and initiates an asynchronous play call 342 // sequence executing |done_cb| with the final status when completed. 343 void DoPlay(const PipelineStatusCB& done_cb); 344 345 // Initiates an asynchronous pause-flush-stop call sequence executing 346 // |done_cb| when completed. 347 void DoStop(const PipelineStatusCB& done_cb); 348 void OnStopCompleted(PipelineStatus status); 349 350 void OnAudioUnderflow(); 351 352 void StartClockIfWaitingForTimeUpdate_Locked(); 353 354 // Message loop used to execute pipeline tasks. 355 scoped_refptr<base::MessageLoopProxy> message_loop_; 356 357 // MediaLog to which to log events. 358 scoped_refptr<MediaLog> media_log_; 359 360 // Lock used to serialize access for the following data members. 361 mutable base::Lock lock_; 362 363 // Whether or not the pipeline is running. 364 bool running_; 365 366 // Amount of available buffered data. Set by filters. 367 Ranges<int64> buffered_byte_ranges_; 368 Ranges<base::TimeDelta> buffered_time_ranges_; 369 370 // True when AddBufferedByteRange() has been called more recently than 371 // DidLoadingProgress(). 372 mutable bool did_loading_progress_; 373 374 // Total size of the media. Set by filters. 375 int64 total_bytes_; 376 377 // Video's natural width and height. Set by filters. 378 gfx::Size natural_size_; 379 380 // Current volume level (from 0.0f to 1.0f). This value is set immediately 381 // via SetVolume() and a task is dispatched on the message loop to notify the 382 // filters. 383 float volume_; 384 385 // Current playback rate (>= 0.0f). This value is set immediately via 386 // SetPlaybackRate() and a task is dispatched on the message loop to notify 387 // the filters. 388 float playback_rate_; 389 390 // base::TickClock used by |clock_|. 391 base::DefaultTickClock default_tick_clock_; 392 393 // Reference clock. Keeps track of current playback time. Uses system 394 // clock and linear interpolation, but can have its time manually set 395 // by filters. 396 scoped_ptr<Clock> clock_; 397 398 // If this value is set to true, then |clock_| is paused and we are waiting 399 // for an update of the clock greater than or equal to the elapsed time to 400 // start the clock. 401 bool waiting_for_clock_update_; 402 403 // Status of the pipeline. Initialized to PIPELINE_OK which indicates that 404 // the pipeline is operating correctly. Any other value indicates that the 405 // pipeline is stopped or is stopping. Clients can call the Stop() method to 406 // reset the pipeline state, and restore this to PIPELINE_OK. 407 PipelineStatus status_; 408 409 // Whether the media contains rendered audio or video streams. 410 // TODO(fischman,scherkus): replace these with checks for 411 // {audio,video}_decoder_ once extraction of {Audio,Video}Decoder from the 412 // Filter heirarchy is done. 413 bool has_audio_; 414 bool has_video_; 415 416 // The following data members are only accessed by tasks posted to 417 // |message_loop_|. 418 419 // Member that tracks the current state. 420 State state_; 421 422 // Whether we've received the audio/video/text ended events. 423 bool audio_ended_; 424 bool video_ended_; 425 bool text_ended_; 426 427 // Set to true in DisableAudioRendererTask(). 428 bool audio_disabled_; 429 430 // Temporary callback used for Start() and Seek(). 431 PipelineStatusCB seek_cb_; 432 433 // Temporary callback used for Stop(). 434 base::Closure stop_cb_; 435 436 // Permanent callbacks passed in via Start(). 437 base::Closure ended_cb_; 438 PipelineStatusCB error_cb_; 439 BufferingStateCB buffering_state_cb_; 440 base::Closure duration_change_cb_; 441 442 // Contains the demuxer and renderers to use when initializing. 443 scoped_ptr<FilterCollection> filter_collection_; 444 445 // Holds the initialized demuxer. Used for seeking. Owned by client. 446 Demuxer* demuxer_; 447 448 // Holds the initialized renderers. Used for setting the volume, 449 // playback rate, and determining when playback has finished. 450 scoped_ptr<AudioRenderer> audio_renderer_; 451 scoped_ptr<VideoRenderer> video_renderer_; 452 scoped_ptr<TextRenderer> text_renderer_; 453 454 PipelineStatistics statistics_; 455 456 // Time of pipeline creation; is non-zero only until the pipeline first 457 // reaches "kStarted", at which point it is used & zeroed out. 458 base::TimeTicks creation_time_; 459 460 scoped_ptr<SerialRunner> pending_callbacks_; 461 462 base::ThreadChecker thread_checker_; 463 464 DISALLOW_COPY_AND_ASSIGN(Pipeline); 465 }; 466 467 } // namespace media 468 469 #endif // MEDIA_BASE_PIPELINE_H_ 470