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/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 "ui/gfx/size.h" 23 24 namespace base { 25 class SingleThreadTaskRunner; 26 class TimeDelta; 27 } 28 29 namespace media { 30 31 class Clock; 32 class FilterCollection; 33 class MediaLog; 34 class TextRenderer; 35 class TextTrackConfig; 36 class VideoRenderer; 37 38 // Metadata describing a pipeline once it has been initialized. 39 struct PipelineMetadata { PipelineMetadataPipelineMetadata40 PipelineMetadata() : has_audio(false), has_video(false) {} 41 42 bool has_audio; 43 bool has_video; 44 gfx::Size natural_size; 45 base::Time timeline_offset; 46 }; 47 48 typedef base::Callback<void(PipelineMetadata)> PipelineMetadataCB; 49 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. 53 // 54 // Here's a state diagram that describes the lifetime of this object. 55 // 56 // [ *Created ] [ Any State ] 57 // | Start() | Stop() / SetError() 58 // V V 59 // [ InitXXX (for each filter) ] [ Stopping ] 60 // | | 61 // V V 62 // [ InitPrerolling ] [ Stopped ] 63 // | 64 // V 65 // [ Playing ] <-- [ Seeking ] 66 // | ^ 67 // `---------------' 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. 80 class 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() const; 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(); 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 kPlaying, 198 kStopping, 199 kStopped, 200 }; 201 202 // Updates |state_|. All state transitions should use this call. 203 void SetState(State next_state); 204 205 static const char* GetStateString(State state); 206 State GetNextState() const; 207 208 // Helper method that runs & resets |seek_cb_| and resets |seek_timestamp_| 209 // and |seek_pending_|. 210 void FinishSeek(); 211 212 // DemuxerHost implementaion. 213 virtual void AddBufferedTimeRange(base::TimeDelta start, 214 base::TimeDelta end) OVERRIDE; 215 virtual void SetDuration(base::TimeDelta duration) OVERRIDE; 216 virtual void OnDemuxerError(PipelineStatus error) OVERRIDE; 217 virtual void AddTextStream(DemuxerStream* text_stream, 218 const TextTrackConfig& config) OVERRIDE; 219 virtual void RemoveTextStream(DemuxerStream* text_stream) OVERRIDE; 220 221 // Initiates teardown sequence in response to a runtime error. 222 // 223 // Safe to call from any thread. 224 void SetError(PipelineStatus error); 225 226 // Callbacks executed when a renderer has ended. 227 void OnAudioRendererEnded(); 228 void OnVideoRendererEnded(); 229 void OnTextRendererEnded(); 230 231 // Callback executed by filters to update statistics. 232 void OnUpdateStatistics(const PipelineStatistics& stats); 233 234 // Callback executed by audio renderer to update clock time. 235 void OnAudioTimeUpdate(base::TimeDelta time, base::TimeDelta max_time); 236 237 // Callback executed by video renderer to update clock time. 238 void OnVideoTimeUpdate(base::TimeDelta max_time); 239 240 // The following "task" methods correspond to the public methods, but these 241 // methods are run as the result of posting a task to the Pipeline's 242 // task runner. 243 void StartTask(); 244 245 // Stops and destroys all filters, placing the pipeline in the kStopped state. 246 void StopTask(const base::Closure& stop_cb); 247 248 // Carries out stopping and destroying all filters, placing the pipeline in 249 // the kStopped state. 250 void ErrorChangedTask(PipelineStatus error); 251 252 // Carries out notifying filters that the playback rate has changed. 253 void PlaybackRateChangedTask(float playback_rate); 254 255 // Carries out notifying filters that the volume has changed. 256 void VolumeChangedTask(float volume); 257 258 // Carries out notifying filters that we are seeking to a new timestamp. 259 void SeekTask(base::TimeDelta time, const PipelineStatusCB& seek_cb); 260 261 // Handles audio/video/text ended logic and running |ended_cb_|. 262 void DoAudioRendererEnded(); 263 void DoVideoRendererEnded(); 264 void DoTextRendererEnded(); 265 void RunEndedCallbackIfNeeded(); 266 267 // Carries out adding a new text stream to the text renderer. 268 void AddTextStreamTask(DemuxerStream* text_stream, 269 const TextTrackConfig& config); 270 271 // Carries out removing a text stream from the text renderer. 272 void RemoveTextStreamTask(DemuxerStream* text_stream); 273 274 // Kicks off initialization for each media object, executing |done_cb| with 275 // the result when completed. 276 void InitializeDemuxer(const PipelineStatusCB& done_cb); 277 void InitializeAudioRenderer(const PipelineStatusCB& done_cb); 278 void InitializeVideoRenderer(const PipelineStatusCB& done_cb); 279 280 // Kicks off destroying filters. Called by StopTask() and ErrorChangedTask(). 281 // When we start to tear down the pipeline, we will consider two cases: 282 // 1. when pipeline has not been initialized, we will transit to stopping 283 // state first. 284 // 2. when pipeline has been initialized, we will first transit to pausing 285 // => flushing => stopping => stopped state. 286 // This will remove the race condition during stop between filters. 287 void TearDownPipeline(); 288 289 // Compute the time corresponding to a byte offset. 290 base::TimeDelta TimeForByteOffset_Locked(int64 byte_offset) const; 291 292 void OnStateTransition(PipelineStatus status); 293 void StateTransitionTask(PipelineStatus status); 294 295 // Initiates an asynchronous preroll call sequence executing |done_cb| 296 // with the final status when completed. 297 void DoInitialPreroll(const PipelineStatusCB& done_cb); 298 299 // Initiates an asynchronous pause-flush-seek-preroll call sequence 300 // executing |done_cb| with the final status when completed. 301 // 302 // TODO(scherkus): Prerolling should be separate from seeking so we can report 303 // finer grained ready states (HAVE_CURRENT_DATA vs. HAVE_FUTURE_DATA) 304 // indepentent from seeking. 305 void DoSeek(base::TimeDelta seek_timestamp, const PipelineStatusCB& done_cb); 306 307 // Initiates an asynchronous pause-flush-stop call sequence executing 308 // |done_cb| when completed. 309 void DoStop(const PipelineStatusCB& done_cb); 310 void OnStopCompleted(PipelineStatus status); 311 312 void OnAudioUnderflow(); 313 314 // Collection of callback methods and helpers for tracking changes in 315 // buffering state and transition from paused/underflow states and playing 316 // states. 317 // 318 // While in the kPlaying state: 319 // - A waiting to non-waiting transition indicates preroll has completed 320 // and StartPlayback() should be called 321 // - A non-waiting to waiting transition indicates underflow has occurred 322 // and StartWaitingForEnoughData() should be called 323 void BufferingStateChanged(BufferingState* buffering_state, 324 BufferingState new_buffering_state); 325 bool WaitingForEnoughData() const; 326 void StartWaitingForEnoughData(); 327 void StartPlayback(); 328 329 void PauseClockAndStopRendering_Locked(); 330 void StartClockIfWaitingForTimeUpdate_Locked(); 331 332 // Task runner used to execute pipeline tasks. 333 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; 334 335 // MediaLog to which to log events. 336 scoped_refptr<MediaLog> media_log_; 337 338 // Lock used to serialize access for the following data members. 339 mutable base::Lock lock_; 340 341 // Whether or not the pipeline is running. 342 bool running_; 343 344 // Amount of available buffered data as reported by |demuxer_|. 345 Ranges<base::TimeDelta> buffered_time_ranges_; 346 347 // True when AddBufferedTimeRange() has been called more recently than 348 // DidLoadingProgress(). 349 bool did_loading_progress_; 350 351 // Current volume level (from 0.0f to 1.0f). This value is set immediately 352 // via SetVolume() and a task is dispatched on the task runner to notify the 353 // filters. 354 float volume_; 355 356 // Current playback rate (>= 0.0f). This value is set immediately via 357 // SetPlaybackRate() and a task is dispatched on the task runner to notify 358 // the filters. 359 float playback_rate_; 360 361 // base::TickClock used by |clock_|. 362 base::DefaultTickClock default_tick_clock_; 363 364 // Reference clock. Keeps track of current playback time. Uses system 365 // clock and linear interpolation, but can have its time manually set 366 // by filters. 367 scoped_ptr<Clock> clock_; 368 369 enum ClockState { 370 // Audio (if present) is not rendering. Clock isn't playing. 371 CLOCK_PAUSED, 372 373 // Audio (if present) is rendering. Clock isn't playing. 374 CLOCK_WAITING_FOR_AUDIO_TIME_UPDATE, 375 376 // Audio (if present) is rendering. Clock is playing. 377 CLOCK_PLAYING, 378 }; 379 380 ClockState clock_state_; 381 382 // Status of the pipeline. Initialized to PIPELINE_OK which indicates that 383 // the pipeline is operating correctly. Any other value indicates that the 384 // pipeline is stopped or is stopping. Clients can call the Stop() method to 385 // reset the pipeline state, and restore this to PIPELINE_OK. 386 PipelineStatus status_; 387 388 // The following data members are only accessed by tasks posted to 389 // |task_runner_|. 390 391 // Member that tracks the current state. 392 State state_; 393 394 // Whether we've received the audio/video/text ended events. 395 bool audio_ended_; 396 bool video_ended_; 397 bool text_ended_; 398 399 BufferingState audio_buffering_state_; 400 BufferingState video_buffering_state_; 401 402 // Temporary callback used for Start() and Seek(). 403 PipelineStatusCB seek_cb_; 404 405 // Temporary callback used for Stop(). 406 base::Closure stop_cb_; 407 408 // Permanent callbacks passed in via Start(). 409 base::Closure ended_cb_; 410 PipelineStatusCB error_cb_; 411 PipelineMetadataCB metadata_cb_; 412 base::Closure preroll_completed_cb_; 413 base::Closure duration_change_cb_; 414 415 // Contains the demuxer and renderers to use when initializing. 416 scoped_ptr<FilterCollection> filter_collection_; 417 418 // Holds the initialized demuxer. Used for seeking. Owned by client. 419 Demuxer* demuxer_; 420 421 // Holds the initialized renderers. Used for setting the volume, 422 // playback rate, and determining when playback has finished. 423 scoped_ptr<AudioRenderer> audio_renderer_; 424 scoped_ptr<VideoRenderer> video_renderer_; 425 scoped_ptr<TextRenderer> text_renderer_; 426 427 PipelineStatistics statistics_; 428 429 // Time of pipeline creation; is non-zero only until the pipeline first 430 // reaches "kStarted", at which point it is used & zeroed out. 431 base::TimeTicks creation_time_; 432 433 scoped_ptr<SerialRunner> pending_callbacks_; 434 435 base::ThreadChecker thread_checker_; 436 437 DISALLOW_COPY_AND_ASSIGN(Pipeline); 438 }; 439 440 } // namespace media 441 442 #endif // MEDIA_BASE_PIPELINE_H_ 443