summaryrefslogtreecommitdiffstats
path: root/media/base/pipeline_impl.h
diff options
context:
space:
mode:
Diffstat (limited to 'media/base/pipeline_impl.h')
-rw-r--r--media/base/pipeline_impl.h98
1 files changed, 71 insertions, 27 deletions
diff --git a/media/base/pipeline_impl.h b/media/base/pipeline_impl.h
index 1050ef1..4eed436 100644
--- a/media/base/pipeline_impl.h
+++ b/media/base/pipeline_impl.h
@@ -23,22 +23,40 @@ namespace media {
// PipelineImpl runs the media pipeline. Filters are created and called on the
// message loop injected into this object. PipelineImpl works like a state
-// machine to perform asynchronous initialization. Initialization is done in
-// multiple passes by InitializeTask(). In each pass a different filter is
-// created and chained with a previously created filter.
+// machine to perform asynchronous initialization, pausing, seeking and playing.
//
// Here's a state diagram that describes the lifetime of this object.
//
-// [ *Created ] -> [ InitDataSource ] -> [ InitDemuxer ] ->
-// [ InitAudioDecoder ] -> [ InitAudioRenderer ] ->
-// [ InitVideoDecoder ] -> [ InitVideoRenderer ] -> [ Started ]
-// | | |
-// .-> [ Error ] .-> [ Stopped ] <-.
+// [ *Created ]
+// | Start()
+// V
+// [ InitXXX (for each filter) ]
+// |
+// V
+// [ Seeking (for each filter) ] <----------------------.
+// | |
+// V |
+// [ Starting (for each filter) ] |
+// | |
+// V Seek() |
+// [ Started ] --------> [ Pausing (for each filter) ] -'
//
-// Initialization is a series of state transitions from "Created" to
-// "Started". If any error happens during initialization, this object will
-// transition to the "Error" state from any state. If Stop() is called during
-// initialization, this object will transition to "Stopped" state.
+//
+// SetError()
+// [ Any State ] -------------> [ Error ]
+// | Stop()
+// '--------------------> [ Stopped ]
+//
+// Initialization is a series of state transitions from "Created" through each
+// filter initialization state. When all filter initialization states have
+// completed, we are implicitly in a "Paused" state. At that point we simulate
+// a Seek() to the beginning of the media to give filters a chance to preroll.
+// From then on the normal Seek() transitions are carried out and we start
+// playing the media.
+//
+// If any error ever happens, this object will transition to the "Error" state
+// from any state. If Stop() is ever called, this object will transition to
+// "Stopped" state.
class PipelineImpl : public Pipeline, public FilterHost {
public:
explicit PipelineImpl(MessageLoop* message_loop);
@@ -65,6 +83,23 @@ class PipelineImpl : public Pipeline, public FilterHost {
virtual PipelineError GetError() const;
private:
+ // Pipeline states, as described above.
+ enum State {
+ kCreated,
+ kInitDataSource,
+ kInitDemuxer,
+ kInitAudioDecoder,
+ kInitAudioRenderer,
+ kInitVideoDecoder,
+ kInitVideoRenderer,
+ kPausing,
+ kSeeking,
+ kStarting,
+ kStarted,
+ kStopped,
+ kError,
+ };
+
virtual ~PipelineImpl();
// Reset the state of the pipeline object to the initial state. This method
@@ -77,6 +112,13 @@ class PipelineImpl : public Pipeline, public FilterHost {
// Helper method to tell whether we are in the state of initializing.
bool IsPipelineInitializing();
+ // Returns true if the given state is one that transitions to the started
+ // state.
+ static bool StateTransitionsToStarted(State state);
+
+ // Given the current state, returns the next state.
+ static State FindNextState(State current);
+
// FilterHost implementation.
virtual void SetError(PipelineError error);
virtual base::TimeDelta GetTime() const;
@@ -94,9 +136,11 @@ class PipelineImpl : public Pipeline, public FilterHost {
// Method called during initialization to determine if we rendered anything.
bool HasRenderedMimeTypes() const;
- // Callback executed by filters upon completing initialization and seeking.
+ // Callback executed by filters upon completing initialization.
void OnFilterInitialize();
- void OnFilterSeek();
+
+ // Callback executed by filters upon completing Play(), Pause() or Seek().
+ void OnFilterStateTransition();
// The following "task" methods correspond to the public methods, but these
// methods are run as the result of posting a task to the PipelineInternal's
@@ -128,6 +172,9 @@ class PipelineImpl : public Pipeline, public FilterHost {
// Carries out notifying filters that we are seeking to a new timestamp.
void SeekTask(base::TimeDelta time, PipelineCallback* seek_callback);
+ // Carries out advancing to the next filter during Play()/Pause()/Seek().
+ void FilterStateTransitionTask();
+
// Internal methods used in the implementation of the pipeline thread. All
// of these methods are only called on the pipeline thread.
@@ -246,20 +293,18 @@ class PipelineImpl : public Pipeline, public FilterHost {
// |message_loop_|.
// Member that tracks the current state.
- enum State {
- kCreated,
- kInitDataSource,
- kInitDemuxer,
- kInitAudioDecoder,
- kInitAudioRenderer,
- kInitVideoDecoder,
- kInitVideoRenderer,
- kStarted,
- kStopped,
- kError,
- };
State state_;
+ // For kPausing, kSeeking and kStarting, we need to track how many filters
+ // have completed transitioning to the destination state. When
+ // |remaining_transitions_| reaches 0 the pipeline can transition out
+ // of the current state.
+ size_t remaining_transitions_;
+
+ // For kSeeking we need to remember where we're seeking between filter
+ // replies.
+ base::TimeDelta seek_timestamp_;
+
// Filter factory as passed in by Start().
scoped_refptr<FilterFactory> filter_factory_;
@@ -267,7 +312,6 @@ class PipelineImpl : public Pipeline, public FilterHost {
std::string url_;
// Callbacks for various pipeline operations.
- scoped_ptr<PipelineCallback> start_callback_;
scoped_ptr<PipelineCallback> seek_callback_;
scoped_ptr<PipelineCallback> stop_callback_;