Discussion:
[gst-devel] why/when are state changes needed in dynamically modified pipelines?
Daniel Lenski
2007-09-12 13:47:47 UTC
Permalink
Okay... sorry to keep up the annoying questions everyone :-) I've
(finally) narrowed down the bug in my auto-transcoder to the
following question:

When and why are state changes needed in dynamic pipeline creation?

In the GStreamer manual (this page:
http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/section-dynamic.html),
the sample code dynamically adds an element to the pipeline. It sets
the element's state to READY immediately before linking it to the
previously existing element, and then sets it to PAUSED immediately
afterwards:

if (sinkelement != audiosink) {
gst_bin_add (GST_BIN (pipeline), sinkelement);
gst_element_set_state (sinkelement, GST_STATE_READY);
}
pad = gst_element_get_pad (sinkelement, padname);
gst_pad_link (srcpad, pad);
if (sinkelement != audiosink) {
gst_element_set_state (sinkelement, GST_STATE_PAUSED);
}

Why is this necessary?

I've found it only (seems to be) needed with the decodebin element,
and then only sometimes... for some stream types things apparently
work without it. In my python code I do this:

# bin contains a typefind already... we're in it's have-type handler

decodebin = gst.element_factory_make('decodebin')
bin.add(decodebin)
convert = gst.element_factory_make('audioconvert')
bin.add(convert)
# add a bunch more elements after the decodebin...

# set up callback to dynamically link decodebin to the following element
decodebin.connect('new-decoded-pad', self.new_decoded_pad,
convert.get_pad('sink'))

bin.set_state(gst.STATE_READY) # put the bin, with new elements,
into READY state
bin.typefind.link(decodebin) # link the typefind to the new decodebin element
gst.element_link_many(convert, ...) # link the rest of the elements
together...
self.set_state(gst.STATE_PAUSED) # put the bin into PAUSED state

So, I see that I can make my code work reliably by linking newly added
elements only after having put them into the READY state. But I still
don't understand the rationale for this. The manual doesn't really
explain when state changes are needed for dynamically modified
pipeines. Can someone explain to me how to figure this out??

Thanks!

Dan Lenski
Andy Wingo
2007-09-12 22:35:58 UTC
Permalink
Hi,
Post by Daniel Lenski
When and why are state changes needed in dynamic pipeline creation?
You want points at which you know what the status of dataflow is.

In READY you know that no data is flowing; you can always link things
then.

For some pipelines, however, all of the state is not ready in READY, as
with decodebin. However you know that within a pad-added signal that
the signal is coming from the streaming thread, so you know what the
state of dataflow is (blocked in the callback for the signal).

You can know what the dataflow status is in PLAYING if you block pads,
either synchronously or asynchronously and wait for the callback. In
that case you can link/unlink in PLAYING.

Linking/unlinking without blocking, in PLAYING, is racy, and you
shouldn't do it; it might work sometimes, or the pipeline might error
out. It should not crash GStreamer, however.

HTH,

Andy.
--
http://wingolog.org/
Daniel Lenski
2007-09-13 04:26:06 UTC
Permalink
Post by Andy Wingo
Hi,
Post by Daniel Lenski
When and why are state changes needed in dynamic pipeline creation?
You want points at which you know what the status of dataflow is.
In READY you know that no data is flowing; you can always link things
then.
Thank you, Andy! This is very helpful. So, as a novice, I can
reliably create dynamic streams as long as I place them into the READY
state before linking in the new elements? Why is it that after
linking the those new elements, I can put the stream into either
PAUSED or PLAYING state... with the same effect apparently?
Post by Andy Wingo
For some pipelines, however, all of the state is not ready in READY, as
with decodebin. However you know that within a pad-added signal that
the signal is coming from the streaming thread, so you know what the
state of dataflow is (blocked in the callback for the signal).
And decodebin's state is not ready in READY because it is itself a
dynamically constructed bin, if I understand correctly, so it has to
wait for data to flow through its typefind element until it fully sets
up its state. Is the dataflow for the whole pipeline automatically
blocked for the duration of the callback, and restored afterwards?

So, the signal is called in the context of the streaming thread...
sometimes in my non-working versions of this program, I've gotten
warning messages saying "can't change the state of the pipeline from
its streaming thread."
Post by Andy Wingo
You can know what the dataflow status is in PLAYING if you block pads,
either synchronously or asynchronously and wait for the callback. In
that case you can link/unlink in PLAYING.
Linking/unlinking without blocking, in PLAYING, is racy, and you
shouldn't do it; it might work sometimes, or the pipeline might error
out. It should not crash GStreamer, however.
Good to know. It has not crashed at all for me, the worst that
happens is the pipeline refuses to continue playing... I wasn't able
to track down the particular element or pad causing the problem.
Post by Andy Wingo
HTH,
Andy.
Indeed it does! Sounds like I will be able to reliably work with
dynamic pipelines as long as I set them to READY state before
modifying them. And I figure out more of the details as I learn.

Thanks,
Dan
Andy Wingo
2007-09-14 21:10:23 UTC
Permalink
Post by Daniel Lenski
Post by Andy Wingo
In READY you know that no data is flowing; you can always link things
then.
Thank you, Andy! This is very helpful. So, as a novice, I can
reliably create dynamic streams as long as I place them into the READY
state before linking in the new elements? Why is it that after
linking the those new elements, I can put the stream into either
PAUSED or PLAYING state... with the same effect apparently?
Not very dynamic if you go to READY; in addition to stopping streaming,
it resets most codecs' internal state, resets the stream time, closes
devices, etc.

If you want to modify a pipeline as it is running, you will have to
become friendly with gst_pad_set_blocked_async.

Cheers,

Andy.
--
http://wingolog.org/
Loading...