So far, we've looked at how to create a pipeline to do media processing and how to make it run ("iterate"). Most application developers will be interested in providing feedback to the user on media progress. Media players, for example, will want to show a slider showing the progress in the song, and usually also a label indicating stream length. Transcoding applications will want to show a progress bar on how much % of the task is done. GStreamer has built-in support for doing all this using a concept known as querying. Since seeking is very similar, it will be discussed here as well. Seeking is done using the concept of events.
Querying is defined as requesting a specific stream-property related
to progress tracking. This includes getting the length of a stream (if
available) or getting the current position. Those stream properties
can be retrieved in various formats such as time, audio samples, video
frames or bytes. The functions used are gst_element_query
()
and gst_pad_query ()
.
Obviously, using either of the above-mentioned functions requires the
application to know which element or pad to run
the query on. This is tricky, but there are some good sides to the
story. The good thing is that elements (or, rather, pads - since
gst_element_query ()
internally calls
gst_pad_query ()
) forward ("dispatch")
events and queries to peer pads (or elements) if they don't handle it
themselves. The bad side is that some elements (or pads) will handle
events, but not the specific formats that you want, and therefore it
still won't work.
Most queries will, fortunately, work fine. Queries are always dispatched backwards. This means, effectively, that it's easiest to run the query on your video or audio output element, and it will take care of dispatching the query to the element that knows the answer (such as the current position or the media length; usually the demuxer or decoder).
#include <gst/gst.h> gint main (gint argc, gchar *argv[]) { GstElement *sink, *pipeline; [..] /* run pipeline */ do { gint64 len, pos; GstFormat fmt = GST_FORMAT_TIME; if (gst_element_query (sink, GST_QUERY_POSITION, &fmt, &pos) && gst_element_query (sink, GST_QUERY_TOTAL, &fmt, &len)) { g_print ("Time: %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "\r", GST_TIME_ARGS (pos), GST_TIME_ARGS (len)); } } while (gst_bin_iterate (GST_BIN (pipeline))); [..] }
If you are having problems with the dispatching behaviour, your best
bet is to manually decide which element to start running the query on.
You can get a list of supported formats and query-types with
gst_element_get_query_types ()
and
gst_element_get_formats ()
.