gst/: Make it possible (and recommended) to set element details and add pad templates in the class_init functions by ...

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.
This commit is contained in:
Sebastian Dröge 2008-02-03 10:48:01 +00:00
parent d7a94887b5
commit 86e45df860
5 changed files with 264 additions and 15 deletions

View file

@ -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),

2
common

@ -1 +1 @@
Subproject commit 571dce3335f9be76978009b3842c050dbb900e6f
Subproject commit 3c5473161ce19a3530bad279b842d542895b1500

View 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;
memset (&element_class->details, 0, sizeof (GstElementDetails));
element_class->padtemplates = NULL;
/* 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;
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;
klass->padtemplates = g_list_append (klass->padtemplates,
gst_object_ref (templ));
/* 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);
}
/* 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.

View file

@ -78,13 +78,13 @@
* </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));

View 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;
}