- implement FLOATING flag on caps/props
authorWim Taymans <wim.taymans@gmail.com>
Sun, 2 Feb 2003 19:58:11 +0000 (19:58 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Sun, 2 Feb 2003 19:58:11 +0000 (19:58 +0000)
Original commit message from CVS:
- implement FLOATING flag on caps/props
- use gstmemchunk for caps/props
- implement remove_entry for props
- various refcounting functions
- fix refcounting on caps/props
- use tracing for caps/props/propsentries
- fix memleak in transform functions
- fix refcounting on elementfactory padtemplates
- add dispose for padtemplates
- shortcut pad negotiation early on

gst/gstcaps.c
gst/gstcaps.h
gst/gstelementfactory.c
gst/gstpad.c
gst/gstpad.h
gst/gstparse.c
gst/gstprops.c
gst/gstprops.h

index 0ac7baf..57de568 100644 (file)
 
 #include "gstcaps.h"
 #include "gsttype.h"
+#include "gstmemchunk.h"
 #include "gstlog.h"
 
-static GMemChunk *_gst_caps_chunk;
-static GMutex *_gst_caps_chunk_lock;
+/* #define GST_WITH_ALLOC_TRACE */
+#include "gsttrace.h"
+
+static GstMemChunk *_gst_caps_chunk;
+
+static GstAllocTrace *_gst_caps_trace;
 
 GType _gst_caps_type;
 
@@ -52,22 +57,23 @@ transform_func (const GValue *src_value,
     g_value_set_boxed  (&value, caps->properties);
     props = g_strdup_value_contents (&value);
 
+    g_value_unset (&value);
     g_string_append (result, props);
     g_free (props);
 
     caps = caps->next;
-    g_string_append_printf (result, " }%s", caps?", ":"");
+    g_string_append_printf (result, " }%s", (caps ? ", " : ""));
   }
   dest_value->data[0].v_pointer = result->str;
+  g_string_free (result, FALSE);
 }
 
 void
 _gst_caps_initialize (void)
 {
-  _gst_caps_chunk = g_mem_chunk_new ("GstCaps",
+  _gst_caps_chunk = gst_mem_chunk_new ("GstCaps",
                   sizeof (GstCaps), sizeof (GstCaps) * 256,
                   G_ALLOC_AND_FREE);
-  _gst_caps_chunk_lock = g_mutex_new ();
 
   _gst_caps_type = g_boxed_type_register_static ("GstCaps",
                                        (GBoxedCopyFunc) gst_caps_ref,
@@ -76,6 +82,8 @@ _gst_caps_initialize (void)
   g_value_register_transform_func (_gst_caps_type,
                                   G_TYPE_STRING,
                                   transform_func);
+
+  _gst_caps_trace = gst_alloc_trace_register (GST_CAPS_TRACE_NAME);
 }
 
 static guint16
@@ -133,24 +141,63 @@ gst_caps_new_id (const gchar *name, const guint16 id, GstProps *props)
 {
   GstCaps *caps;
 
-  g_mutex_lock (_gst_caps_chunk_lock);
-  caps = g_mem_chunk_alloc (_gst_caps_chunk);
-  g_mutex_unlock (_gst_caps_chunk_lock);
+  caps = gst_mem_chunk_alloc (_gst_caps_chunk);
+  gst_alloc_trace_new (_gst_caps_trace, caps);
+
+  GST_DEBUG (GST_CAT_CAPS, "new %p", caps);
+
+  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;
-  if (props)
-    caps->fixed = props->fixed;
+  GST_CAPS_FLAG_SET (caps, GST_CAPS_FLOATING);
+
+  if (props && !GST_PROPS_IS_FIXED (props))
+    GST_CAPS_FLAG_UNSET (caps, GST_CAPS_FIXED);
   else
-    caps->fixed = TRUE;
+    GST_CAPS_FLAG_SET (caps, GST_CAPS_FIXED);
 
   return caps;
 }
 
 /**
+ * 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
  *
@@ -167,11 +214,13 @@ gst_caps_destroy (GstCaps *caps)
 
   next = caps->next;
 
+  GST_DEBUG (GST_CAT_CAPS, "destroy %p", caps);
+
   gst_props_unref (caps->properties);
   g_free (caps->name);
-  g_mutex_lock (_gst_caps_chunk_lock);
-  g_mem_chunk_free (_gst_caps_chunk, caps);
-  g_mutex_unlock (_gst_caps_chunk_lock);
+
+  gst_alloc_trace_free (_gst_caps_trace, caps);
+  gst_mem_chunk_free (_gst_caps_chunk, caps);
 
   if (next) 
     gst_caps_unref (next);
@@ -189,8 +238,10 @@ gst_caps_debug (GstCaps *caps, const gchar *label)
 {
   GST_DEBUG_ENTER ("caps debug: %s", label);
   while (caps) {
-    GST_DEBUG (GST_CAT_CAPS, "caps: %p %s %s (%sfixed)", caps, caps->name, gst_caps_get_mime (caps), 
-               caps->fixed ? "" : "NOT ");
+    GST_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);
@@ -223,6 +274,9 @@ gst_caps_unref (GstCaps *caps)
 
   g_return_val_if_fail (caps->refcount > 0, NULL);
 
+  GST_DEBUG (GST_CAT_CAPS, "unref %p (%d->%d) %d", 
+            caps, caps->refcount, caps->refcount-1, GST_CAPS_FLAGS (caps));
+
   caps->refcount--;
   zero = (caps->refcount == 0);
 
@@ -244,7 +298,13 @@ gst_caps_unref (GstCaps *caps)
 GstCaps*
 gst_caps_ref (GstCaps *caps)
 {
-  g_return_val_if_fail (caps != NULL, NULL);
+  if (caps == NULL)
+    return NULL;
+
+  g_return_val_if_fail (caps->refcount > 0, NULL);
+
+  GST_DEBUG (GST_CAT_CAPS, "ref %p (%d->%d) %d", 
+            caps, caps->refcount, caps->refcount+1, GST_CAPS_FLAGS (caps));
 
   caps->refcount++;
 
@@ -252,12 +312,32 @@ gst_caps_ref (GstCaps *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_DEBUG (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 copy of the GstCaps structure.
+ * Returns: a floating copy of the GstCaps structure.
  */
 GstCaps*
 gst_caps_copy_1 (GstCaps *caps)
@@ -281,7 +361,7 @@ gst_caps_copy_1 (GstCaps *caps)
  *
  * Copies the caps.
  *
- * Returns: a copy of the GstCaps structure.
+ * Returns: a floating copy of the GstCaps structure.
  */
 GstCaps*
 gst_caps_copy (GstCaps *caps)
@@ -312,7 +392,7 @@ gst_caps_copy (GstCaps *caps)
  * Copies the caps if the refcount is greater than 1
  *
  * Returns: a pointer to a GstCaps strcuture that can
- * be safely written to
+ * be safely written to.
  */
 GstCaps*
 gst_caps_copy_on_write (GstCaps *caps)
@@ -360,9 +440,7 @@ gst_caps_set_name (GstCaps *caps, const gchar *name)
 {
   g_return_if_fail (caps != NULL);
 
-  if (caps->name)
-    g_free (caps->name);
-
+  g_free (caps->name);
   caps->name = g_strdup (name);
 }
 
@@ -449,10 +527,8 @@ GstCaps*
 gst_caps_set_props (GstCaps *caps, GstProps *props)
 {
   g_return_val_if_fail (caps != NULL, caps);
-  g_return_val_if_fail (props != NULL, caps);
-  g_return_val_if_fail (caps->properties == NULL, caps);
 
-  caps->properties = props;
+  gst_props_replace_sink (&caps->properties, props);
 
   return caps;
 }
@@ -474,6 +550,23 @@ gst_caps_get_props (GstCaps *caps)
 }
 
 /**
+ * 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
@@ -523,7 +616,7 @@ gst_caps_append (GstCaps *caps, GstCaps *capstoadd)
   while (caps->next) {
     caps = caps->next;
   }
-  caps->next = capstoadd;
+  gst_caps_replace_sink (&caps->next, capstoadd);
 
   return orig;
 }
@@ -550,7 +643,7 @@ gst_caps_prepend (GstCaps *caps, GstCaps *capstoadd)
   while (capstoadd->next) {
     capstoadd = capstoadd->next;
   }
-  capstoadd->next = caps;
+  gst_caps_replace_sink (&capstoadd->next, caps);
 
   return orig;
 }
@@ -679,6 +772,8 @@ gst_caps_intersect_func (GstCaps *caps1, GstCaps *caps2)
   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;
@@ -692,7 +787,7 @@ gst_caps_intersect_func (GstCaps *caps1, GstCaps *caps2)
  * Make the intersection between two caps.
  *
  * Returns: The intersection of the two caps or NULL if the intersection
- * is empty.
+ * is empty. unref the caps after use.
  */
 GstCaps*
 gst_caps_intersect (GstCaps *caps1, GstCaps *caps2)
@@ -704,11 +799,16 @@ gst_caps_intersect (GstCaps *caps1, GstCaps *caps2)
                  
   if (caps1 == NULL) {
     GST_DEBUG (GST_CAT_CAPS, "first caps is NULL, return other caps");
-    return gst_caps_copy (caps2);
+    return gst_caps_ref (caps2);
   }
   if (caps2 == NULL) {
     GST_DEBUG (GST_CAT_CAPS, "second caps is NULL, return other caps");
-    return gst_caps_copy (caps1);
+    return gst_caps_ref (caps1);
+  }
+
+  /* same caps */
+  if (caps1 == caps2) {
+    return gst_caps_ref (caps1);
   }
 
   while (caps1) {
@@ -729,7 +829,27 @@ gst_caps_intersect (GstCaps *caps1, GstCaps *caps2)
       }
       othercaps = othercaps->next;
     }
