gst/gstpoll.c: Fix compilation of GstPoll with mingw32. Fixes bug #526236.
[platform/upstream/gstreamer.git] / gst / gstquery.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wim.taymans@chello.be>
4  *                    2005 Wim Taymans <wim@fluendo.com>
5  *
6  * gstquery.c: GstQueryType registration and Query parsing/creation
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 /**
25  * SECTION:gstquery
26  * @short_description: Dynamically register new query types. Provide functions
27  *                     to create queries, and to set and parse values in them.
28  * @see_also: #GstPad, #GstElement
29  *
30  * GstQuery functions are used to register a new query types to the gstreamer
31  * core.
32  * Query types can be used to perform queries on pads and elements.
33  *
34  * Queries can be created using the gst_query_new_xxx() functions.  
35  * Query values can be set using gst_query_set_xxx(), and parsed using 
36  * gst_query_parse_xxx() helpers.
37  *
38  * The following example shows how to query the duration of a pipeline:
39  * 
40  * <example>
41  *  <title>Query duration on a pipeline</title>
42  *  <programlisting>
43  *  GstQuery *query;
44  *  gboolean res;
45  *  query = gst_query_new_duration (GST_FORMAT_TIME);
46  *  res = gst_element_query (pipeline, query);
47  *  if (res) {
48  *    gint64 duration;
49  *    gst_query_parse_duration (query, NULL, &amp;duration);
50  *    g_print ("duration = %"GST_TIME_FORMAT, GST_TIME_ARGS (duration));
51  *  }
52  *  else {
53  *    g_print ("duration query failed...");
54  *  }
55  *  gst_query_unref (query);
56  *  </programlisting>
57  * </example>
58  *
59  * Last reviewed on 2006-02-14 (0.10.4)
60  */
61
62 #include "gst_private.h"
63 #include "gstinfo.h"
64 #include "gstquery.h"
65 #include "gstvalue.h"
66 #include "gstenumtypes.h"
67 #include "gstquark.h"
68
69 GST_DEBUG_CATEGORY_STATIC (gst_query_debug);
70 #define GST_CAT_DEFAULT gst_query_debug
71
72 static void gst_query_class_init (gpointer g_class, gpointer class_data);
73 static void gst_query_finalize (GstQuery * query);
74 static GstQuery *_gst_query_copy (GstQuery * query);
75
76 static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
77 static GList *_gst_queries = NULL;
78 static GHashTable *_nick_to_query = NULL;
79 static GHashTable *_query_type_to_nick = NULL;
80 static guint32 _n_values = 1;   /* we start from 1 because 0 reserved for NONE */
81
82 static GstMiniObjectClass *parent_class = NULL;
83
84 static GstQueryTypeDefinition standard_definitions[] = {
85   {GST_QUERY_POSITION, "position", "Current position", 0},
86   {GST_QUERY_DURATION, "duration", "Total duration", 0},
87   {GST_QUERY_LATENCY, "latency", "Latency", 0},
88   {GST_QUERY_JITTER, "jitter", "Jitter", 0},
89   {GST_QUERY_RATE, "rate", "Configured rate 1000000 = 1", 0},
90   {GST_QUERY_SEEKING, "seeking", "Seeking capabilities and parameters", 0},
91   {GST_QUERY_SEGMENT, "segment", "currently configured segment", 0},
92   {GST_QUERY_CONVERT, "convert", "Converting between formats", 0},
93   {GST_QUERY_FORMATS, "formats", "Supported formats for conversion", 0},
94   {0, NULL, NULL, 0}
95 };
96
97 void
98 _gst_query_initialize (void)
99 {
100   GstQueryTypeDefinition *standards = standard_definitions;
101
102   GST_CAT_INFO (GST_CAT_GST_INIT, "init queries");
103
104   GST_DEBUG_CATEGORY_INIT (gst_query_debug, "query", 0, "query system");
105
106   g_static_mutex_lock (&mutex);
107   if (_nick_to_query == NULL) {
108     _nick_to_query = g_hash_table_new (g_str_hash, g_str_equal);
109     _query_type_to_nick = g_hash_table_new (NULL, NULL);
110   }
111
112   while (standards->nick) {
113     standards->quark = g_quark_from_static_string (standards->nick);
114     g_hash_table_insert (_nick_to_query, standards->nick, standards);
115     g_hash_table_insert (_query_type_to_nick,
116         GINT_TO_POINTER (standards->value), standards);
117
118     _gst_queries = g_list_append (_gst_queries, standards);
119     standards++;
120     _n_values++;
121   }
122   g_static_mutex_unlock (&mutex);
123
124   g_type_class_ref (gst_query_get_type ());
125 }
126
127 /**
128  * gst_query_type_get_name:
129  * @query: the query type
130  *
131  * Get a printable name for the given query type. Do not modify or free.
132  *
133  * Returns: a reference to the static name of the query.
134  */
135 const gchar *
136 gst_query_type_get_name (GstQueryType query)
137 {
138   const GstQueryTypeDefinition *def;
139
140   def = gst_query_type_get_details (query);
141
142   return def->nick;
143 }
144
145 /**
146  * gst_query_type_to_quark:
147  * @query: the query type
148  *
149  * Get the unique quark for the given query type.
150  *
151  * Returns: the quark associated with the query type
152  */
153 GQuark
154 gst_query_type_to_quark (GstQueryType query)
155 {
156   const GstQueryTypeDefinition *def;
157
158   def = gst_query_type_get_details (query);
159
160   return def->quark;
161 }
162
163 GType
164 gst_query_get_type (void)
165 {
166   static GType _gst_query_type;
167
168   if (G_UNLIKELY (_gst_query_type == 0)) {
169     static const GTypeInfo query_info = {
170       sizeof (GstQueryClass),
171       NULL,
172       NULL,
173       gst_query_class_init,
174       NULL,
175       NULL,
176       sizeof (GstQuery),
177       0,
178       NULL,
179       NULL
180     };
181
182     _gst_query_type = g_type_register_static (GST_TYPE_MINI_OBJECT,
183         "GstQuery", &query_info, 0);
184   }
185   return _gst_query_type;
186 }
187
188 static void
189 gst_query_class_init (gpointer g_class, gpointer class_data)
190 {
191   GstQueryClass *query_class = GST_QUERY_CLASS (g_class);
192
193   parent_class = g_type_class_peek_parent (g_class);
194
195   query_class->mini_object_class.copy =
196       (GstMiniObjectCopyFunction) _gst_query_copy;
197   query_class->mini_object_class.finalize =
198       (GstMiniObjectFinalizeFunction) gst_query_finalize;
199
200 }
201
202 static void
203 gst_query_finalize (GstQuery * query)
204 {
205   g_return_if_fail (query != NULL);
206
207   if (query->structure) {
208     gst_structure_set_parent_refcount (query->structure, NULL);
209     gst_structure_free (query->structure);
210   }
211
212   GST_MINI_OBJECT_CLASS (parent_class)->finalize (GST_MINI_OBJECT (query));
213 }
214
215 static GstQuery *
216 _gst_query_copy (GstQuery * query)
217 {
218   GstQuery *copy;
219
220   copy = (GstQuery *) gst_mini_object_new (GST_TYPE_QUERY);
221
222   copy->type = query->type;
223
224   if (query->structure) {
225     copy->structure = gst_structure_copy (query->structure);
226     gst_structure_set_parent_refcount (copy->structure,
227         &query->mini_object.refcount);
228   }
229
230   return copy;
231 }
232
233
234
235 /**
236  * gst_query_type_register:
237  * @nick: The nick of the new query
238  * @description: The description of the new query
239  *
240  * Create a new GstQueryType based on the nick or return an
241  * already registered query with that nick
242  *
243  * Returns: A new GstQueryType or an already registered query
244  * with the same nick.
245  */
246 GstQueryType
247 gst_query_type_register (const gchar * nick, const gchar * description)
248 {
249   GstQueryTypeDefinition *query;
250   GstQueryType lookup;
251
252   g_return_val_if_fail (nick != NULL, 0);
253   g_return_val_if_fail (description != NULL, 0);
254
255   lookup = gst_query_type_get_by_nick (nick);
256   if (lookup != GST_QUERY_NONE)
257     return lookup;
258
259   query = g_new0 (GstQueryTypeDefinition, 1);
260   query->value = _n_values;
261   query->nick = g_strdup (nick);
262   query->description = g_strdup (description);
263   query->quark = g_quark_from_static_string (query->nick);
264
265   g_static_mutex_lock (&mutex);
266   g_hash_table_insert (_nick_to_query, query->nick, query);
267   g_hash_table_insert (_query_type_to_nick, GINT_TO_POINTER (query->value),
268       query);
269   _gst_queries = g_list_append (_gst_queries, query);
270   _n_values++;
271   g_static_mutex_unlock (&mutex);
272
273   return query->value;
274 }
275
276 /**
277  * gst_query_type_get_by_nick:
278  * @nick: The nick of the query
279  *
280  * Get the query type registered with @nick.
281  *
282  * Returns: The query registered with @nick or #GST_QUERY_NONE
283  * if the query was not registered.
284  */
285 GstQueryType
286 gst_query_type_get_by_nick (const gchar * nick)
287 {
288   GstQueryTypeDefinition *query;
289
290   g_return_val_if_fail (nick != NULL, 0);
291
292   g_static_mutex_lock (&mutex);
293   query = g_hash_table_lookup (_nick_to_query, nick);
294   g_static_mutex_unlock (&mutex);
295
296   if (query != NULL)
297     return query->value;
298   else
299     return GST_QUERY_NONE;
300 }
301
302 /**
303  * gst_query_types_contains:
304  * @types: The query array to search
305  * @type: the #GstQueryType to find
306  *
307  * See if the given #GstQueryType is inside the @types query types array.
308  *
309  * Returns: TRUE if the type is found inside the array
310  */
311 gboolean
312 gst_query_types_contains (const GstQueryType * types, GstQueryType type)
313 {
314   if (!types)
315     return FALSE;
316
317   while (*types) {
318     if (*types == type)
319       return TRUE;
320
321     types++;
322   }
323   return FALSE;
324 }
325
326
327 /**
328  * gst_query_type_get_details:
329  * @type: a #GstQueryType
330  *
331  * Get details about the given #GstQueryType.
332  *
333  * Returns: The #GstQueryTypeDefinition for @type or NULL on failure.
334  */
335 const GstQueryTypeDefinition *
336 gst_query_type_get_details (GstQueryType type)
337 {
338   const GstQueryTypeDefinition *result;
339
340   g_static_mutex_lock (&mutex);
341   result = g_hash_table_lookup (_query_type_to_nick, GINT_TO_POINTER (type));
342   g_static_mutex_unlock (&mutex);
343
344   return result;
345 }
346
347 /**
348  * gst_query_type_iterate_definitions:
349  *
350  * Get a #GstIterator of all the registered query types. The definitions 
351  * iterated over are read only.
352  *
353  * Returns: A #GstIterator of #GstQueryTypeDefinition.
354  */
355 GstIterator *
356 gst_query_type_iterate_definitions (void)
357 {
358   GstIterator *result;
359
360   g_static_mutex_lock (&mutex);
361   /* FIXME: register a boxed type for GstQueryTypeDefinition */
362   result = gst_iterator_new_list (G_TYPE_POINTER,
363       g_static_mutex_get_mutex (&mutex), &_n_values, &_gst_queries,
364       NULL, NULL, NULL);
365   g_static_mutex_unlock (&mutex);
366
367   return result;
368 }
369
370 static GstQuery *
371 gst_query_new (GstQueryType type, GstStructure * structure)
372 {
373   GstQuery *query;
374
375   query = (GstQuery *) gst_mini_object_new (GST_TYPE_QUERY);
376
377   GST_DEBUG ("creating new query %p %d", query, type);
378
379   query->type = type;
380
381   if (structure) {
382     query->structure = structure;
383     gst_structure_set_parent_refcount (query->structure,
384         &query->mini_object.refcount);
385   } else {
386     query->structure = NULL;
387   }
388
389   return query;
390 }
391
392 /**
393  * gst_query_new_position:
394  * @format: the default #GstFormat for the new query
395  *
396  * Constructs a new query stream position query object. Use gst_query_unref()
397  * when done with it. A position query is used to query the current position
398  * of playback in the streams, in some format.
399  *
400  * Returns: A #GstQuery
401  */
402 GstQuery *
403 gst_query_new_position (GstFormat format)
404 {
405   GstQuery *query;
406   GstStructure *structure;
407
408   structure = gst_structure_empty_new ("GstQueryPosition");
409   gst_structure_id_set (structure,
410       GST_QUARK (FORMAT), GST_TYPE_FORMAT, format,
411       GST_QUARK (CURRENT), G_TYPE_INT64, (gint64) - 1, NULL);
412
413   query = gst_query_new (GST_QUERY_POSITION, structure);
414
415   return query;
416 }
417
418 /**
419  * gst_query_set_position:
420  * @query: a #GstQuery with query type GST_QUERY_POSITION
421  * @format: the requested #GstFormat
422  * @cur: the position to set
423  *
424  * Answer a position query by setting the requested value in the given format.
425  */
426 void
427 gst_query_set_position (GstQuery * query, GstFormat format, gint64 cur)
428 {
429   GstStructure *structure;
430
431   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_POSITION);
432
433   structure = gst_query_get_structure (query);
434   gst_structure_id_set (structure,
435       GST_QUARK (FORMAT), GST_TYPE_FORMAT, format,
436       GST_QUARK (CURRENT), G_TYPE_INT64, cur, NULL);
437 }
438
439 /**
440  * gst_query_parse_position:
441  * @query: a #GstQuery
442  * @format: the storage for the #GstFormat of the position values (may be NULL)
443  * @cur: the storage for the current position (may be NULL)
444  *
445  * Parse a position query, writing the format into @format, and the position
446  * into @cur, if the respective parameters are non-NULL.
447  */
448 void
449 gst_query_parse_position (GstQuery * query, GstFormat * format, gint64 * cur)
450 {
451   GstStructure *structure;
452
453   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_POSITION);
454
455   structure = gst_query_get_structure (query);
456   if (format)
457     *format = g_value_get_enum (gst_structure_id_get_value (structure,
458             GST_QUARK (FORMAT)));
459   if (cur)
460     *cur = g_value_get_int64 (gst_structure_id_get_value (structure,
461             GST_QUARK (CURRENT)));
462 }
463
464
465 /**
466  * gst_query_new_duration:
467  * @format: the #GstFormat for this duration query
468  *
469  * Constructs a new stream duration query object to query in the given format. 
470  * Use gst_query_unref() when done with it. A duration query will give the
471  * total length of the stream.
472  *
473  * Returns: A #GstQuery
474  */
475 GstQuery *
476 gst_query_new_duration (GstFormat format)
477 {
478   GstQuery *query;
479   GstStructure *structure;
480
481   structure = gst_structure_empty_new ("GstQueryDuration");
482   gst_structure_id_set (structure,
483       GST_QUARK (FORMAT), GST_TYPE_FORMAT, format,
484       GST_QUARK (DURATION), G_TYPE_INT64, (gint64) - 1, NULL);
485
486   query = gst_query_new (GST_QUERY_DURATION, structure);
487
488   return query;
489 }
490
491 /**
492  * gst_query_set_duration:
493  * @query: a #GstQuery
494  * @format: the #GstFormat for the duration
495  * @duration: the duration of the stream
496  *
497  * Answer a duration query by setting the requested value in the given format.
498  */
499 void
500 gst_query_set_duration (GstQuery * query, GstFormat format, gint64 duration)
501 {
502   GstStructure *structure;
503
504   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_DURATION);
505
506   structure = gst_query_get_structure (query);
507   gst_structure_id_set (structure,
508       GST_QUARK (FORMAT), GST_TYPE_FORMAT, format,
509       GST_QUARK (DURATION), G_TYPE_INT64, duration, NULL);
510 }
511
512 /**
513  * gst_query_parse_duration:
514  * @query: a #GstQuery
515  * @format: the storage for the #GstFormat of the duration value, or NULL.
516  * @duration: the storage for the total duration, or NULL.
517  *
518  * Parse a duration query answer. Write the format of the duration into @format,
519  * and the value into @duration, if the respective variables are non-NULL.
520  */
521 void
522 gst_query_parse_duration (GstQuery * query, GstFormat * format,
523     gint64 * duration)
524 {
525   GstStructure *structure;
526
527   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_DURATION);
528
529   structure = gst_query_get_structure (query);
530   if (format)
531     *format = g_value_get_enum (gst_structure_id_get_value (structure,
532             GST_QUARK (FORMAT)));
533   if (duration)
534     *duration = g_value_get_int64 (gst_structure_id_get_value (structure,
535             GST_QUARK (DURATION)));
536 }
537
538 /**
539  * gst_query_new_latency:
540  *
541  * Constructs a new latency query object. 
542  * Use gst_query_unref() when done with it. A latency query is usually performed
543  * by sinks to compensate for additional latency introduced by elements in the
544  * pipeline.
545  *
546  * Returns: A #GstQuery
547  *
548  * Since: 0.10.12
549  */
550 GstQuery *
551 gst_query_new_latency (void)
552 {
553   GstQuery *query;
554   GstStructure *structure;
555
556   structure = gst_structure_empty_new ("GstQueryLatency");
557   gst_structure_set (structure,
558       "live", G_TYPE_BOOLEAN, FALSE,
559       "min-latency", G_TYPE_UINT64, (gint64) 0,
560       "max-latency", G_TYPE_UINT64, (gint64) - 1, NULL);
561
562   query = gst_query_new (GST_QUERY_LATENCY, structure);
563
564   return query;
565 }
566
567 /**
568  * gst_query_set_latency:
569  * @query: a #GstQuery
570  * @live: if there is a live element upstream
571  * @min_latency: the minimal latency of the live element
572  * @max_latency: the maximal latency of the live element
573  *
574  * Answer a latency query by setting the requested values in the given format.
575  *
576  * Since: 0.10.12
577  */
578 void
579 gst_query_set_latency (GstQuery * query, gboolean live,
580     GstClockTime min_latency, GstClockTime max_latency)
581 {
582   GstStructure *structure;
583
584   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_LATENCY);
585
586   structure = gst_query_get_structure (query);
587   gst_structure_set (structure,
588       "live", G_TYPE_BOOLEAN, live,
589       "min-latency", G_TYPE_UINT64, min_latency,
590       "max-latency", G_TYPE_UINT64, max_latency, NULL);
591 }
592
593 /**
594  * gst_query_parse_latency:
595  * @query: a #GstQuery
596  * @live: storage for live or NULL 
597  * @min_latency: the storage for the min latency or NULL
598  * @max_latency: the storage for the max latency or NULL
599  *
600  * Parse a latency query answer. 
601  *
602  * Since: 0.10.12
603  */
604 void
605 gst_query_parse_latency (GstQuery * query, gboolean * live,
606     GstClockTime * min_latency, GstClockTime * max_latency)
607 {
608   GstStructure *structure;
609
610   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_LATENCY);
611
612   structure = gst_query_get_structure (query);
613   if (live)
614     *live = g_value_get_boolean (gst_structure_get_value (structure, "live"));
615   if (min_latency)
616     *min_latency = g_value_get_uint64 (gst_structure_get_value (structure,
617             "min-latency"));
618   if (max_latency)
619     *max_latency = g_value_get_uint64 (gst_structure_get_value (structure,
620             "max-latency"));
621 }
622
623 /**
624  * gst_query_new_convert:
625  * @src_format: the source #GstFormat for the new query
626  * @value: the value to convert
627  * @dest_format: the target #GstFormat
628  *
629  * Constructs a new convert query object. Use gst_query_unref()
630  * when done with it. A convert query is used to ask for a conversion between
631  * one format and another.
632  *
633  * Returns: A #GstQuery
634  */
635 GstQuery *
636 gst_query_new_convert (GstFormat src_format, gint64 value,
637     GstFormat dest_format)
638 {
639   GstQuery *query;
640   GstStructure *structure;
641
642   g_return_val_if_fail (value >= 0, NULL);
643
644   structure = gst_structure_empty_new ("GstQueryConvert");
645   gst_structure_id_set (structure,
646       GST_QUARK (SRC_FORMAT), GST_TYPE_FORMAT, src_format,
647       GST_QUARK (SRC_VALUE), G_TYPE_INT64, value,
648       GST_QUARK (DEST_FORMAT), GST_TYPE_FORMAT, dest_format,
649       GST_QUARK (DEST_VALUE), G_TYPE_INT64, (gint64) - 1, NULL);
650
651   query = gst_query_new (GST_QUERY_CONVERT, structure);
652
653   return query;
654 }
655
656 /**
657  * gst_query_set_convert:
658  * @query: a #GstQuery
659  * @src_format: the source #GstFormat
660  * @src_value: the source value
661  * @dest_format: the destination #GstFormat
662  * @dest_value: the destination value
663  *
664  * Answer a convert query by setting the requested values.
665  */
666 void
667 gst_query_set_convert (GstQuery * query, GstFormat src_format, gint64 src_value,
668     GstFormat dest_format, gint64 dest_value)
669 {
670   GstStructure *structure;
671
672   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_CONVERT);
673
674   structure = gst_query_get_structure (query);
675   gst_structure_id_set (structure,
676       GST_QUARK (SRC_FORMAT), GST_TYPE_FORMAT, src_format,
677       GST_QUARK (SRC_VALUE), G_TYPE_INT64, src_value,
678       GST_QUARK (DEST_FORMAT), GST_TYPE_FORMAT, dest_format,
679       GST_QUARK (DEST_VALUE), G_TYPE_INT64, (gint64) dest_value, NULL);
680 }
681
682 /**
683  * gst_query_parse_convert:
684  * @query: a #GstQuery
685  * @src_format: the storage for the #GstFormat of the source value, or NULL
686  * @src_value: the storage for the source value, or NULL
687  * @dest_format: the storage for the #GstFormat of the destination value, or NULL
688  * @dest_value: the storage for the destination value, or NULL
689  *
690  * Parse a convert query answer. Any of @src_format, @src_value, @dest_format,
691  * and @dest_value may be NULL, in which case that value is omitted.
692  */
693 void
694 gst_query_parse_convert (GstQuery * query, GstFormat * src_format,
695     gint64 * src_value, GstFormat * dest_format, gint64 * dest_value)
696 {
697   GstStructure *structure;
698
699   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_CONVERT);
700
701   structure = gst_query_get_structure (query);
702   if (src_format)
703     *src_format = g_value_get_enum (gst_structure_id_get_value (structure,
704             GST_QUARK (SRC_FORMAT)));
705   if (src_value)
706     *src_value = g_value_get_int64 (gst_structure_id_get_value (structure,
707             GST_QUARK (SRC_VALUE)));
708   if (dest_format)
709     *dest_format = g_value_get_enum (gst_structure_id_get_value (structure,
710             GST_QUARK (DEST_FORMAT)));
711   if (dest_value)
712     *dest_value = g_value_get_int64 (gst_structure_id_get_value (structure,
713             GST_QUARK (DEST_VALUE)));
714 }
715
716 /**
717  * gst_query_new_segment:
718  * @format: the #GstFormat for the new query
719  *
720  * Constructs a new segment query object. Use gst_query_unref()
721  * when done with it. A segment query is used to discover information about the
722  * currently configured segment for playback.
723  *
724  * Returns: a #GstQuery
725  */
726 GstQuery *
727 gst_query_new_segment (GstFormat format)
728 {
729   GstQuery *query;
730   GstStructure *structure;
731
732   structure = gst_structure_empty_new ("GstQuerySegment");
733   gst_structure_id_set (structure,
734       GST_QUARK (RATE), G_TYPE_DOUBLE, (gdouble) 0.0,
735       GST_QUARK (FORMAT), GST_TYPE_FORMAT, format,
736       GST_QUARK (START_VALUE), G_TYPE_INT64, (gint64) - 1,
737       GST_QUARK (STOP_VALUE), G_TYPE_INT64, (gint64) - 1, NULL);
738
739   query = gst_query_new (GST_QUERY_SEGMENT, structure);
740
741   return query;
742 }
743
744 /**
745  * gst_query_set_segment:
746  * @query: a #GstQuery
747  * @rate: the rate of the segment
748  * @format: the #GstFormat of the segment values (@start_value and @stop_value)
749  * @start_value: the start value
750  * @stop_value: the stop value
751  *
752  * Answer a segment query by setting the requested values. The normal
753  * playback segment of a pipeline is 0 to duration at the default rate of
754  * 1.0. If a seek was performed on the pipeline to play a different
755  * segment, this query will return the range specified in the last seek.
756  *
757  * @start_value and @stop_value will respectively contain the configured 
758  * playback range start and stop values expressed in @format. 
759  * The values are always between 0 and the duration of the media and 
760  * @start_value <= @stop_value. @rate will contain the playback rate. For
761  * negative rates, playback will actually happen from @stop_value to
762  * @start_value.
763  */
764 void
765 gst_query_set_segment (GstQuery * query, gdouble rate, GstFormat format,
766     gint64 start_value, gint64 stop_value)
767 {
768   GstStructure *structure;
769
770   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_SEGMENT);
771
772   structure = gst_query_get_structure (query);
773   gst_structure_id_set (structure,
774       GST_QUARK (RATE), G_TYPE_DOUBLE, rate,
775       GST_QUARK (FORMAT), GST_TYPE_FORMAT, format,
776       GST_QUARK (START_VALUE), G_TYPE_INT64, start_value,
777       GST_QUARK (STOP_VALUE), G_TYPE_INT64, stop_value, NULL);
778 }
779
780 /**
781  * gst_query_parse_segment:
782  * @query: a #GstQuery
783  * @rate: the storage for the rate of the segment, or NULL
784  * @format: the storage for the #GstFormat of the values, or NULL
785  * @start_value: the storage for the start value, or NULL
786  * @stop_value: the storage for the stop value, or NULL
787  *
788  * Parse a segment query answer. Any of @rate, @format, @start_value, and 
789  * @stop_value may be NULL, which will cause this value to be omitted.
790  *
791  * See gst_query_set_segment() for an explanation of the function arguments.
792  */
793 void
794 gst_query_parse_segment (GstQuery * query, gdouble * rate, GstFormat * format,
795     gint64 * start_value, gint64 * stop_value)
796 {
797   GstStructure *structure;
798
799   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_SEGMENT);
800
801   structure = gst_query_get_structure (query);
802   if (rate)
803     *rate = g_value_get_double (gst_structure_id_get_value (structure,
804             GST_QUARK (RATE)));
805   if (format)
806     *format = g_value_get_enum (gst_structure_id_get_value (structure,
807             GST_QUARK (FORMAT)));
808   if (start_value)
809     *start_value = g_value_get_int64 (gst_structure_id_get_value (structure,
810             GST_QUARK (START_VALUE)));
811   if (stop_value)
812     *stop_value = g_value_get_int64 (gst_structure_id_get_value (structure,
813             GST_QUARK (STOP_VALUE)));
814 }
815
816 /**
817  * gst_query_new_application:
818  * @type: the query type
819  * @structure: a structure for the query
820  *
821  * Constructs a new custom application query object. Use gst_query_unref()
822  * when done with it.
823  *
824  * Returns: a #GstQuery
825  */
826 GstQuery *
827 gst_query_new_application (GstQueryType type, GstStructure * structure)
828 {
829   g_return_val_if_fail (gst_query_type_get_details (type) != NULL, NULL);
830   g_return_val_if_fail (structure != NULL, NULL);
831
832   return gst_query_new (type, structure);
833 }
834
835 /**
836  * gst_query_get_structure:
837  * @query: a #GstQuery
838  *
839  * Get the structure of a query.
840  *
841  * Returns: The #GstStructure of the query. The structure is still owned
842  * by the query and will therefore be freed when the query is unreffed.
843  */
844 GstStructure *
845 gst_query_get_structure (GstQuery * query)
846 {
847   g_return_val_if_fail (GST_IS_QUERY (query), NULL);
848
849   return query->structure;
850 }
851
852 /**
853  * gst_query_new_seeking (GstFormat *format)
854  * @format: the default #GstFormat for the new query
855  *
856  * Constructs a new query object for querying seeking properties of
857  * the stream. 
858  *
859  * Returns: A #GstQuery
860  */
861 GstQuery *
862 gst_query_new_seeking (GstFormat format)
863 {
864   GstQuery *query;
865   GstStructure *structure;
866
867   structure = gst_structure_empty_new ("GstQuerySeeking");
868   gst_structure_id_set (structure,
869       GST_QUARK (FORMAT), GST_TYPE_FORMAT, format,
870       GST_QUARK (SEEKABLE), G_TYPE_BOOLEAN, FALSE,
871       GST_QUARK (SEGMENT_START), G_TYPE_INT64, (gint64) - 1,
872       GST_QUARK (SEGMENT_END), G_TYPE_INT64, (gint64) - 1, NULL);
873
874   query = gst_query_new (GST_QUERY_SEEKING, structure);
875
876   return query;
877 }
878
879 /**
880  * gst_query_set_seeking:
881  * @query: a #GstQuery
882  * @format: the format to set for the @segment_start and @segment_end values
883  * @seekable: the seekable flag to set
884  * @segment_start: the segment_start to set
885  * @segment_end: the segment_end to set
886  *
887  * Set the seeking query result fields in @query.
888  */
889 void
890 gst_query_set_seeking (GstQuery * query, GstFormat format,
891     gboolean seekable, gint64 segment_start, gint64 segment_end)
892 {
893   GstStructure *structure;
894
895   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_SEEKING);
896
897   structure = gst_query_get_structure (query);
898   gst_structure_id_set (structure,
899       GST_QUARK (FORMAT), GST_TYPE_FORMAT, format,
900       GST_QUARK (SEEKABLE), G_TYPE_BOOLEAN, seekable,
901       GST_QUARK (SEGMENT_START), G_TYPE_INT64, segment_start,
902       GST_QUARK (SEGMENT_END), G_TYPE_INT64, segment_end, NULL);
903 }
904
905 /**
906  * gst_query_parse_seeking:
907  * @query: a GST_QUERY_SEEKING type query #GstQuery
908  * @format: the format to set for the @segment_start and @segment_end values
909  * @seekable: the seekable flag to set
910  * @segment_start: the segment_start to set
911  * @segment_end: the segment_end to set
912  *
913  * Parse a seeking query, writing the format into @format, and 
914  * other results into the passed parameters, if the respective parameters
915  * are non-NULL
916  */
917 void
918 gst_query_parse_seeking (GstQuery * query, GstFormat * format,
919     gboolean * seekable, gint64 * segment_start, gint64 * segment_end)
920 {
921   GstStructure *structure;
922
923   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_SEEKING);
924
925   structure = gst_query_get_structure (query);
926   if (format)
927     *format = g_value_get_enum (gst_structure_id_get_value (structure,
928             GST_QUARK (FORMAT)));
929   if (seekable)
930     *seekable = g_value_get_boolean (gst_structure_id_get_value (structure,
931             GST_QUARK (SEEKABLE)));
932   if (segment_start)
933     *segment_start = g_value_get_int64 (gst_structure_id_get_value (structure,
934             GST_QUARK (SEGMENT_START)));
935   if (segment_end)
936     *segment_end = g_value_get_int64 (gst_structure_id_get_value (structure,
937             GST_QUARK (SEGMENT_END)));
938 }
939
940 /**
941  * gst_query_new_formats:
942  *
943  * Constructs a new query object for querying formats of
944  * the stream. 
945  *
946  * Returns: A #GstQuery
947  *
948  * Since: 0.10.4
949  */
950 GstQuery *
951 gst_query_new_formats (void)
952 {
953   GstQuery *query;
954   GstStructure *structure;
955
956   structure = gst_structure_new ("GstQueryFormats", NULL);
957   query = gst_query_new (GST_QUERY_FORMATS, structure);
958
959   return query;
960 }
961
962 static void
963 gst_query_list_add_format (GValue * list, GstFormat format)
964 {
965   GValue item = { 0, };
966
967   g_value_init (&item, GST_TYPE_FORMAT);
968   g_value_set_enum (&item, format);
969   gst_value_list_append_value (list, &item);
970   g_value_unset (&item);
971 }
972
973 /**
974  * gst_query_set_formats:
975  * @query: a #GstQuery
976  * @n_formats: the number of formats to set.
977  * @...: A number of @GstFormats equal to @n_formats.
978  *
979  * Set the formats query result fields in @query. The number of formats passed
980  * must be equal to @n_formats.
981  */
982 void
983 gst_query_set_formats (GstQuery * query, gint n_formats, ...)
984 {
985   va_list ap;
986   GValue list = { 0, };
987   GstStructure *structure;
988   gint i;
989
990   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_FORMATS);
991
992   g_value_init (&list, GST_TYPE_LIST);
993
994   va_start (ap, n_formats);
995   for (i = 0; i < n_formats; i++) {
996     gst_query_list_add_format (&list, va_arg (ap, GstFormat));
997   }
998   va_end (ap);
999
1000   structure = gst_query_get_structure (query);
1001   gst_structure_set_value (structure, "formats", &list);
1002
1003   g_value_unset (&list);
1004
1005 }
1006
1007 /**
1008  * gst_query_set_formatsv:
1009  * @query: a #GstQuery
1010  * @n_formats: the number of formats to set.
1011  * @formats: An array containing @n_formats @GstFormat values.
1012  *
1013  * Set the formats query result fields in @query. The number of formats passed
1014  * in the @formats array must be equal to @n_formats.
1015  *
1016  * Since: 0.10.4
1017  */
1018 void
1019 gst_query_set_formatsv (GstQuery * query, gint n_formats, GstFormat * formats)
1020 {
1021   GValue list = { 0, };
1022   GstStructure *structure;
1023   gint i;
1024
1025   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_FORMATS);
1026
1027   g_value_init (&list, GST_TYPE_LIST);
1028   for (i = 0; i < n_formats; i++) {
1029     gst_query_list_add_format (&list, formats[i]);
1030   }
1031   structure = gst_query_get_structure (query);
1032   gst_structure_set_value (structure, "formats", &list);
1033
1034   g_value_unset (&list);
1035 }
1036
1037 /**
1038  * gst_query_parse_formats_length:
1039  * @query: a #GstQuery
1040  * @n_formats: the number of formats in this query.
1041  *
1042  * Parse the number of formats in the formats @query. 
1043  *
1044  * Since: 0.10.4
1045  */
1046 void
1047 gst_query_parse_formats_length (GstQuery * query, guint * n_formats)
1048 {
1049   GstStructure *structure;
1050
1051   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_FORMATS);
1052
1053   if (n_formats) {
1054     const GValue *list;
1055
1056     structure = gst_query_get_structure (query);
1057     list = gst_structure_get_value (structure, "formats");
1058     if (list == NULL)
1059       *n_formats = 0;
1060     else
1061       *n_formats = gst_value_list_get_size (list);
1062   }
1063 }
1064
1065 /**
1066  * gst_query_parse_formats_nth:
1067  * @query: a #GstQuery
1068  * @nth: the nth format to retrieve.
1069  * @format: a pointer to store the nth format
1070  *
1071  * Parse the format query and retrieve the @nth format from it into 
1072  * @format. If the list contains less elements than @nth, @format will be
1073  * set to GST_FORMAT_UNDEFINED.
1074  *
1075  * Since: 0.10.4
1076  */
1077 void
1078 gst_query_parse_formats_nth (GstQuery * query, guint nth, GstFormat * format)
1079 {
1080   GstStructure *structure;
1081
1082   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_FORMATS);
1083
1084   if (format) {
1085     const GValue *list;
1086
1087     structure = gst_query_get_structure (query);
1088     list = gst_structure_get_value (structure, "formats");
1089     if (list == NULL) {
1090       *format = GST_FORMAT_UNDEFINED;
1091     } else {
1092       if (nth < gst_value_list_get_size (list)) {
1093         *format = g_value_get_enum (gst_value_list_get_value (list, nth));
1094       } else
1095         *format = GST_FORMAT_UNDEFINED;
1096     }
1097   }
1098 }