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

Eric Zhang nicolas.m.zhang at gmail.com
Tue Dec 2 03:26:20 CET 2008

Hi, gstreamer-devel:

    Basically, in gstreamer, ASYNC state changing is used by sink elements
to perform preroll. So let source element performs a ASYNC state change is
not a good idea.

    And the ASYNC state changing typically happens during READY->PAUSED
while not NULL->READY.

    So my opinion is you'd better think your design again to try to follow
the gstreamer's design patterns. If your source element want to fetch
something in network -- just do it, there is no need to return ASYNC. For
example, I am working on rtsp/rtp stuffs now and the rtspsrc will do a lot
of works during NULL->READY and READY->PAUSED to communicate with RTSP

Eric Zhang

2008/12/2 John Grossman <johngro at google.com>

> 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?
> 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...
>> {
>>   GstState target;
>>       "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 */
>>       "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)
>>        "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 */
>>        "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
> -------------------------------------------------------------------------
> This SF.Net email is sponsored by the Moblin Your Move Developer's
> challenge
> Build the coolest Linux based applications with Moblin SDK & win great
> prizes
> Grand prize is a trip for two to an Open Source event anywhere in the world
> http://moblin-contest.org/redirect.php?banner_id=100&url=/
> _______________________________________________
> gstreamer-devel mailing list
> gstreamer-devel at lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/gstreamer-devel
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/gstreamer-devel/attachments/20081202/18389176/attachment.htm>

More information about the gstreamer-devel mailing list