docs/pwg/advanced-events.xml: Adding documentation on advanced event handling (up and downstream).

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.
This commit is contained in:
Julien Moutte 2004-01-29 12:46:19 +00:00
parent 55072fb611
commit a093da6d7d
3 changed files with 179 additions and 24 deletions

View file

@ -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:

View file

@ -1,6 +1,154 @@
<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>
<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>

View file

@ -490,31 +490,31 @@ gst_my_filter_probe_interface_init (GstPropertyProbeInterface *iface)
</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
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
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>
@ -523,18 +523,18 @@ gst_myplugin_xoverlay_init (GstXOverlayClass *iface)
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
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;
...
@ -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;
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);
...
}