gst/: Make it possible (and recommended) to set element details and add pad templates...
authorSebastian Dröge <slomo@circular-chaos.org>
Sun, 3 Feb 2008 10:48:01 +0000 (10:48 +0000)
committerSebastian Dröge <slomo@circular-chaos.org>
Sun, 3 Feb 2008 10:48:01 +0000 (10:48 +0000)
Original commit message from CVS:
* gst/gstelement.c: (gst_element_base_class_init),
(gst_element_class_add_pad_template):
* gst/gstpadtemplate.c:
Make it possible (and recommended) to set element details and add
pad templates in the class_init functions by copying the details/pad
templates in GstElement's base_init.
Also make it possible to replace existing pad templates by adding
a new one with the same name. This was done in a hackish fashion
in same elements before already.
Don't reference pad templates that are added a second time. A
new pad template has a refcount of one and is not floating anymore
and to be owned by the element's class. Make this more explicit by
mentioning it in the docs of gst_element_class_add_pad_template().
These changes are backwards compatible. Fixes bug #491501.
* tests/check/gst/gstelement.c:
Add unit test for setting element details, adding pad templates and
replacing them in a subclass.

ChangeLog
common
gst/gstelement.c
gst/gstpadtemplate.c
tests/check/gst/gstelement.c

index c00963622f32ab2276fdc2b3ef15c5cd51cf3baf..edf640f82c1b9cb9686081d70b10f72e8386646a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+2008-02-03  Sebastian Dröge  <slomo@circular-chaos.org>
+
+       * gst/gstelement.c: (gst_element_base_class_init),
+       (gst_element_class_add_pad_template):
+       * gst/gstpadtemplate.c:
+       Make it possible (and recommended) to set element details and add
+       pad templates in the class_init functions by copying the details/pad
+       templates in GstElement's base_init.
+
+       Also make it possible to replace existing pad templates by adding
+       a new one with the same name. This was done in a hackish fashion
+       in same elements before already.
+
+       Don't reference pad templates that are added a second time. A
+       new pad template has a refcount of one and is not floating anymore
+       and to be owned by the element's class. Make this more explicit by
+       mentioning it in the docs of gst_element_class_add_pad_template().
+
+       These changes are backwards compatible. Fixes bug #491501.
+
+       * tests/check/gst/gstelement.c:
+       Add unit test for setting element details, adding pad templates and
+       replacing them in a subclass.
+
 2008-02-02  Sebastian Dröge  <slomo@circular-chaos.org>
 
        * tools/gst-inspect.c: (print_interfaces),
diff --git a/common b/common
index 571dce3335f9be76978009b3842c050dbb900e6f..3c5473161ce19a3530bad279b842d542895b1500 160000 (submodule)
--- a/common
+++ b/common
@@ -1 +1 @@
-Subproject commit 571dce3335f9be76978009b3842c050dbb900e6f
+Subproject commit 3c5473161ce19a3530bad279b842d542895b1500
index 9e97fde479dd728074c25694bbd3bbb671438f0c..a2131c53cfab51908e90aa27c4f4a6fb6fdb8225 100644 (file)
@@ -238,9 +238,34 @@ static void
 gst_element_base_class_init (gpointer g_class)
 {
   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+  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 */
+  /* FIXME: We probably need something like for copying
+   * the details at a central place */
+  element_class->details.longname = g_strdup (element_class->details.longname);
+  element_class->details.klass = g_strdup (element_class->details.klass);
+  element_class->details.description =
+      g_strdup (element_class->details.description);
+  element_class->details.author = g_strdup (element_class->details.author);
+
+  /* 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.
+   */
+  padtemplates = g_list_copy (element_class->padtemplates);
+  for (node = padtemplates; node != NULL; node = node->next) {
+    GstPadTemplate *tmpl = (GstPadTemplate *) node->data;
 
-  memset (&element_class->details, 0, sizeof (GstElementDetails));
-  element_class->padtemplates = NULL;
+    node->data = gst_pad_template_new (tmpl->name_template,
+        tmpl->direction, tmpl->presence, gst_caps_copy (tmpl->caps));
+  }
+  element_class->padtemplates = padtemplates;
 }
 
 static void
