gstfunnel: avoid access of freed pad
[platform/upstream/gstreamer.git] / gst / gstquery.c
index e4efe3e..5fadc9d 100644 (file)
 
 /**
  * SECTION:gstquery
- * @short_description: Dynamically register new query types. Provide functions
- *                     to create queries, and to set and parse values in them.
+ * @short_description: Provide functions to create queries, and to set and parse
+ *                     values in them.
  * @see_also: #GstPad, #GstElement
  *
- * GstQuery functions are used to register new query types to the gstreamer
- * core and use them.
  * Queries can be performed on pads (gst_pad_query()) and elements
  * (gst_element_query()). Please note that some queries might need a running
  * pipeline to work.
  *  </programlisting>
  * </example>
  *
- * Last reviewed on 2006-02-14 (0.10.4)
+ * Last reviewed on 2012-03-29 (0.11.3)
  */
 
+
 #include "gst_private.h"
 #include "gstinfo.h"
 #include "gstquery.h"
@@ -84,30 +83,36 @@ typedef struct
 
 #define GST_QUERY_STRUCTURE(q)  (((GstQueryImpl *)(q))->structure)
 
-static GMutex mutex;
-static GList *_gst_queries = NULL;
-static GHashTable *_nick_to_query = NULL;
-static GHashTable *_query_type_to_nick = NULL;
-static guint32 _n_values = 1;   /* we start from 1 because 0 reserved for NONE */
-
-static GstQueryTypeDefinition standard_definitions[] = {
-  {GST_QUERY_POSITION, "position", "Current position", 0},
-  {GST_QUERY_DURATION, "duration", "Total duration", 0},
-  {GST_QUERY_LATENCY, "latency", "Latency", 0},
-  {GST_QUERY_JITTER, "jitter", "Jitter", 0},
-  {GST_QUERY_RATE, "rate", "Configured rate 1000000 = 1", 0},
-  {GST_QUERY_SEEKING, "seeking", "Seeking capabilities and parameters", 0},
-  {GST_QUERY_SEGMENT, "segment", "currently configured segment", 0},
-  {GST_QUERY_CONVERT, "convert", "Converting between formats", 0},
-  {GST_QUERY_FORMATS, "formats", "Supported formats for conversion", 0},
-  {GST_QUERY_BUFFERING, "buffering", "Buffering status", 0},
-  {GST_QUERY_CUSTOM, "custom", "Custom query", 0},
-  {GST_QUERY_URI, "uri", "URI of the source or sink", 0},
-  {GST_QUERY_ALLOCATION, "allocation", "Allocation properties", 0},
-  {GST_QUERY_SCHEDULING, "scheduling", "Scheduling properties", 0},
-  {GST_QUERY_ACCEPT_CAPS, "accept-caps", "Accept caps", 0},
-  {GST_QUERY_CAPS, "caps", "Caps", 0},
-  {GST_QUERY_NONE, NULL, NULL, 0}
+
+typedef struct
+{
+  const gint type;
+  const gchar *name;
+  GQuark quark;
+} GstQueryQuarks;
+
+static GstQueryQuarks query_quarks[] = {
+  {GST_QUERY_UNKNOWN, "unknown", 0},
+  {GST_QUERY_POSITION, "position", 0},
+  {GST_QUERY_DURATION, "duration", 0},
+  {GST_QUERY_LATENCY, "latency", 0},
+  {GST_QUERY_JITTER, "jitter", 0},
+  {GST_QUERY_RATE, "rate", 0},
+  {GST_QUERY_SEEKING, "seeking", 0},
+  {GST_QUERY_SEGMENT, "segment", 0},
+  {GST_QUERY_CONVERT, "convert", 0},
+  {GST_QUERY_FORMATS, "formats", 0},
+  {GST_QUERY_BUFFERING, "buffering", 0},
+  {GST_QUERY_CUSTOM, "custom", 0},
+  {GST_QUERY_URI, "uri", 0},
+  {GST_QUERY_ALLOCATION, "allocation", 0},
+  {GST_QUERY_SCHEDULING, "scheduling", 0},
+  {GST_QUERY_ACCEPT_CAPS, "accept-caps", 0},
+  {GST_QUERY_CAPS, "caps", 0},
+  {GST_QUERY_DRAIN, "drain", 0},
+  {GST_QUERY_TOC, "toc", 0},
+
+  {0, NULL, 0}
 };
 
 GST_DEFINE_MINI_OBJECT_TYPE (GstQuery, gst_query);
@@ -115,205 +120,73 @@ GST_DEFINE_MINI_OBJECT_TYPE (GstQuery, gst_query);
 void
 _priv_gst_query_initialize (void)
 {
-  GstQueryTypeDefinition *standards = standard_definitions;
+  gint i;
 
-  GST_CAT_INFO (GST_CAT_GST_INIT, "init queries");
+  _gst_query_type = gst_query_get_type ();
 
   GST_DEBUG_CATEGORY_INIT (gst_query_debug, "query", 0, "query system");
 
-  g_mutex_lock (&mutex);
-  if (_nick_to_query == NULL) {
-    _nick_to_query = g_hash_table_new (g_str_hash, g_str_equal);
-    _query_type_to_nick = g_hash_table_new (NULL, NULL);
-  }
-
-  while (standards->nick) {
-    standards->quark = g_quark_from_static_string (standards->nick);
-    g_hash_table_insert (_nick_to_query, (gpointer) standards->nick, standards);
-    g_hash_table_insert (_query_type_to_nick,
-        GINT_TO_POINTER (standards->value), standards);
-
-    _gst_queries = g_list_append (_gst_queries, standards);
-    standards++;
-    _n_values++;
+  for (i = 0; query_quarks[i].name; i++) {
+    query_quarks[i].quark = g_quark_from_static_string (query_quarks[i].name);
   }
-  g_mutex_unlock (&mutex);
-
-  _gst_query_type = gst_query_get_type ();
 }
 
 /**
  * gst_query_type_get_name:
- * @query: the query type
+ * @type: the query type
  *
  * Get a printable name for the given query type. Do not modify or free.
  *
  * Returns: a reference to the static name of the query.
  */
 const gchar *
-gst_query_type_get_name (GstQueryType query)
+gst_query_type_get_name (GstQueryType type)
 {
-  const GstQueryTypeDefinition *def;
-
-  def = gst_query_type_get_details (query);
-  g_return_val_if_fail (def != NULL, NULL);
+  gint i;
 
-  return def->nick;
+  for (i = 0; query_quarks[i].name; i++) {
+    if (type == query_quarks[i].type)
+      return query_quarks[i].name;
+  }
+  return "unknown";
 }
 
 /**
  * gst_query_type_to_quark:
- * @query: the query type
+ * @type: the query type
  *
  * Get the unique quark for the given query type.
  *
  * Returns: the quark associated with the query type
  */
 GQuark
-gst_query_type_to_quark (GstQueryType query)
+gst_query_type_to_quark (GstQueryType type)
 {
-  const GstQueryTypeDefinition *def;
-
-  def = gst_query_type_get_details (query);
-  g_return_val_if_fail (def != NULL, 0);
-
-  return def->quark;
-}
-
-/**
- * gst_query_type_register:
- * @nick: The nick of the new query
- * @description: The description of the new query
- *
- * Create a new GstQueryType based on the nick or return an
- * already registered query with that nick
- *
- * Returns: A new GstQueryType or an already registered query
- * with the same nick.
- */
-GstQueryType
-gst_query_type_register (const gchar * nick, const gchar * description)
-{
-  GstQueryTypeDefinition *query;
-  GstQueryType lookup;
-
-  g_return_val_if_fail (nick != NULL, GST_QUERY_NONE);
-  g_return_val_if_fail (description != NULL, GST_QUERY_NONE);
-
-  lookup = gst_query_type_get_by_nick (nick);
-  if (lookup != GST_QUERY_NONE)
-    return lookup;
-
-  query = g_slice_new (GstQueryTypeDefinition);
-  query->value = (GstQueryType) _n_values;
-  query->nick = g_strdup (nick);
-  query->description = g_strdup (description);
-  query->quark = g_quark_from_static_string (query->nick);
-
-  g_mutex_lock (&mutex);
-  g_hash_table_insert (_nick_to_query, (gpointer) query->nick, query);
-  g_hash_table_insert (_query_type_to_nick, GINT_TO_POINTER (query->value),
-      query);
-  _gst_queries = g_list_append (_gst_queries, query);
-  _n_values++;
-  g_mutex_unlock (&mutex);
-
-  return query->value;
-}
-
-/**
- * gst_query_type_get_by_nick:
- * @nick: The nick of the query
- *
- * Get the query type registered with @nick.
- *
- * Returns: The query registered with @nick or #GST_QUERY_NONE
- * if the query was not registered.
- */
-GstQueryType
-gst_query_type_get_by_nick (const gchar * nick)
-{
-  GstQueryTypeDefinition *query;
-
-  g_return_val_if_fail (nick != NULL, GST_QUERY_NONE);
-
-  g_mutex_lock (&mutex);
-  query = g_hash_table_lookup (_nick_to_query, nick);
-  g_mutex_unlock (&mutex);
-
-  if (query != NULL)
-    return query->value;
-  else
-    return GST_QUERY_NONE;
-}
-
-/**
- * gst_query_types_contains:
- * @types: The query array to search
- * @type: the #GstQueryType to find
- *
- * See if the given #GstQueryType is inside the @types query types array.
- *
- * Returns: TRUE if the type is found inside the array
- */
-gboolean
-gst_query_types_contains (const GstQueryType * types, GstQueryType type)
-{
-  if (!types)
-    return FALSE;
-
-  while (*types) {
-    if (*types == type)
-      return TRUE;
+  gint i;
 
-    types++;
+  for (i = 0; query_quarks[i].name; i++) {
+    if (type == query_quarks[i].type)
+      return query_quarks[i].quark;
   }
-  return FALSE;
+  return 0;
 }
 
-
 /**
- * gst_query_type_get_details:
+ * gst_query_type_get_flags:
  * @type: a #GstQueryType
  *
- * Get details about the given #GstQueryType.
+ * Gets the #GstQueryTypeFlags associated with @type.
  *
- * Returns: The #GstQueryTypeDefinition for @type or NULL on failure.
+ * Returns: a #GstQueryTypeFlags.
  */
-const GstQueryTypeDefinition *
-gst_query_type_get_details (GstQueryType type)
+GstQueryTypeFlags
+gst_query_type_get_flags (GstQueryType type)
 {
-  const GstQueryTypeDefinition *result;
+  GstQueryTypeFlags ret;
 
-  g_mutex_lock (&mutex);
-  result = g_hash_table_lookup (_query_type_to_nick, GINT_TO_POINTER (type));
-  g_mutex_unlock (&mutex);
-
-  return result;
-}
+  ret = type & ((1 << GST_QUERY_NUM_SHIFT) - 1);
 
-/**
- * gst_query_type_iterate_definitions:
- *
- * Get a #GstIterator of all the registered query types. The definitions
- * iterated over are read only.
- *
- * Free-function: gst_iterator_free
- *
- * Returns: (transfer full): a #GstIterator of #GstQueryTypeDefinition.
- */
-GstIterator *
-gst_query_type_iterate_definitions (void)
-{
-  GstIterator *result;
-
-  g_mutex_lock (&mutex);
-  /* FIXME: register a boxed type for GstQueryTypeDefinition */
-  result = gst_iterator_new_list (G_TYPE_POINTER,
-      &mutex, &_n_values, &_gst_queries, NULL, NULL);
-  g_mutex_unlock (&mutex);
-
-  return result;
+  return ret;
 }
 
 static void
@@ -332,41 +205,30 @@ _gst_query_free (GstQuery * query)
   g_slice_free1 (GST_MINI_OBJECT_SIZE (query), query);
 }
 
-static GstQuery *gst_query_new (GstQueryType type, GstStructure * structure);
-
 static GstQuery *
 _gst_query_copy (GstQuery * query)
 {
   GstQuery *copy;
+  GstStructure *s;
 
-  copy = gst_query_new (query->type, GST_QUERY_STRUCTURE (query));
+  s = GST_QUERY_STRUCTURE (query);
+  if (s) {
+    s = gst_structure_copy (s);
+  }
+  copy = gst_query_new_custom (query->type, s);
 
   return copy;
 }
 
-static GstQuery *
-gst_query_new (GstQueryType type, GstStructure * structure)
+static void
+gst_query_init (GstQueryImpl * query, gsize size, GstQueryType type)
 {
-  GstQueryImpl *query;
-
-  query = g_slice_new0 (GstQueryImpl);
-
-  gst_mini_object_init (GST_MINI_OBJECT_CAST (query),
-      _gst_query_type, sizeof (GstQueryImpl));
+  gst_mini_object_init (GST_MINI_OBJECT_CAST (query), _gst_query_type, size);
 
   query->query.mini_object.copy = (GstMiniObjectCopyFunction) _gst_query_copy;
   query->query.mini_object.free = (GstMiniObjectFreeFunction) _gst_query_free;
 
-  GST_DEBUG ("creating new query %p %s", query, gst_query_type_get_name (type));
-
   GST_QUERY_TYPE (query) = type;
-  query->structure = structure;
-
-  if (structure)
-    gst_structure_set_parent_refcount (structure,
-        &query->query.mini_object.refcount);
-
-  return GST_QUERY_CAST (query);
 }
 
 /**
@@ -391,7 +253,7 @@ gst_query_new_position (GstFormat format)
       GST_QUARK (FORMAT), GST_TYPE_FORMAT, format,
       GST_QUARK (CURRENT), G_TYPE_INT64, G_GINT64_CONSTANT (-1), NULL);
 
-  query = gst_query_new (GST_QUERY_POSITION, structure);
+  query = gst_query_new_custom (GST_QUERY_POSITION, structure);
 
   return query;
 }
@@ -470,7 +332,7 @@ gst_query_new_duration (GstFormat format)
       GST_QUARK (FORMAT), GST_TYPE_FORMAT, format,
       GST_QUARK (DURATION), G_TYPE_INT64, G_GINT64_CONSTANT (-1), NULL);
 
-  query = gst_query_new (GST_QUERY_DURATION, structure);
+  query = gst_query_new_custom (GST_QUERY_DURATION, structure);
 
   return query;
 }
@@ -550,7 +412,7 @@ gst_query_new_latency (void)
       GST_QUARK (MIN_LATENCY), G_TYPE_UINT64, G_GUINT64_CONSTANT (0),
       GST_QUARK (MAX_LATENCY), G_TYPE_UINT64, G_GUINT64_CONSTANT (-1), NULL);
 
-  query = gst_query_new (GST_QUERY_LATENCY, structure);
+  query = gst_query_new_custom (GST_QUERY_LATENCY, structure);
 
   return query;
 }
@@ -559,8 +421,8 @@ gst_query_new_latency (void)
  * gst_query_set_latency:
  * @query: a #GstQuery
  * @live: if there is a live element upstream
- * @min_latency: the minimal latency of the live element
- * @max_latency: the maximal latency of the live element
+ * @min_latency: the minimal latency of the upstream elements
+ * @max_latency: the maximal latency of the upstream elements
  *
  * Answer a latency query by setting the requested values in the given format.
  *
@@ -640,7 +502,7 @@ gst_query_new_convert (GstFormat src_format, gint64 value,
       GST_QUARK (DEST_FORMAT), GST_TYPE_FORMAT, dest_format,
       GST_QUARK (DEST_VALUE), G_TYPE_INT64, G_GINT64_CONSTANT (-1), NULL);
 
-  query = gst_query_new (GST_QUERY_CONVERT, structure);
+  query = gst_query_new_custom (GST_QUERY_CONVERT, structure);
 
   return query;
 }
@@ -734,7 +596,7 @@ gst_query_new_segment (GstFormat format)
       GST_QUARK (START_VALUE), G_TYPE_INT64, G_GINT64_CONSTANT (-1),
       GST_QUARK (STOP_VALUE), G_TYPE_INT64, G_GINT64_CONSTANT (-1), NULL);
 
-  query = gst_query_new (GST_QUERY_SEGMENT, structure);
+  query = gst_query_new_custom (GST_QUERY_SEGMENT, structure);
 
   return query;
 }
@@ -828,10 +690,31 @@ gst_query_parse_segment (GstQuery * query, gdouble * rate, GstFormat * format,
 GstQuery *
 gst_query_new_custom (GstQueryType type, GstStructure * structure)
 {
-  g_return_val_if_fail (gst_query_type_get_details (type) != NULL, NULL);
-  g_return_val_if_fail (structure != NULL, NULL);
+  GstQueryImpl *query;
+
+  query = g_slice_new0 (GstQueryImpl);
+
+  GST_DEBUG ("creating new query %p %s", query, gst_query_type_get_name (type));
 
-  return gst_query_new (type, structure);
+  if (structure) {
+    /* structure must not have a parent */
+    if (!gst_structure_set_parent_refcount (structure,
+            &query->query.mini_object.refcount))
+      goto had_parent;
+  }
+  gst_query_init (query, sizeof (GstQueryImpl), type);
+
+  GST_QUERY_STRUCTURE (query) = structure;
+
+  return GST_QUERY_CAST (query);
+
+  /* ERRORS */
+had_parent:
+  {
+    g_slice_free1 (GST_MINI_OBJECT_SIZE (query), query);
+    g_warning ("structure is already owned by another object");
+    return NULL;
+  }
 }
 
 /**
@@ -856,7 +739,8 @@ gst_query_get_structure (GstQuery * query)
  * gst_query_writable_structure:
  * @query: a #GstQuery
  *
- * Get the structure of a query.
+ * Get the structure of a query. This method should be called with a writable
+ * @query so that the returned structure is guranteed to be writable.
  *
  * Returns: (transfer none): the #GstStructure of the query. The structure is
  *     still owned by the query and will therefore be freed when the query
@@ -894,7 +778,7 @@ gst_query_new_seeking (GstFormat format)
       GST_QUARK (SEGMENT_START), G_TYPE_INT64, G_GINT64_CONSTANT (-1),
       GST_QUARK (SEGMENT_END), G_TYPE_INT64, G_GINT64_CONSTANT (-1), NULL);
 
-  query = gst_query_new (GST_QUERY_SEEKING, structure);
+  query = gst_query_new_custom (GST_QUERY_SEEKING, structure);
 
   return query;
 }
@@ -963,21 +847,24 @@ gst_query_parse_seeking (GstQuery * query, GstFormat * format,
             GST_QUARK (SEGMENT_END)));
 }
 
-static GValueArray *
-ensure_array (GstStructure * s, GQuark quark)
+static GArray *
+ensure_array (GstStructure * s, GQuark quark, gsize element_size,
+    GDestroyNotify clear_func)
 {
-  GValueArray *array;
+  GArray *array;
   const GValue *value;
 
   value = gst_structure_id_get_value (s, quark);
   if (value) {
-    array = (GValueArray *) g_value_get_boxed (value);
+    array = (GArray *) g_value_get_boxed (value);
   } else {
     GValue new_array_val = { 0, };
 
-    array = g_value_array_new (0);
+    array = g_array_new (FALSE, TRUE, element_size);
+    if (clear_func)
+      g_array_set_clear_func (array, clear_func);
 
-    g_value_init (&new_array_val, G_TYPE_VALUE_ARRAY);
+    g_value_init (&new_array_val, G_TYPE_ARRAY);
     g_value_take_boxed (&new_array_val, array);
 
     gst_structure_id_take_value (s, quark, &new_array_val);
@@ -1004,7 +891,7 @@ gst_query_new_formats (void)
   GstStructure *structure;
 
   structure = gst_structure_new_id_empty (GST_QUARK (QUERY_FORMATS));
-  query = gst_query_new (GST_QUERY_FORMATS, structure);
+  query = gst_query_new_custom (GST_QUERY_FORMATS, structure);
 
   return query;
 }
@@ -1091,7 +978,7 @@ gst_query_set_formatsv (GstQuery * query, gint n_formats,
 /**
  * gst_query_parse_n_formats:
  * @query: a #GstQuery
- * @n_formats: (out): the number of formats in this query.
+ * @n_formats: (out) (allow-none): the number of formats in this query.
  *
  * Parse the number of formats in the formats @query.
  *
@@ -1120,7 +1007,7 @@ gst_query_parse_n_formats (GstQuery * query, guint * n_formats)
  * gst_query_parse_nth_format:
  * @query: a #GstQuery
  * @nth: (out): the nth format to retrieve.
- * @format: (out): a pointer to store the nth format
+ * @format: (out) (allow-none): a pointer to store the nth format
  *
  * Parse the format query and retrieve the @nth format from it into
  * @format. If the list contains less elements than @nth, @format will be
@@ -1183,7 +1070,7 @@ gst_query_new_buffering (GstFormat format)
       GST_QUARK (START_VALUE), G_TYPE_INT64, G_GINT64_CONSTANT (-1),
       GST_QUARK (STOP_VALUE), G_TYPE_INT64, G_GINT64_CONSTANT (-1), NULL);
 
-  query = gst_query_new (GST_QUERY_BUFFERING, structure);
+  query = gst_query_new_custom (GST_QUERY_BUFFERING, structure);
 
   return query;
 }
@@ -1309,7 +1196,6 @@ gst_query_parse_buffering_stats (GstQuery * query,
             GST_QUARK (BUFFERING_LEFT)));
 }
 
-
 /**
  * gst_query_set_buffering_range:
  * @query: a #GstQuery
@@ -1380,6 +1266,13 @@ gst_query_parse_buffering_range (GstQuery * query, GstFormat * format,
             GST_QUARK (ESTIMATED_TOTAL)));
 }
 
+/* GstQueryBufferingRange: internal struct for GArray */
+typedef struct
+{
+  gint64 start;
+  gint64 stop;
+} GstQueryBufferingRange;
+
 /**
  * gst_query_add_buffering_range:
  * @query: a GST_QUERY_BUFFERING type query #GstQuery
@@ -1396,9 +1289,9 @@ gst_query_parse_buffering_range (GstQuery * query, GstFormat * format,
 gboolean
 gst_query_add_buffering_range (GstQuery * query, gint64 start, gint64 stop)
 {
-  GValueArray *array;
-  GValue value = { 0 };
+  GstQueryBufferingRange range;
   GstStructure *structure;
+  GArray *array;
 
   g_return_val_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_BUFFERING, FALSE);
   g_return_val_if_fail (gst_query_is_writable (query), FALSE);
@@ -1407,19 +1300,21 @@ gst_query_add_buffering_range (GstQuery * query, gint64 start, gint64 stop)
     return FALSE;
 
   structure = GST_QUERY_STRUCTURE (query);
-  array = ensure_array (structure, GST_QUARK (BUFFERING_RANGES));
-  if (array->n_values > 1) {
-    GValue *last_array_value;
+  array = ensure_array (structure, GST_QUARK (BUFFERING_RANGES),
+      sizeof (GstQueryBufferingRange), NULL);
+
+  if (array->len > 1) {
+    GstQueryBufferingRange *last;
+
+    last = &g_array_index (array, GstQueryBufferingRange, array->len - 1);
 
-    last_array_value = g_value_array_get_nth (array, array->n_values - 1);
-    if (G_UNLIKELY (start <= gst_value_get_int64_range_min (last_array_value)))
+    if (G_UNLIKELY (start <= last->start))
       return FALSE;
   }
 
-  g_value_init (&value, GST_TYPE_INT64_RANGE);
-  gst_value_set_int64_range (&value, start, stop);
-  g_value_array_append (array, &value);
-  /* skip the g_value_unset(&value) here, we know it's not needed */
+  range.start = start;
+  range.stop = stop;
+  g_array_append_val (array, range);
 
   return TRUE;
 }
