gst/gst.c (G_OPTION_FLAG_NO_ARG): Apparently GLib 2.8 requires this flag, but it...
[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
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  * SECTION:gstquery
25  * @short_description: Dynamically register new query types and parse results
26  * @see_also: #GstPad, #GstElement
27  *
28  * GstQuery functions are used to register a new query types to the gstreamer
29  * core. 
30  * Query types can be used to perform queries on pads and elements.
31  *
32  * Query answer can be parsed using gst_query_parse_xxx() helpers.
33  */
34 #include <string.h>
35
36 #include "gst_private.h"
37 #include "gstquery.h"
38 #include "gstvalue.h"
39 #include "gstenumtypes.h"
40
41 GST_DEBUG_CATEGORY_STATIC (gst_query_debug);
42 #define GST_CAT_DEFAULT gst_query_debug
43
44 static void gst_query_init (GTypeInstance * instance, gpointer g_class);
45 static void gst_query_class_init (gpointer g_class, gpointer class_data);
46 static void gst_query_finalize (GstQuery * query);
47 static GstQuery *_gst_query_copy (GstQuery * query);
48
49
50 static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
51 static GList *_gst_queries = NULL;
52 static GHashTable *_nick_to_query = NULL;
53 static GHashTable *_query_type_to_nick = NULL;
54 static guint32 _n_values = 1;   /* we start from 1 because 0 reserved for NONE */
55
56 static GstQueryTypeDefinition standard_definitions[] = {
57   {GST_QUERY_POSITION, "position", "Current position and total duration"},
58   {GST_QUERY_LATENCY, "latency", "Latency"},
59   {GST_QUERY_JITTER, "jitter", "Jitter"},
60   {GST_QUERY_RATE, "rate", "Configured rate 1000000 = 1"},
61   {GST_QUERY_SEEKING, "seeking", "Seeking capabilities and parameters"},
62   {GST_QUERY_SEGMENT, "segment", "currently configured segment"},
63   {GST_QUERY_CONVERT, "convert", "Converting between formats"},
64   {GST_QUERY_FORMATS, "formats", "Supported formats for conversion"},
65   {0, NULL, NULL}
66 };
67
68 void
69 _gst_query_initialize (void)
70 {
71   GstQueryTypeDefinition *standards = standard_definitions;
72
73   GST_CAT_INFO (GST_CAT_GST_INIT, "init queries");
74
75   GST_DEBUG_CATEGORY_INIT (gst_query_debug, "query", 0, "query system");
76
77   g_static_mutex_lock (&mutex);
78   if (_nick_to_query == NULL) {
79     _nick_to_query = g_hash_table_new (g_str_hash, g_str_equal);
80     _query_type_to_nick = g_hash_table_new (NULL, NULL);
81   }
82
83   while (standards->nick) {
84     g_hash_table_insert (_nick_to_query, standards->nick, standards);
85     g_hash_table_insert (_query_type_to_nick,
86         GINT_TO_POINTER (standards->value), standards);
87
88     _gst_queries = g_list_append (_gst_queries, standards);
89     standards++;
90     _n_values++;
91   }
92   g_static_mutex_unlock (&mutex);
93
94   gst_query_get_type ();
95 }
96
97 GType
98 gst_query_get_type (void)
99 {
100   static GType _gst_query_type;
101
102   if (G_UNLIKELY (_gst_query_type == 0)) {
103     static const GTypeInfo query_info = {
104       sizeof (GstQueryClass),
105       NULL,
106       NULL,
107       gst_query_class_init,
108       NULL,
109       NULL,
110       sizeof (GstQuery),
111       0,
112       gst_query_init,
113       NULL
114     };
115
116     _gst_query_type = g_type_register_static (GST_TYPE_MINI_OBJECT,
117         "GstQuery", &query_info, 0);
118   }
119   return _gst_query_type;
120 }
121
122 static void
123 gst_query_class_init (gpointer g_class, gpointer class_data)
124 {
125   GstQueryClass *query_class = GST_QUERY_CLASS (g_class);
126
127   query_class->mini_object_class.copy =
128       (GstMiniObjectCopyFunction) _gst_query_copy;
129   query_class->mini_object_class.finalize =
130       (GstMiniObjectFinalizeFunction) gst_query_finalize;
131
132 }
133
134 static void
135 gst_query_finalize (GstQuery * query)
136 {
137   g_return_if_fail (query != NULL);
138
139   if (query->structure) {
140     gst_structure_set_parent_refcount (query->structure, NULL);
141     gst_structure_free (query->structure);
142   }
143 }
144
145 static void
146 gst_query_init (GTypeInstance * instance, gpointer g_class)
147 {
148
149 }
150
151 static GstQuery *
152 _gst_query_copy (GstQuery * query)
153 {
154   GstQuery *copy;
155
156   copy = (GstQuery *) gst_mini_object_new (GST_TYPE_QUERY);
157
158   copy->type = query->type;
159
160   if (query->structure) {
161     copy->structure = gst_structure_copy (query->structure);
162     gst_structure_set_parent_refcount (copy->structure,
163         &query->mini_object.refcount);
164   }
165
166   return copy;
167 }
168
169
170
171 /**
172  * gst_query_type_register:
173  * @nick: The nick of the new query
174  * @description: The description of the new query
175  *
176  * Create a new GstQueryType based on the nick or return an
177  * allrady registered query with that nick
178  *
179  * Returns: A new GstQueryType or an already registered query
180  * with the same nick.
181  */
182 GstQueryType
183 gst_query_type_register (const gchar * nick, const gchar * description)
184 {
185   GstQueryTypeDefinition *query;
186   GstQueryType lookup;
187
188   g_return_val_if_fail (nick != NULL, 0);
189   g_return_val_if_fail (description != NULL, 0);
190
191   lookup = gst_query_type_get_by_nick (nick);
192   if (lookup != GST_QUERY_NONE)
193     return lookup;
194
195   query = g_new0 (GstQueryTypeDefinition, 1);
196   query->value = _n_values;
197   query->nick = g_strdup (nick);
198   query->description = g_strdup (description);
199
200   g_static_mutex_lock (&mutex);
201   g_hash_table_insert (_nick_to_query, query->nick, query);
202   g_hash_table_insert (_query_type_to_nick, GINT_TO_POINTER (query->value),
203       query);
204   _gst_queries = g_list_append (_gst_queries, query);
205   _n_values++;
206   g_static_mutex_unlock (&mutex);
207
208   return query->value;
209 }
210
211 /**
212  * gst_query_type_get_by_nick:
213  * @nick: The nick of the query
214  *
215  * Return the query registered with the given nick. 
216  *
217  * Returns: The query with @nick or GST_QUERY_NONE
218  * if the query was not registered.
219  */
220 GstQueryType
221 gst_query_type_get_by_nick (const gchar * nick)
222 {
223   GstQueryTypeDefinition *query;
224
225   g_return_val_if_fail (nick != NULL, 0);
226
227   g_static_mutex_lock (&mutex);
228   query = g_hash_table_lookup (_nick_to_query, nick);
229   g_static_mutex_unlock (&mutex);
230
231   if (query != NULL)
232     return query->value;
233   else
234     return GST_QUERY_NONE;
235 }
236
237 /**
238  * gst_query_types_contains:
239  * @types: The query array to search
240  * @type: the querytype to find
241  *
242  * See if the given query is inside the query array.
243  *
244  * Returns: TRUE if the query is found inside the array
245  */
246 gboolean
247 gst_query_types_contains (const GstQueryType * types, GstQueryType type)
248 {
249   if (!types)
250     return FALSE;
251
252   while (*types) {
253     if (*types == type)
254       return TRUE;
255
256     types++;
257   }
258   return FALSE;
259 }
260
261
262 /**
263  * gst_query_type_get_details:
264  * @type: The query to get details of
265  *
266  * Get details about the given query.
267  *
268  * Returns: The #GstQueryTypeDefinition for @query or NULL on failure.
269  */
270 const GstQueryTypeDefinition *
271 gst_query_type_get_details (GstQueryType type)
272 {
273   const GstQueryTypeDefinition *result;
274
275   g_static_mutex_lock (&mutex);
276   result = g_hash_table_lookup (_query_type_to_nick, GINT_TO_POINTER (type));
277   g_static_mutex_unlock (&mutex);
278
279   return result;
280 }
281
282 /**
283  * gst_query_type_iterate_definitions:
284  *
285  * Get an Iterator of all the registered query types. The querytype
286  * definition is read only.
287  *
288  * Returns: A #GstIterator of #GstQueryTypeDefinition.
289  */
290 GstIterator *
291 gst_query_type_iterate_definitions (void)
292 {
293   GstIterator *result;
294
295   g_static_mutex_lock (&mutex);
296   /* FIXME: register a boxed type for GstQueryTypeDefinition */
297   result = gst_iterator_new_list (G_TYPE_POINTER,
298       g_static_mutex_get_mutex (&mutex), &_n_values, &_gst_queries,
299       NULL, NULL, NULL);
300   g_static_mutex_unlock (&mutex);
301
302   return result;
303 }
304
305 static GstQuery *
306 gst_query_new (GstQueryType type, GstStructure * structure)
307 {
308   GstQuery *query;
309
310   query = (GstQuery *) gst_mini_object_new (GST_TYPE_QUERY);
311
312   GST_DEBUG ("creating new query %p %d", query, type);
313
314   query->type = type;
315
316   if (structure) {
317     query->structure = structure;
318     gst_structure_set_parent_refcount (query->structure,
319         &query->mini_object.refcount);
320   } else {
321     query->structure = NULL;
322   }
323
324   return query;
325 }
326
327 /**
328  * gst_query_new_position:
329  * @format: the default #GstFormat for the new query
330  *
331  * Constructs a new query stream position query object. Use gst_query_unref()
332  * when done with it.
333  *
334  * Returns: A new #GstQuery
335  */
336 GstQuery *
337 gst_query_new_position (GstFormat format)
338 {
339   GstQuery *query;
340   GstStructure *structure;
341
342   structure = gst_structure_new ("GstQueryPosition",
343       "format", GST_TYPE_FORMAT, format,
344       "cur", G_TYPE_INT64, (gint64) - 1,
345       "end", G_TYPE_INT64, (gint64) - 1, NULL);
346   query = gst_query_new (GST_QUERY_POSITION, structure);
347
348   return query;
349 }
350
351 /**
352  * gst_query_set_position:
353  * @query: the query to fill in
354  * @format: the requested #GstFormat
355  * @cur: the current position
356  * @end: the end position
357  *
358  * Answer a position query by setting the requested values.
359  */
360 void
361 gst_query_set_position (GstQuery * query, GstFormat format,
362     gint64 cur, gint64 end)
363 {
364   GstStructure *structure;
365
366   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_POSITION);
367
368   structure = gst_query_get_structure (query);
369   gst_structure_set (structure,
370       "format", GST_TYPE_FORMAT, format,
371       "cur", G_TYPE_INT64, cur, "end", G_TYPE_INT64, end, NULL);
372 }
373
374 /**
375  * gst_query_parse_position:
376  * @query: the query to parse
377  * @format: the storage for the #GstFormat of the position values
378  * @cur: the storage for the current position
379  * @end: the storage for the end position
380  *
381  * Parse a position query answer.
382  */
383 void
384 gst_query_parse_position (GstQuery * query, GstFormat * format,
385     gint64 * cur, gint64 * end)
386 {
387   GstStructure *structure;
388
389   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_POSITION);
390
391   structure = gst_query_get_structure (query);
392   if (format)
393     *format = g_value_get_enum (gst_structure_get_value (structure, "format"));
394   if (cur)
395     *cur = g_value_get_int64 (gst_structure_get_value (structure, "cur"));
396   if (end)
397     *end = g_value_get_int64 (gst_structure_get_value (structure, "end"));
398 }
399
400 /**
401  * gst_query_new_convert:
402  * @src_fmt: the source #GstFormat for the new query
403  * @value: the value to convert
404  * @dest_fmt: the target #GstFormat
405  *
406  * Constructs a new query convert object. Use gst_query_unref()
407  * when done with it.
408  *
409  * Returns: A new #GstQuery
410  */
411 GstQuery *
412 gst_query_new_convert (GstFormat src_fmt, gint64 value, GstFormat dest_fmt)
413 {
414   GstQuery *query;
415   GstStructure *structure;
416
417   g_return_val_if_fail (value >= 0, NULL);
418
419   structure = gst_structure_new ("GstQueryConvert",
420       "src_format", GST_TYPE_FORMAT, src_fmt,
421       "src_value", G_TYPE_INT64, value,
422       "dest_format", GST_TYPE_FORMAT, dest_fmt,
423       "dest_value", G_TYPE_INT64, (gint64) - 1, NULL);
424   query = gst_query_new (GST_QUERY_CONVERT, structure);
425
426   return query;
427 }
428
429 /**
430  * gst_query_set_convert:
431  * @query: the query to fill in
432  * @src_format: the source #GstFormat
433  * @src_value: the source value
434  * @dest_format: the destination #GstFormat
435  * @dest_value: the destination value
436  *
437  * Answer a convert query by setting the requested values.
438  */
439 void
440 gst_query_set_convert (GstQuery * query, GstFormat src_format, gint64 src_value,
441     GstFormat dest_format, gint64 dest_value)
442 {
443   GstStructure *structure;
444
445   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_CONVERT);
446
447   structure = gst_query_get_structure (query);
448   gst_structure_set (structure,
449       "src_format", GST_TYPE_FORMAT, src_format,
450       "src_value", G_TYPE_INT64, src_value,
451       "dest_format", GST_TYPE_FORMAT, dest_format,
452       "dest_value", G_TYPE_INT64, dest_value, NULL);
453 }
454
455 /**
456  * gst_query_parse_convert:
457  * @query: the query to parse
458  * @src_format: the storage for the #GstFormat of the source value
459  * @src_value: the storage for the source value
460  * @dest_format: the storage for the #GstFormat of the destination value
461  * @dest_value: the storage for the destination value
462  *
463  * Parse a convert query answer.
464  */
465 void
466 gst_query_parse_convert (GstQuery * query, GstFormat * src_format,
467     gint64 * src_value, GstFormat * dest_format, gint64 * dest_value)
468 {
469   GstStructure *structure;
470
471   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_CONVERT);
472
473   structure = gst_query_get_structure (query);
474   if (src_format)
475     *src_format =
476         g_value_get_enum (gst_structure_get_value (structure, "src_format"));
477   if (src_value)
478     *src_value =
479         g_value_get_int64 (gst_structure_get_value (structure, "src_value"));
480   if (dest_format)
481     *dest_format =
482         g_value_get_enum (gst_structure_get_value (structure, "dest_format"));
483   if (dest_value)
484     *dest_value =
485         g_value_get_int64 (gst_structure_get_value (structure, "dest_value"));
486 }
487
488 /**
489  * gst_query_new_segment:
490  * @format: the #GstFormat for the new query
491  *
492  * Constructs a new query segment object. Use gst_query_unref()
493  * when done with it.
494  *
495  * Returns: A new #GstQuery
496  */
497 GstQuery *
498 gst_query_new_segment (GstFormat format)
499 {
500   GstQuery *query;
501   GstStructure *structure;
502
503   structure = gst_structure_new ("GstQuerySegment",
504       "format", GST_TYPE_FORMAT, format, NULL);
505   query = gst_query_new (GST_QUERY_SEGMENT, structure);
506
507   return query;
508 }
509
510 /**
511  * gst_query_set_segment:
512  * @query: the query to fill in
513  * @rate: the rate of the segment
514  * @format: the #GstFormat of the segment values
515  * @start_value: the start value
516  * @stop_value: the stop value
517  * @base: the base value
518  *
519  * Answer a segment query by setting the requested values.
520  */
521 void
522 gst_query_set_segment (GstQuery * query, gdouble rate, GstFormat format,
523     gint64 start_value, gint64 stop_value, gint64 base)
524 {
525   GstStructure *structure;
526
527   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_SEGMENT);
528
529   structure = gst_query_get_structure (query);
530   gst_structure_set (structure,
531       "rate", G_TYPE_DOUBLE, rate,
532       "format", GST_TYPE_FORMAT, format,
533       "start_value", G_TYPE_INT64, start_value,
534       "stop_value", G_TYPE_INT64, stop_value, "base", G_TYPE_INT64, base, NULL);
535 }
536
537 /**
538  * gst_query_parse_segment:
539  * @query: the query to parse
540  * @rate: the storage for the rate of the segment
541  * @format: the storage for the #GstFormat of the values
542  * @start_value: the storage for the start value
543  * @stop_value: the storage for the stop value
544  * @base: the storage for the base value
545  *
546  * Parse a segment query answer.
547  */
548 void
549 gst_query_parse_segment (GstQuery * query, gdouble * rate, GstFormat * format,
550     gint64 * start_value, gint64 * stop_value, gint64 * base)
551 {
552   GstStructure *structure;
553
554   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_SEGMENT);
555
556   structure = gst_query_get_structure (query);
557   if (rate)
558     *rate = g_value_get_double (gst_structure_get_value (structure, "rate"));
559   if (format)
560     *format = g_value_get_enum (gst_structure_get_value (structure, "format"));
561   if (start_value)
562     *start_value =
563         g_value_get_int64 (gst_structure_get_value (structure, "start_value"));
564   if (stop_value)
565     *stop_value =
566         g_value_get_int64 (gst_structure_get_value (structure, "stop_value"));
567   if (base)
568     *base = g_value_get_int64 (gst_structure_get_value (structure, "base"));
569 }
570
571 /**
572  * gst_query_new_application:
573  * @type: the query type
574  * @structure: a structure for the query
575  *
576  * Constructs a new custom application query object. Use gst_query_unref()
577  * when done with it.
578  *
579  * Returns: A new #GstQuery
580  */
581 GstQuery *
582 gst_query_new_application (GstQueryType type, GstStructure * structure)
583 {
584   g_return_val_if_fail (gst_query_type_get_details (type) != NULL, NULL);
585   g_return_val_if_fail (structure != NULL, NULL);
586
587   return gst_query_new (type, structure);
588 }
589
590 /**
591  * gst_query_get_structure:
592  * @query: the query to parse
593  *
594  * Get the structure of a query.
595  *
596  * Returns: The #GstStructure of the query. The structure is still owned
597  * by the query and will therefore be freed when the query is unreffed.
598  */
599 GstStructure *
600 gst_query_get_structure (GstQuery * query)
601 {
602   g_return_val_if_fail (GST_IS_QUERY (query), NULL);
603
604   return query->structure;
605 }
606
607 void
608 gst_query_set_seeking (GstQuery * query, GstFormat format,
609     gboolean seekable, gint64 segment_start, gint64 segment_end)
610 {
611   GstStructure *structure;
612
613   g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_SEEKING);
614
615   structure = gst_query_get_structure (query);
616   gst_structure_set (structure,
617       "format", GST_TYPE_FORMAT, format,
618       "seekable", G_TYPE_BOOLEAN, seekable,
619       "segment-start", G_TYPE_INT64, segment_start,
620       "segment-end", G_TYPE_INT64, segment_end, NULL);
621 }
622
623 void
624 gst_query_set_formats (GstQuery * query, gint n_formats, ...)
625 {
626   va_list ap;
627   GValue list = { 0, };
628   GValue item = { 0, };
629   GstStructure *structure;
630   gint i;
631
632   g_value_init (&list, GST_TYPE_LIST);
633
634   va_start (ap, n_formats);
635
636   for (i = 0; i < n_formats; i++) {
637     g_value_init (&item, GST_TYPE_FORMAT);
638     g_value_set_enum (&item, va_arg (ap, GstFormat));
639     gst_value_list_append_value (&list, &item);
640     g_value_unset (&item);
641   }
642
643   va_end (ap);
644
645   structure = gst_query_get_structure (query);
646   gst_structure_set_value (structure, "formats", &list);
647 }