From ded2fed3b97bf45685487ee3179deeab6b687310 Mon Sep 17 00:00:00 2001 From: Michael Gruner Date: Tue, 18 Oct 2022 18:15:12 +0200 Subject: [PATCH] childproxy: Implement a new ::get_child_by_name_recurse() API Part-of: --- subprojects/gstreamer/gst/gstchildproxy.c | 140 ++++++++++++++++------ subprojects/gstreamer/gst/gstchildproxy.h | 4 + 2 files changed, 105 insertions(+), 39 deletions(-) diff --git a/subprojects/gstreamer/gst/gstchildproxy.c b/subprojects/gstreamer/gst/gstchildproxy.c index 77ef181e13..f229045eb7 100644 --- a/subprojects/gstreamer/gst/gstchildproxy.c +++ b/subprojects/gstreamer/gst/gstchildproxy.c @@ -55,6 +55,69 @@ enum static guint signals[LAST_SIGNAL] = { 0 }; +/** + * gst_child_proxy_get_child_by_name_recurse: + * @parent: the parent object to get the child from + * @name: the full-path child's name + * + * Looks up a child element by the given full-path name. + * + * Similar to gst_child_proxy_get_child_by_name(), this method + * searches and returns a child given a name. The difference is that + * this method allows a hierarchical path in the form of + * child1::child2::child3. In the later example this method would + * return a reference to child3, if found. The name should be made of + * element names only and should not contain any property names. + * + * Returns: (transfer full) (nullable): the child object or %NULL if + * not found. + * + * Since: 1.22 + */ +GObject * +gst_child_proxy_get_child_by_name_recurse (GstChildProxy * child_proxy, + const gchar * name) +{ + gchar **names = NULL, **current = NULL; + GObject *obj = NULL, *next = NULL; + + g_return_val_if_fail (child_proxy != NULL, NULL); + g_return_val_if_fail (name != NULL, NULL); + + current = names = g_strsplit (name, "::", -1); + if (current[0]) { + obj = G_OBJECT (g_object_ref (child_proxy)); + } + + /* walk through the children hierarchy until the requested one is found */ + while (current[0]) { + + /* Cannot ask for the child of a non-childproxy */ + if (!GST_IS_CHILD_PROXY (obj)) { + gst_object_unref (obj); + next = NULL; + break; + } + + next = gst_child_proxy_get_child_by_name (GST_CHILD_PROXY (obj), + current[0]); + gst_object_unref (obj); + + /* The child does not exist */ + if (!next) { + GST_INFO ("Unable to find child %s", current[0]); + break; + } + + obj = next; + current++; + } + + g_strfreev (names); + + return next; +} + static GObject * gst_child_proxy_default_get_child_by_name (GstChildProxy * parent, const gchar * name) @@ -194,55 +257,54 @@ gboolean gst_child_proxy_lookup (GstChildProxy * object, const gchar * name, GObject ** target, GParamSpec ** pspec) { - GObject *obj; gboolean res = FALSE; - gchar **names, **current; + gchar *children = NULL; + const gchar *prop = NULL; + GObject *child = NULL; + static const gchar *separator = "::"; g_return_val_if_fail (GST_IS_CHILD_PROXY (object), FALSE); g_return_val_if_fail (name != NULL, FALSE); - obj = G_OBJECT (g_object_ref (object)); + /* If the requested name does not include a "::" then it is not a + child proxy path, but the property name directly */ + prop = g_strrstr (name, separator); + if (!prop) { + child = gst_object_ref (G_OBJECT (object)); + prop = name; + } else { + /* Skip "::" */ + prop += 2; - current = names = g_strsplit (name, "::", -1); - /* find the owner of the property */ - while (current[1]) { - GObject *next; + /* Extract "child1::child2" from "child1::child2::prop" */ + children = g_strndup (name, prop - name - 2); + GST_INFO ("Looking for property %s in %s", prop, children); - if (!GST_IS_CHILD_PROXY (obj)) { - GST_INFO - ("object %s is not a parent, so you cannot request a child by name %s", - (GST_IS_OBJECT (obj) ? GST_OBJECT_NAME (obj) : ""), current[0]); - break; - } - next = gst_child_proxy_get_child_by_name (GST_CHILD_PROXY (obj), - current[0]); - if (!next) { - GST_INFO ("no such object %s", current[0]); - break; - } - gst_object_unref (obj); - obj = next; - current++; - } + child = gst_child_proxy_get_child_by_name_recurse (object, children); + g_free (children); - /* look for psec */ - if (current[1] == NULL) { - GParamSpec *spec = - g_object_class_find_property (G_OBJECT_GET_CLASS (obj), current[0]); - if (spec == NULL) { - GST_INFO ("no param spec named %s", current[0]); - } else { - if (pspec) - *pspec = spec; - if (target) { - g_object_ref (obj); - *target = obj; - } - res = TRUE; + if (!child) { + GST_INFO ("Child not found"); + goto out; } } - gst_object_unref (obj); - g_strfreev (names); + + GParamSpec *spec = + g_object_class_find_property (G_OBJECT_GET_CLASS (child), prop); + if (spec == NULL) { + GST_INFO ("no param spec named %s", prop); + } else { + if (pspec) + *pspec = spec; + if (target) { + g_object_ref (child); + *target = child; + } + res = TRUE; + } + gst_object_unref (child); + +out: return res; } diff --git a/subprojects/gstreamer/gst/gstchildproxy.h b/subprojects/gstreamer/gst/gstchildproxy.h index deb8f21dcd..407a4f5a8c 100644 --- a/subprojects/gstreamer/gst/gstchildproxy.h +++ b/subprojects/gstreamer/gst/gstchildproxy.h @@ -118,6 +118,10 @@ GType gst_child_proxy_get_type (void); GST_API GObject * gst_child_proxy_get_child_by_name (GstChildProxy * parent, const gchar * name); +GST_API +GObject * gst_child_proxy_get_child_by_name_recurse (GstChildProxy * child_proxy, + const gchar *name); + GST_API guint gst_child_proxy_get_children_count (GstChildProxy * parent);