@@ -1438,15 +1333,16 @@ gst_query_add_buffering_range (GstQuery * query, gint64 start, gint64 stop)
 guint
 gst_query_get_n_buffering_ranges (GstQuery * query)
 {
-  GValueArray *array;
   GstStructure *structure;
+  GArray *array;
 
   g_return_val_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_BUFFERING, 0);
 
   structure = GST_QUERY_STRUCTURE (query);
-  array = ensure_array (structure, GST_QUARK (BUFFERING_RANGES));
+  array = ensure_array (structure, GST_QUARK (BUFFERING_RANGES),
+      sizeof (GstQueryBufferingRange), NULL);
 
-  return array->n_values;
+  return array->len;
 }
 
 
@@ -1468,25 +1364,26 @@ gboolean
 gst_query_parse_nth_buffering_range (GstQuery * query, guint index,
     gint64 * start, gint64 * stop)
 {
-  GValueArray *array;
-  const GValue *value;
-  gboolean ret = FALSE;
+  GstQueryBufferingRange *range;
   GstStructure *structure;
+  GArray *array;
 
-  g_return_val_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_BUFFERING, ret);
+  g_return_val_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_BUFFERING, FALSE);
 
   structure = GST_QUERY_STRUCTURE (query);
-  array = ensure_array (structure, GST_QUARK (BUFFERING_RANGES));
-
-  if ((value = g_value_array_get_nth (array, index))) {
-    if (start)
-      *start = gst_value_get_int64_range_min (value);
-    if (stop)
-      *stop = gst_value_get_int64_range_max (value);
-    ret = TRUE;
-  }
 
