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; -}