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