docs/pwg/advanced-events.xml: Adding documentation on advanced event handling (up...
authorJulien Moutte <julien@moutte.net>
Thu, 29 Jan 2004 12:46:19 +0000 (12:46 +0000)
committerJulien Moutte <julien@moutte.net>
Thu, 29 Jan 2004 12:46:19 +0000 (12:46 +0000)
Original commit message from CVS:
2004-01-29  Julien MOUTTE <julien@moutte.net>

* docs/pwg/advanced-events.xml: Adding documentation on advanced event
handling (up and downstream).
* docs/pwg/advanced-interfaces.xml: Make it coherent with the
my_filter thing.

ChangeLog
docs/pwg/advanced-events.xml
docs/pwg/advanced-interfaces.xml

index 894187d..c6f5b68 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2004-01-29  Julien MOUTTE <julien@moutte.net>
+
+       * docs/pwg/advanced-events.xml: Adding documentation on advanced event
+       handling (up and downstream).
+       * docs/pwg/advanced-interfaces.xml: Make it coherent with the
+       my_filter thing.
+
 2004-01-29  Ronald Bultje  <rbultje@ronald.bitfreak.net>
 
        * docs/pwg/advanced-tagging.xml:
 2004-01-29  Ronald Bultje  <rbultje@ronald.bitfreak.net>
 
        * docs/pwg/advanced-tagging.xml:
index 884c532..df7c77e 100644 (file)
@@ -1,6 +1,154 @@
 <chapter id="chapter-advanced-events">
   <title>Events: Seeking, Navigation and More</title>
   <para>
 <chapter id="chapter-advanced-events">
   <title>Events: Seeking, Navigation and More</title>
   <para>
-    WRITEME
+    There are many different event types but only 2 ways they can travel accross
+    the pipeline: downstream or upstream. It is very important to understand
+    how both of those methods work because if one element in the pipeline is not
+    handling them correctly the whole event system of the pipeline is broken.
+    We will try to explain here how these methods work and how elements are 
+    supposed to implement them.
   </para>
   </para>
+  <sect1 id="section-events-downstream" xreflabel="Downstream events">
+    <title>Downstream events</title>
+    <para>
+      Downstream events are received through the sink pad's dataflow. Depending
+      if your element is loop or chain based you will receive events in your
+      loop/chain function as a GstData with <function>gst_pad_pull</function>
+      or directly in the function call arguments. So when receiving dataflow
+      from the sink pad you have to check first if this data chunk is an event.
+      If that's the case you check what kind of event it is to react on relevant
+      ones and then forward others dowstream using
+      <function>gst_pad_event_default</function>. Here is an example for both
+      loop and chain based elements.
+    </para>
+    <programlisting><![CDATA[
+/* Chain based element */
+static void
+gst_my_filter_chain (GstPad  *pad,
+                     GstData *data)
+{
+  GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad));
+  ...
+  if (GST_IS_EVENT (data)) {
+    GstEvent *event = GST_EVENT (data);
+
+    switch (GST_EVENT_TYPE (event)) {
+      case GST_EVENT_EOS:
+        /* end-of-stream, we should close down all stream leftovers here */
+        gst_my_filter_stop_processing (filter);
+        /* fall-through to default event handling */
+      default:
+        gst_pad_event_default (pad, event);
+        break;
+    }
+    return;
+  }
+  ...
+}
+
+/* Loop based element */
+static void
+gst_my_filter_loop (GstElement *element)
+{
+  GstMyFilter *filter = GST_MY_FILTER (element);
+  GstData *data = NULL;
+  
+  data = gst_pad_pull (filter->sinkpad);
+  
+  if (GST_IS_EVENT (data)) {
+    GstEvent *event = GST_EVENT (data);
+
+    switch (GST_EVENT_TYPE (event)) {
+      case GST_EVENT_EOS:
+        /* end-of-stream, we should close down all stream leftovers here */
+        gst_my_filter_stop_processing (filter);
+        /* fall-through to default event handling */
+      default:
+        gst_pad_event_default (filter->sinkpad, event);
+        break;
+    }
+    return;
+  }
+  ...
+}
+    ]]></programlisting>
+  </sect1>
+  <sect1 id="section-events-upstream" xreflabel="Upstream events">
+    <title>Upstream events</title>
+    <para>
+      Upstream events are generated by an element somewhere in the pipeline and
+      sent using the <function>gst_pad_send_event</function> function. This
+      function simply realizes the pad and call the default event handler of that
+      pad. The default event handler of pads is <function>gst_pad_event_default</function>
+      , it basically sends the event to the peer pad. So upstream events always
+      arrive on the src pad of your element and are handled by the default event
+      handler except if you override that handler to handle it yourself. There
+      are some specific cases where you have to do that :
+    </para>
+    <itemizedlist mark="opencircle">
+      <listitem>
+        <para>
+          If you have multiple sink pads in your element. In that case you will
+          have to decide which one of the sink pads you will send the event to.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          If you need to handle that event locally. For example a navigation 
+          event that you will want to convert before sending it upstream.
+        </para>
+      </listitem>
+    </itemizedlist>
+    <para>
+      The processing you will do in that event handler does not really matter
+      but there are important rules you have to absolutely respect because
+      one broken element event handler is breaking the whole pipeline event 
+      handling. Here they are :
+    </para>
+    <itemizedlist mark="opencircle">
+      <listitem>
+        <para>
+          Always forward events you won't handle upstream using the default 
+          <function>gst_pad_event_default</function> method.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          If you are generating some new event based on the one you received
+          don't forget to gst_event_unref the event you received.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          Event handler function are supposed to return TRUE or FALSE indicating
+          if the event has been handled or not. Never simply return TRUE/FALSE
+          in that handler except if you really know that you have handled that 
+          event.
+        </para>
+      </listitem>
+    </itemizedlist>
+    <para>
+      Here is an example of correct upstream event handling for a plugin
+      that wants to modify navigation events.
+    </para>
+    <programlisting><![CDATA[
+static gboolean
+gst_my_plugin_handle_src_event (GstPad *pad, GstEvent *event)
+{
+  GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad));
+  
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_NAVIGATION:
+      GstEvent *new_event = gst_event_new (GST_EVENT_NAVIGATION);;
+      /* Create a new event based on received one and then send it */
+      ...
+      gst_event_unref (event);
+      return gst_pad_event_default (pad, new_event);
+    default:
+      /* Falling back to default event handling for that pad */
+      return gst_pad_event_default (pad, event);
+  }
+}
+    ]]></programlisting>
+  </sect1>
 </chapter>
 </chapter>
