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