-    caps1 =  caps1->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_DEBUG (GST_CAT_CAPS, "making union of caps %p and %p", caps1, caps2);
+                 
+  if (caps1 == NULL) {
+    GST_DEBUG (GST_CAT_CAPS, "first caps is NULL, return other caps");
+    return gst_caps_ref (caps2);
+  }
+  if (caps2 == NULL) {
+    GST_DEBUG (GST_CAT_CAPS, "second caps is NULL, return other caps");
+    return gst_caps_ref (caps1);
   }
 
   return result;
@@ -742,43 +862,40 @@ gst_caps_intersect (GstCaps *caps1, GstCaps *caps2)
  * 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.
+ * the caps. unref the caps after use.
  *
- * Returns: The normalisation of the caps.
+ * Returns: The normalisation of the caps. Unref after usage.
  */
 GstCaps*
 gst_caps_normalize (GstCaps *caps)
 {
-  GstCaps *result = NULL, *walk = caps;
+  GstCaps *result = NULL, *walk;
 
   if (caps == NULL)
     return caps;
 
+  GST_DEBUG (GST_CAT_CAPS, "normalizing caps %p ", caps);
+
+  walk = caps;
+
   while (caps) {
     GList *proplist;
 
     proplist = gst_props_normalize (caps->properties);
-    if (proplist && g_list_next (proplist) == NULL) {
-      if (result == NULL)
-       walk = result = caps;
-      else {
-       walk = walk->next = caps;
-      }
-      goto next;
-    }
-
     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;
+       walk = walk->next = newcaps;
       }
       proplist = g_list_next (proplist);  
     }
-next:
     caps = caps->next;
   }
   return result;
@@ -836,13 +953,13 @@ gst_caps_load_thyself (xmlNodePtr parent)
       xmlNodePtr subfield = field->xmlChildrenNode;
       GstCaps *caps;
       gchar *content;
-      gboolean fixed = TRUE;
+      GstCapsFlags fixed = GST_CAPS_FIXED;
 
-      g_mutex_lock (_gst_caps_chunk_lock);
-      caps = g_mem_chunk_alloc0 (_gst_caps_chunk);
-      g_mutex_unlock (_gst_caps_chunk_lock);
+      caps = gst_mem_chunk_alloc0 (_gst_caps_chunk);
+      gst_alloc_trace_new (_gst_caps_trace, caps);
 
       caps->refcount = 1;
+      GST_CAPS_FLAG_SET (caps, GST_CAPS_FLOATING);
       caps->next = NULL;
        
       while (subfield) {
@@ -855,13 +972,18 @@ gst_caps_load_thyself (xmlNodePtr parent)
           g_free (content);
         }
         else if (!strcmp (subfield->name, "properties")) {
-          caps->properties = gst_props_load_thyself (subfield);
-          fixed &= caps->properties->fixed;
+          GstProps *props = gst_props_load_thyself (subfield);
+
+         gst_props_ref (props);
+         gst_props_sink (props);
+          caps->properties = props;
+
+          fixed &= (GST_PROPS_IS_FIXED (caps->properties) ? GST_CAPS_FIXED : 0 );
         }
        
         subfield = subfield->next;
       }
