elementfactory: enable construct only property passing
authorThéo MAILLART <tmaillart@gmail.com>
Fri, 29 Jan 2021 19:36:51 +0000 (20:36 +0100)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Fri, 20 Aug 2021 01:41:30 +0000 (01:41 +0000)
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/736>

gst/gstelementfactory.c
gst/gstelementfactory.h

index f7b71bb..cd84130 100644 (file)
@@ -65,6 +65,8 @@
 
 #include "glib-compat-private.h"
 
+#include <gobject/gvaluecollector.h>
+
 GST_DEBUG_CATEGORY_STATIC (element_factory_debug);
 #define GST_CAT_DEFAULT element_factory_debug
 
@@ -325,21 +327,94 @@ detailserror:
   }
 }
 
+static gboolean
+gst_element_factory_property_valist_to_array (const gchar * first,
+    va_list properties, GType object_type, guint * n, const gchar ** names[],
+    GValue ** values)
+{
+  GObjectClass *class;
+  const gchar *name;
+  guint n_params = 0;
+  guint n_params_alloc = 16;
+  GValue *values_array;
+  const gchar **names_array;
+
+  if (!first)
+    return FALSE;
+
+  g_return_val_if_fail (G_TYPE_IS_OBJECT (object_type), FALSE);
+
+  class = g_type_class_ref (object_type);
+  if (!class)
+    return FALSE;
+
+  name = first;
+  names_array = g_new0 (const gchar *, n_params_alloc);
+  values_array = g_new0 (GValue, n_params_alloc);
+
+  do {
+    gchar *error = NULL;
+    GParamSpec *pspec;
+
+    pspec = g_object_class_find_property (class, name);
+    if (!pspec)
+      goto cleanup;
+
+    if (G_UNLIKELY (n_params == n_params_alloc)) {
+      n_params_alloc *= 2u;
+      names_array =
+          g_realloc (names_array, sizeof (const gchar *) * n_params_alloc);
+      values_array = g_realloc (values_array, sizeof (GValue) * n_params_alloc);
+      memset (&values_array[n_params], 0,
+          sizeof (GValue) * (n_params_alloc - n_params));
+    }
+
+    names_array[n_params] = name;
+
+    G_VALUE_COLLECT_INIT (&values_array[n_params], pspec->value_type,
+        properties, 0, &error);
+
+    if (error) {
+      g_critical ("%s", error);
+      g_free (error);
+      goto cleanup;
+    }
+
+    ++n_params;
+    name = va_arg (properties, const gchar *);
+  } while (name);
+
+  *n = n_params;
+  *names = names_array;
+  *values = values_array;
+  g_type_class_unref (class);
+  return TRUE;
+
+cleanup:
+  g_free (names_array);
+  g_free (values_array);
+  g_type_class_unref (class);
+  return FALSE;
+}
+
 /**
- * gst_element_factory_create:
+ * gst_element_factory_create_with_properties:
  * @factory: factory to instantiate
- * @name: (allow-none): name of new element, or %NULL to automatically create
- *    a unique name
+ * @n: count of properties
+ * @names: (nullable): array of properties names
+ * @values: (nullable): array of associated properties values
  *
  * Create a new element of the type defined by the given elementfactory.
- * It will be given the name supplied, since all elements require a name as
- * their first argument.
+ * The supplied list of properties, will be passed at object construction.
  *
  * Returns: (transfer floating) (nullable): new #GstElement or %NULL
  *     if the element couldn't be created
+ *
+ * Since: 1.20
  */
 GstElement *
