From b2ee38575ddf8474a1f9724ff2d7156235bae7cf Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sun, 13 Jan 2002 22:22:42 +0000 Subject: [PATCH] Landed the new improved capsnegotiation system. 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. --- gst/autoplug/gststaticautoplugrender.c | 4 +- gst/elements/gstidentity.c | 22 - gst/elements/gststatistics.c | 22 - gst/elements/gsttee.c | 64 +- gst/gstcaps.c | 200 ++++- gst/gstcaps.h | 22 +- gst/gstelement.c | 73 +- gst/gstelement.h | 5 +- gst/gstpad.c | 965 +++++++++++++------------ gst/gstpad.h | 171 +++-- gst/gstprops.c | 666 +++++++++++++---- gst/gstprops.h | 21 +- gst/gstpropsprivate.h | 2 + gst/gstqueue.c | 64 +- gst/gsttypefind.c | 4 +- plugins/elements/gstidentity.c | 22 - plugins/elements/gstqueue.c | 64 +- plugins/elements/gststatistics.c | 22 - plugins/elements/gsttee.c | 64 +- 19 files changed, 1536 insertions(+), 941 deletions(-) diff --git a/gst/autoplug/gststaticautoplugrender.c b/gst/autoplug/gststaticautoplugrender.c index 348f27eb40..7bf55c931c 100644 --- a/gst/autoplug/gststaticautoplugrender.c +++ b/gst/autoplug/gststaticautoplugrender.c @@ -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 { diff --git a/gst/elements/gstidentity.c b/gst/elements/gstidentity.c index 1da9ab256d..b34511b658 100644 --- a/gst/elements/gstidentity.c +++ b/gst/elements/gstidentity.c @@ -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; diff --git a/gst/elements/gststatistics.c b/gst/elements/gststatistics.c index 913b53beff..8d9736c1a3 100644 --- a/gst/elements/gststatistics.c +++ b/gst/elements/gststatistics.c @@ -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; diff --git a/gst/elements/gsttee.c b/gst/elements/gsttee.c index 0335ae208f..c2702e0434 100644 --- a/gst/elements/gsttee.c +++ b/gst/elements/gsttee.c @@ -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; -} diff --git a/gst/gstcaps.c b/gst/gstcaps.c index 62be582a4f..d0e41e5fb9 100644 --- a/gst/gstcaps.c +++ b/gst/gstcaps.c @@ -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")) { diff --git a/gst/gstcaps.h b/gst/gstcaps.h index 77a8767d98..d96f2cb0d7 100644 --- a/gst/gstcaps.h +++ b/gst/gstcaps.h @@ -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); diff --git a/gst/gstelement.c b/gst/gstelement.c index 0c19d1bca7..398c9e88bf 100644 --- a/gst/gstelement.c +++ b/gst/gstelement.c @@ -690,6 +690,51 @@ gst_element_request_pad_by_name (GstElement *element, const gchar *name) return pad; } +/** + * 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. + */ +gboolean +gst_element_connect_filtered (GstElement *src, const gchar *srcpadname, + GstElement *dest, const gchar *destpadname, + GstCaps *filtercaps) +{ + GstPad *srcpad,*destpad; + + 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 FALSE; + } + destpad = gst_element_get_pad (dest, destpadname); + if (srcpad == NULL) { + GST_ERROR (dest, "destination element has no pad \"%s\"", destpadname); + return FALSE; + } + + /* we're satisified they can be connected, let's do it */ + return gst_pad_connect_filtered (srcpad, destpad, filtercaps); +} + /** * gst_element_connect: * @src: element containing source pad @@ -701,34 +746,14 @@ gst_element_request_pad_by_name (GstElement *element, const gchar *name) * 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 +gboolean gst_element_connect (GstElement *src, const gchar *srcpadname, GstElement *dest, const gchar *destpadname) { - 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); - - /* 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; - } - destpad = gst_element_get_pad (dest, destpadname); - if (srcpad == NULL) { - GST_ERROR(dest,"destination element has no pad \"%s\"",destpadname); - return; - } - - /* we're satisified they can be connected, let's do it */ - gst_pad_connect(srcpad,destpad); + return gst_element_connect_filtered (src, srcpadname, dest, destpadname, NULL); } /** diff --git a/gst/gstelement.h b/gst/gstelement.h index 88a9c7247c..32eb78eea3 100644 --- a/gst/gstelement.h +++ b/gst/gstelement.h @@ -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); diff --git a/gst/gstpad.c b/gst/gstpad.c index f0cd7de158..cb2bf30b91 100644 --- a/gst/gstpad.c +++ b/gst/gstpad.c @@ -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,11 +564,89 @@ 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_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad)); +} + +/** + * 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. The filter indicates the media type + * that should flow trought this connection. + * + * Returns: TRUE if the pad could be connected, FALSE otherwise + */ +gboolean +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); + + GST_INFO (GST_CAT_PADS, "connecting %s:%s and %s:%s", + 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); + + 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)); + + 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)) { + 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); + + /* first set peers */ + GST_RPAD_PEER (realsrc) = realsink; + GST_RPAD_PEER (realsink) = realsrc; + + 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; + + 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); + + /* now tell the scheduler(s) */ + if (realsrc->sched) + gst_scheduler_pad_connect (realsrc->sched, (GstPad *)realsrc, (GstPad *)realsink); + else if (realsink->sched) + 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)); + + return TRUE; } /** @@ -566,108 +656,12 @@ gst_pad_disconnect (GstPad *srcpad, * * 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_pad_try_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 + * Returns: TRUE if the pad could be connected, FALSE otherwise */ gboolean -gst_pad_try_connect (GstPad *srcpad, - GstPad *sinkpad) +gst_pad_connect (GstPad *srcpad, GstPad *sinkpad) { - 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); - - GST_INFO (GST_CAT_PADS, "connecting %s:%s and %s:%s", - 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); - - 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)); - - 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)) { - 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); - - - /* first set peers */ - 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 (!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); - - /* now tell the scheduler(s) */ - if (realsrc->sched) - gst_scheduler_pad_connect (realsrc->sched, (GstPad *)realsrc, (GstPad *)realsink); - else if (realsink->sched) - 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)); - return TRUE; + return gst_pad_connect_filtered (srcpad, sinkpad, NULL); } /** @@ -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; } -/** - * gst_pad_set_caps: - * @pad: the pad to set the caps to - * @caps: the capabilities to attach to this pad - * - * Set the capabilities of this pad. - * - * Returns: a boolean indicating the caps could be set on the pad - */ -gboolean -gst_pad_set_caps (GstPad *pad, - GstCaps *caps) +static GstPadConnectReturn +gst_pad_try_set_caps_func (GstPad *pad, GstCaps *caps, gboolean notify, gboolean set_caps) { GstCaps *oldcaps; - g_return_val_if_fail (pad != NULL, FALSE); - g_return_val_if_fail (GST_IS_REAL_PAD (pad), FALSE); /* NOTE this restriction */ + GST_INFO (GST_CAT_CAPS, "trying to set caps %p on pad %s:%s", + caps, GST_DEBUG_PAD_NAME (pad)); - GST_INFO (GST_CAT_CAPS, "setting caps %p on pad %s:%s", - caps, GST_DEBUG_PAD_NAME(pad)); + if (notify && GST_RPAD_CONNECTFUNC (pad)) { + GstPadConnectReturn res; + gchar *debug_string; - 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_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_try_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. + */ +gboolean +gst_pad_try_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); - oldcaps = GST_PAD_CAPS (pad); + return gst_pad_try_reconnect_filtered_func (pad, filtercaps, TRUE); +} - if (caps) - gst_caps_ref (caps); - GST_PAD_CAPS(pad) = caps; +/** + * 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 (oldcaps) - gst_caps_unref (oldcaps); + if (!gst_pad_try_reconnect_filtered_func (pad, filtercaps, TRUE)) { + gst_pad_disconnect (pad, GST_PAD (GST_PAD_PEER (pad))); + return FALSE; + } + return TRUE; +} - return gst_pad_renegotiate (pad); +/** + * 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)); + + GST_INFO (GST_CAT_CAPS, "proxy connect to pad %s:%s", + GST_DEBUG_PAD_NAME (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)))); diff --git a/gst/gstpad.h b/gst/gstpad.h index 5f572f0c0f..974af3ce34 100644 --- a/gst/gstpad.h +++ b/gst/gstpad.h @@ -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 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 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 } diff --git a/gst/gstprops.c b/gst/gstprops.c index 4d4cb3b170..0afc1066ea 100644 --- a/gst/gstprops.c +++ b/gst/gstprops.c @@ -1,6 +1,6 @@ /* GStreamer * Copyright (C) 1999,2000 Erik Walthinsen - * 2000 Wim Taymans + * 2000 Wim Taymans * * 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); + if (props == NULL) + return 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)); - - 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; } diff --git a/gst/gstprops.h b/gst/gstprops.h index 9fc6dce2e3..ab63efad31 100644 --- a/gst/gstprops.h +++ b/gst/gstprops.h @@ -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); diff --git a/gst/gstpropsprivate.h b/gst/gstpropsprivate.h index 8a1f0e3ac7..b7c45120fb 100644 --- a/gst/gstpropsprivate.h +++ b/gst/gstpropsprivate.h @@ -26,6 +26,8 @@ #include +#define GST_PROPS_ENTRY_IS_VARIABLE(a) (((GstPropsEntry*)(a))->propstype > GST_PROPS_VAR_ID) + typedef struct _GstPropsEntry GstPropsEntry; struct _GstPropsEntry { diff --git a/gst/gstqueue.c b/gst/gstqueue.c index bf67c98388..61ec8f1cbe 100644 --- a/gst/gstqueue.c +++ b/gst/gstqueue.c @@ -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); diff --git a/gst/gsttypefind.c b/gst/gsttypefind.c index e667a75edb..5962807ac3 100644 --- a/gst/gsttypefind.c +++ b/gst/gsttypefind.c @@ -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); diff --git a/plugins/elements/gstidentity.c b/plugins/elements/gstidentity.c index 1da9ab256d..b34511b658 100644 --- a/plugins/elements/gstidentity.c +++ b/plugins/elements/gstidentity.c @@ -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; diff --git a/plugins/elements/gstqueue.c b/plugins/elements/gstqueue.c index bf67c98388..61ec8f1cbe 100644 --- a/plugins/elements/gstqueue.c +++ b/plugins/elements/gstqueue.c @@ -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); diff --git a/plugins/elements/gststatistics.c b/plugins/elements/gststatistics.c index 913b53beff..8d9736c1a3 100644 --- a/plugins/elements/gststatistics.c +++ b/plugins/elements/gststatistics.c @@ -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; diff --git a/plugins/elements/gsttee.c b/plugins/elements/gsttee.c index 0335ae208f..c2702e0434 100644 --- a/plugins/elements/gsttee.c +++ b/plugins/elements/gsttee.c @@ -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; -}