-  return ret;
+  array = ensure_array (structure, GST_QUARK (BUFFERING_RANGES),
+      sizeof (GstQueryBufferingRange), NULL);
+  g_return_val_if_fail (index < array->len, FALSE);
+
+  range = &g_array_index (array, GstQueryBufferingRange, index);
+
+  if (start)
+    *start = range->start;
+  if (stop)
+    *stop = range->stop;
+
+  return TRUE;
 }
 
 
@@ -1512,7 +1409,7 @@ gst_query_new_uri (void)
   structure = gst_structure_new_id (GST_QUARK (QUERY_URI),
       GST_QUARK (URI), G_TYPE_STRING, NULL, NULL);
 
-  query = gst_query_new (GST_QUERY_URI, structure);
+  query = gst_query_new_custom (GST_QUERY_URI, structure);
 
   return query;
 }
@@ -1583,15 +1480,9 @@ gst_query_new_allocation (GstCaps * caps, gboolean need_pool)
 
   structure = gst_structure_new_id (GST_QUARK (QUERY_ALLOCATION),
       GST_QUARK (CAPS), GST_TYPE_CAPS, caps,
-      GST_QUARK (NEED_POOL), G_TYPE_BOOLEAN, need_pool,
-      GST_QUARK (SIZE), G_TYPE_UINT, 0,
-      GST_QUARK (MIN_BUFFERS), G_TYPE_UINT, 0,
-      GST_QUARK (MAX_BUFFERS), G_TYPE_UINT, 0,
-      GST_QUARK (PREFIX), G_TYPE_UINT, 0,
-      GST_QUARK (ALIGN), G_TYPE_UINT, 0,
-      GST_QUARK (POOL), GST_TYPE_BUFFER_POOL, NULL, NULL);
+      GST_QUARK (NEED_POOL), G_TYPE_BOOLEAN, need_pool, NULL);
 
