fix up id's
[platform/upstream/gstreamer.git] / docs / pwg / advanced-request.xml
1 <chapter id="chapter-advanced-request">
2   <title>Request and Sometimes pads</title>
3   <para>
4     Until now, we've only dealt with pads that are always available. However,
5     there's also pads that are only being created in some cases, or only if
6     the application requests the pad. The first is called a
7     <emphasis>sometimes</emphasis>; the second is called a
8     <emphasis>request</emphasis> pad. The availability of a pad (always,
9     sometimes or request) can be seen in a pad's template. This chapted will
10     discuss when each of the two is useful, how they are created and when
11     they should be disposed.
12   </para>
13
14   <sect1 id="section-reqpad-sometimes" xreflabel="Sometimes pads">
15     <title>Sometimes pads</title>
16     <para>
17       A <quote>sometimes</quote> pad is a pad that is created under certain
18       conditions, but not in all cases. This mostly depends on stream content:
19       demuxers will generally parse the stream header, decide what elementary
20       (video, audio, subtitle, etc.) streams are embedded inside the system
21       stream, and will then create a sometimes pad for each of those elementary
22       streams. At its own choice, it can also create more than one instance of
23       each of those per element instance. The only limitation is that each
24       newly created pad should have a unique name. Sometimes pads are disposed
25       when the stream data is disposed, too (i.e. when going from PAUSED to the
26       READY state). You should <emphasis>not</emphasis> dispose the pad on EOS,
27       because someone might re-activate the pipeline and seek back to before
28       the end-of-stream point. The stream should still stay valid after EOS, at
29       least until the stream data is disposed. In any case, the element is
30       always the owner of such a pad.
31     </para>
32     <para>
33       The example code below will parse a text file, where the first line is
34       a number (n). The next lines all start with a number (0 to n-1), which
35       is the number of the source pad over which the data should be sent.
36     </para>
37     <programlisting>
38 3
39 0: foo
40 1: bar
41 0: boo
42 2: bye
43     </programlisting>
44     <para>
45       The code to parse this file and create the dynamic <quote>sometimes</quote>
46       pads, looks like this:
47     </para>
48     <programlisting>
49 typedef struct _GstMyFilter {
50 [..]
51   gboolean firstrun;
52   GList *srcpadlist;
53 } GstMyFilter;
54
55 static void
56 gst_my_filter_base_init (GstMyFilterClass *klass)
57 {
58   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
59   static GstStaticPadTemplate src_factory =
60   GST_STATIC_PAD_TEMPLATE (
61     "src_%02d",
62     GST_PAD_SRC,
63     GST_PAD_SOMETIMES,
64     GST_STATIC_CAPS ("ANY")
65   );
66 [..]
67   gst_element_class_add_pad_template (element_class,
68         gst_static_pad_template_get (&amp;src_factory));
69 [..]
70 }
71
72 static void
73 gst_my_filter_init (GstMyFilter *filter)
74 {
75 [..]
76   filter->firstrun = TRUE;
77   filter->srcpadlist = NULL;
78 }
79
80 /*
81  * Get one line of data - without newline.
82  */
83
84 static GstBuffer *
85 gst_my_filter_getline (GstMyFilter *filter)
86 {
87   guint8 *data;
88   gint n, num;
89
90   /* max. line length is 512 characters - for safety */
91   for (n = 0; n < 512; n++) {
92     num = gst_bytestream_peek_bytes (filter->bs, &amp;data, n + 1);
93     if (num != n + 1)
94       return NULL;
95
96     /* newline? */
97     if (data[n] == '\n') {
98       GstBuffer *buf = gst_buffer_new_and_alloc (n + 1);
99
100       gst_bytestream_peek_bytes (filter->bs, &amp;data, n);
101       memcpy (GST_BUFFER_DATA (buf), data, n);
102       GST_BUFFER_DATA (buf)[n] = '\0';
103       gst_bytestream_flush_fast (filter->bs, n + 1);
104
105       return buf;
106     }
107   }
108 }
109
110 static void
111 gst_my_filter_loopfunc (GstElement *element)
112 {
113   GstMyFilter *filter = GST_MY_FILTER (element);
114   GstBuffer *buf;
115   GstPad *pad;
116   gint num, n;
117
118   /* parse header */
119   if (filter->firstrun) {
120     GstElementClass *klass;
121     GstPadTemplate *templ;
122     gchar *padname;
123
124     if (!(buf = gst_my_filter_getline (filter))) {
125       gst_element_error (element, STREAM, READ, (NULL),
126                          ("Stream contains no header"));
127       return;
128     }
129     num = atoi (GST_BUFFER_DATA (buf));
130     gst_buffer_unref (buf);
131
132     /* for each of the streams, create a pad */
133     klass = GST_ELEMENT_GET_CLASS (filter);
134     templ = gst_element_class_get_pad_template (klass, "src_%02d");
135     for (n = 0; n < num; n++) {
136       padname = g_strdup_printf ("src_%02d", n);
137       pad = gst_pad_new_from_template (templ, padname);
138       g_free (padname);
139
140       /* here, you would set _getcaps () and _link () functions */
141
142       gst_element_add_pad (element, pad);
143       filter->srcpadlist = g_list_append (filter->srcpadlist, pad);
144     }
145   }
146
147   /* and now, simply parse each line and push over */
148   if (!(buf = gst_my_filter_getline (filter))) {
149     GstEvent *event = gst_event_new (GST_EVENT_EOS);
150     GList *padlist;
151
152     for (padlist = srcpadlist;
153          padlist != NULL; padlist = g_list_next (padlist)) {
154       pad = GST_PAD (padlist->data);
155       gst_event_ref (event);
156       gst_pad_push (pad, GST_DATA (event));
157     }
158     gst_event_unref (event);
159     gst_element_set_eos (element);
160
161     return;
162   }
163
164   /* parse stream number and go beyond the ':' in the data */
165   num = atoi (GST_BUFFER_DATA (buf));
166   if (num >= 0 &amp;&amp; num < g_list_length (filter->srcpadlist)) {
167     pad = GST_PAD (g_list_nth_data (filter->srcpadlist, num);
168
169     /* magic buffer parsing foo */
170     for (n = 0; GST_BUFFER_DATA (buf)[n] != ':' &amp;&amp;
171                 GST_BUFFER_DATA (buf)[n] != '\0'; n++) ;
172     if (GST_BUFFER_DATA (buf)[n] != '\0') {
173       GstBuffer *sub;
174
175       /* create subbuffer that starts right past the space. The reason
176        * that we don't just forward the data pointer is because the
177        * pointer is no longer the start of an allocated block of memory,
178        * but just a pointer to a position somewhere in the middle of it.
179        * That cannot be freed upon disposal, so we'd either crash or have
180        * a memleak. Creating a subbuffer is a simple way to solve that. */
181       sub = gst_buffer_create_sub (buf, n + 1, GST_BUFFER_SIZE (buf) - n - 1);
182       gst_pad_push (pad, GST_DATA (sub));
183     }
184   }
185   gst_buffer_unref (buf);
186 }
187     </programlisting>
188     <para>
189       Note that we use a lot of checks everywhere to make sure that the content
190       in the file is valid. This has two purposes: first, the file could be
191       erronous, in which case we prevent a crash. The second and most important
192       reason is that - in extreme cases - the file could be used maliciously to
193       cause undefined behaviour in the plugin, which might lead to security
194       issues. <emphasis>Always</emphasis> assume that the file could be used to
195       do bad things.
196     </para>
197   </sect1>
198
199   <sect1 id="section-reqpad-request" xreflabel="Request pads">
200     <title>Request pads</title>
201     <para>
202       <quote>Request</quote> pads are similar to sometimes pads, except that
203       request are created on demand of something outside of the element rather
204       than something inside the element. This concept is often used in muxers,
205       where - for each elementary stream that is to be placed in the output
206       system stream - one sink pad will be requested. It can also be used in
207       elements with a variable number of input or outputs pads, such as the
208       <classname>tee</classname> (multi-output), <classname>switch</classname>
209       or <classname>aggregator</classname> (both multi-input) elements. At the
210       time of writing this, it is unclear to me who is responsible for cleaning
211       up the created pad and how or when that should be done. Below is a simple
212       example of an aggregator based on request pads.
213     </para>
214     <programlisting>
215 static GstPad * gst_my_filter_request_new_pad   (GstElement     *element,
216                                                  GstPadTemplate *templ,
217                                                  const gchar    *name);
218
219 static void
220 gst_my_filter_base_init (GstMyFilterClass *klass)
221 {
222   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
223   static GstStaticPadTemplate sink_factory =
224   GST_STATIC_PAD_TEMPLATE (
225     "sink_%d",
226     GST_PAD_SINK,
227     GST_PAD_REQUEST,
228     GST_STATIC_CAPS ("ANY")
229   );
230 [..]
231   gst_element_class_add_pad_template (klass,
232         gst_static_pad_template_get (&amp;sink_factory));
233 }
234
235 static void
236 gst_my_filter_class_init (GstMyFilterClass *klass)
237 {
238   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
239 [..]
240   element_class->request_new_pad = gst_my_filter_request_new_pad;
241 }
242
243 static GstPad *
244 gst_my_filter_request_new_pad (GstElement     *element,
245                                GstPadTemplate *templ,
246                                const gchar    *name)
247 {
248   GstPad *pad;
249   GstMyFilterInputContext *context;
250
251   context = g_new0 (GstMyFilterInputContext, 1);
252   pad = gst_pad_new_from_template (templ, name);
253   gst_element_set_private_data (pad, context);
254
255   /* normally, you would set _link () and _getcaps () functions here */
256
257   gst_element_add_pad (element, pad);
258
259   return pad;
260 }
261     </programlisting>
262     <para>
263       The <function>_loop ()</function> function is the same as the one given
264       previously in <xref linkend="section-loopfn-multiinput"/>.
265     </para>
266   </sect1>
267 </chapter>