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