-      caps->fixed = fixed;
+      GST_CAPS_FLAG_SET (caps, fixed);
 
       result = gst_caps_append (result, caps);
     }
index cabd478..2168bc9 100644 (file)
@@ -30,28 +30,43 @@ 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)
 
+typedef enum {
+  GST_CAPS_FIXED       = (1 << 0),     /* caps has no variable properties */
+  GST_CAPS_FLOATING    = (1 << 1)      /* caps is floating */
+} GstCapsFlags;
 
 #define GST_CAPS(caps)         ((GstCaps *)(caps))
 
-#define GST_CAPS_IS_FIXED(caps)                ((caps)->fixed)
-#define GST_CAPS_IS_CHAINED(caps)      ((caps)->next)
+#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)                (GST_CAPS_FLAGS (caps) & GST_CAPS_FIXED)
+#define GST_CAPS_IS_FLOATING(caps)     (GST_CAPS_FLAGS (caps) & GST_CAPS_FLOATING)
+#define GST_CAPS_IS_CHAINED(caps)      (GST_CAPS_NEXT (caps) != NULL)
 
-/* CR1: id is an int corresponding to the quark for the mime type because
- * it's really fast when doing a first-pass check for caps compatibility */
 struct _GstCaps {
+  /* --- public --- */
   gchar        *name;                  /* the name of this caps */
-  guint16      id;                     /* type id (major type) representing 
-                                          the mime type */
+  guint16       id;                    /* type id (major type) representing 
+                                          the mime type, it's stored as a GQuark 
+                                          for speed/space reasons */
 
-  guint        refcount;               
-  gboolean     fixed;                  /* this caps doesn't contain variable properties */
+  guint16       flags;                 /* flags */
+  guint         refcount;              
 
   GstProps     *properties;            /* properties for this capability */
-
   GstCaps      *next;                  /* not with a GList for efficiency */
 };
 
@@ -97,21 +112,30 @@ factoryname (void)                              \
 }
 #endif
 
+/* get caps from a factory */
 #define GST_CAPS_GET(fact) (fact)()
 
 
 /* initialize the subsystem */
 void           _gst_caps_initialize                    (void);
 
+/* creating new caps */
 GstCaps*       gst_caps_new                            (const gchar *name, const gchar *mime, GstProps *props);
 GstCaps*       gst_caps_new_id                         (const gchar *name, const guint16 id, GstProps *props);
+/* 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);
 void           gst_caps_destroy                        (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);
@@ -148,12 +172,18 @@ GstProps* gst_caps_get_props                      (GstCaps *caps);
 
 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
index 4b2b539..4254646 100644 (file)
@@ -122,11 +122,27 @@ gst_element_details_free (GstElementDetails *dp)
 static void
 gst_element_factory_cleanup (GstElementFactory *factory)
 {
+  GList *padtemplates;
+
   if (factory->details_dynamic) {
     gst_element_details_free (factory->details);
     factory->details_dynamic = FALSE;
   }
 
+  padtemplates = factory->padtemplates;
+
+  while (padtemplates) {
+    GstPadTemplate *oldtempl = GST_PAD_TEMPLATE (padtemplates->data);
+     
+    gst_object_unref (GST_OBJECT (oldtempl));
+
+    padtemplates = g_list_next (padtemplates);
+  }
+  g_list_free (factory->padtemplates);
+
+  factory->padtemplates = NULL;
+  factory->numpadtemplates = 0;
+
   g_free (GST_PLUGIN_FEATURE (factory)->name);
 }
 
@@ -301,28 +317,14 @@ gst_element_factory_make_or_warn (const gchar *factoryname, const gchar *name)
  */
 void
 gst_element_factory_add_pad_template (GstElementFactory *factory,
-                                   GstPadTemplate *templ)
+                                     GstPadTemplate *templ)
 {
-  GList *padtemplates;
-  
   g_return_if_fail (factory != NULL);
   g_return_if_fail (templ != NULL);
 
-  padtemplates = factory->padtemplates;
-
   gst_object_ref (GST_OBJECT (templ));
+  gst_object_sink (GST_OBJECT (templ));
 
-  while (padtemplates) {
-    GstPadTemplate *oldtempl = GST_PAD_TEMPLATE (padtemplates->data);
-    
-    if (!strcmp (oldtempl->name_template, templ->name_template)) {
-      gst_object_unref (GST_OBJECT (oldtempl));
-      padtemplates->data = templ;
-      return;
-    }
-    
-    padtemplates = g_list_next (padtemplates);
-  }
   factory->padtemplates = g_list_append (factory->padtemplates, templ);
   factory->numpadtemplates++;
 }
index 1c372d4..71e20e7 100644 (file)
@@ -842,15 +842,15 @@ gst_pad_unlink (GstPad *srcpad,
 
   /* reset the filters, both filters are refcounted once */
   if (GST_RPAD_FILTER (realsrc)) {
-    gst_caps_unref (GST_RPAD_FILTER (realsrc));
-    GST_RPAD_FILTER (realsink) = NULL;
-    GST_RPAD_FILTER (realsrc) = NULL;
+    gst_caps_replace (&GST_RPAD_FILTER (realsink), NULL);
+    gst_caps_replace (&GST_RPAD_FILTER (realsrc), NULL);
   }
 
   /* now tell the scheduler */
   if (src_sched && src_sched == sink_sched) {
     gst_scheduler_pad_unlink (src_sched, 
-                                 GST_PAD_CAST (realsrc), GST_PAD_CAST (realsink));
+                             GST_PAD_CAST (realsrc), 
+                             GST_PAD_CAST (realsink));
   }
 
   /* hold a reference, as they can go away in the signal handlers */
