<!-- ############ 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->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->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>