2 title: Request and Sometimes pads
5 # Request and Sometimes pads
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.
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
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.
45 The code to parse this file and create the dynamic “sometimes” pads,
50 typedef struct _GstMyFilter {
56 static GstStaticPadTemplate src_factory =
57 GST_STATIC_PAD_TEMPLATE (
61 GST_STATIC_CAPS ("ANY")
65 gst_my_filter_class_init (GstMyFilterClass *klass)
67 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
69 gst_element_class_add_pad_template (element_class,
70 gst_static_pad_template_get (&src_factory));
75 gst_my_filter_init (GstMyFilter *filter)
78 filter->firstrun = TRUE;
79 filter->srcpadlist = NULL;
83 * Get one line of data - without newline.
87 gst_my_filter_getline (GstMyFilter *filter)
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);
99 if (data[n] == '\n') {
100 GstBuffer *buf = gst_buffer_new_allocate (NULL, n + 1, NULL);
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);
113 gst_my_filter_loopfunc (GstElement *element)
115 GstMyFilter *filter = GST_MY_FILTER (element);
122 if (filter->firstrun) {
126 if (!(buf = gst_my_filter_getline (filter))) {
127 gst_element_error (element, STREAM, READ, (NULL),
128 ("Stream contains no header"));
131 gst_buffer_extract (buf, 0, &id, 1);
133 gst_buffer_unref (buf);
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);
141 /* here, you would set _event () and _query () functions */
143 /* need to activate the pad before adding */
144 gst_pad_set_active (pad, TRUE);
146 gst_element_add_pad (element, pad);
147 filter->srcpadlist = g_list_append (filter->srcpadlist, pad);
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);
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));
161 gst_event_unref (event);
162 /* pause the task here */
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);
172 /* magic buffer parsing foo */
173 for (n = 0; map.data[n] != ':' &&
174 map.data[n] != '\0'; n++) ;
175 if (map.data[n] != '\0') {
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);
189 gst_buffer_unmap (buf, &map);
190 gst_buffer_unref (buf);
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
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.
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.
221 static GstPad * gst_my_filter_request_new_pad (GstElement *element,
222 GstPadTemplate *templ,
224 const GstCaps *caps);
226 static void gst_my_filter_release_pad (GstElement *element,
229 static GstStaticPadTemplate sink_factory =
230 GST_STATIC_PAD_TEMPLATE (
234 GST_STATIC_CAPS ("ANY")
238 gst_my_filter_class_init (GstMyFilterClass *klass)
240 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
242 gst_element_class_add_pad_template (klass,
243 gst_static_pad_template_get (&sink_factory));
245 element_class->request_new_pad = gst_my_filter_request_new_pad;
246 element_class->release_pad = gst_my_filter_release_pad;
250 gst_my_filter_request_new_pad (GstElement *element,
251 GstPadTemplate *templ,
256 GstMyFilterInputContext *context;
258 context = g_new0 (GstMyFilterInputContext, 1);
259 pad = gst_pad_new_from_template (templ, name);
260 gst_pad_set_element_private (pad, context);
262 /* normally, you would set _chain () and _event () functions here */
264 gst_element_add_pad (element, pad);
270 gst_my_filter_release_pad (GstElement *element,
273 GstMyFilterInputContext *context;
275 context = gst_pad_get_element_private (pad);
278 gst_element_remove_pad (element, pad);