element: Inherit element metadata and pad templates from parent classes
authorSebastian Dröge <sebastian.droege@collabora.co.uk>
Sat, 16 Apr 2011 13:03:33 +0000 (15:03 +0200)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Sat, 16 Apr 2011 13:59:35 +0000 (15:59 +0200)
This allows to add pad templates and set metadata in class_init instead of
base_init. base_init is a concept that is not supported by almost all
languages and copying the templates/metadata for subclasses is the more
intuitive way of doing things.

Subclasses can override pad templates of parent classes by adding a new
template with the same now.

Also gst_element_class_add_pad_template() now takes ownership of the
pad template, which was assumed by all code before anyway.

Fixes bug #491501.

docs/random/porting-to-0.11.txt
gst/gstelement.c
gst/gstpadtemplate.c

index 9c221cf..9d601d2 100644 (file)
@@ -45,6 +45,11 @@ The 0.11 porting guide
 
     gstelementmetadata.h contains the keys for all standard metadata.
 
+    Element metadata and pad templates are inherited from parent classes and
+    should be added in class_init instead of base_init.
+
+    gst_element_class_add_pad_template() takes ownership of the template
+
 * GstPad:
     gst_pad_get_caps() does not return writable caps anymore and an explicit
     gst_caps_make_writable() needs to be performed. This was the functionality
index a52788d..2e8028b 100644 (file)
@@ -238,18 +238,29 @@ static void
 gst_element_base_class_init (gpointer g_class)
 {
   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
-  /* FIXME 0.11: Instead of clearing the
-   * pad template list copy the list and increase the refcount of
-   * the pad templates by one.
-   *
-   * This will make it possible to add pad templates and set element
-   * details in the class_init functions and is the real GObject way
-   * of doing things.
-   * See http://bugzilla.gnome.org/show_bug.cgi?id=491501
+  GList *node, *padtemplates;
+
+  /* Copy the element details here so elements can inherit the
+   * details from their base class and classes only need to set
+   * the details in class_init instead of base_init */
+  element_class->metadata =
+      element_class->metadata ? gst_structure_copy (element_class->metadata) :
+      gst_structure_empty_new ("metadata");
+
+  /* Copy the pad templates so elements inherit them
+   * from their base class but elements can add pad templates in class_init
+   * instead of base_init.
+   */
+  /* FIXME: Do we consider GstPadTemplates as immutable? If so we can
+   * simply ref them instead of copying.
    */
-  element_class->metadata = gst_structure_empty_new ("metadata");
-  element_class->padtemplates = NULL;
+  padtemplates = g_list_copy (element_class->padtemplates);
+  for (node = padtemplates; node != NULL; node = node->next) {
+    GstPadTemplate *tmpl = (GstPadTemplate *) node->data;
+    node->data = gst_pad_template_new (tmpl->name_template,
+        tmpl->direction, tmpl->presence, gst_caps_copy (tmpl->caps));
+  }
+  element_class->padtemplates = padtemplates;
 
   /* set the factory, see gst_element_register() */
   element_class->elementfactory =
@@ -1270,30 +1281,37 @@ gst_element_iterate_sink_pads (GstElement * element)
 /**
  * gst_element_class_add_pad_template:
  * @klass: the #GstElementClass to add the pad template to.
- * @templ: (transfer none): a #GstPadTemplate to add to the element class.
+ * @templ: (transfer full): a #GstPadTemplate to add to the element class.
+ *
+ * Adds a padtemplate to an element class. This is mainly used in the _class_init
+ * functions of classes. If a pad template with the same name as an already
+ * existing one is added the old one is replaced by the new one.
  *
- * Adds a padtemplate to an element class. This is mainly used in the _base_init
- * functions of classes.
  */
 void
 gst_element_class_add_pad_template (GstElementClass * klass,
     GstPadTemplate * templ)
 {
+  GList *template_list = klass->padtemplates;
+
   g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
   g_return_if_fail (GST_IS_PAD_TEMPLATE (templ));
 
-  /* FIXME 0.11: allow replacing the pad templates by
-   * calling this with the same name as an already existing pad
-   * template. For this we _must_ _not_ ref the added pad template
-   * a second time and _must_ document that this function takes
-   * ownership of the pad template. Otherwise we will leak pad templates
-   * or the caller unref's the pad template and it disappears */
-  /* avoid registering pad templates with the same name */
-  g_return_if_fail (gst_element_class_get_pad_template (klass,
-          templ->name_template) == NULL);
-
-  klass->padtemplates = g_list_append (klass->padtemplates,
-      gst_object_ref (templ));
+  /* If we already have a pad template with the same name replace the
+   * old one. */
+  while (template_list) {
+    GstPadTemplate *padtempl = (GstPadTemplate *) template_list->data;
+
+    /* Found pad with the same name, replace and return */
+    if (strcmp (templ->name_template, padtempl->name_template) == 0) {
+      gst_object_unref (padtempl);
+      template_list->data = templ;
+      return;
+    }
+    template_list = g_list_next (template_list);
+  }
+
+  klass->padtemplates = g_list_append (klass->padtemplates, templ);
   klass->numpadtemplates++;
 }
 
@@ -1330,7 +1348,7 @@ gst_element_class_add_metadata (GstElementClass * klass,
  * multiple author metadata. E.g: "Joe Bloggs &lt;joe.blogs at foo.com&gt;"
  *
  * Sets the detailed information for a #GstElementClass.
- * <note>This function is for use in _base_init functions only.</note>
+ * <note>This function is for use in _class_init functions only.</note>
  */
 void
 gst_element_class_set_metadata (GstElementClass * klass,
index 20def77..06c4d55 100644 (file)
  * </example>
  *
  * The following example shows you how to add the padtemplate to an
- * element class, this is usually done in the base_init of the class:
+ * element class, this is usually done in the class_init of the class:
  * <informalexample>
  *   <programlisting>
  *   static void
- *   my_element_base_init (gpointer g_class)
+ *   my_element_class_init (GstMyElementClass *klass)
  *   {
- *     GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
+ *     GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
  *
  *     gst_element_class_add_pad_template (gstelement_class,
  *         gst_static_pad_template_get (&amp;my_template));