-  query = gst_query_new (GST_QUERY_ALLOCATION, structure);
+  query = gst_query_new_custom (GST_QUERY_ALLOCATION, structure);
 
   return query;
 }
@@ -1599,7 +1490,7 @@ gst_query_new_allocation (GstCaps * caps, gboolean need_pool)
 /**
  * gst_query_parse_allocation:
  * @query: a #GstQuery
- * @caps: (out callee-allocates) (allow-none): The #GstCaps
+ * @caps: (out) (transfer none) (allow-none): The #GstCaps
  * @need_pool: (out) (allow-none): Whether a #GstBufferPool is needed
  *
  * Parse an allocation query, writing the requested caps in @caps and
@@ -1615,74 +1506,164 @@ gst_query_parse_allocation (GstQuery * query, GstCaps ** caps,
   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION);
 
   structure = GST_QUERY_STRUCTURE (query);
+  if (caps) {
+    *caps = g_value_get_boxed (gst_structure_id_get_value (structure,
+            GST_QUARK (CAPS)));
+  }
   gst_structure_id_get (structure,
-      GST_QUARK (CAPS), GST_TYPE_CAPS, caps,
       GST_QUARK (NEED_POOL), G_TYPE_BOOLEAN, need_pool, NULL);
 }
 
+typedef struct
+{
+  GstBufferPool *pool;
+  guint size;
+  guint min_buffers;
+  guint max_buffers;
+} AllocationPool;
+
+static void
+allocation_pool_free (AllocationPool * ap)
+{
+  if (ap->pool)
+    gst_object_unref (ap->pool);
+}
+
 /**
- * gst_query_set_allocation_params:
+ * gst_query_add_allocation_pool:
  * @query: A valid #GstQuery of type GST_QUERY_ALLOCATION.
+ * @pool: the #GstBufferPool
  * @size: the size
  * @min_buffers: the min buffers
  * @max_buffers: the max buffers
- * @prefix: the prefix
- * @alignment: the alignment
- * @pool: the #GstBufferPool
  *
- * Set the allocation parameters in @query.
+ * Set the pool parameters in @query.
  */
 void