@@ -906,7 +906,7 @@ gst_pad_check_schedulers (GstRealPad *realsrc, GstRealPad *realsink)
  */
 gboolean
 gst_pad_can_link_filtered (GstPad *srcpad, GstPad *sinkpad,
-                              GstCaps *filtercaps)
+                           GstCaps *filtercaps)
 {
   GstRealPad *realsrc, *realsink;
 
@@ -1041,7 +1041,7 @@ gst_pad_link_filtered (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps)
 
   /* try to negotiate the pads, we don't need to clear the caps here */
   if (!gst_pad_try_relink_filtered_func (realsrc, realsink,
-                                           filtercaps, FALSE)) {
+                                        filtercaps, FALSE)) {
     GST_DEBUG (GST_CAT_CAPS, "relink_filtered_func failed, can't link");
 
     GST_RPAD_PEER (realsrc) = NULL;
@@ -1063,13 +1063,11 @@ gst_pad_link_filtered (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps)
   /* now tell the scheduler */
   if (src_sched && src_sched == sink_sched) {
     gst_scheduler_pad_link (src_sched, 
-                              GST_PAD_CAST (realsrc), GST_PAD_CAST (realsink));
+                           GST_PAD_CAST (realsrc), GST_PAD_CAST (realsink));
   }
 
   GST_INFO (GST_CAT_PADS, "linked %s:%s and %s:%s, successful",
             GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
-  gst_caps_debug (gst_pad_get_caps (GST_PAD_CAST (realsrc)), 
-                  "caps of newly linked src pad");
 
   return TRUE;
 }
@@ -1271,7 +1269,7 @@ gst_pad_get_ghost_pad_list (GstPad *pad)
 static GstPadLinkReturn
 gst_pad_try_set_caps_func (GstRealPad *pad, GstCaps *caps, gboolean notify)
 {
-  GstCaps *oldcaps, *allowed = NULL;
+  GstCaps *allowed = NULL;
   GstPadTemplate *template;
   GstElement *parent = GST_PAD_PARENT (pad);
 
@@ -1290,8 +1288,9 @@ gst_pad_try_set_caps_func (GstRealPad *pad, GstCaps *caps, gboolean notify)
   GST_INFO (GST_CAT_CAPS, "trying to set caps %p on pad %s:%s",
             caps, GST_DEBUG_PAD_NAME (pad));
 
-  /* first see if we have to check against a filter */
-  if (!(allowed = GST_RPAD_FILTER (pad))) {
+  /* first see if we have to check against a filter, we ref the caps here as we're
+   * going to unref it later on */
+  if (!(allowed = gst_caps_ref (GST_RPAD_FILTER (pad)))) {
     /* no filter, make sure we check against the padtemplate then */
     if ((template = gst_pad_get_pad_template (GST_PAD_CAST (pad)))) {
       allowed = gst_pad_template_get_caps (template);
@@ -1312,10 +1311,12 @@ gst_pad_try_set_caps_func (GstRealPad *pad, GstCaps *caps, gboolean notify)
       gst_caps_debug (caps, "caps themselves (attemped to set)");
       gst_caps_debug (allowed,
                       "allowed caps that did not agree with caps");
+      gst_caps_unref (allowed);
       return GST_PAD_LINK_REFUSED;
     }
     /* caps checks out fine, we can unref the intersection now */
     gst_caps_unref (intersection);
+    gst_caps_unref (allowed);
     /* given that the caps are fixed, we know that their intersection with the
      * padtemplate caps is the same as caps itself */
   }
@@ -1383,10 +1384,7 @@ gst_pad_try_set_caps_func (GstRealPad *pad, GstCaps *caps, gboolean notify)
     GST_INFO (GST_CAT_CAPS, "setting caps on pad %s:%s",
               GST_DEBUG_PAD_NAME (pad));
     /* if we got this far all is ok, remove the old caps, set the new one */
-    oldcaps = GST_PAD_CAPS (pad);
-    if (caps) gst_caps_ref (caps);
-    GST_PAD_CAPS (pad) = caps;
-    if (oldcaps) gst_caps_unref (oldcaps);
+    gst_caps_replace_sink (&GST_PAD_CAPS (pad), caps);
 
     g_object_notify (G_OBJECT (pad), "caps");
   }
@@ -1394,6 +1392,8 @@ gst_pad_try_set_caps_func (GstRealPad *pad, GstCaps *caps, gboolean notify)
     GST_INFO (GST_CAT_CAPS, 
              "caps are not fixed on pad %s:%s, not setting them yet",
               GST_DEBUG_PAD_NAME (pad));
+
+    return GST_PAD_LINK_DELAYED;
   }
   return GST_PAD_LINK_OK;
 }
@@ -1403,7 +1403,8 @@ gst_pad_try_set_caps_func (GstRealPad *pad, GstCaps *caps, gboolean notify)
  * @pad: a #GstPad to try to set the caps on.
  * @caps: the #GstCaps to set.
  *
- * Tries to set the caps on the given pad.
+ * Tries to set the caps on the given pad. Ownership is always taken 
+ * of the caps, so you will need to unref non-floating caps.
  *
  * Returns: A #GstPadLinkReturn value indicating whether the caps
  *             could be set.
@@ -1422,15 +1423,21 @@ gst_pad_try_set_caps (GstPad *pad, GstCaps *caps)
 
   gst_caps_debug (caps, "caps that we are trying to set");
 
+  /* try to take ownership */
+  gst_caps_ref (caps);
+  gst_caps_sink (caps);
+
   /* setting non fixed caps on a pad is not allowed */
   if (!GST_CAPS_IS_FIXED (caps)) {
-  GST_INFO (GST_CAT_CAPS, 
-            "trying to set unfixed caps on pad %s:%s, not allowed",
-           GST_DEBUG_PAD_NAME (realpad));
+    GST_INFO (GST_CAT_CAPS, 
+              "trying to set unfixed caps on pad %s:%s, not allowed",
+             GST_DEBUG_PAD_NAME (realpad));
     g_warning ("trying to set non fixed caps on pad %s:%s, not allowed",
                GST_DEBUG_PAD_NAME (realpad));
+
     gst_caps_debug (caps, "unfixed caps");
-    return GST_PAD_LINK_DELAYED;
+    set_retval = GST_PAD_LINK_DELAYED;
+    goto done;
   }
 
   /* if we have a peer try to set the caps, notifying the peerpad
@@ -1439,7 +1446,7 @@ gst_pad_try_set_caps (GstPad *pad, GstCaps *caps)
   {
     GST_INFO (GST_CAT_CAPS, "tried to set caps on peerpad %s:%s but couldn't, return value %d",
              GST_DEBUG_PAD_NAME (peer), set_retval);
-    return set_retval;
+    goto done;
   }
 
   /* then try to set our own caps, we don't need to be notified */
@@ -1447,12 +1454,16 @@ gst_pad_try_set_caps (GstPad *pad, GstCaps *caps)
   {
     GST_INFO (GST_CAT_CAPS, "tried to set own caps on pad %s:%s but couldn't, return value %d",
              GST_DEBUG_PAD_NAME (realpad), set_retval);
-    return set_retval;
+    goto done;
   }
   GST_INFO (GST_CAT_CAPS, "succeeded setting caps %p on pad %s:%s, return value %d",
            caps, GST_DEBUG_PAD_NAME (realpad), set_retval);
   g_assert (GST_PAD_CAPS (pad));
