Index: dynamic.xml
===================================================================
RCS file: /cvs/gstreamer/gstreamer/docs/manual/dynamic.xml,v
retrieving revision 1.14
diff -u -r1.14 dynamic.xml
--- dynamic.xml	28 Jan 2004 15:08:17 -0000	1.14
+++ dynamic.xml	13 Mar 2004 16:56:34 -0000
@@ -23,17 +23,76 @@
 #include &lt;string.h&gt;
 #include &lt;gst/gst.h&gt;
 
+/* compile with
+ *
+ * gcc -Wall -o dynamic dynamic.c `pkg-config --libs --cflags gstreamer-0.8`
+ *
+ */
+ 
 void 
-eof (GstElement *src) 
+eos_cb (GstElement *src, gpointer user_data) 
 {
-  g_print ("have eos, quitting\n");
-  exit (0);
+  g_print ("Have eos (reached end of stream), quitting...\n");
+  gst_main_quit();
+}
+
+void 
+error_cb (GstElement *pipeline, 
+          GstElement *error_element, 
+          GError     *err, 
+          gchar      *errmsg, 
+          gpointer    user_data) 
+{
+  g_printerr ("Element '%s' is in error state: %s\n", 
+              gst_element_get_name(error_element), 
+              errmsg);
+  
+  g_printerr ("Quitting...\n");
+  gst_main_quit();
 }
 
 gboolean 
 idle_func (gpointer data) 
 {
-  gst_bin_iterate (GST_BIN (data));
+  if (gst_bin_iterate (GST_BIN (data)) == FALSE)
+    gst_main_quit();
+
+  return TRUE; /* = call this idle function again */
+}
+
+/* Convenience function that tries to create an
+ *  element and prints out an error message if
+ *  it couldn't create the element. This saves
+ *  us from littering the main code with loads
+ *  of g_printerr() statements. */
+ 
+static gboolean
+create_element(const gchar  *plugin_name, 
+               const gchar  *nick_name, 
+               GstElement  **p_element)
+{
+  GstElement *new_element;
+  
+  g_return_val_if_fail(plugin_name != NULL, FALSE);
+  g_return_val_if_fail(nick_name   != NULL, FALSE);
+  g_return_val_if_fail(p_element   != NULL, FALSE);
+  
+  new_element = gst_element_factory_make (plugin_name, nick_name);
+
+  if (new_element == NULL) {
+    g_printerr("Could not create element '%s'. Check your GStreamer\n"
+               "  installation and check whether you have the plugin.\n"
+               "  Don't forget to run gst-register-%u.%u after installing\n"
+               "  new plugins.\n\n", plugin_name, GST_VERSION_MAJOR, 
+               GST_VERSION_MINOR);
+    
+    *p_element = NULL;
+    
+    return FALSE;
+  }
+  
+  *p_element = new_element;
+    
   return TRUE;
 }
 
@@ -44,6 +103,7 @@
   GstElement *decode_audio, *play, *color, *show;
   GstElement *audio_queue, *video_queue;
   GstElement *audio_thread, *video_thread;
+  gboolean    got_problem = FALSE;
 
   g_print ("***** a new pad %s was created\n", gst_pad_get_name (pad));
   
