aggregator: Assert if the sink/src pad type that is to be used is not a GstAggregator...
[platform/upstream/gstreamer.git] / gst / gststructure.c
index d23ea2e..ee60ce0 100644 (file)
 #include "config.h"
 #endif
 
+/* FIXME 2.0: suppress warnings for deprecated API such as GValueArray
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
 #include <string.h>
 
 #include "gst_private.h"
@@ -391,6 +395,30 @@ gst_structure_free (GstStructure * structure)
 }
 
 /**
+ * gst_clear_structure: (skip)
+ * @structure_ptr: a pointer to a #GstStructure reference
+ *
+ * Clears a reference to a #GstStructure.
+ *
+ * @structure_ptr must not be %NULL.
+ *
+ * If the reference is %NULL then this function does nothing.
+ * Otherwise, the structure is free'd using gst_structure_free() and the
+ * pointer is set to %NULL.
+ *
+ * A macro is also included that allows this function to be used without
+ * pointer casts.
+ *
+ * Since: 1.16
+ **/
+#undef gst_clear_structure
+void
+gst_clear_structure (GstStructure ** structure_ptr)
+{
+  g_clear_pointer (structure_ptr, gst_structure_free);
+}
+
+/**
  * gst_structure_get_name:
  * @structure: a #GstStructure
  *
@@ -603,6 +631,7 @@ gst_structure_set_valist_internal (GstStructure * structure,
     G_VALUE_COLLECT_INIT (&field.value, type, varargs, 0, &err);
     if (G_UNLIKELY (err)) {
       g_critical ("%s", err);
+      g_free (err);
       return;
     }
     gst_structure_set_field (structure, &field);
@@ -669,6 +698,7 @@ gst_structure_id_set_valist_internal (GstStructure * structure,
     G_VALUE_COLLECT_INIT (&field.value, type, varargs, 0, &err);
     if (G_UNLIKELY (err)) {
       g_critical ("%s", err);
+      g_free (err);
       return;
     }
     gst_structure_set_field (structure, &field);
@@ -875,7 +905,8 @@ gst_structure_get_field (const GstStructure * structure,
  *
  * Get the value of the field with name @fieldname.
  *
- * Returns: the #GValue corresponding to the field with the given name.
+ * Returns: (nullable): the #GValue corresponding to the field with the given
+ * name.
  */
 const GValue *
 gst_structure_get_value (const GstStructure * structure,
@@ -900,8 +931,8 @@ gst_structure_get_value (const GstStructure * structure,
  *
  * Get the value of the field with GQuark @field.
  *
- * Returns: the #GValue corresponding to the field with the given name
- *          identifier.
+ * Returns: (nullable): the #GValue corresponding to the field with the given
+ * name identifier.
  */
 const GValue *
 gst_structure_id_get_value (const GstStructure * structure, GQuark field)
@@ -1799,7 +1830,14 @@ priv_gst_structure_append_to_gstring (const GstStructure * structure,
 
     field = GST_STRUCTURE_FIELD (structure, i);
 
-    t = gst_value_serialize (&field->value);
+    if (G_VALUE_TYPE (&field->value) == GST_TYPE_ARRAY) {
+      t = _priv_gst_value_serialize_any_list (&field->value, "< ", " >", FALSE);
+    } else if (G_VALUE_TYPE (&field->value) == GST_TYPE_LIST) {
+      t = _priv_gst_value_serialize_any_list (&field->value, "{ ", " }", FALSE);
+    } else {
+      t = gst_value_serialize (&field->value);
+    }
+
     type = gst_structure_value_get_generic_type (&field->value);
 
     g_string_append_len (s, ", ", 2);
@@ -1811,10 +1849,19 @@ priv_gst_structure_append_to_gstring (const GstStructure * structure,
     if (t) {
       g_string_append (s, t);
       g_free (t);
+    } else if (G_TYPE_CHECK_VALUE_TYPE (&field->value, G_TYPE_POINTER)) {
+      gpointer ptr = g_value_get_pointer (&field->value);
+
+      if (!ptr)
+        g_string_append (s, "NULL");
+      else
+        g_string_append_printf (s, "%p", ptr);
     } else {
-      GST_WARNING ("No value transform to serialize field '%s' of type '%s'",
-          g_quark_to_string (field->name),
-          _priv_gst_value_gtype_to_abbr (type));
+      if (!G_TYPE_CHECK_VALUE_TYPE (&field->value, G_TYPE_STRING))
+        GST_WARNING ("No value transform to serialize field '%s' of type '%s'",
+            g_quark_to_string (field->name),
+            _priv_gst_value_gtype_to_abbr (type));
+      /* TODO(ensonic): don't print NULL if field->value is not empty */
       g_string_append (s, "NULL");
     }
   }
@@ -2161,14 +2208,20 @@ gst_structure_fixate_field_nearest_int (GstStructure * structure,
     /* already fixed */
     return FALSE;
   } else if (G_VALUE_TYPE (value) == GST_TYPE_INT_RANGE) {
-    int x;
+    int min, max, step;
+
+    min = gst_value_get_int_range_min (value);
+    max = gst_value_get_int_range_max (value);
+    step = gst_value_get_int_range_step (value);
+
+    target = CLAMP (target, min, max);
+    if (G_UNLIKELY (step != 1)) {
+      gint rem = target % step;
+      target -= rem;
+      if (rem > step / 2)
+        target += step;
+    }
 
-    x = gst_value_get_int_range_min (value);
-    if (target < x)
-      target = x;
-    x = gst_value_get_int_range_max (value);
-    if (target > x)
-      target = x;
     gst_structure_set (structure, field_name, G_TYPE_INT, target, NULL);
     return TRUE;
   } else if (G_VALUE_TYPE (value) == GST_TYPE_LIST) {
@@ -2833,7 +2886,7 @@ gst_structure_intersect_field2 (GQuark id, const GValue * val1, gpointer data)
  *
  * Intersects @struct1 and @struct2 and returns the intersection.
  *
- * Returns: Intersection of @struct1 and @struct2
+ * Returns: (nullable): Intersection of @struct1 and @struct2
  */
 GstStructure *
 gst_structure_intersect (const GstStructure * struct1,
@@ -2982,3 +3035,145 @@ gst_structure_fixate (GstStructure * structure)
 
   gst_structure_foreach (structure, default_fixate, structure);
 }
+
+static gboolean
+_gst_structure_get_any_list (GstStructure * structure, GType type,
+    const gchar * fieldname, GValueArray ** array)
+{
+  GstStructureField *field;
+  GValue val = G_VALUE_INIT;
+
+  g_return_val_if_fail (structure != NULL, FALSE);
+  g_return_val_if_fail (fieldname != NULL, FALSE);
+  g_return_val_if_fail (array != NULL, FALSE);
+
+  field = gst_structure_get_field (structure, fieldname);
+
+  if (field == NULL || G_VALUE_TYPE (&field->value) != type)
+    return FALSE;
+
+  g_value_init (&val, G_TYPE_VALUE_ARRAY);
+
+  if (g_value_transform (&field->value, &val)) {
+    *array = g_value_get_boxed (&val);
+    return TRUE;
+  }
+
+  g_value_unset (&val);
+  return FALSE;
+}
+
+/**
+ * gst_structure_get_array:
+ * @structure: a #GstStructure
+ * @fieldname: the name of a field
+ * @array: (out): a pointer to a #GValueArray
+ *
+ * This is useful in language bindings where unknown #GValue types are not
+ * supported. This function will convert the %GST_TYPE_ARRAY into a newly
+ * allocated #GValueArray and return it through @array. Be aware that this is
+ * slower then getting the #GValue directly.
+ *
+ * Returns: %TRUE if the value could be set correctly. If there was no field
+ * with @fieldname or the existing field did not contain a %GST_TYPE_ARRAY,
+ * this function returns %FALSE.
+ */
+gboolean
+gst_structure_get_array (GstStructure * structure, const gchar * fieldname,
+    GValueArray ** array)
+{
+  return _gst_structure_get_any_list (structure, GST_TYPE_ARRAY, fieldname,
+      array);
+}
+
+/**
+ * gst_structure_get_list:
+ * @structure: a #GstStructure
+ * @fieldname: the name of a field
+ * @array: (out): a pointer to a #GValueArray
+ *
+ * This is useful in language bindings where unknown #GValue types are not
+ * supported. This function will convert the %GST_TYPE_LIST into a newly
+ * allocated GValueArray and return it through @array. Be aware that this is
+ * slower then getting the #GValue directly.
+ *
+ * Returns: %TRUE if the value could be set correctly. If there was no field
+ * with @fieldname or the existing field did not contain a %GST_TYPE_LIST, this
+ * function returns %FALSE.
+ *
+ * Since: 1.12
+ */
+gboolean
+gst_structure_get_list (GstStructure * structure, const gchar * fieldname,
+    GValueArray ** array)
+{
+  return _gst_structure_get_any_list (structure, GST_TYPE_LIST, fieldname,
+      array);
+}
+
+static void
+_gst_structure_set_any_list (GstStructure * structure, GType type,
+    const gchar * fieldname, const GValueArray * array)
+{
+  GValue arval = G_VALUE_INIT;
+  GValue value = G_VALUE_INIT;
+
+  g_return_if_fail (structure != NULL);
+  g_return_if_fail (fieldname != NULL);
+  g_return_if_fail (array != NULL);
+  g_return_if_fail (IS_MUTABLE (structure));
+
+  g_value_init (&value, type);
+  g_value_init (&arval, G_TYPE_VALUE_ARRAY);
+  g_value_set_static_boxed (&arval, array);
+
+  if (g_value_transform (&arval, &value)) {
+    gst_structure_id_set_value_internal (structure,
+        g_quark_from_string (fieldname), &value);
+  } else {
+    g_warning ("Failed to convert a GValueArray");
+  }
+
+  g_value_unset (&arval);
+  g_value_unset (&value);
+}
+
+/**
+ * gst_structure_set_array:
+ * @structure: a #GstStructure
+ * @fieldname: the name of a field
+ * @array: a pointer to a #GValueArray
+ *
+ * This is useful in language bindings where unknown GValue types are not
+ * supported. This function will convert a @array to %GST_TYPE_ARRAY and set
+ * the field specified by @fieldname.  Be aware that this is slower then using
+ * %GST_TYPE_ARRAY in a #GValue directly.
+ *
+ * Since: 1.12
+ */
+void
+gst_structure_set_array (GstStructure * structure, const gchar * fieldname,
+    const GValueArray * array)
+{
+  _gst_structure_set_any_list (structure, GST_TYPE_ARRAY, fieldname, array);
+}
+
+/**
+ * gst_structure_set_list:
+ * @structure: a #GstStructure
+ * @fieldname: the name of a field
+ * @array: a pointer to a #GValueArray
+ *
+ * This is useful in language bindings where unknown GValue types are not
+ * supported. This function will convert a @array to %GST_TYPE_LIST and set
+ * the field specified by @fieldname. Be aware that this is slower then using
+ * %GST_TYPE_LIST in a #GValue directly.
+ *
+ * Since: 1.12
+ */
+void
+gst_structure_set_list (GstStructure * structure, const gchar * fieldname,
+    const GValueArray * array)
+{
+  _gst_structure_set_any_list (structure, GST_TYPE_LIST, fieldname, array);
+}