bin: Add method to find elements by factory name
authorNiels De Graef <niels.degraef@barco.com>
Fri, 15 Nov 2019 14:49:32 +0000 (15:49 +0100)
committerNiels De Graef <niels.degraef@barco.com>
Fri, 20 Dec 2019 13:29:19 +0000 (14:29 +0100)
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"`).

gst/gstbin.c
gst/gstbin.h
tests/check/gst/gstbin.c

index 173b8bc1ae7ea4277bd37714b024337d96daebd5..6f5e469a3fcf910b534461ebb96a286b85694c99 100644 (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;
+}
index 906097e64e9886c729a8eafd8c527139aa5f7264..8d2af2ef614c9ca0ed680c2f7b2bd7598a300d54 100644 (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
index 21e6043afdb078d80bdac7b3eaabac765420c060..ed4e916301eb1e21b96e90a0c24d74cbc57c049d 100644 (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);