-gst_query_set_allocation_params (GstQuery * query, guint size,
-    guint min_buffers, guint max_buffers, guint prefix,
-    guint alignment, GstBufferPool * pool)
+gst_query_add_allocation_pool (GstQuery * query, GstBufferPool * pool,
+    guint size, guint min_buffers, guint max_buffers)
 {
+  GArray *array;
   GstStructure *structure;
+  AllocationPool ap;
 
   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION);
   g_return_if_fail (gst_query_is_writable (query));
-  g_return_if_fail (((alignment + 1) & alignment) == 0);
-  g_return_if_fail (size != 0 || pool == NULL);
+  g_return_if_fail (size != 0);
 
   structure = GST_QUERY_STRUCTURE (query);
-  gst_structure_id_set (structure,
-      GST_QUARK (SIZE), G_TYPE_UINT, size,
-      GST_QUARK (MIN_BUFFERS), G_TYPE_UINT, min_buffers,
-      GST_QUARK (MAX_BUFFERS), G_TYPE_UINT, max_buffers,
-      GST_QUARK (PREFIX), G_TYPE_UINT, prefix,
-      GST_QUARK (ALIGN), G_TYPE_UINT, alignment,
-      GST_QUARK (POOL), GST_TYPE_BUFFER_POOL, pool, NULL);
+  array = ensure_array (structure, GST_QUARK (POOL),
+      sizeof (AllocationPool), (GDestroyNotify) allocation_pool_free);
+
+  if ((ap.pool = pool))
+    gst_object_ref (pool);
+  ap.size = size;
+  ap.min_buffers = min_buffers;
+  ap.max_buffers = max_buffers;
+
+  g_array_append_val (array, ap);
 }
 
+
 /**
- * gst_query_parse_allocation_params:
+ * gst_query_get_n_allocation_pools:
+ * @query: a GST_QUERY_ALLOCATION type query #GstQuery
+ *
+ * Retrieve the number of values currently stored in the
+ * pool array of the query's structure.
+ *
+ * Returns: the pool array size as a #guint.
+ */
+guint
+gst_query_get_n_allocation_pools (GstQuery * query)
+{
+  GArray *array;
+  GstStructure *structure;
+
+  g_return_val_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION, 0);
+
+  structure = GST_QUERY_STRUCTURE (query);
+  array = ensure_array (structure, GST_QUARK (POOL),
+      sizeof (AllocationPool), (GDestroyNotify) allocation_pool_free);
+
+  return array->len;
+}
+
+/**
+ * gst_query_parse_nth_allocation_pool:
  * @query: A valid #GstQuery of type GST_QUERY_ALLOCATION.
+ * @index: index to parse
+ * @pool: (out) (allow-none) (transfer none): the #GstBufferPool
+ * @size: (out) (allow-none): the size
+ * @min_buffers: (out) (allow-none): the min buffers
+ * @max_buffers: (out) (allow-none): the max buffers
+ *
+ * Get the pool parameters in @query.
+ */
+void
+gst_query_parse_nth_allocation_pool (GstQuery * query, guint index,
+    GstBufferPool ** pool, guint * size, guint * min_buffers,
+    guint * max_buffers)
+{
+  GArray *array;
+  GstStructure *structure;
+  AllocationPool *ap;
+
+  g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION);
+
+  structure = GST_QUERY_STRUCTURE (query);
+  array = ensure_array (structure, GST_QUARK (POOL),
+      sizeof (AllocationPool), (GDestroyNotify) allocation_pool_free);
+  g_return_if_fail (index < array->len);
+
+  ap = &g_array_index (array, AllocationPool, index);
+
+  if (pool)
+    if ((*pool = ap->pool))
+      gst_object_ref (*pool);
+  if (size)
+    *size = ap->size;
+  if (min_buffers)
+    *min_buffers = ap->min_buffers;
+  if (max_buffers)
+    *max_buffers = ap->max_buffers;
+}
+
+/**
+ * gst_query_set_nth_allocation_pool:
+ * @index: index to modify
+ * @query: A valid #GstQuery of type GST_QUERY_ALLOCATION.
+ * @pool: the #GstBufferPool
  * @size: the size
  * @min_buffers: the min buffers
  * @max_buffers: the max buffers
- * @prefix: the prefix
- * @alignment: the alignment
- * @pool: the #GstBufferPool
  *
- * Get the allocation parameters in @query.
+ * Set the pool parameters in @query.
  */
 void
-gst_query_parse_allocation_params (GstQuery * query, guint * size,
-    guint * min_buffers, guint * max_buffers, guint * prefix,
-    guint * alignment, GstBufferPool ** pool)
+gst_query_set_nth_allocation_pool (GstQuery * query, guint index,
+    GstBufferPool * pool, guint size, guint min_buffers, guint max_buffers)
 {
+  GArray *array;
   GstStructure *structure;
+  AllocationPool *oldap, ap;
 
   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION);
 
   structure = GST_QUERY_STRUCTURE (query);
-  gst_structure_id_get (structure,
-      GST_QUARK (SIZE), G_TYPE_UINT, size,
-      GST_QUARK (MIN_BUFFERS), G_TYPE_UINT, min_buffers,
-      GST_QUARK (MAX_BUFFERS), G_TYPE_UINT, max_buffers,
-      GST_QUARK (PREFIX), G_TYPE_UINT, prefix,
-      GST_QUARK (ALIGN), G_TYPE_UINT, alignment,
-      GST_QUARK (POOL), GST_TYPE_BUFFER_POOL, pool, NULL);
+  array = ensure_array (structure, GST_QUARK (POOL),
+      sizeof (AllocationPool), (GDestroyNotify) allocation_pool_free);
+  g_return_if_fail (index < array->len);
+
+  oldap = &g_array_index (array, AllocationPool, index);
+  allocation_pool_free (oldap);
+
+  if ((ap.pool = pool))
+    gst_object_ref (pool);
+  ap.size = size;
+  ap.min_buffers = min_buffers;
+  ap.max_buffers = max_buffers;
+  g_array_index (array, AllocationPool, index) = ap;
 }
 
 /**
@@ -1693,23 +1674,19 @@ gst_query_parse_allocation_params (GstQuery * query, guint * size,
  * Add @api as aone of the supported metadata API to @query.
  */
 void
-gst_query_add_allocation_meta (GstQuery * query, const gchar * api)
+gst_query_add_allocation_meta (GstQuery * query, GType api)
 {
-  GValueArray *array;
-  GValue api_value = { 0 };
+  GArray *array;
   GstStructure *structure;
 
   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION);
-  g_return_if_fail (api != NULL);
+  g_return_if_fail (api != 0);
   g_return_if_fail (gst_query_is_writable (query));
 
   structure = GST_QUERY_STRUCTURE (query);
-  array = ensure_array (structure, GST_QUARK (META));
+  array = ensure_array (structure, GST_QUARK (META), sizeof (GType), NULL);
 
