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