[gst-devel] State issues for Bins

Erik Walthinsen omega at cse.ogi.edu
Thu Nov 23 04:00:25 CET 2000

On Wed, 22 Nov 2000, Wim Taymans wrote:

> > Do we want to generate the plan before or after getting all the children
> > set?  I would think that a plan may be dependent on the prepared state of
> > the children, so I would vote for after. 
> So, state change is the most important thing and we might better do it
> first.
Agreed.  I'll change that.

> > Does the order matter when setting the children?  Currently it follows
> > the order they were added, but I think the order should be derived
> > from the connection order.  Which end it should start from I'm not
> > sure.  This begs the next question. 
> You cannot always know the connection order since some elements will be
> connected while the pipeline is running, when new pads are created by an
> element because of the media types, eg.

> You might also not want to set the state of an element that is not yet
> connected to any other element because it is not yet needed. The downside
> of the delayed state change is that it has to be performed at runtime which
> can introduce serious delays if the element has to perform a complex state
> change (CORBA connect for example).
That makes sense, but that's an argument *for* traversing the pipeline in
some order to pick which to set state on.  As for elements with nasty
state-change stuff, I think we might eventually have a set of Bins that
are smart enough to actually spawn a new thread for elements like that.

> So generally, I don't think the order should be of any importance. I just
> can't imagine what we are supposed to do if, for example, the fifth element
> fails to set its state... The state change of the pipeline either fails
> or succeeds, it is up to the application to decide what to do with it. 
> I might be wrong here though...
Yeah, this is the hardest of the problems to be solved.

> > Do we want to have states travel up or down the pipeline at all?  We
> > could make this an option, in the form of a special buffer flag that
> > causes the system to try to set the state of an element before the
> > buffer is pushed or pulled.  This could be useful, but would have a
> > constant drag on normal operations even if never used.  (this could be
> > mitigated by having single test for a cluster of such bits, though how
> > many such bits there might be is questionable) 

> You could also do this without a buffer flag. When an element pushes or
> pulls a buffer, we could see if the nearby element is in a given state.
> If it isn't, we change its state. 
But this would either set all elements to a hardcoded state (probably
PLAYING), or force the element to take on the state of the neighbor in
question.  The latter could turn into a pretty nasty state flap as per the
scheduler in certain situations.

> I don't think it is a good idea to atach the state change to a buffer. I
> would limit the flags on the buffer to be related to media data/events
> (EOS, DISCONTINUITY, FLUSH, ...). State and quality control should be
> dealt with seperately, I feel.
Yeah, I tend to agree.

> > Do we want to simplify the state-change process for elements by having
> > gst_element_set_state restrict state changes to one level at a time?  If
> > you tell something to go from NULL to PAUSED, it could simply loop 
> > setting the state to READY, then PLAYING, then PAUSED, each time
> > moving only one level.  This would simplify most element's state
> > handler. 
> Yes.
OK, I'll go make that change.

> > How do we deal with failed state changes?  Do we revert the entire Bin
> > back to the state we last attained (the above change would make that more
> > sane, too).  Or do we simply leave things the way they are and return
> > FAILED? 
> Rollback would be nice, if possible. Can we rollback any element?
That's either how it is or how it was at one point.  What do you mean by
the last question?

> > How do we deal with ASYNC returns from state changes?  The only place we
> > use this so far is in the thread code, where a state change requires an
> > acknowledgement from the thread itself.  It's highly broken right now,
> > since the thread never sets the state.  
> ...
> This would solve some problem we have right now, mainly the delay
> introduced by the cleate_plan function. We would also have the thread
> (really) ready after the NULL->READY state change. It would also be more
> consistent with the bin doing the create_plan in the NULL->READY state.
> The READY->PLAYING state change would become pretty fast, and it would
> be easier to start the threads in sync.
I though that create_plan was always called by the Bin's change_state()
function.  Since things are chained, the Thread's change_state() will
defer to the Bin's method first, and see if that succeeded.  If it did, it
goes and sets things up.  I noticed, however, that the thread code doesn't
understand GST_STATE_FAILURE or GST_STATE_SUCCESS, just true/false.  This
has to be fixed.

> > As they come back changed, the count drops towards zero, then finally the
> > Bin's state is set.  This means locking the count. 
> Does the change_state() return _after_ all the ASYNC replies are 
> received or does it also become an ASYNC element when it has ASYNC
> elements in it? The programmer has to attach a callback to the bin in
> this last case, which may be a bit awkward.
That's the question.  I'd lean towards having it make itself ASYNC, since
depending on what it is that goes ASYNC and why, it may deadlock.  I
suppose we can make the stipulation that an time an ASYNC is returned, the
event that completes the state change is must always be in a different
context (i.e. thread).  An option would be to provide a _sync version of
set_state that wraps the main set_state and deals with the ASYNC case.
That would make life easier for simpler projects.

In the full ASYNC case, the application would be responsible for checking
back with the Bin to make sure the state change occurs.  If you use the
_sync method, it would set up callbacks state_change on each ASYNC
element, with a count protected by a mutex/condition variable.  When the
count reaches zero, the _sync method returns.

> OTOH, do we really need ASYNC state changes. Technically we can make all
> state changes blocking. The downside of this is that you cannot
> change_state() many ASYNC elements in parallel.
Right.  Making each element responsible for waiting until something
finishes in order for state change to occur is not such a good idea,
unless everything is already asynchronous, which is pretty hard to do.

         Erik Walthinsen <omega at cse.ogi.edu> - Staff Programmer @ OGI
        Quasar project - http://www.cse.ogi.edu/DISC/projects/quasar/
   Video4Linux Two drivers and stuff - http://www.cse.ogi.edu/~omega/v4l2/
       /  \             SEUL: Simple End-User Linux - http://www.seul.org/
      |    | M E G A           Helping Linux become THE choice
      _\  /_                          for the home or office user

More information about the gstreamer-devel mailing list