@@ -1102,22 +1127,38 @@ gst_element_iterate_sink_pads (GstElement * element)
  * @klass: the #GstElementClass to add the pad template to.
  * @templ: a #GstPadTemplate to add to the element class.
  *
- * Adds a padtemplate to an element class. This is mainly used in the _base_init
- * functions of classes.
+ * 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.
+ *
+ * This function takes the ownership of the #GstPadTemplate.
  */
 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));
 
-  /* avoid registering pad templates with the same name */
-  g_return_if_fail (gst_element_class_get_pad_template (klass,
-          templ->name_template) == NULL);
+  /* 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,
-      gst_object_ref (templ));
+  /* Not found a pad with the same name so add it to the list */
+  klass->padtemplates = g_list_append (klass->padtemplates, templ);
   klass->numpadtemplates++;
 }
 
@@ -1127,7 +1168,7 @@ gst_element_class_add_pad_template (GstElementClass * klass,
  * @details: details to set
  *
  * 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>
  *
  * The @details are copied.
  */
@@ -1155,7 +1196,7 @@ gst_element_class_set_details (GstElementClass * klass,
  *
  * Sets the detailed information for a #GstElementClass. Simpler version of 
  * gst_element_class_set_details() that generates less linker overhead.
- * <note>This function is for use in _base_init functions only.</note>
+ * <note>This function is for use in _class_init functions only.</note>
  *
  * The detail parameter strings are copied into the #GstElementDetails for
  * the element class.
index 2f12f1c5d6fa560c8d9b27648f60356f8fa60e4e..fb1be495670fd582dffb59cbfd5ce595fd4f315a 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));
index 22de7dd546102ec99d2d8088e932e605e44f4b7b..c7877fc5f6e367a49745ca7b6fc6ccc943057166 100644 (file)
@@ -205,6 +205,189 @@ GST_START_TEST (test_class)
 
 GST_END_TEST;
 
