Added 1337 macros to create padtemplates and capstemplates.
[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 static GMemChunk *_gst_caps_chunk;
32 static GMutex *_gst_caps_chunk_lock;
33
34 void
35 _gst_caps_initialize (void)
36 {
37   _gst_caps_chunk = g_mem_chunk_new ("GstCaps",
38                   sizeof (GstCaps), sizeof (GstCaps) * 256,
39                   G_ALLOC_AND_FREE);
40   _gst_caps_chunk_lock = g_mutex_new ();
41 }
42
43 static guint16
44 get_type_for_mime (const gchar *mime)
45 {
46   guint16 typeid;
47
48   typeid = gst_type_find_by_mime (mime);
49   if (typeid == 0) {
50      GstTypeFactory factory; // = g_new0 (GstTypeFactory, 1);
51
52      factory.mime = g_strdup (mime);
53      factory.exts = NULL;
54      factory.typefindfunc = NULL;
55
56      typeid = gst_type_register (&factory);
57   }
58   return typeid;
59 }
60
61 /**
62  * gst_caps_new:
63  * @name: the name of this capability
64  * @mime: the mime type to attach to the capability
65  * @props: the properties to add to this capability
66  *
67  * Create a new capability with the given mime typei and properties.
68  *
69  * Returns: a new capability
70  */
71 GstCaps*
72 gst_caps_new (const gchar *name, const gchar *mime, GstProps *props)
73 {
74   GstCaps *caps;
75
76   g_return_val_if_fail (mime != NULL, NULL);
77
78   g_mutex_lock (_gst_caps_chunk_lock);
79   caps = g_mem_chunk_alloc (_gst_caps_chunk);
80   g_mutex_unlock (_gst_caps_chunk_lock);
81
82   caps->name = g_strdup (name);
83   caps->id = get_type_for_mime (mime);
84   caps->properties = props;
85   caps->next = NULL;
86   caps->refcount = 1;
87   caps->lock = g_mutex_new ();
88
89   return caps;
90 }
91
92 /**
93  * gst_caps_destroy:
94  * @caps: the caps to destroy
95  *
96  * Frees the memory used by this caps structure and all
97  * the chained caps and properties.
98  */
99 void
100 gst_caps_destroy (GstCaps *caps)
101 {
102   GstCaps *next;
103
104   g_return_if_fail (caps != NULL);
105
106   GST_CAPS_LOCK (caps);
107   next = caps->next;
108   g_free (caps->name);
109   g_free (caps);
110   GST_CAPS_UNLOCK (caps);
111
112   if (next) 
113     gst_caps_unref (next);
114 }
115
116 /**
117  * gst_caps_unref:
118  * @caps: the caps to unref
119  *
120  * Decrease the refcount of this caps structure, 
121  * destroying it when the refcount is 0
122  *
123  * Retruns: caps or NULL if the refcount reached 0
124  */
125 GstCaps*
126 gst_caps_unref (GstCaps *caps)
127 {
128   gboolean zero;
129   GstCaps **next;
130
131   g_return_val_if_fail (caps != NULL, NULL);
132   g_return_val_if_fail (caps->refcount > 0, NULL);
133
134   GST_CAPS_LOCK (caps);
135   caps->refcount--;
136   zero = (caps->refcount == 0);
137   next = &caps->next;
138   GST_CAPS_UNLOCK (caps);
139
140   if (*next)
141     *next = gst_caps_unref (*next);
142
143   if (zero) {
144     gst_caps_destroy (caps);
145     caps = NULL;
146   }
147   return caps;
148 }
149
150 /**
151  * gst_caps_ref:
152  * @caps: the caps to ref
153  *
154  * Increase the refcount of this caps structure
155  *
156  * Returnns: the caps with the refcount incremented
157  */
158 GstCaps*
159 gst_caps_ref (GstCaps *caps)
160 {
161   g_return_val_if_fail (caps != NULL, NULL);
162
163   GST_CAPS_LOCK (caps);
164   caps->refcount++;
165   GST_CAPS_UNLOCK (caps);
166
167   return caps;
168 }
169
170 /**
171  * gst_caps_copy:
172  * @caps: the caps to copy
173  *
174  * Copies the caps.
175  *
176  * Returns: a copy of the GstCaps structure.
177  */
178 GstCaps*
179 gst_caps_copy (GstCaps *caps)
180 {
181   GstCaps *new = caps;;
182
183   g_return_val_if_fail (caps != NULL, NULL);
184
185   GST_CAPS_LOCK (caps);
186   new = gst_caps_new (
187                   caps->name,
188                   (gst_type_find_by_id (caps->id))->mime,
189                   gst_props_copy (caps->properties));
190   GST_CAPS_UNLOCK (caps);
191
192   return new;
193 }
194
195 /**
196  * gst_caps_copy_on_write:
197  * @caps: the caps to copy
198  *
199  * Copies the caps if the refcount is greater than 1
200  *
201  * Returns: a pointer to a GstCaps strcuture that can
202  * be safely written to
203  */
204 GstCaps*
205 gst_caps_copy_on_write (GstCaps *caps)
206 {
207   GstCaps *new = caps;
208   gboolean needcopy;
209
210   g_return_val_if_fail (caps != NULL, NULL);
211
212   GST_CAPS_LOCK (caps);
213   needcopy = (caps->refcount > 1);
214   GST_CAPS_UNLOCK (caps);
215
216   if (needcopy) {
217     new = gst_caps_copy (caps);
218     gst_caps_unref (caps);
219   }
220
221   return new;
222 }
223
224 /**
225  * gst_caps_get_name:
226  * @caps: the caps to get the name from
227  *
228  * Get the name of a GstCaps structure.
229  *
230  * Returns: the name of the caps
231  */
232 const gchar*
233 gst_caps_get_name (GstCaps *caps)
234 {
235   g_return_val_if_fail (caps != NULL, NULL);
236
237   return (const gchar *)caps->name;
238 }
239
240 /**
241  * gst_caps_set_name:
242  * @caps: the caps to set the name to
243  * @name: the name to set
244  *
245  * Set the name of a caps.
246  */
247 void
248 gst_caps_set_name (GstCaps *caps, const gchar *name)
249 {
250   g_return_if_fail (caps != NULL);
251
252   if (caps->name)
253     g_free (caps->name);
254
255   caps->name = g_strdup (name);
256 }
257
258 /**
259  * gst_caps_get_mime:
260  * @caps: the caps to get the mime type from
261  *
262  * Get the mime type of the caps as a string.
263  *
264  * Returns: the mime type of the caps
265  */
266 const gchar*
267 gst_caps_get_mime (GstCaps *caps)
268 {
269   GstType *type;
270
271   g_return_val_if_fail (caps != NULL, NULL);
272
273   type = gst_type_find_by_id (caps->id);
274
275   if (type)
276     return type->mime;
277   else
278     return "unknown/unknown";
279 }
280
281 /**
282  * gst_caps_set_mime:
283  * @caps: the caps to set the mime type to
284  * @mime: the mime type to attach to the caps
285  *
286  * Set the mime type of the caps as a string.
287  */
288 void
289 gst_caps_set_mime (GstCaps *caps, const gchar *mime)
290 {
291   g_return_if_fail (caps != NULL);
292   g_return_if_fail (mime != NULL);
293
294   caps->id = get_type_for_mime (mime);
295 }
296
297 /**
298  * gst_caps_get_type_id:
299  * @caps: the caps to get the type id from
300  *
301  * Get the type id of the caps.
302  *
303  * Returns: the type id of the caps
304  */
305 guint16
306 gst_caps_get_type_id (GstCaps *caps)
307 {
308   g_return_val_if_fail (caps != NULL, 0);
309
310   return caps->id;
311 }
312
313 /**
314  * gst_caps_set_type_id:
315  * @caps: the caps to set the type id to
316  * @type_id: the type id to set
317  *
318  * Set the type id of the caps.
319  */
320 void
321 gst_caps_set_type_id (GstCaps *caps, guint16 type_id)
322 {
323   g_return_if_fail (caps != NULL);
324
325   caps->id = type_id;
326 }
327
328 /**
329  * gst_caps_set_props:
330  * @caps: the caps to attach the properties to
331  * @props: the properties to attach
332  *
333  * Set the properties to the given caps.
334  *
335  * Returns: the new caps structure
336  */
337 GstCaps*
338 gst_caps_set_props (GstCaps *caps, GstProps *props)
339 {
340   g_return_val_if_fail (caps != NULL, caps);
341   g_return_val_if_fail (props != NULL, caps);
342   g_return_val_if_fail (caps->properties == NULL, caps);
343
344   caps->properties = props;
345
346   return caps;
347 }
348
349 /**
350  * gst_caps_get_props:
351  * @caps: the caps to get the properties from
352  *
353  * Get the properties of the given caps.
354  *
355  * Returns: the properties of the caps
356  */
357 GstProps*
358 gst_caps_get_props (GstCaps *caps)
359 {
360   g_return_val_if_fail (caps != NULL, NULL);
361
362   return caps->properties;
363 }
364
365 /**
366  * gst_caps_chain:
367  * @caps: a capabilty
368  * @...: more capabilities
369  *
370  * chains the given capabilities
371  *
372  * Returns: the new capability
373  */
374 GstCaps*
375 gst_caps_chain (GstCaps *caps, ...)
376 {
377   GstCaps *orig = caps;
378   va_list var_args;
379
380   va_start (var_args, caps);
381
382   while (caps) {
383     GstCaps *toadd;
384     
385     toadd = va_arg (var_args, GstCaps*);
386     gst_caps_append (caps, toadd);
387     
388     caps = toadd;
389   }
390   va_end (var_args);
391   
392   return orig;
393 }
394
395 /**
396  * gst_caps_append:
397  * @caps: a capabilty
398  * @capstoadd: the capability to append
399  *
400  * Appends a capability to the existing capability.
401  *
402  * Returns: the new capability
403  */
404 GstCaps*
405 gst_caps_append (GstCaps *caps, GstCaps *capstoadd)
406 {
407   GstCaps *orig = caps;
408   
409   g_return_val_if_fail (caps != capstoadd, caps);
410
411   if (caps == NULL)
412     return capstoadd;
413   
414   while (caps->next) {
415     caps = caps->next;
416   }
417   caps->next = capstoadd;
418
419   return orig;
420 }
421
422 /**
423  * gst_caps_prepend:
424  * @caps: a capabilty
425  * @capstoadd: a capabilty to prepend
426  *
427  * prepend the capability to the list of capabilities
428  *
429  * Returns: the new capability
430  */
431 GstCaps*
432 gst_caps_prepend (GstCaps *caps, GstCaps *capstoadd)
433 {
434   GstCaps *orig = capstoadd;
435   
436   g_return_val_if_fail (caps != capstoadd, caps);
437
438   if (capstoadd == NULL)
439     return caps;
440
441   while (capstoadd->next) {
442     capstoadd = capstoadd->next;
443   }
444   capstoadd->next = caps;
445
446   return orig;
447 }
448
449 /**
450  * gst_caps_get_by_name:
451  * @caps: a capabilty
452  * @name: the name of the capability to get
453  *
454  * Get the capability with the given name from this
455  * chain of capabilities.
456  *
457  * Returns: the first capability in the chain with the 
458  * given name
459  */
460 GstCaps*
461 gst_caps_get_by_name (GstCaps *caps, const gchar *name)
462 {
463   g_return_val_if_fail (caps != NULL, NULL);
464   g_return_val_if_fail (name != NULL, NULL);
465    
466   while (caps) {
467     if (!strcmp (caps->name, name)) 
468       return caps;
469     caps = caps->next;
470   }
471
472   return NULL;
473 }
474                                                                                                                    
475 static gboolean
476 gst_caps_check_compatibility_func (GstCaps *fromcaps, GstCaps *tocaps)
477 {
478   if (fromcaps->id != tocaps->id) {
479     GST_DEBUG (0,"gstcaps: mime types differ (%s to %s)\n",
480                gst_type_find_by_id (fromcaps->id)->mime, 
481                gst_type_find_by_id (tocaps->id)->mime);
482     return FALSE;
483   }
484
485   if (tocaps->properties) {
486     if (fromcaps->properties) {
487       return gst_props_check_compatibility (fromcaps->properties, tocaps->properties);
488     }
489     else {
490       GST_DEBUG (0,"gstcaps: no source caps\n");
491       return FALSE;
492     }
493   }
494   else {
495     // assume it accepts everything
496     GST_DEBUG (0,"gstcaps: no caps\n");
497     return TRUE;
498   }
499 }
500
501 /**
502  * gst_caps_check_compatibility:
503  * @fromcaps: a capabilty
504  * @tocaps: a capabilty
505  *
506  * Checks whether two capabilities are compatible.
507  *
508  * Returns: TRUE if compatible, FALSE otherwise
509  */
510 gboolean
511 gst_caps_check_compatibility (GstCaps *fromcaps, GstCaps *tocaps)
512 {
513   if (fromcaps == NULL) {
514     if (tocaps == NULL) {
515       GST_DEBUG (0,"gstcaps: no caps\n");
516       return TRUE;
517     }
518     else {
519       GST_DEBUG (0,"gstcaps: no src but destination caps\n");
520       return FALSE;
521     }
522   }
523   else {
524     if (tocaps == NULL) {
525       GST_DEBUG (0,"gstcaps: src caps and no dest caps\n");
526       return TRUE;
527     }
528   }
529
530   while (fromcaps) {
531     GstCaps *destcaps = tocaps;
532
533     while (destcaps) {
534       if (gst_caps_check_compatibility_func (fromcaps, destcaps))
535         return TRUE;
536
537       destcaps =  destcaps->next;
538     }
539     fromcaps =  fromcaps->next;
540   }
541   return FALSE;
542 }
543
544 /**
545  * gst_caps_save_thyself:
546  * @caps: a capabilty to save
547  * @parent: the parent XML node pointer
548  *
549  * Save the capability into an XML representation.
550  *
551  * Returns: a new XML node pointer
552  */
553 xmlNodePtr
554 gst_caps_save_thyself (GstCaps *caps, xmlNodePtr parent)
555 {
556   xmlNodePtr subtree;
557   xmlNodePtr subsubtree;
558
559   while (caps) {
560     subtree = xmlNewChild (parent, NULL, "capscomp", NULL);
561
562     xmlNewChild (subtree, NULL, "name", caps->name);
563     xmlNewChild (subtree, NULL, "type", gst_type_find_by_id (caps->id)->mime);
564     if (caps->properties) {
565       subsubtree = xmlNewChild (subtree, NULL, "properties", NULL);
566
567       gst_props_save_thyself (caps->properties, subsubtree);
568     }
569
570     caps = caps->next;
571   }
572
573   return parent;
574 }
575
576 /**
577  * gst_caps_load_thyself:
578  * @parent: the parent XML node pointer
579  *
580  * Load a new caps from the XML representation.
581  *
582  * Returns: a new capability
583  */
584 GstCaps*
585 gst_caps_load_thyself (xmlNodePtr parent)
586 {
587   GstCaps *result = NULL;
588   xmlNodePtr field = parent->xmlChildrenNode;
589
590   while (field) {
591     if (!strcmp (field->name, "capscomp")) {
592       xmlNodePtr subfield = field->xmlChildrenNode;
593       GstCaps *caps;
594       gchar *content;
595
596       g_mutex_lock (_gst_caps_chunk_lock);
597       caps = g_mem_chunk_alloc0 (_gst_caps_chunk);
598       g_mutex_unlock (_gst_caps_chunk_lock);
599
600       caps->refcount = 1;
601       caps->lock = g_mutex_new ();
602       caps->next = NULL;
603         
604       while (subfield) {
605         if (!strcmp (subfield->name, "name")) {
606           caps->name = xmlNodeGetContent (subfield);
607         }
608         if (!strcmp (subfield->name, "type")) {
609           content = xmlNodeGetContent (subfield);
610           caps->id = get_type_for_mime (content);
611           g_free (content);
612         }
613         else if (!strcmp (subfield->name, "properties")) {
614           caps->properties = gst_props_load_thyself (subfield);
615         }
616         
617         subfield = subfield->next;
618       }
619       result = gst_caps_append (result, caps);
620     }
621     field = field->next;
622   }
623
624   return result;
625 }
626
627
628