-gst_element_factory_create (GstElementFactory * factory, const gchar * name)
+gst_element_factory_create_with_properties (GstElementFactory * factory,
+    guint n, const gchar * names[], const GValue values[])
 {
   GstElement *element;
   GstElementClass *oclass;
@@ -356,22 +431,14 @@ gst_element_factory_create (GstElementFactory * factory, const gchar * name)
 
   factory = newfactory;
 
-  if (name)
-    GST_INFO ("creating element \"%s\" named \"%s\"",
-        GST_OBJECT_NAME (factory), GST_STR_NULL (name));
-  else
-    GST_INFO ("creating element \"%s\"", GST_OBJECT_NAME (factory));
+  GST_INFO ("creating element \"%s\"", GST_OBJECT_NAME (factory));
 
   if (factory->type == 0)
     goto no_type;
 
-  /* create an instance of the element, cast so we don't assert on NULL
-   * also set name as early as we can
-   */
-  if (name)
-    element = g_object_new (factory->type, "name", name, NULL);
-  else
-    element = g_object_new (factory->type, NULL);
+  element = (GstElement *) g_object_new_with_properties (factory->type, n,
+      names, values);
+
   if (G_UNLIKELY (element == NULL))
     goto no_element;
 
@@ -404,8 +471,7 @@ gst_element_factory_create (GstElementFactory * factory, const gchar * name)
   /* ERRORS */
 load_failed:
   {
-    GST_WARNING_OBJECT (factory,
-        "loading plugin containing feature %s returned NULL!", name);
+    GST_WARNING_OBJECT (factory, "loading plugin returned NULL!");
     return NULL;
   }
 no_type:
@@ -423,21 +489,188 @@ no_element:
 }
 
 /**
- * gst_element_factory_make:
- * @factoryname: a named factory to instantiate
- * @name: (allow-none): name of new element, or %NULL to automatically create
+ * gst_element_factory_create_valist:
+ * @factory: factory to instantiate
+ * @first: (nullable): name of the first property
+ * @properties: (nullable): list of properties
+ *
+ * Create a new element of the type defined by the given elementfactory.
+ * The supplied list of properties, will be passed at object construction.
+ *
+ * Returns: (transfer floating) (nullable): new #GstElement or %NULL
+ *     if the element couldn't be created
+ *
+ * Since: 1.20
+ */
+GstElement *
+gst_element_factory_create_valist (GstElementFactory * factory,
+    const gchar * first, va_list properties)
+{
+  GstElementFactory *newfactory;
+  GstElement *element;
+  const gchar **names = NULL;
+  GValue *values = NULL;
+  guint n = 0;
+
+  g_return_val_if_fail (factory != NULL, NULL);
+
+  newfactory =
+      GST_ELEMENT_FACTORY (gst_plugin_feature_load (GST_PLUGIN_FEATURE
+          (factory)));
+
+  g_return_val_if_fail (newfactory != NULL, NULL);
+  g_return_val_if_fail (newfactory->type != 0, NULL);
+
+  factory = newfactory;
+
+  if (!first) {
+    element =
+        gst_element_factory_create_with_properties (factory, 0, NULL, NULL);
+    goto out;
+  }
+
+  if (!gst_element_factory_property_valist_to_array (first, properties,
+          factory->type, &n, &names, &values)) {
+    GST_ERROR_OBJECT (factory, "property parsing failed");
+    element = NULL;
+    goto out;
+  }
+
+  element = gst_element_factory_create_with_properties (factory, n, names,
+      values);
+
+  g_free (names);
+  while (n--)
+    g_value_unset (&values[n]);
+  g_free (values);
+
+out:
+  gst_object_unref (factory);
+  return element;
+}
+
+/**
+ * gst_element_factory_create_full:
+ * @factory: factory to instantiate
+ * @first: (nullable): name of the first property
+ * @...: (nullable): %NULL terminated list of properties
+ *
+ * Create a new element of the type defined by the given elementfactory.
+ * The supplied list of properties, will be passed at object construction.
+ *
+ * Returns: (transfer floating) (nullable): new #GstElement or %NULL
+ *     if the element couldn't be created
+ *
+ * Since: 1.20
+ */
+GstElement *
+gst_element_factory_create_full (GstElementFactory * factory,
+    const gchar * first, ...)
+{
+  GstElement *element;
+  va_list properties;
+
+  va_start (properties, first);
+  element = gst_element_factory_create_valist (factory, first, properties);
+  va_end (properties);
+
+  return element;
+}
+
+/**
+ * gst_element_factory_create:
+ * @factory: factory to instantiate
+ * @name: (nullable): name of new element, or %NULL to automatically create
  *    a unique name
  *
+ * Create a new element of the type defined by the given elementfactory.
+ * It will be given the name supplied, since all elements require a name as
+ * their first argument.
+ *
+ * Returns: (transfer floating) (nullable): new #GstElement or %NULL
+ *     if the element couldn't be created
+ */
+GstElement *
+gst_element_factory_create (GstElementFactory * factory, const gchar * name)
+{
+  if (name)
+    return gst_element_factory_create_full (factory, "name", name, NULL);
+  else
+    return gst_element_factory_create_with_properties (factory, 0, NULL, NULL);
+}
+
+/**
+ * gst_element_factory_make_with_properties:
+ * @factoryname: a named factory to instantiate
+ * @n: count of properties
+ * @names: (nullable): array of properties names
+ * @values: (nullable): array of associated properties values
+ *
+ * Create a new element of the type defined by the given elementfactory.
+ * The supplied list of properties, will be passed at object construction.
+ *
+ * Returns: (transfer floating) (nullable): new #GstElement or %NULL
+ *     if the element couldn't be created
+ *
+ * Since: 1.20
+ */
+GstElement *
+gst_element_factory_make_with_properties (const gchar * factoryname,
+    guint n, const gchar * names[], const GValue values[])
+{
+  GstElementFactory *factory;
+  GstElement *element;
+
+  g_return_val_if_fail (factoryname != NULL, NULL);
+  g_return_val_if_fail (gst_is_initialized (), NULL);
+
+  GST_LOG ("gstelementfactory: make \"%s\"", factoryname);
+
+  factory = gst_element_factory_find (factoryname);
+  if (factory == NULL)
+    goto no_factory;
+
+  GST_LOG_OBJECT (factory, "found factory %p", factory);
+  element = gst_element_factory_create_with_properties (factory, n, names,
+      values);
+  if (element == NULL)
+    goto create_failed;
+
+  gst_object_unref (factory);
+
+  return element;
+
+  /* ERRORS */
+no_factory:
+  {
+    GST_WARNING ("no such element factory \"%s\"!", factoryname);
+    return NULL;
+  }
+create_failed:
+  {
+    GST_INFO_OBJECT (factory, "couldn't create instance!");
+    gst_object_unref (factory);
+    return NULL;
+  }
+}
+
+/**
+ * gst_element_factory_make_valist:
+ * @factoryname: a named factory to instantiate
+ * @first: (nullable): name of first property
+ * @properties: (nullable): list of properties
+ *
  * Create a new element of the type defined by the given element factory.
- * If name is %NULL, then the element will receive a guaranteed unique name,
- * consisting of the element factory name and a number.
- * If name is given, it will be given the name supplied.
+ * The supplied list of properties, will be passed at object construction.
  *
  * Returns: (transfer floating) (nullable): new #GstElement or %NULL
  * if unable to create element
+ *
+ * Since: 1.20
  */
 GstElement *
