bin: Add method to find elements by factory name

A common use case of a dynamically built pipeline is that you want to
(conditionally) find a certain element, e.g. the `rtpbin`s in a
`uridecodebin`. If that element has a fixed name inside its parent bin
(and only has a single instance) this can be easily done by
`gst_bin_get_by_name()`.

If there are multiple instances of the element however, you can only use
`gst_bin_iterate_all_by_interface()`, but this doesn't work if you don't
have the specific `GType` (which is often the case, due to plugins being
dynamically loaded). As such, another fallback could be to use the
well-known name of the element's factory (in case of our example, this
is of course `"rtpbin"`).
This commit is contained in:
Niels De Graef 2019-11-15 15:49:32 +01:00
parent 1d549ea324
commit 0cb3940c94
3 changed files with 133 additions and 0 deletions

View file

@ -4630,3 +4630,56 @@ gst_bin_iterate_all_by_interface (GstBin * bin, GType iface)
return result;
}
static gint
compare_factory_names (const GValue * velement, GValue * factory_name_val)
{
GstElement *element = g_value_get_object (velement);
GstElementFactory *factory = gst_element_get_factory (element);
const gchar *factory_name = g_value_get_string (factory_name_val);
if (factory == NULL)
return -1;
return g_strcmp0 (GST_OBJECT_NAME (factory), factory_name);
}
/**
* gst_bin_iterate_all_by_element_factory_name:
* @bin: a #GstBin
* @factory_name: (not nullable): the name of the #GstElementFactory
*
* Looks for all elements inside the bin with the given element factory name.
* The function recurses inside child bins. The iterator will yield a series of
* #GstElement that should be unreffed after use.
*
* MT safe. Caller owns returned value.
*
* Returns: (transfer full) (nullable): a #GstIterator of #GstElement
* for all elements in the bin with the given element factory name,
* or %NULL.
*
* Since: 1.18
*/
GstIterator *
gst_bin_iterate_all_by_element_factory_name (GstBin * bin,
const gchar * factory_name)
{
GstIterator *children;
GstIterator *result;
GValue factory_name_val = G_VALUE_INIT;
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
g_return_val_if_fail (factory_name && *factory_name, NULL);
g_value_init (&factory_name_val, G_TYPE_STRING);
g_value_set_string (&factory_name_val, factory_name);
children = gst_bin_iterate_recurse (bin);
result = gst_iterator_filter (children, (GCompareFunc) compare_factory_names,
&factory_name_val);
g_value_unset (&factory_name_val);
return result;
}

View file

@ -237,6 +237,9 @@ GstIterator* gst_bin_iterate_sources (GstBin *bin);
GST_API
GstIterator* gst_bin_iterate_all_by_interface (GstBin *bin, GType iface);
GST_API
GstIterator* gst_bin_iterate_all_by_element_factory_name (GstBin * bin, const gchar * factory_name);
/* latency */
GST_API

View file

@ -153,6 +153,82 @@ GST_START_TEST (test_interface)
GST_END_TEST;
GST_START_TEST (test_iterate_all_by_element_factory_name)
{
GstBin *bin, *bin2;
GstElement *filesrc;
GstIterator *it;
GValue item = { 0, };
bin = GST_BIN (gst_bin_new (NULL));
fail_unless (bin != NULL, "Could not create bin");
filesrc = gst_element_factory_make ("filesrc", NULL);
fail_unless (filesrc != NULL, "Could not create filesrc");
gst_bin_add (bin, filesrc);
/* Test bin with single element */
it = gst_bin_iterate_all_by_element_factory_name (bin, "filesrc");
fail_unless (it != NULL);
fail_unless (gst_iterator_next (it, &item) == GST_ITERATOR_OK);
fail_unless (g_value_get_object (&item) == (gpointer) filesrc);
g_value_reset (&item);
fail_unless (gst_iterator_next (it, &item) == GST_ITERATOR_DONE);
gst_iterator_free (it);
/* Negative test bin with single element */
it = gst_bin_iterate_all_by_element_factory_name (bin, "filesink");
fail_unless (it != NULL);
fail_unless (gst_iterator_next (it, &item) == GST_ITERATOR_DONE);
gst_iterator_free (it);
/* Test bin with multiple other elements, 1 layer */
gst_bin_add_many (bin,
gst_element_factory_make ("identity", NULL),
gst_element_factory_make ("identity", NULL),
gst_element_factory_make ("identity", NULL), NULL);
it = gst_bin_iterate_all_by_element_factory_name (bin, "filesrc");
fail_unless (it != NULL);
fail_unless (gst_iterator_next (it, &item) == GST_ITERATOR_OK);
fail_unless (g_value_get_object (&item) == (gpointer) filesrc);
g_value_reset (&item);
fail_unless (gst_iterator_next (it, &item) == GST_ITERATOR_DONE);
gst_iterator_free (it);
/* Test bin with multiple other elements in subbins */
bin2 = bin;
bin = GST_BIN (gst_bin_new (NULL));
fail_unless (bin != NULL);
gst_bin_add_many (bin,
gst_element_factory_make ("identity", NULL),
gst_element_factory_make ("identity", NULL),
GST_ELEMENT (bin2), gst_element_factory_make ("identity", NULL), NULL);
it = gst_bin_iterate_all_by_element_factory_name (bin, "filesrc");
fail_unless (gst_iterator_next (it, &item) == GST_ITERATOR_OK);
fail_unless (g_value_get_object (&item) == (gpointer) filesrc);
g_value_reset (&item);
fail_unless (gst_iterator_next (it, &item) == GST_ITERATOR_DONE);
gst_iterator_free (it);
/* Test bin with multiple other elements, multiple occurrences in subbins */
gst_bin_add (bin, gst_element_factory_make ("filesrc", NULL));
gst_bin_add (bin2, gst_element_factory_make ("filesrc", NULL));
it = gst_bin_iterate_all_by_element_factory_name (bin, "filesrc");
fail_unless (gst_iterator_next (it, &item) == GST_ITERATOR_OK);
g_value_reset (&item);
fail_unless (gst_iterator_next (it, &item) == GST_ITERATOR_OK);
g_value_reset (&item);
fail_unless (gst_iterator_next (it, &item) == GST_ITERATOR_OK);
g_value_reset (&item);
fail_unless (gst_iterator_next (it, &item) == GST_ITERATOR_DONE);
g_value_unset (&item);
gst_iterator_free (it);
gst_object_unref (bin);
}
GST_END_TEST;
GST_START_TEST (test_eos)
{
GstBus *bus;
@ -1789,6 +1865,7 @@ gst_bin_suite (void)
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_interface);
tcase_add_test (tc_chain, test_iterate_all_by_element_factory_name);
tcase_add_test (tc_chain, test_eos);
tcase_add_test (tc_chain, test_stream_start);
tcase_add_test (tc_chain, test_children_state_change_order_flagged_sink);