GStreamer is a pretty nice piece of software for handling almost all of your multimedia needs but the time will come that you get to the point where seemingly easy things are pretty hard to figure out.
I hit this point when working on the thumbnailing code of PiTiVi and realizing that there is no straightforward way to get video properties like the height, the width or the framerate out of GStreamer. Unfortunately Google couldn’t find any valuable information either so I had to dig for myself.
After some Doc reading and poking around in #gstreamer I finally got the crucial tip to get the required information out of the Caps of the GStreamer pipeline.
So imagine your pipeline conceptually looks like “videosrc ! videosink”. When you link the source with the sink and after the pipeline has been prerolled you will be able to ask the sink for it’s negotiated caps – that is the caps that have been dynamically generated when the pipeline has been initialized.
But without further descriptions let’s get dirty on some code. I’ll use Python here but the results should also be valid for other languages:
#!/usr/bin/python import pygst pygst.require("0.10") import gst import pygtk import gtk class Main: def __init__(self): self.pipeline = gst.element_factory_make("playbin2", "src") self.pipeline.props.uri = "file:///home/daniel/Videos/bbb_trailer_400p.ogg" self.sink = gst.element_factory_make("xvimagesink", "sink") self.pipeline.props.video_sink = self.sink self.pipeline.set_state(gst.STATE_PAUSED) # asynchroneous # wait for the pipeline to be prerolled so the caps get negotiated if gst.STATE_CHANGE_SUCCESS == self.pipeline.get_state(gst.CLOCK_TIME_NONE): pads = self.sink.pads() for pad in pads: neg_caps = pad.get_negotiated_caps() # simplified, there could be more caps framerate = neg_caps["framerate"] # simplified, maybe there is no "framerate" print "The framerate of the src is %d/%dfps" % (framerate.num, framerate.denom) self.pipeline.set_state(gst.STATE_PLAYING) start=Main() gtk.main()
This code makes a few simplifying assumptions such as that there is at least one negotiated cap in the pad and that the first cap contains a value called “framerate” but it should work for the majority of cases and should show you the idea how to do it.
So what did we actually do? First we created a playbin2 and set it’s input file. I chose this element because it handles all the dirty work of setting up the correct pipeline for us. The only thing that is missing is a sink. I took a standard off the shelve xvimagesink for our example but it should also work with other appropriate sinks.
After the playbin2 (the source) and the xvimagesink have been linked we have to make sure that the pipeline gets prerolled so that the caps that will contain the precious information get negotiated. To ensure that, we set the pipeline’s state to playing and because that’s an asynchroneous call we have to wait for that state change to happen successfully by calling get_state.
After the successful statechange the caps will have been negotiated and we can ask our sink for the information that we actually want.
With the same approach you can ask for much more than the framerate, for example the size of the video – neg_caps["width"] and neg_caps["height"] respectively.
I hope this will be of help to somebody and I’m happy for any improvement ideas!