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

John Grossman johngro at google.com
Wed Nov 26 04:28:35 CET 2008


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/20081125/ec6b3c64/attachment.htm>


More information about the gstreamer-devel mailing list