Question about async state changes..

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Question about async state changes..

John Grossman

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
[hidden email]
https://lists.sourceforge.net/lists/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Question about async state changes..

John Grossman
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 <[hidden email]> 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
[hidden email]
https://lists.sourceforge.net/lists/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Question about async state changes..

Eric Zhang-6
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 <[hidden email]>
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 <[hidden email]> 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
[hidden email]
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
[hidden email]
https://lists.sourceforge.net/lists/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Question about async state changes..

John Grossman
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 <[hidden email]> 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 <[hidden email]>
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 <[hidden email]> 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
[hidden email]
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
[hidden email]
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
[hidden email]
https://lists.sourceforge.net/lists/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Question about async state changes..

Eric Zhang-6
Hi, gstreamer-devel:
 
    These docs may be a good start:
 
    <gstreamer root directory>/docs/design/part-element-sink.txt
    <gstreamer root directory>/docs/design/part-preroll.txt
    <gstreamer root directory>/docs/design/part-states.txt
    <gstreamer root directory>/docs/design/part-element-source.txt
 
    Unfortunately, these docs are not step by step tutorials. Actually, they are some keypoints in gstreamer design. So, I think you will have more questions after reading these, at that time, read the source codes directly.
 
Eric Zhang
2008/12/2 John Grossman <[hidden email]>
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 <[hidden email]> 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 <[hidden email]>
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 <[hidden email]> 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
[hidden email]
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
[hidden email]
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
[hidden email]
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
[hidden email]
https://lists.sourceforge.net/lists/listinfo/gstreamer-devel