A threaded example application

As an example we show the helloworld program that we coded in the Chapter called Your first application using a thread. Note that the whole application lives in a thread (as opposed to half of the application living in a thread and the other half being another thread or a pipeline). Therefore, it does not need a queue element in this specific case.


#include <gst/gst.h>

GstElement *thread, *source, *decodebin, *audiosink;

static gboolean
idle_eos (gpointer data)
{
  g_print ("Have idle-func in thread %p\n", g_thread_self ());
  gst_main_quit ();

  /* do this function only once */
  return FALSE;
}

/*
 * EOS will be called when the src element has an end of stream.
 * Note that this function will be called in the thread context.
 * We will place an idle handler to the function that really
 * quits the application.
 */
static void
cb_eos (GstElement *thread,
	gpointer    data) 
{
  g_print ("Have eos in thread %p\n", g_thread_self ());
  g_idle_add ((GSourceFunc) idle_eos, NULL);
}

/*
 * On error, too, you'll want to forward signals to the main
 * thread, especially when using GUI applications.
 */

static void
cb_error (GstElement *thread,
	  GstElement *source,
	  GError     *error,
	  gchar      *debug,
	  gpointer    data)
{
  g_print ("Error in thread %p: %s\n", g_thread_self (), error->message);
  g_idle_add ((GSourceFunc) idle_eos, NULL);
}

/*
 * Link new pad from decodebin to audiosink.
 * Contains no further error checking.
 */

static void
cb_newpad (GstElement *decodebin,
	   GstPad     *pad,
	   gboolean    last,
	   gpointer    data)
{
  gst_pad_link (pad, gst_element_get_pad (audiosink, "sink"));
  gst_bin_add (GST_BIN (thread), audiosink);
  gst_bin_sync_children_state (GST_BIN (thread));
}

gint 
main (gint   argc,
      gchar *argv[]) 
{
  /* init GStreamer */
  gst_init (&argc, &argv);

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

  /* create a new thread to hold the elements */
  thread = gst_thread_new ("thread");
  g_signal_connect (thread, "eos", G_CALLBACK (cb_eos), NULL);
  g_signal_connect (thread, "error", G_CALLBACK (cb_error), NULL);

  /* create elements */
  source = gst_element_factory_make ("filesrc", "source");
  g_object_set (G_OBJECT (source), "location", argv[1], NULL);
  decodebin = gst_element_factory_make ("decodebin", "decoder");
  g_signal_connect (decodebin, "new-decoded-pad",
		    G_CALLBACK (cb_newpad), NULL);
  audiosink = gst_element_factory_make ("alsasink", "audiosink");

  /* setup */
  gst_bin_add_many (GST_BIN (thread), source, decodebin, NULL);
  gst_element_link (source, decodebin);
  gst_element_set_state (audiosink, GST_STATE_PAUSED);
  gst_element_set_state (thread, GST_STATE_PLAYING);

  /* no need to iterate. We can now use a mainloop */
  gst_main ();

  /* unset */
  gst_element_set_state (thread, GST_STATE_NULL);
  gst_object_unref (GST_OBJECT (thread));

  return 0;
}