2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wtay@chello.be>
5 * gstcaps.c: Element capabilities subsystem
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.
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.
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.
23 /* #define GST_DEBUG_ENABLED */
24 #include "gst_private.h"
28 #include "gstmemchunk.h"
31 /* #define GST_WITH_ALLOC_TRACE */
34 static GstMemChunk *_gst_caps_chunk;
36 static GstAllocTrace *_gst_caps_trace;
41 transform_func (const GValue *src_value,
44 GstCaps *caps = g_value_peek_pointer (src_value);
45 GString *result = g_string_new ("");
47 g_string_append_printf (result, "(GstCaps *) ");
51 GValue value = { 0, }; /* the important thing is that value.type = 0 */
53 g_string_append_printf (result,
54 "{ %s; ", gst_caps_get_mime (caps));
56 g_value_init (&value, GST_TYPE_PROPS);
57 g_value_set_boxed (&value, caps->properties);
58 props = g_strdup_value_contents (&value);
60 g_value_unset (&value);
61 g_string_append (result, props);
65 g_string_append_printf (result, " }%s", (caps ? ", " : ""));
67 dest_value->data[0].v_pointer = result->str;
68 g_string_free (result, FALSE);
72 _gst_caps_initialize (void)
74 _gst_caps_chunk = gst_mem_chunk_new ("GstCaps",
75 sizeof (GstCaps), sizeof (GstCaps) * 256,
78 _gst_caps_type = g_boxed_type_register_static ("GstCaps",
79 (GBoxedCopyFunc) gst_caps_ref,
80 (GBoxedFreeFunc) gst_caps_unref);
82 g_value_register_transform_func (_gst_caps_type,
86 _gst_caps_trace = gst_alloc_trace_register (GST_CAPS_TRACE_NAME);
90 get_type_for_mime (const gchar *mime)
94 typeid = gst_type_find_by_mime (mime);
96 GstTypeDefinition definition;
97 GstTypeFactory *factory;
99 definition.name = "capstype";
100 definition.mime = g_strdup (mime);
101 definition.exts = NULL;
102 definition.typefindfunc = NULL;
104 factory = gst_type_factory_new (&definition);
106 typeid = gst_type_register (factory);
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
117 * Create a new capability with the given mime type and properties.
119 * Returns: a new capability
122 gst_caps_new (const gchar *name, const gchar *mime, GstProps *props)
124 g_return_val_if_fail (mime != NULL, NULL);
126 return gst_caps_new_id (name, get_type_for_mime (mime), props);
131 * @name: the name of this capability
132 * @id: the id of the mime type
133 * @props: the properties to add to this capability
135 * Create a new capability with the given mime typeid and properties.
137 * Returns: a new capability
140 gst_caps_new_id (const gchar *name, const guint16 id, GstProps *props)
144 caps = gst_mem_chunk_alloc (_gst_caps_chunk);
145 gst_alloc_trace_new (_gst_caps_trace, caps);
147 GST_DEBUG (GST_CAT_CAPS, "new %p", caps);
149 gst_props_ref (props);
150 gst_props_sink (props);
152 caps->name = g_strdup (name);
154 caps->properties = props;
157 GST_CAPS_FLAG_SET (caps, GST_CAPS_FLOATING);
159 if (props && !GST_PROPS_IS_FIXED (props))
160 GST_CAPS_FLAG_UNSET (caps, GST_CAPS_FIXED);
162 GST_CAPS_FLAG_SET (caps, GST_CAPS_FIXED);
169 * @oldcaps: the caps to take replace
170 * @newcaps: the caps to take replace
172 * Replace the pointer to the caps, doing proper
176 gst_caps_replace (GstCaps **oldcaps, GstCaps *newcaps)
178 if (*oldcaps != newcaps) {
179 if (newcaps) gst_caps_ref (newcaps);
180 if (*oldcaps) gst_caps_unref (*oldcaps);
187 * gst_caps_replace_sink:
188 * @oldcaps: the caps to take replace
189 * @newcaps: the caps to take replace
191 * Replace the pointer to the caps and take ownership.
194 gst_caps_replace_sink (GstCaps **oldcaps, GstCaps *newcaps)
196 gst_caps_replace (oldcaps, newcaps);
197 gst_caps_sink (newcaps);
202 * @caps: the caps to destroy
204 * Frees the memory used by this caps structure and all
205 * the chained caps and properties.
208 gst_caps_destroy (GstCaps *caps)
217 GST_DEBUG (GST_CAT_CAPS, "destroy %p", caps);
219 gst_props_unref (caps->properties);
222 gst_alloc_trace_free (_gst_caps_trace, caps);
223 gst_mem_chunk_free (_gst_caps_chunk, caps);
226 gst_caps_unref (next);
231 * @caps: the caps to print out
232 * @label: a label to put on the printout, or NULL
234 * Print out the contents of the caps structure. Useful for debugging.
237 gst_caps_debug (GstCaps *caps, const gchar *label)
239 GST_DEBUG_ENTER ("caps debug: %s", label);
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" : "");
246 if (caps->properties) {
247 gst_props_debug (caps->properties);
250 GST_DEBUG (GST_CAT_CAPS, "no properties");
255 GST_DEBUG_LEAVE ("caps debug");
260 * @caps: the caps to unref
262 * Decrease the refcount of this caps structure,
263 * destroying it when the refcount is 0
265 * Returns: caps or NULL if the refcount reached 0
268 gst_caps_unref (GstCaps *caps)
275 g_return_val_if_fail (caps->refcount > 0, NULL);
277 GST_DEBUG (GST_CAT_CAPS, "unref %p (%d->%d) %d",
278 caps, caps->refcount, caps->refcount-1, GST_CAPS_FLAGS (caps));
281 zero = (caps->refcount == 0);
284 gst_caps_destroy (caps);
292 * @caps: the caps to ref
294 * Increase the refcount of this caps structure
296 * Returns: the caps with the refcount incremented
299 gst_caps_ref (GstCaps *caps)
304 g_return_val_if_fail (caps->refcount > 0, NULL);
306 GST_DEBUG (GST_CAT_CAPS, "ref %p (%d->%d) %d",
307 caps, caps->refcount, caps->refcount+1, GST_CAPS_FLAGS (caps));
316 * @caps: the caps to take ownership of
318 * Take ownership of a GstCaps
321 gst_caps_sink (GstCaps *caps)
326 if (GST_CAPS_IS_FLOATING (caps)) {
327 GST_DEBUG (GST_CAT_CAPS, "sink %p", caps);
329 GST_CAPS_FLAG_UNSET (caps, GST_CAPS_FLOATING);
330 gst_caps_unref (caps);
336 * @caps: the caps to copy
338 * Copies the caps, not copying any chained caps.
340 * Returns: a floating copy of the GstCaps structure.
343 gst_caps_copy_1 (GstCaps *caps)
350 newcaps = gst_caps_new_id (
353 gst_props_copy (caps->properties));
360 * @caps: the caps to copy
364 * Returns: a floating copy of the GstCaps structure.
367 gst_caps_copy (GstCaps *caps)
369 GstCaps *new = NULL, *walk = NULL;
374 newcaps = gst_caps_copy_1 (caps);
377 new = walk = newcaps;
380 walk = walk->next = newcaps;
389 * gst_caps_copy_on_write:
390 * @caps: the caps to copy
392 * Copies the caps if the refcount is greater than 1
394 * Returns: a pointer to a GstCaps strcuture that can
395 * be safely written to.
398 gst_caps_copy_on_write (GstCaps *caps)
403 g_return_val_if_fail (caps != NULL, NULL);
405 needcopy = (caps->refcount > 1);
408 new = gst_caps_copy (caps);
409 gst_caps_unref (caps);
417 * @caps: the caps to get the name from
419 * Get the name of a GstCaps structure.
421 * Returns: the name of the caps
424 gst_caps_get_name (GstCaps *caps)
426 g_return_val_if_fail (caps != NULL, NULL);
428 return (const gchar *)caps->name;
433 * @caps: the caps to set the name to
434 * @name: the name to set
436 * Set the name of a caps.
439 gst_caps_set_name (GstCaps *caps, const gchar *name)
441 g_return_if_fail (caps != NULL);
444 caps->name = g_strdup (name);
449 * @caps: the caps to get the mime type from
451 * Get the mime type of the caps as a string.
453 * Returns: the mime type of the caps
456 gst_caps_get_mime (GstCaps *caps)
460 g_return_val_if_fail (caps != NULL, NULL);
462 type = gst_type_find_by_id (caps->id);
467 return "unknown/unknown";
472 * @caps: the caps to set the mime type to
473 * @mime: the mime type to attach to the caps
475 * Set the mime type of the caps as a string.
478 gst_caps_set_mime (GstCaps *caps, const gchar *mime)
480 g_return_if_fail (caps != NULL);
481 g_return_if_fail (mime != NULL);
483 caps->id = get_type_for_mime (mime);
487 * gst_caps_get_type_id:
488 * @caps: the caps to get the type id from
490 * Get the type id of the caps.
492 * Returns: the type id of the caps
495 gst_caps_get_type_id (GstCaps *caps)
497 g_return_val_if_fail (caps != NULL, 0);
503 * gst_caps_set_type_id:
504 * @caps: the caps to set the type id to
505 * @type_id: the type id to set
507 * Set the type id of the caps.
510 gst_caps_set_type_id (GstCaps *caps, guint16 type_id)
512 g_return_if_fail (caps != NULL);
518 * gst_caps_set_props:
519 * @caps: the caps to attach the properties to
520 * @props: the properties to attach
522 * Set the properties to the given caps.
524 * Returns: the new caps structure
527 gst_caps_set_props (GstCaps *caps, GstProps *props)
529 g_return_val_if_fail (caps != NULL, caps);
531 gst_props_replace_sink (&caps->properties, props);
537 * gst_caps_get_props:
538 * @caps: the caps to get the properties from
540 * Get the properties of the given caps.
542 * Returns: the properties of the caps
545 gst_caps_get_props (GstCaps *caps)
547 g_return_val_if_fail (caps != NULL, NULL);
549 return caps->properties;
554 * @caps: the caps to query
556 * Get the next caps of this chained caps.
558 * Returns: the next caps or NULL if the chain ended.
561 gst_caps_next (GstCaps *caps)
572 * @...: more capabilities
574 * chains the given capabilities
576 * Returns: the new capability
579 gst_caps_chain (GstCaps *caps, ...)
581 GstCaps *orig = caps;
584 va_start (var_args, caps);
589 toadd = va_arg (var_args, GstCaps*);
590 gst_caps_append (caps, toadd);
602 * @capstoadd: the capability to append
604 * Appends a capability to the existing capability.
606 * Returns: the new capability
609 gst_caps_append (GstCaps *caps, GstCaps *capstoadd)
611 GstCaps *orig = caps;
613 if (caps == NULL || caps == capstoadd)
619 gst_caps_replace_sink (&caps->next, capstoadd);
627 * @capstoadd: a capabilty to prepend
629 * prepend the capability to the list of capabilities
631 * Returns: the new capability
634 gst_caps_prepend (GstCaps *caps, GstCaps *capstoadd)
636 GstCaps *orig = capstoadd;
638 if (capstoadd == NULL)
641 g_return_val_if_fail (caps != capstoadd, caps);
643 while (capstoadd->next) {
644 capstoadd = capstoadd->next;
646 gst_caps_replace_sink (&capstoadd->next, caps);
652 * gst_caps_get_by_name:
654 * @name: the name of the capability to get
656 * Get the capability with the given name from this
657 * chain of capabilities.
659 * Returns: the first capability in the chain with the
663 gst_caps_get_by_name (GstCaps *caps, const gchar *name)
665 g_return_val_if_fail (caps != NULL, NULL);
666 g_return_val_if_fail (name != NULL, NULL);
669 if (!strcmp (caps->name, name))
678 gst_caps_check_compatibility_func (GstCaps *fromcaps, GstCaps *tocaps)
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);
687 if (tocaps->properties) {
688 if (fromcaps->properties) {
689 return gst_props_check_compatibility (fromcaps->properties, tocaps->properties);
692 GST_DEBUG (GST_CAT_CAPS,"no source caps");
697 /* assume it accepts everything */
698 GST_DEBUG (GST_CAT_CAPS,"no caps");
704 * gst_caps_is_always_compatible:
705 * @fromcaps: a #GstCaps capability to check compatibility of.
706 * @tocaps: the #GstCaps capability to check compatibility with.
708 * Checks if a link is always possible from fromcaps to tocaps, for all
709 * possible capabilities.
711 * Returns: TRUE if compatible under all circumstances, FALSE otherwise.
714 gst_caps_is_always_compatible (GstCaps *fromcaps, GstCaps *tocaps)
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");
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");
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");
739 GstCaps *destcaps = tocaps;
742 if (gst_caps_check_compatibility_func (fromcaps, destcaps))
745 destcaps = destcaps->next;
747 fromcaps = fromcaps->next;
753 gst_caps_intersect_func (GstCaps *caps1, GstCaps *caps2)
755 GstCaps *result = NULL;
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);
765 if (caps1->properties == NULL) {
766 return gst_caps_ref (caps2);
768 if (caps2->properties == NULL) {
769 return gst_caps_ref (caps1);
772 props = gst_props_intersect (caps1->properties, caps2->properties);
774 result = gst_caps_new_id ("intersect", caps1->id, props);
775 gst_caps_ref (result);
776 gst_caps_sink (result);
783 * gst_caps_intersect:
784 * @caps1: a capability
785 * @caps2: a capability
787 * Make the intersection between two caps.
789 * Returns: The intersection of the two caps or NULL if the intersection
790 * is empty. unref the caps after use.
793 gst_caps_intersect (GstCaps *caps1, GstCaps *caps2)
795 GstCaps *result = NULL, *walk = NULL;
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);
801 GST_DEBUG (GST_CAT_CAPS, "first caps is NULL, return other caps");
802 return gst_caps_ref (caps2);
805 GST_DEBUG (GST_CAT_CAPS, "second caps is NULL, return other caps");
806 return gst_caps_ref (caps1);
810 if (caps1 == caps2) {
811 return gst_caps_ref (caps1);
815 GstCaps *othercaps = caps2;
818 GstCaps *intersection;
820 intersection = gst_caps_intersect_func (caps1, othercaps);
824 walk = result = intersection;
827 walk = walk->next = intersection;
830 othercaps = othercaps->next;
839 gst_caps_union (GstCaps *caps1, GstCaps *caps2)
841 GstCaps *result = NULL;
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);
847 GST_DEBUG (GST_CAT_CAPS, "first caps is NULL, return other caps");
848 return gst_caps_ref (caps2);
851 GST_DEBUG (GST_CAT_CAPS, "second caps is NULL, return other caps");
852 return gst_caps_ref (caps1);
859 * gst_caps_normalize:
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.
867 * Returns: The normalisation of the caps. Unref after usage.
870 gst_caps_normalize (GstCaps *caps)
872 GstCaps *result = NULL, *walk;
877 GST_DEBUG (GST_CAT_CAPS, "normalizing caps %p ", caps);
884 proplist = gst_props_normalize (caps->properties);
886 GstProps *props = (GstProps *) proplist->data;
887 GstCaps *newcaps = gst_caps_new_id (caps->name, caps->id, props);
889 gst_caps_ref (newcaps);
890 gst_caps_sink (newcaps);
893 walk = result = newcaps;
895 walk = walk->next = newcaps;
897 proplist = g_list_next (proplist);
904 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
906 * gst_caps_save_thyself:
907 * @caps: a capabilty to save
908 * @parent: the parent XML node pointer
910 * Save the capability into an XML representation.
912 * Returns: a new XML node pointer
915 gst_caps_save_thyself (GstCaps *caps, xmlNodePtr parent)
918 xmlNodePtr subsubtree;
921 subtree = xmlNewChild (parent, NULL, "capscomp", NULL);
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);
928 gst_props_save_thyself (caps->properties, subsubtree);
938 * gst_caps_load_thyself:
939 * @parent: the parent XML node pointer
941 * Load a new caps from the XML representation.
943 * Returns: a new capability
946 gst_caps_load_thyself (xmlNodePtr parent)
948 GstCaps *result = NULL;
949 xmlNodePtr field = parent->xmlChildrenNode;
952 if (!strcmp (field->name, "capscomp")) {
953 xmlNodePtr subfield = field->xmlChildrenNode;
956 GstCapsFlags fixed = GST_CAPS_FIXED;
958 caps = gst_mem_chunk_alloc0 (_gst_caps_chunk);
959 gst_alloc_trace_new (_gst_caps_trace, caps);
962 GST_CAPS_FLAG_SET (caps, GST_CAPS_FLOATING);
966 if (!strcmp (subfield->name, "name")) {
967 caps->name = xmlNodeGetContent (subfield);
969 if (!strcmp (subfield->name, "type")) {
970 content = xmlNodeGetContent (subfield);
971 caps->id = get_type_for_mime (content);
974 else if (!strcmp (subfield->name, "properties")) {
975 GstProps *props = gst_props_load_thyself (subfield);
977 gst_props_ref (props);
978 gst_props_sink (props);
979 caps->properties = props;
981 fixed &= (GST_PROPS_IS_FIXED (caps->properties) ? GST_CAPS_FIXED : 0 );
984 subfield = subfield->next;
986 GST_CAPS_FLAG_SET (caps, fixed);
988 result = gst_caps_append (result, caps);
996 #endif /* GST_DISABLE_LOADSAVE_REGISTRY */