Reworked the capsnegotiation function audiosink now uses capsnego to set its paramete...
[platform/upstream/gstreamer.git] / gst / gstcaps.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstcaps.c: Element capabilities subsystem
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 //#define GST_DEBUG_ENABLED
24 #include "gst_private.h"
25
26 #include "gstcaps.h"
27 #include "gsttype.h"
28
29 #include "gstpropsprivate.h"
30
31
32 void
33 _gst_caps_initialize (void)
34 {
35 }
36
37 static guint16
38 get_type_for_mime (const gchar *mime)
39 {
40   guint16 typeid;
41
42   typeid = gst_type_find_by_mime (mime);
43   if (typeid == 0) {
44      GstTypeFactory factory; // = g_new0 (GstTypeFactory, 1);
45
46      factory.mime = g_strdup (mime);
47      factory.exts = NULL;
48      factory.typefindfunc = NULL;
49
50      typeid = gst_type_register (&factory);
51   }
52   return typeid;
53 }
54
55 /**
56  * gst_caps_new:
57  * @name: the name of this capability
58  * @mime: the mime type to attach to the capability
59  *
60  * Create a new capability with the given mime type.
61  *
62  * Returns: a new capability
63  */
64 GstCaps*
65 gst_caps_new (const gchar *name, const gchar *mime)
66 {
67   GstCaps *caps;
68
69   g_return_val_if_fail (mime != NULL, NULL);
70
71   caps = g_new0 (GstCaps, 1);
72   caps->name = g_strdup (name);
73   caps->id = get_type_for_mime (mime);
74   caps->properties = NULL;
75   caps->next = NULL;
76
77   return caps;
78 }
79
80 /**
81  * gst_caps_new_with_props:
82  * @name: the name of this capability
83  * @mime: the mime type to attach to the capability
84  * @props: the properties for this capability
85  *
86  * Create a new capability with the given mime type and the given properties.
87  *
88  * Returns: a new capability
89  */
90 GstCaps*
91 gst_caps_new_with_props (const gchar *name, const gchar *mime, GstProps *props)
92 {
93   GstCaps *caps;
94
95   caps = gst_caps_new (name, mime);
96   caps->properties = props;
97
98   return caps;
99 }
100
101 /**
102  * gst_caps_register:
103  * @factory: the factory to register
104  *
105  * Register the factory.
106  *
107  * Returns: the registered capability
108  */
109 GstCaps*
110 gst_caps_register (GstCapsFactory *factory)
111 {
112   guint dummy;
113
114   return gst_caps_register_count (factory, &dummy);
115 }
116
117 /**
118  * gst_caps_register_count:
119  * @factory: the factory to register
120  * @counter: count how many entries were consumed
121  *
122  * Register the factory.
123  *
124  * Returns: the registered capability
125  */
126 GstCaps*
127 gst_caps_register_count (GstCapsFactory *factory, guint *counter)
128 {
129   GstCapsFactoryEntry tag;
130   gint i = 0;
131   guint16 typeid;
132   gchar *name;
133   GstCaps *caps;
134
135   g_return_val_if_fail (factory != NULL, NULL);
136
137   tag = (*factory)[i++];
138   g_return_val_if_fail (tag != NULL, NULL);
139
140   name = tag;
141
142   tag = (*factory)[i++];
143   g_return_val_if_fail (tag != NULL, NULL);
144
145   typeid = get_type_for_mime ((gchar *)tag);
146
147   caps = g_new0 (GstCaps, 1);
148   g_return_val_if_fail (caps != NULL, NULL);
149
150   caps->name = g_strdup (name);
151   caps->id = typeid;
152   caps->properties = gst_props_register_count (&(*factory)[i], counter);
153
154   *counter += 2;
155
156   return caps;
157 }
158
159 /**
160  * gst_caps_get_name:
161  * @caps: the caps to get the name from
162  *
163  * Get the name of a GstCaps structure.
164  *
165  * Returns: the name of the caps
166  */
167 const gchar*
168 gst_caps_get_name (GstCaps *caps)
169 {
170   g_return_val_if_fail (caps != NULL, NULL);
171
172   return (const gchar *)caps->name;
173 }
174
175 /**
176  * gst_caps_set_name:
177  * @caps: the caps to set the name to
178  * @name: the name to set
179  *
180  * Set the name of a caps.
181  */
182 void
183 gst_caps_set_name (GstCaps *caps, const gchar *name)
184 {
185   g_return_if_fail (caps != NULL);
186
187   if (caps->name)
188     g_free (caps->name);
189
190   caps->name = g_strdup (name);
191 }
192
193 /**
194  * gst_caps_get_mime:
195  * @caps: the caps to get the mime type from
196  *
197  * Get the mime type of the caps as a string.
198  *
199  * Returns: the mime type of the caps
200  */
201 const gchar*
202 gst_caps_get_mime (GstCaps *caps)
203 {
204   GstType *type;
205
206   g_return_val_if_fail (caps != NULL, NULL);
207
208   type = gst_type_find_by_id (caps->id);
209
210   if (type)
211     return type->mime;
212   else
213     return "unknown/unknown";
214 }
215
216 /**
217  * gst_caps_set_mime:
218  * @caps: the caps to set the mime type to
219  * @mime: the mime type to attach to the caps
220  *
221  * Set the mime type of the caps as a string.
222  */
223 void
224 gst_caps_set_mime (GstCaps *caps, const gchar *mime)
225 {
226   g_return_if_fail (caps != NULL);
227   g_return_if_fail (mime != NULL);
228
229   caps->id = get_type_for_mime (mime);
230 }
231
232 /**
233  * gst_caps_get_type_id:
234  * @caps: the caps to get the type id from
235  *
236  * Get the type id of the caps.
237  *
238  * Returns: the type id of the caps
239  */
240 guint16
241 gst_caps_get_type_id (GstCaps *caps)
242 {
243   g_return_val_if_fail (caps != NULL, 0);
244
245   return caps->id;
246 }
247
248 /**
249  * gst_caps_set_type_id:
250  * @caps: the caps to set the type id to
251  * @typeid: the type id to set
252  *
253  * Set the type id of the caps.
254  */
255 void
256 gst_caps_set_type_id (GstCaps *caps, guint16 type_id)
257 {
258   g_return_if_fail (caps != NULL);
259
260   caps->id = type_id;
261 }
262
263 /**
264  * gst_caps_set_props:
265  * @caps: the caps to attach the properties to
266  * @props: the properties to attach
267  *
268  * Set the properties to the given caps.
269  *
270  * Returns: the new caps structure
271  */
272 GstCaps*
273 gst_caps_set_props (GstCaps *caps, GstProps *props)
274 {
275   g_return_val_if_fail (caps != NULL, caps);
276   g_return_val_if_fail (props != NULL, caps);
277   g_return_val_if_fail (caps->properties == NULL, caps);
278
279   caps->properties = props;
280
281   return caps;
282 }
283
284 /**
285  * gst_caps_get_props:
286  * @caps: the caps to get the properties from
287  *
288  * Get the properties of the given caps.
289  *
290  * Returns: the properties of the caps
291  */
292 GstProps*
293 gst_caps_get_props (GstCaps *caps)
294 {
295   g_return_val_if_fail (caps != NULL, NULL);
296
297   return caps->properties;
298 }
299
300 /**
301  * gst_caps_append:
302  * @caps: a capabilty
303  * @capstoadd: the capability to append
304  *
305  * Appends a capability to the existing capability.
306  *
307  * Returns: the new capability
308  */
309 GstCaps*
310 gst_caps_append (GstCaps *caps, GstCaps *capstoadd)
311 {
312   GstCaps *orig = caps;
313
314   if (caps == NULL)
315     return capstoadd;
316   
317   while (caps->next) {
318     caps = caps->next;
319   }
320   caps->next = capstoadd;
321
322   return orig;
323 }
324
325 /**
326  * gst_caps_prepend:
327  * @caps: a capabilty
328  * @capstoadd: a capabilty to prepend
329  *
330  * prepend the capability to the list of capabilities
331  *
332  * Returns: the new capability
333  */
334 GstCaps*
335 gst_caps_prepend (GstCaps *caps, GstCaps *capstoadd)
336 {
337   GstCaps *orig = capstoadd;
338   
339   if (capstoadd == NULL)
340     return caps;
341
342   while (capstoadd->next) {
343     capstoadd = capstoadd->next;
344   }
345   capstoadd->next = caps;
346
347   return orig;
348 }
349
350 GstCaps*
351 gst_caps_get_by_name (GstCaps *caps, const gchar *name)
352 {
353   g_return_val_if_fail (caps != NULL, NULL);
354   g_return_val_if_fail (name != NULL, NULL);
355    
356   while (caps) {
357     if (!strcmp (caps->name, name)) 
358       return caps;
359     caps = caps->next;
360   }
361
362   return NULL;
363 }
364                                                                                                                    
365 static gboolean
366 gst_caps_check_compatibility_func (GstCaps *fromcaps, GstCaps *tocaps)
367 {
368   if (fromcaps->id != tocaps->id) {
369     GST_DEBUG (0,"gstcaps: mime types differ (%d to %d)\n",
370                fromcaps->id, tocaps->id);
371     return FALSE;
372   }
373
374   if (tocaps->properties) {
375     if (fromcaps->properties) {
376       return gst_props_check_compatibility (fromcaps->properties, tocaps->properties);
377     }
378     else {
379       GST_DEBUG (0,"gstcaps: no source caps\n");
380       return FALSE;
381     }
382   }
383   else {
384     // assume it accepts everything
385     GST_DEBUG (0,"gstcaps: no caps\n");
386     return TRUE;
387   }
388 }
389
390 /**
391  * gst_caps_list_check_compatibility:
392  * @fromcaps: a capabilty
393  * @tocaps: a capabilty
394  *
395  * Checks whether two capability lists are compatible.
396  *
397  * Returns: TRUE if compatible, FALSE otherwise
398  */
399 gboolean
400 gst_caps_check_compatibility (GstCaps *fromcaps, GstCaps *tocaps)
401 {
402   if (fromcaps == NULL) {
403     if (tocaps == NULL) {
404       GST_DEBUG (0,"gstcaps: no caps\n");
405       return TRUE;
406     }
407     else {
408       GST_DEBUG (0,"gstcaps: no src but destination caps\n");
409       return FALSE;
410     }
411   }
412   else {
413     if (tocaps == NULL) {
414       GST_DEBUG (0,"gstcaps: src caps and no dest caps\n");
415       return TRUE;
416     }
417   }
418
419   while (fromcaps) {
420     GstCaps *destcaps = tocaps;
421
422     while (destcaps) {
423       if (gst_caps_check_compatibility_func (fromcaps, destcaps))
424         return TRUE;
425
426       destcaps =  destcaps->next;
427     }
428     fromcaps =  fromcaps->next;
429   }
430   return FALSE;
431 }
432
433 /**
434  * gst_caps_save_thyself:
435  * @caps: a capabilty to save
436  * @parent: the parent XML node pointer
437  *
438  * Save the capability into an XML representation.
439  *
440  * Returns: a new XML node pointer
441  */
442 xmlNodePtr
443 gst_caps_save_thyself (GstCaps *caps, xmlNodePtr parent)
444 {
445   xmlNodePtr subtree;
446   xmlNodePtr subsubtree;
447
448   while (caps) {
449     subtree = xmlNewChild (parent, NULL, "capscomp", NULL);
450
451     xmlNewChild (subtree, NULL, "name", caps->name);
452     xmlNewChild (subtree, NULL, "type", gst_type_find_by_id (caps->id)->mime);
453     if (caps->properties) {
454       subsubtree = xmlNewChild (subtree, NULL, "properties", NULL);
455
456       gst_props_save_thyself (caps->properties, subsubtree);
457     }
458
459     caps = caps->next;
460   }
461
462   return parent;
463 }
464
465 /**
466  * gst_caps_load_thyself:
467  * @parent: the parent XML node pointer
468  *
469  * Load a new caps from the XML representation.
470  *
471  * Returns: a new capability
472  */
473 GstCaps*
474 gst_caps_load_thyself (xmlNodePtr parent)
475 {
476   GstCaps *result = NULL;
477   xmlNodePtr field = parent->xmlChildrenNode;
478
479   while (field) {
480     if (!strcmp (field->name, "capscomp")) {
481       xmlNodePtr subfield = field->xmlChildrenNode;
482       GstCaps *caps = g_new0 (GstCaps, 1);
483       gchar *content;
484         
485       while (subfield) {
486         if (!strcmp (subfield->name, "name")) {
487           caps->name = xmlNodeGetContent (subfield);
488         }
489         if (!strcmp (subfield->name, "type")) {
490           content = xmlNodeGetContent (subfield);
491           caps->id = get_type_for_mime (content);
492           g_free (content);
493         }
494         else if (!strcmp (subfield->name, "properties")) {
495           caps->properties = gst_props_load_thyself (subfield);
496         }
497         
498         subfield = subfield->next;
499       }
500       result = gst_caps_append (result, caps);
501     }
502     field = field->next;
503   }
504
505   return result;
506 }
507
508
509