2002-09-27 18:34:33 +00:00
|
|
|
|
|
|
|
<!-- ############ chapter ############# -->
|
|
|
|
|
2004-01-28 15:51:14 +00:00
|
|
|
<chapter id="chapter-building-chainfn">
|
2002-09-27 18:34:33 +00:00
|
|
|
<title>The chain function</title>
|
|
|
|
<para>
|
2004-01-27 13:33:39 +00:00
|
|
|
The chain function is the function in which all data processing takes
|
|
|
|
place. In the case of a simple filter, <function>_chain ()</function>
|
2004-11-06 10:28:07 +00:00
|
|
|
functions are mostly linear functions - so for each incoming buffer,
|
2004-01-27 13:33:39 +00:00
|
|
|
one buffer will go out, too. Below is a very simple implementation of
|
|
|
|
a chain function:
|
|
|
|
</para>
|
2005-07-01 12:43:03 +00:00
|
|
|
<programlisting><!-- example-begin chain.c a --><!--
|
|
|
|
#include "init.func"
|
|
|
|
#include "caps.func"
|
|
|
|
static gboolean
|
|
|
|
gst_my_filter_event (GstPad * pad, GstEvent * event)
|
2004-01-27 13:33:39 +00:00
|
|
|
{
|
2005-07-01 12:43:03 +00:00
|
|
|
return gst_pad_event_default (pad, event);
|
|
|
|
}
|
|
|
|
--><!-- example-end chain.c a -->
|
|
|
|
<!-- example-begin chain.c b -->
|
|
|
|
static GstFlowReturn
|
|
|
|
gst_my_filter_chain (GstPad *pad,
|
|
|
|
GstBuffer *buf)
|
|
|
|
{
|
|
|
|
GstMyFilter *filter = GST_MY_FILTER (GST_OBJECT_PARENT (pad));
|
2004-01-27 13:33:39 +00:00
|
|
|
|
|
|
|
if (!filter->silent)
|
|
|
|
g_print ("Have data of size %u bytes!\n", GST_BUFFER_SIZE (buf));
|
|
|
|
|
2005-07-01 12:43:03 +00:00
|
|
|
return gst_pad_push (filter->srcpad, buf);
|
2004-01-27 13:33:39 +00:00
|
|
|
}
|
2005-07-01 12:43:03 +00:00
|
|
|
<!-- example-end chain.c b -->
|
|
|
|
<!-- example-begin chain.c c --><!--
|
|
|
|
static GstElementStateReturn
|
|
|
|
gst_my_filter_change_state (GstElement * element)
|
|
|
|
{
|
|
|
|
return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS,
|
|
|
|
change_state, (element), GST_STATE_SUCCESS);
|
|
|
|
}
|
|
|
|
#include "register.func"
|
|
|
|
--><!-- example-end chain.c c --></programlisting>
|
2004-01-27 13:33:39 +00:00
|
|
|
<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 writable. In more advanced elements (the ones
|
2005-07-01 12:43:03 +00:00
|
|
|
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 end-of-stream, discontinuities, tags, etc.).
|
2004-01-27 13:33:39 +00:00
|
|
|
</para>
|
|
|
|
<programlisting>
|
|
|
|
static void
|
2005-07-01 12:43:03 +00:00
|
|
|
gst_my_filter_init (GstMyFilter * filter)
|
2004-01-27 13:33:39 +00:00
|
|
|
{
|
2005-07-01 12:43:03 +00:00
|
|
|
[..]
|
|
|
|
gst_pad_set_event_function (filter->sinkpad,
|
|
|
|
gst_my_filter_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)
|
|
|
|
{
|
|
|
|
}
|
2004-01-27 13:33:39 +00:00
|
|
|
|
2005-07-01 12:43:03 +00:00
|
|
|
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_event (GstPad *pad,
|
|
|
|
GstEvent *event)
|
|
|
|
{
|
|
|
|
GstMyFilter *filter = GST_MY_FILTER (GST_OBJECT_PARENT (pad));
|
2004-01-27 13:33:39 +00:00
|
|
|
|
2005-07-01 12:43:03 +00:00
|
|
|
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);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2004-01-27 13:33:39 +00:00
|
|
|
}
|
|
|
|
|
2005-07-01 12:43:03 +00:00
|
|
|
return gst_pad_event_default (pad, event);
|
|
|
|
}
|
|
|
|
|
|
|
|
static GstFlowReturn
|
|
|
|
gst_my_filter_chain (GstPad *pad,
|
|
|
|
GstBuffer *buf)
|
|
|
|
{
|
|
|
|
GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad));
|
|
|
|
GstBuffer *outbuf;
|
|
|
|
|
|
|
|
outbuf = gst_my_filter_process_data (filter, buf);
|
2004-01-27 13:33:39 +00:00
|
|
|
gst_buffer_unref (buf);
|
|
|
|
if (!outbuf) {
|
|
|
|
/* something went wrong - signal an error */
|
2005-07-01 12:43:03 +00:00
|
|
|
GST_ELEMENT_ERROR (GST_ELEMENT (filter), STREAM, FAILED, (NULL), (NULL));
|
|
|
|
return GST_FLOW_ERROR;
|
2004-01-27 13:33:39 +00:00
|
|
|
}
|
|
|
|
|
2005-07-01 12:43:03 +00:00
|
|
|
return gst_pad_push (filter->srcpad, outbuf);
|
|
|
|
}
|
|
|
|
<!-- example-end chain.func b -->
|
|
|
|
<!-- example-begin chain2.c b --><!--
|
|
|
|
static GstElementStateReturn
|
|
|
|
gst_my_filter_change_state (GstElement * element)
|
|
|
|
{
|
|
|
|
return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS,
|
|
|
|
change_state, (element), GST_STATE_SUCCESS);
|
2004-01-27 13:33:39 +00:00
|
|
|
}
|
2005-07-01 12:43:03 +00:00
|
|
|
#include "register.func"
|
|
|
|
--><!-- example-end chain2.c b --></programlisting>
|
2004-01-27 13:33:39 +00:00
|
|
|
<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.
|
2002-09-27 18:34:33 +00:00
|
|
|
</para>
|
|
|
|
</chapter>
|