mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-27 18:50:48 +00:00
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:
parent
55072fb611
commit
a093da6d7d
3 changed files with 179 additions and 24 deletions
|
@ -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:
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
...
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue