Landed the new improved capsnegotiation system.
authorWim Taymans <wim.taymans@gmail.com>
Sun, 13 Jan 2002 22:22:42 +0000 (22:22 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Sun, 13 Jan 2002 22:22:42 +0000 (22:22 +0000)
Original commit message from CVS:
Landed the new improved capsnegotiation system.
The main idea is to keep track of the possible data types that can
pass through a connection. plugins can at any time inspect, adjust and
refine these caps. plugins also get notified when something changes to
the types so that they can reconfigure themselves.
Look at the updated plugins and the soon to be finished doc.

19 files changed:
gst/autoplug/gststaticautoplugrender.c
gst/elements/gstidentity.c
gst/elements/gststatistics.c
gst/elements/gsttee.c
gst/gstcaps.c
gst/gstcaps.h
gst/gstelement.c
gst/gstelement.h
gst/gstpad.c
gst/gstpad.h
gst/gstprops.c
gst/gstprops.h
gst/gstpropsprivate.h
gst/gstqueue.c
gst/gsttypefind.c
plugins/elements/gstidentity.c
plugins/elements/gstqueue.c
plugins/elements/gststatistics.c
plugins/elements/gsttee.c

index 348f27eb403a1ee4f01a027a28fd2d124fa4985c..7bf55c931c401686d5613d3f3a1c4fac30ad7e3d 100644 (file)
@@ -187,10 +187,10 @@ gst_autoplug_pads_autoplug_func (GstElement *src, GstPad *pad, GstElement *sink)
 
     /* if we have a match, connect the pads */
     if (gst_pad_get_direction(sinkpad) == GST_PAD_SINK &&
-        !GST_PAD_CONNECTED (pad) && !GST_PAD_CONNECTED(sinkpad))
+        !GST_PAD_IS_CONNECTED (pad) && !GST_PAD_IS_CONNECTED(sinkpad))
     {
 
-      if ((connected = gst_pad_try_connect (pad, sinkpad))) {
+      if ((connected = gst_pad_connect (pad, sinkpad))) {
        break;
       }
       else {
index 1da9ab256d34994fa6884c71983dc23ab252a3ed..b34511b658401c197a7b6530e36def6ef9df363e 100644 (file)
@@ -133,26 +133,6 @@ gst_identity_get_bufferpool (GstPad *pad)
   return gst_pad_get_bufferpool (identity->srcpad);
 }
 
-static GstPadNegotiateReturn
-gst_identity_negotiate_src (GstPad *pad, GstCaps **caps, gpointer *data)
-{
-  GstIdentity *identity;
-
-  identity = GST_IDENTITY (gst_pad_get_parent (pad));
-
-  return gst_pad_negotiate_proxy (pad, identity->sinkpad, caps);
-}
-
-static GstPadNegotiateReturn
-gst_identity_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data)
-{
-  GstIdentity *identity;
-
-  identity = GST_IDENTITY (gst_pad_get_parent (pad));
-
-  return gst_pad_negotiate_proxy (pad, identity->srcpad, caps);
-}
-
 static void 
 gst_identity_init (GstIdentity *identity) 
 {
@@ -160,11 +140,9 @@ gst_identity_init (GstIdentity *identity)
   gst_element_add_pad (GST_ELEMENT (identity), identity->sinkpad);
   gst_pad_set_chain_function (identity->sinkpad, GST_DEBUG_FUNCPTR (gst_identity_chain));
   gst_pad_set_bufferpool_function (identity->sinkpad, gst_identity_get_bufferpool);
-  gst_pad_set_negotiate_function (identity->sinkpad, gst_identity_negotiate_sink);
   
   identity->srcpad = gst_pad_new ("src", GST_PAD_SRC);
   gst_element_add_pad (GST_ELEMENT (identity), identity->srcpad);
-  gst_pad_set_negotiate_function (identity->srcpad, gst_identity_negotiate_src);
 
   identity->loop_based = FALSE;
   identity->sleep_time = 0;
index 913b53beff6600294e32e2aeae9da2e392a3460e..8d9736c1a3062d5c824c168446f089ce5bcaa48b 100644 (file)
@@ -146,26 +146,6 @@ gst_statistics_get_bufferpool (GstPad *pad)
   return gst_pad_get_bufferpool (statistics->srcpad);
 }
 
-static GstPadNegotiateReturn
-gst_statistics_negotiate_src (GstPad *pad, GstCaps **caps, gpointer *data)
-{
-  GstStatistics *statistics;
-
-  statistics = GST_STATISTICS (gst_pad_get_parent (pad));
-
-  return gst_pad_negotiate_proxy (pad, statistics->sinkpad, caps);
-}
-
-static GstPadNegotiateReturn
-gst_statistics_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data)
-{
-  GstStatistics *statistics;
-
-  statistics = GST_STATISTICS (gst_pad_get_parent (pad));
-
-  return gst_pad_negotiate_proxy (pad, statistics->srcpad, caps);
-}
-
 static void 
 gst_statistics_init (GstStatistics *statistics) 
 {
@@ -173,11 +153,9 @@ gst_statistics_init (GstStatistics *statistics)
   gst_element_add_pad (GST_ELEMENT (statistics), statistics->sinkpad);
   gst_pad_set_chain_function (statistics->sinkpad, GST_DEBUG_FUNCPTR (gst_statistics_chain));
   gst_pad_set_bufferpool_function (statistics->sinkpad, GST_DEBUG_FUNCPTR (gst_statistics_get_bufferpool));
-  gst_pad_set_negotiate_function (statistics->sinkpad, GST_DEBUG_FUNCPTR (gst_statistics_negotiate_sink));
   
   statistics->srcpad = gst_pad_new ("src", GST_PAD_SRC);
   gst_element_add_pad (GST_ELEMENT (statistics), statistics->srcpad);
-  gst_pad_set_negotiate_function (statistics->srcpad, GST_DEBUG_FUNCPTR (gst_statistics_negotiate_src));
 
   statistics->timer = NULL;
   statistics->last_timer = NULL;
index 0335ae208f896ab141794f45b889b201c4b6bea0..c2702e04345760c79865d2ea4da43e0b05396209 100644 (file)
@@ -66,7 +66,6 @@ static void   gst_tee_get_property    (GObject *object, guint prop_id,
 
 static void    gst_tee_chain           (GstPad *pad, GstBuffer *buf);
 
-static GstPadNegotiateReturn   gst_tee_handle_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data);
 
 static GstElementClass *parent_class = NULL;
 /*static guint gst_tee_signals[LAST_SIGNAL] = { 0 };*/
@@ -110,20 +109,44 @@ gst_tee_class_init (GstTeeClass *klass)
                       FALSE, G_PARAM_READWRITE));
 
 
-
   gobject_class->set_property = GST_DEBUG_FUNCPTR(gst_tee_set_property);
   gobject_class->get_property = GST_DEBUG_FUNCPTR(gst_tee_get_property);
 
   gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR(gst_tee_request_new_pad);
 }
 
+static gboolean 
+gst_tee_sinkconnect (GstPad *pad, GstCaps *caps) 
+{
+  GstTee *tee;
+  GList *pads;
+  
+  tee = GST_TEE (gst_pad_get_parent (pad));
+
+  /* go through all the src pads */
+  pads = gst_element_get_pad_list (GST_ELEMENT (tee));
+
+  while (pads) {
+    GstPad *outpad = GST_PAD (pads->data);
+    pads = g_list_next (pads);
+                    
+    if (GST_PAD_DIRECTION (outpad) != GST_PAD_SRC || !GST_PAD_IS_CONNECTED (outpad))
+      continue;
+
+    if (!(gst_pad_try_set_caps (outpad, caps))) {
+      return FALSE;
+    }
+  }
+  return TRUE;
+}
+
 static void 
 gst_tee_init (GstTee *tee) 
 {
   tee->sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
   gst_element_add_pad (GST_ELEMENT (tee), tee->sinkpad);
   gst_pad_set_chain_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_tee_chain));
-  gst_pad_set_negotiate_function (tee->sinkpad, GST_DEBUG_FUNCPTR(gst_tee_handle_negotiate_sink));
+  gst_pad_set_connect_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_tee_sinkconnect));
 
   tee->silent = FALSE;
 }
@@ -152,7 +175,7 @@ gst_tee_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar
   GST_PAD_ELEMENT_PRIVATE (srcpad) = NULL;
 
   if (GST_PAD_CAPS (tee->sinkpad)) {
-    gst_pad_set_caps (srcpad, GST_PAD_CAPS (tee->sinkpad));
+    gst_pad_try_set_caps (srcpad, GST_PAD_CAPS (tee->sinkpad));
   }
 
   return srcpad;
@@ -253,18 +276,18 @@ gst_tee_chain (GstPad *pad, GstBuffer *buf)
       GstEvent *event = GST_EVENT (GST_PAD_ELEMENT_PRIVATE (outpad));
        
       GST_PAD_ELEMENT_PRIVATE (outpad) = NULL;
-      if (GST_PAD_CONNECTED (outpad))
+      if (GST_PAD_IS_CONNECTED (outpad))
         gst_pad_push (outpad, GST_BUFFER (event));
       else
        gst_event_free (event);
     }
 
     if (!tee->silent) {
-      gst_element_info (GST_ELEMENT (tee), "chain        ******* (%s:%s)t (%d bytes, %llu) \n",
+      gst_element_info (GST_ELEMENT (tee), "chain        ******* (%s:%s)t (%d bytes, %llu)",
               GST_DEBUG_PAD_NAME (outpad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf));
     }
 
-    if (GST_PAD_CONNECTED (outpad))
+    if (GST_PAD_IS_CONNECTED (outpad))
       gst_pad_push (outpad, buf);
     else
       gst_buffer_unref (buf);
@@ -279,30 +302,3 @@ gst_tee_factory_init (GstElementFactory *factory)
   return TRUE;
 }
 
-static GstPadNegotiateReturn
-gst_tee_handle_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer* data)
-{
-  GstCaps* tempcaps;
-  gint i;
-  GstTee* tee = GST_TEE (GST_OBJECT_PARENT (pad));
-  GList *pads;
-  
-  if (*caps==NULL) 
-    return GST_PAD_NEGOTIATE_FAIL;
-
-  /* go through all the src pads */
-  pads = gst_element_get_pad_list (GST_ELEMENT (tee));
-
-  while (pads) {
-    GstPad *outpad = GST_PAD (pads->data);
-    pads = g_list_next (pads);
-    if (GST_PAD_DIRECTION (outpad) != GST_PAD_SRC || !GST_PAD_CONNECTED (outpad))
-      continue;
-
-    if (!(gst_pad_set_caps (outpad, *caps))) {
-      return GST_PAD_NEGOTIATE_FAIL;
-    }
-  }
-  return GST_PAD_NEGOTIATE_AGREE;
-}
index 62be582a4fedb7ae92d3990c24418a859d84fa6e..d0e41e5fb9494dd78502a7b3470168fab0334d3a 100644 (file)
@@ -75,20 +75,40 @@ get_type_for_mime (const gchar *mime)
 GstCaps*
 gst_caps_new (const gchar *name, const gchar *mime, GstProps *props)
 {
-  GstCaps *caps;
-
   g_return_val_if_fail (mime != NULL, NULL);
 
+  return gst_caps_new_id (name, get_type_for_mime (mime), props);
+}
+
+/**
+ * gst_caps_new_id:
+ * @name: the name of this capability
+ * @id: the id of the mime type 
+ * @props: the properties to add to this capability
+ *
+ * Create a new capability with the given mime typeid and properties.
+ *
+ * Returns: a new capability
+ */
+GstCaps*
+gst_caps_new_id (const gchar *name, const 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->name = g_strdup (name);
-  caps->id = get_type_for_mime (mime);
+  caps->id = id;
   caps->properties = props;
   caps->next = NULL;
   caps->refcount = 1;
   caps->lock = g_mutex_new ();
+  if (props)
+    caps->fixed = props->fixed;
+  else
+    caps->fixed = TRUE;
 
   return caps;
 }
@@ -105,18 +125,43 @@ gst_caps_destroy (GstCaps *caps)
 {
   GstCaps *next;
 
-  g_return_if_fail (caps != NULL);
-
+  if (caps == NULL)
+    return;
+  
   GST_CAPS_LOCK (caps);
   next = caps->next;
-  g_free (caps->name);
-  g_free (caps);
   GST_CAPS_UNLOCK (caps);
 
+  g_mutex_free (caps->lock);
+  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);
+
   if (next) 
     gst_caps_unref (next);
 }
 
+void
+gst_caps_debug (GstCaps *caps)
+{
+  GST_DEBUG_ENTER ("caps debug");
+  while (caps) {
+    GST_DEBUG (GST_CAT_CAPS, "caps: %p %s %s\n", caps, caps->name, gst_caps_get_mime (caps));
+
+    if (caps->properties) {
+      gst_props_debug (caps->properties);
+    }
+    else {
+      GST_DEBUG (GST_CAT_CAPS, "no properties\n");
+    }
+
+    caps = caps->next;
+  }
+  GST_DEBUG_LEAVE ("caps debug");
+}
+
 /**
  * gst_caps_unref:
  * @caps: the caps to unref
@@ -132,7 +177,9 @@ gst_caps_unref (GstCaps *caps)
   gboolean zero;
   GstCaps **next;
 
-  g_return_val_if_fail (caps != NULL, NULL);
+  if (caps == NULL)
+    return NULL;
+
   g_return_val_if_fail (caps->refcount > 0, NULL);
 
   GST_CAPS_LOCK (caps);
@@ -182,16 +229,24 @@ gst_caps_ref (GstCaps *caps)
 GstCaps*
 gst_caps_copy (GstCaps *caps)
 {
-  GstCaps *new = caps;;
+  GstCaps *new = NULL, *walk = NULL;
 
-  g_return_val_if_fail (caps != NULL, NULL);
+  while (caps) {
+    GstCaps *newcaps;
 
-  GST_CAPS_LOCK (caps);
-  new = gst_caps_new (
+    newcaps = gst_caps_new_id (
                  caps->name,
-                 (gst_type_find_by_id (caps->id))->mime,
+                 caps->id,
                  gst_props_copy (caps->properties));
-  GST_CAPS_UNLOCK (caps);
+
+    if (new == NULL) {
+      new = walk = newcaps;
+    }
+    else {
+      walk = walk->next = newcaps;
+    }
+    caps = caps->next;
+  }
 
   return new;
 }
@@ -437,11 +492,11 @@ gst_caps_prepend (GstCaps *caps, GstCaps *capstoadd)
 {
   GstCaps *orig = capstoadd;
   
-  g_return_val_if_fail (caps != capstoadd, caps);
-
   if (capstoadd == NULL)
     return caps;
 
+  g_return_val_if_fail (caps != capstoadd, caps);
+
   while (capstoadd->next) {
     capstoadd = capstoadd->next;
   }
@@ -545,6 +600,118 @@ gst_caps_check_compatibility (GstCaps *fromcaps, GstCaps *tocaps)
   return FALSE;
 }
 
+static GstCaps*
+gst_caps_intersect_func (GstCaps *caps1, GstCaps *caps2)
+{
+  GstCaps *result = NULL;
+  GstProps *props;
+
+  if (caps1->id != caps2->id) {
+    GST_DEBUG (GST_CAT_CAPS,"mime types differ (%s to %s)\n",
+              gst_type_find_by_id (caps1->id)->mime, 
+              gst_type_find_by_id (caps2->id)->mime);
+    return NULL;
+  }
+
+  if (caps1->properties == NULL) {
+    return gst_caps_ref (caps2);
+  }
+  if (caps2->properties == NULL) {
+    return gst_caps_ref (caps1);
+  }
+  
+  props = gst_props_intersect (caps1->properties, caps2->properties);
+  if (props) {
+    result = gst_caps_new_id ("intersect", caps1->id, props);
+  }
+
+  return result;
+}
+
+/**
+ * gst_caps_intersect:
+ * @caps1: a capabilty
+ * @caps2: a capabilty
+ *
+ * Make the intersection between two caps.
+ *
+ * Returns: The intersection of the two caps or NULL if the intersection
+ * is empty.
+ */
+GstCaps*
+gst_caps_intersect (GstCaps *caps1, GstCaps *caps2)
+{
+  GstCaps *result = NULL, *walk = NULL;
+
+  if (caps1 == NULL) {
+    GST_DEBUG (GST_CAT_CAPS, "first caps is NULL, return other caps\n");
+    return gst_caps_copy (caps2);
+  }
+  if (caps2 == NULL) {
+    GST_DEBUG (GST_CAT_CAPS, "second caps is NULL, return other caps\n");
+    return gst_caps_copy (caps1);
+  }
+
+  while (caps1) {
+    GstCaps *othercaps = caps2;
+
+    while (othercaps) {
+      GstCaps *intersection = gst_caps_intersect_func (caps1, othercaps);
+
+      if (intersection) {
+        if (!result) {
+         walk = result = intersection;
+        }
+        else {
+         walk = walk->next = intersection;
+        }
+      }
+      othercaps = othercaps->next;
+    }
+    caps1 =  caps1->next;
+  }
+
+  return result;
+}
+
+GstCaps*
+gst_caps_normalize (GstCaps *caps)
+{
+  GstCaps *result = NULL, *walk = caps;
+
+  if (caps == NULL)
+    return 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);
+
+      if (result == NULL)
+       walk = result = newcaps;
+      else {
+       walk = walk->next = newcaps;
+      }
+      proplist = g_list_next (proplist);  
+    }
+next:
+    caps = caps->next;
+  }
+  return result;
+}
+
 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
 /**
  * gst_caps_save_thyself:
@@ -605,6 +772,7 @@ gst_caps_load_thyself (xmlNodePtr parent)
       caps->refcount = 1;
       caps->lock = g_mutex_new ();
       caps->next = NULL;
+      caps->fixed = TRUE;
        
       while (subfield) {
         if (!strcmp (subfield->name, "name")) {
index 77a8767d983cc55c4221f42afd17659fc647e0be..d96f2cb0d72bfa0b71d4357030da099fa8cba12d 100644 (file)
@@ -37,16 +37,20 @@ typedef struct _GstCaps GstCaps;
 #define GST_CAPS_TRYLOCK(caps) (g_mutex_trylock(GST_CAPS(caps)->lock))
 #define GST_CAPS_UNLOCK(caps)  (g_mutex_unlock(GST_CAPS(caps)->lock))
 
+#define GST_CAPS_IS_FIXED(caps)                ((caps)->fixed)
+#define GST_CAPS_IS_CHAINED(caps)      ((caps)->next)
+
 struct _GstCaps {
-  gchar *name;                 /* the name of this caps */
-  guint16 id;                  /* type id (major type) */
+  gchar        *name;                  /* the name of this caps */
+  guint16      id;                     /* type id (major type) */
 
-  guint refcount;              
-  GMutex *lock;                        /* global lock for this capability */
+  guint        refcount;               
+  GMutex       *lock;                  /* global lock for this capability */
+  gboolean     fixed;                  /* this caps doesn't contain variable properties */
 
-  GstProps *properties;                /* properties for this capability */
+  GstProps     *properties;            /* properties for this capability */
 
-  GstCaps *next;
+  GstCaps      *next;
 };
 
 #define GST_CAPS_NEW(name, type, a...)          \
@@ -75,11 +79,14 @@ factoryname (void)                              \
 void           _gst_caps_initialize                    (void);
 
 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);
 
 GstCaps*       gst_caps_unref                          (GstCaps *caps);
 GstCaps*       gst_caps_ref                            (GstCaps *caps);
 void           gst_caps_destroy                        (GstCaps *caps);
 
+void           gst_caps_debug                          (GstCaps *caps);
+
 GstCaps*       gst_caps_copy                           (GstCaps *caps);
 GstCaps*       gst_caps_copy_on_write                  (GstCaps *caps);
 
@@ -102,6 +109,7 @@ GstProps*   gst_caps_get_props                      (GstCaps *caps);
 #define                gst_caps_get_fourcc_int(caps, name)     gst_props_get_fourcc_int ((caps)->properties, name)
 #define                gst_caps_get_boolean(caps, name)        gst_props_get_boolean ((caps)->properties, name)
 #define                gst_caps_get_string(caps, name)         gst_props_get_string ((caps)->properties, name)
+#define                gst_caps_has_property(caps, name)       gst_props_has_property ((caps)->properties, name)
 
 GstCaps*       gst_caps_get_by_name                    (GstCaps *caps, const gchar *name);
 
@@ -110,6 +118,8 @@ GstCaps*    gst_caps_append                         (GstCaps *caps, GstCaps *capstoadd);
 GstCaps*       gst_caps_prepend                        (GstCaps *caps, GstCaps *capstoadd); 
 
 gboolean       gst_caps_check_compatibility            (GstCaps *fromcaps, GstCaps *tocaps);
+GstCaps*       gst_caps_intersect                      (GstCaps *caps1, GstCaps *caps2);
+GstCaps*       gst_caps_normalize                      (GstCaps *caps);
 
 #ifndef GST_DISABLE_LOADSAVE
 xmlNodePtr      gst_caps_save_thyself                  (GstCaps *caps, xmlNodePtr parent);
index 0c19d1bca7a311c8fd802eb0aca1833f8f280da2..398c9e88bfae683a7ae4134ebd7795ac554dd9a9 100644 (file)
@@ -691,44 +691,69 @@ gst_element_request_pad_by_name (GstElement *element, const gchar *name)
 }
 
 /**
- * gst_element_connect:
+ * gst_element_connect_filtered:
  * @src: element containing source pad
  * @srcpadname: name of pad in source element
  * @dest: element containing destination pad
  * @destpadname: name of pad in destination element
+ * @filtercaps: the caps to use as a filter
  *
  * Connect the two named pads of the source and destination elements.
  * Side effect is that if one of the pads has no parent, it becomes a
  * child of the parent of the other element.  If they have different
  * parents, the connection fails.
+ *
+ * Return: TRUE if the pads could be connected.
  */
-void
-gst_element_connect (GstElement *src, const gchar *srcpadname,
-                     GstElement *dest, const gchar *destpadname)
+gboolean
+gst_element_connect_filtered (GstElement *src, const gchar *srcpadname,
+                              GstElement *dest, const gchar *destpadname, 
+                             GstCaps *filtercaps)
 {
   GstPad *srcpad,*destpad;
 
-  g_return_if_fail (src != NULL);
-  g_return_if_fail (GST_IS_ELEMENT(src));
-  g_return_if_fail (srcpadname != NULL);
-  g_return_if_fail (dest != NULL);
-  g_return_if_fail (GST_IS_ELEMENT(dest));
-  g_return_if_fail (destpadname != NULL);
+  g_return_val_if_fail (src != NULL, FALSE);
+  g_return_val_if_fail (GST_IS_ELEMENT(src), FALSE);
+  g_return_val_if_fail (srcpadname != NULL, FALSE);
+  g_return_val_if_fail (dest != NULL, FALSE);
+  g_return_val_if_fail (GST_IS_ELEMENT(dest), FALSE);
+  g_return_val_if_fail (destpadname != NULL, FALSE);
 
   /* obtain the pads requested */
   srcpad = gst_element_get_pad (src, srcpadname);
   if (srcpad == NULL) {
-    GST_ERROR(src,"source element has no pad \"%s\"",srcpadname);
-    return;
+    GST_ERROR (src, "source element has no pad \"%s\"", srcpadname);
+    return FALSE;
   }
   destpad = gst_element_get_pad (dest, destpadname);
   if (srcpad == NULL) {
-    GST_ERROR(dest,"destination element has no pad \"%s\"",destpadname);
-    return;
+    GST_ERROR (dest, "destination element has no pad \"%s\"", destpadname);
+    return FALSE;
   }
 
   /* we're satisified they can be connected, let's do it */
-  gst_pad_connect(srcpad,destpad);
+  return gst_pad_connect_filtered (srcpad, destpad, filtercaps);
+}
+
+/**
+ * gst_element_connect:
+ * @src: element containing source pad
+ * @srcpadname: name of pad in source element
+ * @dest: element containing destination pad
+ * @destpadname: name of pad in destination element
+ *
+ * Connect the two named pads of the source and destination elements.
+ * Side effect is that if one of the pads has no parent, it becomes a
+ * child of the parent of the other element.  If they have different
+ * parents, the connection fails.
+ *
+ * Return: TRUE if the pads could be connected.
+ */
+gboolean
+gst_element_connect (GstElement *src, const gchar *srcpadname,
+                     GstElement *dest, const gchar *destpadname)
+{
+  return gst_element_connect_filtered (src, srcpadname, dest, destpadname, NULL);
 }
 
 /**
index 88a9c7247ca6b4dbd487a58033354b6d343f5a85..32eb78eea33dc118bcebb3462761f2e027c23255 100644 (file)
@@ -200,8 +200,11 @@ void                       gst_element_remove_ghost_pad    (GstElement *element, GstPad *pad);
 GstPad*                        gst_element_request_compatible_pad (GstElement *element, GstPadTemplate *templ);
 GstPad*                        gst_element_request_pad_by_name (GstElement *element, const gchar *name);
 
-void                   gst_element_connect             (GstElement *src, const gchar *srcpadname,
+gboolean               gst_element_connect             (GstElement *src, const gchar *srcpadname,
                                                         GstElement *dest, const gchar *destpadname);
+gboolean               gst_element_connect_filtered    (GstElement *src, const gchar *srcpadname,
+                                                        GstElement *dest, const gchar *destpadname,
+                                                        GstCaps *filtercaps);
 void                   gst_element_disconnect          (GstElement *src, const gchar *srcpadname,
                                                         GstElement *dest, const gchar *destpadname);
 
index f0cd7de1588048f97191a138a51d004e1751cef3..cb2bf30b9146d0bc3bdb010c4666238fc7578e3a 100644 (file)
@@ -37,6 +37,8 @@ GType _gst_pad_type = 0;
 static void            gst_pad_class_init              (GstPadClass *klass);
 static void            gst_pad_init                    (GstPad *pad);
 
+static gboolean        gst_pad_try_reconnect_filtered_func (GstPad *pad, GstCaps *caps, gboolean clear);
+
 #ifndef GST_DISABLE_LOADSAVE
 static xmlNodePtr      gst_pad_save_thyself            (GstObject *object, xmlNodePtr parent);
 #endif
@@ -182,12 +184,12 @@ gst_real_pad_class_init (GstRealPadClass *klass)
 
 /*  gtk_object_add_arg_type ("GstRealPad::active", G_TYPE_BOOLEAN, */
 /*                           GTK_ARG_READWRITE, REAL_ARG_ACTIVE); */
-  g_object_class_install_property (G_OBJECT_CLASS(klass), REAL_ARG_ACTIVE,
-    g_param_spec_boolean("active","Active","Whether the pad is active.",
-                         TRUE,G_PARAM_READWRITE));
+  g_object_class_install_property (G_OBJECT_CLASS (klass), REAL_ARG_ACTIVE,
+    g_param_spec_boolean ("active", "Active", "Whether the pad is active.",
+                          TRUE,G_PARAM_READWRITE));
 
 #ifndef GST_DISABLE_LOADSAVE
-  gstobject_class->save_thyself = GST_DEBUG_FUNCPTR(gst_pad_save_thyself);
+  gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_pad_save_thyself);
 #endif
   gstobject_class->path_string_separator = ".";
 }
@@ -205,31 +207,34 @@ gst_real_pad_init (GstRealPad *pad)
   pad->getfunc = NULL;
   pad->getregionfunc = NULL;
 
-  pad->chainhandler = GST_DEBUG_FUNCPTR(gst_pad_push_func);
+  pad->chainhandler = GST_DEBUG_FUNCPTR (gst_pad_push_func);
   pad->gethandler = NULL;
   pad->pullregionfunc = NULL;
 
   pad->bufferpoolfunc = NULL;
   pad->ghostpads = NULL;
   pad->caps = NULL;
+
+  pad->connectfunc = NULL;
+  pad->getcapsfunc = NULL;
 }
 
 static void
 gst_real_pad_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
 {
-  g_return_if_fail(GST_IS_PAD(object));
+  g_return_if_fail (GST_IS_PAD (object));
 
   switch (prop_id) {
     case REAL_ARG_ACTIVE:
-      if (g_value_get_boolean(value)) {
-        GST_DEBUG(GST_CAT_PADS,"activating pad %s:%s\n",GST_DEBUG_PAD_NAME(object));
-        GST_FLAG_UNSET(object,GST_PAD_DISABLED);
+      if (g_value_get_boolean (value)) {
+        GST_DEBUG (GST_CAT_PADS, "activating pad %s:%s\n", GST_DEBUG_PAD_NAME (object));
+        GST_FLAG_UNSET (object, GST_PAD_DISABLED);
       } else {
-        GST_DEBUG(GST_CAT_PADS,"de-activating pad %s:%s\n",GST_DEBUG_PAD_NAME(object));
-        GST_FLAG_SET(object,GST_PAD_DISABLED);
+        GST_DEBUG (GST_CAT_PADS, "de-activating pad %s:%s\n", GST_DEBUG_PAD_NAME (object));
+        GST_FLAG_SET (object, GST_PAD_DISABLED);
       }
-      g_signal_emit(G_OBJECT(object), gst_real_pad_signals[REAL_SET_ACTIVE], 0,
-                      ! GST_FLAG_IS_SET(object,GST_PAD_DISABLED));
+      g_signal_emit (G_OBJECT (object), gst_real_pad_signals[REAL_SET_ACTIVE], 0,
+                      !GST_FLAG_IS_SET (object, GST_PAD_DISABLED));
       break;
     default:
       break;
@@ -244,7 +249,7 @@ gst_real_pad_get_property (GObject *object, guint prop_id, GValue *value, GParam
 
   switch (prop_id) {
     case REAL_ARG_ACTIVE:
-      g_value_set_boolean(value, ! GST_FLAG_IS_SET (object, GST_PAD_DISABLED) );
+      g_value_set_boolean (value, !GST_FLAG_IS_SET (object, GST_PAD_DISABLED));
       break;
     default:
       break;
@@ -272,9 +277,9 @@ gst_pad_new (gchar *name,
 
   pad = g_object_new (gst_real_pad_get_type (), NULL);
   gst_object_set_name (GST_OBJECT (pad), name);
-  GST_RPAD_DIRECTION(pad) = direction;
+  GST_RPAD_DIRECTION (pad) = direction;
 
-  return GST_PAD(pad);
+  return GST_PAD (pad);
 }
 
 /**
@@ -298,7 +303,7 @@ gst_pad_new_from_template (GstPadTemplate *templ,
   pad = gst_pad_new (name, templ->direction);
   
   gst_object_ref (GST_OBJECT (templ));
-  GST_PAD_PADTEMPLATE(pad) = templ;
+  GST_PAD_PADTEMPLATE (pad) = templ;
   
   return pad;
 }
@@ -317,7 +322,7 @@ gst_pad_get_direction (GstPad *pad)
   g_return_val_if_fail (pad != NULL, GST_PAD_UNKNOWN);
   g_return_val_if_fail (GST_IS_PAD (pad), GST_PAD_UNKNOWN);
 
-  return GST_PAD_DIRECTION(pad);
+  return GST_PAD_DIRECTION (pad);
 }
 
 /**
@@ -368,8 +373,8 @@ void gst_pad_set_chain_function (GstPad *pad,
   g_return_if_fail (GST_IS_REAL_PAD (pad));
 
   GST_RPAD_CHAINFUNC(pad) = chain;
-  GST_DEBUG (GST_CAT_PADS,"chainfunc for %s:%s set to %s\n",
-             GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(chain));
+  GST_DEBUG (GST_CAT_PADS, "chainfunc for %s:%s set to %s\n",
+             GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (chain));
 }
 
 /**
@@ -387,8 +392,8 @@ gst_pad_set_get_function (GstPad *pad,
   g_return_if_fail (GST_IS_REAL_PAD (pad));
 
   GST_RPAD_GETFUNC(pad) = get;
-  GST_DEBUG (GST_CAT_PADS,"getfunc for %s:%s  set to %s\n",
-             GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(get));
+  GST_DEBUG (GST_CAT_PADS, "getfunc for %s:%s  set to %s\n",
+             GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (get));
 }
 
 /**
@@ -406,8 +411,8 @@ gst_pad_set_event_function (GstPad *pad,
   g_return_if_fail (GST_IS_REAL_PAD (pad));
 
   GST_RPAD_EVENTFUNC(pad) = event;
-  GST_DEBUG (GST_CAT_PADS,"eventfunc for %s:%s  set to %s\n",
-             GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(event));
+  GST_DEBUG (GST_CAT_PADS, "eventfunc for %s:%s  set to %s\n",
+             GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (event));
 }
 
 /**
@@ -425,48 +430,48 @@ gst_pad_set_getregion_function (GstPad *pad,
   g_return_if_fail (GST_IS_REAL_PAD (pad));
 
   GST_RPAD_GETREGIONFUNC(pad) = getregion;
-  GST_DEBUG (GST_CAT_PADS,"getregionfunc for %s:%s set to %s\n",
-             GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(getregion));
+  GST_DEBUG (GST_CAT_PADS, "getregionfunc for %s:%s set to %s\n",
+             GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (getregion));
 }
 
 /**
- * gst_pad_set_negotiate_function:
- * @pad: the pad to set the negotiate function for
- * @nego: the negotiate function
+ * gst_pad_set_connect_function:
+ * @pad: the pad to set the connect function for
+ * @connect: the connect function
  *
- * Set the given negotiate function for the pad.
+ * Set the given connect function for the pad. It will be called
+ * when the pad is connected or reconnected with caps.
  */
 void
-gst_pad_set_negotiate_function (GstPad *pad,
-                               GstPadNegotiateFunction nego)
+gst_pad_set_connect_function (GstPad *pad,
+                             GstPadConnectFunction connect)
 {
   g_return_if_fail (pad != NULL);
   g_return_if_fail (GST_IS_REAL_PAD (pad));
 
-  GST_RPAD_NEGOTIATEFUNC(pad) = nego;
-  GST_DEBUG (GST_CAT_PADS,"negotiatefunc for %s:%s set to %s\n",
-             GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(nego));
+  GST_RPAD_CONNECTFUNC (pad) = connect;
+  GST_DEBUG (GST_CAT_PADS, "connectfunc for %s:%s set to %s\n",
+             GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (connect));
 }
 
 /**
- * gst_pad_set_newcaps_function:
- * @pad: the pad to set the newcaps function for
- * @newcaps: the newcaps function
+ * gst_pad_set_getcaps_function:
+ * @pad: the pad to set the getcaps function for
+ * @getcaps: the getcaps function
  *
- * Set the given newcaps function for the pad.
+ * Set the given getcaps function for the pad.
  */
 void
-gst_pad_set_newcaps_function (GstPad *pad,
-                             GstPadNewCapsFunction newcaps)
+gst_pad_set_getcaps_function (GstPad *pad,
+                             GstPadGetCapsFunction getcaps)
 {
   g_return_if_fail (pad != NULL);
   g_return_if_fail (GST_IS_REAL_PAD (pad));
 
-  GST_RPAD_NEWCAPSFUNC (pad) = newcaps;
-  GST_DEBUG (GST_CAT_PADS,"newcapsfunc for %s:%s set to %s\n",
-             GST_DEBUG_PAD_NAME(pad),GST_DEBUG_FUNCPTR_NAME(newcaps));
+  GST_RPAD_GETCAPSFUNC (pad) = getcaps;
+  GST_DEBUG (GST_CAT_PADS, "getcapsfunc for %s:%s set to %s\n",
+             GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (getcaps));
 }
-
 /**
  * gst_pad_set_bufferpool_function:
  * @pad: the pad to set the bufferpool function for
@@ -482,19 +487,19 @@ gst_pad_set_bufferpool_function (GstPad *pad,
   g_return_if_fail (GST_IS_REAL_PAD (pad));
 
   GST_RPAD_BUFFERPOOLFUNC (pad) = bufpool;
-  GST_DEBUG (GST_CAT_PADS,"bufferpoolfunc for %s:%s set to %s\n",
-             GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME(bufpool));
+  GST_DEBUG (GST_CAT_PADS, "bufferpoolfunc for %s:%s set to %s\n",
+             GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (bufpool));
 }
 
 static void
 gst_pad_push_func(GstPad *pad, GstBuffer *buf)
 {
-  if (GST_RPAD_CHAINFUNC(GST_RPAD_PEER(pad)) != NULL) {
-    GST_DEBUG (GST_CAT_DATAFLOW,"calling chain function %s\n",
-               GST_DEBUG_FUNCPTR_NAME(GST_RPAD_CHAINFUNC(GST_RPAD_PEER(pad))));
-    (GST_RPAD_CHAINFUNC(GST_RPAD_PEER(pad)))(pad,buf);
+  if (GST_RPAD_CHAINFUNC (GST_RPAD_PEER (pad)) != NULL) {
+    GST_DEBUG (GST_CAT_DATAFLOW, "calling chain function %s\n",
+               GST_DEBUG_FUNCPTR_NAME (GST_RPAD_CHAINFUNC (GST_RPAD_PEER (pad))));
+    (GST_RPAD_CHAINFUNC (GST_RPAD_PEER (pad))) (pad, buf);
   } else {
-    GST_DEBUG (GST_CAT_DATAFLOW,"default pad_push handler in place, no chain function\n");
+    GST_DEBUG (GST_CAT_DATAFLOW, "default pad_push handler in place, no chain function\n");
     g_warning ("(internal error) default pad_push in place for pad %s:%s but it has no chain function", 
                    GST_DEBUG_PAD_NAME (pad));
   }
@@ -521,29 +526,36 @@ gst_pad_disconnect (GstPad *srcpad,
   g_return_if_fail (GST_IS_PAD (sinkpad));
 
   GST_INFO (GST_CAT_ELEMENT_PADS, "disconnecting %s:%s(%p) and %s:%s(%p)",
-            GST_DEBUG_PAD_NAME(srcpad), srcpad, GST_DEBUG_PAD_NAME(sinkpad), sinkpad);
+            GST_DEBUG_PAD_NAME (srcpad), srcpad, GST_DEBUG_PAD_NAME (sinkpad), sinkpad);
 
   /* now we need to deal with the real/ghost stuff */
-  realsrc = GST_PAD_REALIZE(srcpad);
-  realsink = GST_PAD_REALIZE(sinkpad);
+  realsrc = GST_PAD_REALIZE (srcpad);
+  realsink = GST_PAD_REALIZE (sinkpad);
 
-  g_return_if_fail (GST_RPAD_PEER(realsrc) != NULL);
-  g_return_if_fail (GST_RPAD_PEER(realsink) != NULL);
+  g_return_if_fail (GST_RPAD_PEER (realsrc) != NULL);
+  g_return_if_fail (GST_RPAD_PEER (realsink) != NULL);
 
-  if ((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SINK) &&
-      (GST_RPAD_DIRECTION(realsink) == GST_PAD_SRC)) {
+  if ((GST_RPAD_DIRECTION (realsrc) == GST_PAD_SINK) &&
+      (GST_RPAD_DIRECTION (realsink) == GST_PAD_SRC)) {
     GstRealPad *temppad;
 
     temppad = realsrc;
     realsrc = realsink;
     realsink = temppad;
   }
-  g_return_if_fail ((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SRC) &&
-                    (GST_RPAD_DIRECTION(realsink) == GST_PAD_SINK));
+  g_return_if_fail ((GST_RPAD_DIRECTION (realsrc) == GST_PAD_SRC) &&
+                    (GST_RPAD_DIRECTION (realsink) == GST_PAD_SINK));
 
   /* first clear peers */
-  GST_RPAD_PEER(realsrc) = NULL;
-  GST_RPAD_PEER(realsink) = NULL;
+  GST_RPAD_PEER (realsrc) = NULL;
+  GST_RPAD_PEER (realsink) = NULL;
+
+  /* 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;
+  }
 
   /* now tell the scheduler */
   if (GST_PAD_PARENT (realsrc)->sched)
@@ -552,112 +564,78 @@ gst_pad_disconnect (GstPad *srcpad,
     gst_scheduler_pad_disconnect (GST_PAD_PARENT (realsink)->sched, (GstPad *)realsrc, (GstPad *)realsink);
 
   /* fire off a signal to each of the pads telling them that they've been disconnected */
-  g_signal_emit(G_OBJECT(realsrc), gst_real_pad_signals[REAL_DISCONNECTED], 0, realsink);
-  g_signal_emit(G_OBJECT(realsink), gst_real_pad_signals[REAL_DISCONNECTED], 0, realsrc);
+  g_signal_emit (G_OBJECT (realsrc), gst_real_pad_signals[REAL_DISCONNECTED], 0, realsink);
+  g_signal_emit (G_OBJECT (realsink), gst_real_pad_signals[REAL_DISCONNECTED], 0, realsrc);
 
   GST_INFO (GST_CAT_ELEMENT_PADS, "disconnected %s:%s and %s:%s",
-            GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
-}
-
-/**
- * gst_pad_connect:
- * @srcpad: the source pad to connect
- * @sinkpad: the sink pad to connect
- *
- * Connects the source pad to the sink pad.
- *
- * You shouldn't use this API in a real application because the
- * failure mode dumps diagnostics to stderr.  A professional
- * application should never fail, or use gst_pad_try_connect and
- * check the return code.
- */
-void
-gst_pad_connect (GstPad *srcpad,
-                GstPad *sinkpad)
-{
-  if (!gst_pad_try_connect (srcpad, sinkpad)) {
-    g_warning ("couldn't connect %s:%s and %s:%s",
-               GST_DEBUG_PAD_NAME (srcpad),
-               GST_DEBUG_PAD_NAME (sinkpad));
-  }
+            GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
 }
 
 /**
- * gst_pad_try_connect:
+ * gst_pad_connect_filtered:
  * @srcpad: the source pad to connect
  * @sinkpad: the sink pad to connect
+ * @filtercaps: the filter caps.
  *
- * Connects the source pad to the sink pad.
+ * Connects the source pad to the sink pad. The filter indicates the media type
+ * that should flow trought this connection.
  *
- * Returns: TRUE if the pad could be connected
+ * Returns: TRUE if the pad could be connected, FALSE otherwise
  */
 gboolean
-gst_pad_try_connect (GstPad *srcpad,
-                    GstPad *sinkpad)
+gst_pad_connect_filtered (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps)
 {
   GstRealPad *realsrc, *realsink;
   gboolean negotiated = FALSE;
 
   /* generic checks */
-  g_return_val_if_fail(srcpad != NULL, FALSE);
-  g_return_val_if_fail(GST_IS_PAD(srcpad), FALSE);
-  g_return_val_if_fail(sinkpad != NULL, FALSE);
-  g_return_val_if_fail(GST_IS_PAD(sinkpad), FALSE);
+  g_return_val_if_fail (srcpad != NULL, FALSE);
+  g_return_val_if_fail (GST_IS_PAD (srcpad), FALSE);
+  g_return_val_if_fail (sinkpad != NULL, FALSE);
+  g_return_val_if_fail (GST_IS_PAD (sinkpad), FALSE);
 
   GST_INFO (GST_CAT_PADS, "connecting %s:%s and %s:%s",
-            GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
+            GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
 
   /* now we need to deal with the real/ghost stuff */
-  realsrc = GST_PAD_REALIZE(srcpad);
-  realsink = GST_PAD_REALIZE(sinkpad);
+  realsrc = GST_PAD_REALIZE (srcpad);
+  realsink = GST_PAD_REALIZE (sinkpad);
 
   if ((GST_PAD (realsrc) != srcpad) || (GST_PAD (realsink) != sinkpad))
     GST_INFO (GST_CAT_PADS, "*actually* connecting %s:%s and %s:%s",
-              GST_DEBUG_PAD_NAME(realsrc), GST_DEBUG_PAD_NAME(realsink));
+              GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
 
-  g_return_val_if_fail(GST_RPAD_PEER(realsrc) == NULL, FALSE);
-  g_return_val_if_fail(GST_RPAD_PEER(realsink) == NULL, FALSE);
+  g_return_val_if_fail (GST_RPAD_PEER (realsrc) == NULL, FALSE);
+  g_return_val_if_fail (GST_RPAD_PEER (realsink) == NULL, FALSE);
 
   /* check for reversed directions and swap if necessary */
-  if ((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SINK) &&
-      (GST_RPAD_DIRECTION(realsink) == GST_PAD_SRC)) {
+  if ((GST_RPAD_DIRECTION (realsrc) == GST_PAD_SINK) &&
+      (GST_RPAD_DIRECTION (realsink) == GST_PAD_SRC)) {
     GstRealPad *temppad;
 
     temppad = realsrc;
     realsrc = realsink;
     realsink = temppad;
   }
-  g_return_val_if_fail((GST_RPAD_DIRECTION(realsrc) == GST_PAD_SRC) &&
-                       (GST_RPAD_DIRECTION(realsink) == GST_PAD_SINK), FALSE);
-
+  g_return_val_if_fail ((GST_RPAD_DIRECTION (realsrc) == GST_PAD_SRC) &&
+                        (GST_RPAD_DIRECTION (realsink) == GST_PAD_SINK), FALSE);
 
   /* first set peers */
-  GST_RPAD_PEER(realsrc) = realsink;
-  GST_RPAD_PEER(realsink) = realsrc;
+  GST_RPAD_PEER (realsrc) = realsink;
+  GST_RPAD_PEER (realsink) = realsrc;
 
-  if (GST_PAD_CAPS (srcpad)) {
-    GST_DEBUG(GST_CAT_PADS, "renegotiation from srcpad\n");
-    negotiated = gst_pad_renegotiate (srcpad);
-  }
-  else if (GST_PAD_CAPS (sinkpad)) {
-    GST_DEBUG(GST_CAT_PADS, "renegotiation from sinkpad\n");
-    negotiated = gst_pad_renegotiate (sinkpad);
-  }
-  else {
-    GST_DEBUG(GST_CAT_PADS, "not renegotiating connection\n");
-    negotiated = TRUE;
-  }
+  if (!gst_pad_try_reconnect_filtered_func (GST_PAD (realsrc), filtercaps, FALSE)) {
+    GST_DEBUG (GST_CAT_CAPS, "pads cannot connect\n");
+
+    GST_RPAD_PEER (realsrc) = NULL;
+    GST_RPAD_PEER (realsink) = NULL;
 
-  if (!negotiated) {
-    GST_INFO(GST_CAT_PADS, "pads %s:%s and %s:%s failed to negotiate, disconnecting",
-             GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
-    gst_pad_disconnect (GST_PAD (realsrc), GST_PAD (realsink));
     return FALSE;
   }
-
+    
   /* fire off a signal to each of the pads telling them that they've been connected */
-  g_signal_emit(G_OBJECT(realsrc), gst_real_pad_signals[REAL_CONNECTED], 0, realsink);
-  g_signal_emit(G_OBJECT(realsink), gst_real_pad_signals[REAL_CONNECTED], 0, realsrc);
+  g_signal_emit (G_OBJECT (realsrc), gst_real_pad_signals[REAL_CONNECTED], 0, realsink);
+  g_signal_emit (G_OBJECT (realsink), gst_real_pad_signals[REAL_CONNECTED], 0, realsrc);
 
   /* now tell the scheduler(s) */
   if (realsrc->sched)
@@ -666,10 +644,26 @@ gst_pad_try_connect (GstPad *srcpad,
     gst_scheduler_pad_connect (realsink->sched, (GstPad *)realsrc, (GstPad *)realsink);
 
   GST_INFO (GST_CAT_PADS, "connected %s:%s and %s:%s",
-            GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
+            GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
+
   return TRUE;
 }
 
+/**
+ * gst_pad_connect:
+ * @srcpad: the source pad to connect
+ * @sinkpad: the sink pad to connect
+ *
+ * Connects the source pad to the sink pad.
+ *
+ * Returns: TRUE if the pad could be connected, FALSE otherwise
+ */
+gboolean
+gst_pad_connect (GstPad *srcpad, GstPad *sinkpad)
+{
+  return gst_pad_connect_filtered (srcpad, sinkpad, NULL);
+}
+
 /**
  * gst_pad_set_parent:
  * @pad: the pad to set the parent
@@ -796,7 +790,7 @@ gst_pad_add_ghost_pad (GstPad *pad,
   g_return_if_fail (ghostpad != NULL);
   g_return_if_fail (GST_IS_GHOST_PAD (ghostpad));
 
-  realpad = GST_PAD_REALIZE(pad);
+  realpad = GST_PAD_REALIZE (pad);
 
   realpad->ghostpads = g_list_prepend (realpad->ghostpads, ghostpad);
 }
@@ -842,43 +836,263 @@ gst_pad_get_ghost_pad_list (GstPad *pad)
   return GST_PAD_REALIZE(pad)->ghostpads;
 }
 
+static GstPadConnectReturn
+gst_pad_try_set_caps_func (GstPad *pad, GstCaps *caps, gboolean notify, gboolean set_caps)
+{
+  GstCaps *oldcaps;
+
+  GST_INFO (GST_CAT_CAPS, "trying to set caps %p on pad %s:%s",
+            caps, GST_DEBUG_PAD_NAME (pad));
+
+  if (notify && GST_RPAD_CONNECTFUNC (pad)) {
+    GstPadConnectReturn res;
+    gchar *debug_string;
+
+    GST_INFO (GST_CAT_CAPS, "calling connect function on pad %s:%s",
+            GST_DEBUG_PAD_NAME (pad));
+
+    res = GST_RPAD_CONNECTFUNC (pad) (pad, caps);
+
+    switch (res) {
+      case GST_PAD_CONNECT_REFUSED:
+       debug_string = "REFUSED";
+       break;
+      case GST_PAD_CONNECT_OK:
+       debug_string = "OK";
+       break;
+      case GST_PAD_CONNECT_DONE:
+       debug_string = "DONE";
+       break;
+      case GST_PAD_CONNECT_DELAYED:
+       debug_string = "DELAYED";
+       break;
+      default:
+       g_warning ("unknown return code from connect function of pad %s:%s",
+            GST_DEBUG_PAD_NAME (pad));
+        return GST_PAD_CONNECT_REFUSED;
+    }
+
+    GST_INFO (GST_CAT_CAPS, "got reply %s (%d) from connect function on pad %s:%s",
+            debug_string, res, GST_DEBUG_PAD_NAME (pad));
+
+    if (res == GST_PAD_CONNECT_DONE) {
+      GST_INFO (GST_CAT_CAPS, "pad %s:%s is done", GST_DEBUG_PAD_NAME (pad));
+      return GST_PAD_CONNECT_DONE;
+    }
+    if (res == GST_PAD_CONNECT_REFUSED) {
+      GST_INFO (GST_CAT_CAPS, "pad %s:%s doesn't accept caps",
+                   GST_DEBUG_PAD_NAME (pad));
+      return GST_PAD_CONNECT_REFUSED;
+    }
+  }
+  /* we can only set caps on the pad if they are ficed */
+  if (GST_CAPS_IS_FIXED (caps)) {
+
+    if (set_caps) {
+      GST_INFO (GST_CAT_CAPS, "setting caps on pad %s:%s",
+              GST_DEBUG_PAD_NAME (pad));
+      /* if we got this far all is ok */
+      oldcaps = GST_PAD_CAPS (pad);
+      if (caps) gst_caps_ref (caps);
+      GST_PAD_CAPS (pad) = caps;
+      if (oldcaps) gst_caps_unref (oldcaps);
+    }
+    else {
+      GST_INFO (GST_CAT_CAPS, "NOT setting caps on pad %s:%s, as requested",
+              GST_DEBUG_PAD_NAME (pad));
+    }
+  }
+  else {
+    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_CONNECT_OK;
+}
+
+gboolean
+gst_pad_try_set_caps (GstPad *pad, GstCaps *caps)
+{
+  GstCaps *oldcaps;
+  GstPad *peer;
+
+  peer = GST_PAD (GST_RPAD_PEER (pad));
+
+  GST_INFO (GST_CAT_CAPS, "trying to set caps %p on pad %s:%s",
+            caps, GST_DEBUG_PAD_NAME (pad));
+
+  if (!GST_CAPS_IS_FIXED (caps)) {
+    g_warning ("trying to set non fixed caps on pad %s:%s, caps dump follow",
+            GST_DEBUG_PAD_NAME (pad));
+    gst_caps_debug (caps);
+    return FALSE;
+  }
+  if (peer && !gst_pad_try_set_caps_func (peer, caps, TRUE, TRUE))
+    return FALSE;
+  if (!gst_pad_try_set_caps_func (pad, caps, FALSE, TRUE))
+    return FALSE;
+         
+  return TRUE;
+}
+
+
+static gboolean
+gst_pad_try_reconnect_filtered_func (GstPad *pad, GstCaps *filtercaps, gboolean clear)
+{
+  GstCaps *srccaps, *sinkcaps;
+  GstCaps *intersection = NULL;
+  GstRealPad *realsrc, *realsink;
+
+  g_return_val_if_fail (pad != NULL, FALSE);
+
+  realsrc = GST_PAD_REALIZE (pad);
+  realsink = GST_PAD_REALIZE (GST_RPAD_PEER (realsrc));
+
+  g_return_val_if_fail (GST_RPAD_PEER (realsrc) != NULL, FALSE);
+  g_return_val_if_fail (GST_RPAD_PEER (realsink) != NULL, FALSE);
+
+  GST_INFO (GST_CAT_PADS, "reconnect filtered %s:%s and %s:%s",
+        GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
+
+  if (clear) {
+    GST_INFO (GST_CAT_PADS, "reconnect filtered %s:%s and %s:%s, clearing caps",
+        GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
+
+    GST_PAD_CAPS (GST_PAD (realsrc)) = NULL;
+    GST_PAD_CAPS (GST_PAD (realsink)) = NULL;
+  }
+
+  srccaps = gst_pad_get_caps (GST_PAD (realsrc));
+  GST_INFO (GST_CAT_PADS, "dumping caps of pad %s:%s", GST_DEBUG_PAD_NAME (realsrc));
+  gst_caps_debug (srccaps);
+  sinkcaps = gst_pad_get_caps (GST_PAD (realsink));
+  GST_INFO (GST_CAT_PADS, "dumping caps of pad %s:%s", GST_DEBUG_PAD_NAME (realsink));
+  gst_caps_debug (sinkcaps);
+
+  intersection = gst_caps_intersect (srccaps, sinkcaps);
+
+  /* if we have no intersection but one of the caps was not NULL.. */
+  if (!intersection && (srccaps || sinkcaps )) {
+    /* the intersection is NULL, 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));
+    return FALSE;
+  }
+  else {
+    GST_INFO (GST_CAT_PADS, "pads %s:%s and %s:%s intersected to %s caps",
+         GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink), 
+        ((intersection && GST_CAPS_IS_FIXED (intersection)) ? "fixed" : "variable"));
+
+    if (filtercaps) {
+      GstCaps *filtered_intersection = gst_caps_intersect (intersection, filtercaps);
+
+      /* get rid of the old intersection here */
+      gst_caps_unref (intersection);
+
+      if (!filtered_intersection) {
+        GST_INFO (GST_CAT_PADS, "filtered connection between pads %s:%s and %s:%s is empty, disconnecting",
+             GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
+        return FALSE;
+      }
+      intersection = filtered_intersection;
+
+      GST_RPAD_APPFILTER (realsink) = filtercaps;
+      GST_RPAD_APPFILTER (realsrc) = filtercaps;
+    }
+  }
+  GST_DEBUG (GST_CAT_CAPS, "setting filter for connection to:\n");
+  gst_caps_debug (intersection);
+
+  GST_RPAD_FILTER (realsrc) = intersection; 
+  GST_RPAD_FILTER (realsink) = intersection; 
+
+  if (intersection) {
+    GstPadConnectReturn res;
+
+    res = gst_pad_try_set_caps_func (GST_PAD (realsrc), intersection, TRUE, TRUE);
+    if (res == GST_PAD_CONNECT_REFUSED) 
+      return FALSE;
+    if (res == GST_PAD_CONNECT_DONE) 
+      return TRUE;
+
+    res = gst_pad_try_set_caps_func (GST_PAD (realsink), intersection, TRUE, TRUE);
+    if (res == GST_PAD_CONNECT_REFUSED) 
+      return FALSE;
+    if (res == GST_PAD_CONNECT_DONE) 
+      return TRUE;
+  }
+
+  return TRUE;
+}
+
 /**
- * gst_pad_set_caps:
- * @pad: the pad to set the caps to
- * @caps: the capabilities to attach to this pad
+ * gst_pad_try_reconnect_filtered:
+ * @pad: the pad to reconnect
+ * @caps: the capabilities to use in the reconnectiong
  *
- * Set the capabilities of this pad.
+ * Try to reconnect this pad and its peer with the specified caps
  *
- * Returns: a boolean indicating the caps could be set on the pad
+ * Returns: a boolean indicating the peer pad could accept the caps.
  */
 gboolean
-gst_pad_set_caps (GstPad *pad,
-                  GstCaps *caps)
+gst_pad_try_reconnect_filtered (GstPad *pad, GstCaps *filtercaps)
 {
-  GstCaps *oldcaps;
-
   g_return_val_if_fail (pad != NULL, FALSE);
-  g_return_val_if_fail (GST_IS_REAL_PAD (pad), FALSE);         /* NOTE this restriction */
+  g_return_val_if_fail (GST_IS_REAL_PAD (pad), FALSE); 
+  g_return_val_if_fail (GST_PAD_IS_CONNECTED (pad), FALSE);
+  
+  return gst_pad_try_reconnect_filtered_func (pad, filtercaps, TRUE);
+}
 
-  GST_INFO (GST_CAT_CAPS, "setting caps %p on pad %s:%s",
-            caps, GST_DEBUG_PAD_NAME(pad));
+/**
+ * gst_pad_reconnect_filtered:
+ * @pad: the pad to reconnect
+ * @caps: the capabilities to use in the reconnectiong
+ *
+ * Try to reconnect this pad and its peer with the specified caps. 
+ *
+ * Returns: a boolean indicating the peer pad could accept the caps.
+ *    if FALSE is returned, the pads are disconnected.
+ */
+gboolean
+gst_pad_reconnect_filtered (GstPad *pad, GstCaps *filtercaps)
+{
+  g_return_val_if_fail (pad != NULL, FALSE);
+  g_return_val_if_fail (GST_IS_REAL_PAD (pad), FALSE);
+  g_return_val_if_fail (GST_PAD_IS_CONNECTED (pad), FALSE);
 
-  if (!gst_caps_check_compatibility (caps, gst_pad_get_padtemplate_caps (pad))) {
-    g_warning ("pad %s:%s tried to set caps incompatible with its padtemplate\n",
-                   GST_DEBUG_PAD_NAME (pad));
+  if (!gst_pad_try_reconnect_filtered_func (pad, filtercaps, TRUE)) {
+    gst_pad_disconnect (pad, GST_PAD (GST_PAD_PEER (pad)));
     return FALSE;
   }
-  
-  oldcaps = GST_PAD_CAPS (pad);
+  return TRUE;
+}
 
-  if (caps)
-    gst_caps_ref (caps);
-  GST_PAD_CAPS(pad) = caps;
+/**
+ * gst_pad_proxy_connect:
+ * @pad: the pad to proxy to
+ * @caps: the capabilities to use in the proxying
+ *
+ * Proxy the connect function to the specified pad.
+ *
+ * Returns: a boolean indicating the peer pad could accept the caps.
+ */
+GstPadConnectReturn
+gst_pad_proxy_connect (GstPad *pad, GstCaps *caps)
+{
+  GstPad *peer;
+
+  peer = GST_PAD (GST_RPAD_PEER (pad));
 
-  if (oldcaps)
-    gst_caps_unref (oldcaps);
+  GST_INFO (GST_CAT_CAPS, "proxy connect to pad %s:%s",
+            GST_DEBUG_PAD_NAME (pad));
 
-  return gst_pad_renegotiate (pad);
+  if (peer && !gst_pad_try_set_caps_func (peer, caps, TRUE, TRUE))
+    return GST_PAD_CONNECT_REFUSED;
+  if (!gst_pad_try_set_caps_func (pad, caps, FALSE, TRUE))
+    return GST_PAD_CONNECT_REFUSED;
+
+  return GST_PAD_CONNECT_OK;
 }
 
 /**
@@ -895,10 +1109,22 @@ gst_pad_get_caps (GstPad *pad)
   g_return_val_if_fail (pad != NULL, NULL);
   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
 
-  if (GST_PAD_CAPS (pad))
+  GST_DEBUG (GST_CAT_CAPS, "get pad caps of %s:%s (%p)\n",
+            GST_DEBUG_PAD_NAME (pad), pad);
+
+  if (GST_PAD_CAPS (pad)) {
+    GST_DEBUG (GST_CAT_CAPS, "using pad real caps\n");
     return GST_PAD_CAPS (pad);
-  else if (GST_PAD_PADTEMPLATE (pad))
+  }
+  else if GST_RPAD_GETCAPSFUNC (pad) {
+    GST_DEBUG (GST_CAT_CAPS, "using pad get function\n");
+    return GST_RPAD_GETCAPSFUNC (pad) (pad, NULL);
+  }
+  else if (GST_PAD_PADTEMPLATE (pad)) {
+    GST_DEBUG (GST_CAT_CAPS, "using pad template\n");
     return GST_PADTEMPLATE_CAPS (GST_PAD_PADTEMPLATE (pad));
+  }
+  GST_DEBUG (GST_CAT_CAPS, "pad has no caps\n");
 
   return NULL;
 }
@@ -965,8 +1191,8 @@ gst_pad_check_compatibility (GstPad *srcpad, GstPad *sinkpad)
   g_return_val_if_fail (sinkpad != NULL, FALSE);
   g_return_val_if_fail (GST_IS_PAD (sinkpad), FALSE);
 
-  if (GST_PAD_CAPS(srcpad) && GST_PAD_CAPS(sinkpad)) {
-    if (!gst_caps_check_compatibility (GST_PAD_CAPS(srcpad), GST_PAD_CAPS(sinkpad))) {
+  if (GST_PAD_CAPS (srcpad) && GST_PAD_CAPS (sinkpad)) {
+    if (!gst_caps_check_compatibility (GST_PAD_CAPS (srcpad), GST_PAD_CAPS (sinkpad))) {
       return FALSE;
     }
     else {
@@ -974,7 +1200,7 @@ gst_pad_check_compatibility (GstPad *srcpad, GstPad *sinkpad)
     }
   }
   else {
-    GST_DEBUG (GST_CAT_PADS,"could not check capabilities of pads (%s:%s) and (%s:%s) %p %p\n",
+    GST_DEBUG (GST_CAT_PADS, "could not check capabilities of pads (%s:%s) and (%s:%s) %p %p\n",
                    GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad), 
                    GST_PAD_CAPS (srcpad), GST_PAD_CAPS (sinkpad));
     return TRUE;
@@ -995,7 +1221,61 @@ gst_pad_get_peer (GstPad *pad)
   g_return_val_if_fail (pad != NULL, NULL);
   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
 
-  return GST_PAD(GST_PAD_PEER(pad));
+  return GST_PAD (GST_PAD_PEER (pad));
+}
+
+/**
+ * gst_pad_get_allowed_caps:
+ * @pad: the pad to get the allowed caps from
+ *
+ * Gst the caps of the allowed media types that can
+ * go through this pad.
+ *
+ * Returns: the allowed caps
+ */
+GstCaps*
+gst_pad_get_allowed_caps (GstPad *pad)
+{
+  GstRealPad *peer;
+  
+  g_return_val_if_fail (pad != NULL, NULL);
+  g_return_val_if_fail (GST_IS_PAD (pad), NULL);
+
+  peer = GST_RPAD_PEER (pad);
+
+  GST_DEBUG (GST_CAT_PROPERTIES, "get allowed caps of %s:%s\n", GST_DEBUG_PAD_NAME (pad));
+  /* this is not very correct: ... 
+  if (peer && GST_RPAD_GETCAPSFUNC (peer)) {
+    GST_DEBUG (GST_CAT_PROPERTIES, "using getcaps function of peer %s:%s\n", 
+                   GST_DEBUG_PAD_NAME (peer));
+    return GST_RPAD_GETCAPSFUNC (peer) (GST_PAD (peer), NULL);
+  }
+  */
+  return gst_caps_copy (GST_RPAD_FILTER (pad));
+}
+
+/**
+ * gst_pad_get_allowed_caps:
+ * @pad: the pad to get the allowed caps from
+ *
+ * Gst the caps of the allowed media types that can
+ * go through this pad.
+ *
+ * Returns: the allowed caps
+ */
+gboolean
+gst_pad_recalc_allowed_caps (GstPad *pad)
+{
+  GstRealPad *peer;
+
+  g_return_if_fail (pad != NULL);
+  g_return_if_fail (GST_IS_PAD (pad));
+
+  GST_DEBUG (GST_CAT_PROPERTIES, "set allowed caps of %s:%s\n", GST_DEBUG_PAD_NAME (pad));
+
+  peer = GST_RPAD_PEER (pad);
+  if (peer)
+    gst_pad_try_reconnect_filtered (pad, GST_RPAD_APPFILTER (pad));
 }
 
 /**
@@ -1015,18 +1295,20 @@ gst_pad_get_bufferpool (GstPad *pad)
   g_return_val_if_fail (pad != NULL, NULL);
   g_return_val_if_fail (GST_IS_PAD (pad), NULL);
    
-  peer = GST_RPAD_PEER(pad);
+  peer = GST_RPAD_PEER (pad);
 
-  g_return_val_if_fail (peer != NULL, NULL);
+  if (!peer)
+    return NULL;
 
-  GST_DEBUG_ENTER("(%s:%s)",GST_DEBUG_PAD_NAME(pad));
+  GST_DEBUG_ENTER ("(%s:%s)", GST_DEBUG_PAD_NAME (pad));
 
   if (peer->bufferpoolfunc) {
-    GST_DEBUG (GST_CAT_PADS,"calling bufferpoolfunc &%s (@%p) of peer pad %s:%s\n",
-      GST_DEBUG_FUNCPTR_NAME(peer->bufferpoolfunc),&peer->bufferpoolfunc,GST_DEBUG_PAD_NAME(((GstPad*)peer)));
-    return (peer->bufferpoolfunc)(((GstPad*)peer));
+    GST_DEBUG (GST_CAT_PADS, "calling bufferpoolfunc &%s (@%p) of peer pad %s:%s\n",
+      GST_DEBUG_FUNCPTR_NAME (peer->bufferpoolfunc), &peer->bufferpoolfunc, GST_DEBUG_PAD_NAME (((GstPad*) peer)));
+    return (peer->bufferpoolfunc) (((GstPad*) peer));
   } else {
-    GST_DEBUG (GST_CAT_PADS,"no bufferpoolfunc for peer pad %s:%s at %p\n",GST_DEBUG_PAD_NAME(((GstPad*)peer)),&peer->bufferpoolfunc);
+    GST_DEBUG (GST_CAT_PADS, "no bufferpoolfunc for peer pad %s:%s at %p\n",
+                   GST_DEBUG_PAD_NAME (((GstPad*) peer)), &peer->bufferpoolfunc);
     return NULL;
   }
 }
@@ -1048,7 +1330,7 @@ gst_real_pad_dispose (GObject *object)
     gst_pad_disconnect (pad, GST_PAD (GST_PAD_PEER (pad)));
   }
   
-  /* FIXME we should destroy the ghostpads, because they are nothing without the real pad  */
+  /* we destroy the ghostpads, because they are nothing without the real pad  */
   if (GST_REAL_PAD (pad)->ghostpads) {
     GList *orig, *ghostpads;
 
@@ -1058,7 +1340,9 @@ gst_real_pad_dispose (GObject *object)
       GstPad *ghostpad = GST_PAD (ghostpads->data);
 
       if (GST_IS_ELEMENT (GST_OBJECT_PARENT (ghostpad))){
-        GST_DEBUG (GST_CAT_REFCOUNTING, "removing ghost pad from element '%s'\n", GST_OBJECT_NAME(GST_OBJECT_PARENT (ghostpad)));
+        GST_DEBUG (GST_CAT_REFCOUNTING, "removing ghost pad from element '%s'\n", 
+                       GST_OBJECT_NAME (GST_OBJECT_PARENT (ghostpad)));
+
         gst_element_remove_ghost_pad (GST_ELEMENT (GST_OBJECT_PARENT (ghostpad)), GST_PAD (ghostpad));
       }
       ghostpads = g_list_next (ghostpads);
@@ -1068,7 +1352,9 @@ gst_real_pad_dispose (GObject *object)
   }
 
   if (GST_IS_ELEMENT (GST_OBJECT_PARENT (pad))){
-    GST_DEBUG (GST_CAT_REFCOUNTING, "removing pad from element '%s'\n",GST_OBJECT_NAME(GST_OBJECT (GST_ELEMENT (GST_OBJECT_PARENT (pad)))));
+    GST_DEBUG (GST_CAT_REFCOUNTING, "removing pad from element '%s'\n",
+                   GST_OBJECT_NAME (GST_OBJECT (GST_ELEMENT (GST_OBJECT_PARENT (pad)))));
+    
     gst_element_remove_pad (GST_ELEMENT (GST_OBJECT_PARENT (pad)), pad);
   }
   
@@ -1133,255 +1419,7 @@ gst_pad_load_and_connect (xmlNodePtr self,
 cleanup:
   g_strfreev (split);
 }
-#endif /* GST_DISABLE_LOADSAVE */
-
-static gboolean
-gst_pad_renegotiate_func (GstPad *pad, gpointer *data1, GstPad *peerpad, gpointer *data2, GstCaps **newcaps)
-{
-  GstRealPad *currentpad, *otherpad;
-  gpointer *currentdata, *otherdata;
-  GstPadNegotiateReturn result;
-  gint counter = 0;
-  
-  g_return_val_if_fail (pad != NULL, FALSE);
-
-  currentpad = GST_PAD_REALIZE (pad);
-  otherpad = GST_REAL_PAD (peerpad);
-  currentdata = data1;
-  otherdata = data2;
-
-  GST_DEBUG (GST_CAT_NEGOTIATION, "negotiating pad %s:%s and %s:%s data:%p\n",
-            GST_DEBUG_PAD_NAME(currentpad), GST_DEBUG_PAD_NAME(otherpad), currentdata);
-
-  do {
-    gboolean matchtempl;
-    
-    if (!*newcaps) {
-      if (otherpad->negotiatefunc) {
-        GstRealPad *temp;
-        gpointer *tempdata;
-
-        GST_DEBUG (GST_CAT_NEGOTIATION, "requesting other caps from pad %s:%s data:%p\n",
-                        GST_DEBUG_PAD_NAME(otherpad), otherdata);
-        otherpad->negotiatefunc (GST_PAD (otherpad), newcaps, otherdata);
-
-        temp = otherpad;
-        otherpad = currentpad;
-        currentpad = temp;
-
-        tempdata = otherdata;
-        otherdata = currentdata;
-        currentdata = tempdata;
-      }
-    }
-
-    GST_DEBUG (GST_CAT_NEGOTIATION, "checking compatibility with pad %s:%s\n",
-                     GST_DEBUG_PAD_NAME(otherpad));
-    matchtempl = gst_caps_check_compatibility (*newcaps, gst_pad_get_padtemplate_caps (GST_PAD (otherpad)));
-
-    GST_DEBUG (GST_CAT_NEGOTIATION, "caps compatibility check %s\n", (matchtempl?"ok":"fail"));
-
-    if (matchtempl) {
-      GST_DEBUG (GST_CAT_NEGOTIATION, "checking if other pad %s:%s can negotiate data:%p\n",
-                     GST_DEBUG_PAD_NAME(otherpad), otherdata);
-      if (otherpad->negotiatefunc) {
-        GstRealPad *temp;
-        gpointer *tempdata;
-
-        GST_DEBUG (GST_CAT_NEGOTIATION, "switching pad for next phase\n");
-
-        temp = currentpad;
-        currentpad = otherpad;
-        otherpad = temp;
-
-        tempdata = otherdata;
-        otherdata = currentdata;
-        currentdata = tempdata;
-      }
-      else if (gst_caps_check_compatibility (*newcaps, GST_PAD_CAPS (otherpad))) {
-        GST_DEBUG (GST_CAT_NEGOTIATION, "negotiation succeeded\n");
-        return TRUE;
-      }
-      else {
-       *newcaps = GST_PAD_CAPS (otherpad);
-       if (*newcaps) gst_caps_ref(*newcaps);
-      }
-    }
-    else {
-      *newcaps = GST_PAD_CAPS (otherpad);
-      if (*newcaps) gst_caps_ref(*newcaps);
-    }
-
-    counter++;
-
-    if (currentpad->negotiatefunc) {
-      GST_DEBUG (GST_CAT_NEGOTIATION, "calling negotiate function on pad %s:%s data: %p\n",
-                     GST_DEBUG_PAD_NAME (currentpad), currentdata);
-      result = currentpad->negotiatefunc (GST_PAD (currentpad), newcaps, currentdata);
-
-      switch (result) {
-        case GST_PAD_NEGOTIATE_FAIL:
-          GST_DEBUG (GST_CAT_NEGOTIATION, "negotiation failed\n");
-          return FALSE;
-        case GST_PAD_NEGOTIATE_AGREE:
-          GST_DEBUG (GST_CAT_NEGOTIATION, "negotiation succeeded\n");
-          return TRUE;
-        case GST_PAD_NEGOTIATE_TRY:
-          GST_DEBUG (GST_CAT_NEGOTIATION, "try another option\n");
-          break;
-       default:
-          GST_DEBUG (GST_CAT_NEGOTIATION, "invalid return\n");
-          break;
-      }
-    }
-    else {
-      GST_DEBUG (GST_CAT_NEGOTIATION, "negotiation failed, no more options\n");
-      return FALSE;
-    }
-      
-  } while (counter < 100);
-
-  g_warning ("negotiation between (%s:%s) and (%s:%s) failed: too many attempts (%d)\n",
-            GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(peerpad), counter);
-
-  GST_DEBUG (GST_CAT_NEGOTIATION, "negotiation failed, too many attempts\n");
-  
-  return FALSE;
-}
-
-/**
- * gst_pad_renegotiate:
- * @pad: the pad to perform the negotiation on
- *
- * Perform the negotiation process with the peer pad.
- *
- * Returns: TRUE if the negotiation process succeded
- */
-gboolean
-gst_pad_renegotiate (GstPad *pad)
-{
-  GstCaps *newcaps = NULL;
-  GstRealPad *peerpad, *currentpad, *otherpad;
-  gboolean result;
-  gpointer data1 = NULL, data2 = NULL;
-  
-  g_return_val_if_fail (pad != NULL, FALSE);
-
-  peerpad = GST_PAD_PEER (pad);
-
-  currentpad = GST_PAD_REALIZE (pad);
-
-  if (!peerpad) {
-    GST_DEBUG (GST_CAT_NEGOTIATION, "no peer pad for pad %s:%s\n",
-                 GST_DEBUG_PAD_NAME(currentpad));
-    return TRUE;
-  }
-   
-  otherpad = GST_REAL_PAD (peerpad);
-
-  GST_INFO (GST_CAT_NEGOTIATION, "negotiating pad %s:%s and %s:%s",
-            GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(peerpad));
-
-  newcaps = GST_PAD_CAPS (pad);
-  
-  result = gst_pad_renegotiate_func (GST_PAD (currentpad), &data1, GST_PAD (otherpad), &data2, &newcaps);
-
-  if (!result) {
-    GST_DEBUG (GST_CAT_NEGOTIATION, "firing caps_nego_failed signal on %s:%s and %s:%s to give it a chance to succeed\n",
-               GST_DEBUG_PAD_NAME(currentpad),GST_DEBUG_PAD_NAME(otherpad));
-    g_signal_emit (G_OBJECT(currentpad), 
-                     gst_real_pad_signals[REAL_CAPS_NEGO_FAILED], 0, &result);
-    g_signal_emit (G_OBJECT(otherpad), 
-                     gst_real_pad_signals[REAL_CAPS_NEGO_FAILED], 0, &result);
-    if (result)
-      GST_DEBUG (GST_CAT_NEGOTIATION, "caps_nego_failed handler claims success at renego, believing\n");
-  }
-
-  if (result) {
-    GST_DEBUG (GST_CAT_NEGOTIATION, "pads aggreed on caps :)\n");
-
-  newcaps = GST_PAD_CAPS (pad);
-    /* g_return_val_if_fail(newcaps != NULL, FALSE);  FIXME is this valid? */
-
-    /* here we have some sort of aggreement of the caps */
-    GST_PAD_CAPS (currentpad) = gst_caps_ref (newcaps);
-    if (GST_RPAD_NEWCAPSFUNC (currentpad))
-      GST_RPAD_NEWCAPSFUNC (currentpad) (GST_PAD (currentpad), newcaps);
-
-    GST_PAD_CAPS (otherpad) = gst_caps_ref (newcaps);
-    if (GST_RPAD_NEWCAPSFUNC (otherpad))
-      GST_RPAD_NEWCAPSFUNC (otherpad) (GST_PAD (otherpad), newcaps);
-
-    GST_DEBUG (GST_CAT_NEGOTIATION, "firing caps_changed signal on %s:%s and %s:%s\n",
-               GST_DEBUG_PAD_NAME(currentpad),GST_DEBUG_PAD_NAME(otherpad));
-    g_signal_emit (G_OBJECT(currentpad), 
-                     gst_real_pad_signals[REAL_CAPS_CHANGED], 0, GST_PAD_CAPS(currentpad));
-    g_signal_emit (G_OBJECT(otherpad), 
-                     gst_real_pad_signals[REAL_CAPS_CHANGED], 0, GST_PAD_CAPS(otherpad));
-  }
-
-  return result;
-}
 
-/**
- * gst_pad_negotiate_proxy:
- * @srcpad: the pad that proxies
- * @destpad: the pad to proxy the negotiation to
- * @caps: the current caps
- *
- * Proxies the negotiation pad from srcpad to destpad. Further
- * negotiation is done on the peers of both pad instead.
- *
- * Returns: the result of the negotiation preocess.
- */
-GstPadNegotiateReturn
-gst_pad_negotiate_proxy (GstPad *srcpad, GstPad *destpad, GstCaps **caps)
-{
-  GstRealPad *srcpeer;
-  GstRealPad *destpeer;
-  gboolean result;
-  gpointer data1 = NULL, data2 = NULL;
-
-  g_return_val_if_fail (srcpad != NULL, GST_PAD_NEGOTIATE_FAIL);
-  g_return_val_if_fail (destpad != NULL, GST_PAD_NEGOTIATE_FAIL);
-
-  GST_DEBUG (GST_CAT_NEGOTIATION, "negotiation proxied from pad (%s:%s) to pad (%s:%s)\n", 
-                 GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));
-
-  srcpeer = GST_RPAD_PEER (srcpad);
-  destpeer = GST_RPAD_PEER (destpad);
-
-  if (srcpeer && destpeer) {
-    result = gst_pad_renegotiate_func (GST_PAD (srcpeer), &data1, GST_PAD (destpeer), &data2, caps);
-
-    if (result) {
-      GST_DEBUG (GST_CAT_NEGOTIATION, "pads (%s:%s) and (%s:%s) aggreed on caps :)\n",
-                 GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));
-
-      /* here we have some sort of aggreement of the caps */
-      GST_PAD_CAPS (destpeer) = *caps;
-      if (GST_RPAD_NEWCAPSFUNC (destpeer))
-        GST_RPAD_NEWCAPSFUNC (destpeer) (GST_PAD (destpeer), *caps);
-
-      GST_PAD_CAPS (destpad) = *caps;
-      if (GST_RPAD_NEWCAPSFUNC (destpad))
-        GST_RPAD_NEWCAPSFUNC (destpad) (GST_PAD (destpad), *caps);
-    }
-    else {
-      GST_DEBUG (GST_CAT_NEGOTIATION, "pads did not aggree on caps :(\n");
-      return GST_PAD_NEGOTIATE_FAIL;
-    }
-  }
-  else {
-    GST_PAD_CAPS (destpad) = *caps;
-    if (GST_RPAD_NEWCAPSFUNC (destpad))
-      GST_RPAD_NEWCAPSFUNC (destpad) (GST_PAD (destpad), *caps);
-  }
-
-  return GST_PAD_NEGOTIATE_AGREE;
-}
-
-#ifndef GST_DISABLE_LOADSAVE
 /**
  * gst_pad_save_thyself:
  * @pad: the pad to save
@@ -1757,6 +1795,7 @@ gst_padtemplate_new (gchar *name_template,
   va_start (var_args, caps);
 
   while (caps) {
+    new->fixed &= caps->fixed;
     thecaps = gst_caps_append (thecaps, caps);
     caps = va_arg (var_args, GstCaps*);
   }
@@ -1980,21 +2019,21 @@ gst_ghost_pad_new (gchar *name,
   GstGhostPad *ghostpad;
 
   g_return_val_if_fail (name != NULL, NULL);
-  g_return_val_if_fail (GST_IS_PAD(pad), NULL);
+  g_return_val_if_fail (GST_IS_PAD (pad), NULL);
 
-  ghostpad = g_object_new(gst_ghost_pad_get_type () ,NULL);
+  ghostpad = g_object_new (gst_ghost_pad_get_type () ,NULL);
   gst_pad_set_name (GST_PAD (ghostpad), name);
-  GST_GPAD_REALPAD(ghostpad) = GST_PAD_REALIZE(pad);
-  GST_PAD_PADTEMPLATE(ghostpad) = GST_PAD_PADTEMPLATE(pad);
+  GST_GPAD_REALPAD (ghostpad) = GST_PAD_REALIZE (pad);
+  GST_PAD_PADTEMPLATE (ghostpad) = GST_PAD_PADTEMPLATE (pad);
 
   /* add ourselves to the real pad's list of ghostpads */
-  gst_pad_add_ghost_pad (pad, GST_PAD(ghostpad));
+  gst_pad_add_ghost_pad (pad, GST_PAD (ghostpad));
 
   /* FIXME need to ref the real pad here... ? */
 
-  GST_DEBUG(GST_CAT_PADS,"created ghost pad \"%s\"\n",name);
+  GST_DEBUG (GST_CAT_PADS, "created ghost pad \"%s\"\n", name);
 
-  return GST_PAD(ghostpad);
+  return GST_PAD (ghostpad);
 }
 
 static void 
@@ -2007,7 +2046,7 @@ gst_pad_event_default_dispatch (GstPad *pad, GstElement *element, GstEvent *even
     pads = g_list_next (pads);
 
     /* for all pads in the opposite direction that are connected */
-    if (GST_PAD_DIRECTION (eventpad) != GST_PAD_DIRECTION (pad) && GST_PAD_CONNECTED (eventpad)) {
+    if (GST_PAD_DIRECTION (eventpad) != GST_PAD_DIRECTION (pad) && GST_PAD_IS_CONNECTED (eventpad)) {
       if (GST_PAD_DIRECTION (eventpad) == GST_PAD_SRC) {
         gst_pad_push (eventpad, GST_BUFFER (gst_event_new (GST_EVENT_TYPE (event))));
        
index 5f572f0c0f399c8b55c1d66f8c1d94ffb74ad39c..974af3ce3474bbe39e831cc532f3d2d70a934719 100644 (file)
@@ -117,25 +117,27 @@ typedef enum {
   GST_REGION_TIME_LEN,
 } GstRegionType;
 
-typedef enum { 
-  GST_PAD_NEGOTIATE_FAIL,
-  GST_PAD_NEGOTIATE_AGREE,
-  GST_PAD_NEGOTIATE_TRY,
-} GstPadNegotiateReturn;
-
+typedef enum {
+  GST_PAD_CONNECT_REFUSED = 0,
+  GST_PAD_CONNECT_OK      = 1,
+  GST_PAD_CONNECT_DONE    = 2,
+  GST_PAD_CONNECT_DELAYED = 3,
+} GstPadConnectReturn;
 
 /* this defines the functions used to chain buffers
  * pad is the sink pad (so the same chain function can be used for N pads)
  * buf is the buffer being passed */
-typedef void           (*GstPadChainFunction)          (GstPad *pad,GstBuffer *buf);
-typedef GstBuffer*     (*GstPadGetFunction)            (GstPad *pad);
-typedef gboolean       (*GstPadEventFunction)          (GstPad *pad, GstEvent *event);
-
-typedef GstBuffer*     (*GstPadGetRegionFunction)      (GstPad *pad, GstRegionType type, guint64 offset, guint64 len);
-typedef GstBuffer*     (*GstPadPullRegionFunction)     (GstPad *pad, GstRegionType type, guint64 offset, guint64 len);
-typedef GstPadNegotiateReturn (*GstPadNegotiateFunction)       (GstPad *pad, GstCaps **caps, gpointer *data);
-typedef void           (*GstPadNewCapsFunction)        (GstPad *pad, GstCaps *caps);
-typedef GstBufferPool* (*GstPadBufferPoolFunction)     (GstPad *pad);
+typedef void                   (*GstPadChainFunction)          (GstPad *pad,GstBuffer *buf);
+typedef GstBuffer*             (*GstPadGetFunction)            (GstPad *pad);
+typedef gboolean               (*GstPadEventFunction)          (GstPad *pad, GstEvent *event);
+
+typedef GstBuffer*             (*GstPadGetRegionFunction)      (GstPad *pad, GstRegionType type, 
+                                                                guint64 offset, guint64 len);
+typedef GstBuffer*             (*GstPadPullRegionFunction)     (GstPad *pad, GstRegionType type, 
+                                                                guint64 offset, guint64 len);
+typedef GstPadConnectReturn    (*GstPadConnectFunction)        (GstPad *pad, GstCaps *caps);
+typedef GstCaps*               (*GstPadGetCapsFunction)        (GstPad *pad, GstCaps *caps);
+typedef GstBufferPool*         (*GstPadBufferPoolFunction)     (GstPad *pad);
 
 typedef enum {
   GST_PAD_UNKNOWN,
@@ -166,6 +168,8 @@ struct _GstRealPad {
   GstPad                       pad;
 
   GstCaps                      *caps;
+  GstCaps                      *filter;
+  GstCaps                      *appfilter;
   GstPadDirection              direction;
 
   GstScheduler                 *sched;
@@ -189,8 +193,8 @@ struct _GstRealPad {
   GstPadGetRegionFunction      getregionfunc;
   GstPadPullRegionFunction     pullregionfunc;
 
-  GstPadNegotiateFunction      negotiatefunc;
-  GstPadNewCapsFunction        newcapsfunc;
+  GstPadGetCapsFunction        getcapsfunc;
+  GstPadConnectFunction        connectfunc;
   GstPadBufferPoolFunction     bufferpoolfunc;
 
   GList *ghostpads;
@@ -231,6 +235,8 @@ struct _GstGhostPadClass {
 /* GstRealPad */
 #define GST_RPAD_DIRECTION(pad)                (((GstRealPad *)(pad))->direction)
 #define GST_RPAD_CAPS(pad)             (((GstRealPad *)(pad))->caps)
+#define GST_RPAD_FILTER(pad)           (((GstRealPad *)(pad))->filter)
+#define GST_RPAD_APPFILTER(pad)                (((GstRealPad *)(pad))->appfilter)
 #define GST_RPAD_PEER(pad)             (((GstRealPad *)(pad))->peer)
 #define GST_RPAD_BUFPEN(pad)           (((GstRealPad *)(pad))->bufpen)
 #define GST_RPAD_SCHED(pad)            (((GstRealPad *)(pad))->sched)
@@ -244,8 +250,8 @@ struct _GstGhostPadClass {
 #define GST_RPAD_GETREGIONFUNC(pad)    (((GstRealPad *)(pad))->getregionfunc)
 #define GST_RPAD_PULLREGIONFUNC(pad)   (((GstRealPad *)(pad))->pullregionfunc)
 
-#define GST_RPAD_NEGOTIATEFUNC(pad)    (((GstRealPad *)(pad))->negotiatefunc)
-#define GST_RPAD_NEWCAPSFUNC(pad)      (((GstRealPad *)(pad))->newcapsfunc)
+#define GST_RPAD_CONNECTFUNC(pad)      (((GstRealPad *)(pad))->connectfunc)
+#define GST_RPAD_GETCAPSFUNC(pad)      (((GstRealPad *)(pad))->getcapsfunc)
 #define GST_RPAD_BUFFERPOOLFUNC(pad)   (((GstRealPad *)(pad))->bufferpoolfunc)
 
 #define GST_RPAD_REGIONTYPE(pad)       (((GstRealPad *)(pad))->regiontype)
@@ -262,9 +268,10 @@ struct _GstGhostPadClass {
 #define GST_PAD_PEER(pad)              GST_RPAD_PEER(GST_PAD_REALIZE(pad))
 
 /* Some check functions (unused?) */
-#define GST_PAD_CONNECTED(pad)         (GST_PAD_PEER(pad) != NULL)
+#define GST_PAD_IS_CONNECTED(pad)      (GST_PAD_PEER(pad) != NULL)
 #define GST_PAD_CAN_PULL(pad)          (GST_IS_REAL_PAD(pad) && GST_REAL_PAD(pad)->gethandler != NULL)
-
+#define GST_PAD_IS_SRC(pad)            (GST_PAD_DIRECTION(pad) == GST_PAD_SRC)
+#define GST_PAD_IS_SINK(pad)           (GST_PAD_DIRECTION(pad) == GST_PAD_SINK)
 
 /***** PadTemplate *****/
 #define GST_TYPE_PADTEMPLATE           (gst_padtemplate_get_type ())
@@ -283,6 +290,9 @@ typedef enum {
 #define GST_PADTEMPLATE_DIRECTION(templ)       (((GstPadTemplate *)(templ))->direction)
 #define GST_PADTEMPLATE_PRESENCE(templ)                (((GstPadTemplate *)(templ))->presence)
 #define GST_PADTEMPLATE_CAPS(templ)            (((GstPadTemplate *)(templ))->caps)
+#define GST_PADTEMPLATE_FIXED(templ)           (((GstPadTemplate *)(templ))->fixed)
+
+#define GST_PADTEMPLATE_IS_FIXED(templ)                (GST_PADTEMPLATE_FIXED(templ) == TRUE)
 
 struct _GstPadTemplate {
   GstObject      object;
@@ -291,6 +301,7 @@ struct _GstPadTemplate {
   GstPadDirection direction;
   GstPadPresence  presence;
   GstCaps        *caps;
+  gboolean       fixed;
 };
 
 struct _GstPadTemplateClass {
@@ -325,63 +336,66 @@ name (void)                                     \
 
 #define GST_PADTEMPLATE_GET(fact) (fact)()
 
-GType                  gst_pad_get_type                (void);
-GType                  gst_real_pad_get_type           (void);
-GType                  gst_ghost_pad_get_type          (void);
+GType                  gst_pad_get_type                        (void);
+GType                  gst_real_pad_get_type                   (void);
+GType                  gst_ghost_pad_get_type                  (void);
 
-GstPad*                        gst_pad_new                     (gchar *name, GstPadDirection direction);
-#define                        gst_pad_destroy(pad)            gst_object_destroy (GST_OBJECT (pad))
-GstPad*                        gst_pad_new_from_template       (GstPadTemplate *templ, gchar *name);
+GstPad*                        gst_pad_new                             (gchar *name, GstPadDirection direction);
+#define                        gst_pad_destroy(pad)                    gst_object_destroy (GST_OBJECT (pad))
+GstPad*                        gst_pad_new_from_template               (GstPadTemplate *templ, gchar *name);
 
-GstPadDirection                gst_pad_get_direction           (GstPad *pad);
+GstPadDirection                gst_pad_get_direction                   (GstPad *pad);
 
-void                   gst_pad_set_chain_function      (GstPad *pad, GstPadChainFunction chain);
-void                   gst_pad_set_get_function        (GstPad *pad, GstPadGetFunction get);
-void                   gst_pad_set_event_function      (GstPad *pad, GstPadEventFunction event);
+void                   gst_pad_set_chain_function              (GstPad *pad, GstPadChainFunction chain);
+void                   gst_pad_set_get_function                (GstPad *pad, GstPadGetFunction get);
+void                   gst_pad_set_event_function              (GstPad *pad, GstPadEventFunction event);
 
-void                   gst_pad_set_getregion_function  (GstPad *pad, GstPadGetRegionFunction getregion);
+void                   gst_pad_set_getregion_function          (GstPad *pad, GstPadGetRegionFunction getregion);
 
-void                   gst_pad_set_negotiate_function  (GstPad *pad, GstPadNegotiateFunction nego);
-void                   gst_pad_set_newcaps_function    (GstPad *pad, GstPadNewCapsFunction newcaps);
-void                   gst_pad_set_bufferpool_function (GstPad *pad, GstPadBufferPoolFunction bufpool);
+void                   gst_pad_set_connect_function            (GstPad *pad, GstPadConnectFunction connect);
+void                   gst_pad_set_getcaps_function            (GstPad *pad, GstPadGetCapsFunction getcaps);
+void                   gst_pad_set_bufferpool_function         (GstPad *pad, GstPadBufferPoolFunction bufpool);
 
-gboolean               gst_pad_set_caps                (GstPad *pad, GstCaps *caps);
-GstCaps*               gst_pad_get_caps                (GstPad *pad);
-GstCaps*               gst_pad_get_padtemplate_caps    (GstPad *pad);
-gboolean               gst_pad_check_compatibility     (GstPad *srcpad, GstPad *sinkpad);
+GstCaps*               gst_pad_get_caps                        (GstPad *pad);
+GstCaps*               gst_pad_get_padtemplate_caps            (GstPad *pad);
+gboolean               gst_pad_try_set_caps                    (GstPad *pad, GstCaps *caps);
+gboolean               gst_pad_check_compatibility             (GstPad *srcpad, GstPad *sinkpad);
 
-void                   gst_pad_set_element_private     (GstPad *pad, gpointer priv);
-gpointer               gst_pad_get_element_private     (GstPad *pad);
+void                   gst_pad_set_element_private             (GstPad *pad, gpointer priv);
+gpointer               gst_pad_get_element_private             (GstPad *pad);
 
-void                   gst_pad_set_name                (GstPad *pad, const gchar *name);
-const gchar*           gst_pad_get_name                (GstPad *pad);
+void                   gst_pad_set_name                        (GstPad *pad, const gchar *name);
+const gchar*           gst_pad_get_name                        (GstPad *pad);
 
-void                   gst_pad_set_parent              (GstPad *pad, GstObject *parent);
-GstElement*            gst_pad_get_parent              (GstPad *pad);
-GstElement*            gst_pad_get_real_parent         (GstPad *pad);
+void                   gst_pad_set_parent                      (GstPad *pad, GstObject *parent);
+GstElement*            gst_pad_get_parent                      (GstPad *pad);
+GstElement*            gst_pad_get_real_parent                 (GstPad *pad);
 
-void                   gst_pad_set_sched               (GstPad *pad, GstScheduler *sched);
-GstScheduler*          gst_pad_get_sched               (GstPad *pad);
+void                   gst_pad_set_sched                       (GstPad *pad, GstScheduler *sched);
+GstScheduler*          gst_pad_get_sched                       (GstPad *pad);
 
-void                   gst_pad_add_ghost_pad           (GstPad *pad, GstPad *ghostpad);
-void                   gst_pad_remove_ghost_pad        (GstPad *pad, GstPad *ghostpad);
-GList*                 gst_pad_get_ghost_pad_list      (GstPad *pad);
+void                   gst_pad_add_ghost_pad                   (GstPad *pad, GstPad *ghostpad);
+void                   gst_pad_remove_ghost_pad                (GstPad *pad, GstPad *ghostpad);
+GList*                 gst_pad_get_ghost_pad_list              (GstPad *pad);
 
-GstPadTemplate*                gst_pad_get_padtemplate         (GstPad *pad);
+GstPadTemplate*                gst_pad_get_padtemplate                 (GstPad *pad);
 
-GstPad*                        gst_pad_get_peer                (GstPad *pad);
+GstPad*                        gst_pad_get_peer                        (GstPad *pad);
 
-GstBufferPool*         gst_pad_get_bufferpool          (GstPad *pad);
+GstBufferPool*         gst_pad_get_bufferpool                  (GstPad *pad);
 
-gboolean                gst_pad_try_connect             (GstPad *srcpad, GstPad *sinkpad);
-void                    gst_pad_connect                        (GstPad *srcpad, GstPad *sinkpad);
-void                   gst_pad_disconnect              (GstPad *srcpad, GstPad *sinkpad);
+gboolean                gst_pad_connect                        (GstPad *srcpad, GstPad *sinkpad);
+gboolean                gst_pad_connect_filtered                       (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps);
+void                   gst_pad_disconnect                      (GstPad *srcpad, GstPad *sinkpad);
 
-gboolean               gst_pad_renegotiate             (GstPad *pad);
-GstPadNegotiateReturn  gst_pad_negotiate_proxy         (GstPad *srcpad, GstPad *destpad, GstCaps **caps);
+GstPadConnectReturn     gst_pad_proxy_connect                          (GstPad *pad, GstCaps *caps);
+gboolean               gst_pad_reconnect_filtered              (GstPad *pad, GstCaps *filtercaps);
+gboolean               gst_pad_try_reconnect_filtered          (GstPad *pad, GstCaps *filtercaps);
+GstCaps*               gst_pad_get_allowed_caps                (GstPad *pad);
+gboolean               gst_pad_recalc_allowed_caps             (GstPad *pad);
 
 #if 1
-void                   gst_pad_push                    (GstPad *pad, GstBuffer *buf);
+void                   gst_pad_push                            (GstPad *pad, GstBuffer *buf);
 #else
 #define gst_pad_push(pad,buf) G_STMT_START{ \
   if (((GstRealPad *)(pad))->peer->chainhandler) \
@@ -389,8 +403,9 @@ void                        gst_pad_push                    (GstPad *pad, GstBuffer *buf);
 }G_STMT_END
 #endif
 #if 1
-GstBuffer*             gst_pad_pull                    (GstPad *pad);
-GstBuffer*             gst_pad_pullregion              (GstPad *pad, GstRegionType type, guint64 offset, guint64 len);
+GstBuffer*             gst_pad_pull                            (GstPad *pad);
+GstBuffer*             gst_pad_pullregion                      (GstPad *pad, GstRegionType type, 
+                                                                guint64 offset, guint64 len);
 #else
 #define gst_pad_pull(pad) \
   ( (((GstRealPad *)(pad))->peer->gethandler) ? \
@@ -402,42 +417,42 @@ NULL )
 NULL )
 #endif
 
-gboolean               gst_pad_send_event              (GstPad *pad, GstEvent *event);
-void                   gst_pad_event_default           (GstPad *pad, GstEvent *event);
+gboolean               gst_pad_send_event                      (GstPad *pad, GstEvent *event);
+void                   gst_pad_event_default                   (GstPad *pad, GstEvent *event);
 
 
 
-GstBuffer*             gst_pad_peek                    (GstPad *pad);
-GstPad*                        gst_pad_select                  (GList *padlist);
-GstPad*                        gst_pad_selectv                 (GstPad *pad, ...);
+GstBuffer*             gst_pad_peek                            (GstPad *pad);
+GstPad*                        gst_pad_select                          (GList *padlist);
+GstPad*                        gst_pad_selectv                         (GstPad *pad, ...);
 
 #ifndef GST_DISABLE_LOADSAVE
-void                   gst_pad_load_and_connect        (xmlNodePtr self, GstObject *parent);
+void                   gst_pad_load_and_connect                (xmlNodePtr self, GstObject *parent);
 #endif
 
 
 /* ghostpads */
-GstPad*                        gst_ghost_pad_new               (gchar *name,GstPad *pad);
+GstPad*                        gst_ghost_pad_new                       (gchar *name,GstPad *pad);
 
 
 /* templates and factories */
-GType                  gst_padtemplate_get_type        (void);
+GType                  gst_padtemplate_get_type                (void);
 
-GstPadTemplate*                gst_padtemplate_new             (gchar *name_template,
-                                                        GstPadDirection direction, GstPadPresence presence,
-                                                        GstCaps *caps, ...);
+GstPadTemplate*                gst_padtemplate_new                     (gchar *name_template,
+                                                                GstPadDirection direction, GstPadPresence presence,
+                                                                GstCaps *caps, ...);
 
-GstCaps*               gst_padtemplate_get_caps        (GstPadTemplate *templ);
+GstCaps*               gst_padtemplate_get_caps                (GstPadTemplate *templ);
 GstCaps*               gst_padtemplate_get_caps_by_name        (GstPadTemplate *templ, const gchar *name);
 
 #ifndef GST_DISABLE_LOADSAVE
-xmlNodePtr             gst_padtemplate_save_thyself    (GstPadTemplate *templ, xmlNodePtr parent);
-GstPadTemplate*                gst_padtemplate_load_thyself    (xmlNodePtr parent);
+xmlNodePtr             gst_padtemplate_save_thyself            (GstPadTemplate *templ, xmlNodePtr parent);
+GstPadTemplate*                gst_padtemplate_load_thyself            (xmlNodePtr parent);
 #endif
 
-xmlNodePtr              gst_pad_ghost_save_thyself   (GstPad *pad,
-                                                     GstElement *bin,
-                                                     xmlNodePtr parent);
+xmlNodePtr              gst_pad_ghost_save_thyself             (GstPad *pad,
+                                                                GstElement *bin,
+                                                                xmlNodePtr parent);
 
 #ifdef __cplusplus
 }
index 4d4cb3b1700b0749bcee9fb403fdf75ba81f6ff3..0afc1066ea37d03e8ec4bd53ad60060116622faf 100644 (file)
@@ -1,6 +1,6 @@
 /* GStreamer
  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- *                    2000 Wim Taymans <wtay@chello.be>
+ *                    2000 Wim Taymans <wim.taymans@chello.be>
  *
  * gstprops.c: Properties subsystem for generic usage
  *
@@ -34,6 +34,8 @@ static GMemChunk *_gst_props_chunk;
 static GMutex *_gst_props_chunk_lock;
 
 static gboolean        gst_props_entry_check_compatibility     (GstPropsEntry *entry1, GstPropsEntry *entry2);
+static GList*          gst_props_list_copy                     (GList *propslist);
+
        
 void 
 _gst_props_initialize (void) 
@@ -52,33 +54,45 @@ _gst_props_initialize (void)
 static void
 gst_props_debug_entry (GstPropsEntry *entry)
 {
+  gchar *name = g_quark_to_string (entry->propid);
+
   switch (entry->propstype) {
     case GST_PROPS_INT_ID:
-      GST_DEBUG (GST_CAT_PROPERTIES, "%d\n", entry->data.int_data);
+      GST_DEBUG (GST_CAT_PROPERTIES, "%s: int %d\n", name, entry->data.int_data);
       break;
     case GST_PROPS_FLOAT_ID:
-      GST_DEBUG (GST_CAT_PROPERTIES, "%f\n", entry->data.float_data);
+      GST_DEBUG (GST_CAT_PROPERTIES, "%s: float %f\n", name, entry->data.float_data);
       break;
     case GST_PROPS_FOURCC_ID:
-      GST_DEBUG (GST_CAT_PROPERTIES, "%4.4s\n", (gchar*)&entry->data.fourcc_data);
+      GST_DEBUG (GST_CAT_PROPERTIES, "%s: fourcc %4.4s\n", name, (gchar*)&entry->data.fourcc_data);
       break;
     case GST_PROPS_BOOL_ID:
-      GST_DEBUG (GST_CAT_PROPERTIES, "%d\n", entry->data.bool_data);
+      GST_DEBUG (GST_CAT_PROPERTIES, "%s: bool %d\n", name, entry->data.bool_data);
       break;
     case GST_PROPS_STRING_ID:
-      GST_DEBUG (GST_CAT_PROPERTIES, "%s\n", entry->data.string_data.string);
+      GST_DEBUG (GST_CAT_PROPERTIES, "%s: string %s\n", name, entry->data.string_data.string);
       break;
     case GST_PROPS_INT_RANGE_ID:
-      GST_DEBUG (GST_CAT_PROPERTIES, "%d-%d\n", entry->data.int_range_data.min,
+      GST_DEBUG (GST_CAT_PROPERTIES, "%s: int range %d-%d\n", name, entry->data.int_range_data.min,
                      entry->data.int_range_data.max);
       break;
     case GST_PROPS_FLOAT_RANGE_ID:
-      GST_DEBUG (GST_CAT_PROPERTIES, "%f-%f\n", entry->data.float_range_data.min,
+      GST_DEBUG (GST_CAT_PROPERTIES, "%s: float range %f-%f\n", name, entry->data.float_range_data.min,
                      entry->data.float_range_data.max);
       break;
     case GST_PROPS_LIST_ID:
       GST_DEBUG (GST_CAT_PROPERTIES, "[list]\n");
+      {
+       GList *entries = entry->data.list_data.entries;
+
+       while (entries) {
+          gst_props_debug_entry ((GstPropsEntry *)entries->data);
+         entries = g_list_next (entries);
+       }
+      }
+      break;
     default:
+      g_warning ("unknown property type %d", entry->propstype);
       break;
   }
 }
@@ -98,9 +112,9 @@ props_find_func (gconstpointer a,
                 gconstpointer b) 
 {
   GstPropsEntry *entry2 = (GstPropsEntry *)a;
-  GQuark entry1 = (GQuark) GPOINTER_TO_INT (b);
+  GQuark quark = (GQuark) GPOINTER_TO_INT (b);
 
-  return (entry1 - entry2->propid);
+  return (quark - entry2->propid);
 }
 
 /* This is implemented as a huge macro because we cannot pass
@@ -139,6 +153,72 @@ G_STMT_START {                                                                     \
   }                                                                            \
 } G_STMT_END
 
+static GstPropsEntry*
+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);
+
+  return entry;
+}
+
+static void
+gst_props_entry_destroy (GstPropsEntry *entry)
+{
+  switch (entry->propstype) {
+    case GST_PROPS_STRING_ID:          
+      g_free (entry->data.string_data.string);
+      break;                           
+    case GST_PROPS_LIST_ID:            
+    {
+      GList *entries = entry->data.list_data.entries;
+
+      while (entries) {
+       gst_props_entry_destroy ((GstPropsEntry *)entries->data);
+       entries = g_list_next (entries);
+      }
+      g_list_free (entry->data.list_data.entries);
+      break;
+    }
+    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);
+}
+
+static GstProps*
+gst_props_alloc (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->properties = NULL;
+  props->refcount = 1;
+  props->fixed = TRUE;
+
+  return props;
+}
+
+static void
+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;
+  }
+  props->properties = g_list_insert_sorted (props->properties, entry, props_compare_func);
+}
+
 /**
  * gst_props_new:
  * @firstname: the first property name
@@ -163,19 +243,19 @@ gst_props_new (const gchar *firstname, ...)
   return props;
 } 
 
-/**
- * gst_props_add_to_list:
- * @entries: the existing list of entries
- * @entry: the new entry to add to the list
- *
- * Add a property to a list of properties.
- *
- * Returns: a pointer to a list with the new entry added.
- */
-static GList *
-gst_props_add_to_list (GList * entries, GstPropsEntry *entry)
+
+void
+gst_props_debug (GstProps *props)
 {
-  return g_list_prepend (entries, entry);
+  GList *propslist = props->properties;
+
+  while (propslist) { 
+    GstPropsEntry *entry = (GstPropsEntry *)propslist->data;
+
+    gst_props_debug_entry (entry);
+    
+    propslist = g_list_next (propslist);
+  }
 }
 
 /**
@@ -283,7 +363,7 @@ gst_props_add_to_int_list (GList * entries, GstPropsEntry * newentry)
     i = g_list_next (i);
   }
 
-  return gst_props_add_to_list (entries, newentry);
+  return g_list_prepend (entries, newentry);
 }
 
 /**
@@ -318,23 +398,15 @@ gst_props_newv (const gchar *firstname, va_list var_args)
   if (firstname == NULL)
     return NULL;
 
-  g_mutex_lock (_gst_props_chunk_lock);
-  props = g_mem_chunk_alloc (_gst_props_chunk);
-  g_mutex_unlock (_gst_props_chunk_lock);
-
-  props->properties = NULL;
-  props->refcount = 1;
+  props = gst_props_alloc ();
 
   prop_name = firstname;
 
   /* properties */
   while (prop_name) {
     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_props_alloc_entry ();
     entry->propid = g_quark_from_string (prop_name);
     GST_PROPS_ENTRY_FILL (entry, var_args);
 
@@ -371,6 +443,10 @@ gst_props_newv (const gchar *firstname, va_list var_args)
          g_mem_chunk_free (_gst_props_entries_chunk, subentry);
          g_mutex_unlock (_gst_props_entries_chunk_lock);
        }
+       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);
@@ -399,13 +475,13 @@ gst_props_newv (const gchar *firstname, va_list var_args)
            break;
          default:
            list_entry->data.list_data.entries =
-                   gst_props_add_to_list (list_entry->data.list_data.entries, entry);
+                   g_list_prepend (list_entry->data.list_data.entries, entry);
            break;
        }
       }
     }
     else {
-      props->properties = g_list_insert_sorted (props->properties, entry, props_compare_func);
+      gst_props_add_entry (props, entry);
     }
     if (!inlist)
       prop_name = va_arg (var_args, gchar*);
@@ -463,7 +539,8 @@ gst_props_set (GstProps *props, const gchar *name, ...)
 void
 gst_props_unref (GstProps *props)
 {
-  g_return_if_fail (props != NULL);
+  if (props == NULL)
+    return;
   
   props->refcount--;
 
@@ -485,6 +562,7 @@ gst_props_ref (GstProps *props)
   props->refcount++;
 }
 
+
 /**
  * gst_props_destroy:
  * @props: the props to destroy
@@ -497,25 +575,13 @@ gst_props_destroy (GstProps *props)
 {
   GList *entries;
 
-  g_return_if_fail (props != NULL);
+  if (props == NULL)
+    return;
   
   entries = props->properties;
 
   while (entries) {
-    GstPropsEntry *entry = (GstPropsEntry *)entries->data;
-
-    switch (entry->propstype) {
-      case GST_PROPS_STRING_ID:                
-        g_free (entry->data.string_data.string);
-        break;                         
-      /* FIXME also free the lists */
-      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);
-
+    gst_props_entry_destroy ((GstPropsEntry *)entries->data);
     entries = g_list_next (entries);
   }
   g_list_free (props->properties);
@@ -525,6 +591,43 @@ gst_props_destroy (GstProps *props)
   g_mutex_unlock (_gst_props_chunk_lock);
 }
 
+/* 
+ * copy entries 
+ */
+static GstPropsEntry*
+gst_props_entry_copy (GstPropsEntry *entry)
+{
+  GstPropsEntry *newentry;
+
+  newentry = gst_props_alloc_entry ();
+  memcpy (newentry, entry, sizeof (GstPropsEntry));
+  if (entry->propstype == GST_PROPS_LIST_ID) {
+    newentry->data.list_data.entries = gst_props_list_copy (entry->data.list_data.entries);
+  }
+  else if (entry->propstype == GST_PROPS_STRING_ID) {
+    newentry->data.string_data.string = g_strdup (entry->data.string_data.string);
+  }
+
+  return newentry;
+}
+
+static GList*
+gst_props_list_copy (GList *propslist)
+{
+  GList *new = NULL;
+
+  while (propslist) {
+    GstPropsEntry *entry = (GstPropsEntry *)propslist->data;
+
+    new = g_list_prepend (new, gst_props_entry_copy (entry));
+    
+    propslist = g_list_next (propslist);
+  }
+  new = g_list_reverse (new);
+
+  return new;
+}
+
 /**
  * gst_props_copy:
  * @props: the props to copy
@@ -540,32 +643,12 @@ gst_props_copy (GstProps *props)
   GstProps *new;
   GList *properties;
 
-  g_return_val_if_fail (props != NULL, NULL);
-
-  g_mutex_lock (_gst_props_chunk_lock);
-  new = g_mem_chunk_alloc (_gst_props_chunk);
-  g_mutex_unlock (_gst_props_chunk_lock);
-
-  new->properties = NULL;
-
-  properties = props->properties;
-
-  while (properties) {
-    GstPropsEntry *entry = (GstPropsEntry *)properties->data;
-    GstPropsEntry *newentry;
-
-    g_mutex_lock (_gst_props_entries_chunk_lock);
-    newentry = g_mem_chunk_alloc (_gst_props_entries_chunk);
-    g_mutex_unlock (_gst_props_entries_chunk_lock);
-
-    /* FIXME copy lists too */
-    memcpy (newentry, entry, sizeof (GstPropsEntry));
+  if (props == NULL)
+    return NULL;
 
-    new->properties = g_list_prepend (new->properties, newentry);
-    
-    properties = g_list_next (properties);
-  }
-  new->properties = g_list_reverse (new->properties);
+  new = gst_props_alloc ();
+  new->properties = gst_props_list_copy (props->properties);
+  new->fixed = props->fixed;
 
   return new;
 }
@@ -614,6 +697,12 @@ gst_props_get_entry_func (GstProps *props, const gchar *name)
   return NULL;
 }
 
+gboolean
+gst_props_has_property (GstProps *props, const gchar *name)
+{
+  return (gst_props_get_entry_func (props, name) != NULL);
+}
+
 /**
  * gst_props_get_int:
  * @props: the props to get the int value from
@@ -633,6 +722,9 @@ gst_props_get_int (GstProps *props, const gchar *name)
   if (thisentry) {
     return thisentry->data.int_data;
   }
+  else {
+    g_warning ("props: property %s not found", name);
+  }
   return 0;
 }
 
@@ -655,6 +747,9 @@ gst_props_get_float (GstProps *props, const gchar *name)
   if (thisentry) {
     return thisentry->data.float_data;
   }
+  else {
+    g_warning ("props: property %s not found", name);
+  }
   return 0.0F;
 }
 
@@ -677,6 +772,9 @@ gst_props_get_fourcc_int (GstProps *props, const gchar *name)
   if (thisentry) {
     return thisentry->data.fourcc_data;
   }
+  else {
+    g_warning ("props: property %s not found", name);
+  }
   return 0;
 }
 
@@ -699,6 +797,9 @@ gst_props_get_boolean (GstProps *props, const gchar *name)
   if (thisentry) {
     return thisentry->data.bool_data;
   }
+  else {
+    g_warning ("props: property %s not found", name);
+  }
   return 0;
 }
 
@@ -721,6 +822,9 @@ gst_props_get_string (GstProps *props, const gchar *name)
   if (thisentry) {
     return thisentry->data.string_data.string;
   }
+  else {
+    g_warning ("props: property %s not found", name);
+  }
   return NULL;
 }
 
@@ -747,7 +851,7 @@ gst_props_merge (GstProps *props, GstProps *tomerge)
   while (merge_props) {
     GstPropsEntry *entry = (GstPropsEntry *)merge_props->data;
 
-    props->properties = g_list_insert_sorted (props->properties, entry, props_compare_func);
+    gst_props_add_entry (props, entry);
          
     merge_props = g_list_next (merge_props);
   }
@@ -779,8 +883,11 @@ gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry
 {
   GST_DEBUG (GST_CAT_PROPERTIES,"compare: %s %s\n", g_quark_to_string (entry1->propid),
                             g_quark_to_string (entry2->propid));
-  gst_props_debug_entry (entry1);
-  gst_props_debug_entry (entry2);
+
+  if (entry2->propstype == GST_PROPS_LIST_ID && entry1->propstype != GST_PROPS_LIST_ID) {
+    return gst_props_entry_check_list_compatibility (entry1, entry2);
+  }
+
   switch (entry1->propstype) {
     case GST_PROPS_LIST_ID:
     {
@@ -803,10 +910,6 @@ gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry
         case GST_PROPS_INT_RANGE_ID:
          return (entry2->data.int_range_data.min <= entry1->data.int_range_data.min &&
                  entry2->data.int_range_data.max >= entry1->data.int_range_data.max);
-        case GST_PROPS_LIST_ID:
-         return gst_props_entry_check_list_compatibility (entry1, entry2);
-        default:
-          return FALSE;
       }
       break;
     case GST_PROPS_FLOAT_RANGE_ID:
@@ -815,22 +918,15 @@ gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry
         case GST_PROPS_FLOAT_RANGE_ID:
          return (entry2->data.float_range_data.min <= entry1->data.float_range_data.min &&
                  entry2->data.float_range_data.max >= entry1->data.float_range_data.max);
-        case GST_PROPS_LIST_ID:
-         return gst_props_entry_check_list_compatibility (entry1, entry2);
-        default:
-          return FALSE;
       }
       break;
     case GST_PROPS_FOURCC_ID:
       switch (entry2->propstype) {
        /* b   <--->   a */
         case GST_PROPS_FOURCC_ID:
+          GST_DEBUG(GST_CAT_PROPERTIES,"\"%4.4s\" <--> \"%4.4s\" ?\n",
+                         &entry2->data.fourcc_data, &entry1->data.fourcc_data);
          return (entry2->data.fourcc_data == entry1->data.fourcc_data);
-       /* b   <--->   a,b,c */
-        case GST_PROPS_LIST_ID:
-         return gst_props_entry_check_list_compatibility (entry1, entry2);
-        default:
-          return FALSE;
       }
       break;
     case GST_PROPS_INT_ID:
@@ -845,11 +941,6 @@ gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry
         case GST_PROPS_INT_ID:
           GST_DEBUG(GST_CAT_PROPERTIES,"%d == %d ?\n",entry1->data.int_data,entry2->data.int_data);
          return (entry2->data.int_data == entry1->data.int_data);
-       /* b   <--->   a,b,c */
-        case GST_PROPS_LIST_ID:
-         return gst_props_entry_check_list_compatibility (entry1, entry2);
-        default:
-          return FALSE;
       }
       break;
     case GST_PROPS_FLOAT_ID:
@@ -861,11 +952,6 @@ gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry
        /* b   <--->   a */
         case GST_PROPS_FLOAT_ID:
          return (entry2->data.float_data == entry1->data.float_data);
-       /* b   <--->   a,b,c */
-        case GST_PROPS_LIST_ID:
-         return gst_props_entry_check_list_compatibility (entry1, entry2);
-        default:
-          return FALSE;
       }
       break;
     case GST_PROPS_BOOL_ID:
@@ -873,23 +959,13 @@ gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry
        /* t   <--->   t */
         case GST_PROPS_BOOL_ID:
           return (entry2->data.bool_data == entry1->data.bool_data);
-        case GST_PROPS_LIST_ID:
-         return gst_props_entry_check_list_compatibility (entry1, entry2);
-        default:
-          return FALSE;
       }
     case GST_PROPS_STRING_ID:
       switch (entry2->propstype) {
        /* t   <--->   t */
         case GST_PROPS_STRING_ID:
           return (!strcmp (entry2->data.string_data.string, entry1->data.string_data.string));
-        case GST_PROPS_LIST_ID:
-         return gst_props_entry_check_list_compatibility (entry1, entry2);
-        default:
-          return FALSE;
       }
-    default:
-      break;
   }
 
   return FALSE;
@@ -927,14 +1003,12 @@ gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops)
     entry2 = (GstPropsEntry *)sinklist->data;
 
     while (entry1->propid < entry2->propid) {
-      GST_DEBUG (GST_CAT_PROPERTIES,"source is more specific in \"%s\"\n", g_quark_to_string (entry1->propid));
       more++;
       sourcelist = g_list_next (sourcelist);
       if (sourcelist) entry1 = (GstPropsEntry *)sourcelist->data;
       else goto end;
     }
     while (entry1->propid > entry2->propid) {
-      GST_DEBUG (GST_CAT_PROPERTIES,"source has missing property \"%s\"\n", g_quark_to_string (entry2->propid));
       missing++;
       sinklist = g_list_next (sinklist);
       if (sinklist) entry2 = (GstPropsEntry *)sinklist->data;
@@ -945,8 +1019,6 @@ gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops)
        compatible = FALSE; 
        GST_DEBUG (GST_CAT_PROPERTIES, "%s are not compatible: \n",
                   g_quark_to_string (entry1->propid));
-       gst_props_debug_entry (entry1);
-       gst_props_debug_entry (entry2);
     }
 
     sourcelist = g_list_next (sourcelist);
@@ -956,7 +1028,6 @@ gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops)
     GstPropsEntry *entry2;
     entry2 = (GstPropsEntry *)sinklist->data;
     missing++;
-    GST_DEBUG (GST_CAT_PROPERTIES,"source has missing property \"%s\"\n", g_quark_to_string (entry2->propid));
   }
 end:
 
@@ -966,6 +1037,339 @@ end:
   return compatible;
 }
 
+static GstPropsEntry*
+gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2)
+{
+  GstPropsEntry *result = NULL;
+
+  /* try to move the ranges and lists first */
+  switch (entry2->propstype) {
+    case GST_PROPS_INT_RANGE_ID:
+    case GST_PROPS_FLOAT_RANGE_ID:
+    case GST_PROPS_LIST_ID:
+    {
+      GstPropsEntry *temp;
+
+      temp = entry1;
+      entry1 = entry2;
+      entry2 = temp;
+    }
+  }
+
+  switch (entry1->propstype) {
+    case GST_PROPS_LIST_ID:
+    {
+      GList *entrylist = entry1->data.list_data.entries;
+      GList *intersection = NULL;
+
+      while (entrylist) {
+       GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
+       GstPropsEntry *intersectentry;
+
+       intersectentry = gst_props_entry_intersect (entry2, entry);
+
+       if (intersectentry) {
+         if (intersectentry->propstype == GST_PROPS_LIST_ID) {
+           intersection = g_list_concat (intersection, intersectentry->data.list_data.entries);
+           /* set the list to NULL because the entries are concatenated to the above
+            * list and we don't want to free them */
+           intersectentry->data.list_data.entries = NULL;
+           gst_props_entry_destroy (intersectentry);
+         }
+         else {
+           intersection = g_list_prepend (intersection, intersectentry);
+         }
+       }
+       entrylist = g_list_next (entrylist);
+      }
+      if (intersection) {
+       /* check if the list only contains 1 element, if so, we can just copy it */
+       if (g_list_next (intersection) == NULL) {
+         result = (GstPropsEntry *) (intersection->data); 
+         g_list_free (intersection);
+       }
+       /* else we need to create a new entry to hold the list */
+       else {
+         result = gst_props_alloc_entry ();
+         result->propid = entry1->propid;
+         result->propstype = GST_PROPS_LIST_ID;
+         result->data.list_data.entries = g_list_reverse (intersection);
+       }
+      }
+      return result;
+    }
+    case GST_PROPS_INT_RANGE_ID:
+      switch (entry2->propstype) {
+       /* a - b   <--->   a - c */
+        case GST_PROPS_INT_RANGE_ID:
+        {
+         gint lower = MAX (entry1->data.int_range_data.min, entry2->data.int_range_data.min);
+         gint upper = MIN (entry1->data.int_range_data.max, entry2->data.int_range_data.max);
+
+         if (lower <= upper) {
+            result = gst_props_alloc_entry ();
+           result->propid = entry1->propid;
+
+           if (lower == upper) {
+             result->propstype = GST_PROPS_INT_ID;
+             result->data.int_data = lower;
+           }
+           else {
+             result->propstype = GST_PROPS_INT_RANGE_ID;
+             result->data.int_range_data.min = lower;
+             result->data.int_range_data.max = upper;
+           }
+         }
+         break;
+       }
+        case GST_PROPS_INT_ID:
+         if (entry1->data.int_range_data.min <= entry2->data.int_data && 
+             entry1->data.int_range_data.max >= entry2->data.int_data) {
+            result = gst_props_entry_copy (entry2);
+         }
+      }
+      break;
+    case GST_PROPS_FLOAT_RANGE_ID:
+      switch (entry2->propstype) {
+       /* a - b   <--->   a - c */
+        case GST_PROPS_FLOAT_RANGE_ID:
+        {
+         gfloat lower = MAX (entry1->data.float_range_data.min, entry2->data.float_range_data.min);
+         gfloat upper = MIN (entry1->data.float_range_data.max, entry2->data.float_range_data.max);
+
+         if (lower <= upper) {
+            result = gst_props_alloc_entry ();
+           result->propid = entry1->propid;
+
+           if (lower == upper) {
+             result->propstype = GST_PROPS_FLOAT_ID;
+             result->data.float_data = lower;
+           }
+           else {
+             result->propstype = GST_PROPS_FLOAT_RANGE_ID;
+             result->data.float_range_data.min = lower;
+             result->data.float_range_data.max = upper;
+           }
+         }
+         break;
+       }
+        case GST_PROPS_FLOAT_ID:
+         if (entry1->data.float_range_data.min <= entry2->data.float_data && 
+             entry1->data.float_range_data.max >= entry2->data.float_data) {
+            result = gst_props_entry_copy (entry2);
+         }
+      }
+      break;
+    case GST_PROPS_FOURCC_ID:
+      switch (entry2->propstype) {
+       /* b   <--->   a */
+        case GST_PROPS_FOURCC_ID:
+          if (entry1->data.fourcc_data == entry2->data.fourcc_data)
+           result = gst_props_entry_copy (entry1);
+      }
+      break;
+    case GST_PROPS_INT_ID:
+      switch (entry2->propstype) {
+       /* b   <--->   a */
+        case GST_PROPS_INT_ID:
+          if (entry1->data.int_data == entry2->data.int_data)
+           result = gst_props_entry_copy (entry1);
+      }
+      break;
+    case GST_PROPS_FLOAT_ID:
+      switch (entry2->propstype) {
+       /* b   <--->   a */
+        case GST_PROPS_FLOAT_ID:
+          if (entry1->data.float_data == entry2->data.float_data)
+           result = gst_props_entry_copy (entry1);
+      }
+      break;
+    case GST_PROPS_BOOL_ID:
+      switch (entry2->propstype) {
+       /* t   <--->   t */
+        case GST_PROPS_BOOL_ID:
+          if (entry1->data.bool_data == entry2->data.bool_data)
+           result = gst_props_entry_copy (entry1);
+      }
+    case GST_PROPS_STRING_ID:
+      switch (entry2->propstype) {
+       /* t   <--->   t */
+        case GST_PROPS_STRING_ID:
+          if (!strcmp (entry1->data.string_data.string, entry2->data.string_data.string))
+           result = gst_props_entry_copy (entry1);
+      }
+  }
+
+  return result;
+}
+
+/**
+ * gst_props_intersect:
+ * @props1: a property
+ * @props2: another property
+ *
+ * Calculates the intersection bewteen two GstProps.
+ *
+ * Returns: a GstProps with the intersection or NULL if the 
+ * intersection is empty.
+ */
+GstProps*
+gst_props_intersect (GstProps *props1, GstProps *props2)
+{
+  GList *props1list;
+  GList *props2list;
+  GstProps *intersection;
+  GList *leftovers;
+  GstPropsEntry *iprops = NULL;
+
+  intersection = gst_props_alloc ();
+  intersection->fixed = TRUE;
+
+  g_return_val_if_fail (props1 != NULL, NULL);
+  g_return_val_if_fail (props2 != NULL, NULL);
+       
+  props1list = props1->properties;
+  props2list = props2->properties;
+
+  while (props1list && props2list) {
+    GstPropsEntry *entry1;
+    GstPropsEntry *entry2;
+
+    entry1 = (GstPropsEntry *)props1list->data;
+    entry2 = (GstPropsEntry *)props2list->data;
+
+    while (entry1->propid < entry2->propid) {
+      GstPropsEntry *toadd;
+
+      GST_DEBUG (GST_CAT_PROPERTIES,"source is more specific in \"%s\"\n", 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);
+
+      props1list = g_list_next (props1list);
+      if (props1list) 
+       entry1 = (GstPropsEntry *)props1list->data;
+      else 
+       goto end;
+    }
+    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);
+
+      props2list = g_list_next (props2list);
+      if (props2list)
+       entry2 = (GstPropsEntry *)props2list->data;
+      else 
+       goto end;
+    }
+    /* 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 {
+      gst_props_unref (intersection);
+      return NULL;
+    }
+
+    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)
+    leftovers = props2list;
+  else 
+    goto finish;
+
+  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));
+
+    leftovers = g_list_next (leftovers);
+  }
+
+finish:
+  intersection->properties = g_list_reverse (intersection->properties);
+
+  return intersection;
+}
+
+GList*
+gst_props_normalize (GstProps *props)
+{
+  GList *entries;
+  GList *result = NULL;
+
+  if (!props) 
+    return NULL;
+
+  entries = props->properties;
+
+  while (entries) {
+    GstPropsEntry *entry = (GstPropsEntry *) entries->data;
+
+    if (entry->propstype == GST_PROPS_LIST_ID) {
+      GList *list_entries = entry->data.list_data.entries;
+
+      while (list_entries) {
+        GstPropsEntry *list_entry = (GstPropsEntry *) list_entries->data;
+        GstPropsEntry *new_entry;
+       GstProps *newprops;
+       GList *lentry;
+
+       newprops = gst_props_alloc ();
+       newprops->properties = gst_props_list_copy (props->properties);
+        lentry = g_list_find_custom (newprops->properties, GINT_TO_POINTER (list_entry->propid), props_find_func);
+       if (lentry) {
+          GList *new_list = NULL;
+
+          new_entry = (GstPropsEntry *) lentry->data;
+         memcpy (new_entry, list_entry, sizeof (GstPropsEntry));
+
+         new_list = gst_props_normalize (newprops);
+          result = g_list_concat (new_list, result);
+       }
+       else {
+          result = g_list_append (result, newprops);
+       }
+       
+        list_entries = g_list_next (list_entries);     
+      }
+      /* we break out of the loop because the other lists are
+       * unrolled in the recursive call */
+      break;
+    }
+    entries = g_list_next (entries);
+  }
+  if (!result) {
+    result = g_list_prepend (result, props);
+  }
+  else {
+    result = g_list_reverse (result);
+    gst_props_unref (props);
+  }
+  return result;
+}
+
 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
 static xmlNodePtr
 gst_props_save_thyself_func (GstPropsEntry *entry, xmlNodePtr parent)
@@ -1029,6 +1433,7 @@ gst_props_save_thyself_func (GstPropsEntry *entry, xmlNodePtr parent)
       xmlNewProp (subtree, "value", entry->data.string_data.string);
       break;
     default:
+      g_warning ("trying to save unknown property type %d", entry->propstype);
       break;
   }
 
@@ -1062,6 +1467,7 @@ gst_props_save_thyself (GstProps *props, xmlNodePtr parent)
         subtree = xmlNewChild (parent, NULL, "list", NULL);
         xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
         g_list_foreach (entry->data.list_data.entries, (GFunc) gst_props_save_thyself_func, subtree);
+       break;
       default:
        gst_props_save_thyself_func (entry, parent);
     }
@@ -1078,9 +1484,7 @@ gst_props_load_thyself_func (xmlNodePtr field)
   GstPropsEntry *entry;
   gchar *prop;
 
-  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_props_alloc_entry ();
 
   if (!strcmp(field->name, "int")) {
     entry->propstype = GST_PROPS_INT_ID;
@@ -1175,27 +1579,19 @@ gst_props_load_thyself (xmlNodePtr parent)
   xmlNodePtr field = parent->xmlChildrenNode;
   gchar *prop;
 
-  g_mutex_lock (_gst_props_chunk_lock);
-  props = g_mem_chunk_alloc (_gst_props_chunk);
-  g_mutex_unlock (_gst_props_chunk_lock);
-
-  props->properties = NULL;
-  props->refcount = 1;
+  props = gst_props_alloc ();
 
   while (field) {
     if (!strcmp (field->name, "list")) {
       GstPropsEntry *entry;
       xmlNodePtr subfield = field->xmlChildrenNode;
 
-      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->propstype = GST_PROPS_LIST_ID;
-      entry->data.list_data.entries = NULL;
+      entry = gst_props_alloc_entry ();
       prop = xmlGetProp (field, "name");
       entry->propid = g_quark_from_string (prop);
       g_free (prop);
+      entry->propstype = GST_PROPS_LIST_ID;
+      entry->data.list_data.entries = NULL;
 
       while (subfield) {
         GstPropsEntry *subentry = gst_props_load_thyself_func (subfield);
@@ -1206,7 +1602,7 @@ gst_props_load_thyself (xmlNodePtr parent)
         subfield = subfield->next;
       }
       entry->data.list_data.entries = g_list_reverse (entry->data.list_data.entries);
-      props->properties = g_list_insert_sorted (props->properties, entry, props_compare_func);
+      gst_props_add_entry (props, entry);
     }
     else {
       GstPropsEntry *entry;
@@ -1214,7 +1610,7 @@ gst_props_load_thyself (xmlNodePtr parent)
       entry = gst_props_load_thyself_func (field);
 
       if (entry) 
-       props->properties = g_list_insert_sorted (props->properties, entry, props_compare_func);
+        gst_props_add_entry (props, entry);
     }
     field = field->next;
   }
index 9fc6dce2e3dd916cac2a417881f4b815da0cc174..ab63efad31a2fc9f1ee3e5b26e87011ace732c65 100644 (file)
@@ -32,14 +32,18 @@ typedef struct _GstProps GstProps;
 
 typedef enum {
    GST_PROPS_END_ID = 0,
-   GST_PROPS_LIST_ID,
    GST_PROPS_INT_ID,
-   GST_PROPS_INT_RANGE_ID,
    GST_PROPS_FLOAT_ID,
-   GST_PROPS_FLOAT_RANGE_ID,
    GST_PROPS_FOURCC_ID,
    GST_PROPS_BOOL_ID,
    GST_PROPS_STRING_ID,
+
+   GST_PROPS_VAR_ID,   /* after this marker start the variable properties */
+
+   GST_PROPS_LIST_ID,
+   GST_PROPS_FLOAT_RANGE_ID,
+   GST_PROPS_INT_RANGE_ID,
+
    GST_PROPS_LAST_ID = GST_PROPS_END_ID + 16,
 } GstPropsId;
 
@@ -55,10 +59,15 @@ typedef enum {
 #define GST_PROPS_BOOLEAN(a)           GST_PROPS_BOOL_ID,(a)
 #define GST_PROPS_STRING(a)            GST_PROPS_STRING_ID,(a)
 
+#define GST_PROPS_INT_POSITIVE         GST_PROPS_INT_RANGE(0,G_MAXINT)
+#define GST_PROPS_INT_NEGATIVE         GST_PROPS_INT_RANGE(G_MININT,0)
+#define GST_PROPS_INT_ANY              GST_PROPS_INT_RANGE(G_MININT,G_MAXINT)
+
 
 struct _GstProps {
   gint refcount;
   GMutex *lock;
+  gboolean fixed;
 
   GList *properties;           /* real properties for this property */
 };
@@ -73,15 +82,21 @@ void            gst_props_unref                 (GstProps *props);
 void            gst_props_ref                   (GstProps *props);
 void            gst_props_destroy               (GstProps *props);
 
+void            gst_props_debug                (GstProps *props);
+
 GstProps*       gst_props_copy                  (GstProps *props);
 GstProps*       gst_props_copy_on_write         (GstProps *props);
 
 GstProps*      gst_props_merge                 (GstProps *props, GstProps *tomerge);
 
 gboolean       gst_props_check_compatibility   (GstProps *fromprops, GstProps *toprops);
+GstProps*      gst_props_intersect             (GstProps *props1, GstProps *props2);
+GList*                 gst_props_normalize             (GstProps *props);
 
 GstProps*      gst_props_set                   (GstProps *props, const gchar *name, ...);
 
+gboolean       gst_props_has_property          (GstProps *props, const gchar *name);
+
 gint           gst_props_get_int               (GstProps *props, const gchar *name);
 gfloat                 gst_props_get_float             (GstProps *props, const gchar *name);
 gulong         gst_props_get_fourcc_int        (GstProps *props, const gchar *name);
index 8a1f0e3ac71e9f84a93aefc9db83e39e5f49074c..b7c45120fb7eedefe4966bdf965b9350e72a1ee4 100644 (file)
@@ -26,6 +26,8 @@
 
 #include <gst/gstprops.h>
 
+#define GST_PROPS_ENTRY_IS_VARIABLE(a) (((GstPropsEntry*)(a))->propstype > GST_PROPS_VAR_ID)
+
 typedef struct _GstPropsEntry GstPropsEntry;
 
 struct _GstPropsEntry {
index bf67c983889439cdf877c978d0770a430ac86b3b..61ec8f1cbe38a928e4a96730c9552ab80027b2e6 100644 (file)
@@ -78,8 +78,6 @@ static void                   gst_queue_set_property          (GObject *object, guint prop_id,
 static void                    gst_queue_get_property          (GObject *object, guint prop_id, 
                                                                 GValue *value, GParamSpec *pspec);
 
-static GstPadNegotiateReturn   gst_queue_handle_negotiate_src  (GstPad *pad, GstCaps **caps, gpointer *data);
-static GstPadNegotiateReturn   gst_queue_handle_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data);
 static void                    gst_queue_chain                 (GstPad *pad, GstBuffer *buf);
 static GstBuffer *             gst_queue_get                   (GstPad *pad);
 static GstBufferPool*          gst_queue_get_bufferpool        (GstPad *pad);
@@ -163,6 +161,34 @@ gst_queue_class_init (GstQueueClass *klass)
   gstelement_class->change_state = GST_DEBUG_FUNCPTR(gst_queue_change_state);
 }
 
+static GstPadConnectReturn
+gst_queue_connect (GstPad *pad, GstCaps *caps)
+{
+  GstQueue *queue = GST_QUEUE (gst_pad_get_parent (pad));
+  GstPad *otherpad;
+
+  if (pad == queue->srcpad) 
+    otherpad = queue->sinkpad;
+  else
+    otherpad = queue->srcpad;
+
+  return gst_pad_proxy_connect (otherpad, caps);
+}
+
+static GstCaps*
+gst_queue_getcaps (GstPad *pad, GstCaps *caps)
+{
+  GstQueue *queue = GST_QUEUE (gst_pad_get_parent (pad));
+  GstPad *otherpad;
+
+  if (pad == queue->srcpad) 
+    otherpad = queue->sinkpad;
+  else
+    otherpad = queue->srcpad;
+
+  return gst_pad_get_allowed_caps (otherpad);
+}
+
 static void
 gst_queue_init (GstQueue *queue)
 {
@@ -171,15 +197,17 @@ gst_queue_init (GstQueue *queue)
   GST_FLAG_SET (queue, GST_ELEMENT_EVENT_AWARE);
 
   queue->sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
-  gst_pad_set_chain_function (queue->sinkpad, GST_DEBUG_FUNCPTR(gst_queue_chain));
+  gst_pad_set_chain_function (queue->sinkpad, GST_DEBUG_FUNCPTR (gst_queue_chain));
   gst_element_add_pad (GST_ELEMENT (queue), queue->sinkpad);
-  gst_pad_set_negotiate_function (queue->sinkpad, GST_DEBUG_FUNCPTR(gst_queue_handle_negotiate_sink));
-  gst_pad_set_bufferpool_function (queue->sinkpad, GST_DEBUG_FUNCPTR(gst_queue_get_bufferpool));
+  gst_pad_set_bufferpool_function (queue->sinkpad, GST_DEBUG_FUNCPTR (gst_queue_get_bufferpool));
+  gst_pad_set_connect_function (queue->sinkpad, GST_DEBUG_FUNCPTR (gst_queue_connect));
+  gst_pad_set_getcaps_function (queue->sinkpad, GST_DEBUG_FUNCPTR (gst_queue_getcaps));
 
   queue->srcpad = gst_pad_new ("src", GST_PAD_SRC);
-  gst_pad_set_get_function (queue->srcpad, GST_DEBUG_FUNCPTR(gst_queue_get));
+  gst_pad_set_get_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_get));
   gst_element_add_pad (GST_ELEMENT (queue), queue->srcpad);
-  gst_pad_set_negotiate_function (queue->srcpad, GST_DEBUG_FUNCPTR(gst_queue_handle_negotiate_src));
+  gst_pad_set_connect_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_connect));
+  gst_pad_set_getcaps_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_getcaps));
 
   queue->leaky = GST_QUEUE_NO_LEAK;
   queue->queue = NULL;
@@ -221,26 +249,6 @@ gst_queue_get_bufferpool (GstPad *pad)
   return gst_pad_get_bufferpool (queue->srcpad);
 }
 
-static GstPadNegotiateReturn
-gst_queue_handle_negotiate_src (GstPad *pad, GstCaps **caps, gpointer *data)
-{
-  GstQueue *queue;
-
-  queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
-
-  return gst_pad_negotiate_proxy (pad, queue->sinkpad, caps);
-}
-
-static GstPadNegotiateReturn
-gst_queue_handle_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data)
-{
-  GstQueue *queue;
-
-  queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
-
-  return gst_pad_negotiate_proxy (pad, queue->srcpad, caps);
-}
-
 static void
 gst_queue_cleanup_buffers (gpointer data, const gpointer user_data)
 {
@@ -535,7 +543,7 @@ gst_queue_change_state (GstElement *element)
     gst_queue_locked_flush (queue);
   }
   else if (new_state == GST_STATE_PLAYING) {
-    if (!GST_PAD_CONNECTED (queue->sinkpad)) {
+    if (!GST_PAD_IS_CONNECTED (queue->sinkpad)) {
       /* FIXME can this be? */
       if (queue->reader)
         g_cond_signal (queue->not_empty);
index e667a75edb0d36c9946290e9b16b0721919f3860..5962807ac3e8183b468f0e402d105d722d2e34ae 100644 (file)
@@ -187,7 +187,9 @@ gst_typefind_chain (GstPad *pad, GstBuffer *buf)
                        gst_caps_get_name (caps));
        typefind->caps = caps;
 
-       gst_pad_set_caps (pad, caps);
+       if (!gst_pad_try_reconnect_filtered (pad, caps)) {
+          g_warning ("typefind: found type but peer didn't accept it");
+       }
 
        {
           int oldstate = GST_STATE(typefind);
index 1da9ab256d34994fa6884c71983dc23ab252a3ed..b34511b658401c197a7b6530e36def6ef9df363e 100644 (file)
@@ -133,26 +133,6 @@ gst_identity_get_bufferpool (GstPad *pad)
   return gst_pad_get_bufferpool (identity->srcpad);
 }
 
-static GstPadNegotiateReturn
-gst_identity_negotiate_src (GstPad *pad, GstCaps **caps, gpointer *data)
-{
-  GstIdentity *identity;
-
-  identity = GST_IDENTITY (gst_pad_get_parent (pad));
-
-  return gst_pad_negotiate_proxy (pad, identity->sinkpad, caps);
-}
-
-static GstPadNegotiateReturn
-gst_identity_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data)
-{
-  GstIdentity *identity;
-
-  identity = GST_IDENTITY (gst_pad_get_parent (pad));
-
-  return gst_pad_negotiate_proxy (pad, identity->srcpad, caps);
-}
-
 static void 
 gst_identity_init (GstIdentity *identity) 
 {
@@ -160,11 +140,9 @@ gst_identity_init (GstIdentity *identity)
   gst_element_add_pad (GST_ELEMENT (identity), identity->sinkpad);
   gst_pad_set_chain_function (identity->sinkpad, GST_DEBUG_FUNCPTR (gst_identity_chain));
   gst_pad_set_bufferpool_function (identity->sinkpad, gst_identity_get_bufferpool);
-  gst_pad_set_negotiate_function (identity->sinkpad, gst_identity_negotiate_sink);
   
   identity->srcpad = gst_pad_new ("src", GST_PAD_SRC);
   gst_element_add_pad (GST_ELEMENT (identity), identity->srcpad);
-  gst_pad_set_negotiate_function (identity->srcpad, gst_identity_negotiate_src);
 
   identity->loop_based = FALSE;
   identity->sleep_time = 0;
index bf67c983889439cdf877c978d0770a430ac86b3b..61ec8f1cbe38a928e4a96730c9552ab80027b2e6 100644 (file)
@@ -78,8 +78,6 @@ static void                   gst_queue_set_property          (GObject *object, guint prop_id,
 static void                    gst_queue_get_property          (GObject *object, guint prop_id, 
                                                                 GValue *value, GParamSpec *pspec);
 
-static GstPadNegotiateReturn   gst_queue_handle_negotiate_src  (GstPad *pad, GstCaps **caps, gpointer *data);
-static GstPadNegotiateReturn   gst_queue_handle_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data);
 static void                    gst_queue_chain                 (GstPad *pad, GstBuffer *buf);
 static GstBuffer *             gst_queue_get                   (GstPad *pad);
 static GstBufferPool*          gst_queue_get_bufferpool        (GstPad *pad);
@@ -163,6 +161,34 @@ gst_queue_class_init (GstQueueClass *klass)
   gstelement_class->change_state = GST_DEBUG_FUNCPTR(gst_queue_change_state);
 }
 
+static GstPadConnectReturn
+gst_queue_connect (GstPad *pad, GstCaps *caps)
+{
+  GstQueue *queue = GST_QUEUE (gst_pad_get_parent (pad));
+  GstPad *otherpad;
+
+  if (pad == queue->srcpad) 
+    otherpad = queue->sinkpad;
+  else
+    otherpad = queue->srcpad;
+
+  return gst_pad_proxy_connect (otherpad, caps);
+}
+
+static GstCaps*
+gst_queue_getcaps (GstPad *pad, GstCaps *caps)
+{
+  GstQueue *queue = GST_QUEUE (gst_pad_get_parent (pad));
+  GstPad *otherpad;
+
+  if (pad == queue->srcpad) 
+    otherpad = queue->sinkpad;
+  else
+    otherpad = queue->srcpad;
+
+  return gst_pad_get_allowed_caps (otherpad);
+}
+
 static void
 gst_queue_init (GstQueue *queue)
 {
@@ -171,15 +197,17 @@ gst_queue_init (GstQueue *queue)
   GST_FLAG_SET (queue, GST_ELEMENT_EVENT_AWARE);
 
   queue->sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
-  gst_pad_set_chain_function (queue->sinkpad, GST_DEBUG_FUNCPTR(gst_queue_chain));
+  gst_pad_set_chain_function (queue->sinkpad, GST_DEBUG_FUNCPTR (gst_queue_chain));
   gst_element_add_pad (GST_ELEMENT (queue), queue->sinkpad);
-  gst_pad_set_negotiate_function (queue->sinkpad, GST_DEBUG_FUNCPTR(gst_queue_handle_negotiate_sink));
-  gst_pad_set_bufferpool_function (queue->sinkpad, GST_DEBUG_FUNCPTR(gst_queue_get_bufferpool));
+  gst_pad_set_bufferpool_function (queue->sinkpad, GST_DEBUG_FUNCPTR (gst_queue_get_bufferpool));
+  gst_pad_set_connect_function (queue->sinkpad, GST_DEBUG_FUNCPTR (gst_queue_connect));
+  gst_pad_set_getcaps_function (queue->sinkpad, GST_DEBUG_FUNCPTR (gst_queue_getcaps));
 
   queue->srcpad = gst_pad_new ("src", GST_PAD_SRC);
-  gst_pad_set_get_function (queue->srcpad, GST_DEBUG_FUNCPTR(gst_queue_get));
+  gst_pad_set_get_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_get));
   gst_element_add_pad (GST_ELEMENT (queue), queue->srcpad);
-  gst_pad_set_negotiate_function (queue->srcpad, GST_DEBUG_FUNCPTR(gst_queue_handle_negotiate_src));
+  gst_pad_set_connect_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_connect));
+  gst_pad_set_getcaps_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_getcaps));
 
   queue->leaky = GST_QUEUE_NO_LEAK;
   queue->queue = NULL;
@@ -221,26 +249,6 @@ gst_queue_get_bufferpool (GstPad *pad)
   return gst_pad_get_bufferpool (queue->srcpad);
 }
 
-static GstPadNegotiateReturn
-gst_queue_handle_negotiate_src (GstPad *pad, GstCaps **caps, gpointer *data)
-{
-  GstQueue *queue;
-
-  queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
-
-  return gst_pad_negotiate_proxy (pad, queue->sinkpad, caps);
-}
-
-static GstPadNegotiateReturn
-gst_queue_handle_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data)
-{
-  GstQueue *queue;
-
-  queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
-
-  return gst_pad_negotiate_proxy (pad, queue->srcpad, caps);
-}
-
 static void
 gst_queue_cleanup_buffers (gpointer data, const gpointer user_data)
 {
@@ -535,7 +543,7 @@ gst_queue_change_state (GstElement *element)
     gst_queue_locked_flush (queue);
   }
   else if (new_state == GST_STATE_PLAYING) {
-    if (!GST_PAD_CONNECTED (queue->sinkpad)) {
+    if (!GST_PAD_IS_CONNECTED (queue->sinkpad)) {
       /* FIXME can this be? */
       if (queue->reader)
         g_cond_signal (queue->not_empty);
index 913b53beff6600294e32e2aeae9da2e392a3460e..8d9736c1a3062d5c824c168446f089ce5bcaa48b 100644 (file)
@@ -146,26 +146,6 @@ gst_statistics_get_bufferpool (GstPad *pad)
   return gst_pad_get_bufferpool (statistics->srcpad);
 }
 
-static GstPadNegotiateReturn
-gst_statistics_negotiate_src (GstPad *pad, GstCaps **caps, gpointer *data)
-{
-  GstStatistics *statistics;
-
-  statistics = GST_STATISTICS (gst_pad_get_parent (pad));
-
-  return gst_pad_negotiate_proxy (pad, statistics->sinkpad, caps);
-}
-
-static GstPadNegotiateReturn
-gst_statistics_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data)
-{
-  GstStatistics *statistics;
-
-  statistics = GST_STATISTICS (gst_pad_get_parent (pad));
-
-  return gst_pad_negotiate_proxy (pad, statistics->srcpad, caps);
-}
-
 static void 
 gst_statistics_init (GstStatistics *statistics) 
 {
@@ -173,11 +153,9 @@ gst_statistics_init (GstStatistics *statistics)
   gst_element_add_pad (GST_ELEMENT (statistics), statistics->sinkpad);
   gst_pad_set_chain_function (statistics->sinkpad, GST_DEBUG_FUNCPTR (gst_statistics_chain));
   gst_pad_set_bufferpool_function (statistics->sinkpad, GST_DEBUG_FUNCPTR (gst_statistics_get_bufferpool));
-  gst_pad_set_negotiate_function (statistics->sinkpad, GST_DEBUG_FUNCPTR (gst_statistics_negotiate_sink));
   
   statistics->srcpad = gst_pad_new ("src", GST_PAD_SRC);
   gst_element_add_pad (GST_ELEMENT (statistics), statistics->srcpad);
-  gst_pad_set_negotiate_function (statistics->srcpad, GST_DEBUG_FUNCPTR (gst_statistics_negotiate_src));
 
   statistics->timer = NULL;
   statistics->last_timer = NULL;
index 0335ae208f896ab141794f45b889b201c4b6bea0..c2702e04345760c79865d2ea4da43e0b05396209 100644 (file)
@@ -66,7 +66,6 @@ static void   gst_tee_get_property    (GObject *object, guint prop_id,
 
 static void    gst_tee_chain           (GstPad *pad, GstBuffer *buf);
 
-static GstPadNegotiateReturn   gst_tee_handle_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data);
 
 static GstElementClass *parent_class = NULL;
 /*static guint gst_tee_signals[LAST_SIGNAL] = { 0 };*/
@@ -110,20 +109,44 @@ gst_tee_class_init (GstTeeClass *klass)
                       FALSE, G_PARAM_READWRITE));
 
 
