aboutsummaryrefslogtreecommitdiff
path: root/docs/pwg/building-chainfn.xml
blob: 137ca496322d1252d730e9539524628f08773948 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158

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