pwg: rework dynamic pads docs
authorWim Taymans <wim.taymans@collabora.co.uk>
Fri, 28 Sep 2012 11:25:49 +0000 (13:25 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Fri, 28 Sep 2012 11:25:49 +0000 (13:25 +0200)
docs/pwg/advanced-request.xml

index dc71d82..8ef9897 100644 (file)
@@ -53,17 +53,18 @@ typedef struct _GstMyFilter {
   GList *srcpadlist;
 } GstMyFilter;
 
+static GstStaticPadTemplate src_factory =
+GST_STATIC_PAD_TEMPLATE (
+  "src_%u",
+  GST_PAD_SRC,
+  GST_PAD_SOMETIMES,
+  GST_STATIC_CAPS ("ANY")
+);
+
 static void
-gst_my_filter_base_init (GstMyFilterClass *klass)
+gst_my_filter_class_init (GstMyFilterClass *klass)
 {
   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
-  static GstStaticPadTemplate src_factory =
-  GST_STATIC_PAD_TEMPLATE (
-    "src_%02d",
-    GST_PAD_SRC,
-    GST_PAD_SOMETIMES,
-    GST_STATIC_CAPS ("ANY")
-  );
 [..]
   gst_element_class_add_pad_template (element_class,
        gst_static_pad_template_get (&src_factory));
@@ -96,11 +97,11 @@ gst_my_filter_getline (GstMyFilter *filter)
 
     /* newline? */
     if (data[n] == '\n') {
-      GstBuffer *buf = gst_buffer_new_and_alloc (n + 1);
+      GstBuffer *buf = gst_buffer_new_allocate (NULL, n + 1, NULL);
 
       gst_bytestream_peek_bytes (filter->bs, &data, n);
-      memcpy (GST_BUFFER_DATA (buf), data, n);
-      GST_BUFFER_DATA (buf)[n] = '\0';
+      gst_buffer_fill (buf, 0, data, n);
+      gst_buffer_memset (buf, n, '\0', 1);
       gst_bytestream_flush_fast (filter->bs, n + 1);
 
       return buf;
@@ -114,31 +115,33 @@ gst_my_filter_loopfunc (GstElement *element)
   GstMyFilter *filter = GST_MY_FILTER (element);
   GstBuffer *buf;
   GstPad *pad;
+  GstMapInfo map;
   gint num, n;
 
   /* parse header */
   if (filter->firstrun) {
-    GstElementClass *klass;
-    GstPadTemplate *templ;
     gchar *padname;
+    guint8 id;
 
     if (!(buf = gst_my_filter_getline (filter))) {
       gst_element_error (element, STREAM, READ, (NULL),
                         ("Stream contains no header"));
       return;
     }
-    num = atoi (GST_BUFFER_DATA (buf));
+    gst_buffer_extract (buf, 0, &id, 1);
+    num = atoi (id);
     gst_buffer_unref (buf);
 
     /* for each of the streams, create a pad */
-    klass = GST_ELEMENT_GET_CLASS (filter);
-    templ = gst_element_class_get_pad_template (klass, "src_%02d");
     for (n = 0; n < num; n++) {
-      padname = g_strdup_printf ("src_%02d", n);
-      pad = gst_pad_new_from_template (templ, padname);
+      padname = g_strdup_printf ("src_%u", n);
+      pad = gst_pad_new_from_static_template (src_factory, padname);
       g_free (padname);
 
-      /* here, you would set _getcaps () and _link () functions */
+      /* here, you would set _event () and _query () functions */
+
+      /* need to activate the pad before adding */
+      gst_pad_set_active (pad, TRUE);
 
       gst_element_add_pad (element, pad);
       filter->srcpadlist = g_list_append (filter->srcpadlist, pad);
@@ -153,36 +156,37 @@ gst_my_filter_loopfunc (GstElement *element)
     for (padlist = srcpadlist;
          padlist != NULL; padlist = g_list_next (padlist)) {
       pad = GST_PAD (padlist->data);
-      gst_event_ref (event);
-      gst_pad_push (pad, GST_DATA (event));
+      gst_pad_push_event (pad, gst_event_ref (event));
     }
     gst_event_unref (event);
-    gst_element_set_eos (element);
-
+    /* pause the task here */
     return;
   }
 
   /* parse stream number and go beyond the ':' in the data */
-  num = atoi (GST_BUFFER_DATA (buf));
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  num = atoi (map.data[0]);
   if (num >= 0 && num < g_list_length (filter->srcpadlist)) {
     pad = GST_PAD (g_list_nth_data (filter->srcpadlist, num);
 
     /* magic buffer parsing foo */
-    for (n = 0; GST_BUFFER_DATA (buf)[n] != ':' &&
-                GST_BUFFER_DATA (buf)[n] != '\0'; n++) ;
-    if (GST_BUFFER_DATA (buf)[n] != '\0') {
+    for (n = 0; map.data[n] != ':' &&
+                map.data[n] != '\0'; n++) ;
+    if (map.data[n] != '\0') {
       GstBuffer *sub;
 
-      /* create subbuffer that starts right past the space. The reason
+      /* create region copy that starts right past the space. The reason
        * that we don't just forward the data pointer is because the
        * pointer is no longer the start of an allocated block of memory,
        * but just a pointer to a position somewhere in the middle of it.
        * That cannot be freed upon disposal, so we'd either crash or have
-       * a memleak. Creating a subbuffer is a simple way to solve that. */
-      sub = gst_buffer_create_sub (buf, n + 1, GST_BUFFER_SIZE (buf) - n - 1);
-      gst_pad_push (pad, GST_DATA (sub));
+       * a memleak. Creating a region copy is a simple way to solve that. */
+      sub = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
+          n + 1, map.size - n - 1);
+      gst_pad_push (pad, sub);
     }
   }
+  gst_buffer_unmap (buf, &map);
   gst_buffer_unref (buf);
 }
 ]]>
@@ -207,46 +211,52 @@ gst_my_filter_loopfunc (GstElement *element)
       where - for each elementary stream that is to be placed in the output
       system stream - one sink pad will be requested. It can also be used in
       elements with a variable number of input or outputs pads, such as the
-      <classname>tee</classname> (multi-output), <classname>switch</classname>
-      or <classname>aggregator</classname> (both multi-input) elements. At the
-      time of writing this, it is unclear to me who is responsible for cleaning
-      up the created pad and how or when that should be done. Below is a simple
-      example of an aggregator based on request pads.
+      <classname>tee</classname> (multi-output) or
+      <classname>input-selector</classname> (multi-input) elements.
+    </para>
+    <para>
+      To implement request pads, you need to provide a padtemplate with a
+      GST_PAD_REQUEST presence and implement the
+      <function>request_new_pad</function> virtual method in
+      <classname>GstElement</classname>.
+      To clean up, you will need to implement the
+      <function>release_pad</function> virtual method.
     </para>
     <programlisting>
 <![CDATA[
 static GstPad *        gst_my_filter_request_new_pad   (GstElement     *element,
                                                 GstPadTemplate *templ,
-                                                const gchar    *name);
+                                                 const gchar    *name,
+                                                 const GstCaps  *caps);
+
+static void gst_my_filter_release_pad (GstElement *element,
+                                       GstPad *pad);
+
+static GstStaticPadTemplate sink_factory =
+GST_STATIC_PAD_TEMPLATE (
+  "sink_%u",
+  GST_PAD_SINK,
+  GST_PAD_REQUEST,
+  GST_STATIC_CAPS ("ANY")
+);
 
 static void
-gst_my_filter_base_init (GstMyFilterClass *klass)
+gst_my_filter_class_init (GstMyFilterClass *klass)
 {
   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
-  static GstStaticPadTemplate sink_factory =
-  GST_STATIC_PAD_TEMPLATE (
-    "sink_%d",
-    GST_PAD_SINK,
-    GST_PAD_REQUEST,
-    GST_STATIC_CAPS ("ANY")
-  );
 [..]
   gst_element_class_add_pad_template (klass,
        gst_static_pad_template_get (&sink_factory));
-}
-
-static void
-gst_my_filter_class_init (GstMyFilterClass *klass)
-{
-  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
 [..]
   element_class->request_new_pad = gst_my_filter_request_new_pad;
+  element_class->release_pad = gst_my_filter_release_pad;
 }
 
 static GstPad *
 gst_my_filter_request_new_pad (GstElement     *element,
                               GstPadTemplate *templ,
-                              const gchar    *name)
+                              const gchar    *name,
+                               const GstCaps  *caps)
 {
   GstPad *pad;
   GstMyFilterInputContext *context;
@@ -255,12 +265,25 @@ gst_my_filter_request_new_pad (GstElement     *element,
   pad = gst_pad_new_from_template (templ, name);
   gst_pad_set_element_private (pad, context);
 
-  /* normally, you would set _link () and _getcaps () functions here */
+  /* normally, you would set _chain () and _event () functions here */
 
   gst_element_add_pad (element, pad);
 
   return pad;
 }
+
+static void
+gst_my_filter_release_pad (GstElement *element,
+                           GstPad *pad)
+{
+  GstMyFilterInputContext *context;
+
+  context = gst_pad_get_element_private (pad);
+  g_free (context);
+
+  gst_element_remove_pad (element, pad);
+}
+
 ]]>
     </programlisting>
   </sect1>