-                         
+
+done:                    
+  /* if we took ownership, the caps will be freed */
+  gst_caps_unref (caps);
+
   return set_retval;
 }
 
@@ -1486,10 +1497,10 @@ gst_pad_try_relink_filtered_func (GstRealPad *srcpad, GstRealPad *sinkpad,
               GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
 
     /* FIXME does this leak? */
-    GST_PAD_CAPS (GST_PAD (realsrc)) = NULL;
-    GST_PAD_CAPS (GST_PAD (realsink)) = NULL;
-    GST_RPAD_FILTER (realsrc) = NULL
-    GST_RPAD_FILTER (realsink) = NULL
+    gst_caps_replace (&GST_PAD_CAPS (GST_PAD (realsrc)), NULL);
+    gst_caps_replace (&GST_PAD_CAPS (GST_PAD (realsink)), NULL);
+    gst_caps_replace (&GST_RPAD_FILTER (realsrc), NULL)
+    gst_caps_replace (&GST_RPAD_FILTER (realsink), NULL)
   }
   else {
     GST_INFO (GST_CAT_PADS, "start relink filtered %s:%s and %s:%s",
@@ -1515,6 +1526,9 @@ gst_pad_try_relink_filtered_func (GstRealPad *srcpad, GstRealPad *sinkpad,
      * this means they have no common format */
     GST_INFO (GST_CAT_PADS, "pads %s:%s and %s:%s have no common type",
               GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
+    /* make sure any floating caps from gst_pad_get_caps are freed here */
+    gst_caps_sink (srccaps);
+    gst_caps_sink (sinkcaps);
     return FALSE;
   } else  {
     GST_INFO (GST_CAT_PADS, "pads %s:%s and %s:%s intersected to %s caps",
@@ -1523,6 +1537,10 @@ gst_pad_try_relink_filtered_func (GstRealPad *srcpad, GstRealPad *sinkpad,
           (GST_CAPS_IS_FIXED (intersection) ? "fixed" : "variable") :
           "NULL"));
 
+    /* we don't need those anymore, as the caps can be floating */
+    gst_caps_sink (srccaps);
+    gst_caps_sink (sinkcaps);
+
     /* then filter this against the app filter */
     if (filtercaps) {
       GstCaps *filtered_intersection;
@@ -1530,7 +1548,6 @@ gst_pad_try_relink_filtered_func (GstRealPad *srcpad, GstRealPad *sinkpad,
       filtered_intersection = gst_caps_intersect (intersection, 
                                                  filtercaps);
 
-      /* get rid of the old intersection here */
       gst_caps_unref (intersection);
 
       if (!filtered_intersection) {
@@ -1542,8 +1559,8 @@ gst_pad_try_relink_filtered_func (GstRealPad *srcpad, GstRealPad *sinkpad,
       intersection = filtered_intersection;
 
       /* keep a reference to the app caps */
-      GST_RPAD_APPFILTER (realsink) = filtercaps;
-      GST_RPAD_APPFILTER (realsrc) = filtercaps;
+      gst_caps_replace_sink (&GST_RPAD_APPFILTER (realsink), filtercaps);
+      gst_caps_replace_sink (&GST_RPAD_APPFILTER (realsrc), filtercaps);
     }
   }
   GST_DEBUG (GST_CAT_CAPS, "setting filter for link to:");
@@ -1551,8 +1568,9 @@ gst_pad_try_relink_filtered_func (GstRealPad *srcpad, GstRealPad *sinkpad,
 
   /* both the app filter and the filter, while stored on both peer pads, 
    * are equal to the same thing on both */
-  GST_RPAD_FILTER (realsrc) = intersection; 
-  GST_RPAD_FILTER (realsink) = intersection; 
+  gst_caps_replace_sink (&GST_RPAD_FILTER (realsrc), intersection); 
+  gst_caps_replace_sink (&GST_RPAD_FILTER (realsink), intersection); 
+  gst_caps_unref (intersection);
 
   return gst_pad_perform_negotiate (GST_PAD (realsrc), GST_PAD (realsink));
 }
@@ -1572,6 +1590,9 @@ gst_pad_perform_negotiate (GstPad *srcpad, GstPad *sinkpad)
   GstCaps *intersection, *filtered_intersection;
   GstRealPad *realsrc, *realsink;
   GstCaps *srccaps, *sinkcaps, *filter;
+  gboolean res = TRUE;
+  GstElement *parent;
+  
 
   g_return_val_if_fail (srcpad != NULL, FALSE);
   g_return_val_if_fail (sinkpad != NULL, FALSE);
@@ -1582,6 +1603,20 @@ gst_pad_perform_negotiate (GstPad *srcpad, GstPad *sinkpad)
   g_return_val_if_fail (GST_RPAD_PEER (realsrc) != NULL, FALSE);
   g_return_val_if_fail (GST_RPAD_PEER (realsink) == realsrc, FALSE);
 
+  /* shortcut negotiation */
+  parent = GST_PAD_PARENT (realsrc);
+  if (parent && GST_STATE (parent) < GST_STATE_READY) {
+    GST_DEBUG (GST_CAT_CAPS, "parent %s of pad %s:%s is not READY",
+              GST_ELEMENT_NAME (parent), GST_DEBUG_PAD_NAME (realsrc));
+    return TRUE;
+  }
+  parent = GST_PAD_PARENT (realsink);
+  if (parent && GST_STATE (parent) < GST_STATE_READY) {
+    GST_DEBUG (GST_CAT_CAPS, "parent %s of pad %s:%s is not READY",
+              GST_ELEMENT_NAME (parent), GST_DEBUG_PAD_NAME (realsink));
+    return TRUE;
+  }
+
   GST_INFO (GST_CAT_PADS, "perform negotiate for link %s:%s-%s:%s",
               GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
 
@@ -1605,28 +1640,39 @@ gst_pad_perform_negotiate (GstPad *srcpad, GstPad *sinkpad)
                   "sink caps, awaiting negotiation, after applying filter");
   intersection = gst_caps_intersect (srccaps, sinkcaps);
   filtered_intersection = gst_caps_intersect (intersection, filter);
-  if (filtered_intersection) {
-    gst_caps_unref (intersection);
-    intersection = filtered_intersection;
-  }
+  gst_caps_unref (intersection);
 
   /* no negotiation is performed if the pads have filtercaps */
-  if (intersection) {
-    GstPadLinkReturn res;
+  if (filtered_intersection) {
+    GstPadLinkReturn link_res;
 
-    res = gst_pad_try_set_caps_func (realsrc, intersection, TRUE);
-    if (res == GST_PAD_LINK_REFUSED) 
-      return FALSE;
-    if (res == GST_PAD_LINK_DONE) 
-      return TRUE;
+    link_res = gst_pad_try_set_caps_func (realsrc, filtered_intersection, TRUE);
+    if (link_res == GST_PAD_LINK_REFUSED) 
+      goto error;
+    if (link_res == GST_PAD_LINK_DONE) 
+      goto success;
 
-    res = gst_pad_try_set_caps_func (realsink, intersection, TRUE);
-    if (res == GST_PAD_LINK_REFUSED) 
-      return FALSE;
-    if (res == GST_PAD_LINK_DONE) 
-      return TRUE;
+    link_res = gst_pad_try_set_caps_func (realsink, filtered_intersection, TRUE);
+    if (link_res == GST_PAD_LINK_REFUSED) 
+      goto error;
+    if (link_res == GST_PAD_LINK_DONE) 
+      goto success;
   }
-  return TRUE;
+  /* no filtered_intersection, some pads had caps and ther was a filter */
+  else if ((srccaps || sinkcaps) && filter) {
+    goto error;
+  }
+
+success:
+cleanup:
+  gst_caps_sink (srccaps);
+  gst_caps_sink (sinkcaps);
+  gst_caps_unref (filtered_intersection);
+  return res;
+
+error:
+  res = FALSE;
+  goto cleanup;
 }
 
 /**
@@ -1656,7 +1702,7 @@ gst_pad_try_relink_filtered (GstPad *srcpad, GstPad *sinkpad,
   g_return_val_if_fail (GST_RPAD_PEER (realsink) == realsrc, FALSE);
   
   return gst_pad_try_relink_filtered_func (realsrc, realsink, 
-                                              filtercaps, TRUE);
+                                           filtercaps, TRUE);
 }
 
 /**
@@ -1686,8 +1732,9 @@ gst_pad_relink_filtered (GstPad *srcpad, GstPad *sinkpad,
   g_return_val_if_fail (GST_RPAD_PEER (realsrc) != NULL, FALSE);
   g_return_val_if_fail (GST_RPAD_PEER (realsink) == realsrc, FALSE);
   
-  if (! gst_pad_try_relink_filtered_func (realsrc, realsink, 
-                                            filtercaps, TRUE)) {
+  if (!gst_pad_try_relink_filtered_func (realsrc, realsink, 
+                                        filtercaps, TRUE)) 
+  {
     gst_pad_unlink (srcpad, GST_PAD (GST_PAD_PEER (srcpad)));
     return FALSE;
   }
@@ -1729,7 +1776,9 @@ gst_pad_proxy_link (GstPad *pad, GstCaps *caps)
  *
  * Gets the capabilities of this pad.
  *
- * Returns: the #GstCaps of this pad.
+ * Returns: the #GstCaps of this pad. This function potentially
+ * returns a floating caps, so use gst_caps_sink to get rid of
+ * it.
  */
 GstCaps*
 gst_pad_get_caps (GstPad *pad)
@@ -1744,6 +1793,8 @@ gst_pad_get_caps (GstPad *pad)
   GST_DEBUG (GST_CAT_CAPS, "get pad caps of %s:%s (%p)",
             GST_DEBUG_PAD_NAME (realpad), realpad);
 
+  /* note that we will not _ref the caps here as this function might be 
+   * called recursively */
   if (GST_PAD_CAPS (realpad)) {
     GST_DEBUG (GST_CAT_CAPS, "using pad real caps %p", GST_PAD_CAPS (realpad));
     return GST_PAD_CAPS (realpad);
@@ -1769,7 +1820,8 @@ gst_pad_get_caps (GstPad *pad)
  *
  * Gets the template capabilities of this pad.
  *
- * Returns: the template #GstCaps of this pad.
+ * Returns: the template #GstCaps of this pad, unref the caps
+ * if you no longer need it.
  */
 GstCaps*
 gst_pad_get_pad_template_caps (GstPad *pad)
@@ -1778,7 +1830,7 @@ gst_pad_get_pad_template_caps (GstPad *pad)
   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
 
   if (GST_PAD_PAD_TEMPLATE (pad))
-    return GST_PAD_TEMPLATE_CAPS (GST_PAD_PAD_TEMPLATE (pad));
+    return gst_caps_ref (GST_PAD_TEMPLATE_CAPS (GST_PAD_PAD_TEMPLATE (pad)));
 
   return NULL;
 }
@@ -1790,7 +1842,8 @@ gst_pad_get_pad_template_caps (GstPad *pad)
  *
  * Gets the capability with the given name from this pad template.
  *
- * Returns: the #GstCaps, or NULL if not found or in case of an error.
+ * Returns: the #GstCaps, or NULL if not found or in case of an error. unref 
+ * the caps if you no longer need it.
  */
 GstCaps*
 gst_pad_template_get_caps_by_name (GstPadTemplate *templ, const gchar *name)
@@ -1803,7 +1856,7 @@ gst_pad_template_get_caps_by_name (GstPadTemplate *templ, const gchar *name)
   if (!caps) 
     return NULL;
 
-  return gst_caps_get_by_name (caps, name);
+  return gst_caps_ref (gst_caps_get_by_name (caps, name));
 }
 
 /**
@@ -1866,7 +1919,8 @@ gst_pad_get_peer (GstPad *pad)
  * Gets the capabilities of the allowed media types that can
  * flow through this pad.  The caller must free the resulting caps.
  *
- * Returns: a newly allocated copy of the allowed #GstCaps.
+ * Returns: the allowed #GstCaps of the pad link. unref the caps if
+ * you no longer need it.
  */
 GstCaps*
 gst_pad_get_allowed_caps (GstPad *pad)
@@ -1879,7 +1933,7 @@ gst_pad_get_allowed_caps (GstPad *pad)
   GST_DEBUG (GST_CAT_PROPERTIES, "get allowed caps of %s:%s", 
              GST_DEBUG_PAD_NAME (pad));
 
-  caps = gst_caps_copy (GST_RPAD_FILTER (pad));
+  caps = gst_caps_ref (GST_RPAD_FILTER (pad));
 
   return caps;
 }
@@ -1909,7 +1963,7 @@ gst_pad_recalc_allowed_caps (GstPad *pad)
   peer = GST_RPAD_PEER (pad);
   if (peer)
     return gst_pad_try_relink_filtered (pad, GST_PAD (peer), 
-                                          GST_RPAD_APPFILTER (pad));
+                                       GST_RPAD_APPFILTER (pad));
 
   return TRUE;
 }
@@ -1992,6 +2046,9 @@ gst_real_pad_dispose (GObject *object)
     g_list_free (GST_REAL_PAD(pad)->ghostpads);
   }
 
+  gst_caps_replace (&GST_PAD_CAPS (pad), NULL);
+  gst_caps_replace (&GST_RPAD_APPFILTER (pad), NULL);
+
   if (GST_IS_ELEMENT (GST_OBJECT_PARENT (pad))) {
     GST_DEBUG (GST_CAT_REFCOUNTING, "removing pad from element '%s'",
                GST_OBJECT_NAME (GST_OBJECT (GST_ELEMENT (GST_OBJECT_PARENT (pad)))));
@@ -2319,6 +2376,7 @@ gst_pad_selectv (GstPad *pad, ...)
  */
 static void            gst_pad_template_class_init     (GstPadTemplateClass *klass);
 static void            gst_pad_template_init           (GstPadTemplate *templ);
+static void            gst_pad_template_dispose        (GObject *object);
 
 GType
 gst_pad_template_get_type (void)
@@ -2356,6 +2414,8 @@ gst_pad_template_class_init (GstPadTemplateClass *klass)
                  NULL, NULL, gst_marshal_VOID__POINTER, G_TYPE_NONE, 1,
                   G_TYPE_POINTER);
 
+  gobject_class->dispose = gst_pad_template_dispose;
+
   gstobject_class->path_string_separator = "*";
 }
 
