From: Erik W. <om...@cs...> - 2000-11-22 08:57:59
|
I'm working up a list of issues, here's the first set: Bins: 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. 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. 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) 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. 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? 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. My plan was to make use signals, but the question of context comes up, and thus thread safety. The general idea is that the Bin's change_state() will attach a callback to the change_state signal of the any element that says ASYNC, and keep a count. As they come back changed, the count drops towards zero, then finally the Bin's state is set. This means locking the count. Erik Walthinsen <om...@cs...> - 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 |
From: Wim T. <wim...@ch...> - 2000-11-22 18:38:19
|
On Wed, 22 Nov 2000 09:57:57 Erik Walthinsen wrote: > I'm working up a list of issues, here's the first set: > > Bins: > > 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. I'm not sure how the plan would be any different if one of the children failed to set its state, I would guess that if the child failed to set its state, we would be in an error condition. I could however imagine that if a child fails, the plan could be different by not including the child in the pipeline or somesuch, so create_plan should be done after the state change. Anyway, are we going to run this crippled pipeline? So, state change is the most important thing and we might better do it first. > > 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). 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... > > 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. 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. > > 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. > > 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? > > 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. Yes, something is wrong. Actually, the thread does change its state, but not ASYNC as it says with its GstElementStateReturn value and it is not depending on the success of the actual state change of its children, it always succeeds. > My plan was to make use signals, > but the question of context comes up, and thus thread safety. The > general > idea is that the Bin's change_state() will attach a callback to the > change_state signal of the any element that says ASYNC, and keep a count. That will do fine I think. The ASYNC thread state change would currently only happen when going from READY to PLAYING. We should probably change this ASYNC behaviour to the NULL->READY state. so for the threads we have: currently: NULL->READY: create the thread, delay create_plan READY->PLAYING: start the thread (unlock mutex) create_plan and play (ASYNC). better: NULL->READY: create the thread, start the thread, create plan (ASYNC) READY->PLAYING: unlock mutex to start playing 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. > > 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. 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. Just my 0,2 EUR Wim > > > Erik Walthinsen <om...@cs...> - 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 > > _______________________________________________ > gstreamer-devel mailing list > gst...@li... > http://lists.sourceforge.net/mailman/listinfo/gstreamer-devel > -- You're dead, Jim. -- McCoy, "The Tholian Web", stardate unknown |
From: Wim T. <wim...@ch...> - 2000-11-22 22:37:43
|
On Wed, 22 Nov 2000 19:46:56 Wim Taymans wrote: > > That will do fine I think. The ASYNC thread state change would currently > only happen when going from READY to PLAYING. We should probably change > this > ASYNC behaviour to the NULL->READY state. so for the threads we have: > > currently: > > NULL->READY: create the thread, delay create_plan > READY->PLAYING: start the thread (unlock mutex) create_plan and play > (ASYNC). > > better: > > NULL->READY: create the thread, start the thread, create plan (ASYNC) > READY->PLAYING: unlock mutex to start playing > Forget about this better solution: we allready have it. I rechecked :-) The problem of not setting the state correctly is present though. Since we do not block on the state change, it is theoretically possible to proceed to the PLAYING state while the ASYNC READY state change is not yet completed. -- The true way goes over a rope which is not stretched at any great height but just above the ground. It seems more designed to make people stumble than to be walked upon. -- Franz Kafka |
From: Erik W. <om...@cs...> - 2000-11-23 03:00:36
|
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. True. > 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 <om...@cs...> - 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 |