@@ -53,19 +113,32 @@
   if (strncmp (gst_pad_get_name (pad), "audio_", 6) == 0) {
 
     /* construct internal pipeline elements */
-    decode_audio = gst_element_factory_make ("mad", "decode_audio");
-    g_return_if_fail (decode_audio != NULL);
-    play = gst_element_factory_make ("osssink", "play_audio");
-    g_return_if_fail (play != NULL);
+    if (!create_element("mad", "decode_audio", &amp;decode_audio))
+      got_problem = TRUE;
+    
+    if (!create_element("osssink", "play_audio", &amp;play))
+      got_problem = TRUE;
 
     /* create the thread and pack stuff into it */
     audio_thread = gst_thread_new ("audio_thread");
-    g_return_if_fail (audio_thread != NULL);
+    if (audio_thread == NULL)
+    {
+      g_printerr("Could not create 'thread' element - maybe you are\n"
+                 " missing the plugin or did not run gst-register?\n");
+      got_problem = TRUE;
+    }
 
     /* construct queue and link everything in the main pipeline */
-    audio_queue = gst_element_factory_make ("queue", "audio_queue");
-    g_return_if_fail (audio_queue != NULL);
+    if (!create_element("queue", "audio_queue", &amp;audio_queue))
+      got_problem = TRUE;
 
+    /* just return and leave pipeline in PAUSED
+     *  state, that will make gst_bin_iterate()
+     *  return FALSE, at which point we quit
+     *  in the idle timeout function above */
+    if (got_problem)
+      return;
+          
     gst_bin_add_many (GST_BIN (audio_thread), 
                       audio_queue, decode_audio, play, NULL);
 
@@ -73,12 +146,26 @@
     gst_element_add_ghost_pad (audio_thread,
                                gst_element_get_pad (audio_queue, "sink"),
                                "sink");
-    gst_element_link (audio_queue, decode_audio);
-    gst_element_link (decode_audio, play);
+    
+    if (!gst_element_link (audio_queue, decode_audio))
+    {
+      g_printerr("Could not link audio_queue => decode_audio\n");
+      return;
+    }
+    
+    if (!gst_element_link (decode_audio, play))
+    {
+      g_printerr("Could not link decode_audio => audiosink\n");
+      return;
+    }
 
     gst_bin_add (GST_BIN (pipeline), audio_thread);
 
-    gst_pad_link (pad, gst_element_get_pad (audio_thread, "sink"));
+    if (!gst_pad_link (pad, gst_element_get_pad (audio_thread, "sink")))
+    {
+      g_printerr("Could not link demuxer audio pad => audio thread sink pad\n");
+      return;
+    }
 
     /* set up thread state and kick things off */
     g_print ("setting to READY state\n");
@@ -88,23 +175,36 @@
   else if (strncmp (gst_pad_get_name (pad), "video_", 6) == 0) {
 
     /* construct internal pipeline elements */
-    decode_video = gst_element_factory_make ("mpeg2dec", "decode_video");
-    g_return_if_fail (decode_video != NULL);
+    if (!create_element("mpeg2dec", "decode_video", &amp;decode_video))
+      got_problem = TRUE;
 
-    color = gst_element_factory_make ("colorspace", "color");
-    g_return_if_fail (color != NULL);
+    if (!create_element("colorspace", "color", &amp;color))
+     got_problem = TRUE;
 
+    if (!create_element("ximagesink", "show", &amp;show))
+      got_problem = TRUE;
    
-    show = gst_element_factory_make ("xvideosink", "show");
-    g_return_if_fail (show != NULL);
-
     /* construct queue and link everything in the main pipeline */
-    video_queue = gst_element_factory_make ("queue", "video_queue");
-    g_return_if_fail (video_queue != NULL);
-
+    if (!create_element("queue", "video_queue", &amp;video_queue))
+      got_problem = TRUE;
+    
     /* create the thread and pack stuff into it */
     video_thread = gst_thread_new ("video_thread");
-    g_return_if_fail (video_thread != NULL);
+    if (video_thread == NULL)
+    {
+      g_printerr("Could not create 'thread' element - maybe you are\n"
+                 " missing the plugin or did not run gst-register?\n");
+      got_problem = TRUE;
+    }
+
+    /* just return and leave pipeline in PAUSED
+     *  state, that will make gst_bin_iterate()
+     *  return FALSE, at which point we quit
+     *  in the idle timeout function above */
+    
+    if (got_problem)
+      return;
+            
     gst_bin_add_many (GST_BIN (video_thread), video_queue, 
                       decode_video, color, show, NULL);
 
@@ -112,47 +212,82 @@
     gst_element_add_ghost_pad (video_thread,
                                gst_element_get_pad (video_queue, "sink"),
                                "sink");
-    gst_element_link (video_queue, decode_video);
-    gst_element_link_many (decode_video, color, show, NULL);
+    
+    if (!gst_element_link (video_queue, decode_video))
+    {
+      g_printerr("Could not link video_queue => decode_video\n");
+      return;
+    }
+    
+    if (!gst_element_link_many (decode_video, color, show, NULL))
+    {
+      g_printerr("Could not link decode_video => colorspace converter => video image sink\n");
+      return;
+    }
 
     gst_bin_add (GST_BIN (pipeline), video_thread);
 
-    gst_pad_link (pad, gst_element_get_pad (video_thread, "sink"));
+    if (!gst_pad_link (pad, gst_element_get_pad (video_thread, "sink")))
+    {
+      g_printerr("Could not link demuxer video pad => video thread sink pad\n");
+      return;
+    }
 
     /* set up thread state and kick things off */
     g_print ("setting to READY state\n");
     gst_element_set_state (GST_ELEMENT (video_thread), GST_STATE_READY);
   }
+  
   gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
 }
 
+
 int 
 main (int argc, char *argv[]) 
 {
   GstElement *pipeline, *src, *demux;
-
+  gboolean    got_problem; 
+  
   gst_init (&amp;argc, &amp;argv);
 
-  pipeline = gst_pipeline_new ("pipeline");
-  g_return_val_if_fail (pipeline != NULL, -1);
-
-  src = gst_element_factory_make ("filesrc", "src");
-  g_return_val_if_fail (src != NULL, -1);
   if (argc &lt; 2) 
-    g_error ("Please specify a video file to play !");
-
-  g_object_set (G_OBJECT (src), "location", argv[1], NULL);
+    g_error ("Please specify a video file to play !"); /* aborts */
+  
+  got_problem = FALSE;
+  
+  pipeline = gst_pipeline_new ("pipeline");
+  if (pipeline == NULL) {
+    g_printerr("Could not create pipeline - check your\n"
+               "  GStreamer installation.\n");
+    got_problem = TRUE;
+  }
 
-  demux = gst_element_factory_make ("mpegdemux", "demux");
-  g_return_val_if_fail (demux != NULL, -1);
+  if (!create_element("filesrc", "src", &amp;src))
+    got_problem = TRUE;
+  else  
+    g_object_set (G_OBJECT (src), "location", argv[1], NULL);
 
+  if (!create_element("mpegdemux", "demux", &amp;demux))
+    got_problem = TRUE;
+  
+  if (got_problem)
+    return -1;
+    
   gst_bin_add_many (GST_BIN (pipeline), src, demux, NULL);
 
+  /* we want to be notified when the mpegdemux element
+   *  has created its source pads according to the
+   *  properties of the MPEG stream we feed to it */
   g_signal_connect (G_OBJECT (demux), "new_pad",
                      G_CALLBACK (new_pad_created), pipeline);
 
+  /* we want to know when we reach the end of the file */
   g_signal_connect (G_OBJECT (src), "eos",
-                     G_CALLBACK (eof), NULL);
+                     G_CALLBACK (eos_cb), NULL);
+
+  /* we want to know when an error occured */
+  g_signal_connect (G_OBJECT (pipeline), "error",
+                     G_CALLBACK (error_cb), NULL);
 
   gst_element_link (src, demux);
 
