- implement FLOATING flag on caps/props
[platform/upstream/gstreamer.git] / gst / gstprops.c
index 0dea80f..49a914b 100644 (file)
 
 #include "gstlog.h"
 #include "gstprops.h"
+#include "gstmemchunk.h"
+
+/* #define GST_WITH_ALLOC_TRACE */
+#include "gsttrace.h"
 
 GType _gst_props_type;
 GType _gst_props_entry_type;
 
+static GstAllocTrace *_props_trace;
+static GstAllocTrace *_entries_trace;
+
 #define GST_PROPS_ENTRY_IS_VARIABLE(a) (((GstPropsEntry*)(a))->propstype > GST_PROPS_VAR_TYPE)
 
 struct _GstPropsEntry {
@@ -60,11 +67,8 @@ struct _GstPropsEntry {
   } data;
 };
 
-static GMemChunk *_gst_props_entries_chunk;
-static GMutex *_gst_props_entries_chunk_lock;
-
-static GMemChunk *_gst_props_chunk;
-static GMutex *_gst_props_chunk_lock;
+static GstMemChunk *_gst_props_entries_chunk;
+static GstMemChunk *_gst_props_chunk;
 
 static gboolean        gst_props_entry_check_compatibility     (GstPropsEntry *entry1, GstPropsEntry *entry2);
 static GList*          gst_props_list_copy                     (GList *propslist);
