Merged the CAPSNEGO1 branch..
[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 == NULL ||
369       tocaps == NULL) 
370     return TRUE;
371         
372   if (fromcaps->id != tocaps->id) {
373     GST_DEBUG (0,"gstcaps: mime types differ (%d to %d)\n",
374                fromcaps->id, tocaps->id);
375     return FALSE;
376   }
377
378   if (tocaps->properties) {
379     if (fromcaps->properties) {
380       return gst_props_check_compatibility (fromcaps->properties, tocaps->properties);
381     }
382     else {
383       GST_DEBUG (0,"gstcaps: no source caps\n");
384       return FALSE;
385     }
386   }
387   else {
388     // assume it accepts everything
389     GST_DEBUG (0,"gstcaps: no caps\n");
390     return TRUE;
391   }
392 }
393
394 /**
395  * gst_caps_list_check_compatibility:
396  * @fromcaps: a capabilty
397  * @tocaps: a capabilty
398  *
399  * Checks whether two capability lists are compatible.
400  *
401  * Returns: TRUE if compatible, FALSE otherwise
402  */
403 gboolean
404 gst_caps_check_compatibility (GstCaps *fromcaps, GstCaps *tocaps)
405 {
406   while (fromcaps) {
407     GstCaps *destcaps = tocaps;
408
409     while (destcaps) {
410       if (gst_caps_check_compatibility_func (fromcaps, destcaps))
411         return TRUE;
412
413       destcaps =  destcaps->next;
414     }
415     fromcaps =  fromcaps->next;
416   }
417   return FALSE;
418 }
419
420 /**
421  * gst_caps_save_thyself:
422  * @caps: a capabilty to save
423  * @parent: the parent XML node pointer
424  *
425  * Save the capability into an XML representation.
426  *
427  * Returns: a new XML node pointer
428  */
429 xmlNodePtr
430 gst_caps_save_thyself (GstCaps *caps, xmlNodePtr parent)
431 {
432   xmlNodePtr subtree;
433   xmlNodePtr subsubtree;
434
435   while (caps) {
436     subtree = xmlNewChild (parent, NULL, "capscomp", NULL);
437
438     xmlNewChild (subtree, NULL, "name", caps->name);
439     xmlNewChild (subtree, NULL, "type", gst_type_find_by_id (caps->id)->mime);
440     if (caps->properties) {
441       subsubtree = xmlNewChild (subtree, NULL, "properties", NULL);
442
443       gst_props_save_thyself (caps->properties, subsubtree);
444     }
445
446     caps = caps->next;
447   }
448
449   return parent;
450 }
451
452 /**
453  * gst_caps_load_thyself:
454  * @parent: the parent XML node pointer
455  *
456  * Load a new caps from the XML representation.
457  *
458  * Returns: a new capability
459  */
460 GstCaps*
461 gst_caps_load_thyself (xmlNodePtr parent)
462 {
463   GstCaps *result = NULL;
464   xmlNodePtr field = parent->xmlChildrenNode;
465
466   while (field) {
467     if (!strcmp (field->name, "capscomp")) {
468       xmlNodePtr subfield = field->xmlChildrenNode;
469       GstCaps *caps = g_new0 (GstCaps, 1);
470       gchar *content;
471         
472       while (subfield) {
473         if (!strcmp (subfield->name, "name")) {
474           caps->name = xmlNodeGetContent (subfield);
475         }
476         if (!strcmp (subfield->name, "type")) {
477           content = xmlNodeGetContent (subfield);
478           caps->id = get_type_for_mime (content);
479           g_free (content);
480         }
481         else if (!strcmp (subfield->name, "properties")) {
482           caps->properties = gst_props_load_thyself (subfield);
483         }
484         
485         subfield = subfield->next;
486       }
487       result = gst_caps_append (result, caps);
488     }
489     field = field->next;
490   }
491
492   return result;
493 }
494
495
496