@@ -2364,6 +2424,17 @@ gst_pad_template_init (GstPadTemplate *templ)
 {
 }
 
+static void
+gst_pad_template_dispose (GObject *object)
+{
+  GstPadTemplate *templ = GST_PAD_TEMPLATE (object);
+
+  g_free (GST_PAD_TEMPLATE_NAME_TEMPLATE (templ));
+  gst_caps_unref (GST_PAD_TEMPLATE_CAPS (templ));
+
+  G_OBJECT_CLASS (padtemplate_parent_class)->dispose (object);
+}
+
 /* ALWAYS padtemplates cannot have conversion specifications, it doesn't make
  * sense.
  * SOMETIMES padtemplates can do whatever they want, they are provided by the
@@ -2442,14 +2513,19 @@ gst_pad_template_new (const gchar *name_template,
 
   va_start (var_args, caps);
 
+  GST_FLAG_SET (GST_OBJECT (new), GST_PAD_TEMPLATE_FIXED);
   while (caps) {
-    new->fixed &= caps->fixed;
-    thecaps = gst_caps_append (thecaps, gst_caps_ref (caps));
+    if (!GST_CAPS_IS_FIXED (caps)) {
+      GST_FLAG_UNSET (GST_OBJECT (new), GST_PAD_TEMPLATE_FIXED);
+    }
+    thecaps = gst_caps_append (thecaps, caps);
     caps = va_arg (var_args, GstCaps*);
   }
   va_end (var_args);
   
   GST_PAD_TEMPLATE_CAPS (new) = thecaps;
+  gst_caps_ref (thecaps);
+  gst_caps_sink (thecaps);
 
   return new;
 }
@@ -2460,14 +2536,15 @@ gst_pad_template_new (const gchar *name_template,
  *
  * Gets the capabilities of the pad template.
  *
- * Returns: the #GstCaps of the pad template.
+ * Returns: the #GstCaps of the pad template. unref the caps
+ * after use.
  */
 GstCaps*
 gst_pad_template_get_caps (GstPadTemplate *templ)
 {
   g_return_val_if_fail (templ != NULL, NULL);
 
-  return GST_PAD_TEMPLATE_CAPS (templ);
+  return gst_caps_ref (GST_PAD_TEMPLATE_CAPS (templ));
 }
 
 /**
index 1b34597..b29d470 100644 (file)
@@ -146,7 +146,7 @@ typedef const GstFormat*    (*GstPadFormatsFunction)        (GstPad *pad);
 typedef const GstEventMask*    (*GstPadEventMaskFunction)      (GstPad *pad);
 typedef const GstQueryType*    (*GstPadQueryTypeFunction)      (GstPad *pad);
 
-typedef GstPadLinkReturn       (*GstPadLinkFunction)   (GstPad *pad, GstCaps *caps);
+typedef GstPadLinkReturn       (*GstPadLinkFunction)           (GstPad *pad, GstCaps *caps);
 typedef GstCaps*               (*GstPadGetCapsFunction)        (GstPad *pad, GstCaps *caps);
 typedef GstBufferPool*         (*GstPadBufferPoolFunction)     (GstPad *pad);
 
@@ -276,7 +276,7 @@ struct _GstGhostPadClass {
 #define GST_PAD_PEER(pad)              GST_PAD_CAST(GST_RPAD_PEER(GST_PAD_REALIZE(pad)))
 
 /* Some check functions (unused?) */
