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