index c7a3788..fdf9a4c 100644 (file)
@@ -490,31 +490,31 @@ gst_my_filter_probe_interface_init (GstPropertyProbeInterface *iface)
     </para>
     <programlisting><![CDATA[
 static void
     </para>
     <programlisting><![CDATA[
 static void
-gst_myplugin_set_xwindow_id (GstXOverlay *overlay, XID xwindow_id)
+gst_my_filter_set_xwindow_id (GstXOverlay *overlay, XID xwindow_id)
 {
 {
-  GstMyPlugin *my_plugin = GST_MYPLUGIN (overlay);
-  
-  if (my_plugin->window)
-    gst_myplugin_destroy_window (myplugin->window);
+  GstMyFilter *my_filter = GST_MY_FILTER (overlay);
+
+  if (my_filter->window)
+    gst_my_filter_destroy_window (my_filter->window);
     
     
-  myplugin->window = xwindow_id;
+  my_filter->window = xwindow_id;
 }
 
 static void
 }
 
 static void
-gst_myplugin_get_desired_size (GstXOverlay *overlay,
-                             guint *width, guint *height)
+gst_my_filter_get_desired_size (GstXOverlay *overlay,
+                                guint *width, guint *height)
 {
 {
-  GstMyPlugin *my_plugin = GST_MYPLUGIN (overlay);
+  GstMyFilter *my_filter = GST_MY_FILTER (overlay);
 
 
-  *width = my_plugin->width;
-  *height = my_plugin->height;
+  *width = my_filter->width;
+  *height = my_filter->height;
 }
 
 static void
 }
 
 static void
-gst_myplugin_xoverlay_init (GstXOverlayClass *iface)
+gst_my_filter_xoverlay_init (GstXOverlayClass *iface)
 {
 {
-  iface->set_xwindow_id = gst_myplugin_set_xwindow_id;
-  iface->get_desired_size = gst_myplugin_get_desired_size;
+  iface->set_xwindow_id = gst_my_filter_set_xwindow_id;
+  iface->get_desired_size = gst_my_filter_get_desired_size;
 }
     ]]></programlisting>
     <para>
 }
     ]]></programlisting>
     <para>
@@ -523,18 +523,18 @@ gst_myplugin_xoverlay_init (GstXOverlayClass *iface)
       geometry and maybe create the window.
     </para>
     <programlisting><![CDATA[
       geometry and maybe create the window.
     </para>
     <programlisting><![CDATA[
-static MyPluginWindow *
-gst_myplugin_window_create (GstMyPlugin *my_plugin, gint width, gint height)
+static MyFilterWindow *
+gst_my_filter_window_create (GstMyFilter *my_filter, gint width, gint height)
 {
 {
-  MyPluginWindow *window = g_new (MyPluginWindow, 1);
+  MyFilterWindow *window = g_new (MyFilterWindow, 1);
   ...
   ...
-  gst_x_overlay_got_xwindow_id (GST_X_OVERLAY (my_plugin), window->win);
+  gst_x_overlay_got_xwindow_id (GST_X_OVERLAY (my_filter), window->win);
 }
 
 static GstPadLinkReturn
 }
 
 static GstPadLinkReturn
-gst_myplugin_sinkconnect (GstPad *pad, const GstCaps *caps)
+gst_my_filter_sink_link (GstPad *pad, const GstCaps *caps)
 {
 {
-  GstMyPlugin *my_plugin = GST_MYPLUGIN (overlay);
+  GstMyFilter *my_filter = GST_MY_FILTER (overlay);
   gint width, height;
   gboolean ret;
   ...
   gint width, height;
   gboolean ret;
   ...
@@ -542,10 +542,10 @@ gst_myplugin_sinkconnect (GstPad *pad, const GstCaps *caps)
   ret &= gst_structure_get_int (structure, "height", &height);
   if (!ret) return GST_PAD_LINK_REFUSED;
   
   ret &= gst_structure_get_int (structure, "height", &height);
   if (!ret) return GST_PAD_LINK_REFUSED;
   
-  if (!my_plugin->window)
-    my_plugin->window = gst_myplugin_create_window (my_plugin, width, height);
+  if (!my_filter->window)
+    my_filter->window = gst_my_filter_create_window (my_filter, width, height);
 
 
-  gst_x_overlay_got_desired_size (GST_X_OVERLAY (my_plugin),
+  gst_x_overlay_got_desired_size (GST_X_OVERLAY (my_filter),
                                   width, height);
   ...
 }
                                   width, height);
   ...
 }