-#define GST_PAD_IS_LINKED(pad) (GST_PAD_PEER(pad) != NULL)
+#define GST_PAD_IS_LINKED(pad)         (GST_PAD_PEER(pad) != NULL)
 #define GST_PAD_IS_ACTIVE(pad)         (!GST_FLAG_IS_SET(GST_PAD_REALIZE(pad), GST_PAD_DISABLED))
 #define GST_PAD_IS_USABLE(pad)         (GST_PAD_IS_LINKED (pad) && \
                                         GST_PAD_IS_ACTIVE(pad) && GST_PAD_IS_ACTIVE(GST_PAD_PEER (pad)))
@@ -301,22 +301,26 @@ typedef enum {
 #define GST_PAD_TEMPLATE_DIRECTION(templ)      (((GstPadTemplate *)(templ))->direction)
 #define GST_PAD_TEMPLATE_PRESENCE(templ)       (((GstPadTemplate *)(templ))->presence)
 #define GST_PAD_TEMPLATE_CAPS(templ)           (((GstPadTemplate *)(templ))->caps)
-#define GST_PAD_TEMPLATE_FIXED(templ)          (((GstPadTemplate *)(templ))->fixed)
 
-#define GST_PAD_TEMPLATE_IS_FIXED(templ)       (GST_PAD_TEMPLATE_FIXED(templ) == TRUE)
+typedef enum {
+  GST_PAD_TEMPLATE_FIXED       = GST_OBJECT_FLAG_LAST,
+
+  GST_PAD_TEMPLATE_FLAG_LAST   = GST_OBJECT_FLAG_LAST + 4
+} GstPadTemplateFlags;
+
+#define GST_PAD_TEMPLATE_IS_FIXED(templ)       (GST_FLAG_IS_SET(templ), GST_PAD_TEMPLATE_FIXED)
 
 struct _GstPadTemplate {
-  GstObject      object;
+  GstObject       object;
 
   gchar           *name_template;
-  GstPadDirection direction;
-  GstPadPresence  presence;
+  GstPadDirection  direction;
+  GstPadPresence   presence;
   GstCaps        *caps;
-  gboolean       fixed;
 };
 
 struct _GstPadTemplateClass {
-  GstObjectClass parent_class;
+  GstObjectClass   parent_class;
 
   /* signal callbacks */
   void (*pad_created)  (GstPadTemplate *templ, GstPad *pad);
@@ -425,7 +429,7 @@ gboolean                gst_pad_can_link_filtered                   (GstPad *srcpad, GstPad *s
 
 gboolean                gst_pad_link                           (GstPad *srcpad, GstPad *sinkpad);
 gboolean                gst_pad_link_filtered                  (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps);
-void                   gst_pad_unlink                  (GstPad *srcpad, GstPad *sinkpad);
+void                   gst_pad_unlink                          (GstPad *srcpad, GstPad *sinkpad);
 
 GstPad*                        gst_pad_get_peer                        (GstPad *pad);
 
@@ -437,7 +441,7 @@ gboolean            gst_pad_check_compatibility             (GstPad *srcpad, GstPad *sinkpad);
 
 void                   gst_pad_set_getcaps_function            (GstPad *pad, GstPadGetCapsFunction getcaps);
 GstPadLinkReturn       gst_pad_proxy_link                      (GstPad *pad, GstCaps *caps);
-gboolean               gst_pad_relink_filtered         (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps);
+gboolean               gst_pad_relink_filtered                 (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps);
 gboolean               gst_pad_perform_negotiate               (GstPad *srcpad, GstPad *sinkpad);
 gboolean               gst_pad_try_relink_filtered             (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps);
 GstCaps*               gst_pad_get_allowed_caps                (GstPad *pad);
@@ -475,9 +479,9 @@ gboolean            gst_pad_query                           (GstPad *pad, GstQueryType type,
 gboolean               gst_pad_query_default                   (GstPad *pad, GstQueryType type,
                                                                 GstFormat *format, gint64 *value);
 
-void                   gst_pad_set_internal_link_function(GstPad *pad, GstPadIntLinkFunction intlink);
-GList*                 gst_pad_get_internal_links      (GstPad *pad);
-GList*                 gst_pad_get_internal_links_default (GstPad *pad);
+void                   gst_pad_set_internal_link_function      (GstPad *pad, GstPadIntLinkFunction intlink);
+GList*                 gst_pad_get_internal_links              (GstPad *pad);
+GList*                 gst_pad_get_internal_links_default      (GstPad *pad);
        
 /* misc helper functions */
 gboolean               gst_pad_dispatcher                      (GstPad *pad, GstPadDispatcherFunction dispatch, 
@@ -489,7 +493,7 @@ gboolean            gst_pad_dispatcher                      (GstPad *pad, GstPadDispatcherFunction dispatch
                        (gst_probe_dispatcher_remove_probe (&(GST_REAL_PAD (pad)-probedisp), probe))
 
 #ifndef GST_DISABLE_LOADSAVE
-void                   gst_pad_load_and_link           (xmlNodePtr self, GstObject *parent);
+void                   gst_pad_load_and_link                   (xmlNodePtr self, GstObject *parent);
 #endif
 
 
index 2b9138b..ec2874a 100644 (file)
@@ -262,6 +262,9 @@ make_links (graph_t *g, GError **error)
     a = c->src_pads;
     b = c->sink_pads;
     caps = c->caps;
+    gst_caps_ref (caps);
+    gst_caps_sink (caps);
+
     gst_caps_debug (caps, "foo");
     /* g_print ("a: %p, b: %p\n", a, b); */
     if (a && b) {
@@ -363,6 +366,7 @@ make_links (graph_t *g, GError **error)
       }
     }
 next:
+    gst_caps_unref (caps);
     l = g_list_next (l);
   }
   
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;
   }
 
index c03ea59..11b355d 100644 (file)
@@ -33,6 +33,8 @@ 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)
 
 typedef enum {
@@ -78,56 +80,91 @@ typedef enum {
 #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)->properties)
+
+#define GST_PROPS_IS_FIXED(props)         (GST_PROPS_FLAGS (props) & GST_PROPS_FIXED)
+#define GST_PROPS_IS_FLOATING(props)      (GST_PROPS_FLAGS (props) & GST_PROPS_FLOATING)
+
 struct _GstProps {
-  gint refcount;
-  gboolean fixed;
+  gint   refcount;
+  gint   flags;
 
-  GList *properties;           /* real properties for this property */
+  GList *properties;           /* real property entries for this property */
 };
 
 /* initialize the subsystem */
 void                   _gst_props_initialize           (void);
 
+/* creating new properties */
 GstProps*              gst_props_new                   (const gchar *firstname, ...);
 GstProps*              gst_props_newv                  (const gchar *firstname, va_list var_args);
 GstProps*              gst_props_empty_new             (void);
 
-void                   gst_props_unref                 (GstProps *props);
-void                   gst_props_ref                   (GstProps *props);
+/* 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);
 void                   gst_props_destroy               (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);
 
-GstProps*              gst_props_merge                 (GstProps *props, GstProps *tomerge);
-
+/* 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 */
 GstPropsEntry*         gst_props_entry_new             (const gchar *name, ...);
 
 void                   gst_props_entry_destroy         (GstPropsEntry *entry);
-GstPropsEntry*         gst_props_entry_copy            (GstPropsEntry *entry);
+GstPropsEntry*         gst_props_entry_copy            (const GstPropsEntry *entry);
 GstPropsType           gst_props_entry_get_type        (const GstPropsEntry *entry);
 const gchar*           gst_props_entry_get_name        (const GstPropsEntry *entry);
 gboolean               gst_props_entry_is_fixed        (const GstPropsEntry *entry);