diff --git a/gst/gstcaps.c b/gst/gstcaps.c deleted file mode 100644 index 69ea7a5f0f..0000000000 --- a/gst/gstcaps.c +++ /dev/null @@ -1,1136 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2000 Wim Taymans - * - * gstcaps.c: Element capabilities subsystem - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "gst_private.h" - -#include "gstcaps.h" -#include "gstmemchunk.h" -#include "gstinfo.h" - -#ifndef GST_DISABLE_TRACE -/* #define GST_WITH_ALLOC_TRACE */ -#include "gsttrace.h" - -static GstAllocTrace *_gst_caps_trace; -#endif - -static GstMemChunk *_gst_caps_chunk; - -GType _gst_caps_type; - -extern GstProps * __gst_props_from_string_func (gchar *s, gchar **end, gboolean caps); -extern gboolean __gst_props_parse_string (gchar *r, gchar **end, gchar **next); - -/* transform functions */ -static void gst_caps_transform_to_string (const GValue *src_value, GValue *dest_value); - -static void gst_caps_destroy (GstCaps *caps); - - -static void -gst_caps_transform_to_string (const GValue *src_value, GValue *dest_value) -{ - GstCaps *caps = g_value_peek_pointer (src_value); - dest_value->data[0].v_pointer = gst_caps_to_string (caps); -} -/** - * gst_caps_to_string: - * caps: the caps to convert to a string - * - * Converts a #GstCaps into a readable format. This is mainly intended for - * debugging purposes. You have to free the string using g_free. - * A string converted with #gst_caps_to_string can always be converted back to - * its caps representation using #gst_caps_from_string. - * - * Returns: A newly allocated string - */ -gchar * -gst_caps_to_string (GstCaps *caps) -{ - gchar *ret; - GString *result; - - result = g_string_new (""); - - if(caps==NULL){ - g_string_append(result, "NULL"); - } - - while (caps) { - gchar *props; - GValue value = { 0, }; /* the important thing is that value.type = 0 */ - - g_string_append_printf (result, "\"%s\"", gst_caps_get_mime (caps)); - - if (caps->properties) { - g_value_init (&value, GST_TYPE_PROPS); - g_value_set_boxed (&value, caps->properties); - props = g_strdup_value_contents (&value); - - /* this happens with empty (but existing) caps->properties */ - if (props[0] != '\0') { - g_value_unset (&value); - g_string_append (result, ", "); - g_string_append (result, props); - g_free (props); - } - } - - caps = caps->next; - if (caps) - g_string_append (result, "; "); - } - ret = result->str; - g_string_free (result, FALSE); - return ret; -} - -static GstCaps * -gst_caps_from_string_func (gchar *r) -{ - gchar *mime, *w; - GstCaps *caps, *append; - GstProps *props = NULL; - - mime = r; - if (!__gst_props_parse_string (r, &w, &r)) goto error; - - if (*r == '\0') goto found; - if (*r++ != ',') goto error; - while (g_ascii_isspace (*r)) r++; - - props = __gst_props_from_string_func (r, &r, TRUE); - if (!props) goto error; - -found: - *w = '\0'; - if (*mime == '\0') { - gst_props_unref (props); - goto error; - } - caps = gst_caps_new ("parsed caps", mime, props); - if (*r == '\0') - return caps; - - while (g_ascii_isspace (*r)) r++; - if (*r == ';') { - r++; - while (g_ascii_isspace (*r)) r++; - append = gst_caps_from_string_func (r); - if (!append) { - gst_caps_unref (caps); - goto error; - } - gst_caps_append (caps, append); - } - - return caps; - -error: - return NULL; -} -/** - * gst_caps_from_string: - * str: the str to convert into caps - * - * Tries to convert a string into a #GstCaps. This is mainly intended for - * debugging purposes. The returned caps are floating. - * - * Returns: A floating caps or NULL if the string couldn't be converted - */ -GstCaps * -gst_caps_from_string (gchar *str) -{ - gchar *s; - GstCaps *caps; - g_return_val_if_fail (str != NULL, NULL); - - s = g_strdup (str); - caps = gst_caps_from_string_func (s); - g_free (s); - - return caps; -} -void -_gst_caps_initialize (void) -{ - _gst_caps_chunk = gst_mem_chunk_new ("GstCaps", - sizeof (GstCaps), sizeof (GstCaps) * 256, - G_ALLOC_AND_FREE); - - _gst_caps_type = g_boxed_type_register_static ("GstCaps", - (GBoxedCopyFunc) gst_caps_ref, - (GBoxedFreeFunc) gst_caps_unref); - - g_value_register_transform_func (_gst_caps_type, G_TYPE_STRING, - gst_caps_transform_to_string); - -#ifndef GST_DISABLE_TRACE - _gst_caps_trace = gst_alloc_trace_register (GST_CAPS_TRACE_NAME); -#endif -} - -GType -gst_caps_get_type (void) -{ - return _gst_caps_type; -} -/** - * gst_caps_new: - * @name: the name of this capability - * @mime: the mime type to attach to the capability - * @props: the properties to add to this capability - * - * Create a new capability with the given mime type and properties. - * - * Returns: a new capability - */ -GstCaps* -gst_caps_new (const gchar *name, const gchar *mime, GstProps *props) -{ - g_return_val_if_fail (mime != NULL, NULL); - - return gst_caps_new_id (name, g_quark_from_string (mime), props); -} -/** - * gst_caps_new_id: - * @name: the name of this capability - * @id: the id of the mime type - * @props: the properties to add to this capability - * - * Create a new capability with the given mime typeid and properties. - * - * Returns: a new capability - */ -GstCaps* -gst_caps_new_id (const gchar *name, const GQuark id, GstProps *props) -{ - GstCaps *caps; - - caps = gst_mem_chunk_alloc (_gst_caps_chunk); -#ifndef GST_DISABLE_TRACE - gst_alloc_trace_new (_gst_caps_trace, caps); -#endif - - GST_CAT_LOG (GST_CAT_CAPS, "new %p, props %p", caps, props); - - gst_props_ref (props); - gst_props_sink (props); - - caps->name = g_strdup (name); - caps->id = id; - caps->properties = props; - caps->next = NULL; - caps->refcount = 1; - GST_CAPS_FLAG_SET (caps, GST_CAPS_FLOATING); - - return caps; -} - -/** - * gst_caps_get_any: - * - * Return a copy of the caps that represents any capability. - * - * Returns: the ANY capability - */ -GstCaps* -gst_caps_get_any (void) -{ -#if 0 - static GstCaps *caps; - - if (!caps){ - caps = GST_CAPS_NEW ("gst_caps_any", "*", NULL); - gst_caps_ref(caps); - gst_caps_sink(caps); - } - - return gst_caps_ref(caps); -#else - return NULL; -#endif -} - -/** - * gst_caps_replace: - * @oldcaps: the caps to take replace - * @newcaps: the caps to take replace - * - * Replace the pointer to the caps, doing proper - * refcounting. - */ -void -gst_caps_replace (GstCaps **oldcaps, GstCaps *newcaps) -{ - if (*oldcaps != newcaps) { - if (newcaps) gst_caps_ref (newcaps); - if (*oldcaps) gst_caps_unref (*oldcaps); - - *oldcaps = newcaps; - } -} - -/** - * gst_caps_replace_sink: - * @oldcaps: the caps to take replace - * @newcaps: the caps to take replace - * - * Replace the pointer to the caps and take ownership. - */ -void -gst_caps_replace_sink (GstCaps **oldcaps, GstCaps *newcaps) -{ - gst_caps_replace (oldcaps, newcaps); - gst_caps_sink (newcaps); -} - -/** - * gst_caps_destroy: - * @caps: the caps to destroy - * - * Frees the memory used by this caps structure and all - * the chained caps and properties. - */ -static void -gst_caps_destroy (GstCaps *caps) -{ - GstCaps *next; - - if (caps == NULL) - return; - - next = caps->next; - - GST_CAT_LOG (GST_CAT_CAPS, "destroy %p", caps); - - gst_props_unref (caps->properties); - g_free (caps->name); - -#ifdef USE_POISONING - memset(caps, 0xff, sizeof(*caps)); -#endif - -#ifndef GST_DISABLE_TRACE - gst_alloc_trace_free (_gst_caps_trace, caps); -#endif - gst_mem_chunk_free (_gst_caps_chunk, caps); - - if (next) - gst_caps_unref (next); -} - -/** - * gst_caps_debug: - * @caps: the caps to print out - * @label: a label to put on the printout, or NULL - * - * Print out the contents of the caps structure. Useful for debugging. - */ -void -gst_caps_debug (GstCaps *caps, const gchar *label) -{ - GST_CAT_DEBUG (GST_CAT_CAPS, "starting caps debug: %s", label); - if (caps && caps->refcount == 0) { - g_warning ("Warning: refcount of caps %s is 0", label); - return; - } - - while (caps) { - GST_CAT_DEBUG (GST_CAT_CAPS, "caps: %p %s %s (%sfixed) (refcount %d) %s", - caps, caps->name, gst_caps_get_mime (caps), - GST_CAPS_IS_FIXED (caps) ? "" : "NOT ", caps->refcount, - GST_CAPS_IS_FLOATING (caps) ? "FLOATING" : ""); - - if (caps->properties) { - gst_props_debug (caps->properties); - } - else { - GST_CAT_DEBUG (GST_CAT_CAPS, "no properties"); - } - - caps = caps->next; - } - GST_CAT_DEBUG (GST_CAT_CAPS, "finished caps debug"); -} - -/** - * gst_caps_unref: - * @caps: the caps to unref - * - * Decrease the refcount of this caps structure, - * destroying it when the refcount is 0 - * - * Returns: caps or NULL if the refcount reached 0 - */ -GstCaps* -gst_caps_unref (GstCaps *caps) -{ - gboolean zero; - - if (caps == NULL) - return NULL; - - g_return_val_if_fail (caps->refcount > 0, NULL); - - GST_CAT_LOG (GST_CAT_CAPS, "unref %p (%d->%d) %d", - caps, caps->refcount, caps->refcount-1, GST_CAPS_FLAGS (caps)); - - caps->refcount--; - zero = (caps->refcount == 0); - - if (zero) { - gst_caps_destroy (caps); - caps = NULL; - } - return caps; -} - -/** - * gst_caps_ref: - * @caps: the caps to ref - * - * Increase the refcount of this caps structure - * - * Returns: the caps with the refcount incremented - */ -GstCaps* -gst_caps_ref (GstCaps *caps) -{ - if (caps == NULL) - return NULL; - - g_return_val_if_fail (caps->refcount > 0, NULL); - - GST_CAT_LOG (GST_CAT_CAPS, "ref %p (%d->%d) %d", - caps, caps->refcount, caps->refcount+1, GST_CAPS_FLAGS (caps)); - - caps->refcount++; - - return caps; -} - -/** - * gst_caps_sink: - * @caps: the caps to take ownership of - * - * Take ownership of a GstCaps - */ -void -gst_caps_sink (GstCaps *caps) -{ - if (caps == NULL) - return; - - if (GST_CAPS_IS_FLOATING (caps)) { - GST_CAT_LOG (GST_CAT_CAPS, "sink %p", caps); - - GST_CAPS_FLAG_UNSET (caps, GST_CAPS_FLOATING); - gst_caps_unref (caps); - } -} - -/** - * gst_caps_copy_1: - * @caps: the caps to copy - * - * Copies the caps, not copying any chained caps. - * - * Returns: a floating copy of the GstCaps structure. - */ -GstCaps* -gst_caps_copy_1 (GstCaps *caps) -{ - GstCaps *newcaps; - - if (!caps) - return NULL; - - newcaps = gst_caps_new_id ( - caps->name, - caps->id, - gst_props_copy (caps->properties)); - - return newcaps; -} - -/** - * gst_caps_copy: - * @caps: the caps to copy - * - * Copies the caps. - * - * Returns: a floating copy of the GstCaps structure. - */ -GstCaps* -gst_caps_copy (GstCaps *caps) -{ - GstCaps *new = NULL, *walk = NULL; - - while (caps) { - GstCaps *newcaps; - - newcaps = gst_caps_copy_1 (caps); - - if (new == NULL) { - new = walk = newcaps; - } - else { - walk = walk->next = newcaps; - } - caps = caps->next; - } - - return new; -} - -/** - * gst_caps_copy_on_write: - * @caps: the caps to copy - * - * Copies the caps if the refcount is greater than 1 - * - * Returns: a pointer to a GstCaps strcuture that can - * be safely written to. - */ -GstCaps* -gst_caps_copy_on_write (GstCaps *caps) -{ - GstCaps *new = caps; - gboolean needcopy; - - g_return_val_if_fail (caps != NULL, NULL); - - needcopy = (caps->refcount > 1); - - if (needcopy) { - new = gst_caps_copy (caps); - gst_caps_unref (caps); - } - - return new; -} - -/** - * gst_caps_get_name: - * @caps: the caps to get the name from - * - * Get the name of a GstCaps structure. - * - * Returns: the name of the caps - */ -const gchar* -gst_caps_get_name (GstCaps *caps) -{ - g_return_val_if_fail (caps != NULL, NULL); - - return (const gchar *)caps->name; -} - -/** - * gst_caps_set_name: - * @caps: the caps to set the name to - * @name: the name to set - * - * Set the name of a caps. - */ -void -gst_caps_set_name (GstCaps *caps, const gchar *name) -{ - g_return_if_fail (caps != NULL); - - g_free (caps->name); - caps->name = g_strdup (name); -} -/** - * gst_caps_get_mime: - * @caps: the caps to get the mime type from - * - * Get the mime type of the caps as a string. - * - * Returns: the mime type of the caps - */ -const gchar* -gst_caps_get_mime (GstCaps *caps) -{ - g_return_val_if_fail (caps != NULL, NULL); - - return g_quark_to_string (caps->id); -} -/** - * gst_caps_set_mime: - * @caps: the caps to set the mime type to - * @mime: the mime type to attach to the caps - * - * Set the mime type of the caps as a string. - */ -void -gst_caps_set_mime (GstCaps *caps, const gchar *mime) -{ - g_return_if_fail (caps != NULL); - g_return_if_fail (mime != NULL); - - caps->id = g_quark_from_string (mime); -} -/** - * gst_caps_set_props: - * @caps: the caps to attach the properties to - * @props: the properties to attach - * - * Set the properties to the given caps. - * - * Returns: the new caps structure - */ -GstCaps* -gst_caps_set_props (GstCaps *caps, GstProps *props) -{ - g_return_val_if_fail (caps != NULL, caps); - - gst_props_replace_sink (&caps->properties, props); - - return caps; -} - -/** - * gst_caps_get_props: - * @caps: the caps to get the properties from - * - * Get the properties of the given caps. - * - * Returns: the properties of the caps - */ -GstProps* -gst_caps_get_props (GstCaps *caps) -{ - g_return_val_if_fail (caps != NULL, NULL); - - return caps->properties; -} - -/** - * gst_caps_has_property: - * @caps: the caps to query - * @name: the name of the property to search for - * - * Figure out whether this caps contains the requested property. - * - * Returns: true if the caps contains the property. - */ - -gboolean -gst_caps_has_property (GstCaps *caps, const gchar *name) -{ - GstProps *props = gst_caps_get_props (caps); - - return (props != NULL && - gst_props_has_property (props, name)); -} - -/** - * gst_caps_has_property_typed: - * @caps: the caps to query - * @name: the name of the property to search for - * @type: the type of the property to search for - * - * Figure out whether this caps contains the requested property, - * and whether this property is of the requested type. - * - * Returns: true if the caps contains the typed property. - */ - -gboolean -gst_caps_has_property_typed (GstCaps *caps, const gchar *name, GstPropsType type) -{ - GstProps *props = gst_caps_get_props (caps); - - return (props != NULL && - gst_props_has_property_typed (props, name, type)); -} - -/** - * gst_caps_has_fixed_property - * @caps: the caps to query - * @name: the name of the property to search for - * - * Figure out whether this caps contains the requested property, - * and whether this property is fixed. - * - * Returns: true if the caps contains the fixed property. - */ - -gboolean -gst_caps_has_fixed_property (GstCaps *caps, const gchar *name) -{ - GstProps *props = gst_caps_get_props (caps); - - return (props != NULL && - gst_props_has_fixed_property (props, name)); -} - -/** - * gst_caps_next: - * @caps: the caps to query - * - * Get the next caps of this chained caps. - * - * Returns: the next caps or NULL if the chain ended. - */ -GstCaps* -gst_caps_next (GstCaps *caps) -{ - if (caps == NULL) - return NULL; - - return caps->next; -} - -/** - * gst_caps_chain: - * @caps: a capabilty - * @...: more capabilities - * - * chains the given capabilities - * - * Returns: the new capability - */ -GstCaps* -gst_caps_chain (GstCaps *caps, ...) -{ - GstCaps *orig = caps; - va_list var_args; - - va_start (var_args, caps); - - while (caps) { - GstCaps *toadd; - - toadd = va_arg (var_args, GstCaps*); - gst_caps_append (caps, toadd); - - caps = toadd; - } - va_end (var_args); - - return orig; -} - -/** - * gst_caps_append: - * @caps: a capabilty - * @capstoadd: the capability to append - * - * Appends a capability to the existing capability. - * - * Returns: the new capability - */ -GstCaps* -gst_caps_append (GstCaps *caps, GstCaps *capstoadd) -{ - GstCaps *orig = caps; - - if (caps == NULL || caps == capstoadd) - return capstoadd; - - while (caps->next) { - caps = caps->next; - } - gst_caps_replace_sink (&caps->next, capstoadd); - - return orig; -} - -/** - * gst_caps_prepend: - * @caps: a capabilty - * @capstoadd: a capabilty to prepend - * - * prepend the capability to the list of capabilities - * - * Returns: the new capability - */ -GstCaps* -gst_caps_prepend (GstCaps *caps, GstCaps *capstoadd) -{ - GstCaps *orig = capstoadd; - - if (capstoadd == NULL) - return caps; - - g_return_val_if_fail (caps != capstoadd, caps); - - while (capstoadd->next) { - capstoadd = capstoadd->next; - } - gst_caps_replace_sink (&capstoadd->next, caps); - - return orig; -} - -/** - * gst_caps_get_by_name: - * @caps: a capabilty - * @name: the name of the capability to get - * - * Get the capability with the given name from this - * chain of capabilities. - * - * Returns: the first capability in the chain with the - * given name - */ -GstCaps* -gst_caps_get_by_name (GstCaps *caps, const gchar *name) -{ - g_return_val_if_fail (caps != NULL, NULL); - g_return_val_if_fail (name != NULL, NULL); - - while (caps) { - if (!strcmp (caps->name, name)) - return caps; - caps = caps->next; - } - - return NULL; -} - -static gboolean -gst_caps_check_compatibility_func (GstCaps *fromcaps, GstCaps *tocaps) -{ - if (fromcaps->id != tocaps->id) { - GST_CAT_DEBUG (GST_CAT_CAPS,"mime types differ (%s to %s)", - gst_caps_get_mime (fromcaps), - gst_caps_get_mime (tocaps)); - return FALSE; - } - - if (tocaps->properties) { - if (fromcaps->properties) { - return gst_props_check_compatibility (fromcaps->properties, tocaps->properties); - } - else { - GST_CAT_DEBUG (GST_CAT_CAPS,"no source caps"); - return FALSE; - } - } - else { - /* assume it accepts everything */ - GST_CAT_DEBUG (GST_CAT_CAPS,"no caps"); - return TRUE; - } -} - -/** - * gst_caps_is_always_compatible: - * @fromcaps: a #GstCaps capability to check compatibility of. - * @tocaps: the #GstCaps capability to check compatibility with. - * - * Checks if a link is always possible from fromcaps to tocaps, for all - * possible capabilities. - * - * Returns: TRUE if compatible under all circumstances, FALSE otherwise. - */ -gboolean -gst_caps_is_always_compatible (GstCaps *fromcaps, GstCaps *tocaps) -{ - if (fromcaps == NULL) { - if (tocaps == NULL) { - /* if both are NULL, they can always link. Think filesrc ! filesink */ - GST_CAT_DEBUG (GST_CAT_CAPS, "both caps NULL, compatible"); - return TRUE; - } - else { - /* if source caps are NULL, it could be sending anything, so the - * destination can't know if it can accept this. Think filesrc ! mad */ - GST_CAT_DEBUG (GST_CAT_CAPS, "source caps NULL, not guaranteed compatible"); - return FALSE; - } - } - else { - if (tocaps == NULL) { - /* if the dest caps are NULL, the element can accept anything, always, - * so they're compatible by definition. Think mad ! filesink */ - GST_CAT_DEBUG (GST_CAT_CAPS,"destination caps NULL"); - return TRUE; - } - } - - while (fromcaps) { - GstCaps *destcaps = tocaps; - /* assume caps is incompatible */ - gboolean compat = FALSE; - - while (destcaps && !compat) { - if (gst_caps_check_compatibility_func (fromcaps, destcaps)) { - compat = TRUE; - } - destcaps = destcaps->next; - } - if (!compat) - return FALSE; - - fromcaps = fromcaps->next; - } - return TRUE; -} - -static GstCaps* -gst_caps_intersect_func (GstCaps *caps1, GstCaps *caps2) -{ - GstCaps *result = NULL; - GstProps *props; - - if (caps1->id != caps2->id) { - GST_CAT_DEBUG (GST_CAT_CAPS, "mime types differ (%s to %s)", - gst_caps_get_mime (caps1), - gst_caps_get_mime (caps2)); - return NULL; - } - - if (caps1->properties == NULL) { - return gst_caps_ref (caps2); - } - if (caps2->properties == NULL) { - return gst_caps_ref (caps1); - } - - props = gst_props_intersect (caps1->properties, caps2->properties); - if (props) { - result = gst_caps_new_id ("intersect", caps1->id, props); - gst_caps_ref (result); - gst_caps_sink (result); - } - - return result; -} - -/** - * gst_caps_intersect: - * @caps1: a capability - * @caps2: a capability - * - * Make the intersection between two caps. - * - * Returns: The intersection of the two caps or NULL if the intersection - * is empty. unref the caps after use. - */ -GstCaps* -gst_caps_intersect (GstCaps *caps1, GstCaps *caps2) -{ - GstCaps *result = NULL, *walk = NULL; - - /* printing the name is not useful here since caps can be chained */ - GST_CAT_DEBUG (GST_CAT_CAPS, "intersecting caps %p and %p", caps1, caps2); - - if (caps1 == NULL) { - GST_CAT_DEBUG (GST_CAT_CAPS, "first caps is NULL, return other caps"); - return gst_caps_ref (caps2); - } - if (caps2 == NULL) { - GST_CAT_DEBUG (GST_CAT_CAPS, "second caps is NULL, return other caps"); - return gst_caps_ref (caps1); - } - - /* same caps */ - if (caps1 == caps2) { - return gst_caps_ref (caps1); - } - - while (caps1) { - GstCaps *othercaps = caps2; - - while (othercaps) { - GstCaps *intersection; - - intersection = gst_caps_intersect_func (caps1, othercaps); - - if (intersection) { - if (!result) { - walk = result = intersection; - } - else { - walk = walk->next = intersection; - } - } - othercaps = othercaps->next; - } - caps1 = caps1->next; - } - - return result; -} - -GstCaps* -gst_caps_union (GstCaps *caps1, GstCaps *caps2) -{ - GstCaps *result = NULL; - - /* printing the name is not useful here since caps can be chained */ - GST_CAT_DEBUG (GST_CAT_CAPS, "making union of caps %p and %p", caps1, caps2); - - if (caps1 == NULL) { - GST_CAT_DEBUG (GST_CAT_CAPS, "first caps is NULL, return other caps"); - return gst_caps_ref (caps2); - } - if (caps2 == NULL) { - GST_CAT_DEBUG (GST_CAT_CAPS, "second caps is NULL, return other caps"); - return gst_caps_ref (caps1); - } - - return result; -} - -/** - * gst_caps_normalize: - * @caps: a capabilty - * - * Make the normalisation of the caps. This will return a new caps - * that is equivalent to the input caps with the exception that all - * lists are unrolled. This function is useful when you want to iterate - * the caps. unref the caps after use. - * - * Returns: The normalisation of the caps. Unref after usage. - */ -GstCaps* -gst_caps_normalize (GstCaps *caps) -{ - GstCaps *result = NULL, *walk; - - if (caps == NULL) - return caps; - - GST_CAT_DEBUG (GST_CAT_CAPS, "normalizing caps %p ", caps); - - walk = caps; - - while (caps) { - GList *proplist; - - proplist = gst_props_normalize (caps->properties); - while (proplist) { - GstProps *props = (GstProps *) proplist->data; - GstCaps *newcaps = gst_caps_new_id (caps->name, caps->id, props); - - gst_caps_ref (newcaps); - gst_caps_sink (newcaps); - - if (result == NULL) - walk = result = newcaps; - else { - walk = walk->next = newcaps; - } - proplist = g_list_next (proplist); - } - caps = caps->next; - } - return result; -} - -#ifndef GST_DISABLE_LOADSAVE_REGISTRY -/** - * gst_caps_save_thyself: - * @caps: a capabilty to save - * @parent: the parent XML node pointer - * - * Save the capability into an XML representation. - * - * Returns: a new XML node pointer - */ -xmlNodePtr -gst_caps_save_thyself (GstCaps *caps, xmlNodePtr parent) -{ - xmlNodePtr subtree; - xmlNodePtr subsubtree; - - while (caps) { - subtree = xmlNewChild (parent, NULL, "capscomp", NULL); - - xmlNewChild (subtree, NULL, "name", caps->name); - xmlNewChild (subtree, NULL, "type", gst_caps_get_mime (caps)); - if (caps->properties) { - subsubtree = xmlNewChild (subtree, NULL, "properties", NULL); - - gst_props_save_thyself (caps->properties, subsubtree); - } - - caps = caps->next; - } - - return parent; -} - -/** - * gst_caps_load_thyself: - * @parent: the parent XML node pointer - * - * Load a new caps from the XML representation. - * - * Returns: a new capability - */ -GstCaps* -gst_caps_load_thyself (xmlNodePtr parent) -{ - GstCaps *result = NULL; - xmlNodePtr field = parent->xmlChildrenNode; - - while (field) { - if (!strcmp (field->name, "capscomp")) { - xmlNodePtr subfield = field->xmlChildrenNode; - GstCaps *caps; - gchar *content; - - caps = gst_mem_chunk_alloc0 (_gst_caps_chunk); -#ifndef GST_DISABLE_TRACE - gst_alloc_trace_new (_gst_caps_trace, caps); -#endif - - caps->refcount = 1; - GST_CAPS_FLAG_SET (caps, GST_CAPS_FLOATING); - caps->next = NULL; - - while (subfield) { - if (!strcmp (subfield->name, "name")) { - caps->name = xmlNodeGetContent (subfield); - } - if (!strcmp (subfield->name, "type")) { - content = xmlNodeGetContent (subfield); - caps->id = g_quark_from_string (content); - g_free (content); - } - else if (!strcmp (subfield->name, "properties")) { - GstProps *props = gst_props_load_thyself (subfield); - - gst_props_ref (props); - gst_props_sink (props); - caps->properties = props; - } - - subfield = subfield->next; - } - - result = gst_caps_append (result, caps); - } - field = field->next; - } - - return result; -} - -#endif /* GST_DISABLE_LOADSAVE_REGISTRY */ diff --git a/gst/gstcaps.h b/gst/gstcaps.h deleted file mode 100644 index 25cbd1c1af..0000000000 --- a/gst/gstcaps.h +++ /dev/null @@ -1,204 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2000 Wim Taymans - * - * gstcaps.h: Header for caps subsystem - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - - -#ifndef __GST_CAPS_H__ -#define __GST_CAPS_H__ - -#include - -G_BEGIN_DECLS - -typedef struct _GstCaps GstCaps; - -#define GST_CAPS_TRACE_NAME "GstCaps" - -extern GType _gst_caps_type; - -#define GST_TYPE_CAPS (_gst_caps_type) - -#if 0 -typedef enum { - GST_CAPS_UNUSED = (1 << 0), /* unused flag */ - GST_CAPS_FLOATING = (1 << 1) /* caps is floating */ -} GstCapsFlags; -#endif - -#define GST_CAPS(caps) ((GstCaps *)(caps)) - -#define GST_CAPS_FLAGS(caps) ((caps)->flags) -#define GST_CAPS_FLAG_IS_SET(caps,flag) (GST_CAPS_FLAGS (caps) & (flag)) -#define GST_CAPS_FLAG_SET(caps,flag) (GST_CAPS_FLAGS (caps) |= (flag)) -#define GST_CAPS_FLAG_UNSET(caps,flag) (GST_CAPS_FLAGS (caps) &= ~(flag)) - -#define GST_CAPS_REFCOUNT(caps) ((caps)->refcount) -#define GST_CAPS_PROPERTIES(caps) ((caps)->properties) -#define GST_CAPS_NEXT(caps) ((caps)->next) - -#define GST_CAPS_IS_FIXED(caps) (((caps)->properties == NULL) || \ - (GST_PROPS_IS_FIXED ((caps)->properties))) -#define GST_CAPS_IS_FLOATING(caps) (GST_CAPS_FLAG_IS_SET ((caps), GST_CAPS_FLOATING)) -#define GST_CAPS_IS_CHAINED(caps) (GST_CAPS_NEXT (caps) != NULL) - -#define GST_CAPS_NONE NULL -#define GST_CAPS_ANY (gst_caps_get_any()) - -struct _GstCaps { - /* --- public --- */ - gchar *name; /* the name of this caps */ - GQuark id; /* type id (major type) representing - the mime type, it's stored as a GQuark - for speed/space reasons */ - - guint16 flags; /* flags */ - guint refcount; - - GstProps *properties; /* properties for this capability */ - GstCaps *next; /* not with a GList for efficiency */ -}; - -/* factory macros which make it easier for plugins to instantiate */ - -#ifdef G_HAVE_ISO_VARARGS -#define GST_CAPS_NEW(name, type, ...) \ -gst_caps_new ( \ - name, \ - type, \ - gst_props_new ( \ - __VA_ARGS__, \ - NULL)) - -#define GST_CAPS_FACTORY(factoryname, ...) \ -static GstCaps* \ -factoryname (void) \ -{ \ - static GstCaps *caps = NULL; \ - if (!caps) { \ - caps = gst_caps_chain (__VA_ARGS__, NULL); \ - } \ - return gst_caps_ref(caps); \ -} -#elif defined(G_HAVE_GNUC_VARARGS) -#define GST_CAPS_NEW(name, type, a...) \ -gst_caps_new ( \ - name, \ - type, \ - gst_props_new ( \ - a, \ - NULL)) - -#define GST_CAPS_FACTORY(factoryname, a...) \ -static GstCaps* \ -factoryname (void) \ -{ \ - static GstCaps *caps = NULL; \ - if (!caps) { \ - caps = gst_caps_chain (a, NULL); \ - } \ - return gst_caps_ref(caps); \ -} -#endif - -/* get caps from a factory */ -#define GST_CAPS_GET(fact) (fact)() - - -/* initialize the subsystem */ -void _gst_caps_initialize (void); - -/* creating new caps */ -GType gst_caps_get_type (void); -GstCaps* gst_caps_new (const gchar *name, const gchar *mime, GstProps *props); -GstCaps* gst_caps_new_id (const gchar *name, const GQuark id, GstProps *props); -GstCaps* gst_caps_get_any (void); -/* replace pointer to caps, doing proper refcounting */ -void gst_caps_replace (GstCaps **oldcaps, GstCaps *newcaps); -void gst_caps_replace_sink (GstCaps **oldcaps, GstCaps *newcaps); - -/* caps lifecycle control */ -GstCaps* gst_caps_unref (GstCaps *caps); -GstCaps* gst_caps_ref (GstCaps *caps); -void gst_caps_sink (GstCaps *caps); - -/* write debug lines to the log */ -void gst_caps_debug (GstCaps *caps, const gchar *label); - -/* copy caps */ -GstCaps* gst_caps_copy (GstCaps *caps); -GstCaps* gst_caps_copy_1 (GstCaps *caps); -GstCaps* gst_caps_copy_on_write (GstCaps *caps); - -const gchar* gst_caps_get_name (GstCaps *caps); -void gst_caps_set_name (GstCaps *caps, const gchar *name); - -const gchar* gst_caps_get_mime (GstCaps *caps); -void gst_caps_set_mime (GstCaps *caps, const gchar *mime); - -GstCaps* gst_caps_set_props (GstCaps *caps, GstProps *props); -GstProps* gst_caps_get_props (GstCaps *caps); - -#ifdef G_HAVE_ISO_VARARGS -#define gst_caps_set(caps, ...) gst_props_set ((caps)->properties, __VA_ARGS__) -#define gst_caps_get(caps, ...) gst_props_get ((caps)->properties, __VA_ARGS__) -#elif defined(G_HAVE_GNUC_VARARGS) -#define gst_caps_set(caps, name, args...) gst_props_set ((caps)->properties, name, ##args) -#define gst_caps_get(caps, name, args...) gst_props_get ((caps)->properties, name, ##args) -#endif - -#define gst_caps_get_int(caps,name,res) gst_props_entry_get_int(gst_props_get_entry((caps)->properties,name),res) -#define gst_caps_get_float(caps,name,res) gst_props_entry_get_float(gst_props_get_entry((caps)->properties,name),res) -#define gst_caps_get_fourcc_int(caps,name,res) gst_props_entry_get_fourcc_int(gst_props_get_entry((caps)->properties,name),res) -#define gst_caps_get_boolean(caps,name,res) gst_props_entry_get_boolean(gst_props_get_entry((caps)->properties,name),res) -#define gst_caps_get_string(caps,name,res) gst_props_entry_get_string(gst_props_get_entry((caps)->properties,name),res) - -gboolean gst_caps_has_property (GstCaps *caps, const gchar *name); -gboolean gst_caps_has_property_typed (GstCaps *caps, const gchar *name, GstPropsType type); -gboolean gst_caps_has_fixed_property (GstCaps *caps, const gchar *name); - -GstCaps* gst_caps_get_by_name (GstCaps *caps, const gchar *name); - -/* use and construct chained caps */ -GstCaps* gst_caps_next (GstCaps *caps); -GstCaps* gst_caps_chain (GstCaps *caps, ...); -GstCaps* gst_caps_append (GstCaps *caps, GstCaps *capstoadd); -GstCaps* gst_caps_prepend (GstCaps *caps, GstCaps *capstoadd); - -/* see if fromcaps is a subset of tocaps */ -gboolean gst_caps_is_always_compatible (GstCaps *fromcaps, GstCaps *tocaps); - -/* operations on caps */ -GstCaps* gst_caps_intersect (GstCaps *caps1, GstCaps *caps2); -GstCaps* gst_caps_union (GstCaps *caps1, GstCaps *caps2); -GstCaps* gst_caps_normalize (GstCaps *caps); - -#ifndef GST_DISABLE_LOADSAVE -xmlNodePtr gst_caps_save_thyself (GstCaps *caps, xmlNodePtr parent); -GstCaps* gst_caps_load_thyself (xmlNodePtr parent); -#endif - -/* for debugging purposes */ -gchar * gst_caps_to_string (GstCaps *caps); -GstCaps * gst_caps_from_string (gchar *str); - -G_END_DECLS - -#endif /* __GST_CAPS_H__ */ diff --git a/gst/gstprops.c b/gst/gstprops.c deleted file mode 100644 index ee6549ebc4..0000000000 --- a/gst/gstprops.c +++ /dev/null @@ -1,2827 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2000 Wim Taymans - * - * gstprops.c: Properties subsystem for generic usage - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "gst_private.h" - -#include "gstinfo.h" -#include "gstprops.h" -#include "gstmemchunk.h" - -#ifndef GST_DISABLE_TRACE -/* #define GST_WITH_ALLOC_TRACE */ -#include "gsttrace.h" -static GstAllocTrace *_props_trace; -static GstAllocTrace *_entries_trace; -#endif - -GType _gst_props_type; -GType _gst_props_entry_type; - -#define GST_PROPS_ENTRY_IS_VARIABLE(a) (((GstPropsEntry*)(a))->propstype > GST_PROPS_VAR_TYPE) - -struct _GstPropsEntry { - GQuark propid; - GstPropsType propstype; - - union { - /* flat values */ - gboolean bool_data; - guint32 fourcc_data; - gint int_data; - gfloat float_data; - - /* structured values */ - struct { - GList *entries; - } list_data; - struct { - gchar *string; - } string_data; - struct { - gint min; - gint max; - } int_range_data; - struct { - gfloat min; - gfloat max; - } float_range_data; - } data; -}; - -static GstMemChunk *_gst_props_entries_chunk; -static GstMemChunk *_gst_props_chunk; - -/* transform functions */ -static void gst_props_transform_to_string (const GValue *src_value, GValue *dest_value); -static gchar * gst_props_entry_to_string (GstPropsEntry *entry); -gboolean __gst_props_parse_string (gchar *r, gchar **end, gchar **next); - -static gboolean gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2); -static GList* gst_props_list_copy (GList *propslist); - -static GstPropsEntry* gst_props_alloc_entry (void); -static inline void gst_props_entry_free (GstPropsEntry *entry); - -static void gst_props_destroy (GstProps *props); - -static gchar * -gst_props_entry_to_string (GstPropsEntry *entry) -{ - switch (entry->propstype) { - case GST_PROPS_INT_TYPE: - return g_strdup_printf ("int = %d", entry->data.int_data); - case GST_PROPS_FLOAT_TYPE: - return g_strdup_printf ("float = %g", entry->data.float_data); - break; - case GST_PROPS_FOURCC_TYPE: { - gchar fourcc[5] = { GST_FOURCC_ARGS (entry->data.fourcc_data), '\0' }; /* Do all compilers understand that? */ - if (g_ascii_isalnum(fourcc[1]) && g_ascii_isalnum(fourcc[2]) && - g_ascii_isalnum(fourcc[3]) && g_ascii_isalnum(fourcc[4])) { - return g_strdup_printf ("fourcc = %s", fourcc); - } else { - return g_strdup_printf ("fourcc = %d", entry->data.fourcc_data); - } - } - case GST_PROPS_BOOLEAN_TYPE: - return g_strdup_printf ("bool = %s", (entry->data.bool_data ? "TRUE" : "FALSE")); - case GST_PROPS_STRING_TYPE: - /* FIXME: Need to escape stuff here */ - return g_strdup_printf ("string = '%s'", entry->data.string_data.string); - case GST_PROPS_INT_RANGE_TYPE: - return g_strdup_printf ("int = [%d, %d]", entry->data.int_range_data.min, entry->data.int_range_data.max); - case GST_PROPS_FLOAT_RANGE_TYPE: - return g_strdup_printf ("float = [%g, %g]", entry->data.float_range_data.min, entry->data.float_range_data.max); - case GST_PROPS_LIST_TYPE: { - GList *walk; - GString *s; - gchar *temp; - - s = g_string_new ("list = ("); - walk = entry->data.list_data.entries; - while (walk) { - temp = gst_props_entry_to_string ((GstPropsEntry *) walk->data); - g_string_append (s, temp); - walk = walk->next; - if (walk) { - g_string_append (s, ", "); - } else { - g_string_append (s, ")"); - } - g_free (temp); - } - temp = s->str; - g_string_free (s, FALSE); - return temp; - } - default: - /* transforms always succeed */ - g_warning("corrupt property list, type==%d\n",entry->propstype); - g_assert_not_reached(); - return NULL; - } -} -/** - * gst_props_to_string: - * props: the props to convert to a string - * - * Converts a #GstProps into a readable format. This is mainly intended for - * debugging purposes. You have to free the string using g_free. - * A string converted with #gst_props_to_string can always be converted back to - * its props representation using #gst_props_from_string. - * - * Returns: A newly allocated string - */ -gchar * -gst_props_to_string (GstProps *props) -{ - GString *s; - gchar *temp; - GList *propslist; - - s = g_string_new (""); - propslist = props->properties; - while (propslist) { - GstPropsEntry *entry = (GstPropsEntry *)propslist->data; - const gchar *name = g_quark_to_string (entry->propid); - - temp = gst_props_entry_to_string (entry); - propslist = g_list_next (propslist); - if (temp) { - if (propslist) { - g_string_append_printf (s, "%s:%s, ", name, temp); - } else { - g_string_append_printf (s, "%s:%s", name, temp); - } - g_free (temp); - } - } - temp = s->str; - g_string_free (s, FALSE); - - return temp; -} -static void -gst_props_transform_to_string (const GValue *src_value, GValue *dest_value) -{ - GstProps *props = g_value_peek_pointer (src_value); - - if (props) - dest_value->data[0].v_pointer = gst_props_to_string (props); -} -/* - * r will still point to the string. if end == next, the string will not be - * null-terminated. In all other cases it will be. - * end = pointer to char behind end of string, next = pointer to start of - * unread data. - * THIS FUNCTION MODIFIES THE STRING AND DETECTS INSIDE A NONTERMINATED STRING - */ -gboolean -__gst_props_parse_string (gchar *r, gchar **end, gchar **next) -{ - gchar *w; - gchar c = '\0'; - - w = r; - if (*r == '\'' || *r == '\"') { - c = *r; - r++; - } - - for (;;r++) { - if (*r == '\0') { - if (c) { - goto error; - } else { - goto found; - } - } - - if (*r == '\\') { - r++; - if (*r == '\0') - goto error; - *w++ = *r; - continue; - } - - if (*r == c) { - r++; - if (*r == '\0') - goto found; - break; - } - - if (!c) { - if (g_ascii_isspace (*r)) - break; - /* this needs to be escaped */ - if (*r == ',' || *r == ')' || *r == ']' || *r == ':' || - *r == ';' || *r == '(' || *r == '[') - break; - } - *w++ = *r; - } - -found: - while (g_ascii_isspace (*r)) r++; - if (w != r) - *w++ = '\0'; - *end = w; - *next = r; - return TRUE; - -error: - return FALSE; -} -static GstPropsEntry * -gst_props_entry_from_string_no_name (gchar *s, gchar **after, gboolean has_type) -{ - GstPropsEntry *entry; - gchar org = '\0'; - gchar *end, *next, *check = s; - GstPropsType type = GST_PROPS_INVALID_TYPE; - /* [TYPE=]VALUE */ - /* - * valid type identifiers case insensitive: - * INT: "i", "int" - * FLOAT: "f", "float" - * FOURCC: "4", "fourcc" - * BOOLEAN: "b", "bool", "boolean" - * STRING: "s", "str", "string" - * lists/ranges are identified by the value - */ - if (g_ascii_tolower (s[0]) == 'i') { - type = GST_PROPS_INT_TYPE; - if (g_ascii_tolower (s[1]) == 'n' && g_ascii_tolower (s[2]) == 't') { - check = s + 3; - } else { - check = s + 1; - } - } else if (g_ascii_tolower (s[0]) == 'f') { - type = GST_PROPS_FLOAT_TYPE; - if (g_ascii_tolower (s[1]) == 'l' && g_ascii_tolower (s[2]) == 'o' && - g_ascii_tolower (s[3]) == 'a' && g_ascii_tolower (s[4]) == 't') { - check = s + 5; - } else if (g_ascii_tolower (s[1]) == 'o' && g_ascii_tolower (s[2]) == 'u' && - g_ascii_tolower (s[3]) == 'r' && g_ascii_tolower (s[4]) == 'c' && - g_ascii_tolower (s[5]) == 'c') { - check = s + 6; - type = GST_PROPS_FOURCC_TYPE; - } else { - check = s + 1; - } - } else if (g_ascii_tolower (s[0]) == '4') { - type = GST_PROPS_FOURCC_TYPE; - check = s + 1; - } else if (g_ascii_tolower (s[0]) == 'b') { - type = GST_PROPS_BOOLEAN_TYPE; - if (g_ascii_tolower (s[1]) == 'o' && g_ascii_tolower (s[2]) == 'o' && - g_ascii_tolower (s[3]) == 'l') { - if (g_ascii_tolower (s[4]) == 'e' && g_ascii_tolower (s[5]) == 'a' && - g_ascii_tolower (s[6]) == 'n') { - check = s + 7; - } else { - check = s + 4; - } - } else { - check = s + 1; - } - } else if (g_ascii_tolower (s[0]) == 's') { - type = GST_PROPS_STRING_TYPE; - if (g_ascii_tolower (s[1]) == 't' && g_ascii_tolower (s[2]) == 'r') { - if (g_ascii_tolower (s[3]) == 'i' && g_ascii_tolower (s[4]) == 'n' && - g_ascii_tolower (s[5]) == 'g') { - check = s + 6; - } else { - check = s + 3; - } - } else { - check = s + 1; - } - } else if (g_ascii_tolower (s[0]) == 'l') { - type = GST_PROPS_LIST_TYPE; - if (g_ascii_tolower (s[1]) == 'i' && g_ascii_tolower (s[2]) == 's' && - g_ascii_tolower (s[3]) == 't') { - check = s + 4; - } else { - check = s + 1; - } - } - while (g_ascii_isspace(*check)) check++; - if (*check != '=') { - if (has_type) goto error; - type = GST_PROPS_INVALID_TYPE; - check = s; - } else { - check++; - while (g_ascii_isspace(*check)) check++; - } - /* ok. Now type is GST_PROPS_INVALID_TYPE for guessing or the selected type. - check points to the string containing the contents. s still is the beginning - of the string */ - if (type == GST_PROPS_INVALID_TYPE || type == GST_PROPS_INT_TYPE || type == GST_PROPS_FOURCC_TYPE) { - glong l; - l = strtol (check, &end, 0); - while (g_ascii_isspace (*end)) end++; - if (*end == '\0' || *end == ',' || *end == ';' || *end == ')' || *end == ']') { - *after = end; - entry = gst_props_alloc_entry (); - if (type == GST_PROPS_FOURCC_TYPE) { - entry->propstype = GST_PROPS_FOURCC_TYPE; - entry->data.fourcc_data = l; - } else { - entry->propstype = GST_PROPS_INT_TYPE; - entry->data.int_data = l; - } - return entry; - } - } - if (type == GST_PROPS_INVALID_TYPE || type == GST_PROPS_FLOAT_TYPE) { - gdouble d; - d = g_ascii_strtod (check, &end); - while (g_ascii_isspace (*end)) end++; - if (*end == '\0' || *end == ',' || *end == ';' || *end == ')' || *end == ']') { - *after = end; - entry = gst_props_alloc_entry (); - entry->propstype = GST_PROPS_FLOAT_TYPE; - entry->data.float_data = d; - return entry; - } - } - if ((type == GST_PROPS_INVALID_TYPE || type == GST_PROPS_FLOAT_TYPE || - type == GST_PROPS_INT_TYPE) && *check == '[') { - GstPropsEntry *min, *max; - check++; - if (g_ascii_isspace (*check)) check++; - min = gst_props_entry_from_string_no_name (check, &check, FALSE); - if (!min) goto error; - if (*check++ != ',') goto error; - if (g_ascii_isspace (*check)) check++; - max = gst_props_entry_from_string_no_name (check, &check, FALSE); - if (!max || *check++ != ']') { - gst_props_entry_destroy (min); - goto error; - } - if (g_ascii_isspace (*check)) check++; - entry = gst_props_alloc_entry (); - entry->propstype = GST_PROPS_FLOAT_RANGE_TYPE; - if (min->propstype == GST_PROPS_INT_TYPE && max->propstype == GST_PROPS_INT_TYPE && type != GST_PROPS_FLOAT_TYPE) { - entry->propstype = GST_PROPS_INT_RANGE_TYPE; - entry->data.int_range_data.min = min->data.int_data; - entry->data.int_range_data.max = max->data.int_data; - } else if (min->propstype == GST_PROPS_INT_TYPE && max->propstype == GST_PROPS_INT_TYPE && type == GST_PROPS_FLOAT_TYPE) { - entry->data.float_range_data.min = min->data.int_data; - entry->data.float_range_data.max = max->data.int_data; - } else if (min->propstype == GST_PROPS_INT_TYPE && max->propstype == GST_PROPS_FLOAT_TYPE && type != GST_PROPS_INT_TYPE) { - entry->data.float_range_data.min = min->data.int_data; - entry->data.float_range_data.max = max->data.float_data; - } else if (min->propstype == GST_PROPS_FLOAT_TYPE && max->propstype == GST_PROPS_INT_TYPE && type != GST_PROPS_INT_TYPE) { - entry->data.float_range_data.min = min->data.float_data; - entry->data.float_range_data.max = max->data.int_data; - } else if (min->propstype == GST_PROPS_FLOAT_TYPE && max->propstype == GST_PROPS_FLOAT_TYPE && type != GST_PROPS_INT_TYPE) { - entry->data.float_range_data.min = min->data.float_data; - entry->data.float_range_data.max = max->data.float_data; - } else { - gst_props_entry_destroy (min); - gst_props_entry_destroy (max); - gst_props_entry_destroy (entry); - goto error; - } - gst_props_entry_destroy (min); - gst_props_entry_destroy (max); - *after = check; - return entry; - } - if ((type == GST_PROPS_INVALID_TYPE || type == GST_PROPS_LIST_TYPE) && *check == '(') { - GstPropsEntry *next; - check++; - entry = gst_props_alloc_entry (); - entry->propstype = GST_PROPS_LIST_TYPE; - entry->data.list_data.entries = NULL; - do { - while (g_ascii_isspace (*check)) check++; - next = gst_props_entry_from_string_no_name (check, &check, FALSE); - /* use g_list_append to keep original order */ - entry->data.list_data.entries = g_list_append (entry->data.list_data.entries, next); - if (*check == ')') break; - if (*check++ != ',') goto error; - } while (TRUE); - check++; - while (g_ascii_isspace (*check)) check++; - *after = check; - return entry; - } - if (!__gst_props_parse_string (check, &next, &end)) - goto error; - if (next == end) { - org = *end; - *end = '\0'; - } - if (type == GST_PROPS_INVALID_TYPE || type == GST_PROPS_BOOLEAN_TYPE) { - if (!(g_ascii_strcasecmp (check, "true") && - g_ascii_strcasecmp (check, "yes"))) { - entry = gst_props_alloc_entry (); - entry->propstype = GST_PROPS_BOOLEAN_TYPE; - entry->data.bool_data = TRUE; - goto string_out; - } - if (!(g_ascii_strcasecmp (check, "false") && - g_ascii_strcasecmp (check, "no"))) { - entry = gst_props_alloc_entry (); - entry->propstype = GST_PROPS_BOOLEAN_TYPE; - entry->data.bool_data = FALSE; - goto string_out; - } - } - if (type == GST_PROPS_FOURCC_TYPE) { - gint l = strlen (check); - entry = gst_props_alloc_entry (); - entry->propstype = GST_PROPS_FOURCC_TYPE; - entry->data.fourcc_data = GST_MAKE_FOURCC(l > 0 ? check[0] : ' ', - l > 1 ? check[1] : ' ', - l > 2 ? check[2] : ' ', - l > 3 ? check[3] : ' '); - goto string_out; - } - if (type == GST_PROPS_INVALID_TYPE || type == GST_PROPS_STRING_TYPE) { - entry = gst_props_alloc_entry (); - entry->propstype = GST_PROPS_STRING_TYPE; - entry->data.string_data.string = g_strdup (check); - goto string_out; - } -error: - return NULL; - -string_out: - *next = org; - *after = end; - return entry; -} -static GstPropsEntry * -gst_props_entry_from_string (gchar *str, gchar **after) -{ - /* NAME[:TYPE]=VALUE */ - gchar *name; - gchar *s, *del; - gboolean has_type = FALSE; - GstPropsEntry *entry; - - name = s = str; - while (g_ascii_isalnum (*s) || *s == '_' || *s == '-') s++; - del = s; - while (g_ascii_isspace (*s)) s++; - if (!(*s == '=' || *s == ':')) return NULL; - if (*s == ':') has_type = TRUE; - s++; - while (g_ascii_isspace (*s)) s++; - *del = '\0'; - - entry = gst_props_entry_from_string_no_name (s, &s, has_type); - if (entry) { - entry->propid = g_quark_from_string (name); - *after = s; - } - - return entry; -} -GstProps * -__gst_props_from_string_func (gchar *s, gchar **end, gboolean caps) -{ - GstProps *props; - GstPropsEntry *entry; - - props = gst_props_empty_new (); - for (;;) { - entry = gst_props_entry_from_string (s, &s); - if (!entry) goto error; - gst_props_add_entry (props, entry); - while (g_ascii_isspace (*s)) s++; - if ((*s == '\0') || /* end */ - (caps && (*s == ';'))) /* another caps */ - break; - if (!(*s == ',')) goto error; - s++; - while (g_ascii_isspace (*s)) s++; - } - - *end = s; - return props; -error: - gst_props_unref (props); - return NULL; -} -/** - * gst_props_from_string: - * str: the str to convert into props - * - * Tries to convert a string into a #GstProps. This is mainly intended for - * debugging purposes. The returned props are floating. - * - * Returns: A floating props or NULL if the string couldn't be converted - */ -GstProps * -gst_props_from_string (gchar *str) -{ - /* - * format to parse is ENTRY[,ENTRY ...] - * ENTRY is NAME[:TYPE]=VALUE - * NAME is alphanumeric - * TYPE is a list of values - * VALUE is evil, see gst_props_entry_to_string - */ - GstProps *props; - gchar *temp, *org; - - g_return_val_if_fail (str != NULL, NULL); - - org = g_strdup (str); - props = __gst_props_from_string_func (org, &temp, FALSE); - g_free (org); - - return props; -} - -void -_gst_props_initialize (void) -{ - _gst_props_entries_chunk = gst_mem_chunk_new ("GstPropsEntries", - sizeof (GstPropsEntry), sizeof (GstPropsEntry) * 1024, - G_ALLOC_AND_FREE); - - _gst_props_chunk = gst_mem_chunk_new ("GstProps", - sizeof (GstProps), sizeof (GstProps) * 256, - G_ALLOC_AND_FREE); - - _gst_props_type = g_boxed_type_register_static ("GstProps", - (GBoxedCopyFunc) gst_props_ref, - (GBoxedFreeFunc) gst_props_unref); - - g_value_register_transform_func (_gst_props_type, G_TYPE_STRING, - gst_props_transform_to_string); - - _gst_props_entry_type = g_boxed_type_register_static ("GstPropsEntry", - (GBoxedCopyFunc) gst_props_entry_copy, - (GBoxedFreeFunc) gst_props_entry_destroy); - -#ifndef GST_DISABLE_TRACE - _props_trace = gst_alloc_trace_register (GST_PROPS_TRACE_NAME); - _entries_trace = gst_alloc_trace_register (GST_PROPS_ENTRY_TRACE_NAME); -#endif -} - -static void -gst_props_debug_entry (GstPropsEntry *entry) -{ - /* unused when debugging is disabled */ - G_GNUC_UNUSED const gchar *name = g_quark_to_string (entry->propid); - - switch (entry->propstype) { - case GST_PROPS_INT_TYPE: - GST_CAT_DEBUG (GST_CAT_PROPERTIES, "%p: %s: int %d", entry, name, entry->data.int_data); - break; - case GST_PROPS_FLOAT_TYPE: - GST_CAT_DEBUG (GST_CAT_PROPERTIES, "%p: %s: float %g", entry, name, entry->data.float_data); - break; - case GST_PROPS_FOURCC_TYPE: - GST_CAT_DEBUG (GST_CAT_PROPERTIES, "%p: %s: fourcc %c%c%c%c", entry, name, - (entry->data.fourcc_data>>0)&0xff, - (entry->data.fourcc_data>>8)&0xff, - (entry->data.fourcc_data>>16)&0xff, - (entry->data.fourcc_data>>24)&0xff); - break; - case GST_PROPS_BOOLEAN_TYPE: - GST_CAT_DEBUG (GST_CAT_PROPERTIES, "%p: %s: bool %d", entry, name, entry->data.bool_data); - break; - case GST_PROPS_STRING_TYPE: - GST_CAT_DEBUG (GST_CAT_PROPERTIES, "%p: %s: string \"%s\"", entry, name, entry->data.string_data.string); - break; - case GST_PROPS_INT_RANGE_TYPE: - GST_CAT_DEBUG (GST_CAT_PROPERTIES, "%p: %s: int range %d-%d", entry, name, entry->data.int_range_data.min, - entry->data.int_range_data.max); - break; - case GST_PROPS_FLOAT_RANGE_TYPE: - GST_CAT_DEBUG (GST_CAT_PROPERTIES, "%p: %s: float range %g-%g", entry, name, entry->data.float_range_data.min, - entry->data.float_range_data.max); - break; - case GST_PROPS_LIST_TYPE: - GST_CAT_DEBUG (GST_CAT_PROPERTIES, "%p: [list]", entry); - g_list_foreach (entry->data.list_data.entries, (GFunc) gst_props_debug_entry, NULL); - break; - default: - g_warning ("unknown property type %d at %p", entry->propstype, entry); - break; - } -} - -static gint -props_compare_func (gconstpointer a, - gconstpointer b) -{ - GstPropsEntry *entry1 = (GstPropsEntry *)a; - GstPropsEntry *entry2 = (GstPropsEntry *)b; - - return (entry1->propid - entry2->propid); -} - -static gint -props_find_func (gconstpointer a, - gconstpointer b) -{ - GstPropsEntry *entry2 = (GstPropsEntry *)a; - GQuark quark = (GQuark) GPOINTER_TO_INT (b); - - return (quark - entry2->propid); -} - -/* This is implemented as a huge macro because we cannot pass - * va_list variables by reference on some architectures. - */ -static inline GstPropsType -gst_props_type_sanitize (GstPropsType type) -{ - switch (type) { - case GST_PROPS_INT_TYPE: - case GST_PROPS_INT_RANGE_TYPE: - return GST_PROPS_INT_TYPE; - case GST_PROPS_FLOAT_TYPE: - case GST_PROPS_FLOAT_RANGE_TYPE: - return GST_PROPS_FLOAT_TYPE; - case GST_PROPS_FOURCC_TYPE: - case GST_PROPS_BOOLEAN_TYPE: - case GST_PROPS_STRING_TYPE: - return type; - case GST_PROPS_LIST_TYPE: - case GST_PROPS_GLIST_TYPE: - return GST_PROPS_LIST_TYPE; - case GST_PROPS_END_TYPE: - case GST_PROPS_INVALID_TYPE: - case GST_PROPS_VAR_TYPE: - case GST_PROPS_LAST_TYPE: - break; - } - g_assert_not_reached (); - return GST_PROPS_END_TYPE; -} -#define GST_PROPS_ENTRY_FILL(entry, var_args) \ -G_STMT_START { \ - entry->propstype = va_arg (var_args, GstPropsType); \ - if (entry->propstype == GST_PROPS_LIST_TYPE) { \ - GList *_list = NULL; \ - GstPropsEntry *_cur = NULL; /* initialize so gcc doesn't complain */ \ - GstPropsType _cur_type; \ - GstPropsType _type = va_arg (var_args, GstPropsType); \ - _cur_type = _type; \ - _type = gst_props_type_sanitize (_type); \ - while (_cur_type != GST_PROPS_END_TYPE) { \ - _cur = gst_props_alloc_entry (); \ - _cur->propid = entry->propid; \ - _cur->propstype = _cur_type; \ - _cur_type = gst_props_type_sanitize (_cur_type); \ - g_assert (_cur_type == _type); \ - GST_PROPS_ENTRY_FILL_DATA(_cur, var_args); \ - if (_cur_type == GST_PROPS_INT_TYPE) { \ - _list = gst_props_add_to_int_list (_list, _cur); \ - } else { \ - _list = g_list_prepend (_list, _cur); \ - } \ - _cur_type = va_arg (var_args, GstPropsType); \ - } \ - if (_list && g_list_next (_list)) { \ - entry->data.list_data.entries = _list; \ - } else { \ - entry->propstype = _cur->propstype; \ - entry->data = _cur->data; \ - gst_props_entry_free (_cur); \ - } \ - } else { \ - GST_PROPS_ENTRY_FILL_DATA(entry, var_args); \ - } \ -} G_STMT_END - -#define GST_PROPS_ENTRY_FILL_DATA(entry, var_args) \ -G_STMT_START { \ - switch (entry->propstype) { \ - case GST_PROPS_INT_TYPE: \ - entry->data.int_data = va_arg (var_args, gint); \ - break; \ - case GST_PROPS_INT_RANGE_TYPE: \ - entry->data.int_range_data.min = va_arg (var_args, gint); \ - entry->data.int_range_data.max = va_arg (var_args, gint); \ - break; \ - case GST_PROPS_FLOAT_TYPE: \ - entry->data.float_data = va_arg (var_args, gdouble); \ - break; \ - case GST_PROPS_FLOAT_RANGE_TYPE: \ - entry->data.float_range_data.min = va_arg (var_args, gdouble); \ - entry->data.float_range_data.max = va_arg (var_args, gdouble); \ - break; \ - case GST_PROPS_FOURCC_TYPE: \ - entry->data.fourcc_data = va_arg (var_args, gulong); \ - break; \ - case GST_PROPS_BOOLEAN_TYPE: \ - entry->data.bool_data = va_arg (var_args, gboolean); \ - break; \ - case GST_PROPS_STRING_TYPE: \ - entry->data.string_data.string = g_strdup (va_arg (var_args, gchar*)); \ - break; \ - case GST_PROPS_GLIST_TYPE: \ - entry->propstype = GST_PROPS_LIST_TYPE; \ - entry->data.list_data.entries = g_list_copy (va_arg (var_args, GList*)); \ - break; \ - case GST_PROPS_END_TYPE: \ - break; \ - default: \ - g_warning("attempt to set invalid props type\n"); \ - break; \ - } \ -} G_STMT_END - - -#define GST_PROPS_ENTRY_READ(entry, var_args, safe, result) \ -G_STMT_START { \ - \ - *result = TRUE; \ - \ - if (safe) { \ - GstPropsType propstype = va_arg (var_args, GstPropsType); \ - if (propstype != entry->propstype) { \ - *result = FALSE; \ - } \ - } \ - if (*result) { \ - switch (entry->propstype) { \ - case GST_PROPS_INT_TYPE: \ - *(va_arg (var_args, gint*)) = entry->data.int_data; \ - break; \ - case GST_PROPS_INT_RANGE_TYPE: \ - *(va_arg (var_args, gint*)) = entry->data.int_range_data.min; \ - *(va_arg (var_args, gint*)) = entry->data.int_range_data.max; \ - break; \ - case GST_PROPS_FLOAT_TYPE: \ - *(va_arg (var_args, gfloat*)) = entry->data.float_data; \ - break; \ - case GST_PROPS_FLOAT_RANGE_TYPE: \ - *(va_arg (var_args, gfloat*)) = entry->data.float_range_data.min; \ - *(va_arg (var_args, gfloat*)) = entry->data.float_range_data.max; \ - break; \ - case GST_PROPS_FOURCC_TYPE: \ - *(va_arg (var_args, guint32*)) = entry->data.fourcc_data; \ - break; \ - case GST_PROPS_BOOLEAN_TYPE: \ - *(va_arg (var_args, gboolean*)) = entry->data.bool_data; \ - break; \ - case GST_PROPS_STRING_TYPE: \ - *(va_arg (var_args, gchar**)) = entry->data.string_data.string; \ - break; \ - case GST_PROPS_LIST_TYPE: \ - *(va_arg (var_args, GList**)) = entry->data.list_data.entries; \ - break; \ - case GST_PROPS_END_TYPE: \ - break; \ - default: \ - *result = FALSE; \ - break; \ - } \ - } \ -} G_STMT_END - -static GstPropsEntry* -gst_props_alloc_entry (void) -{ - GstPropsEntry *entry; - - entry = gst_mem_chunk_alloc (_gst_props_entries_chunk); -#ifndef GST_DISABLE_TRACE - gst_alloc_trace_new (_entries_trace, entry); -#endif - - GST_CAT_LOG (GST_CAT_PROPERTIES, "new entry %p", entry); - - return entry; -} - -static void -gst_props_entry_clean (GstPropsEntry *entry) -{ - switch (entry->propstype) { - case GST_PROPS_STRING_TYPE: - g_free (entry->data.string_data.string); - break; - case GST_PROPS_LIST_TYPE: - g_list_foreach (entry->data.list_data.entries, (GFunc) gst_props_entry_destroy, NULL); - g_list_free (entry->data.list_data.entries); - break; - default: - break; - } -} -static inline void -gst_props_entry_free (GstPropsEntry *entry) -{ -#ifdef USE_POISONING - memset (entry, 0xff, sizeof(*entry)); -#endif - gst_mem_chunk_free (_gst_props_entries_chunk, entry); -#ifndef GST_DISABLE_TRACE - gst_alloc_trace_free (_entries_trace, entry); -#endif -} -/** - * gst_props_entry_destroy: - * @entry: the entry to destroy - * - * Free the given propsentry - */ -void -gst_props_entry_destroy (GstPropsEntry *entry) -{ - if (!entry) return; - - GST_CAT_LOG (GST_CAT_PROPERTIES, "destroy entry %p", entry); - - gst_props_entry_clean (entry); - - gst_props_entry_free (entry); -} - -GType -gst_props_get_type (void) -{ - return _gst_props_type; -} - -/** - * gst_props_empty_new: - * - * Create a new empty property. - * - * Returns: the new property - */ -GstProps* -gst_props_empty_new (void) -{ - GstProps *props; - - props = gst_mem_chunk_alloc (_gst_props_chunk); -#ifndef GST_DISABLE_TRACE - gst_alloc_trace_new (_props_trace, props); -#endif - - GST_CAT_LOG (GST_CAT_PROPERTIES, "new %p", props); - - props->properties = NULL; - props->refcount = 1; - GST_PROPS_FLAG_SET (props, GST_PROPS_FLOATING); - GST_PROPS_FLAG_SET (props, GST_PROPS_FIXED); - - return props; -} - -/** - * gst_props_replace: - * @oldprops: the props to take replace - * @newprops: the props to take replace - * - * Replace the pointer to the props, doing proper - * refcounting. - */ -void -gst_props_replace (GstProps **oldprops, GstProps *newprops) -{ - if (*oldprops != newprops) { - if (newprops) gst_props_ref (newprops); - if (*oldprops) gst_props_unref (*oldprops); - - *oldprops = newprops; - } -} - -/** - * gst_props_replace_sink: - * @oldprops: the props to take replace - * @newprops: the props to take replace - * - * Replace the pointer to the props and take ownership. - */ -void -gst_props_replace_sink (GstProps **oldprops, GstProps *newprops) -{ - gst_props_replace (oldprops, newprops); - gst_props_sink (newprops); -} - -/** - * gst_props_add_entry: - * @props: the property to add the entry to - * @entry: the entry to add - * - * Addes the given propsentry to the props - */ -void -gst_props_add_entry (GstProps *props, GstPropsEntry *entry) -{ - g_return_if_fail (props); - g_return_if_fail (entry); - - /* only variable properties can change the fixed flag */ - if (GST_PROPS_IS_FIXED (props) && GST_PROPS_ENTRY_IS_VARIABLE (entry)) { - GST_PROPS_FLAG_UNSET (props, GST_PROPS_FIXED); - } - props->properties = g_list_insert_sorted (props->properties, entry, props_compare_func); -} - -static void -gst_props_remove_entry_by_id (GstProps *props, GQuark propid) -{ - GList *properties; - gboolean found; - - /* assume fixed */ - GST_PROPS_FLAG_SET (props, GST_PROPS_FIXED); - - found = FALSE; - - properties = props->properties; - while (properties) { - GList *current = properties; - GstPropsEntry *lentry = (GstPropsEntry *) current->data; - - properties = g_list_next (properties); - - if (lentry->propid == propid) { - found = TRUE; - props->properties = g_list_delete_link (props->properties, current); - gst_props_entry_destroy (lentry); - } - else if (GST_PROPS_ENTRY_IS_VARIABLE (lentry)) { - GST_PROPS_FLAG_UNSET (props, GST_PROPS_FIXED); - /* no need to check for further variable entries - * if we already removed the entry */ - if (found) - break; - } - } -} -/** - * gst_props_remove_entry: - * @props: the property to remove the entry from - * @entry: the entry to remove - * - * Removes the given propsentry from the props. - */ -void -gst_props_remove_entry (GstProps *props, GstPropsEntry *entry) -{ - g_return_if_fail (props != NULL); - g_return_if_fail (entry != NULL); - - gst_props_remove_entry_by_id (props, entry->propid); -} - -/** - * gst_props_remove_entry_by_name: - * @props: the property to remove the entry from - * @name: the name of the entry to remove - * - * Removes the propsentry with the given name from the props. - */ -void -gst_props_remove_entry_by_name (GstProps *props, const gchar *name) -{ - GQuark quark; - - g_return_if_fail (props != NULL); - g_return_if_fail (name != NULL); - - quark = g_quark_from_string (name); - gst_props_remove_entry_by_id (props, quark); -} - -/** - * gst_props_new: - * @firstname: the first property name - * @...: the property values - * - * Create a new property from the given key/value pairs - * - * Returns: the new property - */ -GstProps* -gst_props_new (const gchar *firstname, ...) -{ - GstProps *props; - va_list var_args; - - va_start (var_args, firstname); - - props = gst_props_newv (firstname, var_args); - - va_end (var_args); - - return props; -} - -/** - * gst_props_debug: - * @props: the props to debug - * - * Dump the contents of the given properties into the DEBUG log. - */ -void -gst_props_debug (GstProps *props) -{ - if (!props) { - GST_CAT_DEBUG (GST_CAT_PROPERTIES, "props (null)"); - return; - } - - GST_CAT_DEBUG (GST_CAT_PROPERTIES, "props %p, refcount %d, flags %d", - props, props->refcount, props->flags); - - g_list_foreach (props->properties, (GFunc) gst_props_debug_entry, NULL); -} - -/** - * gst_props_merge_int_entries: - * @newentry: the new entry - * @oldentry: an old entry - * - * Tries to merge oldentry into newentry, if there is a simpler single entry which represents - * - * Assumes that the entries are either ints or int ranges. - * - * Returns: TRUE if the entries were merged, FALSE otherwise. - */ -static gboolean -gst_props_merge_int_entries(GstPropsEntry *newentry, GstPropsEntry *oldentry) -{ - gint new_min, new_max, old_min, old_max; - gboolean can_merge = FALSE; - - if (newentry->propstype == GST_PROPS_INT_TYPE) { - new_min = newentry->data.int_data; - new_max = newentry->data.int_data; - } else { - new_min = newentry->data.int_range_data.min; - new_max = newentry->data.int_range_data.max; - } - - if (oldentry->propstype == GST_PROPS_INT_TYPE) { - old_min = oldentry->data.int_data; - old_max = oldentry->data.int_data; - } else { - old_min = oldentry->data.int_range_data.min; - old_max = oldentry->data.int_range_data.max; - } - - /* Put range which starts lower into (new_min, new_max) */ - if (old_min < new_min) { - gint tmp; - tmp = old_min; - old_min = new_min; - new_min = tmp; - tmp = old_max; - old_max = new_max; - new_max = tmp; - } - - /* new_min is min of either entry - second half of the following conditional */ - /* is to avoid overflow problems. */ - if (new_max >= old_min - 1 && old_min - 1 < old_min) { - /* ranges overlap, or are adjacent. Pick biggest maximum. */ - can_merge = TRUE; - if (old_max > new_max) new_max = old_max; - } - - if (can_merge) { - if (new_min == new_max) { - newentry->propstype = GST_PROPS_INT_TYPE; - newentry->data.int_data = new_min; - } else { - newentry->propstype = GST_PROPS_INT_RANGE_TYPE; - newentry->data.int_range_data.min = new_min; - newentry->data.int_range_data.max = new_max; - } - } - return can_merge; -} - -/** - * gst_props_add_to_int_list: - * @entries: the existing list of entries - * @entry: the new entry to add to the list - * - * Add an integer property to a list of properties, removing duplicates - * and merging ranges. - * - * Assumes that the existing list is in simplest form, contains - * only ints and int ranges, and that the new entry is an int or - * an int range. - * - * Returns: a pointer to a list with the new entry added. - */ -static GList* -gst_props_add_to_int_list (GList *entries, GstPropsEntry *newentry) -{ - GList *i; - - i = entries; - while (i) { - GstPropsEntry *oldentry = (GstPropsEntry *)(i->data); - gboolean merged = gst_props_merge_int_entries(newentry, oldentry); - - if (merged) { - /* replace the existing one with the merged one */ - gst_props_entry_destroy (oldentry); - - entries = g_list_remove_link (entries, i); - g_list_free_1 (i); - - /* start again: it's possible that this change made an earlier entry */ - /* mergeable, and the pointer is now invalid anyway. */ - i = entries; - } - - i = g_list_next (i); - } - - return g_list_prepend (entries, newentry); -} - -GType -gst_props_entry_get_type (void) -{ - return _gst_props_entry_type; -} - -#define GST_PROPS_ENTRY_NEW(entry, name,var_args) \ -G_STMT_START { \ - entry = gst_props_alloc_entry (); \ - entry->propid = g_quark_from_string (name); \ - GST_PROPS_ENTRY_FILL (entry, var_args); \ -} G_STMT_END -static GstPropsEntry* -gst_props_entry_newv (const gchar *name, va_list var_args) -{ - GstPropsEntry *entry; - - GST_PROPS_ENTRY_NEW (entry, name, var_args); - - return entry; -} - -/** - * gst_props_entry_new: - * @name: the name of the props entry - * @...: the value of the entry - * - * Create a new property entry with the given key/value. - * - * Returns: the new entry. - */ -GstPropsEntry* -gst_props_entry_new (const gchar *name, ...) -{ - va_list var_args; - GstPropsEntry *entry; - - va_start (var_args, name); - entry = gst_props_entry_newv (name, var_args); - va_end (var_args); - - return entry; -} - -/** - * gst_props_newv: - * @firstname: the first property name - * @var_args: the property values - * - * Create a new property from the list of entries. - * - * Returns: the new property created from the list of entries - */ -GstProps* -gst_props_newv (const gchar *firstname, va_list var_args) -{ - GstProps *props; - const gchar *prop_name; - - if (firstname == NULL) - return NULL; - - props = gst_props_empty_new (); - - prop_name = firstname; - - /* properties */ - while (prop_name) { - GstPropsEntry *entry; - - GST_PROPS_ENTRY_NEW (entry, prop_name, var_args); - gst_props_add_entry (props, entry); - - prop_name = va_arg (var_args, gchar*); - } - - return props; -} - -/** - * gst_props_set: - * @props: the props to modify - * @name: the name of the entry to modify - * @...: The prop entry. - * - * Modifies the value of the given entry in the props struct. - * For the optional args, use GST_PROPS_FOO, where FOO is INT, - * STRING, etc. This macro expands to a variable number of arguments, - * hence the lack of precision in the function prototype. No - * terminating NULL is necessary as only one property can be changed. - * - * Returns: the new modified property structure. - */ -GstProps* -gst_props_set (GstProps *props, const gchar *name, ...) -{ - GQuark quark; - GList *properties; - va_list var_args; - gboolean found; - gboolean was_fixed; - - g_return_val_if_fail (props != NULL, NULL); - - found = FALSE; - was_fixed = GST_PROPS_IS_FIXED (props); - GST_PROPS_FLAG_SET (props, GST_PROPS_FIXED); - - quark = g_quark_from_string (name); - /* this looks a little complicated but the idea is to get - * out of the loop ASAP. Changing the entry to a variable - * property immediatly marks the props as non-fixed. - * changing the entry to fixed when the props was fixed - * does not change the props and we can get out of the loop - * as well. - * When changing the entry to a fixed entry, we need to - * see if all entries are fixed before we can decide the props - */ - properties = props->properties; - while (properties) { - GstPropsEntry *entry; - - entry = (GstPropsEntry *) properties->data; - - if (entry->propid == quark) { - found = TRUE; - - va_start (var_args, name); - gst_props_entry_clean (entry); - GST_PROPS_ENTRY_FILL (entry, var_args); - va_end (var_args); - - /* if the props was fixed and we changed this entry - * with a fixed entry, we can stop now as the global - * props flag cannot change */ - if (was_fixed && !GST_PROPS_ENTRY_IS_VARIABLE (entry)) - break; - /* if we already found a non fixed entry we can exit */ - if (!GST_PROPS_IS_FIXED (props)) - break; - /* if the entry is variable, we'll get out of the loop - * in the next statement */ - /* if the entry is fixed we have to check all other - * entries before we can decide if the props are fixed */ - } - - if (GST_PROPS_ENTRY_IS_VARIABLE (entry)) { - /* mark the props as variable */ - GST_PROPS_FLAG_UNSET (props, GST_PROPS_FIXED); - /* if we already changed the entry, we can stop now */ - if (found) - break; - } - properties = g_list_next (properties); - } - - if (!found) { - g_warning ("gstprops: no property '%s' to change\n", name); - } - - return props; -} - - -/** - * gst_props_unref: - * @props: the props to unref - * - * Decrease the refcount of the property structure, destroying - * the property if the refcount is 0. - * - * Returns: handle to unrefed props or NULL when it was - * destroyed. - */ -GstProps* -gst_props_unref (GstProps *props) -{ - if (props == NULL) - return NULL; - - g_return_val_if_fail (props->refcount > 0, NULL); - - GST_CAT_LOG (GST_CAT_PROPERTIES, "unref %p (%d->%d)", props, props->refcount, props->refcount-1); - props->refcount--; - - if (props->refcount == 0) { - gst_props_destroy (props); - return NULL; - } - - return props; -} - -/** - * gst_props_ref: - * @props: the props to ref - * - * Increase the refcount of the property structure. - * - * Returns: handle to refed props. - */ -GstProps* -gst_props_ref (GstProps *props) -{ - if (props == NULL) - return NULL; - - g_return_val_if_fail (props->refcount > 0, NULL); - - GST_CAT_LOG (GST_CAT_PROPERTIES, "ref %p (%d->%d)", props, props->refcount, props->refcount+1); - - props->refcount++; - - return props; -} - -/** - * gst_props_sink: - * @props: the props to sink - * - * If the props if floating, decrease its refcount. Usually used - * with gst_props_ref() to take ownership of the props. - */ -void -gst_props_sink (GstProps *props) -{ - if (props == NULL) - return; - - GST_CAT_LOG (GST_CAT_PROPERTIES, "sink %p", props); - - if (GST_PROPS_IS_FLOATING (props)) { - GST_PROPS_FLAG_UNSET (props, GST_PROPS_FLOATING); - gst_props_unref (props); - } -} - -/** - * gst_props_destroy: - * @props: the props to destroy - * - * Destroy the property, freeing all the memory that - * was allocated. - */ -static void -gst_props_destroy (GstProps *props) -{ - if (props == NULL) - return; - - g_list_foreach (props->properties, (GFunc) gst_props_entry_destroy, NULL); - g_list_free (props->properties); - -#ifdef USE_POISONING - memset(props, 0xff, sizeof(*props)); -#endif - gst_mem_chunk_free (_gst_props_chunk, props); -#ifndef GST_DISABLE_TRACE - gst_alloc_trace_free (_props_trace, props); -#endif -} - -/** - * gst_props_entry_copy: - * @entry: the entry to copy - * - * Copy the propsentry. - * - * Returns: a new #GstPropsEntry that is a copy of the original - * given entry. - */ -GstPropsEntry* -gst_props_entry_copy (const GstPropsEntry *entry) -{ - GstPropsEntry *newentry; - - newentry = gst_props_alloc_entry (); - memcpy (newentry, entry, sizeof (GstPropsEntry)); - - switch (entry->propstype) { - case GST_PROPS_LIST_TYPE: - newentry->data.list_data.entries = gst_props_list_copy (entry->data.list_data.entries); - break; - case GST_PROPS_STRING_TYPE: - newentry->data.string_data.string = g_strdup (entry->data.string_data.string); - break; - default: - /* FIXME more? */ - break; - } - - return newentry; -} - -static GList* -gst_props_list_copy (GList *propslist) -{ - GList *new = NULL; - - while (propslist) { - GstPropsEntry *entry = (GstPropsEntry *)propslist->data; - - new = g_list_prepend (new, gst_props_entry_copy (entry)); - - propslist = g_list_next (propslist); - } - new = g_list_reverse (new); - - return new; -} - -/** - * gst_props_copy: - * @props: the props to copy - * - * Copy the property structure. - * - * Returns: the new property that is a copy of the original - * one. - */ -GstProps* -gst_props_copy (GstProps *props) -{ - GstProps *new; - - if (props == NULL) - return NULL; - - new = gst_props_empty_new (); - new->properties = gst_props_list_copy (props->properties); - GST_PROPS_FLAGS (new) = GST_PROPS_FLAGS (props) | GST_PROPS_FLOATING; - - return new; -} - -/** - * gst_props_copy_on_write: - * @props: the props to copy on write - * - * Copy the property structure if the refcount is >1. - * - * Returns: A new props that can be safely written to. - */ -GstProps* -gst_props_copy_on_write (GstProps *props) -{ - GstProps *new = props;; - - g_return_val_if_fail (props != NULL, NULL); - - if (props->refcount > 1) { - new = gst_props_copy (props); - gst_props_unref (props); - } - - return new; -} - -/** - * gst_props_get_entry: - * @props: the props to query - * @name: the name of the entry to get - * - * Get the props entry with the given name - * - * Returns: The props entry with the given name or NULL if - * the entry does not exist. - */ -const GstPropsEntry* -gst_props_get_entry (GstProps *props, const gchar *name) -{ - GList *lentry; - GQuark quark; - - g_return_val_if_fail (name != NULL, NULL); - - if (props == NULL) return FALSE; - - quark = g_quark_from_string (name); - - lentry = g_list_find_custom (props->properties, GINT_TO_POINTER (quark), props_find_func); - - if (lentry) { - GstPropsEntry *thisentry; - thisentry = (GstPropsEntry *)lentry->data; - return thisentry; - } - return NULL; -} - -/** - * gst_props_has_property: - * @props: the props to check - * @name: the name of the key to find - * - * Checks if a given props has a property with the given name. - * - * Returns: TRUE if the property was found, FALSE otherwise. - */ -gboolean -gst_props_has_property (GstProps *props, const gchar *name) -{ - return (gst_props_get_entry (props, name) != NULL); -} - -/** - * gst_props_has_property_typed: - * @props: the props to check - * @name: the name of the key to find - * @type: the type of the required property - * - * Checks if a given props has a property with the given name and the given type. - * - * Returns: TRUE if the property was found, FALSE otherwise. - */ -gboolean -gst_props_has_property_typed (GstProps *props, const gchar *name, GstPropsType type) -{ - const GstPropsEntry *entry; - - entry = gst_props_get_entry (props, name); - if (!entry) - return FALSE; - - return (entry->propstype == type); -} - -/** - * gst_props_has_fixed_property: - * @props: the props to check - * @name: the name of the key to find - * - * Checks if a given props has a property with the given name that - * is also fixed, ie. is not a list or a range. - * - * Returns: TRUE if the property was found, FALSE otherwise. - */ -gboolean -gst_props_has_fixed_property (GstProps *props, const gchar *name) -{ - const GstPropsEntry *entry; - - entry = gst_props_get_entry (props, name); - if (!entry) - return FALSE; - - return !GST_PROPS_ENTRY_IS_VARIABLE (entry); -} - -/** - * gst_props_entry_get_props_type: - * @entry: the props entry to query - * - * Get the type of the given props entry. - * - * Returns: The type of the props entry. - */ -GstPropsType -gst_props_entry_get_props_type (const GstPropsEntry *entry) -{ - g_return_val_if_fail (entry != NULL, GST_PROPS_INVALID_TYPE); - - return entry->propstype; -} - -/** - * gst_props_entry_get_name: - * @entry: the props entry to query - * - * Get the name of the given props entry. - * - * Returns: The name of the props entry. - */ -const gchar* -gst_props_entry_get_name (const GstPropsEntry *entry) -{ - g_return_val_if_fail (entry != NULL, NULL); - - return g_quark_to_string (entry->propid); -} - -/** - * gst_props_entry_is_fixed: - * @entry: the props entry to query - * - * Checks if the props entry is fixe, ie. is not a list - * or a range. - * - * Returns: TRUE is the props entry is fixed. - */ -gboolean -gst_props_entry_is_fixed (const GstPropsEntry *entry) -{ - g_return_val_if_fail (entry != NULL, FALSE); - - return !GST_PROPS_ENTRY_IS_VARIABLE (entry); -} - -static gboolean -gst_props_entry_getv (const GstPropsEntry *entry, gboolean safe, va_list var_args) -{ - gboolean result; - - GST_PROPS_ENTRY_READ (entry, var_args, safe, &result); - - return result; -} - -/** - * gst_props_entry_get: - * @entry: the props entry to query - * @...: a pointer to a type that can hold the value. - * - * Gets the contents of the entry. - * - * Returns: TRUE is the props entry could be fetched. - */ -gboolean -gst_props_entry_get (const GstPropsEntry *entry, ...) -{ - gboolean result; - va_list var_args; - - g_return_val_if_fail (entry != NULL, FALSE); - - va_start (var_args, entry); - result = gst_props_entry_getv (entry, FALSE, var_args); - va_end (var_args); - - return result; -} - -static gboolean -gst_props_entry_get_safe (const GstPropsEntry *entry, ...) -{ - gboolean result; - va_list var_args; - - if(entry == NULL) return FALSE; - - va_start (var_args, entry); - result = gst_props_entry_getv (entry, TRUE, var_args); - va_end (var_args); - - return result; -} - -static gboolean -gst_props_getv (GstProps *props, gboolean safe, gchar *first_name, va_list var_args) -{ - while (first_name) { - const GstPropsEntry *entry = gst_props_get_entry (props, first_name); - gboolean result; - - if (!entry) return FALSE; - GST_PROPS_ENTRY_READ (entry, var_args, safe, &result); - if (!result) return FALSE; - - first_name = va_arg (var_args, gchar *); - } - return TRUE; -} - -/** - * gst_props_get: - * @props: the props to query - * @first_name: the first key - * @...: a pointer to a datastructure that can hold the value. - * - * Gets the contents of the props into given key/value pairs. - * Make sure you pass a NULL terminated list. - * - * Returns: TRUE if all of the props entries could be fetched. - */ -gboolean -gst_props_get (GstProps *props, gchar *first_name, ...) -{ - va_list var_args; - gboolean ret; - - va_start (var_args, first_name); - ret = gst_props_getv (props, FALSE, first_name, var_args); - va_end (var_args); - - return ret; -} - -/** - * gst_props_get_safe: - * @props: the props to query - * @first_name: the first key - * @...: a pointer to a datastructure that can hold the value. - * - * Gets the contents of the props into given key/value pairs. - * - * Returns: TRUE if all of the props entries could be fetched. - */ -gboolean -gst_props_get_safe (GstProps *props, gchar *first_name, ...) -{ - va_list var_args; - gboolean ret; - - va_start (var_args, first_name); - ret = gst_props_getv (props, TRUE, first_name, var_args); - va_end (var_args); - - return ret; -} - -/** - * gst_props_entry_get_int: - * @entry: the props entry to query - * @val: a pointer to a gint to hold the value. - * - * Get the contents of the entry into the given gint. - * - * Returns: TRUE is the value could be fetched. FALSE if the - * entry is not of given type or did not exist. - */ -gboolean -gst_props_entry_get_int (const GstPropsEntry *entry, gint *val) -{ - return gst_props_entry_get_safe (entry, GST_PROPS_INT_TYPE, val); -} - -/** - * gst_props_entry_get_float: - * @entry: the props entry to query - * @val: a pointer to a gfloat to hold the value. - * - * Get the contents of the entry into the given gfloat. - * - * Returns: TRUE is the value could be fetched. FALSE if the - * entry is not of given type or did not exist. - */ -gboolean -gst_props_entry_get_float (const GstPropsEntry *entry, gfloat *val) -{ - return gst_props_entry_get_safe (entry, GST_PROPS_FLOAT_TYPE, val); -} - -/** - * gst_props_entry_get_fourcc_int: - * @entry: the props entry to query - * @val: a pointer to a guint32 to hold the value. - * - * Get the contents of the entry into the given guint32. - * - * Returns: TRUE is the value could be fetched. FALSE if the - * entry is not of given type or did not exist. - */ -gboolean -gst_props_entry_get_fourcc_int (const GstPropsEntry *entry, guint32 *val) -{ - return gst_props_entry_get_safe (entry, GST_PROPS_FOURCC_TYPE, val); -} - -/** - * gst_props_entry_get_boolean: - * @entry: the props entry to query - * @val: a pointer to a gboolean to hold the value. - * - * Get the contents of the entry into the given gboolean. - * - * Returns: TRUE is the value could be fetched. FALSE if the - * entry is not of given type or did not exist. - */ -gboolean -gst_props_entry_get_boolean (const GstPropsEntry *entry, gboolean *val) -{ - return gst_props_entry_get_safe (entry, GST_PROPS_BOOLEAN_TYPE, val); -} - -/** - * gst_props_entry_get_string: - * @entry: the props entry to query - * @val: a pointer to a gchar* to hold the value. - * - * Get the contents of the entry into the given gchar*. - * - * Returns: TRUE is the value could be fetched. FALSE if the - * entry is not of given type or did not exist. - */ -gboolean -gst_props_entry_get_string (const GstPropsEntry *entry, const gchar **val) -{ - return gst_props_entry_get_safe (entry, GST_PROPS_STRING_TYPE, val); -} - -/** - * gst_props_entry_get_int_range: - * @entry: the props entry to query - * @min: a pointer to a gint to hold the minimun value. - * @max: a pointer to a gint to hold the maximum value. - * - * Get the contents of the entry into the given gints. - * - * Returns: TRUE is the value could be fetched. FALSE if the - * entry is not of given type or did not exist. - */ -gboolean -gst_props_entry_get_int_range (const GstPropsEntry *entry, gint *min, gint *max) -{ - return gst_props_entry_get_safe (entry, GST_PROPS_INT_RANGE_TYPE, min, max); -} - -/** - * gst_props_entry_get_float_range: - * @entry: the props entry to query - * @min: a pointer to a gfloat to hold the minimun value. - * @max: a pointer to a gfloat to hold the maximum value. - * - * Get the contents of the entry into the given gfloats. - * - * Returns: TRUE is the value could be fetched. FALSE if the - * entry is not of given type or did not exist. - */ -gboolean -gst_props_entry_get_float_range (const GstPropsEntry *entry, gfloat *min, gfloat *max) -{ - return gst_props_entry_get_safe (entry, GST_PROPS_FLOAT_RANGE_TYPE, min, max); -} - -/** - * gst_props_entry_get_list: - * @entry: the props entry to query - * @val: a pointer to a GList to hold the value. - * - * Get the contents of the entry into the given GList. - * - * Returns: TRUE is the value could be fetched. FALSE if the - * entry is not of given type or did not exist. - */ -gboolean -gst_props_entry_get_list (const GstPropsEntry *entry, const GList **val) -{ - return gst_props_entry_get_safe (entry, GST_PROPS_LIST_TYPE, val); -} - -/** - * gst_props_merge: - * @props: the property to merge into - * @tomerge: the property to merge - * - * Merge the properties of tomerge into props. - * - * Returns: the new merged property - */ -GstProps* -gst_props_merge (GstProps *props, GstProps *tomerge) -{ - GList *merge_props; - - g_return_val_if_fail (props != NULL, NULL); - g_return_val_if_fail (tomerge != NULL, NULL); - - merge_props = tomerge->properties; - - /* FIXME do proper merging here... */ - while (merge_props) { - GstPropsEntry *entry = (GstPropsEntry *)merge_props->data; - - gst_props_add_entry (props, entry); - - merge_props = g_list_next (merge_props); - } - - return props; -} - - -/* entry2 is always a list, entry1 never is */ -static gboolean -gst_props_entry_check_list_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2) -{ - GList *entrylist = entry2->data.list_data.entries; - gboolean found = FALSE; - - while (entrylist && !found) { - GstPropsEntry *entry = (GstPropsEntry *) entrylist->data; - - found |= gst_props_entry_check_compatibility (entry1, entry); - - entrylist = g_list_next (entrylist); - } - - return found; -} - -static gboolean -gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2) -{ - GST_CAT_DEBUG (GST_CAT_PROPERTIES,"compare: %s %s", g_quark_to_string (entry1->propid), g_quark_to_string (entry2->propid)); - - if (entry2->propstype == GST_PROPS_LIST_TYPE && entry1->propstype != GST_PROPS_LIST_TYPE) { - return gst_props_entry_check_list_compatibility (entry1, entry2); - } - - switch (entry1->propstype) { - case GST_PROPS_LIST_TYPE: - { - GList *entrylist = entry1->data.list_data.entries; - gboolean valid = TRUE; /* innocent until proven guilty */ - - while (entrylist && valid) { - GstPropsEntry *entry = (GstPropsEntry *) entrylist->data; - - valid &= gst_props_entry_check_compatibility (entry, entry2); - - entrylist = g_list_next (entrylist); - } - - return valid; - } - case GST_PROPS_INT_RANGE_TYPE: - switch (entry2->propstype) { - /* a - b <---> a - c */ - case GST_PROPS_INT_RANGE_TYPE: - return (entry2->data.int_range_data.min <= entry1->data.int_range_data.min && - entry2->data.int_range_data.max >= entry1->data.int_range_data.max); - default: - break; - } - break; - case GST_PROPS_FLOAT_RANGE_TYPE: - switch (entry2->propstype) { - /* a - b <---> a - c */ - case GST_PROPS_FLOAT_RANGE_TYPE: - return (entry2->data.float_range_data.min <= entry1->data.float_range_data.min && - entry2->data.float_range_data.max >= entry1->data.float_range_data.max); - default: - break; - } - break; - case GST_PROPS_FOURCC_TYPE: - switch (entry2->propstype) { - /* b <---> a */ - case GST_PROPS_FOURCC_TYPE: - GST_CAT_DEBUG (GST_CAT_PROPERTIES,"\"%c%c%c%c\" <--> \"%c%c%c%c\" ?", - (entry2->data.fourcc_data>>0)&0xff, - (entry2->data.fourcc_data>>8)&0xff, - (entry2->data.fourcc_data>>16)&0xff, - (entry2->data.fourcc_data>>24)&0xff, - (entry1->data.fourcc_data>>0)&0xff, - (entry1->data.fourcc_data>>8)&0xff, - (entry1->data.fourcc_data>>16)&0xff, - (entry1->data.fourcc_data>>24)&0xff); - return (entry2->data.fourcc_data == entry1->data.fourcc_data); - default: - break; - } - break; - case GST_PROPS_INT_TYPE: - switch (entry2->propstype) { - /* b <---> a - d */ - case GST_PROPS_INT_RANGE_TYPE: - GST_CAT_DEBUG (GST_CAT_PROPERTIES,"%d <= %d <= %d ?",entry2->data.int_range_data.min, - entry1->data.int_data,entry2->data.int_range_data.max); - return (entry2->data.int_range_data.min <= entry1->data.int_data && - entry2->data.int_range_data.max >= entry1->data.int_data); - /* b <---> a */ - case GST_PROPS_INT_TYPE: - GST_CAT_DEBUG (GST_CAT_PROPERTIES,"%d == %d ?",entry1->data.int_data,entry2->data.int_data); - return (entry2->data.int_data == entry1->data.int_data); - default: - break; - } - break; - case GST_PROPS_FLOAT_TYPE: - switch (entry2->propstype) { - /* b <---> a - d */ - case GST_PROPS_FLOAT_RANGE_TYPE: - return (entry2->data.float_range_data.min <= entry1->data.float_data && - entry2->data.float_range_data.max >= entry1->data.float_data); - /* b <---> a */ - case GST_PROPS_FLOAT_TYPE: - return (entry2->data.float_data == entry1->data.float_data); - default: - break; - } - break; - case GST_PROPS_BOOLEAN_TYPE: - switch (entry2->propstype) { - /* t <---> t */ - case GST_PROPS_BOOLEAN_TYPE: - return (entry2->data.bool_data == entry1->data.bool_data); - default: - break; - } - case GST_PROPS_STRING_TYPE: - switch (entry2->propstype) { - /* t <---> t */ - case GST_PROPS_STRING_TYPE: - GST_CAT_DEBUG (GST_CAT_PROPERTIES,"\"%s\" <--> \"%s\" ?", - entry2->data.string_data.string, entry1->data.string_data.string); - return (!strcmp (entry2->data.string_data.string, entry1->data.string_data.string)); - default: - break; - } - default: - break; - } - - return FALSE; -} - -/** - * gst_props_check_compatibility: - * @fromprops: a property - * @toprops: a property - * - * Checks whether two capabilities are compatible. - * - * Returns: TRUE if compatible, FALSE otherwise - */ -gboolean -gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops) -{ - GList *sourcelist; - GList *sinklist; - gint missing = 0; - gint more = 0; - gboolean compatible = TRUE; - - g_return_val_if_fail (fromprops != NULL, FALSE); - g_return_val_if_fail (toprops != NULL, FALSE); - - sourcelist = fromprops->properties; - sinklist = toprops->properties; - - while (sourcelist && sinklist && compatible) { - GstPropsEntry *entry1; - GstPropsEntry *entry2; - - entry1 = (GstPropsEntry *)sourcelist->data; - entry2 = (GstPropsEntry *)sinklist->data; - - while (entry1->propid < entry2->propid) { - more++; - sourcelist = g_list_next (sourcelist); - if (sourcelist) entry1 = (GstPropsEntry *)sourcelist->data; - else goto end; - } - while (entry1->propid > entry2->propid) { - missing++; - sinklist = g_list_next (sinklist); - if (sinklist) entry2 = (GstPropsEntry *)sinklist->data; - else goto end; - } - - if (!gst_props_entry_check_compatibility (entry1, entry2)) { - compatible = FALSE; - GST_CAT_DEBUG (GST_CAT_PROPERTIES, "%s are not compatible: ", - g_quark_to_string (entry1->propid)); - } - - sourcelist = g_list_next (sourcelist); - sinklist = g_list_next (sinklist); - } - if (sinklist && compatible) { - GstPropsEntry *entry2; - entry2 = (GstPropsEntry *)sinklist->data; - missing++; - } -end: - - if (missing) - return FALSE; - - return compatible; -} - -static gint -_props_entry_flexibility (GstPropsEntry *entry) -{ - gint rank; - switch (entry->propstype) { - default: - rank = 0; - break; - case GST_PROPS_INT_RANGE_TYPE: - rank = 1; - break; - case GST_PROPS_FLOAT_RANGE_TYPE: - rank = 2; - break; - case GST_PROPS_LIST_TYPE: - rank = 3; - break; - } - return rank; -} - -static GstPropsEntry* -gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2) -{ - GstPropsEntry *result = NULL; - - /* Swap more flexible types into entry1 */ - if (_props_entry_flexibility (entry1) < _props_entry_flexibility (entry2)) { - GstPropsEntry *temp; - temp = entry1; - entry1 = entry2; - entry2 = temp; - } - - switch (entry1->propstype) { - case GST_PROPS_LIST_TYPE: - { - GList *entrylist = entry1->data.list_data.entries; - GList *intersection = NULL; - - while (entrylist) { - GstPropsEntry *entry = (GstPropsEntry *) entrylist->data; - GstPropsEntry *intersectentry; - - intersectentry = gst_props_entry_intersect (entry2, entry); - - if (intersectentry) { - if (intersectentry->propstype == GST_PROPS_LIST_TYPE) { - intersection = g_list_concat (intersection, - intersectentry->data.list_data.entries); - /* set the list to NULL because the entries are concatenated to the above - * list and we don't want to free them */ - intersectentry->data.list_data.entries = NULL; - gst_props_entry_destroy (intersectentry); - } - else { - intersection = g_list_prepend (intersection, intersectentry); - } - } - entrylist = g_list_next (entrylist); - } - if (intersection) { - /* check if the list only contains 1 element, if so, we can just copy it */ - if (g_list_next (intersection) == NULL) { - result = (GstPropsEntry *) (intersection->data); - g_list_free (intersection); - } - /* else we need to create a new entry to hold the list */ - else { - result = gst_props_alloc_entry (); - result->propid = entry1->propid; - result->propstype = GST_PROPS_LIST_TYPE; - result->data.list_data.entries = g_list_reverse (intersection); - } - } - return result; - } - case GST_PROPS_INT_RANGE_TYPE: - switch (entry2->propstype) { - /* a - b <---> a - c */ - case GST_PROPS_INT_RANGE_TYPE: - { - gint lower = MAX (entry1->data.int_range_data.min, entry2->data.int_range_data.min); - gint upper = MIN (entry1->data.int_range_data.max, entry2->data.int_range_data.max); - - if (lower <= upper) { - result = gst_props_alloc_entry (); - result->propid = entry1->propid; - - if (lower == upper) { - result->propstype = GST_PROPS_INT_TYPE; - result->data.int_data = lower; - } - else { - result->propstype = GST_PROPS_INT_RANGE_TYPE; - result->data.int_range_data.min = lower; - result->data.int_range_data.max = upper; - } - } - break; - } - case GST_PROPS_LIST_TYPE: - { - GList *entries = entry2->data.list_data.entries; - result = gst_props_alloc_entry (); - result->propid = entry1->propid; - result->propstype = GST_PROPS_LIST_TYPE; - result->data.list_data.entries = NULL; - while (entries) { - GstPropsEntry *this = (GstPropsEntry *)entries->data; - if (this->propstype != GST_PROPS_INT_TYPE) { - /* no hope, this list doesn't even contain ints! */ - gst_props_entry_destroy (result); - result = NULL; - break; - } - if (this->data.int_data >= entry1->data.int_range_data.min && - this->data.int_data <= entry1->data.int_range_data.max) - { - /* prepend and reverse at the end */ - result->data.list_data.entries = g_list_prepend (result->data.list_data.entries, - gst_props_entry_copy (this)); - } - entries = g_list_next (entries); - } - if (result) { - result->data.list_data.entries = g_list_reverse (result->data.list_data.entries); - } - break; - } - case GST_PROPS_INT_TYPE: - { - if (entry1->data.int_range_data.min <= entry2->data.int_data && - entry1->data.int_range_data.max >= entry2->data.int_data) - { - result = gst_props_entry_copy (entry2); - } - break; - } - default: - break; - } - break; - case GST_PROPS_FLOAT_RANGE_TYPE: - switch (entry2->propstype) { - /* a - b <---> a - c */ - case GST_PROPS_FLOAT_RANGE_TYPE: - { - gfloat lower = MAX (entry1->data.float_range_data.min, entry2->data.float_range_data.min); - gfloat upper = MIN (entry1->data.float_range_data.max, entry2->data.float_range_data.max); - - if (lower <= upper) { - result = gst_props_alloc_entry (); - result->propid = entry1->propid; - - if (lower == upper) { - result->propstype = GST_PROPS_FLOAT_TYPE; - result->data.float_data = lower; - } - else { - result->propstype = GST_PROPS_FLOAT_RANGE_TYPE; - result->data.float_range_data.min = lower; - result->data.float_range_data.max = upper; - } - } - break; - } - case GST_PROPS_FLOAT_TYPE: - if (entry1->data.float_range_data.min <= entry2->data.float_data && - entry1->data.float_range_data.max >= entry2->data.float_data) - { - result = gst_props_entry_copy (entry2); - } - default: - break; - } - break; - case GST_PROPS_FOURCC_TYPE: - switch (entry2->propstype) { - /* b <---> a */ - case GST_PROPS_FOURCC_TYPE: - if (entry1->data.fourcc_data == entry2->data.fourcc_data) - result = gst_props_entry_copy (entry1); - default: - break; - } - break; - case GST_PROPS_INT_TYPE: - switch (entry2->propstype) { - /* b <---> a */ - case GST_PROPS_INT_TYPE: - if (entry1->data.int_data == entry2->data.int_data) - result = gst_props_entry_copy (entry1); - default: - break; - } - break; - case GST_PROPS_FLOAT_TYPE: - switch (entry2->propstype) { - /* b <---> a */ - case GST_PROPS_FLOAT_TYPE: - if (entry1->data.float_data == entry2->data.float_data) - result = gst_props_entry_copy (entry1); - default: - break; - } - break; - case GST_PROPS_BOOLEAN_TYPE: - switch (entry2->propstype) { - /* t <---> t */ - case GST_PROPS_BOOLEAN_TYPE: - if (entry1->data.bool_data == entry2->data.bool_data) - result = gst_props_entry_copy (entry1); - default: - break; - } - case GST_PROPS_STRING_TYPE: - switch (entry2->propstype) { - /* t <---> t */ - case GST_PROPS_STRING_TYPE: - if (!strcmp (entry1->data.string_data.string, entry2->data.string_data.string)) - result = gst_props_entry_copy (entry1); - default: - break; - } - default: - break; - } - - /* make caps debugging extremely verbose - - GST_CAT_DEBUG (GST_CAT_CAPS, "intersecting %s: %s x %s => %s", - g_quark_to_string (entry1->propid), - gst_props_entry_to_string (entry1), - gst_props_entry_to_string (entry2), - result? gst_props_entry_to_string (result) : "fail"); - */ - - return result; -} - -/* when running over the entries in sorted order we can - * optimize addition with _prepend and a reverse at the end */ -#define gst_props_entry_add_sorted_prepend(props, entry) \ -G_STMT_START { \ - /* avoid double evaluation of input */ \ - GstPropsEntry *toadd = (entry); \ - if (GST_PROPS_ENTRY_IS_VARIABLE (toadd)) \ - GST_PROPS_FLAG_UNSET ((props), GST_PROPS_FIXED); \ - props->properties = g_list_prepend ((props)->properties, toadd); \ -} G_STMT_END -static gint -compare_props_entry (gconstpointer one, gconstpointer two) -{ - GstPropsEntry *a = (GstPropsEntry *) one; - GstPropsEntry *b = (GstPropsEntry *) two; - - if (a->propid > b->propid) return 1; - if (a->propid < b->propid) return -1; - return 0; -} -/** - * gst_props_intersect: - * @props1: a property - * @props2: another property - * - * Calculates the intersection bewteen two GstProps. - * - * Returns: a GstProps with the intersection or NULL if the - * intersection is empty. The new GstProps is floating and must - * be unreffed afetr use. - */ -GstProps* -gst_props_intersect (GstProps *props1, GstProps *props2) -{ - GList *props1list; - GList *props2list; - GstProps *intersection; - GList *leftovers; - GstPropsEntry *iprops = NULL; - - g_return_val_if_fail (props1 != NULL, NULL); - g_return_val_if_fail (props2 != NULL, NULL); - - intersection = gst_props_empty_new (); - - props1->properties = g_list_sort (props1->properties, compare_props_entry); - props2->properties = g_list_sort (props2->properties, compare_props_entry); - - props1list = props1->properties; - props2list = props2->properties; - - while (props1list && props2list) { - GstPropsEntry *entry1; - GstPropsEntry *entry2; - - entry1 = (GstPropsEntry *)props1list->data; - entry2 = (GstPropsEntry *)props2list->data; - - while (entry1->propid < entry2->propid) { - gst_props_entry_add_sorted_prepend (intersection, gst_props_entry_copy (entry1)); - - props1list = g_list_next (props1list); - if (!props1list) - goto end; - - entry1 = (GstPropsEntry *)props1list->data; - } - while (entry1->propid > entry2->propid) { - gst_props_entry_add_sorted_prepend (intersection, gst_props_entry_copy (entry2)); - - props2list = g_list_next (props2list); - if (!props2list) - goto end; - - entry2 = (GstPropsEntry *)props2list->data; - } - if (entry1->propid < entry2->propid) - continue; - /* at this point we are talking about the same property */ - iprops = gst_props_entry_intersect (entry1, entry2); - if (!iprops) { - /* common properties did not intersect, intersection is empty */ - gst_props_unref (intersection); - return NULL; - } - - gst_props_entry_add_sorted_prepend (intersection, iprops); - - props1list = g_list_next (props1list); - props2list = g_list_next (props2list); - } - -end: - /* at this point one of the lists could contain leftover properties, while - * the other one is NULL */ - leftovers = props1list; - if (!leftovers) - leftovers = props2list; - - while (leftovers) { - gst_props_entry_add_sorted_prepend (intersection, - gst_props_entry_copy ((GstPropsEntry *) leftovers->data)); - leftovers = g_list_next (leftovers); - } - - intersection->properties = g_list_reverse (intersection->properties); - - return intersection; -} - -/** - * gst_props_normalize: - * @props: a property - * - * Unrolls all lists in the given GstProps. This is usefull if you - * want to loop over the props. - * - * Returns: A GList with the unrolled props entries. g_list_free - * after usage. - */ -GList* -gst_props_normalize (GstProps *props) -{ - GList *entries; - GList *result = NULL; - gboolean fixed = TRUE; - - if (!props) - return NULL; - - /* warning: the property here could have a wrong FIXED flag - * but it'll be fixed at the end of the loop */ - entries = props->properties; - - while (entries) { - GstPropsEntry *entry = (GstPropsEntry *) entries->data; - - /* be carefull with the bitmasks */ - fixed &= (GST_PROPS_ENTRY_IS_VARIABLE (entry) ? FALSE : TRUE); - - if (entry->propstype == GST_PROPS_LIST_TYPE) { - GList *list_entries = entry->data.list_data.entries; - - while (list_entries) { - GstPropsEntry *list_entry = (GstPropsEntry *) list_entries->data; - GstPropsEntry *new_entry; - GstProps *newprops; - GList *lentry; - - newprops = gst_props_copy (props); - lentry = g_list_find_custom (newprops->properties, - GINT_TO_POINTER (list_entry->propid), - props_find_func); - if (lentry) { - GList *new_list; - - new_entry = (GstPropsEntry *) lentry->data; - memcpy (new_entry, list_entry, sizeof (GstPropsEntry)); - /* it's possible that this property now became fixed, since we - * removed the list, we'll update the flag when everything is - * unreolled at the end of this function */ - new_list = gst_props_normalize (newprops); - result = g_list_concat (new_list, result); - } - else { - /* FIXME append or prepend */ - result = g_list_append (result, newprops); - } - - list_entries = g_list_next (list_entries); - } - /* we break out of the loop because the other lists are - * unrolled in the recursive call */ - break; - } - entries = g_list_next (entries); - } - if (!result) { - /* at this point, the props did not need any unrolling, we have scanned - * all entries and the fixed flag will hold the correct value */ - if (fixed) - GST_PROPS_FLAG_SET (props, GST_PROPS_FIXED); - else - GST_PROPS_FLAG_UNSET (props, GST_PROPS_FIXED); - - /* no result, create list with input props */ - result = g_list_prepend (result, props); - } - else { - result = g_list_reverse (result); - } - return result; -} - -#ifndef GST_DISABLE_LOADSAVE_REGISTRY -static xmlNodePtr -gst_props_save_thyself_func (GstPropsEntry *entry, xmlNodePtr parent) -{ - xmlNodePtr subtree; - gchar *str; - - switch (entry->propstype) { - case GST_PROPS_INT_TYPE: - subtree = xmlNewChild (parent, NULL, "int", NULL); - xmlNewProp (subtree, "name", g_quark_to_string (entry->propid)); - str = g_strdup_printf ("%d", entry->data.int_data); - xmlNewProp (subtree, "value", str); - g_free(str); - break; - case GST_PROPS_INT_RANGE_TYPE: - subtree = xmlNewChild (parent, NULL, "range", NULL); - xmlNewProp (subtree, "name", g_quark_to_string (entry->propid)); - str = g_strdup_printf ("%d", entry->data.int_range_data.min); - xmlNewProp (subtree, "min", str); - g_free(str); - str = g_strdup_printf ("%d", entry->data.int_range_data.max); - xmlNewProp (subtree, "max", str); - g_free(str); - break; - case GST_PROPS_FLOAT_TYPE: - subtree = xmlNewChild (parent, NULL, "float", NULL); - xmlNewProp (subtree, "name", g_quark_to_string (entry->propid)); - str = g_strdup_printf ("%g", entry->data.float_data); - xmlNewProp (subtree, "value", str); - g_free(str); - break; - case GST_PROPS_FLOAT_RANGE_TYPE: - subtree = xmlNewChild (parent, NULL, "floatrange", NULL); - xmlNewProp (subtree, "name", g_quark_to_string (entry->propid)); - str = g_strdup_printf ("%g", entry->data.float_range_data.min); - xmlNewProp (subtree, "min", str); - g_free(str); - str = g_strdup_printf ("%g", entry->data.float_range_data.max); - xmlNewProp (subtree, "max", str); - g_free(str); - break; - case GST_PROPS_FOURCC_TYPE: - str = g_strdup_printf ("%c%c%c%c", - (entry->data.fourcc_data>>0)&0xff, - (entry->data.fourcc_data>>8)&0xff, - (entry->data.fourcc_data>>16)&0xff, - (entry->data.fourcc_data>>24)&0xff); - xmlAddChild (parent, xmlNewComment (str)); - g_free(str); - subtree = xmlNewChild (parent, NULL, "fourcc", NULL); - xmlNewProp (subtree, "name", g_quark_to_string (entry->propid)); - str = g_strdup_printf ("%08x", entry->data.fourcc_data); - xmlNewProp (subtree, "hexvalue", str); - g_free(str); - break; - case GST_PROPS_BOOLEAN_TYPE: - subtree = xmlNewChild (parent, NULL, "boolean", NULL); - xmlNewProp (subtree, "name", g_quark_to_string (entry->propid)); - xmlNewProp (subtree, "value", (entry->data.bool_data ? "true" : "false")); - break; - case GST_PROPS_STRING_TYPE: - subtree = xmlNewChild (parent, NULL, "string", NULL); - xmlNewProp (subtree, "name", g_quark_to_string (entry->propid)); - xmlNewProp (subtree, "value", entry->data.string_data.string); - break; - default: - g_warning ("trying to save unknown property type %d", entry->propstype); - break; - } - - return parent; -} - -/** - * gst_props_save_thyself: - * @props: a property to save - * @parent: the parent XML tree - * - * Saves the property into an XML representation. - * - * Returns: the new XML tree - */ -xmlNodePtr -gst_props_save_thyself (GstProps *props, xmlNodePtr parent) -{ - GList *proplist; - xmlNodePtr subtree; - - g_return_val_if_fail (props != NULL, NULL); - - proplist = props->properties; - - while (proplist) { - GstPropsEntry *entry = (GstPropsEntry *) proplist->data; - - switch (entry->propstype) { - case GST_PROPS_LIST_TYPE: - subtree = xmlNewChild (parent, NULL, "list", NULL); - xmlNewProp (subtree, "name", g_quark_to_string (entry->propid)); - g_list_foreach (entry->data.list_data.entries, (GFunc) gst_props_save_thyself_func, subtree); - break; - default: - gst_props_save_thyself_func (entry, parent); - } - - proplist = g_list_next (proplist); - } - - return parent; -} - -static GstPropsEntry* -gst_props_load_thyself_func (xmlNodePtr field) -{ - GstPropsEntry *entry; - gchar *prop; - - entry = gst_props_alloc_entry (); - - if (!strcmp(field->name, "int")) { - entry->propstype = GST_PROPS_INT_TYPE; - prop = xmlGetProp(field, "name"); - entry->propid = g_quark_from_string (prop); - g_free (prop); - prop = xmlGetProp(field, "value"); - sscanf (prop, "%d", &entry->data.int_data); - g_free (prop); - } - else if (!strcmp(field->name, "range")) { - entry->propstype = GST_PROPS_INT_RANGE_TYPE; - prop = xmlGetProp(field, "name"); - entry->propid = g_quark_from_string (prop); - g_free (prop); - prop = xmlGetProp (field, "min"); - sscanf (prop, "%d", &entry->data.int_range_data.min); - g_free (prop); - prop = xmlGetProp (field, "max"); - sscanf (prop, "%d", &entry->data.int_range_data.max); - g_free (prop); - } - else if (!strcmp(field->name, "float")) { - entry->propstype = GST_PROPS_FLOAT_TYPE; - prop = xmlGetProp(field, "name"); - entry->propid = g_quark_from_string (prop); - g_free (prop); - prop = xmlGetProp(field, "value"); - sscanf (prop, "%f", &entry->data.float_data); - g_free (prop); - } - else if (!strcmp(field->name, "floatrange")) { - entry->propstype = GST_PROPS_FLOAT_RANGE_TYPE; - prop = xmlGetProp(field, "name"); - entry->propid = g_quark_from_string (prop); - g_free (prop); - prop = xmlGetProp (field, "min"); - sscanf (prop, "%f", &entry->data.float_range_data.min); - g_free (prop); - prop = xmlGetProp (field, "max"); - sscanf (prop, "%f", &entry->data.float_range_data.max); - g_free (prop); - } - else if (!strcmp(field->name, "boolean")) { - entry->propstype = GST_PROPS_BOOLEAN_TYPE; - prop = xmlGetProp(field, "name"); - entry->propid = g_quark_from_string (prop); - g_free (prop); - prop = xmlGetProp (field, "value"); - if (!strcmp (prop, "false")) entry->data.bool_data = 0; - else entry->data.bool_data = 1; - g_free (prop); - } - else if (!strcmp(field->name, "fourcc")) { - entry->propstype = GST_PROPS_FOURCC_TYPE; - prop = xmlGetProp(field, "name"); - entry->propid = g_quark_from_string (prop); - g_free (prop); - prop = xmlGetProp (field, "hexvalue"); - sscanf (prop, "%08x", &entry->data.fourcc_data); - g_free (prop); - } - else if (!strcmp(field->name, "string")) { - entry->propstype = GST_PROPS_STRING_TYPE; - prop = xmlGetProp(field, "name"); - entry->propid = g_quark_from_string (prop); - g_free (prop); - entry->data.string_data.string = xmlGetProp (field, "value"); - } - else { - gst_props_entry_destroy (entry); - entry = NULL; - } - - return entry; -} - -/** - * gst_props_load_thyself: - * @parent: the XML tree to load from - * - * Creates a new property out of an XML tree. - * - * Returns: the new property - */ -GstProps* -gst_props_load_thyself (xmlNodePtr parent) -{ - GstProps *props; - xmlNodePtr field = parent->xmlChildrenNode; - gchar *prop; - - props = gst_props_empty_new (); - - while (field) { - if (!strcmp (field->name, "list")) { - GstPropsEntry *entry; - xmlNodePtr subfield = field->xmlChildrenNode; - - entry = gst_props_alloc_entry (); - prop = xmlGetProp (field, "name"); - entry->propid = g_quark_from_string (prop); - g_free (prop); - entry->propstype = GST_PROPS_LIST_TYPE; - entry->data.list_data.entries = NULL; - - while (subfield) { - GstPropsEntry *subentry = gst_props_load_thyself_func (subfield); - - if (subentry) - entry->data.list_data.entries = g_list_prepend (entry->data.list_data.entries, subentry); - - subfield = subfield->next; - } - entry->data.list_data.entries = g_list_reverse (entry->data.list_data.entries); - gst_props_add_entry (props, entry); - } - else { - GstPropsEntry *entry; - - entry = gst_props_load_thyself_func (field); - - if (entry) - gst_props_add_entry (props, entry); - } - field = field->next; - } - - return props; -} -#endif /* GST_DISABLE_LOADSAVE_REGISTRY */ diff --git a/gst/gstprops.h b/gst/gstprops.h deleted file mode 100644 index 3ac1239d07..0000000000 --- a/gst/gstprops.h +++ /dev/null @@ -1,205 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2000 Wim Taymans - * - * gstprops.h: Header for properties subsystem - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - - -#ifndef __GST_PROPS_H__ -#define __GST_PROPS_H__ - -#include - -#include - -G_BEGIN_DECLS - -typedef struct _GstProps GstProps; -extern GType _gst_props_type; - -#define GST_PROPS_TRACE_NAME "GstProps" - -#define GST_TYPE_PROPS (_gst_props_type) - -#if 0 -typedef enum { - GST_PROPS_END_TYPE = 0, - - GST_PROPS_INVALID_TYPE, - - GST_PROPS_INT_TYPE, - GST_PROPS_FLOAT_TYPE, - GST_PROPS_FOURCC_TYPE, - GST_PROPS_BOOLEAN_TYPE, - GST_PROPS_STRING_TYPE, - - GST_PROPS_VAR_TYPE, /* after this marker start the variable properties */ - - GST_PROPS_LIST_TYPE, - GST_PROPS_GLIST_TYPE, - GST_PROPS_FLOAT_RANGE_TYPE, - GST_PROPS_INT_RANGE_TYPE, - - GST_PROPS_LAST_TYPE = GST_PROPS_END_TYPE + 16 -} GstPropsType; -#endif - -#define GST_MAKE_FOURCC(a,b,c,d) (guint32)((a)|(b)<<8|(c)<<16|(d)<<24) -#define GST_STR_FOURCC(f) (guint32)(((f)[0])|((f)[1]<<8)|((f)[2]<<16)|((f)[3]<<24)) - -#define GST_FOURCC_FORMAT "%c%c%c%c" -#define GST_FOURCC_ARGS(fourcc) \ - ((gchar) ((fourcc) &0xff)), \ - ((gchar) (((fourcc)>>8 )&0xff)), \ - ((gchar) (((fourcc)>>16)&0xff)), \ - ((gchar) (((fourcc)>>24)&0xff)) - -#ifdef G_HAVE_ISO_VARARGS -# define GST_PROPS_LIST(...) GST_PROPS_LIST_TYPE,__VA_ARGS__,GST_PROPS_END_TYPE -#elif defined(G_HAVE_GNUC_VARARGS) -# define GST_PROPS_LIST(a...) GST_PROPS_LIST_TYPE,a,GST_PROPS_END_TYPE -#endif - -#define GST_PROPS_GLIST(a) GST_PROPS_GLIST_TYPE,(a) -#define GST_PROPS_INT(a) GST_PROPS_INT_TYPE,(a) -#define GST_PROPS_INT_RANGE(a,b) GST_PROPS_INT_RANGE_TYPE,(a),(b) -#define GST_PROPS_FLOAT(a) GST_PROPS_FLOAT_TYPE,((float)(a)) -#define GST_PROPS_FLOAT_RANGE(a,b) GST_PROPS_FLOAT_RANGE_TYPE,((float)(a)),((float)(b)) -#define GST_PROPS_FOURCC(a) GST_PROPS_FOURCC_TYPE,(a) -#define GST_PROPS_BOOLEAN(a) GST_PROPS_BOOLEAN_TYPE,(a) -#define GST_PROPS_STRING(a) GST_PROPS_STRING_TYPE,(a) - -#define GST_PROPS_INT_POSITIVE GST_PROPS_INT_RANGE(0,G_MAXINT) -#define GST_PROPS_INT_NEGATIVE GST_PROPS_INT_RANGE(G_MININT,0) -#define GST_PROPS_INT_ANY GST_PROPS_INT_RANGE(G_MININT,G_MAXINT) - -/* propsentries are private */ -typedef struct _GstPropsEntry GstPropsEntry; -extern GType _gst_props_entry_type; - -#define GST_PROPS_ENTRY_TRACE_NAME "GstPropsEntry" - -#define GST_TYPE_PROPS_ENTRY (_gst_props_entry_type) - -typedef enum { - GST_PROPS_FIXED = (1 << 0), /* props has no variable entries */ - GST_PROPS_FLOATING = (1 << 1) /* props is floating */ -} GstPropsFlags; - -#define GST_PROPS_FLAGS(props) ((props)->flags) -#define GST_PROPS_FLAG_IS_SET(props,flag) (GST_PROPS_FLAGS (props) & (flag)) -#define GST_PROPS_FLAG_SET(props,flag) (GST_PROPS_FLAGS (props) |= (flag)) -#define GST_PROPS_FLAG_UNSET(props,flag) (GST_PROPS_FLAGS (props) &= ~(flag)) - -#define GST_PROPS_REFCOUNT(props) ((props)->refcount) -#define GST_PROPS_PROPERTIES(props) ((props) ? ((props)->properties) : NULL) - -#define GST_PROPS_IS_FIXED(props) (GST_PROPS_FLAG_IS_SET ((props), GST_PROPS_FIXED)) -#define GST_PROPS_IS_FLOATING(props) (GST_PROPS_FLAG_IS_SET ((props), GST_PROPS_FLOATING)) - -struct _GstProps { - gint refcount; - gint flags; - - GList *properties; /* real property entries for this property */ -}; - -/* initialize the subsystem */ -void _gst_props_initialize (void); - -/* creating new properties */ -GType gst_props_get_type (void); -GstProps* gst_props_new (const gchar *firstname, ...); -GstProps* gst_props_newv (const gchar *firstname, va_list var_args); -GstProps* gst_props_empty_new (void); - -/* replace pointer to props, doing proper refcounting */ -void gst_props_replace (GstProps **oldprops, GstProps *newprops); -void gst_props_replace_sink (GstProps **oldprops, GstProps *newprops); - -/* lifecycle management */ -GstProps* gst_props_unref (GstProps *props); -GstProps* gst_props_ref (GstProps *props); -void gst_props_sink (GstProps *props); - -/* dump property debug info to the log */ -void gst_props_debug (GstProps *props); - -/* copy */ -GstProps* gst_props_copy (GstProps *props); -GstProps* gst_props_copy_on_write (GstProps *props); - -/* check if fromprops is subset of toprops */ -gboolean gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops); - -/* operation on props */ -GstProps* gst_props_merge (GstProps *props, GstProps *tomerge); -GstProps* gst_props_intersect (GstProps *props1, GstProps *props2); -GList* gst_props_normalize (GstProps *props); - -/* modify entries */ -GstProps* gst_props_set (GstProps *props, const gchar *name, ...); -gboolean gst_props_get (GstProps *props, gchar *first_name, ...); -gboolean gst_props_get_safe (GstProps *props, gchar *first_name, ...); - -/* query entries */ -gboolean gst_props_has_property (GstProps *props, const gchar *name); -gboolean gst_props_has_property_typed (GstProps *props, const gchar *name, GstPropsType type); -gboolean gst_props_has_fixed_property (GstProps *props, const gchar *name); - -/* add/get entries */ -const GstPropsEntry* gst_props_get_entry (GstProps *props, const gchar *name); -void gst_props_add_entry (GstProps *props, GstPropsEntry *entry); -void gst_props_remove_entry (GstProps *props, GstPropsEntry *entry); -void gst_props_remove_entry_by_name (GstProps *props, const gchar *name); - -/* working with props entries */ -GType gst_props_entry_get_type (void); -GstPropsEntry* gst_props_entry_new (const gchar *name, ...); - -void gst_props_entry_destroy (GstPropsEntry *entry); -GstPropsEntry* gst_props_entry_copy (const GstPropsEntry *entry); -GstPropsType gst_props_entry_get_props_type (const GstPropsEntry *entry); -const gchar* gst_props_entry_get_name (const GstPropsEntry *entry); -gboolean gst_props_entry_is_fixed (const GstPropsEntry *entry); - -gboolean gst_props_entry_get (const GstPropsEntry *entry, ...); - -gboolean gst_props_entry_get_int (const GstPropsEntry *entry, gint *val); -gboolean gst_props_entry_get_float (const GstPropsEntry *entry, gfloat *val); -gboolean gst_props_entry_get_fourcc_int (const GstPropsEntry *entry, guint32 *val); -gboolean gst_props_entry_get_boolean (const GstPropsEntry *entry, gboolean *val); -gboolean gst_props_entry_get_string (const GstPropsEntry *entry, const gchar **val); -gboolean gst_props_entry_get_int_range (const GstPropsEntry *entry, gint *min, gint *max); -gboolean gst_props_entry_get_float_range (const GstPropsEntry *entry, gfloat *min, gfloat *max); -gboolean gst_props_entry_get_list (const GstPropsEntry *entry, const GList **val); - -/* for debugging purposes */ -gchar * gst_props_to_string (GstProps *props); -GstProps * gst_props_from_string (gchar *str); - -#ifndef GST_DISABLE_LOADSAVE -xmlNodePtr gst_props_save_thyself (GstProps *props, xmlNodePtr parent); -GstProps* gst_props_load_thyself (xmlNodePtr parent); -#endif - - -G_END_DECLS - -#endif /* __GST_PROPS_H__ */