gstreamer: Fix memory leaks when context parse fails
[platform/upstream/gstreamer.git] / docs / manual / advanced-dataaccess.xml
index b8f6544..fa56b13 100644 (file)
@@ -2,9 +2,9 @@
   <title>Pipeline manipulation</title>
   <para>
     This chapter will discuss how you can manipulate your pipeline in several
-    ways from your application on. Parts of this chapter are downright
-    hackish, so be assured that you'll need some programming knowledge
-    before you start reading this.
+    ways from your application on. Parts of this chapter are very
+    lowlevel, so be assured that you'll need some programming knowledge
+    and a good understanding of &GStreamer; before you start reading this.
   </para>
   <para>
     Topics that will be discussed here include how you can insert data into
     to listen to a pipeline's data processing.
   </para>
 
-  <sect1 id="section-data-probe">
-    <title>Data probing</title>
+  <sect1 id="section-using-probes">
+    <title>Using probes</title>
     <para>
       Probing is best envisioned as a pad listener. Technically, a probe is
       nothing more than a callback that can be attached to a pad.
       You can attach a probe using <function>gst_pad_add_probe ()</function>.
       Similarly, one can use the
       <function>gst_pad_remove_probe ()</function>
-      to remove the callback again.
+      to remove the callback again. The probe notifies you of any activity
+      that happens on the pad, like buffers, events and queries. You can
+      define what kind of notifications you are interested in when you
+      add the probe.
     </para>
     <para>
-      Probes run in pipeline threading context, so callbacks should try to
-      not block and generally not do any weird stuff, since this could
-      have a negative impact on pipeline performance or, in case of bugs,
-      cause deadlocks or crashes. More precisely, one should usually not
-      call any GUI-related functions from within a probe callback, nor try
-      to change the state of the pipeline.  An application may post custom
-      messages on the pipeline's bus though to communicate with the main
-      application thread and have it do things like stop the pipeline.
+      The probe can notify you of the following activity on pads:
     </para>