-  g_value_init (&api_value, G_TYPE_STRING);
-  g_value_set_string (&api_value, api);
-  g_value_array_append (array, &api_value);
-  g_value_unset (&api_value);
+  g_array_append_val (array, api);
 }
 
 /**
@@ -1724,15 +1701,15 @@ gst_query_add_allocation_meta (GstQuery * query, const gchar * api)
 guint
 gst_query_get_n_allocation_metas (GstQuery * query)
 {
-  GValueArray *array;
+  GArray *array;
   GstStructure *structure;
 
   g_return_val_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION, 0);
 
   structure = GST_QUERY_STRUCTURE (query);
-  array = ensure_array (structure, GST_QUARK (META));
+  array = ensure_array (structure, GST_QUARK (META), sizeof (GType), NULL);
 
-  return array->n_values;
+  return array->len;
 }
 
 /**
@@ -1743,25 +1720,45 @@ gst_query_get_n_allocation_metas (GstQuery * query)
  * Parse an available query and get the metadata API
  * at @index of the metadata API array.
  *
- * Returns: a #gchar of the metadata API at @index.
+ * Returns: a #GType of the metadata API at @index.
  */
-const gchar *
+GType
 gst_query_parse_nth_allocation_meta (GstQuery * query, guint index)
 {
-  GValueArray *array;
-  GValue *value;
-  const gchar *ret = NULL;
+  GArray *array;
   GstStructure *structure;
 
-  g_return_val_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION, NULL);
+  g_return_val_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION, 0);
 
   structure = GST_QUERY_STRUCTURE (query);
-  array = ensure_array (structure, GST_QUARK (META));
+  array = ensure_array (structure, GST_QUARK (META), sizeof (GType), NULL);
 
-  if ((value = g_value_array_get_nth (array, index)))
-    ret = g_value_get_string (value);
+  g_return_val_if_fail (index < array->len, 0);
 
-  return ret;
+  return g_array_index (array, GType, index);
+}
+
+/**
+ * gst_query_remove_nth_allocation_meta:
+ * @query: a GST_QUERY_ALLOCATION type query #GstQuery
+ * @index: position in the metadata API array to remove
+ *
+ * Remove the metadata API at @index of the metadata API array.
+ */
+void
+gst_query_remove_nth_allocation_meta (GstQuery * query, guint index)
+{
+  GArray *array;
+  GstStructure *structure;
+
+  g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION);
+  g_return_if_fail (gst_query_is_writable (query));
+
+  structure = GST_QUERY_STRUCTURE (query);
+  array = ensure_array (structure, GST_QUARK (META), sizeof (GType), NULL);
+  g_return_if_fail (index < array->len);
+
+  g_array_remove_index (array, index);
 }
 
 /**
@@ -1774,59 +1771,79 @@ gst_query_parse_nth_allocation_meta (GstQuery * query, guint index)
  * Returns: TRUE when @api is in the list of metadata.
  */
 gboolean
-gst_query_has_allocation_meta (GstQuery * query, const gchar * api)
+gst_query_has_allocation_meta (GstQuery * query, GType api)
 {
-  GValueArray *array;
-  GValue *value;
+  GArray *array;
   GstStructure *structure;
-  guint i;
+  guint i, len;
 
   g_return_val_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION, FALSE);
-  g_return_val_if_fail (api != NULL, FALSE);
+  g_return_val_if_fail (api != 0, FALSE);
 
   structure = GST_QUERY_STRUCTURE (query);
-  array = ensure_array (structure, GST_QUARK (META));
+  array = ensure_array (structure, GST_QUARK (META), sizeof (GType), NULL);
 
-  for (i = 0; i < array->n_values; i++) {
-    value = g_value_array_get_nth (array, i);
-    if (!strcmp (api, g_value_get_string (value)))
+  len = array->len;
+  for (i = 0; i < len; i++) {
+    if (g_array_index (array, GType, i) == api)
       return TRUE;
   }
   return FALSE;
 }
 
+typedef struct
+{
+  GstAllocator *allocator;
+  GstAllocationParams params;
+} AllocationParam;
+
+static void
+allocation_param_free (AllocationParam * ap)
+{
+  if (ap->allocator)
+    gst_allocator_unref (ap->allocator);
+}
+
 /**
- * gst_query_add_allocation_memory:
+ * gst_query_add_allocation_param:
  * @query: a GST_QUERY_ALLOCATION type query #GstQuery
- * @alloc: the memory allocator
+ * @allocator: the memory allocator
+ * @params: a #GstAllocationParams
  *
- * Add @alloc as a supported memory allocator.
+ * Add @allocator and its @params as a supported memory allocator.
  */
 void
-gst_query_add_allocation_memory (GstQuery * query, const gchar * alloc)
+gst_query_add_allocation_param (GstQuery * query, GstAllocator * allocator,
+    const GstAllocationParams * params)
 {
-  GValueArray *array;
-  GValue value = { 0 };
+  GArray *array;
   GstStructure *structure;
+  AllocationParam ap;
 
   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION);
   g_return_if_fail (gst_query_is_writable (query));
+  g_return_if_fail (allocator != NULL || params != NULL);
 
   structure = GST_QUERY_STRUCTURE (query);
-  array = ensure_array (structure, GST_QUARK (ALLOCATOR));
+  array = ensure_array (structure, GST_QUARK (ALLOCATOR),
+      sizeof (AllocationParam), (GDestroyNotify) allocation_param_free);
+
+  if ((ap.allocator = allocator))
+    gst_allocator_ref (allocator);
+  if (params)
+    ap.params = *params;
+  else
+    gst_allocation_params_init (&ap.params);
 
-  g_value_init (&value, G_TYPE_STRING);
-  g_value_set_string (&value, alloc);
-  g_value_array_append (array, &value);
-  g_value_unset (&value);
+  g_array_append_val (array, ap);
 }
 
 /**
- * gst_query_get_n_allocation_memories:
+ * gst_query_get_n_allocation_params:
  * @query: a GST_QUERY_ALLOCATION type query #GstQuery
  *
  * Retrieve the number of values currently stored in the
- * allocator array of the query's structure.
+ * allocator params array of the query's structure.
  *
  * If no memory allocator is specified, the downstream element can handle
  * the default memory allocator.
@@ -1834,46 +1851,90 @@ gst_query_add_allocation_memory (GstQuery * query, const gchar * alloc)
  * Returns: the allocator array size as a #guint.
  */
 guint
-gst_query_get_n_allocation_memories (GstQuery * query)
+gst_query_get_n_allocation_params (GstQuery * query)
 {
-  GValueArray *array;
+  GArray *array;
   GstStructure *structure;
 
   g_return_val_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION, 0);
 
   structure = GST_QUERY_STRUCTURE (query);
-  array = ensure_array (structure, GST_QUARK (ALLOCATOR));
+  array = ensure_array (structure, GST_QUARK (ALLOCATOR),
+      sizeof (AllocationParam), (GDestroyNotify) allocation_param_free);
 
