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