- Added value transform functions for caps and props boxed types
[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 #include "gstlog.h"
29
30 static GMemChunk *_gst_caps_chunk;
31 static GMutex *_gst_caps_chunk_lock;
32
33 GType _gst_caps_type;
34
35 static void
36 transform_func (const GValue *src_value,
37                 GValue *dest_value)
38 {
39   GstCaps *caps = g_value_peek_pointer (src_value);
40   GString *result = g_string_new (""); 
41
42   g_string_append_printf (result, "(GstCaps *) ");
43                   
44   while (caps) {
45     gchar *props;
46     GValue value = { 0, }; /* the important thing is that value.type = 0 */
47     
48     g_string_append_printf (result,
49                   "{ %s; ", gst_caps_get_mime (caps));
50
51     g_value_init (&value, GST_TYPE_PROPS);
52     g_value_set_boxed  (&value, caps->properties);
53     props = g_strdup_value_contents (&value);
54
55     g_string_append (result, props);
56     g_free (props);
57
58     caps = caps->next;
59     g_string_append_printf (result, " }%s", caps?", ":"");
60   }
61   dest_value->data[0].v_pointer = result->str;
62 }
63
64 void
65 _gst_caps_initialize (void)
66 {
67   _gst_caps_chunk = g_mem_chunk_new ("GstCaps",
68                   sizeof (GstCaps), sizeof (GstCaps) * 256,
69                   G_ALLOC_AND_FREE);
70   _gst_caps_chunk_lock = g_mutex_new ();
71
72   _gst_caps_type = g_boxed_type_register_static ("GstCaps",
73                                        (GBoxedCopyFunc) gst_caps_ref,
74                                        (GBoxedFreeFunc) gst_caps_unref);
75
76   g_value_register_transform_func (_gst_caps_type,
77                                    G_TYPE_STRING,
78                                    transform_func);
79 }
80
81 static guint16
82 get_type_for_mime (const gchar *mime)
83 {
84   guint16 typeid;
85
86   typeid = gst_type_find_by_mime (mime);
87   if (typeid == 0) {
88      GstTypeDefinition definition;
89      GstTypeFactory *factory;
90
91      definition.name = "capstype";
92      definition.mime = g_strdup (mime);
93      definition.exts = NULL;
94      definition.typefindfunc = NULL;
95
96      factory = gst_type_factory_new (&definition);
97
98      typeid = gst_type_register (factory);
99   }
100   return typeid;
101 }
102
103 /**
104  * gst_caps_new:
105  * @name: the name of this capability
106  * @mime: the mime type to attach to the capability
107  * @props: the properties to add to this capability
108  *
109  * Create a new capability with the given mime typei and properties.
110  *
111  * Returns: a new capability
112  */
113 GstCaps*
114 gst_caps_new (const gchar *name, const gchar *mime, GstProps *props)
115 {
116   g_return_val_if_fail (mime != NULL, NULL);
117
118   return gst_caps_new_id (name, get_type_for_mime (mime), props);
119 }
120
121 /**
122  * gst_caps_new_id:
123  * @name: the name of this capability
124  * @id: the id of the mime type 
125  * @props: the properties to add to this capability
126  *
127  * Create a new capability with the given mime typeid and properties.
128  *
129  * Returns: a new capability
130  */
131 GstCaps*
132 gst_caps_new_id (const gchar *name, const guint16 id, GstProps *props)
133 {
134   GstCaps *caps;
135
136   g_mutex_lock (_gst_caps_chunk_lock);
137   caps = g_mem_chunk_alloc (_gst_caps_chunk);
138   g_mutex_unlock (_gst_caps_chunk_lock);
139
140   caps->name = g_strdup (name);
141   caps->id = id;
142   caps->properties = props;
143   caps->next = NULL;
144   caps->refcount = 1;
145   if (props)
146     caps->fixed = props->fixed;
147   else
148     caps->fixed = TRUE;
149
150   return caps;
151 }
152
153 /**
154  * gst_caps_destroy:
155  * @caps: the caps to destroy
156  *
157  * Frees the memory used by this caps structure and all
158  * the chained caps and properties.
159  */
160 void
161 gst_caps_destroy (GstCaps *caps)
162 {
163   GstCaps *next;
164
165   if (caps == NULL)
166     return;
167
168   next = caps->next;
169
170   gst_props_unref (caps->properties);
171   g_free (caps->name);
172   g_mutex_lock (_gst_caps_chunk_lock);
173   g_mem_chunk_free (_gst_caps_chunk, caps);
174   g_mutex_unlock (_gst_caps_chunk_lock);
175
176   if (next) 
177     gst_caps_unref (next);
178 }
179
180 /**
181  * gst_caps_debug:
182  * @caps: the caps to print out
183  * @label: a label to put on the printout, or NULL
184  *
185  * Print out the contents of the caps structure. Useful for debugging.
186  */
187 void
188 gst_caps_debug (GstCaps *caps, const gchar *label)
189 {
190   GST_DEBUG_ENTER ("caps debug: %s", label);
191   while (caps) {
192     GST_DEBUG (GST_CAT_CAPS, "caps: %p %s %s (%sfixed)", caps, caps->name, gst_caps_get_mime (caps), 
193                caps->fixed ? "" : "NOT ");
194
195     if (caps->properties) {
196       gst_props_debug (caps->properties);
197     }
198     else {
199       GST_DEBUG (GST_CAT_CAPS, "no properties");
200     }
201
202     caps = caps->next;
203   }
204   GST_DEBUG_LEAVE ("caps debug");
205 }
206
207 /**
208  * gst_caps_unref:
209  * @caps: the caps to unref
210  *
211  * Decrease the refcount of this caps structure, 
212  * destroying it when the refcount is 0
213  *
214  * Returns: caps or NULL if the refcount reached 0
215  */
216 GstCaps*
217 gst_caps_unref (GstCaps *caps)
218 {
219   gboolean zero;
220   GstCaps **next;
221
222   if (caps == NULL)
223     return NULL;
224
225   g_return_val_if_fail (caps->refcount > 0, NULL);
226
227   caps->refcount--;
228   zero = (caps->refcount == 0);
229   next = &caps->next;
230
231   if (*next)
232     *next = gst_caps_unref (*next);
233
234   if (zero) {
235     gst_caps_destroy (caps);
236     caps = NULL;
237   }
238   return caps;
239 }
240
241 /**
242  * gst_caps_ref:
243  * @caps: the caps to ref
244  *
245  * Increase the refcount of this caps structure
246  *
247  * Returns: the caps with the refcount incremented
248  */
249 GstCaps*
250 gst_caps_ref (GstCaps *caps)
251 {
252   g_return_val_if_fail (caps != NULL, NULL);
253
254   caps->refcount++;
255
256   return caps;
257 }
258
259 /**
260  * gst_caps_copy_1:
261  * @caps: the caps to copy
262  *
263  * Copies the caps, not copying any chained caps.
264  *
265  * Returns: a copy of the GstCaps structure.
266  */
267 GstCaps*
268 gst_caps_copy_1 (GstCaps *caps)
269 {
270   GstCaps *newcaps;
271   
272   if (!caps)
273     return NULL;
274
275   newcaps = gst_caps_new_id (
276                   caps->name,
277                   caps->id,
278                   gst_props_copy (caps->properties));
279
280   return newcaps;
281 }
282
283 /**
284  * gst_caps_copy:
285  * @caps: the caps to copy
286  *
287  * Copies the caps.
288  *
289  * Returns: a copy of the GstCaps structure.
290  */
291 GstCaps*
292 gst_caps_copy (GstCaps *caps)
293 {
294   GstCaps *new = NULL, *walk = NULL;
295
296   while (caps) {
297     GstCaps *newcaps;
298
299     newcaps = gst_caps_copy_1 (caps);
300
301     if (new == NULL) {
302       new = walk = newcaps;
303     }
304     else {
305       walk = walk->next = newcaps;
306     }
307     caps = caps->next;
308   }
309
310   return new;
311 }
312
313 /**
314  * gst_caps_copy_on_write:
315  * @caps: the caps to copy
316  *
317  * Copies the caps if the refcount is greater than 1
318  *
319  * Returns: a pointer to a GstCaps strcuture that can
320  * be safely written to
321  */
322 GstCaps*
323 gst_caps_copy_on_write (GstCaps *caps)
324 {
325   GstCaps *new = caps;
326   gboolean needcopy;
327
328   g_return_val_if_fail (caps != NULL, NULL);
329
330   needcopy = (caps->refcount > 1);
331
332   if (needcopy) {
333     new = gst_caps_copy (caps);
334     gst_caps_unref (caps);
335   }
336
337   return new;
338 }
339
340 /**
341  * gst_caps_get_name:
342  * @caps: the caps to get the name from
343  *
344  * Get the name of a GstCaps structure.
345  *
346  * Returns: the name of the caps
347  */
348 const gchar*
349 gst_caps_get_name (GstCaps *caps)
350 {
351   g_return_val_if_fail (caps != NULL, NULL);
352
353   return (const gchar *)caps->name;
354 }
355
356 /**
357  * gst_caps_set_name:
358  * @caps: the caps to set the name to
359  * @name: the name to set
360  *
361  * Set the name of a caps.
362  */
363 void
364 gst_caps_set_name (GstCaps *caps, const gchar *name)
365 {
366   g_return_if_fail (caps != NULL);
367
368   if (caps->name)
369     g_free (caps->name);
370
371   caps->name = g_strdup (name);
372 }
373
374 /**
375  * gst_caps_get_mime:
376  * @caps: the caps to get the mime type from
377  *
378  * Get the mime type of the caps as a string.
379  *
380  * Returns: the mime type of the caps
381  */
382 const gchar*
383 gst_caps_get_mime (GstCaps *caps)
384 {
385   GstType *type;
386
387   g_return_val_if_fail (caps != NULL, NULL);
388
389   type = gst_type_find_by_id (caps->id);
390
391   if (type)
392     return type->mime;
393   else
394     return "unknown/unknown";
395 }
396
397 /**
398  * gst_caps_set_mime:
399  * @caps: the caps to set the mime type to
400  * @mime: the mime type to attach to the caps
401  *
402  * Set the mime type of the caps as a string.
403  */
404 void
405 gst_caps_set_mime (GstCaps *caps, const gchar *mime)
406 {
407   g_return_if_fail (caps != NULL);
408   g_return_if_fail (mime != NULL);
409
410   caps->id = get_type_for_mime (mime);
411 }
412
413 /**
414  * gst_caps_get_type_id:
415  * @caps: the caps to get the type id from
416  *
417  * Get the type id of the caps.
418  *
419  * Returns: the type id of the caps
420  */
421 guint16
422 gst_caps_get_type_id (GstCaps *caps)
423 {
424   g_return_val_if_fail (caps != NULL, 0);
425
426   return caps->id;
427 }
428
429 /**
430  * gst_caps_set_type_id:
431  * @caps: the caps to set the type id to
432  * @type_id: the type id to set
433  *
434  * Set the type id of the caps.
435  */
436 void
437 gst_caps_set_type_id (GstCaps *caps, guint16 type_id)
438 {
439   g_return_if_fail (caps != NULL);
440
441   caps->id = type_id;
442 }
443
444 /**
445  * gst_caps_set_props:
446  * @caps: the caps to attach the properties to
447  * @props: the properties to attach
448  *
449  * Set the properties to the given caps.
450  *
451  * Returns: the new caps structure
452  */
453 GstCaps*
454 gst_caps_set_props (GstCaps *caps, GstProps *props)
455 {
456   g_return_val_if_fail (caps != NULL, caps);
457   g_return_val_if_fail (props != NULL, caps);
458   g_return_val_if_fail (caps->properties == NULL, caps);
459
460   caps->properties = props;
461
462   return caps;
463 }
464
465 /**
466  * gst_caps_get_props:
467  * @caps: the caps to get the properties from
468  *
469  * Get the properties of the given caps.
470  *
471  * Returns: the properties of the caps
472  */
473 GstProps*
474 gst_caps_get_props (GstCaps *caps)
475 {
476   g_return_val_if_fail (caps != NULL, NULL);
477
478   return caps->properties;
479 }
480
481 /**
482  * gst_caps_chain:
483  * @caps: a capabilty
484  * @...: more capabilities
485  *
486  * chains the given capabilities
487  *
488  * Returns: the new capability
489  */
490 GstCaps*
491 gst_caps_chain (GstCaps *caps, ...)
492 {
493   GstCaps *orig = caps;
494   va_list var_args;
495
496   va_start (var_args, caps);
497
498   while (caps) {
499     GstCaps *toadd;
500     
501     toadd = va_arg (var_args, GstCaps*);
502     gst_caps_append (caps, toadd);
503     
504     caps = toadd;
505   }
506   va_end (var_args);
507   
508   return orig;
509 }
510
511 /**
512  * gst_caps_append:
513  * @caps: a capabilty
514  * @capstoadd: the capability to append
515  *
516  * Appends a capability to the existing capability.
517  *
518  * Returns: the new capability
519  */
520 GstCaps*
521 gst_caps_append (GstCaps *caps, GstCaps *capstoadd)
522 {
523   GstCaps *orig = caps;
524   
525   if (caps == NULL || caps == capstoadd)
526     return capstoadd;
527   
528   while (caps->next) {
529     caps = caps->next;
530   }
531   caps->next = capstoadd;
532
533   return orig;
534 }
535
536 /**
537  * gst_caps_prepend:
538  * @caps: a capabilty
539  * @capstoadd: a capabilty to prepend
540  *
541  * prepend the capability to the list of capabilities
542  *
543  * Returns: the new capability
544  */
545 GstCaps*
546 gst_caps_prepend (GstCaps *caps, GstCaps *capstoadd)
547 {
548   GstCaps *orig = capstoadd;
549   
550   if (capstoadd == NULL)
551     return caps;
552
553   g_return_val_if_fail (caps != capstoadd, caps);
554
555   while (capstoadd->next) {
556     capstoadd = capstoadd->next;
557   }
558   capstoadd->next = caps;
559
560   return orig;
561 }
562
563 /**
564  * gst_caps_get_by_name:
565  * @caps: a capabilty
566  * @name: the name of the capability to get
567  *
568  * Get the capability with the given name from this
569  * chain of capabilities.
570  *
571  * Returns: the first capability in the chain with the 
572  * given name
573  */
574 GstCaps*
575 gst_caps_get_by_name (GstCaps *caps, const gchar *name)
576 {
577   g_return_val_if_fail (caps != NULL, NULL);
578   g_return_val_if_fail (name != NULL, NULL);
579    
580   while (caps) {
581     if (!strcmp (caps->name, name)) 
582       return caps;
583     caps = caps->next;
584   }
585
586   return NULL;
587 }
588                                                                                                                    
589 static gboolean
590 gst_caps_check_compatibility_func (GstCaps *fromcaps, GstCaps *tocaps)
591 {
592   if (fromcaps->id != tocaps->id) {
593     GST_DEBUG (GST_CAT_CAPS,"mime types differ (%s to %s)",
594                gst_type_find_by_id (fromcaps->id)->mime, 
595                gst_type_find_by_id (tocaps->id)->mime);
596     return FALSE;
597   }
598
599   if (tocaps->properties) {
600     if (fromcaps->properties) {
601       return gst_props_check_compatibility (fromcaps->properties, tocaps->properties);
602     }
603     else {
604       GST_DEBUG (GST_CAT_CAPS,"no source caps");
605       return FALSE;
606     }
607   }
608   else {
609     /* assume it accepts everything */
610     GST_DEBUG (GST_CAT_CAPS,"no caps");
611     return TRUE;
612   }
613 }
614
615 /**
616  * gst_caps_check_compatibility:
617  * @fromcaps: a capabilty
618  * @tocaps: a capabilty
619  *
620  * Checks whether two capabilities are compatible.
621  *
622  * Returns: TRUE if compatible, FALSE otherwise
623  */
624 gboolean
625 gst_caps_check_compatibility (GstCaps *fromcaps, GstCaps *tocaps)
626 {
627   if (fromcaps == NULL) {
628     if (tocaps == NULL) {
629       GST_DEBUG (GST_CAT_CAPS,"no caps");
630       return TRUE;
631     }
632     else {
633       GST_DEBUG (GST_CAT_CAPS,"no source but destination caps");
634       return FALSE;
635     }
636   }
637   else {
638     if (tocaps == NULL) {
639       GST_DEBUG (GST_CAT_CAPS,"source caps and no destination caps");
640       return TRUE;
641     }
642   }
643
644   while (fromcaps) {
645     GstCaps *destcaps = tocaps;
646
647     while (destcaps) {
648       if (gst_caps_check_compatibility_func (fromcaps, destcaps))
649         return TRUE;
650
651       destcaps =  destcaps->next;
652     }
653     fromcaps =  fromcaps->next;
654   }
655   return FALSE;
656 }
657
658 static GstCaps*
659 gst_caps_intersect_func (GstCaps *caps1, GstCaps *caps2)
660 {
661   GstCaps *result = NULL;
662   GstProps *props;
663
664   if (caps1->id != caps2->id) {
665     GST_DEBUG (GST_CAT_CAPS,"mime types differ (%s to %s)",
666                gst_type_find_by_id (caps1->id)->mime, 
667                gst_type_find_by_id (caps2->id)->mime);
668     return NULL;
669   }
670
671   if (caps1->properties == NULL) {
672     return gst_caps_ref (caps2);
673   }
674   if (caps2->properties == NULL) {
675     return gst_caps_ref (caps1);
676   }
677   
678   props = gst_props_intersect (caps1->properties, caps2->properties);
679   if (props) {
680     result = gst_caps_new_id ("intersect", caps1->id, props);
681   }
682
683   return result;
684 }
685
686 /**
687  * gst_caps_intersect:
688  * @caps1: a capabilty
689  * @caps2: a capabilty
690  *
691  * Make the intersection between two caps.
692  *
693  * Returns: The intersection of the two caps or NULL if the intersection
694  * is empty.
695  */
696 GstCaps*
697 gst_caps_intersect (GstCaps *caps1, GstCaps *caps2)
698 {
699   GstCaps *result = NULL, *walk = NULL;
700
701   if (caps1 == NULL) {
702     GST_DEBUG (GST_CAT_CAPS, "first caps is NULL, return other caps");
703     return gst_caps_copy (caps2);
704   }
705   if (caps2 == NULL) {
706     GST_DEBUG (GST_CAT_CAPS, "second caps is NULL, return other caps");
707     return gst_caps_copy (caps1);
708   }
709
710   while (caps1) {
711     GstCaps *othercaps = caps2;
712
713     while (othercaps) {
714       GstCaps *intersection;
715       
716       intersection = gst_caps_intersect_func (caps1, othercaps);
717
718       if (intersection) {
719         if (!result) {
720           walk = result = intersection;
721         }
722         else {
723           walk = walk->next = intersection;
724         }
725       }
726       othercaps = othercaps->next;
727     }
728     caps1 =  caps1->next;
729   }
730
731   return result;
732 }
733
734 /**
735  * gst_caps_normalize:
736  * @caps: a capabilty
737  *
738  * Make the normalisation of the caps. This will return a new caps
739  * that is equivalent to the input caps with the exception that all
740  * lists are unrolled. This function is useful when you want to iterate
741  * the caps.
742  *
743  * Returns: The normalisation of the caps.
744  */
745 GstCaps*
746 gst_caps_normalize (GstCaps *caps)
747 {
748   GstCaps *result = NULL, *walk = caps;
749
750   if (caps == NULL)
751     return caps;
752
753   while (caps) {
754     GList *proplist;
755
756     proplist = gst_props_normalize (caps->properties);
757     if (proplist && g_list_next (proplist) == NULL) {
758       if (result == NULL)
759         walk = result = caps;
760       else {
761         walk = walk->next = caps;
762       }
763       goto next;
764     }
765
766     while (proplist) {
767       GstProps *props = (GstProps *) proplist->data;
768       GstCaps *newcaps = gst_caps_new_id (caps->name, caps->id, props);
769
770       if (result == NULL)
771         walk = result = newcaps;
772       else {
773         walk = walk->next = newcaps;
774       }
775       proplist = g_list_next (proplist);  
776     }
777 next:
778     caps = caps->next;
779   }
780   return result;
781 }
782
783 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
784 /**
785  * gst_caps_save_thyself:
786  * @caps: a capabilty to save
787  * @parent: the parent XML node pointer
788  *
789  * Save the capability into an XML representation.
790  *
791  * Returns: a new XML node pointer
792  */
793 xmlNodePtr
794 gst_caps_save_thyself (GstCaps *caps, xmlNodePtr parent)
795 {
796   xmlNodePtr subtree;
797   xmlNodePtr subsubtree;
798
799   while (caps) {
800     subtree = xmlNewChild (parent, NULL, "capscomp", NULL);
801
802     xmlNewChild (subtree, NULL, "name", caps->name);
803     xmlNewChild (subtree, NULL, "type", gst_type_find_by_id (caps->id)->mime);
804     if (caps->properties) {
805       subsubtree = xmlNewChild (subtree, NULL, "properties", NULL);
806
807       gst_props_save_thyself (caps->properties, subsubtree);
808     }
809
810     caps = caps->next;
811   }
812
813   return parent;
814 }
815
816 /**
817  * gst_caps_load_thyself:
818  * @parent: the parent XML node pointer
819  *
820  * Load a new caps from the XML representation.
821  *
822  * Returns: a new capability
823  */
824 GstCaps*
825 gst_caps_load_thyself (xmlNodePtr parent)
826 {
827   GstCaps *result = NULL;
828   xmlNodePtr field = parent->xmlChildrenNode;
829
830   while (field) {
831     if (!strcmp (field->name, "capscomp")) {
832       xmlNodePtr subfield = field->xmlChildrenNode;
833       GstCaps *caps;
834       gchar *content;
835
836       g_mutex_lock (_gst_caps_chunk_lock);
837       caps = g_mem_chunk_alloc0 (_gst_caps_chunk);
838       g_mutex_unlock (_gst_caps_chunk_lock);
839
840       caps->refcount = 1;
841       caps->next = NULL;
842       caps->fixed = TRUE;
843         
844       while (subfield) {
845         if (!strcmp (subfield->name, "name")) {
846           caps->name = xmlNodeGetContent (subfield);
847         }
848         if (!strcmp (subfield->name, "type")) {
849           content = xmlNodeGetContent (subfield);
850           caps->id = get_type_for_mime (content);
851           g_free (content);
852         }
853         else if (!strcmp (subfield->name, "properties")) {
854           caps->properties = gst_props_load_thyself (subfield);
855         }
856         
857         subfield = subfield->next;
858       }
859       result = gst_caps_append (result, caps);
860     }
861     field = field->next;
862   }
863
864   return result;
865 }
866
867 #endif /* GST_DISABLE_LOADSAVE_REGISTRY */