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

John Grossman johngro at google.com
Tue Dec 2 03:46:29 CET 2008


ok - do you know a good place to read up on GStreamer's design patterns when
it comes to asynchronous state changing?  The application and plugin
development handbooks don't seem to cover the topic in much detail.

peace
-john

On Mon, Dec 1, 2008 at 6:26 PM, Eric Zhang <nicolas.m.zhang at gmail.com>wrote:

> 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
> server.
>
> 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?
>>
>> 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
>>>
>>
>>
>> -------------------------------------------------------------------------
>> 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
>>
>>
>
> -------------------------------------------------------------------------
> 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/20081201/1c10a5ce/attachment.htm>


More information about the gstreamer-devel mailing list