Wednesday, October 27, 2010

Looping playback with GStreamer

Recently on the GStreamer mailing list, someone asked how to loop playback using the playbin element. Since this seemed pretty straightforward, I thought I'd post it here. To clarify, playbin is a higher-level element that greatly simplifies typical playback scenarios. The code posted here is derived from this playbin example. The important addition is the bus callback, which simply listens for an end of stream (EOS) message, and upon receiving it, seeks to the beginning of the stream. This restarts playback.

#include <gst/gst.h>

gboolean bus_callback(GstBus *bus, GstMessage *msg, gpointer data)
{
    GstElement *play = GST_ELEMENT(data);
    switch (GST_MESSAGE_TYPE(msg))
    {
        case GST_MESSAGE_EOS:
            /* restart playback if at end */
            if (!gst_element_seek(play, 
                        1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
                        GST_SEEK_TYPE_SET, 0,
                        GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
                g_print("Seek failed!\n");
            }
            break;
        default:
            break;
    }
    return TRUE;
}

gint
main (gint   argc,
      gchar *argv[])
{
  GMainLoop *loop;
  GstElement *play;
  GstBus *bus;

  /* init GStreamer */
  gst_init (&argc, &argv);
  loop = g_main_loop_new (NULL, FALSE);

  /* make sure we have a URI */
  if (argc != 2) {
    g_print ("Usage: %s <URI>\n", argv[0]);
    return -1;
  }

  /* set up */
  play = gst_element_factory_make ("playbin", "play");
  g_object_set (G_OBJECT (play), "uri", argv[1], NULL);

  bus = gst_pipeline_get_bus (GST_PIPELINE (play));
  gst_bus_add_watch (bus, bus_callback, play);
  gst_object_unref (bus);

  gst_element_set_state (play, GST_STATE_PLAYING);

  /* now run */
  g_main_loop_run (loop);

  /* also clean up */
  gst_element_set_state (play, GST_STATE_NULL);
  gst_object_unref (GST_OBJECT (play));

  return 0;
}

3 comments:

Alexandre Quessy said...

Hello!
It's similar to what I have done in Toonplayer, but a bit more straightforward, I think. I'll convert Toonplayer to C when I'll need a looping player again. See https://bitbucket.org/aalex/toonplayer/src/244cbb505387/toonplay/gui.py

Brian said...

This dosn't seem to work with this sample stream:

mms://mediaserver2.otn.ca/mediasite/4e8a17d6-75f5-4624-be96-efd4e083e47e.wmv

I get a warning: bin gstbin.c:2380:gst_bin_do_latency_func: did not really configure latency of 0:00:00.000000000

Tristan Matthews said...

Hmmm...totem isn't able to play that sample in repeat either. Best file a bug with GStreamer.