@@ -84,9 +88,6 @@ transform_func (const GValue *src_value,
       const gchar *name = g_quark_to_string (entry->propid);
 
       switch (entry->propstype) {
-        case GST_PROPS_STRING_TYPE:
-         g_string_append_printf (result, "%s=(string) '%s'", name, entry->data.string_data.string);
-         break;
         case GST_PROPS_INT_TYPE:
          g_string_append_printf (result, "%s=(int) %d", name, entry->data.int_data);
          break;
@@ -98,7 +99,10 @@ transform_func (const GValue *src_value,
          break;
         case GST_PROPS_BOOLEAN_TYPE:
          g_string_append_printf (result, "%s=(boolean) %s", name, 
-                         (entry->data.bool_data ? "TRUE" : "FALSE"));
+                                 (entry->data.bool_data ? "TRUE" : "FALSE"));
+         break;
+        case GST_PROPS_STRING_TYPE:
+         g_string_append_printf (result, "%s=(string) '%s'", name, entry->data.string_data.string);
          break;
         default:
          break;
@@ -111,21 +115,20 @@ transform_func (const GValue *src_value,
     }
   }
   dest_value->data[0].v_pointer = result->str;
+  g_string_free (result, FALSE);
 }
 
        
 void 
 _gst_props_initialize (void) 
 {
-  _gst_props_entries_chunk = g_mem_chunk_new ("GstPropsEntries", 
-                 sizeof (GstPropsEntry), sizeof (GstPropsEntry) * 256
+  _gst_props_entries_chunk = gst_mem_chunk_new ("GstPropsEntries", 
+                 sizeof (GstPropsEntry), sizeof (GstPropsEntry) * 1024
                  G_ALLOC_AND_FREE);
-  _gst_props_entries_chunk_lock = g_mutex_new ();
 
-  _gst_props_chunk = g_mem_chunk_new ("GstProps", 
+  _gst_props_chunk = gst_mem_chunk_new ("GstProps", 
                  sizeof (GstProps), sizeof (GstProps) * 256, 
                  G_ALLOC_AND_FREE);
-  _gst_props_chunk_lock = g_mutex_new ();
 
   _gst_props_type = g_boxed_type_register_static ("GstProps",
                                       (GBoxedCopyFunc) gst_props_ref,
@@ -138,6 +141,9 @@ _gst_props_initialize (void)
   _gst_props_entry_type = g_boxed_type_register_static ("GstPropsEntry",
                  (GBoxedCopyFunc) gst_props_entry_copy,
                  (GBoxedFreeFunc) gst_props_entry_destroy);
+
+  _props_trace = gst_alloc_trace_register (GST_PROPS_TRACE_NAME);
+  _entries_trace = gst_alloc_trace_register (GST_PROPS_ENTRY_TRACE_NAME);
 }
 
 static void
@@ -147,34 +153,34 @@ gst_props_debug_entry (GstPropsEntry *entry)
 
   switch (entry->propstype) {
     case GST_PROPS_INT_TYPE:
-      GST_DEBUG (GST_CAT_PROPERTIES, "%s: int %d", name, entry->data.int_data);
+      GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: int %d", entry, name, entry->data.int_data);
       break;
     case GST_PROPS_FLOAT_TYPE:
-      GST_DEBUG (GST_CAT_PROPERTIES, "%s: float %f", name, entry->data.float_data);
+      GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: float %f", entry, name, entry->data.float_data);
       break;
     case GST_PROPS_FOURCC_TYPE:
-      GST_DEBUG (GST_CAT_PROPERTIES, "%s: fourcc %c%c%c%c", name,
+      GST_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_DEBUG (GST_CAT_PROPERTIES, "%s: bool %d", name, entry->data.bool_data);
+      GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: bool %d", entry, name, entry->data.bool_data);
       break;
     case GST_PROPS_STRING_TYPE:
-      GST_DEBUG (GST_CAT_PROPERTIES, "%s: string \"%s\"", name, entry->data.string_data.string);
+      GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: string \"%s\"", entry, name, entry->data.string_data.string);
       break;
     case GST_PROPS_INT_RANGE_TYPE:
-      GST_DEBUG (GST_CAT_PROPERTIES, "%s: int range %d-%d", name, entry->data.int_range_data.min,
+      GST_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_DEBUG (GST_CAT_PROPERTIES, "%s: float range %f-%f", name, entry->data.float_range_data.min,
+      GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: float range %f-%f", entry, name, entry->data.float_range_data.min,
                      entry->data.float_range_data.max);
       break;
     case GST_PROPS_LIST_TYPE:
-      GST_DEBUG (GST_CAT_PROPERTIES, "[list]");
+      GST_DEBUG (GST_CAT_PROPERTIES, "%p: [list]", entry);
       {
        GList *entries = entry->data.list_data.entries;
 
@@ -185,7 +191,7 @@ gst_props_debug_entry (GstPropsEntry *entry)
       }
       break;
     default:
-      g_warning ("unknown property type %d", entry->propstype);
+      g_warning ("unknown property type %d at %p", entry->propstype, entry);
       break;
   }
 }
@@ -302,15 +308,16 @@ gst_props_alloc_entry (void)
 {
   GstPropsEntry *entry;
 
-  g_mutex_lock (_gst_props_entries_chunk_lock);
-  entry = g_mem_chunk_alloc (_gst_props_entries_chunk);
-  g_mutex_unlock (_gst_props_entries_chunk_lock);
+  entry = gst_mem_chunk_alloc (_gst_props_entries_chunk);
+  gst_alloc_trace_new (_entries_trace, entry);
+
+  GST_DEBUG (GST_CAT_PROPERTIES, "new entry %p", entry);
 
   return entry;
 }
 
-void
-gst_props_entry_destroy (GstPropsEntry *entry)
+static void
+gst_props_entry_clean (GstPropsEntry *entry)
 {
   switch (entry->propstype) {
     case GST_PROPS_STRING_TYPE:                
@@ -330,9 +337,17 @@ gst_props_entry_destroy (GstPropsEntry *entry)
     default:                   
       break;           
   }
-  g_mutex_lock (_gst_props_entries_chunk_lock);
-  g_mem_chunk_free (_gst_props_entries_chunk, entry);
-  g_mutex_unlock (_gst_props_entries_chunk_lock);
+}
+
+void
+gst_props_entry_destroy (GstPropsEntry *entry)
+{
+  GST_DEBUG (GST_CAT_PROPERTIES, "destroy entry %p", entry);
+
+  gst_props_entry_clean (entry);
+
+  gst_mem_chunk_free (_gst_props_entries_chunk, entry);
+  gst_alloc_trace_free (_entries_trace, entry);
 }
 
 /**
@@ -347,18 +362,53 @@ gst_props_empty_new (void)
 {
   GstProps *props;
 
-  g_mutex_lock (_gst_props_chunk_lock);
-  props = g_mem_chunk_alloc (_gst_props_chunk);
-  g_mutex_unlock (_gst_props_chunk_lock);
+  props = gst_mem_chunk_alloc (_gst_props_chunk);
+  gst_alloc_trace_new (_props_trace, props);
+
+  GST_DEBUG (GST_CAT_PROPERTIES, "new %p", props);
 
   props->properties = NULL;
   props->refcount = 1;
-  props->fixed = TRUE;
+  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
@@ -371,13 +421,53 @@ gst_props_add_entry (GstProps *props, GstPropsEntry *entry)
   g_return_if_fail (props);
   g_return_if_fail (entry);
 
-  if (props->fixed && GST_PROPS_ENTRY_IS_VARIABLE (entry)) {
-    props->fixed = FALSE;
+  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);
 }
 
 /**
+ * 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);
+
+  props->properties = g_list_remove (props->properties, entry);
+}
+
+/**
+ * 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)
+{
+  GList *lentry;
+  GQuark quark;
+
+  g_return_if_fail (props != NULL);
+  g_return_if_fail (name != NULL);
+  
+  quark = g_quark_from_string (name);
+
+  lentry = g_list_find_custom (props->properties, GINT_TO_POINTER (quark), props_find_func);
+  if (lentry) {
+    gst_props_remove_entry (props, (GstPropsEntry *)lentry->data);
+  }
+}
+
+/**
  * gst_props_new:
  * @firstname: the first property name
  * @...: the property values 
@@ -413,6 +503,8 @@ gst_props_debug (GstProps *props)
 {
   GList *propslist = props->properties;
 
+  GST_DEBUG (GST_CAT_PROPERTIES, "props %p, refcount %d, flags %d", props, props->refcount, props->flags);
+
   while (propslist) { 
     GstPropsEntry *entry = (GstPropsEntry *)propslist->data;
 
@@ -434,7 +526,7 @@ gst_props_debug (GstProps *props)
  * Returns: TRUE if the entries were merged, FALSE otherwise.
  */
 static gboolean
-gst_props_merge_int_entries(GstPropsEntry * newentry, GstPropsEntry * oldentry)
+gst_props_merge_int_entries(GstPropsEntry *newentry, GstPropsEntry *oldentry)
 {
   gint new_min, new_max, old_min, old_max;
   gboolean can_merge = FALSE;
@@ -501,21 +593,20 @@ gst_props_merge_int_entries(GstPropsEntry * newentry, GstPropsEntry * oldentry)
  *
  * Returns: a pointer to a list with the new entry added.
  */
-static GList *
-gst_props_add_to_int_list (GList * entries, GstPropsEntry * newentry)
+static GList*
+gst_props_add_to_int_list (GList *entries, GstPropsEntry *newentry)
 {
-  GList * i;
+  GList *i;
 
   i = entries;
   while (i) {
-    GstPropsEntry * oldentry = (GstPropsEntry *)(i->data);
+    GstPropsEntry *oldentry = (GstPropsEntry *)(i->data);
     gboolean merged = gst_props_merge_int_entries(newentry, oldentry);
 
     if (merged) {
       /* replace the existing one with the merged one */
-      g_mutex_lock (_gst_props_entries_chunk_lock);
-      g_mem_chunk_free (_gst_props_entries_chunk, oldentry);
-      g_mutex_unlock (_gst_props_entries_chunk_lock);
+      gst_props_entry_destroy (oldentry);
+
       entries = g_list_remove_link (entries, i);
       g_list_free_1 (i);
 
@@ -634,30 +725,24 @@ gst_props_newv (const gchar *firstname, va_list var_args)
 
        /* if list was of size 1, replace the list by a the item it contains */
        if (g_list_length(list_entry->data.list_data.entries) == 1) {
-         GstPropsEntry * subentry = (GstPropsEntry *)(list_entry->data.list_data.entries->data);
+         GstPropsEntry *subentry = (GstPropsEntry *)(list_entry->data.list_data.entries->data);
          list_entry->propstype = subentry->propstype;
          list_entry->data = subentry->data;
-         g_mutex_lock (_gst_props_entries_chunk_lock);
-         g_mem_chunk_free (_gst_props_entries_chunk, subentry);
-         g_mutex_unlock (_gst_props_entries_chunk_lock);
+          gst_props_entry_destroy (subentry);
        }
        else {
          list_entry->data.list_data.entries =
                    g_list_reverse (list_entry->data.list_data.entries);
        }
 
-        g_mutex_lock (_gst_props_entries_chunk_lock);
-        g_mem_chunk_free (_gst_props_entries_chunk, entry);
-        g_mutex_unlock (_gst_props_entries_chunk_lock);
+        gst_props_entry_destroy (entry);
        inlist = FALSE;
        list_entry = NULL;
         prop_name = va_arg (var_args, gchar*);
        continue;
       default:
        g_warning ("unknown property type found %d for '%s'\n", entry->propstype, prop_name);
-        g_mutex_lock (_gst_props_entries_chunk_lock);
-        g_mem_chunk_free (_gst_props_entries_chunk, entry);
-        g_mutex_unlock (_gst_props_entries_chunk_lock);
+        gst_props_entry_destroy (entry);
        break;
     }
 
@@ -721,9 +806,8 @@ gst_props_set (GstProps *props, const gchar *name, ...)
     entry = (GstPropsEntry *)lentry->data;
 
     va_start (var_args, name);
-
+    gst_props_entry_clean (entry);
     GST_PROPS_ENTRY_FILL (entry, var_args);
-
     va_end (var_args);
   }
   else {
@@ -740,17 +824,27 @@ gst_props_set (GstProps *props, const gchar *name, ...)
  *
  * 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.
  */
-void
+GstProps*
 gst_props_unref (GstProps *props)
 {
   if (props == NULL)
-    return;
+    return NULL;
   
+  g_return_val_if_fail (props->refcount > 0, NULL);
+
+  GST_DEBUG (GST_CAT_PROPERTIES, "unref %p (%d->%d)", props, props->refcount, props->refcount-1);
   props->refcount--;
 
-  if (props->refcount == 0)
+  if (props->refcount == 0) {
     gst_props_destroy (props);
+    return NULL;
+  }
+
+  return props;
 }
 
 /**
@@ -758,15 +852,44 @@ gst_props_unref (GstProps *props)
  * @props: the props to ref
  *
  * Increase the refcount of the property structure.
+ *
+ * Returns: handle to refed props.
  */
-void
+GstProps*
 gst_props_ref (GstProps *props)
 {
-  g_return_if_fail (props != NULL);
+  if (props == NULL)
+    return NULL;
+
+  g_return_val_if_fail (props->refcount > 0, NULL);
+
+  GST_DEBUG (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_DEBUG (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:
@@ -791,26 +914,31 @@ gst_props_destroy (GstProps *props)
   }
   g_list_free (props->properties);
 
-  g_mutex_lock (_gst_props_chunk_lock);
-  g_mem_chunk_free (_gst_props_chunk, props);
-  g_mutex_unlock (_gst_props_chunk_lock);
+  gst_mem_chunk_free (_gst_props_chunk, props);
+  gst_alloc_trace_free (_props_trace, props);
 }
 
 /* 
  * copy entries 
  */
 GstPropsEntry*
-gst_props_entry_copy (GstPropsEntry *entry)
+gst_props_entry_copy (const GstPropsEntry *entry)
 {
   GstPropsEntry *newentry;
 
   newentry = gst_props_alloc_entry ();
   memcpy (newentry, entry, sizeof (GstPropsEntry));
-  if (entry->propstype == GST_PROPS_LIST_TYPE) {
-    newentry->data.list_data.entries = gst_props_list_copy (entry->data.list_data.entries);
-  }
-  else if (entry->propstype == GST_PROPS_STRING_TYPE) {
-    newentry->data.string_data.string = g_strdup (entry->data.string_data.string);
+
+  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;
@@ -852,7 +980,7 @@ gst_props_copy (GstProps *props)
 
   new = gst_props_empty_new ();
   new->properties = gst_props_list_copy (props->properties);
-  new->fixed = props->fixed;
+  GST_PROPS_FLAGS (new) = GST_PROPS_FLAGS (props) | GST_PROPS_FLOATING;
 
   return new;
 }
@@ -1076,7 +1204,7 @@ gst_props_getv (GstProps *props, gboolean safe, gchar *first_name, va_list var_a
     gboolean result;
 
     if (!entry) return FALSE;
-    GST_PROPS_ENTRY_READ (entry, var_args, FALSE, &result);
+    GST_PROPS_ENTRY_READ (entry, var_args, safe, &result);
     if (!result) return FALSE;
 
     first_name = va_arg (var_args, gchar *);
@@ -1091,8 +1219,9 @@ gst_props_getv (GstProps *props, gboolean safe, gchar *first_name, va_list var_a
  * @...: 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 is the props entry could be fetched.
+ * Returns: TRUE if all of the props entries could be fetched.
  */
 gboolean
 gst_props_get (GstProps *props, gchar *first_name, ...)
@@ -1115,7 +1244,7 @@ gst_props_get (GstProps *props, gchar *first_name, ...)
  *
  * Gets the contents of the props into given key/value pairs.
  *
- * Returns: TRUE is the props entry could be fetched.
+ * Returns: TRUE if all of the props entries could be fetched.
  */
 gboolean
 gst_props_get_safe (GstProps *props, gchar *first_name, ...)
@@ -1138,7 +1267,7 @@ gst_props_get_safe (GstProps *props, gchar *first_name, ...)
  * 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.
+ * entry is not of given type or did not exist.
  */
 gboolean
 gst_props_entry_get_int (const GstPropsEntry *entry, gint *val)
@@ -1154,7 +1283,7 @@ gst_props_entry_get_int (const GstPropsEntry *entry, gint *val)
  * 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.
+ * entry is not of given type or did not exist.
  */
 gboolean
 gst_props_entry_get_float (const GstPropsEntry *entry, gfloat *val)
@@ -1170,7 +1299,7 @@ gst_props_entry_get_float (const GstPropsEntry *entry, gfloat *val)
  * 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.
+ * entry is not of given type or did not exist.
  */
 gboolean
 gst_props_entry_get_fourcc_int (const GstPropsEntry *entry, guint32 *val)
@@ -1186,7 +1315,7 @@ gst_props_entry_get_fourcc_int (const GstPropsEntry *entry, guint32 *val)
  * 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.
+ * entry is not of given type or did not exist.
  */
 gboolean
 gst_props_entry_get_boolean (const GstPropsEntry *entry, gboolean *val)
@@ -1202,7 +1331,7 @@ gst_props_entry_get_boolean (const GstPropsEntry *entry, gboolean *val)
  * 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.
+ * entry is not of given type or did not exist.
  */
 gboolean
 gst_props_entry_get_string (const GstPropsEntry *entry, const gchar **val)
@@ -1219,7 +1348,7 @@ gst_props_entry_get_string (const GstPropsEntry *entry, const gchar **val)
  * 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.
+ * entry is not of given type or did not exist.
  */
 gboolean
 gst_props_entry_get_int_range (const GstPropsEntry *entry, gint *min, gint *max)
@@ -1236,7 +1365,7 @@ gst_props_entry_get_int_range (const GstPropsEntry *entry, gint *min, gint *max)
  * 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.
+ * entry is not of given type or did not exist.
  */
 gboolean
 gst_props_entry_get_float_range (const GstPropsEntry *entry, gfloat *min, gfloat *max)
@@ -1252,7 +1381,7 @@ gst_props_entry_get_float_range (const GstPropsEntry *entry, gfloat *min, gfloat
  * 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.
+ * entry is not of given type or did not exist.
  */
 gboolean
 gst_props_entry_get_list (const GstPropsEntry *entry, const GList **val)
@@ -1530,7 +1659,7 @@ gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2)
        if (intersectentry) {
          if (intersectentry->propstype == GST_PROPS_LIST_TYPE) {
            intersection = g_list_concat (intersection, 
-                           g_list_copy (intersectentry->data.list_data.entries));
+                              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;
@@ -1590,7 +1719,7 @@ gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2)
           result->propstype = GST_PROPS_LIST_TYPE;
           result->data.list_data.entries = NULL;
           while (entries) {
-            GstPropsEntry * this = (GstPropsEntry *)entries->data;
+            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);
@@ -1598,18 +1727,24 @@ gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2)
               break;
             }
             if (this->data.int_data >= entry1->data.int_range_data.min &&
-                this->data.int_data <= entry1->data.int_range_data.max) {
-              result->data.list_data.entries = g_list_append (result->data.list_data.entries,
-                                                              gst_props_entry_copy (this));
+                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) {
+             entry1->data.int_range_data.max >= entry2->data.int_data) 
+         {
             result = gst_props_entry_copy (entry2);
          }
           break;
@@ -1644,7 +1779,8 @@ gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2)
        }
         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) {
+             entry1->data.float_range_data.max >= entry2->data.float_data) 
+         {
             result = gst_props_entry_copy (entry2);
          }
         default:
@@ -1706,6 +1842,17 @@ gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2)
   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
+  
 /**
  * gst_props_intersect:
  * @props1: a property
@@ -1714,7 +1861,8 @@ gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2)
  * Calculates the intersection bewteen two GstProps.
  *
  * Returns: a GstProps with the intersection or NULL if the 
- * intersection is empty.
+ * intersection is empty. The new GstProps is floating and must
+ * be unreffed afetr use.
  */
 GstProps*
 gst_props_intersect (GstProps *props1, GstProps *props2)
@@ -1725,11 +1873,10 @@ gst_props_intersect (GstProps *props1, GstProps *props2)
   GList *leftovers;
   GstPropsEntry *iprops = NULL;
 
-  intersection = gst_props_empty_new ();
-  intersection->fixed = TRUE;
-
   g_return_val_if_fail (props1 != NULL, NULL);
   g_return_val_if_fail (props2 != NULL, NULL);
+
+  intersection = gst_props_empty_new ();
        
   props1list = props1->properties;
   props2list = props2->properties;
@@ -1742,74 +1889,47 @@ gst_props_intersect (GstProps *props1, GstProps *props2)
     entry2 = (GstPropsEntry *)props2list->data;
 
     while (entry1->propid < entry2->propid) {
-      GstPropsEntry *toadd;
-
-      /* FIXME: this needs more explanation; 
-       * I've had format "int" < format "int" ! */
-      GST_DEBUG (GST_CAT_PROPERTIES, "source is more specific in \"%s\"", 
-                g_quark_to_string (entry1->propid));
-
-      toadd = gst_props_entry_copy (entry1);
-      if (GST_PROPS_ENTRY_IS_VARIABLE (toadd))
-       intersection->fixed = FALSE;
-
-      intersection->properties = g_list_prepend (intersection->properties, toadd);
+      gst_props_entry_add_sorted_prepend (intersection, gst_props_entry_copy (entry1));
 
       props1list = g_list_next (props1list);
-      if (props1list) 
-       entry1 = (GstPropsEntry *)props1list->data;
-      else 
+      if (!props1list) 
        goto end;
+
+      entry1 = (GstPropsEntry *)props1list->data;
     }
     while (entry1->propid > entry2->propid) {
-      GstPropsEntry *toadd;
-
-      toadd = gst_props_entry_copy (entry2);
-      if (GST_PROPS_ENTRY_IS_VARIABLE (toadd))
-       intersection->fixed = FALSE;
-
-      intersection->properties = g_list_prepend (intersection->properties, toadd);
+      gst_props_entry_add_sorted_prepend (intersection, gst_props_entry_copy (entry2));
 
       props2list = g_list_next (props2list);
-      if (props2list)
-       entry2 = (GstPropsEntry *)props2list->data;
-      else 
+      if (!props2list) 
        goto end;
+
+      entry2 = (GstPropsEntry *)props2list->data;
     }
     /* at this point we are talking about the same property */
     iprops = gst_props_entry_intersect (entry1, entry2);
-
-    if (iprops) {
-      if (GST_PROPS_ENTRY_IS_VARIABLE (iprops))
-       intersection->fixed = FALSE;
-      intersection->properties = g_list_prepend (intersection->properties, iprops);
-    }
-    else {
+    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 */
-  if (props1list)
-    leftovers = props1list;
-  else if (props2list)
+  /* at this point one of the lists could contain leftover properties, while
+   * the other one is NULL */
+  leftovers = props1list;
+  if (!leftovers)
     leftovers = props2list;
-  else 
-    leftovers = NULL;
 
   while (leftovers) {
-    GstPropsEntry *entry;
-
-    entry = (GstPropsEntry *) leftovers->data;
-    if (GST_PROPS_ENTRY_IS_VARIABLE (entry))
-      intersection->fixed = FALSE;
-    intersection->properties = g_list_prepend (intersection->properties, gst_props_entry_copy (entry));
-
+    gst_props_entry_add_sorted_prepend (intersection, 
+                        gst_props_entry_copy ((GstPropsEntry *) leftovers->data));
     leftovers = g_list_next (leftovers);
   }
 
@@ -1825,7 +1945,8 @@ end:
  * 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.
+ * Returns: A GList with the unrolled props entries. g_list_free 
+ * after usage.
  */
 GList*
 gst_props_normalize (GstProps *props)
@@ -1850,11 +1971,11 @@ gst_props_normalize (GstProps *props)
        GstProps *newprops;
        GList *lentry;
 
-       newprops = gst_props_empty_new ();
-       newprops->properties = gst_props_list_copy (props->properties);
+       /* FIXME fixed flags is probably messed up here */
+       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 = NULL;
+          GList *new_list;
 
           new_entry = (GstPropsEntry *) lentry->data;
          memcpy (new_entry, list_entry, sizeof (GstPropsEntry));
@@ -1863,6 +1984,7 @@ gst_props_normalize (GstProps *props)
           result = g_list_concat (new_list, result);
        }
        else {
+          /* FIXME append or prepend */
           result = g_list_append (result, newprops);
        }
        
@@ -1875,11 +1997,11 @@ gst_props_normalize (GstProps *props)
     entries = g_list_next (entries);
   }
   if (!result) {
+    /* no result, create list with input props */
     result = g_list_prepend (result, props);
   }
   else {
     result = g_list_reverse (result);
-    gst_props_unref (props);
   }
   return result;
 }
@@ -2073,9 +2195,7 @@ gst_props_load_thyself_func (xmlNodePtr field)
     entry->data.string_data.string = xmlGetProp (field, "value");
   }
   else {
-    g_mutex_lock (_gst_props_entries_chunk_lock);
-    g_mem_chunk_free (_gst_props_entries_chunk, entry);
-    g_mutex_unlock (_gst_props_entries_chunk_lock);
+    gst_props_entry_destroy (entry);
     entry = NULL;
   }