-  return array->n_values;
+  return array->len;
 }
 
 /**
- * gst_query_parse_nth_allocation_memory:
+ * gst_query_parse_nth_allocation_param:
  * @query: a GST_QUERY_ALLOCATION type query #GstQuery
  * @index: position in the allocator array to read
+ * @allocator: (transfer none): variable to hold the result
+ * @params: parameters for the allocator
  *
- * Parse an available query and get the alloctor
+ * Parse an available query and get the alloctor and its params
  * at @index of the allocator array.
+ */
+void
+gst_query_parse_nth_allocation_param (GstQuery * query, guint index,
+    GstAllocator ** allocator, GstAllocationParams * params)
+{
+  GArray *array;
+  GstStructure *structure;
+  AllocationParam *ap;
+
+  g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION);
+
+  structure = GST_QUERY_STRUCTURE (query);
+  array = ensure_array (structure, GST_QUARK (ALLOCATOR),
+      sizeof (AllocationParam), (GDestroyNotify) allocation_param_free);
+  g_return_if_fail (index < array->len);
+
+  ap = &g_array_index (array, AllocationParam, index);
+
+  if (allocator)
+    if ((*allocator = ap->allocator))
+      gst_allocator_ref (*allocator);
+  if (params)
+    *params = ap->params;
+}
+
+/**
+ * gst_query_set_nth_allocation_param:
+ * @query: a GST_QUERY_ALLOCATION type query #GstQuery
+ * @index: position in the allocator array to set
+ * @allocator: (transfer full): new allocator to set
+ * @params: parameters for the allocator
  *
- * Returns: the name of the allocator at @index.
+ * Parse an available query and get the alloctor and its params
+ * at @index of the allocator array.
  */
-const gchar *
-gst_query_parse_nth_allocation_memory (GstQuery * query, guint index)
+void
+gst_query_set_nth_allocation_param (GstQuery * query, guint index,
+    GstAllocator * allocator, const GstAllocationParams * params)
 {
-  GValueArray *array;
-  GValue *value;
-  const gchar *ret = NULL;
+  GArray *array;
   GstStructure *structure;
+  AllocationParam *old, ap;
 
-  g_return_val_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION, NULL);
+  g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION);
 
   structure = GST_QUERY_STRUCTURE (query);
-  array = ensure_array (structure, GST_QUARK (ALLOCATOR));
+  array = ensure_array (structure, GST_QUARK (ALLOCATOR),
+      sizeof (AllocationParam), (GDestroyNotify) allocation_param_free);
+  g_return_if_fail (index < array->len);
 
-  if ((value = g_value_array_get_nth (array, index)))
-    ret = g_value_get_string (value);
+  old = &g_array_index (array, AllocationParam, index);
+  allocation_param_free (old);
 
-  return ret;
+  if ((ap.allocator = allocator))
+    gst_allocator_ref (allocator);
+  if (params)
+    ap.params = *params;
+  else
+    gst_allocation_params_init (&ap.params);
+
+  g_array_index (array, AllocationParam, index) = ap;
 }
 
 /**
@@ -1896,7 +1957,7 @@ gst_query_new_scheduling (void)
       GST_QUARK (MINSIZE), G_TYPE_INT, 1,
       GST_QUARK (MAXSIZE), G_TYPE_INT, -1,
       GST_QUARK (ALIGN), G_TYPE_INT, 0, NULL);
-  query = gst_query_new (GST_QUERY_SCHEDULING, structure);
+  query = gst_query_new_custom (GST_QUERY_SCHEDULING, structure);
 
   return query;
 }
@@ -1931,10 +1992,10 @@ gst_query_set_scheduling (GstQuery * query, GstSchedulingFlags flags,
 /**
  * gst_query_parse_scheduling:
  * @query: A valid #GstQuery of type GST_QUERY_SCHEDULING.
- * @flags: #GstSchedulingFlags
- * @minsize: the suggested minimum size of pull requests
- * @maxsize: the suggested maximum size of pull requests:
- * @align: the suggested alignment of pull requests
+ * @flags: (out) (allow-none): #GstSchedulingFlags
+ * @minsize: (out) (allow-none): the suggested minimum size of pull requests
+ * @maxsize: (out) (allow-none): the suggested maximum size of pull requests:
+ * @align: (out) (allow-none): the suggested alignment of pull requests
  *
  * Set the scheduling properties.
  */
