Posted on November 3, 2006 - by jono
GStreamer Dynamic Pads, Explained
(for an intro to GStreamer, see my previous article)
You know, one thing that gets people confused in GStreamer is the idea of Dynamic Pads. Some elements, most notably the decodebin and gnlcomposition only have certain pads at certain times. This is because they figure out what kind of content they are processing, and apply the relevant pads where needed. This is often told to new users, but then they wonder how exactly these dynamic pads are handled.
Here is how it works, using decodebin as an example:
- When the pipeline is run, the
decodebingenerates a signal that says a new pad has been added. In the case ofdecodebinthis is thenew-decoded-padsignal, in the case ofgnlcompositionthis is apad-addedsignal. - You hook this signal up to your own callback, such as
OnDecodedPad(). - The signal passes your callback the pad that was added and some other stuff. You then link this pad to the next element along in the pipeline. So if your pipeline is
filesrc ! decodebin ! audioconvert ! alsasink, the pad passed to yourOnDecodeBin()method would be linked to theaudioconvert.
To outline this, I have written a sample script to show how it works:
#!/usr/bin/python
import pygst
pygst.require("0.10")
import gst
import pygtk
import gtk
class Main:
def __init__(self):
self.pipeline = gst.Pipeline("mypipeline")
self.filesrc = gst.element_factory_make("filesrc", "source")
self.pipeline.add(self.filesrc)
self.filesrc.set_property("location", "/home/jono/Desktop/jonobacon-voicesoffreedom.ogg")
self.decode = gst.element_factory_make("decodebin", "decode")
self.decode.connect("new-decoded-pad", self.OnDynamicPad)
self.pipeline.add(self.decode)
self.filesrc.link(self.decode)
self.convert = gst.element_factory_make("audioconvert", "convert")
self.pipeline.add(self.convert)
self.sink = gst.element_factory_make("alsasink", "sink")
self.pipeline.add(self.sink)
self.convert.link(self.sink)
self.pipeline.set_state(gst.STATE_PLAYING)
def OnDynamicPad(self, dbin, pad, islast):
print "OnDynamicPad Called!"
pad.link(self.convert.get_pad("sink"))
start=Main()
gtk.main()
You can grab the script from here. Hope this helps some of you.
This entry was posted on Friday, November 3rd, 2006 at 10:18 am and is filed under Desktop, Jokosher. You can follow any responses to this entry through the RSS 2.0 feed.
You can leave a response, or trackback from your own site.
16 Comments
We'd love to hear yours!
Leave a Reply
Here's your chance to speak.








Visit My Website
November 3, 2006
Permalink
In the example pipeline don’t you mean filesrc not filesink… otherwise with my meager understanding you’d have two sinks and no source.. right?
Visit My Website
November 3, 2006
Permalink
Fixed! Thanks David.
Visit My Website
November 3, 2006
Permalink
Dude you more than rock – thank you for your help with this
Visit My Website
November 3, 2006
Permalink
Not being a big Python fan this strikes me as inconsistent: self.pipeline.add(self.filesrc)
when everywhere else you use the passed name from the factory_make function I would have though it should be: self.pipeline.add(self.source)
Visit My Website
November 3, 2006
Permalink
David – wha?
Visit My Website
November 3, 2006
Permalink
okay, I’ll try slower for your sake Jono:
shouldn’t: self.filesrc = gst.element_factory_make(“filesrc”, “source”) self.pipeline.add(self.filesrc)
be: self.filesrc = gst.element_factory_make(“filesrc”, “source”) self.pipeline.add(self.source)
Visit My Website
November 4, 2006
Permalink
Insert “not a gstreamer fundi” disclaimer here, but doesn’t your decodebin element want to link to the ‘convert’ element, and not to the ’sink’ element?
In other words, your callback:
def OnDynamicPad(self, dbin, pad, islast): print “OnDynamicPad Called!” pad.link(self.convert.get_pad(“sink”))
Should be, if I’m right: def OnDynamicPad(self, dbin, pad, islast): print “OnDynamicPad Called!” pad.link(self.convert.get_pad(“convert”))
Not so?
Still, we get the point – thanks for the explanation!
Visit My Website
November 5, 2006
Permalink
well at least we are all learning from this.. I had never touched GStreamer code before but now I’m getting into it by reading Jono’ examples..
Visit My Website
November 19, 2006
Permalink
while running the above example follwing error is coming:
python: Python/ceval.c:2531: PyEval_EvalCodeEx: Assertion `tstate != ((void *)0)’ failed. Aborted
Visit My Website
November 22, 2006
Permalink
David,
I see where you’re coming from.
Here, self.filesrc is a GStreamer filesrc element, which is a Python object. This object has various properties, one of which is a “name” field, which in this case is equal to “source”. This name is how GStreamer refers to the element.
I agree that it’s a bit confusing, that an element can have a (Python) object name that’s different from its GStreamer name; I tend to set them to be the same whenever I create an element, so I don’t get mixed up
Visit My Website
June 19, 2007
Permalink
How would you set up a queue to play many files sequentially or randomly? Would you have a pipeline in your play pipeline or just have a boolean test after it is done playing and if it isn’t the last in the a queue list and then play that file? Thanks for nay response.
Visit My Website
July 14, 2007
Permalink
I would like to create a never stopping stream of data (to send to an icecast server, with shout2send..). In my case, i want to play files, using a playlist. But i don’t understand how to make gstreamer aware of loading the next file, if the other one is ended. I understand i have to change something in the pipeline.
The pipeline for one file is: filesrc file1.mp3 ! decodebin ! audioconvert ! lame ! etc.
After file1.mp3 is finished, i have to make filesrc aware to load a new file, or i have to cut filesrc file1 from the pipeline and reconnect anew filesrc element. But how do i do that?
Visit My Website
March 18, 2009
Permalink
Hi Jono, I am actually using your tutorials to teach myself some basic python/gstreamer hacking. One thing you might want to change in your example is naming your alsasink element ’sink’ as it confused the hell out of me when I then saw ’sink’ again in the pad.link argument.