+typedef struct _GstTestElement
+{
+  GstElement parent;
+
+} GstTestElement;
+
+typedef struct _GstTestElementClass
+{
+  GstElementClass parent;
+
+} GstTestElementClass;
+
+static void
+gst_test_element_class_init (GstTestElementClass * klass)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+  GstPadTemplate *templ;
+
+  gst_element_class_set_details_simple (element_class, "Test element",
+      "Element", "Does nothing", "Foo Bar <foo@bar.com>");
+
+  fail_unless_equals_int (g_list_length (gst_element_class_get_pad_template_list
+          (element_class)), 0);
+
+  fail_unless (gst_element_class_get_pad_template (element_class,
+          "test") == NULL);
+
+  gst_element_class_add_pad_template (element_class,
+      gst_pad_template_new ("test", GST_PAD_SRC, GST_PAD_ALWAYS, GST_CAPS_ANY));
+
+  fail_unless_equals_int (g_list_length (gst_element_class_get_pad_template_list
+          (element_class)), 1);
+
+  fail_unless ((templ =
+          gst_element_class_get_pad_template (element_class, "test")) != NULL);
+  fail_unless (gst_caps_is_any (templ->caps));
+
+  gst_element_class_add_pad_template (element_class,
+      gst_pad_template_new ("test2", GST_PAD_SRC, GST_PAD_ALWAYS,
+          GST_CAPS_ANY));
+
+  fail_unless_equals_int (g_list_length (gst_element_class_get_pad_template_list
+          (element_class)), 2);
+
+  fail_unless ((templ =
+          gst_element_class_get_pad_template (element_class, "test2")) != NULL);
+  fail_unless (gst_caps_is_any (templ->caps));
+
+  /* Add "test" again, with NONE caps this time */
+  gst_element_class_add_pad_template (element_class,
+      gst_pad_template_new ("test", GST_PAD_SRC, GST_PAD_ALWAYS,
+          GST_CAPS_NONE));
+
+  fail_unless_equals_int (g_list_length (gst_element_class_get_pad_template_list
+          (element_class)), 2);
+
+  fail_unless ((templ =
+          gst_element_class_get_pad_template (element_class, "test")) != NULL);
+  fail_unless (gst_caps_is_empty (templ->caps));
+}
+
+GType
+gst_test_element_get_type (void)
+{
+  static GType gst_test_element_type = G_TYPE_NONE;
+
+  if (gst_test_element_type == G_TYPE_NONE) {
+    static const GTypeInfo gst_test_element_info = {
+      sizeof (GstTestElementClass),
+      NULL,                     /* base_init */
+      NULL,                     /* base_finalize */
+      (GClassInitFunc) gst_test_element_class_init,
+      NULL,
+      NULL,
+      sizeof (GstTestElement),
+      0,
+      NULL,                     /* instance_init */
+      NULL
+    };
+
+    gst_test_element_type = g_type_register_static (GST_TYPE_ELEMENT,
+        "GstTestElement", &gst_test_element_info, 0);
+  }
+  return gst_test_element_type;
+}
+
+typedef struct _GstTestElement2
+{
+  GstTestElement parent;
+
+} GstTestElement2;
+
+typedef struct _GstTestElement2Class
+{
+  GstTestElementClass parent;
+
+} GstTestElement2Class;
+
+static void
+gst_test_element2_class_init (GstTestElement2Class * klass)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+  GstPadTemplate *templ;
+
+  gst_element_class_set_details_simple (element_class, "Test element 2",
+      "Element", "Does nothing", "Foo Bar <foo@bar.com>");
+
+  fail_unless_equals_int (g_list_length (gst_element_class_get_pad_template_list
+          (element_class)), 2);
+
+  fail_unless ((templ =
+          gst_element_class_get_pad_template (element_class, "test")) != NULL);
+  fail_unless (gst_caps_is_empty (templ->caps));
+
+  fail_unless ((templ =
+          gst_element_class_get_pad_template (element_class, "test2")) != NULL);
+  fail_unless (gst_caps_is_any (templ->caps));
+
+  /* Add "test" pad with ANY caps, should have "test" pad with EMPTY caps before */
+  gst_element_class_add_pad_template (element_class,
+      gst_pad_template_new ("test", GST_PAD_SRC, GST_PAD_ALWAYS, GST_CAPS_ANY));
+
+  fail_unless_equals_int (g_list_length (gst_element_class_get_pad_template_list
+          (element_class)), 2);
+
+  fail_unless ((templ =
+          gst_element_class_get_pad_template (element_class, "test")) != NULL);
+  fail_unless (gst_caps_is_any (templ->caps));
+
+
+  gst_element_class_add_pad_template (element_class,
+      gst_pad_template_new ("test4", GST_PAD_SRC, GST_PAD_ALWAYS,
+          GST_CAPS_ANY));
+
+  fail_unless_equals_int (g_list_length (gst_element_class_get_pad_template_list
+          (element_class)), 3);
+
+  fail_unless ((templ =
+          gst_element_class_get_pad_template (element_class, "test4")) != NULL);
+  fail_unless (gst_caps_is_any (templ->caps));
+}
+
+GType
+gst_test_element2_get_type (void)
+{
+  static GType gst_test_element2_type = G_TYPE_NONE;
+
+  if (gst_test_element2_type == G_TYPE_NONE) {
+    static const GTypeInfo gst_test_element2_info = {
+      sizeof (GstTestElement2Class),
+      NULL,                     /* base_init */
+      NULL,                     /* base_finalize */
+      (GClassInitFunc) gst_test_element2_class_init,
+      NULL,
+      NULL,
+      sizeof (GstTestElement2),
+      0,
+      NULL,                     /* instance_init */
+      NULL
+    };
+
+    gst_test_element2_type =
+        g_type_register_static (gst_test_element_get_type (), "GstTestElement2",
+        &gst_test_element2_info, 0);
+  }
+  return gst_test_element2_type;
+}
+
+
+GST_START_TEST (test_pad_templates)
+{
+  GstTestElement *test;
+  GstTestElement2 *test2;
+
+  test = g_object_new (gst_test_element_get_type (), NULL);
+  test2 = g_object_new (gst_test_element2_get_type (), NULL);
+
+  g_object_unref (test);
+  g_object_unref (test2);
+}
+
+GST_END_TEST;
+
 Suite *
 gst_element_suite (void)
 {
@@ -218,6 +401,7 @@ gst_element_suite (void)
   tcase_add_test (tc_chain, test_link);
   tcase_add_test (tc_chain, test_link_no_pads);
   tcase_add_test (tc_chain, test_class);
+  tcase_add_test (tc_chain, test_pad_templates);
 
   return s;
 }