public bool query_duration (Format format, out int64 duration)

Queries an element (usually top-level pipeline or playbin element) for the total stream duration in nanoseconds.

This query will only work once the pipeline is prerolled (i.e. reached PAUSED or PLAYING state). The application will receive an ASYNC_DONE message on the pipeline bus when that is the case.

If the duration changes for some reason, you will get a DURATION_CHANGED message on the pipeline bus, in which case you should re-query the duration using this function.

Example: Time management:

// See http://docs.gstreamer.com/x/cAAF
// for a detailed description

public class Main {

// TODO: GST_CLOCK_TIME_IS_VALID(time) isn't bound (Tue Aug 20, 2013)
private static inline bool GST_CLOCK_TIME_IS_VALID (Gst.ClockTime time) {
return ((time) != Gst.CLOCK_TIME_NONE);

// Our one and only element
private Gst.Element playbin2;

// Are we in the PLAYING state?
private bool playing;

// Should we terminate execution?
private bool terminate;

// Is seeking enabled for this media?
private bool seek_enabled;

// Have we performed the seek already?
private bool seek_done;

// How long does this media last, in nanoseconds
private Gst.ClockTime duration;

// Forward definition of the message processing function
private void handle_message (Gst.Message msg) {
switch (msg.type) {
case Gst.MessageType.ERROR:
GLib.Error err;
string debug_info;

msg.parse_error (out err, out debug_info);
print ("Error received from element %s: %s\n", msg.src.name, err.message);
print ("Debugging information: %s\n", (debug_info != null)? debug_info : "none");
this.terminate = true;

case Gst.MessageType.EOS:
print ("End-Of-Stream reached.\n");
this.terminate = true;

case Gst.MessageType.DURATION_CHANGED :
// The duration has changed, mark the current one as invalid:
this.duration = Gst.CLOCK_TIME_NONE;

case Gst.MessageType.STATE_CHANGED:
Gst.State old_state;
Gst.State new_state;
Gst.State pending_state;

msg.parse_state_changed (out old_state, out new_state, out pending_state);
if (msg.src == this.playbin2) {
print ("Pipeline state changed from %s to %s:\n",
Gst.Element.state_get_name (old_state),
Gst.Element.state_get_name (new_state));

// Remember whether we are in the PLAYING state or not:
this.playing = (new_state == Gst.State.PLAYING);

if (this.playing) {
// We just moved to PLAYING. Check if seeking is possible:
Gst.Query query = new Gst.Query.seeking (Gst.Format.TIME);
int64 start;
int64 end;

if (this.playbin2.query (query)) {
query.parse_seeking (null, out this.seek_enabled, out start, out end);
if (this.seek_enabled) {
// GST_TIME_ARGS isn't available (Tue Aug 20, 2013)
//print ("Seeking is ENABLED from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT "\n",
// GST_TIME_ARGS (start), GST_TIME_ARGS (end));
print ("Seeking is ENABLED from %" + int64.FORMAT + " to %" + int64.FORMAT + "\n", start, end);
} else {
print ("Seeking is DISABLED for this stream.\n");
} else {
print ("Seeking query failed.\n");

// We should not reach here:
assert_not_reached ();

public int run () {
// init:
this.playing = false;
this.terminate = false;
this.seek_enabled = false;
this.seek_done = false;
this.duration = Gst.CLOCK_TIME_NONE;

// Create the elements:
this.playbin2 = Gst.ElementFactory.make ("playbin", "playbin");

if (this.playbin2 == null) {
print ("Not all elements could be created.\n");
return -1;

// Set the URI to play:
this.playbin2.set ("uri", "http://docs.gstreamer.com/media/sintel_trailer-480p.webm");

// Start playing:
Gst.StateChangeReturn ret = this.playbin2.set_state (Gst.State.PLAYING);
if (ret == Gst.StateChangeReturn.FAILURE) {
stderr.puts ("Unable to set the pipeline to the playing state.\n");
this.playbin2 = null;
return -1;

// Listen to the bus:
Gst.Bus bus = this.playbin2.get_bus ();
do {
Gst.Message msg = bus.timed_pop_filtered (100 * Gst.MSECOND,
Gst.MessageType.STATE_CHANGED | Gst.MessageType.ERROR | Gst.MessageType.EOS | Gst.MessageType.DURATION_CHANGED);

// Parse message:
if (msg != null) {
handle_message (msg);
} else {
// We got no message, this means the timeout expired:
if (this.playing) {
Gst.Format fmt = Gst.Format.TIME;
int64 current = -1;

// Query the current position of the stream:
if (!this.playbin2.query_position (fmt, out current)) {
stderr.puts ("Could not query current position.\n");

// If we didn't know it yet, query the stream duration:
if (!GST_CLOCK_TIME_IS_VALID (this.duration)) {
if (!this.playbin2.query_duration (fmt, out this.duration)) {
stderr.puts ("Could not query current duration.\n");

// Print current position and total duration:
// GST_TIME_ARGS isn't available (Tue Aug 20, 2013)
// print ("Position %" + Gst.TIME_FORMAT + " / %" + Gst.TIME_FORMAT + "\r",
// GST_TIME_ARGS (current), GST_TIME_ARGS (this.duration));
print ("Position %" + int64.FORMAT + " / %" + int64.FORMAT + "\r",
current, this.duration);

// If seeking is enabled, we have not done it yet, and the time is right, seek:
if (this.seek_enabled && !this.seek_done && current > 10 * Gst.SECOND) {
print ("\nReached 10s, performing seek...\n");
this.playbin2.seek_simple (Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, 30 * Gst.SECOND);
this.seek_done = true;
} while (!this.terminate);

// Free resources:
this.playbin2.set_state (Gst.State.NULL);
this.playbin2 = null;

return 0;

public static int main (string[] args) {
// Initialize GStreamer:
Gst.init (ref args);

return new Main ().run ();

valac --pkg gstreamer-1.0 --enable-experimental time-management.vala



a Element to invoke the duration query on.


the Format requested


A location in which to store the total duration, or null.


true if the query could be performed.