-    <para>
-      In any case, most common buffer operations
-      that elements can do in <function>_chain ()</function> functions, can
-      be done in probe callbacks as well. The example below gives a short
-      impression on how to use them (even if this usage is not entirely
-      correct, but more on that below):
-    </para>
-    <programlisting><!-- example-begin probe.c -->
-#include &lt;gst/gst.h&gt;
+    <itemizedlist>
+      <listitem>
+        <para>
+          A buffer is pushed or pulled. You want to specify the
+          GST_PAD_PROBE_TYPE_BUFFER when registering the probe. Because the
+          pad can be scheduled in different ways, it is possible to also
+          specify in what scheduling mode you are interested with the
+          optional GST_PAD_PROBE_TYPE_PUSH and GST_PAD_PROBE_TYPE_PULL
+          flags.
+        </para>
+        <para>
+          You can use this probe to inspect, modify or drop the buffer.
+          See <xref linkend="section-data-probes"/>.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          A bufferlist is pushed. Use the GST_PAD_PROBE_TYPE_BUFFER_LIST
+          when registering the probe.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          An event travels over a pad. Use the GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM
+          and GST_PAD_PROBE_TYPE_EVENT_UPSTREAM flags to select downstream
+          and upstream events. There is also a convenience
+          GST_PAD_PROBE_TYPE_EVENT_BOTH to be notified of events going both
+          upstream and downstream. By default, flush events do not cause
+          a notification. You need to explicitly enable GST_PAD_PROBE_TYPE_EVENT_FLUSH
+          to receive callbacks from flushing events. Events are always
+          only notified in push mode.
+        </para>
+        <para>
+          You can use this probe to inspect, modify or drop the event.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          A query travels over a pad. Use the GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM
+          and GST_PAD_PROBE_TYPE_QUERY_UPSTREAM flags to select downstream
+          and upstream queries. The convenience GST_PAD_PROBE_TYPE_QUERY_BOTH
+          can also be used to select both directions. Query probes will be
+          notified twice, once when the query travels upstream/downstream and
+          once when the query result is returned. You can select in what stage
+          the callback will be called with the GST_PAD_PROBE_TYPE_PUSH and
+          GST_PAD_PROBE_TYPE_PULL, respectively when the query is performed
+          and when the query result is returned.
+        </para>
+        <para>
+          You can use this probe to inspect or modify the query. You can also
+          answer the query in the probe callback by placing the result value
+          in the query and by returning GST_PAD_PROBE_DROP from the 
+          callback.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          In addition to notifying you of dataflow, you can also ask the
+          probe to block the dataflow when the callback returns. This is
+          called a blocking probe and is activated by specifying the
+          GST_PAD_PROBE_TYPE_BLOCK flag. You can use this flag with the
+          other flags to only block dataflow on selected activity. A pad
+          becomes unblocked again if you remove the probe or when you return
+          GST_PAD_PROBE_REMOVE from the callback. You can let only the
+          currently blocked item pass by returning GST_PAD_PROBE_PASS
+          from the callback, it will block again on the next item.
+        </para>
+        <para>
+          Blocking probes are used to temporarily block pads because they
+          are unlinked or because you are going to unlink them. If the
+          dataflow is not blocked, the pipeline would go into an error
+          state if data is pushed on an unlinked pad. We will se how
+          to use blocking probes to partially preroll a pipeline.
+          See also <xref linkend="section-preroll-probes"/>.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          Be notified when no activity is happening on a pad. You install
+          this probe with the GST_PAD_PROBE_TYPE_IDLE flag. You can specify
+          GST_PAD_PROBE_TYPE_PUSH and/or GST_PAD_PROBE_TYPE_PULL to 
+          only be notified depending on the pad scheduling mode.
+          The IDLE probe is also a blocking probe in that it will not let
+          any data pass on the pad for as long as the IDLE probe is
+          installed.
+        </para>
+        <para>
+          You can use idle probes to dynamically relink a pad.  We will see
+          how to use idle probes to replace an element in the pipeline.
+          See also <xref linkend="section-dynamic-pipelines"/>.
+        </para>
+      </listitem>
+    </itemizedlist>
+
+    <sect2 id="section-data-probes">
+      <title>Data probes</title>
+      <para>
+        Data probes allow you to be notified when there is data passing
+        on a pad. When adding the probe, specify the GST_PAD_PROBE_TYPE_BUFFER
+        and/or GST_PAD_PROBE_TYPE_BUFFER_LIST. 
+      </para>
+      <para>
+        Data probes run in pipeline streaming thread context, so callbacks
+        should try to not block and generally not do any weird stuff, since
+        this could have a negative impact on pipeline performance or, in case
+        of bugs, cause deadlocks or crashes. More precisely, one should usually
+        not call any GUI-related functions from within a probe callback, nor try
+        to change the state of the pipeline.  An application may post custom
+        messages on the pipeline's bus though to communicate with the main
+        application thread and have it do things like stop the pipeline.
+      </para>
+      <para>
+        In any case, most common buffer operations
+        that elements can do in <function>_chain ()</function> functions, can
+        be done in probe callbacks as well. The example below gives a short
+        impression on how to use them.
+      </para>
+      <programlisting>
+<!-- example-begin probe.c -->
+<![CDATA[
+#include <gst/gst.h>
 
 static GstPadProbeReturn
 cb_have_data (GstPad          *pad,
@@ -57,23 +165,23 @@ cb_have_data (GstPad          *pad,
 
   buffer = gst_buffer_make_writable (buffer);
   
-  gst_buffer_map (buffer, &amp;map, GST_MAP_WRITE);
+  gst_buffer_map (buffer, &map, GST_MAP_WRITE);
 
   ptr = (guint16 *) map.data;
   /* invert data */
-  for (y = 0; y &lt; 288; y++) {
-    for (x = 0; x &lt; 384 / 2; x++) {
+  for (y = 0; y < 288; y++) {
+    for (x = 0; x < 384 / 2; x++) {
       t = ptr[384 - 1 - x];
       ptr[384 - 1 - x] = ptr[x];
       ptr[x] = t;
     }
     ptr += 384;
   }
-  gst_buffer_unmap (buffer, &amp;map);
+  gst_buffer_unmap (buffer, &map);
 
   GST_PAD_PROBE_INFO_DATA (info) = buffer;
 
-  return TRUE;
+  return GST_PAD_PROBE_OK;
 }
 
 gint
@@ -86,7 +194,7 @@ main (gint   argc,
   GstPad *pad;
 
   /* init GStreamer */
-  gst_init (&amp;argc, &amp;argv);
+  gst_init (&argc, &argv);
   loop = g_main_loop_new (NULL, FALSE);
 
   /* build */
@@ -142,39 +250,274 @@ main (gint   argc,
 
   return 0;
 }
-    <!-- example-end probe.c --></programlisting>
-    <para>
-      Compare that output with the output of <quote>gst-launch-1.0
-      videotestsrc ! xvimagesink</quote>, just so you know what you're
-      looking for.
-    </para>
-    <para>
-      Strictly speaking, a pad probe callback is only allowed to modify the
-      buffer content if the buffer is writable.  Whether this is the case or
-      not depends a lot on the pipeline and the elements involved.  Often
-      enough, this is the case, but sometimes it is not, and if it is not
-      then unexpected modification of the data or metadata can introduce
-      bugs that are very hard to debug and track down. You can check if a
-      buffer is writable with <function>gst_buffer_is_writable ()</function>.
-      Since you can pass back a different buffer than the one passed in,
-      it is a good idea to make the buffer writable in the callback function
-      with <function>gst_buffer_make_writable ()</function>.
-    </para>
-    <para>
-      Pad probes are suited best for looking at data as it passes through
-      the pipeline. If you need to modify data, you should better write your
-      own GStreamer element. Base classes like GstAudioFilter, GstVideoFilter or
-      GstBaseTransform make this fairly easy.
-    </para>
-    <para>
-      If you just want to inspect buffers as they pass through the pipeline,
-      you don't even need to set up pad probes. You could also just insert
-      an identity element into the pipeline and connect to its "handoff"
-      signal. The identity element also provides a few useful debugging tools
-      like the "dump" property or the "last-message" property (the latter is
-      enabled by passing the '-v' switch to gst-launch and by setting the
-      silent property on the identity to FALSE).
-    </para>
+]]>
+<!-- example-end probe.c -->
+      </programlisting>
+      <para>
+        Compare that output with the output of <quote>gst-launch-1.0
+        videotestsrc ! xvimagesink</quote>, just so you know what you're
+        looking for.
+      </para>
+      <para>
+        Strictly speaking, a pad probe callback is only allowed to modify the
+        buffer content if the buffer is writable.  Whether this is the case or
+        not depends a lot on the pipeline and the elements involved.  Often
+        enough, this is the case, but sometimes it is not, and if it is not
+        then unexpected modification of the data or metadata can introduce
+        bugs that are very hard to debug and track down. You can check if a
+        buffer is writable with <function>gst_buffer_is_writable ()</function>.
+        Since you can pass back a different buffer than the one passed in,
+        it is a good idea to make the buffer writable in the callback function
+        with <function>gst_buffer_make_writable ()</function>.
+      </para>
+      <para>
+        Pad probes are suited best for looking at data as it passes through
+        the pipeline. If you need to modify data, you should better write your
+        own GStreamer element. Base classes like GstAudioFilter, GstVideoFilter or
+        GstBaseTransform make this fairly easy.
+      </para>
+      <para>
+        If you just want to inspect buffers as they pass through the pipeline,
+        you don't even need to set up pad probes. You could also just insert
+        an identity element into the pipeline and connect to its "handoff"
+        signal. The identity element also provides a few useful debugging tools
+        like the "dump" property or the "last-message" property (the latter is
+        enabled by passing the '-v' switch to gst-launch and by setting the
+        silent property on the identity to FALSE).
+      </para>
+    </sect2>
+
+    <sect2 id="section-preroll-probes">
+      <title>Play a region of a media file</title>
+      <para>
+        In this example we will show you how to play back a region of
+        a media file. The goal is to only play the part of a file
+        from 2 seconds to 5 seconds and then EOS.
+      </para>
+      <para>
+        In a first step we will set a uridecodebin element to the PAUSED
+        state and make sure that we block all the source pads that are
+        created. When all the source pads are blocked, we have data on
+        all source pads and we say that the uridecodebin is prerolled.
+      </para>
+      <para>
+        In a prerolled pipeline we can ask for the duration of the media
+        and we can also perform seeks. We are interested in performing a
+        seek operation on the pipeline to select the range of media
+        that we are interested in.
+      </para>
+      <para>
+        After we configure the region we are interested in, we can link
+        the sink element, unblock the source pads and set the pipeline to
+        the playing state. You will see that exactly the requested
+        region is played by the sink before it goes to EOS.
+      </para>
+      <para>
+        What follows is an example application that loosly follows this
+        algorithm.
+      </para>
+      <programlisting>
+<!-- example-begin blockprobe.c -->
+<![CDATA[
+#include <gst/gst.h>
+
+static GMainLoop *loop;
+static volatile gint counter;
+static GstBus *bus;
+static gboolean prerolled = FALSE;
+static GstPad *sinkpad;
+
+static void
+dec_counter (GstElement * pipeline)
+{
+  if (prerolled)
+    return;
+
+  if (g_atomic_int_dec_and_test (&counter)) {
+    /* all probes blocked and no-more-pads signaled, post
+     * message on the bus. */
+    prerolled = TRUE;
+
+    gst_bus_post (bus, gst_message_new_application (
+          GST_OBJECT_CAST (pipeline),
+          gst_structure_new_empty ("ExPrerolled")));
+  }
+}
+
+/* called when a source pad of uridecodebin is blocked */
+static GstPadProbeReturn
+cb_blocked (GstPad          *pad,
+            GstPadProbeInfo *info,
+            gpointer         user_data)
+{
+  GstElement *pipeline = GST_ELEMENT (user_data);
+
+  if (prerolled)
+    return GST_PAD_PROBE_REMOVE;
+
+  dec_counter (pipeline);
+
+  return GST_PAD_PROBE_OK;
+}
+
+/* called when uridecodebin has a new pad */
+static void
+cb_pad_added (GstElement *element,
+              GstPad     *pad,
+              gpointer    user_data)
+{
+  GstElement *pipeline = GST_ELEMENT (user_data);
+
+  if (prerolled)
+    return;
+
+  g_atomic_int_inc (&counter);
+
+  gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
+      (GstPadProbeCallback) cb_blocked, pipeline, NULL);
+
+  /* try to link to the video pad */
+  gst_pad_link (pad, sinkpad);
+}
+
+/* called when uridecodebin has created all pads */
+static void
+cb_no_more_pads (GstElement *element,
+                 gpointer    user_data)
+{
+  GstElement *pipeline = GST_ELEMENT (user_data);
+
+  if (prerolled)
+    return;
+
+  dec_counter (pipeline);
+}
+
+/* called when a new message is posted on the bus */
+static void
+cb_message (GstBus     *bus,
+            GstMessage *message,
+            gpointer    user_data)
+{
+  GstElement *pipeline = GST_ELEMENT (user_data);
+
+  switch (GST_MESSAGE_TYPE (message)) {
+    case GST_MESSAGE_ERROR:
+      g_print ("we received an error!\n");
+      g_main_loop_quit (loop);
+      break;
+    case GST_MESSAGE_EOS:
+      g_print ("we reached EOS\n");
+      g_main_loop_quit (loop);
+      break;
+    case GST_MESSAGE_APPLICATION:
+    {
+      if (gst_message_has_name (message, "ExPrerolled")) {
+        /* it's our message */
+        g_print ("we are all prerolled, do seek\n");
+        gst_element_seek (pipeline,
+            1.0, GST_FORMAT_TIME,
+            GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE,
+            GST_SEEK_TYPE_SET, 2 * GST_SECOND,
+            GST_SEEK_TYPE_SET, 5 * GST_SECOND);
+
+        gst_element_set_state (pipeline, GST_STATE_PLAYING);
+      }
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+gint
+main (gint   argc,
+      gchar *argv[])
+{
+  GstElement *pipeline, *src, *csp, *vs, *sink;
+
+  /* init GStreamer */
+  gst_init (&argc, &argv);
+  loop = g_main_loop_new (NULL, FALSE);
+
+  if (argc < 2) {
+    g_print ("usage: %s <uri>", argv[0]);
+    return -1;
+  }
+
+  /* build */
+  pipeline = gst_pipeline_new ("my-pipeline");
+
+  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+  gst_bus_add_signal_watch (bus);
+  g_signal_connect (bus, "message", (GCallback) cb_message,
+      pipeline);
+
+  src = gst_element_factory_make ("uridecodebin", "src");
+  if (src == NULL)
+    g_error ("Could not create 'uridecodebin' element");
+
+  g_object_set (src, "uri", argv[1], NULL);
+
+  csp = gst_element_factory_make ("videoconvert", "csp");
+  if (csp == NULL)
+    g_error ("Could not create 'videoconvert' element");
+
+  vs = gst_element_factory_make ("videoscale", "vs");
+  if (csp == NULL)
+    g_error ("Could not create 'videoscale' element");
+
+  sink = gst_element_factory_make ("autovideosink", "sink");
+  if (sink == NULL)
+    g_error ("Could not create 'autovideosink' element");
+
+  gst_bin_add_many (GST_BIN (pipeline), src, csp, vs, sink, NULL);
+
+  /* can't link src yet, it has no pads */
+  gst_element_link_many (csp, vs, sink, NULL);
+
+  sinkpad = gst_element_get_static_pad (csp, "sink");
+
+  /* for each pad block that is installed, we will increment
+   * the counter. for each pad block that is signaled, we
+   * decrement the counter. When the counter is 0 we post
+   * an app message to tell the app that all pads are
+   * blocked. Start with 1 that is decremented when no-more-pads
+   * is signaled to make sure that we only post the message
+   * after no-more-pads */
+  g_atomic_int_set (&counter, 1);
+
+  g_signal_connect (src, "pad-added",
+      (GCallback) cb_pad_added, pipeline);
+  g_signal_connect (src, "no-more-pads",
+      (GCallback) cb_no_more_pads, pipeline);
+
+  gst_element_set_state (pipeline, GST_STATE_PAUSED);
+
+  g_main_loop_run (loop);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  gst_object_unref (sinkpad);
+  gst_object_unref (bus);
+  gst_object_unref (pipeline);
+  g_main_loop_unref (loop);
+
+  return 0;
+}
+]]>
+<!-- example-end blockprobe.c -->
+</programlisting>
+      <para>
+        Note that we use a custom application message to signal the
+        main thread that the uridecidebin is prerolled. The main thread
+        will then issue a flushing seek to the requested region. The
+        flush will temporarily unblock the pad and reblock them when
+        new data arrives again. We detect this second block to remove
+        the probes. Then we set the pipeline to PLAYING and it should
+        play from 2 to 5 seconds, then EOS and exit the application.
+      </para>
+    </sect2>
   </sect1>
 
   <sect1 id="section-data-spoof">
@@ -235,7 +578,7 @@ main (gint   argc,
         </listitem>
         <listitem>
           <para>
-            It the appsrc operates in live mode or not. This can be configured
+            If the appsrc operates in live mode or not. This can be configured
             with the is-live property. When operating in live-mode it is
             important to configure the min-latency and max-latency in appsrc.
             The min-latency should be set to the amount of time it takes between
@@ -359,8 +702,10 @@ main (gint   argc,
           Note how we use the pull mode method of pushing new buffers into
           appsrc although appsrc is running in push mode. 
         </para>
-        <programlisting><!-- example-begin appsrc.c -->
-#include &lt;gst/gst.h&gt;
+        <programlisting>
+<!-- example-begin appsrc.c -->
+<![CDATA[
+#include <gst/gst.h>
 
 static GMainLoop *loop;
 
@@ -389,7 +734,7 @@ cb_need_data (GstElement *appsrc,
 
   timestamp += GST_BUFFER_DURATION (buffer);
 
-  g_signal_emit_by_name (appsrc, "push-buffer", buffer, &amp;ret);
+  g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret);
 
   if (ret != GST_FLOW_OK) {
     /* something wrong, stop pushing */
@@ -404,7 +749,7 @@ main (gint   argc,
   GstElement *pipeline, *appsrc, *conv, *videosink;
 
   /* init GStreamer */
-  gst_init (&amp;argc, &amp;argv);
+  gst_init (&argc, &argv);
   loop = g_main_loop_new (NULL, FALSE);
 
   /* setup pipeline */
@@ -440,115 +785,809 @@ main (gint   argc,
   g_main_loop_unref (loop);
 
   return 0;
-}
-      <!-- example-end appsrc.c --></programlisting>
+  }
+]]>
+<!-- example-end appsrc.c -->
+        </programlisting>
       </sect3>
     </sect2>
 
     <sect2 id="section-spoof-appsink">
       <title>Grabbing data with appsink</title>
       <para>
-        The two before-mentioned elements (fakesrc, fakesink and identity)
-        each have a <quote>handoff</quote> signal that will be called in
-        the <function>_get ()</function>- (fakesrc) or <function>_chain
-        ()</function>-function (identity, fakesink). In the signal handler,
-        you can set (fakesrc) or get (identity, fakesink) data to/from the
-        provided buffer. Note that in the case of fakesrc, you have to set
-        the size of the provided buffer using the <quote>sizemax</quote>
-        property. For both fakesrc and fakesink, you also have to set the
-        <quote>signal-handoffs</quote> property for this method to work.
+        Unlike appsrc, appsink is a little easier to use. It also supports
+        a pull and push based model of getting data from the pipeline.
       </para>
       <para>
-        Note that your handoff function should <emphasis>not</emphasis>
-        block, since this will block pipeline iteration. Also, do not try
-        to use all sort of weird hacks in such functions to accomplish
-        something that looks like synchronization or so; it's not the right
-        way and will lead to issues elsewhere. If you're doing any of this,
-        you're basically misunderstanding the &GStreamer; design.
+        The normal way of retrieving samples from appsink is by using the
+        <function>gst_app_sink_pull_sample()</function> and
+        <function>gst_app_sink_pull_preroll()</function> methods or by using
+        the <quote>pull-sample</quote> and <quote>pull-preroll</quote>
+        signals.  These methods block until a sample becomes available in the
+        sink or when the sink is shut down or reaches EOS.
       </para>
+      <para>
+        Appsink will internally use a queue to collect buffers from the
+        streaming thread. If the application is not pulling samples fast
+        enough, this queue will consume a lot of memory over time. The
+        <quote>max-buffers</quote> property can be used to limit the queue
+        size. The <quote>drop</quote> property controls whether the
+        streaming thread blocks or if older buffers are dropped when the
+        maximum queue size is reached. Note that blocking the streaming thread
+        can negatively affect real-time performance and should be avoided.
+      </para>
+      <para>
+        If a blocking behaviour is not desirable, setting the 
+        <quote>emit-signals</quote> property to TRUE will make appsink emit
+        the <quote>new-sample</quote> and <quote>new-preroll</quote> signals
+        when a sample can be pulled without blocking.
+      </para>
+      <para>
+        The <quote>caps</quote> property on appsink can be used to control
+        the formats that appsink can receive. This property can contain
+        non-fixed caps, the format of the pulled samples can be obtained by
+        getting the sample caps.
+      </para>
+      <para>
+        If one of the pull-preroll or pull-sample methods return NULL, the
+        appsink is stopped or in the EOS state. You can check for the EOS state
+        with the <quote>eos</quote> property or with the
+        <function>gst_app_sink_is_eos()</function> method.
+      </para>
+      <para>
+        The eos signal can also be used to be informed when the EOS state is
+        reached to avoid polling.
+      </para>
+      <para>
+        Consider configuring the following properties in the appsink:
+      </para>
+      <itemizedlist>
+        <listitem>
+          <para>
+            The <quote>sync</quote> property if you want to have the sink
+            base class synchronize the buffer against the pipeline clock
+            before handing you the sample.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            Enable Quality-of-Service with the <quote>qos</quote> property.
+            If you are dealing with raw video frames and let the base class
+            sycnhronize on the clock, it might be a good idea to also let
+            the base class send QOS events upstream.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            The caps property that contains the accepted caps. Upstream elements
+            will try to convert the format so that it matches the configured
+            caps on appsink. You must still check the
+            <classname>GstSample</classname> to get the actual caps of the
+            buffer.
+          </para>
+        </listitem>
+      </itemizedlist>
+
+      <sect3 id="section-spoof-appsink-ex">
+        <title>Appsink example</title>
+        <para>
+          What follows is an example on how to capture a snapshot of a video
+          stream using appsink.
+        </para>
+        <programlisting>
+<!-- example-begin appsink.c -->
+<![CDATA[
+#include <gst/gst.h>
+#ifdef HAVE_GTK
+#include <gtk/gtk.h>
+#endif
+
+#include <stdlib.h>
+
+#define CAPS "video/x-raw,format=RGB,width=160,pixel-aspect-ratio=1/1"
+
+int
+main (int argc, char *argv[])
+{
+  GstElement *pipeline, *sink;
+  gint width, height;
+  GstSample *sample;
+  gchar *descr;
+  GError *error = NULL;
+  gint64 duration, position;
+  GstStateChangeReturn ret;
+  gboolean res;
+  GstMapInfo map;
+
+  gst_init (&argc, &argv);
+
+  if (argc != 2) {
+    g_print ("usage: %s <uri>\n Writes snapshot.png in the current directory\n",
+        argv[0]);
+    exit (-1);
+  }
+
+  /* create a new pipeline */
+  descr =
+      g_strdup_printf ("uridecodebin uri=%s ! videoconvert ! videoscale ! "
+      " appsink name=sink caps=\"" CAPS "\"", argv[1]);
+  pipeline = gst_parse_launch (descr, &error);
+
+  if (error != NULL) {
+    g_print ("could not construct pipeline: %s\n", error->message);
+    g_clear_error (&error);
+    exit (-1);
+  }
+
+  /* get sink */
+  sink = gst_bin_get_by_name (GST_BIN (pipeline), "sink");
+
+  /* set to PAUSED to make the first frame arrive in the sink */
+  ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
+  switch (ret) {
+    case GST_STATE_CHANGE_FAILURE:
+      g_print ("failed to play the file\n");
+      exit (-1);
+    case GST_STATE_CHANGE_NO_PREROLL:
+      /* for live sources, we need to set the pipeline to PLAYING before we can
+       * receive a buffer. We don't do that yet */
+      g_print ("live sources not supported yet\n");
+      exit (-1);
+    default:
+      break;
+  }
+  /* This can block for up to 5 seconds. If your machine is really overloaded,
+   * it might time out before the pipeline prerolled and we generate an error. A
+   * better way is to run a mainloop and catch errors there. */
+  ret = gst_element_get_state (pipeline, NULL, NULL, 5 * GST_SECOND);
+  if (ret == GST_STATE_CHANGE_FAILURE) {
+    g_print ("failed to play the file\n");
+    exit (-1);
+  }
+
+  /* get the duration */
+  gst_element_query_duration (pipeline, GST_FORMAT_TIME, &duration);
+
+  if (duration != -1)
+    /* we have a duration, seek to 5% */
+    position = duration * 5 / 100;
+  else
+    /* no duration, seek to 1 second, this could EOS */
+    position = 1 * GST_SECOND;
+
+  /* seek to the a position in the file. Most files have a black first frame so
+   * by seeking to somewhere else we have a bigger chance of getting something
+   * more interesting. An optimisation would be to detect black images and then
+   * seek a little more */
+  gst_element_seek_simple (pipeline, GST_FORMAT_TIME,
+      GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_FLUSH, position);
+
+  /* get the preroll buffer from appsink, this block untils appsink really
+   * prerolls */
+  g_signal_emit_by_name (sink, "pull-preroll", &sample, NULL);
+
+  /* if we have a buffer now, convert it to a pixbuf. It's possible that we
+   * don't have a buffer because we went EOS right away or had an error. */
+  if (sample) {
+    GstBuffer *buffer;
+    GstCaps *caps;
+    GstStructure *s;
+
+    /* get the snapshot buffer format now. We set the caps on the appsink so
+     * that it can only be an rgb buffer. The only thing we have not specified
+     * on the caps is the height, which is dependant on the pixel-aspect-ratio
+     * of the source material */
+    caps = gst_sample_get_caps (sample);
+    if (!caps) {
+      g_print ("could not get snapshot format\n");
+      exit (-1);
+    }
+    s = gst_caps_get_structure (caps, 0);
+
+    /* we need to get the final caps on the buffer to get the size */
+    res = gst_structure_get_int (s, "width", &width);
+    res |= gst_structure_get_int (s, "height", &height);
+    if (!res) {
+      g_print ("could not get snapshot dimension\n");
+      exit (-1);
+    }
+
+    /* create pixmap from buffer and save, gstreamer video buffers have a stride
+     * that is rounded up to the nearest multiple of 4 */
+    buffer = gst_sample_get_buffer (sample);
+    gst_buffer_map (buffer, &map, GST_MAP_READ);
+#ifdef HAVE_GTK
+    pixbuf = gdk_pixbuf_new_from_data (map.data,
+        GDK_COLORSPACE_RGB, FALSE, 8, width, height,
+        GST_ROUND_UP_4 (width * 3), NULL, NULL);
+
+    /* save the pixbuf */
+    gdk_pixbuf_save (pixbuf, "snapshot.png", "png", &error, NULL);
+#endif
+    gst_buffer_unmap (buffer, &map);
+    gst_sample_unref (sample);
+  } else {
+    g_print ("could not make snapshot\n");
+  }
+
+  /* cleanup and exit */
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_object_unref (pipeline);
+
+  exit (0);
+}
+]]>
+<!-- example-end appsink.c -->
+</programlisting>
+      </sect3>
     </sect2>
+  </sect1>
 
-    <sect2 id="section-spoof-format">
-      <title>Forcing a format</title>
+  <sect1 id="section-spoof-format">
+    <title>Forcing a format</title>
+    <para>
+      Sometimes you'll want to set a specific format, for example a video
+      size and format or an audio bitsize and number of channels. You can
+      do this by forcing a specific <classname>GstCaps</classname> on
+      the pipeline, which is possible by using
+      <emphasis>filtered caps</emphasis>. You can set a filtered caps on
+      a link by using the <quote>capsfilter</quote> element in between the
+      two elements, and specifying a <classname>GstCaps</classname> as
+      <quote>caps</quote> property on this element. It will then
+      only allow types matching that specified capability set for
+      negotiation.  See also <xref linkend="section-caps-filter"/>.
+    </para>
+
+    <sect2 id="section-dynamic-format">
+      <title>Changing format in a PLAYING pipeline</title>
+      <para>
+        It is also possible to dynamically change the format in a pipeline
+        while PLAYING. This can simply be done by changing the caps 
+        property on a capsfilter. The capsfilter will send a RECONFIGURE
+        event upstream that will make the upstream element attempt to
+        renegotiate a new format and allocator. This only works if
+        the upstream element is not using fixed caps on the source pad.
+      </para>
       <para>
-        Sometimes you'll want to set a specific format, for example a video
-        size and format or an audio bitsize and number of channels. You can
-        do this by forcing a specific <classname>GstCaps</classname> on
-        the pipeline, which is possible by using
-        <emphasis>filtered caps</emphasis>. You can set a filtered caps on
-        a link by using the <quote>capsfilter</quote> element in between the
-        two elements, and specifying a <classname>GstCaps</classname> as
-        <quote>caps</quote> property on this element. It will then
-        only allow types matching that specified capability set for
-       negotiation.  See also <xref linkend="section-caps-filter"/>.
+        Below is an example of how you can change the caps of a pipeline
+        while in the PLAYING state:
+      </para>
+      <programlisting>
+<!-- example-begin dynformat.c -->
+<![CDATA[
+#include <stdlib.h>
+
+#include <gst/gst.h>
+
+#define MAX_ROUND 100
+
+int
+main (int argc, char **argv)
+{
+  GstElement *pipe, *filter;
+  GstCaps *caps;
+  gint width, height;
+  gint xdir, ydir;
+  gint round;
+  GstMessage *message;
+
+  gst_init (&argc, &argv);
+
+  pipe = gst_parse_launch_full ("videotestsrc ! capsfilter name=filter ! "
+             "ximagesink", NULL, GST_PARSE_FLAG_NONE, NULL);
+  g_assert (pipe != NULL);
+
+  filter = gst_bin_get_by_name (GST_BIN (pipe), "filter");
+  g_assert (filter);
+
+  width = 320;
+  height = 240;
+  xdir = ydir = -10;
+
+  for (round = 0; round < MAX_ROUND; round++) {
+    gchar *capsstr;
+    g_print ("resize to %dx%d (%d/%d)   \r", width, height, round, MAX_ROUND);
+
+    /* we prefer our fixed width and height but allow other dimensions to pass
+     * as well */
+    capsstr = g_strdup_printf ("video/x-raw, width=(int)%d, height=(int)%d",
+        width, height);
+
+    caps = gst_caps_from_string (capsstr);
+    g_free (capsstr);
+    g_object_set (filter, "caps", caps, NULL);
+    gst_caps_unref (caps);
+
+    if (round == 0)
+      gst_element_set_state (pipe, GST_STATE_PLAYING);
+
+    width += xdir;
+    if (width >= 320)
+      xdir = -10;
+    else if (width < 200)
+      xdir = 10;
+
+    height += ydir;
+    if (height >= 240)
+      ydir = -10;
+    else if (height < 150)
+      ydir = 10;
+
+    message =
+        gst_bus_poll (GST_ELEMENT_BUS (pipe), GST_MESSAGE_ERROR,
+        50 * GST_MSECOND);
+    if (message) {
+      g_print ("got error           \n");
+
+      gst_message_unref (message);
+    }
+  }
+  g_print ("done                    \n");
+
+  gst_object_unref (filter);
+  gst_element_set_state (pipe, GST_STATE_NULL);
+  gst_object_unref (pipe);
+
+  return 0;
+}
+]]>
+<!-- example-end dynformat.c -->
+      </programlisting>
+      <para>
+        Note how we use <function>gst_bus_poll()</function> with a
+        small timeout to get messages and also introduce a short
+        sleep.
+      </para>
+      <para>
+        It is possible to set multiple caps for the capsfilter separated
+        with a ;. The capsfilter will try to renegotiate to the first
+        possible format from the list.
       </para>
     </sect2>
   </sect1>
 
-  <sect1 id="section-data-manager">
-    <title>Embedding static elements in your application</title>
+  <sect1 id="section-dynamic-pipelines">
+    <title>Dynamically changing the pipeline</title>
     <para>
-      The <ulink type="http"
-      url="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/pwg/html/index.html">Plugin
-      Writer's Guide</ulink> describes in great detail how to write elements
-      for the &GStreamer; framework. In this section, we will solely discuss
-      how to embed such elements statically in your application. This can be
-      useful for application-specific elements that have no use elsewhere in
-      &GStreamer;.
+      In this section we talk about some techniques for dynamically
+      modifying the pipeline. We are talking specifically about changing
+      the pipeline while it is in the PLAYING state without interrupting
+      the flow.
     </para>
     <para>
-      Dynamically loaded plugins contain a structure that's defined using
-      <function>GST_PLUGIN_DEFINE ()</function>. This structure is loaded
-      when the plugin is loaded by the &GStreamer; core. The structure
-      contains an initialization function (usually called
-      <function>plugin_init</function>) that will be called right after that.
-      It's purpose is to register the elements provided by the plugin with
-      the &GStreamer; framework. 
-      If you want to embed elements directly in
-      your application, the only thing you need to do is to replace
-         <function>GST_PLUGIN_DEFINE ()</function> with a call to
-          <function>gst_plugin_register_static ()</function>. As soon as you
-      call <function>gst_plugin_register_static ()</function>, the elements
-      will from then on be available like any other element, without them
-      having to be dynamically loadable libraries. In the example below, you
-      would be able to call <function>gst_element_factory_make
-      ("my-element-name", "some-name")</function> to create an instance of the
-      element.
+      There are some important things to consider when building dynamic
+      pipelines:
     </para>
+    <itemizedlist>
+      <listitem>
+        <para>
+          When removing elements from the pipeline, make sure that there
+          is no dataflow on unlinked pads because that will cause a fatal
+          pipeline error. Always block source pads (in push mode) or
+          sink pads (in pull mode) before unlinking pads.
+          See also <xref linkend="section-dynamic-changing"/>.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          When adding elements to a pipeline, make sure to put the element
+          into the right state, usually the same state as the parent, before
+          allowing dataflow the element. When an element is newly created,
+          it is in the NULL state and will return an error when it
+          receives data.
+          See also <xref linkend="section-dynamic-changing"/>.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          When adding elements to a pipeline, &GStreamer; will by default
+          set the clock and base-time on the element to the current values
+          of the pipeline. This means that the element will be able to
+          construct the same pipeline running-time as the other elements
+          in the pipeline. This means that sinks will synchronize buffers
+          like the other sinks in the pipeline and that sources produce
+          buffers with a running-time that matches the other sources.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          When unlinking elements from an upstream chain, always make sure
+          to flush any queued data in the element by sending an EOS event
+          down the element sink pad(s) and by waiting that the EOS leaves
+          the elements (with an event probe).
+          See also <xref linkend="section-dynamic-changing"/>.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          A live source will produce buffers with a running-time of the
+          current running-time in the pipeline.
+        </para>
+        <para>
+          A pipeline without a live source produces buffers with a
+          running-time starting from 0. Likewise, after a flushing seek,
+          those pipelines reset the running-time back to 0.
+        </para>
+        <para>
+          The running-time can be changed with
+          <function>gst_pad_set_offset ()</function>. It is important to
+          know the running-time of the elements in the pipeline in order
+          to maintain synchronization.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          Adding elements might change the state of the pipeline. Adding a
+          non-prerolled sink, for example, brings the pipeline back to the
+          prerolling state. Removing a non-prerolled sink, for example, might
+          change the pipeline to PAUSED and PLAYING state.
+        </para>
+        <para>
+          Adding a live source cancels the preroll stage and put the pipeline
+          to the playing state. Adding a live source or other live elements
+          might also change the latency of a pipeline.
+        </para>
+        <para>
+          Adding or removing elements to the pipeline might change the clock
+          selection of the pipeline. If the newly added element provides a clock,
+          it might be worth changing the clock in the pipeline to the new
+          clock. If, on the other hand, the element that provides the clock
+          for the pipeline is removed, a new clock has to be selected.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          Adding and removing elements might cause upstream or downstream
+          elements to renegotiate caps and or allocators. You don't really
+          need to do anything from the application, plugins largely
+          adapt themself to the new pipeline topology in order to optimize
+          their formats and allocation strategy.
+        </para>
+        <para>
+          What is important is that when you add, remove or change elements
+          in the pipeline, it is possible that the pipeline needs to
+          negotiate a new format and this can fail. Usually you can fix this
+          by inserting the right converter elements where needed.
+          See also <xref linkend="section-dynamic-changing"/>.
+        </para>
+      </listitem>
+    </itemizedlist>
 
-    <programlisting>
-/*
- * Here, you would write the actual plugin code.
- */
+    <para>
+      &GStreamer; offers support for doing about any dynamic pipeline
+      modification but it requires you to know a bit of details before
+      you can do this without causing pipeline errors. In the following
+      sections we will demonstrate a couple of typical use-cases.
+    </para>
 
-[..]
+    <sect2 id="section-dynamic-changing">
+      <title>Changing elements in a pipeline</title>
+      <para>
+        In the next example we look at the following chain of elements:
+      </para>
+      <programlisting>
+            - ----.      .----------.      .---- -
+         element1 |      | element2 |      | element3
+                src -> sink       src -> sink
+            - ----'      '----------'      '---- -
+      </programlisting>
+      <para>
+        We want to change element2 by element4 while the pipeline is in
+        the PLAYING state. Let's say that element2 is a visualization and
+        that you want to switch the visualization in the pipeline.
+      </para>
+      <para>
+        We can't just unlink element2's sinkpad from element1's source
+        pad because that would leave element1's source pad
+        unlinked and would cause a streaming error in the pipeline when
+        data is pushed on the source pad.
+        The technique is to block the dataflow from element1's source pad
+        before we change element2 by element4 and then resume dataflow
+        as shown in the following steps:
+      </para>
+      <itemizedlist>
+        <listitem>
+          <para>
+            Block element1's source pad with a blocking pad probe. When the
+            pad is blocked, the probe callback will be called.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            Inside the block callback nothing is flowing between element1
+            and element2 and nothing will flow until unblocked.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            Unlink element1 and element2.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            Make sure data is flushed out of element2. Some elements might
+            internally keep some data, you need to make sure not to lose data
+            by forcing it out of element2. You can do this by pushing EOS into
+            element2, like this:
+          </para>
+          <itemizedlist>
+            <listitem>
+              <para>
+                Put an event probe on element2's source pad.
+              </para>
+            </listitem>
+            <listitem>
+              <para>
+                Send EOS to element2's sinkpad. This makes sure the all the
+                data inside element2 is forced out.
+              </para>
+            </listitem>
+            <listitem>
+              <para>
+                Wait for the EOS event to appear on element2's source pad.
+                When the EOS is received, drop it and remove the event
+                probe.
+              </para>
+            </listitem>
+          </itemizedlist>
+        </listitem>
+        <listitem>
+          <para>
+            Unlink element2 and element3. You can now also remove element2
+            from the pipeline and set the state to NULL.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            Add element4 to the pipeline, if not already added. Link element4
+            and element3. Link element1 and element4.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            Make sure element4 is in the same state as the rest of the elements
+            in the pipeline. It should be at least in the PAUSED state before
+            it can receive buffers and events.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            Unblock element1's source pad probe. This will let new data into
+            element4 and continue streaming.
+          </para>
+        </listitem>
+      </itemizedlist>
+      <para>
+        The above algorithm works when the source pad is blocked, i.e. when
+        there is dataflow in the pipeline. If there is no dataflow, there is
+        also no point in changing the element (just yet) so this algorithm can
+        be used in the PAUSED state as well.
+      </para>
+      <para>
+        Let show you how this works with an example. This example changes the
+        video effect on a simple pipeline every second.
+      </para>
+      <programlisting>
+<!-- example-begin effectswitch.c -->
+<![CDATA[
+#include <gst/gst.h>
+
+static gchar *opt_effects = NULL;
+
+#define DEFAULT_EFFECTS "identity,exclusion,navigationtest," \
+    "agingtv,videoflip,vertigotv,gaussianblur,shagadelictv,edgetv"
+
+static GstPad *blockpad;
+static GstElement *conv_before;
+static GstElement *conv_after;
+static GstElement *cur_effect;
+static GstElement *pipeline;
+
+static GQueue effects = G_QUEUE_INIT;
+
+static GstPadProbeReturn
+event_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
+{
+  GMainLoop *loop = user_data;
+  GstElement *next;
+
+  if (GST_EVENT_TYPE (GST_PAD_PROBE_INFO_DATA (info)) != GST_EVENT_EOS)
+    return GST_PAD_PROBE_OK;
+
+  gst_pad_remove_probe (pad, GST_PAD_PROBE_INFO_ID (info));
+
+  /* push current event back into the queue */
+  g_queue_push_tail (&effects, gst_object_ref (cur_effect));
+  /* take next effect from the queue */
+  next = g_queue_pop_head (&effects);
+  if (next == NULL) {
+    GST_DEBUG_OBJECT (pad, "no more effects");
+    g_main_loop_quit (loop);
+    return GST_PAD_PROBE_DROP;
+  }
+
+  g_print ("Switching from '%s' to '%s'..\n", GST_OBJECT_NAME (cur_effect),
+      GST_OBJECT_NAME (next));
+
+  gst_element_set_state (cur_effect, GST_STATE_NULL);
+
+  /* remove unlinks automatically */
+  GST_DEBUG_OBJECT (pipeline, "removing %" GST_PTR_FORMAT, cur_effect);
+  gst_bin_remove (GST_BIN (pipeline), cur_effect);
+
+  GST_DEBUG_OBJECT (pipeline, "adding   %" GST_PTR_FORMAT, next);
+  gst_bin_add (GST_BIN (pipeline), next);
+
+  GST_DEBUG_OBJECT (pipeline, "linking..");
+  gst_element_link_many (conv_before, next, conv_after, NULL);
+
+  gst_element_set_state (next, GST_STATE_PLAYING);
+
+  cur_effect = next;
+  GST_DEBUG_OBJECT (pipeline, "done");
+
+  return GST_PAD_PROBE_DROP;
+}
+
+static GstPadProbeReturn
+pad_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
+{
+  GstPad *srcpad, *sinkpad;
+
+  GST_DEBUG_OBJECT (pad, "pad is blocked now");
+
+  /* remove the probe first */
+  gst_pad_remove_probe (pad, GST_PAD_PROBE_INFO_ID (info));
+
+  /* install new probe for EOS */
+  srcpad = gst_element_get_static_pad (cur_effect, "src");
+  gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_BLOCK |
+      GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, event_probe_cb, user_data, NULL);
+  gst_object_unref (srcpad);
+
+  /* push EOS into the element, the probe will be fired when the
+   * EOS leaves the effect and it has thus drained all of its data */
+  sinkpad = gst_element_get_static_pad (cur_effect, "sink");
+  gst_pad_send_event (sinkpad, gst_event_new_eos ());
+  gst_object_unref (sinkpad);
+
+  return GST_PAD_PROBE_OK;
+}
+
+static gboolean
+timeout_cb (gpointer user_data)
+{
+  gst_pad_add_probe (blockpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
+      pad_probe_cb, user_data, NULL);
+
+  return TRUE;
+}
 
 static gboolean
-register_elements (GstPlugin *plugin)
+bus_cb (GstBus * bus, GstMessage * msg, gpointer user_data)
 {
-  return gst_element_register (plugin, "my-element-name",
-                              GST_RANK_NONE, MY_PLUGIN_TYPE);
+  GMainLoop *loop = user_data;
+
+  switch (GST_MESSAGE_TYPE (msg)) {
+    case GST_MESSAGE_ERROR:{
+      GError *err = NULL;
+      gchar *dbg;
+
+      gst_message_parse_error (msg, &err, &dbg);
+      gst_object_default_error (msg->src, err, dbg);
+      g_clear_error (&err);
+      g_free (dbg);
+      g_main_loop_quit (loop);
+      break;
+    }
+    default:
+      break;
+  }
+  return TRUE;
 }
 
-static
-my_code_init (void)
+int
+main (int argc, char **argv)
 {
-  ...
-
-  gst_plugin_register_static (
-    GST_VERSION_MAJOR,
-    GST_VERSION_MINOR,
-    "my-private-plugins",
-    "Private elements of my application",
-    register_elements,
-    VERSION,
-    "LGPL",
-    "my-application-source",
-    "my-application",
-    "http://www.my-application.net/")
-
-  ...
+  GOptionEntry options[] = {
+    {"effects", 'e', 0, G_OPTION_ARG_STRING, &opt_effects,
+        "Effects to use (comma-separated list of element names)", NULL},
+    {NULL}
+  };
+  GOptionContext *ctx;
+  GError *err = NULL;
+  GMainLoop *loop;
+  GstElement *src, *q1, *q2, *effect, *filter1, *filter2, *sink;
+  gchar **effect_names, **e;
+
+  ctx = g_option_context_new ("");
+  g_option_context_add_main_entries (ctx, options, NULL);
+  g_option_context_add_group (ctx, gst_init_get_option_group ());
+  if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
+    g_print ("Error initializing: %s\n", err->message);
+    g_clear_error (&amp;err);
+    g_option_context_free (ctx);
+    return 1;
+  }
+  g_option_context_free (ctx);
+
+  if (opt_effects != NULL)
+    effect_names = g_strsplit (opt_effects, ",", -1);
+  else
+    effect_names = g_strsplit (DEFAULT_EFFECTS, ",", -1);
+
+  for (e = effect_names; e != NULL && *e != NULL; ++e) {
+    GstElement *el;
+
+    el = gst_element_factory_make (*e, NULL);
+    if (el) {
+      g_print ("Adding effect '%s'\n", *e);
+      g_queue_push_tail (&effects, el);
+    }
+  }
+
+  pipeline = gst_pipeline_new ("pipeline");
+
+  src = gst_element_factory_make ("videotestsrc", NULL);
+  g_object_set (src, "is-live", TRUE, NULL);
+
+  filter1 = gst_element_factory_make ("capsfilter", NULL);
+  gst_util_set_object_arg (G_OBJECT (filter1), "caps",
+      "video/x-raw, width=320, height=240, "
+      "format={ I420, YV12, YUY2, UYVY, AYUV, Y41B, Y42B, "
+      "YVYU, Y444, v210, v216, NV12, NV21, UYVP, A420, YUV9, YVU9, IYU1 }");
+
+  q1 = gst_element_factory_make ("queue", NULL);
+
+  blockpad = gst_element_get_static_pad (q1, "src");
+
+  conv_before = gst_element_factory_make ("videoconvert", NULL);
+
+  effect = g_queue_pop_head (&effects);
+  cur_effect = effect;
+
+  conv_after = gst_element_factory_make ("videoconvert", NULL);
+
+  q2 = gst_element_factory_make ("queue", NULL);
+
+  filter2 = gst_element_factory_make ("capsfilter", NULL);
+  gst_util_set_object_arg (G_OBJECT (filter2), "caps",
+      "video/x-raw, width=320, height=240, "
+      "format={ RGBx, BGRx, xRGB, xBGR, RGBA, BGRA, ARGB, ABGR, RGB, BGR }");
+
+  sink = gst_element_factory_make ("ximagesink", NULL);
+
+  gst_bin_add_many (GST_BIN (pipeline), src, filter1, q1, conv_before, effect,
+      conv_after, q2, sink, NULL);
+
+  gst_element_link_many (src, filter1, q1, conv_before, effect, conv_after,
+      q2, sink, NULL);
+
+  gst_element_set_state (pipeline, GST_STATE_PLAYING);
+
+  loop = g_main_loop_new (NULL, FALSE);
+
+  gst_bus_add_watch (GST_ELEMENT_BUS (pipeline), bus_cb, loop);
+
+  g_timeout_add_seconds (1, timeout_cb, loop);
+
+  g_main_loop_run (loop);
+
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_object_unref (pipeline);
+
+  return 0;
 }
-    </programlisting>
+]]>
+<!-- example-end effectswitch.c -->
+      </programlisting>
+      <para>
+        Note how we added videoconvert elements before and after the effect.
+        This is needed because some elements might operate in different
+        colorspaces than other elements. By inserting the conversion elements
+        you ensure that the right format can be negotiated at any time.
+      </para>
+    </sect2>
   </sect1>
+
 </chapter>