diff --git a/girs/Gst-1.0.gir b/girs/Gst-1.0.gir index d676d5baa2..d149589b2b 100644 --- a/girs/Gst-1.0.gir +++ b/girs/Gst-1.0.gir @@ -49595,6 +49595,42 @@ contextual data, which they must not modify. + + Sets whether the tracer should use structure parameters for configuration. +This function configures how parameters should be passed when instantiating +the tracer. + +This is typically called in the tracer's class initialization function to +indicate its parameter handling preference. + + + + + + + + + + %TRUE to use structure parameters, %FALSE otherwise + + + + + + If set, the tracer subsystem will consider parameters passed to the +`GST_TRACERS` environment variable as a #GstStructure and use its +fields as properties to instanciate the tracer. + + + %TRUE if the tracer uses structure parameters, %FALSE otherwise + + + + + + + + Use gst_tracer_factory_get_list() to get a list of tracer factories known to diff --git a/subprojects/gstreamer/gst/gsttracer.c b/subprojects/gstreamer/gst/gsttracer.c index 1849142745..e69561cac9 100644 --- a/subprojects/gstreamer/gst/gsttracer.c +++ b/subprojects/gstreamer/gst/gsttracer.c @@ -52,6 +52,11 @@ enum static GParamSpec *properties[PROP_LAST]; +typedef struct +{ + gboolean use_structure_params; +} GstTracerClassPrivate; + static void gst_tracer_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_tracer_get_property (GObject * object, guint prop_id, @@ -62,8 +67,13 @@ struct _GstTracerPrivate gchar *params; }; +#define _do_init \ + g_type_add_class_private (g_define_type_id, \ + sizeof (GstTracerClassPrivate)); + #define gst_tracer_parent_class parent_class -G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstTracer, gst_tracer, GST_TYPE_OBJECT); +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstTracer, gst_tracer, GST_TYPE_OBJECT, + G_ADD_PRIVATE (GstTracer) _do_init); static void gst_tracer_dispose (GObject * object) @@ -192,3 +202,48 @@ gst_tracer_register (GstPlugin * plugin, const gchar * name, GType type) return TRUE; } + +/** + * gst_tracer_class_uses_structure_params: + * @klass: the #GstTracerClass to to check + * + * If set, the tracer subsystem will consider parameters passed to the + * `GST_TRACERS` environment variable as a #GstStructure and use its + * fields as properties to instanciate the tracer. + * + * Returns: %TRUE if the tracer uses structure parameters, %FALSE otherwise + * + * Since: 1.26 + */ +gboolean +gst_tracer_class_uses_structure_params (GstTracerClass * klass) +{ + g_return_val_if_fail (GST_IS_TRACER_CLASS (klass), FALSE); + + return G_TYPE_CLASS_GET_PRIVATE (klass, GST_TYPE_TRACER, + GstTracerClassPrivate)->use_structure_params; +} + +/** + * gst_tracer_class_set_use_structure_params: + * @klass: the #GstTracerFactoryClass to mark as using structure parameters + * @use_structure_params: %TRUE to use structure parameters, %FALSE otherwise + * + * Sets whether the tracer should use structure parameters for configuration. + * This function configures how parameters should be passed when instantiating + * the tracer. + * + * This is typically called in the tracer's class initialization function to + * indicate its parameter handling preference. + * + * Since: 1.26 + */ +void +gst_tracer_class_set_use_structure_params (GstTracerClass * klass, + gboolean use_structure_params) +{ + g_return_if_fail (GST_IS_TRACER_CLASS (klass)); + + G_TYPE_CLASS_GET_PRIVATE (klass, GST_TYPE_TRACER, + GstTracerClassPrivate)->use_structure_params = use_structure_params; +} diff --git a/subprojects/gstreamer/gst/gsttracer.h b/subprojects/gstreamer/gst/gsttracer.h index 6560296af1..c1a597aefb 100644 --- a/subprojects/gstreamer/gst/gsttracer.h +++ b/subprojects/gstreamer/gst/gsttracer.h @@ -75,6 +75,12 @@ gboolean gst_tracer_register (GstPlugin * plugin, const gchar * name, GType type GST_API GList* gst_tracing_get_active_tracers (void); +GST_API +gboolean gst_tracer_class_uses_structure_params (GstTracerClass *tracer_class); +GST_API +void gst_tracer_class_set_use_structure_params (GstTracerClass *tracer_class, + gboolean use_structure_params); + G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstTracer, gst_object_unref) G_END_DECLS diff --git a/subprojects/gstreamer/gst/gsttracerfactory.c b/subprojects/gstreamer/gst/gsttracerfactory.c index 3942acebb8..b0efcc2ce4 100644 --- a/subprojects/gstreamer/gst/gsttracerfactory.c +++ b/subprojects/gstreamer/gst/gsttracerfactory.c @@ -32,6 +32,7 @@ #include "gstinfo.h" #include "gsttracerfactory.h" #include "gstregistry.h" +#include "gsttracer.h" GST_DEBUG_CATEGORY (tracer_debug); #define GST_CAT_DEFAULT tracer_debug diff --git a/subprojects/gstreamer/gst/gsttracerfactory.h b/subprojects/gstreamer/gst/gsttracerfactory.h index ff88a4a605..a4bd24bcaa 100644 --- a/subprojects/gstreamer/gst/gsttracerfactory.h +++ b/subprojects/gstreamer/gst/gsttracerfactory.h @@ -57,6 +57,7 @@ GList * gst_tracer_factory_get_list (void); GST_API GType gst_tracer_factory_get_tracer_type (GstTracerFactory * factory); + G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstTracerFactory, gst_object_unref) G_END_DECLS diff --git a/subprojects/gstreamer/gst/gsttracerutils.c b/subprojects/gstreamer/gst/gsttracerutils.c index eccf6602a3..a443a92fd1 100644 --- a/subprojects/gstreamer/gst/gsttracerutils.c +++ b/subprojects/gstreamer/gst/gsttracerutils.c @@ -34,6 +34,7 @@ #include "gst_private.h" #include "gsttracer.h" #include "gsttracerfactory.h" +#include "gstvalue.h" #include "gsttracerutils.h" #ifndef GST_DISABLE_GST_TRACER_HOOKS @@ -66,6 +67,169 @@ GQuark _priv_gst_tracer_quark_table[GST_TRACER_QUARK_MAX]; gboolean _priv_tracer_enabled = FALSE; GHashTable *_priv_tracers = NULL; +static gchar * +list_available_tracer_properties (GObjectClass * class) +{ + GParamSpec **properties; + guint n_properties; + GString *props_str; + guint i; + + props_str = g_string_new (NULL); + properties = g_object_class_list_properties (class, &n_properties); + + if (n_properties == 0) { + g_string_append (props_str, "No properties available"); + g_free (properties); + return g_string_free (props_str, FALSE); + } + + g_string_append (props_str, "Available properties:"); + + for (i = 0; i < n_properties; i++) { + GParamSpec *prop = properties[i]; + + if (!((prop->flags & G_PARAM_CONSTRUCT) + || (prop->flags & G_PARAM_CONSTRUCT_ONLY)) + || !(prop->flags & G_PARAM_WRITABLE)) + continue; + + if (!g_strcmp0 (g_param_spec_get_name (prop), "parent")) + continue; + if (!g_strcmp0 (g_param_spec_get_name (prop), "params")) + continue; + + const gchar *type_name = G_PARAM_SPEC_TYPE_NAME (prop); + GValue default_value = G_VALUE_INIT; + + /* Get default value if possible */ + g_value_init (&default_value, prop->value_type); + g_param_value_set_default (prop, &default_value); + gchar *default_str = g_strdup_value_contents (&default_value); + + g_string_append_printf (props_str, + "\n '%s' (%s) (Default: %s): %s", + g_param_spec_get_name (prop), + type_name, + default_str, + g_param_spec_get_blurb (prop) ? g_param_spec_get_blurb (prop) : + "(no description available)"); + + g_free (default_str); + g_value_unset (&default_value); + } + + g_free (properties); + return g_string_free (props_str, FALSE); +} + +static void +gst_tracer_utils_create_tracer (GstTracerFactory * factory, const gchar * name, + const gchar * params) +{ + gchar *available_props = NULL; + GObjectClass *gobject_class = g_type_class_ref (factory->type); + GstTracer *tracer; + const gchar **names = NULL; + GValue *values = NULL; + gint n_properties = 1; + + if (gst_tracer_class_uses_structure_params (GST_TRACER_CLASS (gobject_class))) { + GST_DEBUG ("Use structure parameters for %s", params); + + if (!params) { + n_properties = 0; + goto create; + } + + gchar *struct_str = g_strdup_printf ("%s,%s", name, params); + GstStructure *structure = gst_structure_from_string (struct_str, NULL); + g_free (struct_str); + + if (!structure) { + available_props = list_available_tracer_properties (gobject_class); + g_warning + ("Can't instantiate `%s` tracer: invalid parameters '%s'\n %s\n", + name, params, available_props); + goto done; + } + n_properties = gst_structure_n_fields (structure); + + names = g_new0 (const gchar *, n_properties); + values = g_new0 (GValue, n_properties); + for (gint i = 0; i < n_properties; i++) { + const gchar *field_name = gst_structure_nth_field_name (structure, i); + const GValue *field_value = + gst_structure_get_value (structure, field_name); + GParamSpec *pspec = + g_object_class_find_property (gobject_class, field_name); + + if (!pspec) { + available_props = list_available_tracer_properties (gobject_class); + g_warning + ("Can't instantiate `%s` tracer: property '%s' not found\n %s\n", + name, field_name, available_props); + goto done; + } + + if (G_VALUE_TYPE (field_value) == pspec->value_type) { + names[i] = field_name; + g_value_init (&values[i], G_VALUE_TYPE (field_value)); + g_value_copy (field_value, &values[i]); + } else if (G_VALUE_TYPE (field_value) == G_TYPE_STRING) { + names[i] = field_name; + g_value_init (&values[i], G_PARAM_SPEC_VALUE_TYPE (pspec)); + if (!gst_value_deserialize_with_pspec (&values[i], + g_value_get_string (field_value), pspec)) { + available_props = list_available_tracer_properties (gobject_class); + g_warning + ("Can't instantiate `%s` tracer: invalid property '%s' value: '%s'\n %s\n", + name, field_name, g_value_get_string (field_value), + available_props); + goto done; + } + } else { + available_props = list_available_tracer_properties (gobject_class); + g_warning + ("Can't instantiate `%s` tracer: property '%s' type mismatch, expected %s, got %s\n %s\n", + name, field_name, g_type_name (pspec->value_type), + g_type_name (G_VALUE_TYPE (field_value)), available_props); + goto done; + } + } + + g_type_class_unref (gobject_class); + } else { + names = g_new0 (const gchar *, n_properties); + names[0] = (const gchar *) "params"; + values = g_new0 (GValue, 1); + g_value_init (&values[0], G_TYPE_STRING); + g_value_set_string (&values[0], name); + } + GST_INFO_OBJECT (factory, "creating tracer: type-id=%u", + (guint) factory->type); + +create: + tracer = + GST_TRACER (g_object_new_with_properties (factory->type, + n_properties, names, values)); + + for (gint j = 0; j < n_properties; j++) { + g_value_unset (&values[j]); + } + g_free (names); + g_free (values); + + /* Clear floating flag */ + gst_object_ref_sink (tracer); + + /* tracers register them self to the hooks */ + gst_object_unref (tracer); + +done: + g_free (available_props); +} + /* Initialize the tracing system */ void _priv_gst_tracing_init (void) @@ -128,24 +292,12 @@ _priv_gst_tracing_init (void) if ((feature = gst_registry_lookup_feature (registry, t[i]))) { factory = GST_TRACER_FACTORY (gst_plugin_feature_load (feature)); if (factory) { - GstTracer *tracer; - - GST_INFO_OBJECT (factory, "creating tracer: type-id=%u", - (guint) factory->type); - - tracer = g_object_new (factory->type, "params", params, NULL); - - /* Clear floating flag */ - gst_object_ref_sink (tracer); - - /* tracers register them self to the hooks */ - gst_object_unref (tracer); + gst_tracer_utils_create_tracer (factory, t[i], params); } else { - GST_WARNING_OBJECT (feature, - "loading plugin containing feature %s failed!", t[i]); + g_warning ("loading plugin containing feature %s failed!", t[i]); } } else { - GST_WARNING ("no tracer named '%s'", t[i]); + g_warning ("no tracer named '%s'", t[i]); } i++; }