blob: 137ca496322d1252d730e9539524628f08773948 [file] [log] [blame]
<!-- ############ chapter ############# -->
<chapter id="chapter-building-chainfn">
<title>The chain function</title>
<para>
The chain function is the function in which all data processing takes
place. In the case of a simple filter, <function>_chain ()</function>
functions are mostly linear functions - so for each incoming buffer,
one buffer will go out, too. Below is a very simple implementation of
a chain function:
</para>
<programlisting><!-- example-begin chain.c a --><!--
#include "init.func"
#include "caps.func"
static gboolean
gst_my_filter_event (GstPad * pad, GstObject * parent, GstEvent * event)
{
return gst_pad_event_default (pad, parent, event);
}
--><!-- example-end chain.c a -->
<!-- example-begin chain.c b -->
static GstFlowReturn gst_my_filter_chain (GstPad *pad,
GstObject *parent,
GstBuffer *buf);
[..]
static void
gst_my_filter_init (GstMyFilter * filter)
{
[..]
/* configure chain function on the pad before adding
* the pad to the element */
gst_pad_set_chain_function (filter-&gt;sinkpad,
gst_my_filter_chain);
[..]
}
static GstFlowReturn
gst_my_filter_chain (GstPad *pad,
GstObject *parent,
GstBuffer *buf)
{
GstMyFilter *filter = GST_MY_FILTER (parent);
if (!filter->silent)
g_print ("Have data of size %" G_GSIZE_FORMAT" bytes!\n",
gst_buffer_get_size (buf));
return gst_pad_push (filter->srcpad, buf);
}
<!-- example-end chain.c b -->
<!-- example-begin chain.c c --><!--
static GstStateChangeReturn
gst_my_filter_change_state (GstElement * element, GstStateChange transition)
{
return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS,
change_state, (element, transition), GST_STATE_CHANGE_SUCCESS);
}
#include "register.func"
--><!-- example-end chain.c c --></programlisting>
<para>
Obviously, the above doesn't do much useful. Instead of printing that the
data is in, you would normally process the data there. Remember, however,
that buffers are not always writeable.
</para>
<para>
In more advanced elements (the ones that do event processing), you may want
to additionally specify an event handling function, which will be called
when stream-events are sent (such as caps, end-of-stream, newsegment, tags, etc.).
</para>
<programlisting>
static void
gst_my_filter_init (GstMyFilter * filter)
{
[..]
gst_pad_set_event_function (filter-&gt;sinkpad,
gst_my_filter_sink_event);
[..]
}
<!-- example-begin chain2.c a --><!--
#include "init.func"
#include "caps.func"
#include "chain.func"
--><!-- example-end chain2.c a -->
<!-- example-begin chain.func a --><!--
static void
gst_my_filter_stop_processing (GstMyFilter * filter)
{
}
static GstBuffer *
gst_my_filter_process_data (GstMyFilter * filter, const GstBuffer * buf)
{
return NULL;
}
--><!-- example-end chain.func a -->
<!-- example-begin chain.func b -->
static gboolean
gst_my_filter_sink_event (GstPad *pad,
GstObject *parent,
GstEvent *event)
{
GstMyFilter *filter = GST_MY_FILTER (parent);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_CAPS:
/* we should handle the format here */
break;
case GST_EVENT_EOS:
/* end-of-stream, we should close down all stream leftovers here */
gst_my_filter_stop_processing (filter);
break;
default:
break;
}
return gst_pad_event_default (pad, parent, event);
}
static GstFlowReturn
gst_my_filter_chain (GstPad *pad,
GstObject *parent,
GstBuffer *buf)
{
GstMyFilter *filter = GST_MY_FILTER (parent);
GstBuffer *outbuf;
outbuf = gst_my_filter_process_data (filter, buf);
gst_buffer_unref (buf);
if (!outbuf) {
/* something went wrong - signal an error */
GST_ELEMENT_ERROR (GST_ELEMENT (filter), STREAM, FAILED, (NULL), (NULL));
return GST_FLOW_ERROR;
}
return gst_pad_push (filter->srcpad, outbuf);
}
<!-- example-end chain.func b -->
<!-- example-begin chain2.c b --><!--
static GstStateChangeReturn
gst_my_filter_change_state (GstElement * element, GstStateChange transition)
{
return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS,
change_state, (element, transition), GST_STATE_CHANGE_SUCCESS);
}
#include "register.func"
--><!-- example-end chain2.c b --></programlisting>
<para>
In some cases, it might be useful for an element to have control over the
input data rate, too. In that case, you probably want to write a so-called
<emphasis>loop-based</emphasis> element. Source elements (with only source
pads) can also be <emphasis>get-based</emphasis> elements. These concepts
will be explained in the advanced section of this guide, and in the section
that specifically discusses source pads.
</para>
</chapter>