Understanding Bins and Ghost_pads

Ian Davidson id012c3076 at blueyonder.co.uk
Sat Dec 15 06:47:18 PST 2012

I have compiled the helloWorld example from the GStreamer documentation 
and it worked.

To attempt to understand Bins and Pipelines and so on a bit better, I 
tried to split the helloworld into two parts.  I made two bins - but 
they would not link together.  Then, I re-read the documentation and 
realised that my bins needed Ghost Pads so that they could talk to each 
other.  However, I have not got it right.

The program fails after printing "Step 2a" because in gst_ghost_pad_new, 
the assertion GST_IS_PAD failed.  Clearly, I don't know what I am 
doing.  Help would be appreciated.

#include <gst/gst.h>
#include <glib.h>

static gboolean
bus_call (GstBus     *bus,
           GstMessage *msg,
           gpointer    data)
   GMainLoop *loop = (GMainLoop *) data;

   switch (GST_MESSAGE_TYPE (msg)) {

     case GST_MESSAGE_EOS:
       g_print ("End of stream\n");
       g_main_loop_quit (loop);

     case GST_MESSAGE_ERROR: {
       gchar  *debug;
       GError *error;

       gst_message_parse_error (msg, &error, &debug);
       g_free (debug);

       g_printerr ("Error: %s\n", error->message);
       g_error_free (error);

       g_main_loop_quit (loop);

   return TRUE;

static void
on_pad_added (GstElement *element,
               GstPad     *pad,
               gpointer    data)
   GstPad *sinkpad;
   GstElement *decoder = (GstElement *) data;

   /* We can now link this pad with the vorbis-decoder sink pad */
   g_print ("Dynamic pad created, linking demuxer/decoder\n");

   sinkpad = gst_element_get_static_pad (decoder, "sink");

   gst_pad_link (pad, sinkpad);

   gst_object_unref (sinkpad);

main (int   argc,
       char *argv[])
   GMainLoop *loop;

   GstElement *bin1, *bin2, *pipeline, *pipeline1, *pipeline2, *source, 
*demuxer, *decoder, *conv, *sink, *ghostsrc, *ghostsink;
   GstBus *bus;
   GstPad *pad1, *pad2;
   guint bus_watch_id;

   /* Initialisation */
   gst_init (&argc, &argv);

   loop = g_main_loop_new (NULL, FALSE);

   /* Check input arguments */
   if (argc != 2) {
     g_printerr ("Usage: %s <Ogg/Vorbis filename>\n", argv[0]);
     return -1;

   /* Create gstreamer elements */
   pipeline = gst_pipeline_new ("audio-player");
   pipeline1 = gst_pipeline_new ("pipe1");
   pipeline2 = gst_pipeline_new ("pipe2");
   bin1 = gst_bin_new ("bin1");
   bin2 = gst_bin_new ("bin2");
   source   = gst_element_factory_make ("filesrc", "file-source");
   demuxer  = gst_element_factory_make ("oggdemux", "ogg-demuxer");
   decoder  = gst_element_factory_make ("vorbisdec", "vorbis-decoder");
   conv     = gst_element_factory_make ("audioconvert", "converter");
   sink     = gst_element_factory_make ("autoaudiosink", "audio-output");
   ghostsrc = gst_element_factory_make ("fakesrc", "ghostsrc");
   ghostsink =gst_element_factory_make ("fakesink", "ghostsink");

   if (!pipeline || !pipeline1 || !pipeline2 || !bin1 ||  !bin2 || 
!source || !demuxer || !decoder || !conv || !sink) {
     g_printerr ("One element could not be created. Exiting.\n");
     return -1;

   /* Set up the pipeline */

   /* we set the input filename to the source element */
   g_object_set (G_OBJECT (source), "location", argv[1], NULL);

   /* we add a message handler */
   bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
   bus_watch_id = gst_bus_add_watch (bus, bus_call, loop);
   gst_object_unref (bus);

   /* we add all elements into the pipeline */
   /* file-source | ogg-demuxer | vorbis-decoder | converter | 
alsa-output */
   g_print ("Step 1...\n");
   gst_bin_add_many (GST_BIN (bin1),
                     source, demuxer, decoder, ghostsrc, NULL);
   g_print ("Step 2...\n");
   pad1 = gst_element_get_static_pad (ghostsrc, "ghostsrc");
   g_print ("Step 2a...\n");
   gst_element_add_pad (bin1, gst_ghost_pad_new ("ghostsrc", pad1));
   g_print ("Step 2b...\n");
   gst_object_unref (GST_OBJECT (pad1));
   g_print ("Step 3...\n");
   gst_bin_add_many (GST_BIN (bin2),
                     ghostsink, conv, sink, NULL);
   g_print ("Step 4...\n");
   pad2 = gst_element_get_static_pad (ghostsink, "ghostsink");
   g_print ("Step 4a...\n");
   gst_element_add_pad (bin2, gst_ghost_pad_new ("ghostsink", pad2));
   g_print ("Step 4b...\n");
   gst_object_unref (GST_OBJECT (pad2));
   g_print ("Step 5...\n");
   gst_bin_add_many (GST_BIN (pipeline), bin1, bin2, NULL);

   /* we link the elements together */
   /* file-source -> ogg-demuxer ~> vorbis-decoder -> converter -> 
alsa-output */
   g_print ("Step 6...\n");
   gst_element_link (source, demuxer);
   g_print ("Step 7...\n");
   gst_element_link_many (conv, sink, NULL);
   g_print ("Step 8...\n");
   gst_element_link (bin1, bin2);
   g_print ("Step 9...\n");
   g_signal_connect (demuxer, "pad-added", G_CALLBACK (on_pad_added), 

   /* note that the demuxer will be linked to the decoder dynamically.
      The reason is that Ogg may contain various streams (for example
      audio and video). The source pad(s) will be created at run time,
      by the demuxer when it detects the amount and nature of streams.
      Therefore we connect a callback function which will be executed
      when the "pad-added" is emitted.*/

   /* Set the pipeline to "playing" state*/
   g_print ("Now playing: %s\n", argv[1]);
   gst_element_set_state (pipeline, GST_STATE_PLAYING);

   /* Iterate */
   g_print ("Running...\n");
   g_main_loop_run (loop);

   /* Out of the main loop, clean up nicely */
   g_print ("Returned, stopping playback\n");
   gst_element_set_state (pipeline, GST_STATE_NULL);

   g_print ("Deleting pipeline\n");
   gst_object_unref (GST_OBJECT (pipeline));
   g_source_remove (bus_watch_id);
   g_main_loop_unref (loop);

   return 0;

Ian Davidson
Facts used in this message may or may not reflect an underlying 
objective reality. Facts are supplied for personal use only.
Recipients quoting supplied information do so at their own risk. Facts 
supplied may vary in whole or part from widely accepted standards.
While painstakingly researched, facts may or may not be indicative of 
actually occurring events or natural phenomena.
The author accepts no responsibility for personal loss or injury 
resulting from memorisation and subsequent use.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/gstreamer-devel/attachments/20121215/bed28b1b/attachment.html>

More information about the gstreamer-devel mailing list