[gst-devel] Question about async state changes..

John Grossman johngro at google.com
Mon Dec 1 19:05:51 CET 2008


bump...

Still looking for some help with this issue; does anyone have an idea of
what might be going on?  Alternatively, does anyone know of a good example
of how to properly implement an element which performs async state changes
which I could use to set myself straight?

TIA

peace
-john

On Tue, Nov 25, 2008 at 7:28 PM, John Grossman <johngro at google.com> wrote:

>
> Hello, my name is John and I am a developer currently working on writing a
> gstreamer plugin to act as a source element.  I'm having some trouble with
> async state changes and I was hoping that someone on this list could provide
> some insight.  Basically, my element needs to make the transition from NULL
> to READY asynchronously.  After my element has transitioned to READY,
> downstream elements expect me to answer questions like, "how long is the
> source in bytes".  I am actually fetching the source over a network, but I
> want to provide a pull interface to make file oriented demux elements
> happy.  It will take me some time to get this information from the network
> so it is important for me to make the transition asynchronously.
>
> I have overridden the change_state, get_state and set_state methods of my
> element so that I can have some control over the process.  My change state
> just calls to the base element's change_state for any transition except for
> NULL_TO_READY.  When I see the NULL_TO_READY change, I kick off my network
> fetch and return GST_STATE_CHANGE_ASYNC.
>
> My set state method always calls the base element's set_state; I pretty
> much just have it hooked so that I can see what the base element is
> returning to the rest of the framework.
>
> My get_state implementation will return the base element's get_state,
> unless I am in an asynchronous transition from NULL to READY.  In this case,
> it waits for the signal from the rest of my code that has managed to fetch
> the required info from the network.  If the get times out, it will return
> ASYNC again.  If something goes wrong fetching the file over the net, it
> will return FAILURE, and if everything went well it will return SUCCESS (and
> my element should officially be in the READY state).
>
> Unfortunately, things do not seem to be working as I expected.  Even though
> I return ASYNC at the appropriate time in my implementation of change_state,
> the base implementation of set_state is simply returning SUCCESS.  I am
> working with the 0.10.21 version of GStreamer, and I think I have tracked
> the issue down to the implementation of gst_element_change_state in
> gstelement.c at line 2412.  This function calls my implementation of
> change_state and then switches on the return value I give back.  The handler
> for GST_STATE_CHANGE_ASYNC looks like the following...
>
> case GST_STATE_CHANGE_ASYNC:
> {
>   GstState target;
>
>   GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
>       "element will change state ASYNC");
>
>   target = GST_STATE_TARGET (element);
>
>   if (target > GST_STATE_READY)
>     goto async;
>
>   /* else we just continue the state change downwards */
>   GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
>       "forcing commit state %s <= %s",
>       gst_element_state_get_name (target),
>       gst_element_state_get_name (GST_STATE_READY));
>
>   ret = gst_element_continue_state (element, GST_STATE_CHANGE_SUCCESS);
>   break;
> }
>
> Essentially, what seems to be killing me is the "if (target >
> GST_STATE_READY) statement".  The system is attempting to go from NULL to
> READY, and this line seems to be saying that asynchronous transitions can
> only be made if the target state is either PAUSED or PLAYING.  (BTW - I am
> seeing both the "element will change state ASYNC" and the "forcing commit
> state" messages in my debug logs).  I couldn't make sense of the comment
> following the if statement so I did some research in the CVS archives to see
> if I could track down where this if statement came from.  You can check out
> the diffs here
>
> http://webcvs.freedesktop.org/gstreamer/gstreamer/gst/gstelement.c?r1=1.448&r2=1.449
> but to save you some time, here is what the code used to look like (about
> 20 months ago)
>
> case GST_STATE_CHANGE_ASYNC:
>    GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
>        "element will change state ASYNC");
>
>    /* if we go upwards, we give the app a change to wait for
>     * completion */
>    if (current < next)
>      goto async;
>
>    /* else we just continue the state change downwards */
>    GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
>        "forcing commit state %s < %s",
>        gst_element_state_get_name (current),
>        gst_element_state_get_name (next));
>
>    ret = gst_element_continue_state (element, GST_STATE_CHANGE_SUCCESS);
>    break;
>
> Essentially, it looked like the code used to allow async state changes
> while moving up in the state sequence, but not while moving down.  I suspect
> this was to prevent element from blocking shutdown by never completing their
> state changes.  With the code change present in 1.449, it looks like
> elements are allowed to make an async state change to either PLAYING or
> PAUSED, but not if their target is NULL or READY.
>
> This is where I get confused...  If I had set the target state of my
> pipeline directly to PLAYING instead of just READY, it looks like this code
> would have allowed me to make the async change from NULL to READY.  So if
> the purpose of this code is to force the change from NULL to READY to be
> synchronous, it seems like there are ways of wiggling around it.
>
> If the behavior of this code was supposed to be the same as before
> (allowing async in the up direction instead of down), then it seems like "if
> (current < target)" is the appropriate change, instead of "if (target >
> READY)".
>
> It has also occurred to me that the intention might have been to allow
> async changes in both directions instead of just up, but not if the target
> state is set to NULL (in which case the pipeline is tearing down and should
> do so with all haste).  If that is the case, then the if statement present
> here might just have a typo ("if (target > GST_STATE_READY)" instead of "if
> (target >= GST_STATE_READY)")
>
> Does anyone know what the intention was here?  If the intent was to
> actually prevent elements from transitioning from NULL to READY
> asynchronously, then does anyone know how I should be approaching my problem
> instead?  I suppose I could build my graph by adding just my source element,
> setting it to ready, and then waiting for a bus message from the async part
> of my element indicating that it has fetched the initial data.  That really
> didn't seem to be in the spirit of things, however, since it would mean that
> my application needed to be aware of my source's particular requirements.
>
> Thanks in advance for any help anyone out there can provide.
>
> -john
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/gstreamer-devel/attachments/20081201/fc8c7c7a/attachment.htm>


More information about the gstreamer-devel mailing list