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 "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" 22 23namespace base { 24class SingleThreadTaskRunner; 25class TimeDelta; 26} 27 28namespace media { 29 30class MediaLog; 31class Renderer; 32class TextRenderer; 33class TextTrackConfig; 34class TimeDeltaInterpolator; 35 36// Metadata describing a pipeline once it has been initialized. 37struct PipelineMetadata { 38 PipelineMetadata() 39 : has_audio(false), has_video(false), video_rotation(VIDEO_ROTATION_0) {} 40 41 bool has_audio; 42 bool has_video; 43 gfx::Size natural_size; 44 VideoRotation video_rotation; 45 base::Time timeline_offset; 46}; 47 48typedef 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// [ Playing ] <-- [ Seeking ] [ Stopped ] 63// | ^ 64// `---------------' 65// Seek() 66// 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 72// playing the media. 73// 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 76// "Stopped" state. 77class MEDIA_EXPORT Pipeline : public DemuxerHost { 78 public: 79 // Constructs a media pipeline that will execute on |task_runner|. 80 Pipeline(const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, 81 MediaLog* media_log); 82 virtual ~Pipeline(); 83 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. 86 // 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); 110 111 // Asynchronously stops the pipeline, executing |stop_cb| when the pipeline 112 // teardown has completed. 113 // 114 // Stop() must complete before destroying the pipeline. It it permissible to 115 // call Stop() at any point during the lifetime of the pipeline. 116 // 117 // It is safe to delete the pipeline during the execution of |stop_cb|. 118 void Stop(const base::Closure& stop_cb); 119 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. 122 // 123 // Clients are expected to call GetMediaTime() to check whether the seek 124 // succeeded. 125 // 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); 128 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 131 // the pipeline. 132 bool IsRunning() const; 133 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; 139 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. 143 // 144 // TODO(scherkus): What about maximum rate? Does HTML5 specify a max? 145 void SetPlaybackRate(float playback_rate); 146 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; 151 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); 156 157 // Returns the current media playback time, which progresses from 0 until 158 // GetMediaDuration(). 159 base::TimeDelta GetMediaTime() const; 160 161 // Get approximate time ranges of buffered media. 162 Ranges<base::TimeDelta> GetBufferedTimeRanges() const; 163 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; 167 168 // Return true if loading progress has been made since the last time this 169 // method was called. 170 bool DidLoadingProgress(); 171 172 // Gets the current pipeline statistics. 173 PipelineStatistics GetStatistics() const; 174 175 void SetErrorForTesting(PipelineStatus status); 176 bool HasWeakPtrsForTesting() const; 177 178 private: 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; 183 184 // Pipeline states, as described above. 185 enum State { 186 kCreated, 187 kInitDemuxer, 188 kInitRenderer, 189 kSeeking, 190 kPlaying, 191 kStopping, 192 kStopped, 193 }; 194 195 // Updates |state_|. All state transitions should use this call. 196 void SetState(State next_state); 197 198 static const char* GetStateString(State state); 199 State GetNextState() const; 200 201 // Helper method that runs & resets |seek_cb_| and resets |seek_timestamp_| 202 // and |seek_pending_|. 203 void FinishSeek(); 204 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; 213 214 // Callback executed when a rendering error happened, initiating the teardown 215 // sequence. 216 void OnError(PipelineStatus error); 217 218 // Callback executed by filters to update statistics. 219 void OnUpdateStatistics(const PipelineStatistics& stats); 220 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 223 // task runner. 224 void StartTask(); 225 226 // Stops and destroys all filters, placing the pipeline in the kStopped state. 227 void StopTask(const base::Closure& stop_cb); 228 229 // Carries out stopping and destroying all filters, placing the pipeline in 230 // the kStopped state. 231 void ErrorChangedTask(PipelineStatus error); 232 233 // Carries out notifying filters that the playback rate has changed. 234 void PlaybackRateChangedTask(float playback_rate); 235 236 // Carries out notifying filters that the volume has changed. 237 void VolumeChangedTask(float volume); 238 239 // Carries out notifying filters that we are seeking to a new timestamp. 240 void SeekTask(base::TimeDelta time, const PipelineStatusCB& seek_cb); 241 242 // Callbacks executed when a renderer has ended. 243 void OnRendererEnded(); 244 void OnTextRendererEnded(); 245 void RunEndedCallbackIfNeeded(); 246 247 scoped_ptr<TextRenderer> CreateTextRenderer(); 248 249 // Carries out adding a new text stream to the text renderer. 250 void AddTextStreamTask(DemuxerStream* text_stream, 251 const TextTrackConfig& config); 252 253 // Carries out removing a text stream from the text renderer. 254 void RemoveTextStreamTask(DemuxerStream* text_stream); 255 256 // Callbacks executed when a text track is added. 257 void OnAddTextTrack(const TextTrackConfig& config, 258 const AddTextTrackDoneCB& done_cb); 259 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); 264 265 void OnStateTransition(PipelineStatus status); 266 void StateTransitionTask(PipelineStatus status); 267 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); 271 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); 276 277 void ReportMetadata(); 278 279 void BufferingStateChanged(BufferingState new_buffering_state); 280 281 // Task runner used to execute pipeline tasks. 282 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; 283 284 // MediaLog to which to log events. 285 scoped_refptr<MediaLog> media_log_; 286 287 // Lock used to serialize access for the following data members. 288 mutable base::Lock lock_; 289 290 // Whether or not the pipeline is running. 291 bool running_; 292 293 // Amount of available buffered data as reported by |demuxer_|. 294 Ranges<base::TimeDelta> buffered_time_ranges_; 295 296 // True when AddBufferedTimeRange() has been called more recently than 297 // DidLoadingProgress(). 298 bool did_loading_progress_; 299 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 302 // filters. 303 float volume_; 304 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 307 // the filters. 308 float playback_rate_; 309 310 // Current duration as reported by |demuxer_|. 311 base::TimeDelta duration_; 312 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_; 318 319 // The following data members are only accessed by tasks posted to 320 // |task_runner_|. 321 322 bool is_initialized_; 323 324 // Member that tracks the current state. 325 State state_; 326 327 // The timestamp to start playback from after starting/seeking has completed. 328 base::TimeDelta start_timestamp_; 329 330 // Whether we've received the audio/video/text ended events. 331 bool renderer_ended_; 332 bool text_renderer_ended_; 333 334 // Temporary callback used for Start() and Seek(). 335 PipelineStatusCB seek_cb_; 336 337 // Temporary callback used for Stop(). 338 base::Closure stop_cb_; 339 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_; 347 348 // Holds the initialized demuxer. Used for seeking. Owned by client. 349 Demuxer* demuxer_; 350 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_; 355 356 PipelineStatistics statistics_; 357 358 scoped_ptr<SerialRunner> pending_callbacks_; 359 360 base::ThreadChecker thread_checker_; 361 362 // NOTE: Weak pointers must be invalidated before all other member variables. 363 base::WeakPtrFactory<Pipeline> weak_factory_; 364 365 DISALLOW_COPY_AND_ASSIGN(Pipeline); 366}; 367 368} // namespace media 369 370#endif // MEDIA_BASE_PIPELINE_H_ 371