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 #include "gst_private.h"
27 #include "gstmemchunk.h"
30 #ifndef GST_DISABLE_TRACE
31 /* #define GST_WITH_ALLOC_TRACE */
34 static GstAllocTrace *_gst_caps_trace;
37 static GstMemChunk *_gst_caps_chunk;
41 extern GstProps * __gst_props_from_string_func (gchar *s, gchar **end, gboolean caps);
42 extern gboolean __gst_props_parse_string (gchar *r, gchar **end, gchar **next);
44 /* transform functions */
45 static void gst_caps_transform_to_string (const GValue *src_value, GValue *dest_value);
47 static void gst_caps_destroy (GstCaps *caps);
51 gst_caps_transform_to_string (const GValue *src_value, GValue *dest_value)
53 GstCaps *caps = g_value_peek_pointer (src_value);
54 dest_value->data[0].v_pointer = gst_caps_to_string (caps);
58 * caps: the caps to convert to a string
60 * Converts a #GstCaps into a readable format. This is mainly intended for
61 * debugging purposes. You have to free the string using g_free.
62 * A string converted with #gst_caps_to_string can always be converted back to
63 * its caps representation using #gst_caps_from_string.
65 * Returns: A newly allocated string
68 gst_caps_to_string (GstCaps *caps)
73 g_return_val_if_fail (caps != NULL, NULL);
75 result = g_string_new ("");
79 GValue value = { 0, }; /* the important thing is that value.type = 0 */
81 g_string_append_printf (result, "\"%s\"", gst_caps_get_mime (caps));
83 if (caps->properties) {
84 g_value_init (&value, GST_TYPE_PROPS);
85 g_value_set_boxed (&value, caps->properties);
86 props = g_strdup_value_contents (&value);
88 g_value_unset (&value);
89 g_string_append (result, ", ");
90 g_string_append (result, props);
96 g_string_append (result, "; ");
99 g_string_free (result, FALSE);
104 gst_caps_from_string_func (gchar *r)
107 GstCaps *caps, *append;
108 GstProps *props = NULL;
111 if (!__gst_props_parse_string (r, &w, &r)) goto error;
113 if (*r == '\0') goto found;
114 if (*r++ != ',') goto error;
115 while (g_ascii_isspace (*r)) r++;
117 props = __gst_props_from_string_func (r, &r, TRUE);
118 if (!props) goto error;
123 gst_props_unref (props);
126 caps = gst_caps_new ("parsed caps", mime, props);
130 while (g_ascii_isspace (*r)) r++;
133 while (g_ascii_isspace (*r)) r++;
134 append = gst_caps_from_string_func (r);
136 gst_caps_unref (caps);
139 gst_caps_append (caps, append);
148 * gst_caps_from_string:
149 * str: the str to convert into caps
151 * Tries to convert a string into a #GstCaps. This is mainly intended for
152 * debugging purposes. The returned caps are floating.
154 * Returns: A floating caps or NULL if the string couldn't be converted
157 gst_caps_from_string (gchar *str)
161 g_return_val_if_fail (str != NULL, NULL);
164 caps = gst_caps_from_string_func (s);
170 _gst_caps_initialize (void)
172 _gst_caps_chunk = gst_mem_chunk_new ("GstCaps",
173 sizeof (GstCaps), sizeof (GstCaps) * 256,
176 _gst_caps_type = g_boxed_type_register_static ("GstCaps",
177 (GBoxedCopyFunc) gst_caps_ref,
178 (GBoxedFreeFunc) gst_caps_unref);
180 g_value_register_transform_func (_gst_caps_type, G_TYPE_STRING,
181 gst_caps_transform_to_string);
183 #ifndef GST_DISABLE_TRACE
184 _gst_caps_trace = gst_alloc_trace_register (GST_CAPS_TRACE_NAME);
189 gst_caps_get_type (void)
191 return _gst_caps_type;
195 get_type_for_mime (const gchar *mime)
199 typeid = gst_type_find_by_mime (mime);
201 GstTypeDefinition definition;
202 GstTypeFactory *factory;
204 definition.name = "capstype";
205 definition.mime = g_strdup (mime);
206 definition.exts = NULL;
207 definition.typefindfunc = NULL;
209 factory = gst_type_factory_new (&definition);
211 typeid = gst_type_register (factory);
218 * @name: the name of this capability
219 * @mime: the mime type to attach to the capability
220 * @props: the properties to add to this capability
222 * Create a new capability with the given mime type and properties.
224 * Returns: a new capability
227 gst_caps_new (const gchar *name, const gchar *mime, GstProps *props)
229 g_return_val_if_fail (mime != NULL, NULL);
231 return gst_caps_new_id (name, get_type_for_mime (mime), props);
236 * @name: the name of this capability
237 * @id: the id of the mime type
238 * @props: the properties to add to this capability
240 * Create a new capability with the given mime typeid and properties.
242 * Returns: a new capability
245 gst_caps_new_id (const gchar *name, const guint16 id, GstProps *props)
249 caps = gst_mem_chunk_alloc (_gst_caps_chunk);
250 #ifndef GST_DISABLE_TRACE
251 gst_alloc_trace_new (_gst_caps_trace, caps);
254 GST_DEBUG (GST_CAT_CAPS, "new %p", caps);
256 gst_props_ref (props);
257 gst_props_sink (props);
259 caps->name = g_strdup (name);
261 caps->properties = props;
264 GST_CAPS_FLAG_SET (caps, GST_CAPS_FLOATING);
266 if (props && !GST_PROPS_IS_FIXED (props))
267 GST_CAPS_FLAG_UNSET (caps, GST_CAPS_FIXED);
269 GST_CAPS_FLAG_SET (caps, GST_CAPS_FIXED);
276 * @oldcaps: the caps to take replace
277 * @newcaps: the caps to take replace
279 * Replace the pointer to the caps, doing proper
283 gst_caps_replace (GstCaps **oldcaps, GstCaps *newcaps)
285 if (*oldcaps != newcaps) {
286 if (newcaps) gst_caps_ref (newcaps);
287 if (*oldcaps) gst_caps_unref (*oldcaps);
294 * gst_caps_replace_sink:
295 * @oldcaps: the caps to take replace
296 * @newcaps: the caps to take replace
298 * Replace the pointer to the caps and take ownership.
301 gst_caps_replace_sink (GstCaps **oldcaps, GstCaps *newcaps)
303 gst_caps_replace (oldcaps, newcaps);
304 gst_caps_sink (newcaps);
309 * @caps: the caps to destroy
311 * Frees the memory used by this caps structure and all
312 * the chained caps and properties.
315 gst_caps_destroy (GstCaps *caps)
324 GST_DEBUG (GST_CAT_CAPS, "destroy %p", caps);
326 gst_props_unref (caps->properties);
329 #ifndef GST_DISABLE_TRACE
330 gst_alloc_trace_free (_gst_caps_trace, caps);
332 gst_mem_chunk_free (_gst_caps_chunk, caps);
335 gst_caps_unref (next);
340 * @caps: the caps to print out
341 * @label: a label to put on the printout, or NULL
343 * Print out the contents of the caps structure. Useful for debugging.
346 gst_caps_debug (GstCaps *caps, const gchar *label)
348 GST_DEBUG_ENTER ("caps debug: %s", label);
350 GST_DEBUG (GST_CAT_CAPS, "caps: %p %s %s (%sfixed) (refcount %d) %s",
351 caps, caps->name, gst_caps_get_mime (caps),
352 GST_CAPS_IS_FIXED (caps) ? "" : "NOT ", caps->refcount,
353 GST_CAPS_IS_FLOATING (caps) ? "FLOATING" : "");
355 if (caps->properties) {
356 gst_props_debug (caps->properties);
359 GST_DEBUG (GST_CAT_CAPS, "no properties");
364 GST_DEBUG_LEAVE ("caps debug");
369 * @caps: the caps to unref
371 * Decrease the refcount of this caps structure,
372 * destroying it when the refcount is 0
374 * Returns: caps or NULL if the refcount reached 0
377 gst_caps_unref (GstCaps *caps)
384 g_return_val_if_fail (caps->refcount > 0, NULL);
386 GST_DEBUG (GST_CAT_CAPS, "unref %p (%d->%d) %d",
387 caps, caps->refcount, caps->refcount-1, GST_CAPS_FLAGS (caps));
390 zero = (caps->refcount == 0);
393 gst_caps_destroy (caps);
401 * @caps: the caps to ref
403 * Increase the refcount of this caps structure
405 * Returns: the caps with the refcount incremented
408 gst_caps_ref (GstCaps *caps)
413 g_return_val_if_fail (caps->refcount > 0, NULL);
415 GST_DEBUG (GST_CAT_CAPS, "ref %p (%d->%d) %d",
416 caps, caps->refcount, caps->refcount+1, GST_CAPS_FLAGS (caps));
425 * @caps: the caps to take ownership of
427 * Take ownership of a GstCaps
430 gst_caps_sink (GstCaps *caps)
435 if (GST_CAPS_IS_FLOATING (caps)) {
436 GST_DEBUG (GST_CAT_CAPS, "sink %p", caps);
438 GST_CAPS_FLAG_UNSET (caps, GST_CAPS_FLOATING);
439 gst_caps_unref (caps);
445 * @caps: the caps to copy
447 * Copies the caps, not copying any chained caps.
449 * Returns: a floating copy of the GstCaps structure.
452 gst_caps_copy_1 (GstCaps *caps)
459 newcaps = gst_caps_new_id (
462 gst_props_copy (caps->properties));
469 * @caps: the caps to copy
473 * Returns: a floating copy of the GstCaps structure.
476 gst_caps_copy (GstCaps *caps)
478 GstCaps *new = NULL, *walk = NULL;
483 newcaps = gst_caps_copy_1 (caps);
486 new = walk = newcaps;
489 walk = walk->next = newcaps;
498 * gst_caps_copy_on_write:
499 * @caps: the caps to copy
501 * Copies the caps if the refcount is greater than 1
503 * Returns: a pointer to a GstCaps strcuture that can
504 * be safely written to.
507 gst_caps_copy_on_write (GstCaps *caps)
512 g_return_val_if_fail (caps != NULL, NULL);
514 needcopy = (caps->refcount > 1);
517 new = gst_caps_copy (caps);
518 gst_caps_unref (caps);
526 * @caps: the caps to get the name from
528 * Get the name of a GstCaps structure.
530 * Returns: the name of the caps
533 gst_caps_get_name (GstCaps *caps)
535 g_return_val_if_fail (caps != NULL, NULL);
537 return (const gchar *)caps->name;
542 * @caps: the caps to set the name to
543 * @name: the name to set
545 * Set the name of a caps.
548 gst_caps_set_name (GstCaps *caps, const gchar *name)
550 g_return_if_fail (caps != NULL);
553 caps->name = g_strdup (name);
558 * @caps: the caps to get the mime type from
560 * Get the mime type of the caps as a string.
562 * Returns: the mime type of the caps
565 gst_caps_get_mime (GstCaps *caps)
569 g_return_val_if_fail (caps != NULL, NULL);
571 type = gst_type_find_by_id (caps->id);
576 return "unknown/unknown";
581 * @caps: the caps to set the mime type to
582 * @mime: the mime type to attach to the caps
584 * Set the mime type of the caps as a string.
587 gst_caps_set_mime (GstCaps *caps, const gchar *mime)
589 g_return_if_fail (caps != NULL);
590 g_return_if_fail (mime != NULL);
592 caps->id = get_type_for_mime (mime);
596 * gst_caps_get_type_id:
597 * @caps: the caps to get the type id from
599 * Get the type id of the caps.
601 * Returns: the type id of the caps
604 gst_caps_get_type_id (GstCaps *caps)
606 g_return_val_if_fail (caps != NULL, 0);
612 * gst_caps_set_type_id:
613 * @caps: the caps to set the type id to
614 * @type_id: the type id to set
616 * Set the type id of the caps.
619 gst_caps_set_type_id (GstCaps *caps, guint16 type_id)
621 g_return_if_fail (caps != NULL);
627 * gst_caps_set_props:
628 * @caps: the caps to attach the properties to
629 * @props: the properties to attach
631 * Set the properties to the given caps.
633 * Returns: the new caps structure
636 gst_caps_set_props (GstCaps *caps, GstProps *props)
638 g_return_val_if_fail (caps != NULL, caps);
640 gst_props_replace_sink (&caps->properties, props);
642 if (props && !GST_PROPS_IS_FIXED (props))
643 GST_CAPS_FLAG_UNSET (caps, GST_CAPS_FIXED);
645 GST_CAPS_FLAG_SET (caps, GST_CAPS_FIXED);
651 * gst_caps_get_props:
652 * @caps: the caps to get the properties from
654 * Get the properties of the given caps.
656 * Returns: the properties of the caps
659 gst_caps_get_props (GstCaps *caps)
661 g_return_val_if_fail (caps != NULL, NULL);
663 return caps->properties;
668 * @caps: the caps to query
670 * Get the next caps of this chained caps.
672 * Returns: the next caps or NULL if the chain ended.
675 gst_caps_next (GstCaps *caps)
686 * @...: more capabilities
688 * chains the given capabilities
690 * Returns: the new capability
693 gst_caps_chain (GstCaps *caps, ...)
695 GstCaps *orig = caps;
698 va_start (var_args, caps);
703 toadd = va_arg (var_args, GstCaps*);
704 gst_caps_append (caps, toadd);
716 * @capstoadd: the capability to append
718 * Appends a capability to the existing capability.
720 * Returns: the new capability
723 gst_caps_append (GstCaps *caps, GstCaps *capstoadd)
725 GstCaps *orig = caps;
727 if (caps == NULL || caps == capstoadd)
733 gst_caps_replace_sink (&caps->next, capstoadd);
741 * @capstoadd: a capabilty to prepend
743 * prepend the capability to the list of capabilities
745 * Returns: the new capability
748 gst_caps_prepend (GstCaps *caps, GstCaps *capstoadd)
750 GstCaps *orig = capstoadd;
752 if (capstoadd == NULL)
755 g_return_val_if_fail (caps != capstoadd, caps);
757 while (capstoadd->next) {
758 capstoadd = capstoadd->next;
760 gst_caps_replace_sink (&capstoadd->next, caps);
766 * gst_caps_get_by_name:
768 * @name: the name of the capability to get
770 * Get the capability with the given name from this
771 * chain of capabilities.
773 * Returns: the first capability in the chain with the
777 gst_caps_get_by_name (GstCaps *caps, const gchar *name)
779 g_return_val_if_fail (caps != NULL, NULL);
780 g_return_val_if_fail (name != NULL, NULL);
783 if (!strcmp (caps->name, name))
792 gst_caps_check_compatibility_func (GstCaps *fromcaps, GstCaps *tocaps)
794 if (fromcaps->id != tocaps->id) {
795 GST_DEBUG (GST_CAT_CAPS,"mime types differ (%s to %s)",
796 gst_type_find_by_id (fromcaps->id)->mime,
797 gst_type_find_by_id (tocaps->id)->mime);
801 if (tocaps->properties) {
802 if (fromcaps->properties) {
803 return gst_props_check_compatibility (fromcaps->properties, tocaps->properties);
806 GST_DEBUG (GST_CAT_CAPS,"no source caps");
811 /* assume it accepts everything */
812 GST_DEBUG (GST_CAT_CAPS,"no caps");
818 * gst_caps_is_always_compatible:
819 * @fromcaps: a #GstCaps capability to check compatibility of.
820 * @tocaps: the #GstCaps capability to check compatibility with.
822 * Checks if a link is always possible from fromcaps to tocaps, for all
823 * possible capabilities.
825 * Returns: TRUE if compatible under all circumstances, FALSE otherwise.
828 gst_caps_is_always_compatible (GstCaps *fromcaps, GstCaps *tocaps)
830 if (fromcaps == NULL) {
831 if (tocaps == NULL) {
832 /* if both are NULL, they can always link. Think filesrc ! filesink */
833 GST_DEBUG (GST_CAT_CAPS, "both caps NULL, compatible");
837 /* if source caps are NULL, it could be sending anything, so the
838 * destination can't know if it can accept this. Think filesrc ! mad */
839 GST_DEBUG (GST_CAT_CAPS, "source caps NULL, not guaranteed compatible");
844 if (tocaps == NULL) {
845 /* if the dest caps are NULL, the element can accept anything, always,
846 * so they're compatible by definition. Think mad ! filesink */
847 GST_DEBUG (GST_CAT_CAPS,"destination caps NULL");
853 GstCaps *destcaps = tocaps;
854 /* assume caps is incompatible */
855 gboolean compat = FALSE;
857 while (destcaps && !compat) {
858 if (gst_caps_check_compatibility_func (fromcaps, destcaps)) {
861 destcaps = destcaps->next;
866 fromcaps = fromcaps->next;
872 gst_caps_intersect_func (GstCaps *caps1, GstCaps *caps2)
874 GstCaps *result = NULL;
877 if (caps1->id != caps2->id) {
878 GST_DEBUG (GST_CAT_CAPS, "mime types differ (%s to %s)",
879 gst_type_find_by_id (caps1->id)->mime,
880 gst_type_find_by_id (caps2->id)->mime);
884 if (caps1->properties == NULL) {
885 return gst_caps_ref (caps2);
887 if (caps2->properties == NULL) {
888 return gst_caps_ref (caps1);
891 props = gst_props_intersect (caps1->properties, caps2->properties);
893 result = gst_caps_new_id ("intersect", caps1->id, props);
894 gst_caps_ref (result);
895 gst_caps_sink (result);
902 * gst_caps_intersect:
903 * @caps1: a capability
904 * @caps2: a capability
906 * Make the intersection between two caps.
908 * Returns: The intersection of the two caps or NULL if the intersection
909 * is empty. unref the caps after use.
912 gst_caps_intersect (GstCaps *caps1, GstCaps *caps2)
914 GstCaps *result = NULL, *walk = NULL;
916 /* printing the name is not useful here since caps can be chained */
917 GST_DEBUG (GST_CAT_CAPS, "intersecting caps %p and %p", caps1, caps2);
920 GST_DEBUG (GST_CAT_CAPS, "first caps is NULL, return other caps");
921 return gst_caps_ref (caps2);
924 GST_DEBUG (GST_CAT_CAPS, "second caps is NULL, return other caps");
925 return gst_caps_ref (caps1);
929 if (caps1 == caps2) {
930 return gst_caps_ref (caps1);
934 GstCaps *othercaps = caps2;
937 GstCaps *intersection;
939 intersection = gst_caps_intersect_func (caps1, othercaps);
943 walk = result = intersection;
946 walk = walk->next = intersection;
949 othercaps = othercaps->next;
958 gst_caps_union (GstCaps *caps1, GstCaps *caps2)
960 GstCaps *result = NULL;
962 /* printing the name is not useful here since caps can be chained */
963 GST_DEBUG (GST_CAT_CAPS, "making union of caps %p and %p", caps1, caps2);
966 GST_DEBUG (GST_CAT_CAPS, "first caps is NULL, return other caps");
967 return gst_caps_ref (caps2);
970 GST_DEBUG (GST_CAT_CAPS, "second caps is NULL, return other caps");
971 return gst_caps_ref (caps1);
978 * gst_caps_normalize:
981 * Make the normalisation of the caps. This will return a new caps
982 * that is equivalent to the input caps with the exception that all
983 * lists are unrolled. This function is useful when you want to iterate
984 * the caps. unref the caps after use.
986 * Returns: The normalisation of the caps. Unref after usage.
989 gst_caps_normalize (GstCaps *caps)
991 GstCaps *result = NULL, *walk;
996 GST_DEBUG (GST_CAT_CAPS, "normalizing caps %p ", caps);
1003 proplist = gst_props_normalize (caps->properties);
1005 GstProps *props = (GstProps *) proplist->data;
1006 GstCaps *newcaps = gst_caps_new_id (caps->name, caps->id, props);
1008 gst_caps_ref (newcaps);
1009 gst_caps_sink (newcaps);
1012 walk = result = newcaps;
1014 walk = walk->next = newcaps;
1016 proplist = g_list_next (proplist);
1023 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
1025 * gst_caps_save_thyself:
1026 * @caps: a capabilty to save
1027 * @parent: the parent XML node pointer
1029 * Save the capability into an XML representation.
1031 * Returns: a new XML node pointer
1034 gst_caps_save_thyself (GstCaps *caps, xmlNodePtr parent)
1037 xmlNodePtr subsubtree;
1040 subtree = xmlNewChild (parent, NULL, "capscomp", NULL);
1042 xmlNewChild (subtree, NULL, "name", caps->name);
1043 xmlNewChild (subtree, NULL, "type", gst_type_find_by_id (caps->id)->mime);
1044 if (caps->properties) {
1045 subsubtree = xmlNewChild (subtree, NULL, "properties", NULL);
1047 gst_props_save_thyself (caps->properties, subsubtree);
1057 * gst_caps_load_thyself:
1058 * @parent: the parent XML node pointer
1060 * Load a new caps from the XML representation.
1062 * Returns: a new capability
1065 gst_caps_load_thyself (xmlNodePtr parent)
1067 GstCaps *result = NULL;
1068 xmlNodePtr field = parent->xmlChildrenNode;
1071 if (!strcmp (field->name, "capscomp")) {
1072 xmlNodePtr subfield = field->xmlChildrenNode;
1075 GstCapsFlags fixed = GST_CAPS_FIXED;
1077 caps = gst_mem_chunk_alloc0 (_gst_caps_chunk);
1078 #ifndef GST_DISABLE_TRACE
1079 gst_alloc_trace_new (_gst_caps_trace, caps);
1083 GST_CAPS_FLAG_SET (caps, GST_CAPS_FLOATING);
1087 if (!strcmp (subfield->name, "name")) {
1088 caps->name = xmlNodeGetContent (subfield);
1090 if (!strcmp (subfield->name, "type")) {
1091 content = xmlNodeGetContent (subfield);
1092 caps->id = get_type_for_mime (content);
1095 else if (!strcmp (subfield->name, "properties")) {
1096 GstProps *props = gst_props_load_thyself (subfield);
1098 gst_props_ref (props);
1099 gst_props_sink (props);
1100 caps->properties = props;
1102 fixed &= (GST_PROPS_IS_FIXED (caps->properties) ? GST_CAPS_FIXED : 0 );
1105 subfield = subfield->next;
1107 GST_CAPS_FLAG_SET (caps, fixed);
1109 result = gst_caps_append (result, caps);
1111 field = field->next;
1117 #endif /* GST_DISABLE_LOADSAVE_REGISTRY */