/**
* SECTION:gsttracerrecord
+ * @title: GstTracerRecord
* @short_description: Trace log entry class
*
* Tracing modules will create instances of this class to announce the data they
#define GST_USE_UNSTABLE_API
#include "gst_private.h"
+#include "gstenumtypes.h"
#include "gstinfo.h"
#include "gststructure.h"
#include "gsttracerrecord.h"
#include "gstvalue.h"
+#include <gobject/gvaluecollector.h>
GST_DEBUG_CATEGORY_EXTERN (tracer_debug);
#define GST_CAT_DEFAULT tracer_debug
-
-enum
-{
- PROP_0,
- PROP_SPEC,
- PROP_LAST
-};
-
-static GParamSpec *properties[PROP_LAST];
-
struct _GstTracerRecord
{
GstObject parent;
GString *s = (GString *) user_data;
const GstStructure *sub;
GValue template_value = { 0, };
- GType type;
+ GType type = G_TYPE_INVALID;
+ GstTracerValueFlags flags = GST_TRACER_VALUE_FLAGS_NONE;
gboolean res;
- g_return_val_if_fail (G_VALUE_TYPE (value) == GST_TYPE_STRUCTURE, FALSE);
+ if (G_VALUE_TYPE (value) != GST_TYPE_STRUCTURE) {
+ GST_WARNING ("expected field of type GstStructure, but %s is %s",
+ g_quark_to_string (field_id), G_VALUE_TYPE_NAME (value));
+ return FALSE;
+ }
sub = gst_value_get_structure (value);
- type = g_value_get_gtype (gst_structure_get_value (sub, "type"));
- g_value_init (&template_value, type);
+ gst_structure_get (sub, "type", G_TYPE_GTYPE, &type, "flags",
+ GST_TYPE_TRACER_VALUE_FLAGS, &flags, NULL);
+
+ if (flags & GST_TRACER_VALUE_FLAGS_OPTIONAL) {
+ gchar *opt_name = g_strconcat ("have-", g_quark_to_string (field_id), NULL);
+
+ /* add a boolean field, that indicates the presence of the next field */
+ g_value_init (&template_value, G_TYPE_BOOLEAN);
+ priv__gst_structure_append_template_to_gstring (g_quark_from_string
+ (opt_name), &template_value, s);
+ g_value_unset (&template_value);
+ g_free (opt_name);
+ }
+ g_value_init (&template_value, type);
res = priv__gst_structure_append_template_to_gstring (field_id,
&template_value, s);
g_value_unset (&template_value);
g_return_if_fail (g_str_has_suffix (name, ".class"));
+ /* announce the format */
GST_TRACE ("%" GST_PTR_FORMAT, structure);
/* cut off '.class' suffix */
name = g_strdup (name);
p = strrchr (name, '.');
+ g_assert (p != NULL);
*p = '\0';
s = g_string_sized_new (STRUCTURE_ESTIMATED_STRING_LEN (structure));
g_string_append_c (s, ';');
self->format = g_string_free (s, FALSE);
- GST_INFO ("new format string: %s", self->format);
+ GST_DEBUG ("new format string: %s", self->format);
g_free (name);
}
{
GstTracerRecord *self = GST_TRACER_RECORD (object);
- gst_structure_free (self->spec);
- g_free (self->format);
-}
-
-static void
-gst_tracer_record_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstTracerRecord *self = GST_TRACER_RECORD_CAST (object);
-
- switch (prop_id) {
- case PROP_SPEC:
- self->spec = g_value_get_boxed (value);
- gst_tracer_record_build_format (self);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_tracer_record_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstTracerRecord *self = GST_TRACER_RECORD_CAST (object);
-
- switch (prop_id) {
- case PROP_SPEC:
- // TODO(ensonic): copy?
- g_value_set_boxed (value, self->spec);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
+ if (self->spec) {
+ gst_structure_free (self->spec);
+ self->spec = NULL;
}
+ g_free (self->format);
+ self->format = NULL;
}
static void
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- gobject_class->set_property = gst_tracer_record_set_property;
- gobject_class->get_property = gst_tracer_record_get_property;
gobject_class->dispose = gst_tracer_record_dispose;
-
- properties[PROP_SPEC] =
- g_param_spec_boxed ("spec", "Spec", "Log record specification",
- GST_TYPE_STRUCTURE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
-
- g_object_class_install_properties (gobject_class, PROP_LAST, properties);
}
static void
/**
* gst_tracer_record_new:
- * @spec: the record specification
+ * @name: name of new record, must end on ".class".
+ * @firstfield: name of first field to set
+ * @...: additional arguments
+
*
* Create a new tracer record. The record instance can be used to efficiently
* log entries using gst_tracer_record_log().
*
- * The name of the @spec #GstStructure must end on '.class'. This name without
- * the suffix will be used for the log records. The @spec must have a field for
- * each value that gets logged where the field name is the value name. The field
- * must be a nested structure describing the value. The sub structure must
- * contain a field called 'type' of %G_TYPE_GTYPE that contains the GType of the
- * value.
+ * The @name without the ".class" suffix will be used for the log records.
+ * There must be fields for each value that gets logged where the field name is
+ * the value name. The field must be a #GstStructure describing the value. The
+ * sub structure must contain a field called 'type' of %G_TYPE_GTYPE that
+ * contains the GType of the value. The resulting #GstTracerRecord will take
+ * ownership of the field structures.
*
* The way to deal with optional values is to log an additional boolean before
* the optional field, that if %TRUE signals that the optional field is valid
* pointer type values must not be NULL - the underlying serialisation can not
* handle that right now.
*
- * <note><para>
- * Please note that this is still under discussion and subject to change.
- * </para></note>
+ * > Please note that this is still under discussion and subject to change.
*
- * Returns: a new #GstTracerRecord
+ * Returns: (transfer full): a new #GstTracerRecord
*/
GstTracerRecord *
-gst_tracer_record_new (GstStructure * spec)
+gst_tracer_record_new (const gchar * name, const gchar * firstfield, ...)
{
- return g_object_new (GST_TYPE_TRACER_RECORD, "spec", spec, NULL);
+ GstTracerRecord *self;
+ GstStructure *structure;
+ va_list varargs;
+ gchar *err = NULL;
+ GType type;
+ GQuark id;
+
+ va_start (varargs, firstfield);
+ structure = gst_structure_new_empty (name);
+
+ while (firstfield) {
+ GValue val = { 0, };
+
+ id = g_quark_from_string (firstfield);
+ type = va_arg (varargs, GType);
+
+ /* all fields passed here must be GstStructures which we take over */
+ if (type != GST_TYPE_STRUCTURE) {
+ GST_WARNING ("expected field of type GstStructure, but %s is %s",
+ firstfield, g_type_name (type));
+ }
+
+ G_VALUE_COLLECT_INIT (&val, type, varargs, G_VALUE_NOCOPY_CONTENTS, &err);
+ if (G_UNLIKELY (err)) {
+ g_critical ("%s", err);
+ break;
+ }
+ /* see boxed_proxy_collect_value */
+ val.data[1].v_uint &= ~G_VALUE_NOCOPY_CONTENTS;
+ gst_structure_id_take_value (structure, id, &val);
+
+ firstfield = va_arg (varargs, gchar *);
+ }
+ va_end (varargs);
+
+ self = g_object_new (GST_TYPE_TRACER_RECORD, NULL);
+
+ /* Clear floating flag */
+ gst_object_ref_sink (self);
+
+ self->spec = structure;
+ gst_tracer_record_build_format (self);
+
+ return self;
}
+#ifndef GST_DISABLE_GST_DEBUG
/**
* gst_tracer_record_log:
* @self: the tracer-record
*
* Right now this is using the gstreamer debug log with the level TRACE (7) and
* the category "GST_TRACER".
- * <note><para>
- * Please note that this is still under discussion and subject to change.
- * </para></note>
+ *
+ * > Please note that this is still under discussion and subject to change.
*/
void
gst_tracer_record_log (GstTracerRecord * self, ...)
}
va_end (var_args);
}
+#endif