-gst_element_factory_make (const gchar * factoryname, const gchar * name)
+gst_element_factory_make_valist (const gchar * factoryname,
+    const gchar * first, va_list properties)
 {
   GstElementFactory *factory;
   GstElement *element;
@@ -445,15 +678,14 @@ gst_element_factory_make (const gchar * factoryname, const gchar * name)
   g_return_val_if_fail (factoryname != NULL, NULL);
   g_return_val_if_fail (gst_is_initialized (), NULL);
 
-  GST_LOG ("gstelementfactory: make \"%s\" \"%s\"",
-      factoryname, GST_STR_NULL (name));
+  GST_LOG ("gstelementfactory: make \"%s\"", factoryname);
 
   factory = gst_element_factory_find (factoryname);
   if (factory == NULL)
     goto no_factory;
 
   GST_LOG_OBJECT (factory, "found factory %p", factory);
-  element = gst_element_factory_create (factory, name);
+  element = gst_element_factory_create_valist (factory, first, properties);
   if (element == NULL)
     goto create_failed;
 
@@ -475,6 +707,59 @@ create_failed:
   }
 }
 
+/**
+ * gst_element_factory_make_full:
+ * @factoryname: a named factory to instantiate
+ * @first: (nullable): name of first property
+ * @...: (nullable): %NULL terminated list of properties
+ *
+ * Create a new element of the type defined by the given element factory.
+ * The supplied list of properties, will be passed at object construction.
+ *
+ * Returns: (transfer floating) (nullable): new #GstElement or %NULL
+ * if unable to create element
+ *
+ * Since: 1.20
+ */
+GstElement *
+gst_element_factory_make_full (const gchar * factoryname,
+    const gchar * first, ...)
+{
+  GstElement *element;
+  va_list properties;
+
+  va_start (properties, first);
+
+  element = gst_element_factory_make_valist (factoryname, first, properties);
+
+  va_end (properties);
+  return element;
+}
+
+/**
+ * gst_element_factory_make:
+ * @factoryname: a named factory to instantiate
+ * @name: (nullable): name of new element, or %NULL to automatically create
+ *    a unique name
+ *
+ * Create a new element of the type defined by the given element factory.
+ * If name is %NULL, then the element will receive a guaranteed unique name,
+ * consisting of the element factory name and a number.
+ * If name is given, it will be given the name supplied.
+ *
+ * Returns: (transfer floating) (nullable): new #GstElement or %NULL
+ * if unable to create element
+ */
+GstElement *
+gst_element_factory_make (const gchar * factoryname, const gchar * name)
+{
+  if (name)
+    return gst_element_factory_make_full (factoryname, "name", name, NULL);
+  else
+    return gst_element_factory_make_with_properties (factoryname, 0, NULL,
+        NULL);
+}
+
 void
 __gst_element_factory_add_static_pad_template (GstElementFactory * factory,
     GstStaticPadTemplate * templ)
