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