@@ -1964,20 +2025,17 @@ gst_query_parse_scheduling (GstQuery * query, GstSchedulingFlags * flags,
 void
 gst_query_add_scheduling_mode (GstQuery * query, GstPadMode mode)
 {
-  GValueArray *array;
-  GValue value = { 0 };
   GstStructure *structure;
+  GArray *array;
 
   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_SCHEDULING);
   g_return_if_fail (gst_query_is_writable (query));
 
   structure = GST_QUERY_STRUCTURE (query);
-  array = ensure_array (structure, GST_QUARK (MODES));
+  array =
+      ensure_array (structure, GST_QUARK (MODES), sizeof (GstPadMode), NULL);
 
-  g_value_init (&value, GST_TYPE_PAD_MODE);
-  g_value_set_enum (&value, mode);
-  g_value_array_append (array, &value);
-  g_value_unset (&value);
+  g_array_append_val (array, mode);
 }
 
 /**
@@ -1992,15 +2050,16 @@ gst_query_add_scheduling_mode (GstQuery * query, GstPadMode mode)
 guint
 gst_query_get_n_scheduling_modes (GstQuery * query)
 {
-  GValueArray *array;
+  GArray *array;
   GstStructure *structure;
 
   g_return_val_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_SCHEDULING, 0);
 
   structure = GST_QUERY_STRUCTURE (query);
-  array = ensure_array (structure, GST_QUARK (MODES));
+  array =
+      ensure_array (structure, GST_QUARK (MODES), sizeof (GstPadMode), NULL);
 
-  return array->n_values;
+  return array->len;
 }
 
 /**
@@ -2016,20 +2075,18 @@ gst_query_get_n_scheduling_modes (GstQuery * query)
 GstPadMode
 gst_query_parse_nth_scheduling_mode (GstQuery * query, guint index)
 {
-  GValueArray *array;
-  GValue *value;
-  GstPadMode ret = GST_PAD_MODE_NONE;
   GstStructure *structure;
+  GArray *array;
 
-  g_return_val_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_SCHEDULING, ret);
+  g_return_val_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_SCHEDULING,
+      GST_PAD_MODE_NONE);
 
   structure = GST_QUERY_STRUCTURE (query);
-  array = ensure_array (structure, GST_QUARK (MODES));
-
-  if ((value = g_value_array_get_nth (array, index)))
-    ret = g_value_get_enum (value);
+  array =
+      ensure_array (structure, GST_QUARK (MODES), sizeof (GstPadMode), NULL);
+  g_return_val_if_fail (index < array->len, GST_PAD_MODE_NONE);
 
-  return ret;
+  return g_array_index (array, GstPadMode, index);
 }
 
 /**
@@ -2044,19 +2101,19 @@ gst_query_parse_nth_scheduling_mode (GstQuery * query, guint index)
 gboolean
 gst_query_has_scheduling_mode (GstQuery * query, GstPadMode mode)
 {
-  GValueArray *array;
-  GValue *value;
   GstStructure *structure;
-  guint i;
+  GArray *array;
+  guint i, len;
 
   g_return_val_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_SCHEDULING, FALSE);
 
   structure = GST_QUERY_STRUCTURE (query);
-  array = ensure_array (structure, GST_QUARK (MODES));
+  array =
+      ensure_array (structure, GST_QUARK (MODES), sizeof (GstPadMode), NULL);
 
-  for (i = 0; i < array->n_values; i++) {
-    value = g_value_array_get_nth (array, i);
-    if (mode == g_value_get_enum (value))
+  len = array->len;
+  for (i = 0; i < len; i++) {
+    if (mode == g_array_index (array, GstPadMode, i))
       return TRUE;
   }
   return FALSE;
@@ -2064,7 +2121,7 @@ gst_query_has_scheduling_mode (GstQuery * query, GstPadMode mode)
 
 /**
  * gst_query_new_accept_caps:
- * @caps: a #GstCaps
+ * @caps: a fixed #GstCaps
  *
  * Constructs a new query object for querying if @caps are accepted.
  *
@@ -2078,10 +2135,12 @@ gst_query_new_accept_caps (GstCaps * caps)
   GstQuery *query;
   GstStructure *structure;
 
+  g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
+
   structure = gst_structure_new_id (GST_QUARK (QUERY_ACCEPT_CAPS),
       GST_QUARK (CAPS), GST_TYPE_CAPS, caps,
       GST_QUARK (RESULT), G_TYPE_BOOLEAN, FALSE, NULL);
-  query = gst_query_new (GST_QUERY_ACCEPT_CAPS, structure);
+  query = gst_query_new_custom (GST_QUERY_ACCEPT_CAPS, structure);
 
   return query;
 }
@@ -2100,6 +2159,7 @@ gst_query_parse_accept_caps (GstQuery * query, GstCaps ** caps)
   GstStructure *structure;
 
   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_ACCEPT_CAPS);
+  g_return_if_fail (caps != NULL);
 
   structure = GST_QUERY_STRUCTURE (query);
   *caps = g_value_get_boxed (gst_structure_id_get_value (structure,
@@ -2137,7 +2197,7 @@ gst_query_parse_accept_caps_result (GstQuery * query, gboolean * result)
  *
  * Constructs a new query object for querying the caps.
  *
- * The CAPS query should return the* allowable caps for a pad in the context
+ * The CAPS query should return the allowable caps for a pad in the context
  * of the element's state, its link to other elements, and the devices or files
  * it has opened. These caps must be a subset of the pad template caps. In the
  * NULL state with no links, the CAPS query should ideally return the same caps
@@ -2150,6 +2210,10 @@ gst_query_parse_accept_caps_result (GstQuery * query, gboolean * result)
  * the CAPS query should return the most specific caps it reasonably can, since this
  * helps with autoplugging.
  *
+ * The @filter is used to restrict the result caps, only the caps matching
+ * @filter should be returned from the CAPS query. Specifying a filter might
+ * greatly reduce the amount of processing an element needs to do.
+ *
  * Free-function: gst_query_unref
  *
  * Returns: (transfer full): a new #GstQuery
@@ -2163,7 +2227,7 @@ gst_query_new_caps (GstCaps * filter)
   structure = gst_structure_new_id (GST_QUARK (QUERY_CAPS),
       GST_QUARK (FILTER), GST_TYPE_CAPS, filter,
       GST_QUARK (CAPS), GST_TYPE_CAPS, NULL, NULL);
-  query = gst_query_new (GST_QUERY_CAPS, structure);
+  query = gst_query_new_custom (GST_QUERY_CAPS, structure);
 
   return query;
 }
@@ -2182,6 +2246,7 @@ gst_query_parse_caps (GstQuery * query, GstCaps ** filter)
   GstStructure *structure;
 
   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_CAPS);
+  g_return_if_fail (filter != NULL);
 
   structure = GST_QUERY_STRUCTURE (query);
   *filter = g_value_get_boxed (gst_structure_id_get_value (structure,
@@ -2221,6 +2286,7 @@ gst_query_parse_caps_result (GstQuery * query, GstCaps ** caps)
   GstStructure *structure;
 
   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_CAPS);
+  g_return_if_fail (caps != NULL);
 
   structure = GST_QUERY_STRUCTURE (query);
   *caps = g_value_get_boxed (gst_structure_id_get_value (structure,
@@ -2238,3 +2304,114 @@ gst_query_intersect_caps_result (GstQuery * query, GstCaps * filter,
   gst_query_set_caps_result (query, res);
   gst_caps_unref (res);
 }
+
+/**
+ * gst_query_new_drain:
+ *
+ * Constructs a new query object for querying the drain state.
+ *
+ * Free-function: gst_query_unref
+ *
+ * Returns: (transfer full): a new #GstQuery
+ */
+GstQuery *
+gst_query_new_drain (void)
+{
+  GstQuery *query;
+  GstStructure *structure;
+
+  structure = gst_structure_new_id_empty (GST_QUARK (QUERY_DRAIN));
+  query = gst_query_new_custom (GST_QUERY_DRAIN, structure);
+
+  return query;
+}
+
+/**
+ * gst_query_new_toc:
+ *
+ * Constructs a new query TOC query object. Use gst_query_unref()
+ * when done with it. A TOC query is used to query the full TOC with
+ * the UID marker for TOC extending (to insert some new entries).
+ *
+ * Returns: A #GstQuery.
+ */
+GstQuery *
+gst_query_new_toc (void)
+{
+  GstQuery *query;
+  GstStructure *structure;
+
+  structure = gst_structure_new_id_empty (GST_QUARK (QUERY_TOC));
+  query = gst_query_new_custom (GST_QUERY_TOC, structure);
+
+  return query;
+}
+
+/**
+ * gst_query_set_toc:
+ * @query: a #GstQuery with query type GST_QUERY_TOC.
+ * @toc: the GstToc to set.
+ * @extend_uid: UID which can be used for TOC extending (may be NULL),
+ * 0 means root TOC level.
+ *
+ * Answer a TOC query by setting appropriate #GstToc structure.
+ */
+void
+gst_query_set_toc (GstQuery * query, GstToc * toc, const gchar * extend_uid)
+{
+  GstStructure *structure;
+  GstStructure *old_structure;
+
+  g_return_if_fail (query != NULL);
+  g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_TOC);
+  g_return_if_fail (toc != NULL);
+
+  structure = __gst_toc_to_structure (toc);
+
+  g_return_if_fail (structure != NULL);
+
+  /* that shouldn't be happen in normal usage */
+  old_structure = GST_QUERY_STRUCTURE (query);
+  if (old_structure) {
+    gst_structure_set_parent_refcount (old_structure, NULL);
+    gst_structure_free (old_structure);
+  }
+
+  if (extend_uid != NULL)
+    __gst_toc_structure_set_extend_uid (structure, extend_uid);
+
+  gst_structure_set_parent_refcount (structure, &(query->mini_object.refcount));
+  GST_QUERY_STRUCTURE (query) = structure;
+}
+
+/**
+ * gst_query_parse_toc:
+ * @query: a #GstQuery.
+ * @toc: (out): the storage for the received TOC (may be NULL).
+ * @extend_uid: (out): the storage for the received extend UID marker (may be NULL),
+ * 0 means root TOC level.
+ *
+ * Parse a TOC query, writing the TOC into @toc as a newly
+ * allocated #GstToc and extend UID into @extend_uid, if the respective parameters
+ * are non-NULL. Use @extend_uid value to insert new entries into the TOC (@extend_uid will
+ * act as root entry for newly inserted entries).
+ * Free @toc with gst_toc_free() and @extend_uid with g_free() after usage.
+ */
+void
+gst_query_parse_toc (GstQuery * query, GstToc ** toc, gchar ** extend_uid)
+{
+  const GstStructure *structure;
+
+  g_return_if_fail (query != NULL);
+  g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_TOC);
+
+  structure = gst_query_get_structure (query);
+
+  g_return_if_fail (structure != NULL);
+
+  if (toc != NULL)
+    *toc = __gst_toc_from_structure (structure);
+
+  if (extend_uid != NULL)
+    *extend_uid = __gst_toc_structure_get_extend_uid (structure);
+}