-
   gobject_class->set_property = GST_DEBUG_FUNCPTR(gst_tee_set_property);
   gobject_class->get_property = GST_DEBUG_FUNCPTR(gst_tee_get_property);
 
   gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR(gst_tee_request_new_pad);
 }
 
+static gboolean 
+gst_tee_sinkconnect (GstPad *pad, GstCaps *caps) 
+{
+  GstTee *tee;
+  GList *pads;
+  
+  tee = GST_TEE (gst_pad_get_parent (pad));
+
+  /* go through all the src pads */
+  pads = gst_element_get_pad_list (GST_ELEMENT (tee));
+
+  while (pads) {
+    GstPad *outpad = GST_PAD (pads->data);
+    pads = g_list_next (pads);
+                    
+    if (GST_PAD_DIRECTION (outpad) != GST_PAD_SRC || !GST_PAD_IS_CONNECTED (outpad))
+      continue;
+
+    if (!(gst_pad_try_set_caps (outpad, caps))) {
+      return FALSE;
+    }
+  }
+  return TRUE;
+}
+
 static void 
 gst_tee_init (GstTee *tee) 
 {
   tee->sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
   gst_element_add_pad (GST_ELEMENT (tee), tee->sinkpad);
   gst_pad_set_chain_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_tee_chain));
