Initialize Tizen 2.3
[framework/multimedia/gstreamer0.10.git] / mobile / 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 chapter 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 <![CDATA[
50 typedef struct _GstMyFilter {
51 [..]
52   gboolean firstrun;
53   GList *srcpadlist;
54 } GstMyFilter;
55
56 static void
57 gst_my_filter_base_init (GstMyFilterClass *klass)
58 {
59   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
60   static GstStaticPadTemplate src_factory =
61   GST_STATIC_PAD_TEMPLATE (
62     "src_%02d",
63     GST_PAD_SRC,
64     GST_PAD_SOMETIMES,
65     GST_STATIC_CAPS ("ANY")
66   );
67 [..]
68   gst_element_class_add_pad_template (element_class,
69         gst_static_pad_template_get (&src_factory));
70 [..]
71 }
72
73 static void
74 gst_my_filter_init (GstMyFilter *filter)
75 {
76 [..]
77   filter->firstrun = TRUE;
78   filter->srcpadlist = NULL;
79 }
80
81 /*
82  * Get one line of data - without newline.
83  */
84
85 static GstBuffer *
86 gst_my_filter_getline (GstMyFilter *filter)
87 {
88   guint8 *data;
89   gint n, num;
90
91   /* max. line length is 512 characters - for safety */
92   for (n = 0; n < 512; n++) {
93     num = gst_bytestream_peek_bytes (filter->bs, &data, n + 1);
94     if (num != n + 1)
95       return NULL;
96
97     /* newline? */
98     if (data[n] == '\n') {
99       GstBuffer *buf = gst_buffer_new_and_alloc (n + 1);
100
101       gst_bytestream_peek_bytes (filter->bs, &data, n);
102       memcpy (GST_BUFFER_DATA (buf), data, n);
103       GST_BUFFER_DATA (buf)[n] = '\0';
104       gst_bytestream_flush_fast (filter->bs, n + 1);
105
106       return buf;
107     }
108   }
109 }
110
111 static void
112 gst_my_filter_loopfunc (GstElement *element)
113 {
114   GstMyFilter *filter = GST_MY_FILTER (element);
115   GstBuffer *buf;
116   GstPad *pad;
117   gint num, n;
118
119   /* parse header */
120   if (filter->firstrun) {
121     GstElementClass *klass;
122     GstPadTemplate *templ;
123     gchar *padname;
124
125     if (!(buf = gst_my_filter_getline (filter))) {
126       gst_element_error (element, STREAM, READ, (NULL),
127                          ("Stream contains no header"));
128       return;
129     }
130     num = atoi (GST_BUFFER_DATA (buf));
131     gst_buffer_unref (buf);
132
133     /* for each of the streams, create a pad */
134     klass = GST_ELEMENT_GET_CLASS (filter);
135     templ = gst_element_class_get_pad_template (klass, "src_%02d");
136     for (n = 0; n < num; n++) {
137       padname = g_strdup_printf ("src_%02d", n);
138       pad = gst_pad_new_from_template (templ, padname);
139       g_free (padname);
140
141       /* here, you would set _getcaps () and _link () functions */
142
143       gst_element_add_pad (element, pad);
144       filter->srcpadlist = g_list_append (filter->srcpadlist, pad);
145     }
146   }
147
148   /* and now, simply parse each line and push over */
149   if (!(buf = gst_my_filter_getline (filter))) {
150     GstEvent *event = gst_event_new (GST_EVENT_EOS);
151     GList *padlist;
152
153     for (padlist = srcpadlist;
154          padlist != NULL; padlist = g_list_next (padlist)) {
155       pad = GST_PAD (padlist->data);
156       gst_event_ref (event);
157       gst_pad_push (pad, GST_DATA (event));
158     }
159     gst_event_unref (event);
160     gst_element_set_eos (element);
161
162     return;
163   }
164
165   /* parse stream number and go beyond the ':' in the data */
166   num = atoi (GST_BUFFER_DATA (buf));
167   if (num >= 0 && num < g_list_length (filter->srcpadlist)) {
168     pad = GST_PAD (g_list_nth_data (filter->srcpadlist, num);
169
170     /* magic buffer parsing foo */
171     for (n = 0; GST_BUFFER_DATA (buf)[n] != ':' &&
172                 GST_BUFFER_DATA (buf)[n] != '\0'; n++) ;
173     if (GST_BUFFER_DATA (buf)[n] != '\0') {
174       GstBuffer *sub;
175
176       /* create subbuffer that starts right past the space. The reason
177        * that we don't just forward the data pointer is because the
178        * pointer is no longer the start of an allocated block of memory,
179        * but just a pointer to a position somewhere in the middle of it.
180        * That cannot be freed upon disposal, so we'd either crash or have
181        * a memleak. Creating a subbuffer is a simple way to solve that. */
182       sub = gst_buffer_create_sub (buf, n + 1, GST_BUFFER_SIZE (buf) - n - 1);
183       gst_pad_push (pad, GST_DATA (sub));
184     }
185   }
186   gst_buffer_unref (buf);
187 }
188 ]]>
189     </programlisting>
190     <para>
191       Note that we use a lot of checks everywhere to make sure that the content
192       in the file is valid. This has two purposes: first, the file could be
193       erroneous, in which case we prevent a crash. The second and most important
194       reason is that - in extreme cases - the file could be used maliciously to
195       cause undefined behaviour in the plugin, which might lead to security
196       issues. <emphasis>Always</emphasis> assume that the file could be used to
197       do bad things.
198     </para>
199   </sect1>
200
201   <sect1 id="section-reqpad-request" xreflabel="Request pads">
202     <title>Request pads</title>
203     <para>
204       <quote>Request</quote> pads are similar to sometimes pads, except that
205       request are created on demand of something outside of the element rather
206       than something inside the element. This concept is often used in muxers,
207       where - for each elementary stream that is to be placed in the output
208       system stream - one sink pad will be requested. It can also be used in
209       elements with a variable number of input or outputs pads, such as the
210       <classname>tee</classname> (multi-output), <classname>switch</classname>
211       or <classname>aggregator</classname> (both multi-input) elements. At the
212       time of writing this, it is unclear to me who is responsible for cleaning
213       up the created pad and how or when that should be done. Below is a simple
214       example of an aggregator based on request pads.
215     </para>
216     <programlisting>
217 <![CDATA[
218 static GstPad * gst_my_filter_request_new_pad   (GstElement     *element,
219                                                  GstPadTemplate *templ,
220                                                  const gchar    *name);
221
222 static void
223 gst_my_filter_base_init (GstMyFilterClass *klass)
224 {
225   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
226   static GstStaticPadTemplate sink_factory =
227   GST_STATIC_PAD_TEMPLATE (
228     "sink_%d",
229     GST_PAD_SINK,
230     GST_PAD_REQUEST,
231     GST_STATIC_CAPS ("ANY")
232   );
233 [..]
234   gst_element_class_add_pad_template (klass,
235         gst_static_pad_template_get (&sink_factory));
236 }
237
238 static void
239 gst_my_filter_class_init (GstMyFilterClass *klass)
240 {
241   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
242 [..]
243   element_class->request_new_pad = gst_my_filter_request_new_pad;
244 }
245
246 static GstPad *
247 gst_my_filter_request_new_pad (GstElement     *element,
248                                GstPadTemplate *templ,
249                                const gchar    *name)
250 {
251   GstPad *pad;
252   GstMyFilterInputContext *context;
253
254   context = g_new0 (GstMyFilterInputContext, 1);
255   pad = gst_pad_new_from_template (templ, name);
256   gst_pad_set_element_private (pad, context);
257
258   /* normally, you would set _link () and _getcaps () functions here */
259
260   gst_element_add_pad (element, pad);
261
262   return pad;
263 }
264 ]]>
265     </programlisting>
266   </sect1>
267 </chapter>