diff --git a/gst/gstelementfactory.c b/gst/gstelementfactory.c index f7b71bb7c3..cd84130268 100644 --- a/gst/gstelementfactory.c +++ b/gst/gstelementfactory.c @@ -65,6 +65,8 @@ #include "glib-compat-private.h" +#include + 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,134 @@ no_element: } /** - * gst_element_factory_make: - * @factoryname: a named factory to instantiate - * @name: (allow-none): name of new element, or %NULL to automatically create - * a unique name + * 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 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. + * 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 unable to create element + * if the element couldn't be created + * + * Since: 1.20 */ GstElement * -gst_element_factory_make (const gchar * factoryname, const gchar * name) +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; @@ -445,15 +624,15 @@ 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_with_properties (factory, n, names, + values); if (element == NULL) goto create_failed; @@ -475,6 +654,112 @@ create_failed: } } +/** + * 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. + * 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_valist (const gchar * factoryname, + const gchar * first, va_list properties) +{ + 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_valist (factory, first, properties); + 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_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) diff --git a/gst/gstelementfactory.h b/gst/gstelementfactory.h index cffb123429..518bb9bec5 100644 --- a/gst/gstelementfactory.h +++ b/gst/gstelementfactory.h @@ -84,8 +84,26 @@ 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);