-  gst_pad_set_negotiate_function (tee->sinkpad, GST_DEBUG_FUNCPTR(gst_tee_handle_negotiate_sink));
+  gst_pad_set_connect_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_tee_sinkconnect));
 
   tee->silent = FALSE;
 }
@@ -152,7 +175,7 @@ gst_tee_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar
   GST_PAD_ELEMENT_PRIVATE (srcpad) = NULL;
 
   if (GST_PAD_CAPS (tee->sinkpad)) {
-    gst_pad_set_caps (srcpad, GST_PAD_CAPS (tee->sinkpad));
+    gst_pad_try_set_caps (srcpad, GST_PAD_CAPS (tee->sinkpad));
   }
 
   return srcpad;
@@ -253,18 +276,18 @@ gst_tee_chain (GstPad *pad, GstBuffer *buf)
       GstEvent *event = GST_EVENT (GST_PAD_ELEMENT_PRIVATE (outpad));
        
       GST_PAD_ELEMENT_PRIVATE (outpad) = NULL;
-      if (GST_PAD_CONNECTED (outpad))
+      if (GST_PAD_IS_CONNECTED (outpad))
         gst_pad_push (outpad, GST_BUFFER (event));
       else
        gst_event_free (event);
     }
 
     if (!tee->silent) {
-      gst_element_info (GST_ELEMENT (tee), "chain        ******* (%s:%s)t (%d bytes, %llu) \n",
+      gst_element_info (GST_ELEMENT (tee), "chain        ******* (%s:%s)t (%d bytes, %llu)",
               GST_DEBUG_PAD_NAME (outpad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf));
     }
 
-    if (GST_PAD_CONNECTED (outpad))
+    if (GST_PAD_IS_CONNECTED (outpad))
       gst_pad_push (outpad, buf);
     else
       gst_buffer_unref (buf);
@@ -279,30 +302,3 @@ gst_tee_factory_init (GstElementFactory *factory)
   return TRUE;
 }
 
-static GstPadNegotiateReturn
-gst_tee_handle_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer* data)
-{
-  GstCaps* tempcaps;
-  gint i;
-  GstTee* tee = GST_TEE (GST_OBJECT_PARENT (pad));
-  GList *pads;
-  
-  if (*caps==NULL) 
-    return GST_PAD_NEGOTIATE_FAIL;
-
-  /* go through all the src pads */
-  pads = gst_element_get_pad_list (GST_ELEMENT (tee));
-
-  while (pads) {
-    GstPad *outpad = GST_PAD (pads->data);
-    pads = g_list_next (pads);
-    if (GST_PAD_DIRECTION (outpad) != GST_PAD_SRC || !GST_PAD_CONNECTED (outpad))
-      continue;
-
-    if (!(gst_pad_set_caps (outpad, *caps))) {
-      return GST_PAD_NEGOTIATE_FAIL;
-    }
-  }
-  return GST_PAD_NEGOTIATE_AGREE;
-}