index cffb123..518bb9b 100644 (file)
@@ -84,9 +84,27 @@ GST_API
 GstElement*             gst_element_factory_create              (GstElementFactory *factory,
                                                                  const gchar *name) G_GNUC_MALLOC;
 GST_API
+GstElement*             gst_element_factory_create_full         (GstElementFactory * factory,
+                                                                 const gchar * first, ...) G_GNUC_MALLOC;
+GST_API
+GstElement *            gst_element_factory_create_valist       (GstElementFactory * factory,
+                                                                 const gchar * first, va_list properties) G_GNUC_MALLOC;
+GST_API
+GstElement *            gst_element_factory_create_with_properties (GstElementFactory * factory,
+                                                                 guint n, const gchar *names[], const GValue values[]) G_GNUC_MALLOC;
+GST_API
 GstElement*             gst_element_factory_make                (const gchar *factoryname, const gchar *name) G_GNUC_MALLOC;
 
 GST_API
+GstElement*             gst_element_factory_make_full           (const gchar *factoryname,
+                                                                  const gchar *first, ...) G_GNUC_MALLOC;
+GST_API
+GstElement*             gst_element_factory_make_valist         (const gchar *factoryname,
+                                                                 const gchar *first, va_list properties) G_GNUC_MALLOC;
+GST_API
+GstElement*             gst_element_factory_make_with_properties (const gchar *factoryname,
+                                                                 guint n, const gchar *names[], const GValue values[]) G_GNUC_MALLOC;
+GST_API
 gboolean                gst_element_register                    (GstPlugin *plugin, const gchar *name,
                                                                  guint rank, GType type);