From 6ad8197d61485e0aba3e936280682634449a8824 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sun, 2 Feb 2003 19:58:11 +0000 Subject: [PATCH] - implement FLOATING flag on caps/props Original commit message from CVS: - implement FLOATING flag on caps/props - use gstmemchunk for caps/props - implement remove_entry for props - various refcounting functions - fix refcounting on caps/props - use tracing for caps/props/propsentries - fix memleak in transform functions - fix refcounting on elementfactory padtemplates - add dispose for padtemplates - shortcut pad negotiation early on --- gst/gstcaps.c | 228 +++++++++++++++++++------- gst/gstcaps.h | 48 ++++-- gst/gstelementfactory.c | 34 ++-- gst/gstpad.c | 207 ++++++++++++++++-------- gst/gstpad.h | 34 ++-- gst/gstparse.c | 4 + gst/gstprops.c | 414 +++++++++++++++++++++++++++++++----------------- gst/gstprops.h | 53 ++++++- 8 files changed, 709 insertions(+), 313 deletions(-) diff --git a/gst/gstcaps.c b/gst/gstcaps.c index 0ac7baf..57de568 100644 --- a/gst/gstcaps.c +++ b/gst/gstcaps.c @@ -25,10 +25,15 @@ #include "gstcaps.h" #include "gsttype.h" +#include "gstmemchunk.h" #include "gstlog.h" -static GMemChunk *_gst_caps_chunk; -static GMutex *_gst_caps_chunk_lock; +/* #define GST_WITH_ALLOC_TRACE */ +#include "gsttrace.h" + +static GstMemChunk *_gst_caps_chunk; + +static GstAllocTrace *_gst_caps_trace; GType _gst_caps_type; @@ -52,22 +57,23 @@ transform_func (const GValue *src_value, g_value_set_boxed (&value, caps->properties); props = g_strdup_value_contents (&value); + g_value_unset (&value); g_string_append (result, props); g_free (props); caps = caps->next; - g_string_append_printf (result, " }%s", caps?", ":""); + g_string_append_printf (result, " }%s", (caps ? ", " : "")); } dest_value->data[0].v_pointer = result->str; + g_string_free (result, FALSE); } void _gst_caps_initialize (void) { - _gst_caps_chunk = g_mem_chunk_new ("GstCaps", + _gst_caps_chunk = gst_mem_chunk_new ("GstCaps", sizeof (GstCaps), sizeof (GstCaps) * 256, G_ALLOC_AND_FREE); - _gst_caps_chunk_lock = g_mutex_new (); _gst_caps_type = g_boxed_type_register_static ("GstCaps", (GBoxedCopyFunc) gst_caps_ref, @@ -76,6 +82,8 @@ _gst_caps_initialize (void) g_value_register_transform_func (_gst_caps_type, G_TYPE_STRING, transform_func); + + _gst_caps_trace = gst_alloc_trace_register (GST_CAPS_TRACE_NAME); } static guint16 @@ -133,24 +141,63 @@ gst_caps_new_id (const gchar *name, const guint16 id, GstProps *props) { GstCaps *caps; - g_mutex_lock (_gst_caps_chunk_lock); - caps = g_mem_chunk_alloc (_gst_caps_chunk); - g_mutex_unlock (_gst_caps_chunk_lock); + caps = gst_mem_chunk_alloc (_gst_caps_chunk); + gst_alloc_trace_new (_gst_caps_trace, caps); + + GST_DEBUG (GST_CAT_CAPS, "new %p", caps); + + gst_props_ref (props); + gst_props_sink (props); caps->name = g_strdup (name); caps->id = id; caps->properties = props; caps->next = NULL; caps->refcount = 1; - if (props) - caps->fixed = props->fixed; + GST_CAPS_FLAG_SET (caps, GST_CAPS_FLOATING); + + if (props && !GST_PROPS_IS_FIXED (props)) + GST_CAPS_FLAG_UNSET (caps, GST_CAPS_FIXED); else - caps->fixed = TRUE; + GST_CAPS_FLAG_SET (caps, GST_CAPS_FIXED); return caps; } /** + * gst_caps_replace: + * @oldcaps: the caps to take replace + * @newcaps: the caps to take replace + * + * Replace the pointer to the caps, doing proper + * refcounting. + */ +void +gst_caps_replace (GstCaps **oldcaps, GstCaps *newcaps) +{ + if (*oldcaps != newcaps) { + if (newcaps) gst_caps_ref (newcaps); + if (*oldcaps) gst_caps_unref (*oldcaps); + + *oldcaps = newcaps; + } +} + +/** + * gst_caps_replace_sink: + * @oldcaps: the caps to take replace + * @newcaps: the caps to take replace + * + * Replace the pointer to the caps and take ownership. + */ +void +gst_caps_replace_sink (GstCaps **oldcaps, GstCaps *newcaps) +{ + gst_caps_replace (oldcaps, newcaps); + gst_caps_sink (newcaps); +} + +/** * gst_caps_destroy: * @caps: the caps to destroy * @@ -167,11 +214,13 @@ gst_caps_destroy (GstCaps *caps) next = caps->next; + GST_DEBUG (GST_CAT_CAPS, "destroy %p", caps); + gst_props_unref (caps->properties); g_free (caps->name); - g_mutex_lock (_gst_caps_chunk_lock); - g_mem_chunk_free (_gst_caps_chunk, caps); - g_mutex_unlock (_gst_caps_chunk_lock); + + gst_alloc_trace_free (_gst_caps_trace, caps); + gst_mem_chunk_free (_gst_caps_chunk, caps); if (next) gst_caps_unref (next); @@ -189,8 +238,10 @@ gst_caps_debug (GstCaps *caps, const gchar *label) { GST_DEBUG_ENTER ("caps debug: %s", label); while (caps) { - GST_DEBUG (GST_CAT_CAPS, "caps: %p %s %s (%sfixed)", caps, caps->name, gst_caps_get_mime (caps), - caps->fixed ? "" : "NOT "); + GST_DEBUG (GST_CAT_CAPS, "caps: %p %s %s (%sfixed) (refcount %d) %s", + caps, caps->name, gst_caps_get_mime (caps), + GST_CAPS_IS_FIXED (caps) ? "" : "NOT ", caps->refcount, + GST_CAPS_IS_FLOATING (caps) ? "FLOATING" : ""); if (caps->properties) { gst_props_debug (caps->properties); @@ -223,6 +274,9 @@ gst_caps_unref (GstCaps *caps) g_return_val_if_fail (caps->refcount > 0, NULL); + GST_DEBUG (GST_CAT_CAPS, "unref %p (%d->%d) %d", + caps, caps->refcount, caps->refcount-1, GST_CAPS_FLAGS (caps)); + caps->refcount--; zero = (caps->refcount == 0); @@ -244,7 +298,13 @@ gst_caps_unref (GstCaps *caps) GstCaps* gst_caps_ref (GstCaps *caps) { - g_return_val_if_fail (caps != NULL, NULL); + if (caps == NULL) + return NULL; + + g_return_val_if_fail (caps->refcount > 0, NULL); + + GST_DEBUG (GST_CAT_CAPS, "ref %p (%d->%d) %d", + caps, caps->refcount, caps->refcount+1, GST_CAPS_FLAGS (caps)); caps->refcount++; @@ -252,12 +312,32 @@ gst_caps_ref (GstCaps *caps) } /** + * gst_caps_sink: + * @caps: the caps to take ownership of + * + * Take ownership of a GstCaps + */ +void +gst_caps_sink (GstCaps *caps) +{ + if (caps == NULL) + return; + + if (GST_CAPS_IS_FLOATING (caps)) { + GST_DEBUG (GST_CAT_CAPS, "sink %p", caps); + + GST_CAPS_FLAG_UNSET (caps, GST_CAPS_FLOATING); + gst_caps_unref (caps); + } +} + +/** * gst_caps_copy_1: * @caps: the caps to copy * * Copies the caps, not copying any chained caps. * - * Returns: a copy of the GstCaps structure. + * Returns: a floating copy of the GstCaps structure. */ GstCaps* gst_caps_copy_1 (GstCaps *caps) @@ -281,7 +361,7 @@ gst_caps_copy_1 (GstCaps *caps) * * Copies the caps. * - * Returns: a copy of the GstCaps structure. + * Returns: a floating copy of the GstCaps structure. */ GstCaps* gst_caps_copy (GstCaps *caps) @@ -312,7 +392,7 @@ gst_caps_copy (GstCaps *caps) * Copies the caps if the refcount is greater than 1 * * Returns: a pointer to a GstCaps strcuture that can - * be safely written to + * be safely written to. */ GstCaps* gst_caps_copy_on_write (GstCaps *caps) @@ -360,9 +440,7 @@ gst_caps_set_name (GstCaps *caps, const gchar *name) { g_return_if_fail (caps != NULL); - if (caps->name) - g_free (caps->name); - + g_free (caps->name); caps->name = g_strdup (name); } @@ -449,10 +527,8 @@ GstCaps* gst_caps_set_props (GstCaps *caps, GstProps *props) { g_return_val_if_fail (caps != NULL, caps); - g_return_val_if_fail (props != NULL, caps); - g_return_val_if_fail (caps->properties == NULL, caps); - caps->properties = props; + gst_props_replace_sink (&caps->properties, props); return caps; } @@ -474,6 +550,23 @@ gst_caps_get_props (GstCaps *caps) } /** + * gst_caps_next: + * @caps: the caps to query + * + * Get the next caps of this chained caps. + * + * Returns: the next caps or NULL if the chain ended. + */ +GstCaps* +gst_caps_next (GstCaps *caps) +{ + if (caps == NULL) + return NULL; + + return caps->next; +} + +/** * gst_caps_chain: * @caps: a capabilty * @...: more capabilities @@ -523,7 +616,7 @@ gst_caps_append (GstCaps *caps, GstCaps *capstoadd) while (caps->next) { caps = caps->next; } - caps->next = capstoadd; + gst_caps_replace_sink (&caps->next, capstoadd); return orig; } @@ -550,7 +643,7 @@ gst_caps_prepend (GstCaps *caps, GstCaps *capstoadd) while (capstoadd->next) { capstoadd = capstoadd->next; } - capstoadd->next = caps; + gst_caps_replace_sink (&capstoadd->next, caps); return orig; } @@ -679,6 +772,8 @@ gst_caps_intersect_func (GstCaps *caps1, GstCaps *caps2) props = gst_props_intersect (caps1->properties, caps2->properties); if (props) { result = gst_caps_new_id ("intersect", caps1->id, props); + gst_caps_ref (result); + gst_caps_sink (result); } return result; @@ -692,7 +787,7 @@ gst_caps_intersect_func (GstCaps *caps1, GstCaps *caps2) * Make the intersection between two caps. * * Returns: The intersection of the two caps or NULL if the intersection - * is empty. + * is empty. unref the caps after use. */ GstCaps* gst_caps_intersect (GstCaps *caps1, GstCaps *caps2) @@ -704,11 +799,16 @@ gst_caps_intersect (GstCaps *caps1, GstCaps *caps2) if (caps1 == NULL) { GST_DEBUG (GST_CAT_CAPS, "first caps is NULL, return other caps"); - return gst_caps_copy (caps2); + return gst_caps_ref (caps2); } if (caps2 == NULL) { GST_DEBUG (GST_CAT_CAPS, "second caps is NULL, return other caps"); - return gst_caps_copy (caps1); + return gst_caps_ref (caps1); + } + + /* same caps */ + if (caps1 == caps2) { + return gst_caps_ref (caps1); } while (caps1) { @@ -729,7 +829,27 @@ gst_caps_intersect (GstCaps *caps1, GstCaps *caps2) } othercaps = othercaps->next; } - caps1 = caps1->next; + caps1 = caps1->next; + } + + return result; +} + +GstCaps* +gst_caps_union (GstCaps *caps1, GstCaps *caps2) +{ + GstCaps *result = NULL; + + /* printing the name is not useful here since caps can be chained */ + GST_DEBUG (GST_CAT_CAPS, "making union of caps %p and %p", caps1, caps2); + + if (caps1 == NULL) { + GST_DEBUG (GST_CAT_CAPS, "first caps is NULL, return other caps"); + return gst_caps_ref (caps2); + } + if (caps2 == NULL) { + GST_DEBUG (GST_CAT_CAPS, "second caps is NULL, return other caps"); + return gst_caps_ref (caps1); } return result; @@ -742,43 +862,40 @@ gst_caps_intersect (GstCaps *caps1, GstCaps *caps2) * Make the normalisation of the caps. This will return a new caps * that is equivalent to the input caps with the exception that all * lists are unrolled. This function is useful when you want to iterate - * the caps. + * the caps. unref the caps after use. * - * Returns: The normalisation of the caps. + * Returns: The normalisation of the caps. Unref after usage. */ GstCaps* gst_caps_normalize (GstCaps *caps) { - GstCaps *result = NULL, *walk = caps; + GstCaps *result = NULL, *walk; if (caps == NULL) return caps; + GST_DEBUG (GST_CAT_CAPS, "normalizing caps %p ", caps); + + walk = caps; + while (caps) { GList *proplist; proplist = gst_props_normalize (caps->properties); - if (proplist && g_list_next (proplist) == NULL) { - if (result == NULL) - walk = result = caps; - else { - walk = walk->next = caps; - } - goto next; - } - while (proplist) { GstProps *props = (GstProps *) proplist->data; GstCaps *newcaps = gst_caps_new_id (caps->name, caps->id, props); + gst_caps_ref (newcaps); + gst_caps_sink (newcaps); + if (result == NULL) walk = result = newcaps; else { - walk = walk->next = newcaps; + walk = walk->next = newcaps; } proplist = g_list_next (proplist); } -next: caps = caps->next; } return result; @@ -836,13 +953,13 @@ gst_caps_load_thyself (xmlNodePtr parent) xmlNodePtr subfield = field->xmlChildrenNode; GstCaps *caps; gchar *content; - gboolean fixed = TRUE; + GstCapsFlags fixed = GST_CAPS_FIXED; - g_mutex_lock (_gst_caps_chunk_lock); - caps = g_mem_chunk_alloc0 (_gst_caps_chunk); - g_mutex_unlock (_gst_caps_chunk_lock); + caps = gst_mem_chunk_alloc0 (_gst_caps_chunk); + gst_alloc_trace_new (_gst_caps_trace, caps); caps->refcount = 1; + GST_CAPS_FLAG_SET (caps, GST_CAPS_FLOATING); caps->next = NULL; while (subfield) { @@ -855,13 +972,18 @@ gst_caps_load_thyself (xmlNodePtr parent) g_free (content); } else if (!strcmp (subfield->name, "properties")) { - caps->properties = gst_props_load_thyself (subfield); - fixed &= caps->properties->fixed; + GstProps *props = gst_props_load_thyself (subfield); + + gst_props_ref (props); + gst_props_sink (props); + caps->properties = props; + + fixed &= (GST_PROPS_IS_FIXED (caps->properties) ? GST_CAPS_FIXED : 0 ); } subfield = subfield->next; } - caps->fixed = fixed; + GST_CAPS_FLAG_SET (caps, fixed); result = gst_caps_append (result, caps); } diff --git a/gst/gstcaps.h b/gst/gstcaps.h index cabd478..2168bc9 100644 --- a/gst/gstcaps.h +++ b/gst/gstcaps.h @@ -30,28 +30,43 @@ G_BEGIN_DECLS typedef struct _GstCaps GstCaps; +#define GST_CAPS_TRACE_NAME "GstCaps" + extern GType _gst_caps_type; #define GST_TYPE_CAPS (_gst_caps_type) +typedef enum { + GST_CAPS_FIXED = (1 << 0), /* caps has no variable properties */ + GST_CAPS_FLOATING = (1 << 1) /* caps is floating */ +} GstCapsFlags; #define GST_CAPS(caps) ((GstCaps *)(caps)) -#define GST_CAPS_IS_FIXED(caps) ((caps)->fixed) -#define GST_CAPS_IS_CHAINED(caps) ((caps)->next) +#define GST_CAPS_FLAGS(caps) ((caps)->flags) +#define GST_CAPS_FLAG_IS_SET(caps,flag) (GST_CAPS_FLAGS (caps) & flag) +#define GST_CAPS_FLAG_SET(caps,flag) (GST_CAPS_FLAGS (caps) |= (flag)) +#define GST_CAPS_FLAG_UNSET(caps,flag) (GST_CAPS_FLAGS (caps) &= ~(flag)) + +#define GST_CAPS_REFCOUNT(caps) ((caps)->refcount) +#define GST_CAPS_PROPERTIES(caps) ((caps)->properties) +#define GST_CAPS_NEXT(caps) ((caps)->next) + +#define GST_CAPS_IS_FIXED(caps) (GST_CAPS_FLAGS (caps) & GST_CAPS_FIXED) +#define GST_CAPS_IS_FLOATING(caps) (GST_CAPS_FLAGS (caps) & GST_CAPS_FLOATING) +#define GST_CAPS_IS_CHAINED(caps) (GST_CAPS_NEXT (caps) != NULL) -/* CR1: id is an int corresponding to the quark for the mime type because - * it's really fast when doing a first-pass check for caps compatibility */ struct _GstCaps { + /* --- public --- */ gchar *name; /* the name of this caps */ - guint16 id; /* type id (major type) representing - the mime type */ + guint16 id; /* type id (major type) representing + the mime type, it's stored as a GQuark + for speed/space reasons */ - guint refcount; - gboolean fixed; /* this caps doesn't contain variable properties */ + guint16 flags; /* flags */ + guint refcount; GstProps *properties; /* properties for this capability */ - GstCaps *next; /* not with a GList for efficiency */ }; @@ -97,21 +112,30 @@ factoryname (void) \ } #endif +/* get caps from a factory */ #define GST_CAPS_GET(fact) (fact)() /* initialize the subsystem */ void _gst_caps_initialize (void); +/* creating new caps */ GstCaps* gst_caps_new (const gchar *name, const gchar *mime, GstProps *props); GstCaps* gst_caps_new_id (const gchar *name, const guint16 id, GstProps *props); +/* replace pointer to caps, doing proper refcounting */ +void gst_caps_replace (GstCaps **oldcaps, GstCaps *newcaps); +void gst_caps_replace_sink (GstCaps **oldcaps, GstCaps *newcaps); +/* caps lifecycle control */ GstCaps* gst_caps_unref (GstCaps *caps); GstCaps* gst_caps_ref (GstCaps *caps); +void gst_caps_sink (GstCaps *caps); void gst_caps_destroy (GstCaps *caps); +/* write debug lines to the log */ void gst_caps_debug (GstCaps *caps, const gchar *label); +/* copy caps */ GstCaps* gst_caps_copy (GstCaps *caps); GstCaps* gst_caps_copy_1 (GstCaps *caps); GstCaps* gst_caps_copy_on_write (GstCaps *caps); @@ -148,12 +172,18 @@ GstProps* gst_caps_get_props (GstCaps *caps); GstCaps* gst_caps_get_by_name (GstCaps *caps, const gchar *name); +/* use and construct chained caps */ +GstCaps* gst_caps_next (GstCaps *caps); GstCaps* gst_caps_chain (GstCaps *caps, ...); GstCaps* gst_caps_append (GstCaps *caps, GstCaps *capstoadd); GstCaps* gst_caps_prepend (GstCaps *caps, GstCaps *capstoadd); +/* see if fromcaps is a subset of tocaps */ gboolean gst_caps_is_always_compatible (GstCaps *fromcaps, GstCaps *tocaps); + +/* operations on caps */ GstCaps* gst_caps_intersect (GstCaps *caps1, GstCaps *caps2); +GstCaps* gst_caps_union (GstCaps *caps1, GstCaps *caps2); GstCaps* gst_caps_normalize (GstCaps *caps); #ifndef GST_DISABLE_LOADSAVE diff --git a/gst/gstelementfactory.c b/gst/gstelementfactory.c index 4b2b539..4254646 100644 --- a/gst/gstelementfactory.c +++ b/gst/gstelementfactory.c @@ -122,11 +122,27 @@ gst_element_details_free (GstElementDetails *dp) static void gst_element_factory_cleanup (GstElementFactory *factory) { + GList *padtemplates; + if (factory->details_dynamic) { gst_element_details_free (factory->details); factory->details_dynamic = FALSE; } + padtemplates = factory->padtemplates; + + while (padtemplates) { + GstPadTemplate *oldtempl = GST_PAD_TEMPLATE (padtemplates->data); + + gst_object_unref (GST_OBJECT (oldtempl)); + + padtemplates = g_list_next (padtemplates); + } + g_list_free (factory->padtemplates); + + factory->padtemplates = NULL; + factory->numpadtemplates = 0; + g_free (GST_PLUGIN_FEATURE (factory)->name); } @@ -301,28 +317,14 @@ gst_element_factory_make_or_warn (const gchar *factoryname, const gchar *name) */ void gst_element_factory_add_pad_template (GstElementFactory *factory, - GstPadTemplate *templ) + GstPadTemplate *templ) { - GList *padtemplates; - g_return_if_fail (factory != NULL); g_return_if_fail (templ != NULL); - padtemplates = factory->padtemplates; - gst_object_ref (GST_OBJECT (templ)); + gst_object_sink (GST_OBJECT (templ)); - while (padtemplates) { - GstPadTemplate *oldtempl = GST_PAD_TEMPLATE (padtemplates->data); - - if (!strcmp (oldtempl->name_template, templ->name_template)) { - gst_object_unref (GST_OBJECT (oldtempl)); - padtemplates->data = templ; - return; - } - - padtemplates = g_list_next (padtemplates); - } factory->padtemplates = g_list_append (factory->padtemplates, templ); factory->numpadtemplates++; } diff --git a/gst/gstpad.c b/gst/gstpad.c index 1c372d4..71e20e7 100644 --- a/gst/gstpad.c +++ b/gst/gstpad.c @@ -842,15 +842,15 @@ gst_pad_unlink (GstPad *srcpad, /* reset the filters, both filters are refcounted once */ if (GST_RPAD_FILTER (realsrc)) { - gst_caps_unref (GST_RPAD_FILTER (realsrc)); - GST_RPAD_FILTER (realsink) = NULL; - GST_RPAD_FILTER (realsrc) = NULL; + gst_caps_replace (&GST_RPAD_FILTER (realsink), NULL); + gst_caps_replace (&GST_RPAD_FILTER (realsrc), NULL); } /* now tell the scheduler */ if (src_sched && src_sched == sink_sched) { gst_scheduler_pad_unlink (src_sched, - GST_PAD_CAST (realsrc), GST_PAD_CAST (realsink)); + GST_PAD_CAST (realsrc), + GST_PAD_CAST (realsink)); } /* hold a reference, as they can go away in the signal handlers */ @@ -906,7 +906,7 @@ gst_pad_check_schedulers (GstRealPad *realsrc, GstRealPad *realsink) */ gboolean gst_pad_can_link_filtered (GstPad *srcpad, GstPad *sinkpad, - GstCaps *filtercaps) + GstCaps *filtercaps) { GstRealPad *realsrc, *realsink; @@ -1041,7 +1041,7 @@ gst_pad_link_filtered (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps) /* try to negotiate the pads, we don't need to clear the caps here */ if (!gst_pad_try_relink_filtered_func (realsrc, realsink, - filtercaps, FALSE)) { + filtercaps, FALSE)) { GST_DEBUG (GST_CAT_CAPS, "relink_filtered_func failed, can't link"); GST_RPAD_PEER (realsrc) = NULL; @@ -1063,13 +1063,11 @@ gst_pad_link_filtered (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps) /* now tell the scheduler */ if (src_sched && src_sched == sink_sched) { gst_scheduler_pad_link (src_sched, - GST_PAD_CAST (realsrc), GST_PAD_CAST (realsink)); + GST_PAD_CAST (realsrc), GST_PAD_CAST (realsink)); } GST_INFO (GST_CAT_PADS, "linked %s:%s and %s:%s, successful", GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad)); - gst_caps_debug (gst_pad_get_caps (GST_PAD_CAST (realsrc)), - "caps of newly linked src pad"); return TRUE; } @@ -1271,7 +1269,7 @@ gst_pad_get_ghost_pad_list (GstPad *pad) static GstPadLinkReturn gst_pad_try_set_caps_func (GstRealPad *pad, GstCaps *caps, gboolean notify) { - GstCaps *oldcaps, *allowed = NULL; + GstCaps *allowed = NULL; GstPadTemplate *template; GstElement *parent = GST_PAD_PARENT (pad); @@ -1290,8 +1288,9 @@ gst_pad_try_set_caps_func (GstRealPad *pad, GstCaps *caps, gboolean notify) GST_INFO (GST_CAT_CAPS, "trying to set caps %p on pad %s:%s", caps, GST_DEBUG_PAD_NAME (pad)); - /* first see if we have to check against a filter */ - if (!(allowed = GST_RPAD_FILTER (pad))) { + /* first see if we have to check against a filter, we ref the caps here as we're + * going to unref it later on */ + if (!(allowed = gst_caps_ref (GST_RPAD_FILTER (pad)))) { /* no filter, make sure we check against the padtemplate then */ if ((template = gst_pad_get_pad_template (GST_PAD_CAST (pad)))) { allowed = gst_pad_template_get_caps (template); @@ -1312,10 +1311,12 @@ gst_pad_try_set_caps_func (GstRealPad *pad, GstCaps *caps, gboolean notify) gst_caps_debug (caps, "caps themselves (attemped to set)"); gst_caps_debug (allowed, "allowed caps that did not agree with caps"); + gst_caps_unref (allowed); return GST_PAD_LINK_REFUSED; } /* caps checks out fine, we can unref the intersection now */ gst_caps_unref (intersection); + gst_caps_unref (allowed); /* given that the caps are fixed, we know that their intersection with the * padtemplate caps is the same as caps itself */ } @@ -1383,10 +1384,7 @@ gst_pad_try_set_caps_func (GstRealPad *pad, GstCaps *caps, gboolean notify) GST_INFO (GST_CAT_CAPS, "setting caps on pad %s:%s", GST_DEBUG_PAD_NAME (pad)); /* if we got this far all is ok, remove the old caps, set the new one */ - oldcaps = GST_PAD_CAPS (pad); - if (caps) gst_caps_ref (caps); - GST_PAD_CAPS (pad) = caps; - if (oldcaps) gst_caps_unref (oldcaps); + gst_caps_replace_sink (&GST_PAD_CAPS (pad), caps); g_object_notify (G_OBJECT (pad), "caps"); } @@ -1394,6 +1392,8 @@ gst_pad_try_set_caps_func (GstRealPad *pad, GstCaps *caps, gboolean notify) GST_INFO (GST_CAT_CAPS, "caps are not fixed on pad %s:%s, not setting them yet", GST_DEBUG_PAD_NAME (pad)); + + return GST_PAD_LINK_DELAYED; } return GST_PAD_LINK_OK; } @@ -1403,7 +1403,8 @@ gst_pad_try_set_caps_func (GstRealPad *pad, GstCaps *caps, gboolean notify) * @pad: a #GstPad to try to set the caps on. * @caps: the #GstCaps to set. * - * Tries to set the caps on the given pad. + * Tries to set the caps on the given pad. Ownership is always taken + * of the caps, so you will need to unref non-floating caps. * * Returns: A #GstPadLinkReturn value indicating whether the caps * could be set. @@ -1422,15 +1423,21 @@ gst_pad_try_set_caps (GstPad *pad, GstCaps *caps) gst_caps_debug (caps, "caps that we are trying to set"); + /* try to take ownership */ + gst_caps_ref (caps); + gst_caps_sink (caps); + /* setting non fixed caps on a pad is not allowed */ if (!GST_CAPS_IS_FIXED (caps)) { - GST_INFO (GST_CAT_CAPS, - "trying to set unfixed caps on pad %s:%s, not allowed", - GST_DEBUG_PAD_NAME (realpad)); + GST_INFO (GST_CAT_CAPS, + "trying to set unfixed caps on pad %s:%s, not allowed", + GST_DEBUG_PAD_NAME (realpad)); g_warning ("trying to set non fixed caps on pad %s:%s, not allowed", GST_DEBUG_PAD_NAME (realpad)); + gst_caps_debug (caps, "unfixed caps"); - return GST_PAD_LINK_DELAYED; + set_retval = GST_PAD_LINK_DELAYED; + goto done; } /* if we have a peer try to set the caps, notifying the peerpad @@ -1439,7 +1446,7 @@ gst_pad_try_set_caps (GstPad *pad, GstCaps *caps) { GST_INFO (GST_CAT_CAPS, "tried to set caps on peerpad %s:%s but couldn't, return value %d", GST_DEBUG_PAD_NAME (peer), set_retval); - return set_retval; + goto done; } /* then try to set our own caps, we don't need to be notified */ @@ -1447,12 +1454,16 @@ gst_pad_try_set_caps (GstPad *pad, GstCaps *caps) { GST_INFO (GST_CAT_CAPS, "tried to set own caps on pad %s:%s but couldn't, return value %d", GST_DEBUG_PAD_NAME (realpad), set_retval); - return set_retval; + goto done; } GST_INFO (GST_CAT_CAPS, "succeeded setting caps %p on pad %s:%s, return value %d", caps, GST_DEBUG_PAD_NAME (realpad), set_retval); g_assert (GST_PAD_CAPS (pad)); - + +done: + /* if we took ownership, the caps will be freed */ + gst_caps_unref (caps); + return set_retval; } @@ -1486,10 +1497,10 @@ gst_pad_try_relink_filtered_func (GstRealPad *srcpad, GstRealPad *sinkpad, GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink)); /* FIXME does this leak? */ - GST_PAD_CAPS (GST_PAD (realsrc)) = NULL; - GST_PAD_CAPS (GST_PAD (realsink)) = NULL; - GST_RPAD_FILTER (realsrc) = NULL; - GST_RPAD_FILTER (realsink) = NULL; + gst_caps_replace (&GST_PAD_CAPS (GST_PAD (realsrc)), NULL); + gst_caps_replace (&GST_PAD_CAPS (GST_PAD (realsink)), NULL); + gst_caps_replace (&GST_RPAD_FILTER (realsrc), NULL); + gst_caps_replace (&GST_RPAD_FILTER (realsink), NULL); } else { GST_INFO (GST_CAT_PADS, "start relink filtered %s:%s and %s:%s", @@ -1515,6 +1526,9 @@ gst_pad_try_relink_filtered_func (GstRealPad *srcpad, GstRealPad *sinkpad, * this means they have no common format */ GST_INFO (GST_CAT_PADS, "pads %s:%s and %s:%s have no common type", GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink)); + /* make sure any floating caps from gst_pad_get_caps are freed here */ + gst_caps_sink (srccaps); + gst_caps_sink (sinkcaps); return FALSE; } else { GST_INFO (GST_CAT_PADS, "pads %s:%s and %s:%s intersected to %s caps", @@ -1523,6 +1537,10 @@ gst_pad_try_relink_filtered_func (GstRealPad *srcpad, GstRealPad *sinkpad, (GST_CAPS_IS_FIXED (intersection) ? "fixed" : "variable") : "NULL")); + /* we don't need those anymore, as the caps can be floating */ + gst_caps_sink (srccaps); + gst_caps_sink (sinkcaps); + /* then filter this against the app filter */ if (filtercaps) { GstCaps *filtered_intersection; @@ -1530,7 +1548,6 @@ gst_pad_try_relink_filtered_func (GstRealPad *srcpad, GstRealPad *sinkpad, filtered_intersection = gst_caps_intersect (intersection, filtercaps); - /* get rid of the old intersection here */ gst_caps_unref (intersection); if (!filtered_intersection) { @@ -1542,8 +1559,8 @@ gst_pad_try_relink_filtered_func (GstRealPad *srcpad, GstRealPad *sinkpad, intersection = filtered_intersection; /* keep a reference to the app caps */ - GST_RPAD_APPFILTER (realsink) = filtercaps; - GST_RPAD_APPFILTER (realsrc) = filtercaps; + gst_caps_replace_sink (&GST_RPAD_APPFILTER (realsink), filtercaps); + gst_caps_replace_sink (&GST_RPAD_APPFILTER (realsrc), filtercaps); } } GST_DEBUG (GST_CAT_CAPS, "setting filter for link to:"); @@ -1551,8 +1568,9 @@ gst_pad_try_relink_filtered_func (GstRealPad *srcpad, GstRealPad *sinkpad, /* both the app filter and the filter, while stored on both peer pads, * are equal to the same thing on both */ - GST_RPAD_FILTER (realsrc) = intersection; - GST_RPAD_FILTER (realsink) = intersection; + gst_caps_replace_sink (&GST_RPAD_FILTER (realsrc), intersection); + gst_caps_replace_sink (&GST_RPAD_FILTER (realsink), intersection); + gst_caps_unref (intersection); return gst_pad_perform_negotiate (GST_PAD (realsrc), GST_PAD (realsink)); } @@ -1572,6 +1590,9 @@ gst_pad_perform_negotiate (GstPad *srcpad, GstPad *sinkpad) GstCaps *intersection, *filtered_intersection; GstRealPad *realsrc, *realsink; GstCaps *srccaps, *sinkcaps, *filter; + gboolean res = TRUE; + GstElement *parent; + g_return_val_if_fail (srcpad != NULL, FALSE); g_return_val_if_fail (sinkpad != NULL, FALSE); @@ -1582,6 +1603,20 @@ gst_pad_perform_negotiate (GstPad *srcpad, GstPad *sinkpad) g_return_val_if_fail (GST_RPAD_PEER (realsrc) != NULL, FALSE); g_return_val_if_fail (GST_RPAD_PEER (realsink) == realsrc, FALSE); + /* shortcut negotiation */ + parent = GST_PAD_PARENT (realsrc); + if (parent && GST_STATE (parent) < GST_STATE_READY) { + GST_DEBUG (GST_CAT_CAPS, "parent %s of pad %s:%s is not READY", + GST_ELEMENT_NAME (parent), GST_DEBUG_PAD_NAME (realsrc)); + return TRUE; + } + parent = GST_PAD_PARENT (realsink); + if (parent && GST_STATE (parent) < GST_STATE_READY) { + GST_DEBUG (GST_CAT_CAPS, "parent %s of pad %s:%s is not READY", + GST_ELEMENT_NAME (parent), GST_DEBUG_PAD_NAME (realsink)); + return TRUE; + } + GST_INFO (GST_CAT_PADS, "perform negotiate for link %s:%s-%s:%s", GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink)); @@ -1605,28 +1640,39 @@ gst_pad_perform_negotiate (GstPad *srcpad, GstPad *sinkpad) "sink caps, awaiting negotiation, after applying filter"); intersection = gst_caps_intersect (srccaps, sinkcaps); filtered_intersection = gst_caps_intersect (intersection, filter); - if (filtered_intersection) { - gst_caps_unref (intersection); - intersection = filtered_intersection; - } + gst_caps_unref (intersection); /* no negotiation is performed if the pads have filtercaps */ - if (intersection) { - GstPadLinkReturn res; + if (filtered_intersection) { + GstPadLinkReturn link_res; - res = gst_pad_try_set_caps_func (realsrc, intersection, TRUE); - if (res == GST_PAD_LINK_REFUSED) - return FALSE; - if (res == GST_PAD_LINK_DONE) - return TRUE; + link_res = gst_pad_try_set_caps_func (realsrc, filtered_intersection, TRUE); + if (link_res == GST_PAD_LINK_REFUSED) + goto error; + if (link_res == GST_PAD_LINK_DONE) + goto success; - res = gst_pad_try_set_caps_func (realsink, intersection, TRUE); - if (res == GST_PAD_LINK_REFUSED) - return FALSE; - if (res == GST_PAD_LINK_DONE) - return TRUE; + link_res = gst_pad_try_set_caps_func (realsink, filtered_intersection, TRUE); + if (link_res == GST_PAD_LINK_REFUSED) + goto error; + if (link_res == GST_PAD_LINK_DONE) + goto success; } - return TRUE; + /* no filtered_intersection, some pads had caps and ther was a filter */ + else if ((srccaps || sinkcaps) && filter) { + goto error; + } + +success: +cleanup: + gst_caps_sink (srccaps); + gst_caps_sink (sinkcaps); + gst_caps_unref (filtered_intersection); + return res; + +error: + res = FALSE; + goto cleanup; } /** @@ -1656,7 +1702,7 @@ gst_pad_try_relink_filtered (GstPad *srcpad, GstPad *sinkpad, g_return_val_if_fail (GST_RPAD_PEER (realsink) == realsrc, FALSE); return gst_pad_try_relink_filtered_func (realsrc, realsink, - filtercaps, TRUE); + filtercaps, TRUE); } /** @@ -1686,8 +1732,9 @@ gst_pad_relink_filtered (GstPad *srcpad, GstPad *sinkpad, g_return_val_if_fail (GST_RPAD_PEER (realsrc) != NULL, FALSE); g_return_val_if_fail (GST_RPAD_PEER (realsink) == realsrc, FALSE); - if (! gst_pad_try_relink_filtered_func (realsrc, realsink, - filtercaps, TRUE)) { + if (!gst_pad_try_relink_filtered_func (realsrc, realsink, + filtercaps, TRUE)) + { gst_pad_unlink (srcpad, GST_PAD (GST_PAD_PEER (srcpad))); return FALSE; } @@ -1729,7 +1776,9 @@ gst_pad_proxy_link (GstPad *pad, GstCaps *caps) * * Gets the capabilities of this pad. * - * Returns: the #GstCaps of this pad. + * Returns: the #GstCaps of this pad. This function potentially + * returns a floating caps, so use gst_caps_sink to get rid of + * it. */ GstCaps* gst_pad_get_caps (GstPad *pad) @@ -1744,6 +1793,8 @@ gst_pad_get_caps (GstPad *pad) GST_DEBUG (GST_CAT_CAPS, "get pad caps of %s:%s (%p)", GST_DEBUG_PAD_NAME (realpad), realpad); + /* note that we will not _ref the caps here as this function might be + * called recursively */ if (GST_PAD_CAPS (realpad)) { GST_DEBUG (GST_CAT_CAPS, "using pad real caps %p", GST_PAD_CAPS (realpad)); return GST_PAD_CAPS (realpad); @@ -1769,7 +1820,8 @@ gst_pad_get_caps (GstPad *pad) * * Gets the template capabilities of this pad. * - * Returns: the template #GstCaps of this pad. + * Returns: the template #GstCaps of this pad, unref the caps + * if you no longer need it. */ GstCaps* gst_pad_get_pad_template_caps (GstPad *pad) @@ -1778,7 +1830,7 @@ gst_pad_get_pad_template_caps (GstPad *pad) g_return_val_if_fail (GST_IS_PAD (pad), NULL); if (GST_PAD_PAD_TEMPLATE (pad)) - return GST_PAD_TEMPLATE_CAPS (GST_PAD_PAD_TEMPLATE (pad)); + return gst_caps_ref (GST_PAD_TEMPLATE_CAPS (GST_PAD_PAD_TEMPLATE (pad))); return NULL; } @@ -1790,7 +1842,8 @@ gst_pad_get_pad_template_caps (GstPad *pad) * * Gets the capability with the given name from this pad template. * - * Returns: the #GstCaps, or NULL if not found or in case of an error. + * Returns: the #GstCaps, or NULL if not found or in case of an error. unref + * the caps if you no longer need it. */ GstCaps* gst_pad_template_get_caps_by_name (GstPadTemplate *templ, const gchar *name) @@ -1803,7 +1856,7 @@ gst_pad_template_get_caps_by_name (GstPadTemplate *templ, const gchar *name) if (!caps) return NULL; - return gst_caps_get_by_name (caps, name); + return gst_caps_ref (gst_caps_get_by_name (caps, name)); } /** @@ -1866,7 +1919,8 @@ gst_pad_get_peer (GstPad *pad) * Gets the capabilities of the allowed media types that can * flow through this pad. The caller must free the resulting caps. * - * Returns: a newly allocated copy of the allowed #GstCaps. + * Returns: the allowed #GstCaps of the pad link. unref the caps if + * you no longer need it. */ GstCaps* gst_pad_get_allowed_caps (GstPad *pad) @@ -1879,7 +1933,7 @@ gst_pad_get_allowed_caps (GstPad *pad) GST_DEBUG (GST_CAT_PROPERTIES, "get allowed caps of %s:%s", GST_DEBUG_PAD_NAME (pad)); - caps = gst_caps_copy (GST_RPAD_FILTER (pad)); + caps = gst_caps_ref (GST_RPAD_FILTER (pad)); return caps; } @@ -1909,7 +1963,7 @@ gst_pad_recalc_allowed_caps (GstPad *pad) peer = GST_RPAD_PEER (pad); if (peer) return gst_pad_try_relink_filtered (pad, GST_PAD (peer), - GST_RPAD_APPFILTER (pad)); + GST_RPAD_APPFILTER (pad)); return TRUE; } @@ -1992,6 +2046,9 @@ gst_real_pad_dispose (GObject *object) g_list_free (GST_REAL_PAD(pad)->ghostpads); } + gst_caps_replace (&GST_PAD_CAPS (pad), NULL); + gst_caps_replace (&GST_RPAD_APPFILTER (pad), NULL); + if (GST_IS_ELEMENT (GST_OBJECT_PARENT (pad))) { GST_DEBUG (GST_CAT_REFCOUNTING, "removing pad from element '%s'", GST_OBJECT_NAME (GST_OBJECT (GST_ELEMENT (GST_OBJECT_PARENT (pad))))); @@ -2319,6 +2376,7 @@ gst_pad_selectv (GstPad *pad, ...) */ static void gst_pad_template_class_init (GstPadTemplateClass *klass); static void gst_pad_template_init (GstPadTemplate *templ); +static void gst_pad_template_dispose (GObject *object); GType gst_pad_template_get_type (void) @@ -2356,6 +2414,8 @@ gst_pad_template_class_init (GstPadTemplateClass *klass) NULL, NULL, gst_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); + gobject_class->dispose = gst_pad_template_dispose; + gstobject_class->path_string_separator = "*"; } @@ -2364,6 +2424,17 @@ gst_pad_template_init (GstPadTemplate *templ) { } +static void +gst_pad_template_dispose (GObject *object) +{ + GstPadTemplate *templ = GST_PAD_TEMPLATE (object); + + g_free (GST_PAD_TEMPLATE_NAME_TEMPLATE (templ)); + gst_caps_unref (GST_PAD_TEMPLATE_CAPS (templ)); + + G_OBJECT_CLASS (padtemplate_parent_class)->dispose (object); +} + /* ALWAYS padtemplates cannot have conversion specifications, it doesn't make * sense. * SOMETIMES padtemplates can do whatever they want, they are provided by the @@ -2442,14 +2513,19 @@ gst_pad_template_new (const gchar *name_template, va_start (var_args, caps); + GST_FLAG_SET (GST_OBJECT (new), GST_PAD_TEMPLATE_FIXED); while (caps) { - new->fixed &= caps->fixed; - thecaps = gst_caps_append (thecaps, gst_caps_ref (caps)); + if (!GST_CAPS_IS_FIXED (caps)) { + GST_FLAG_UNSET (GST_OBJECT (new), GST_PAD_TEMPLATE_FIXED); + } + thecaps = gst_caps_append (thecaps, caps); caps = va_arg (var_args, GstCaps*); } va_end (var_args); GST_PAD_TEMPLATE_CAPS (new) = thecaps; + gst_caps_ref (thecaps); + gst_caps_sink (thecaps); return new; } @@ -2460,14 +2536,15 @@ gst_pad_template_new (const gchar *name_template, * * Gets the capabilities of the pad template. * - * Returns: the #GstCaps of the pad template. + * Returns: the #GstCaps of the pad template. unref the caps + * after use. */ GstCaps* gst_pad_template_get_caps (GstPadTemplate *templ) { g_return_val_if_fail (templ != NULL, NULL); - return GST_PAD_TEMPLATE_CAPS (templ); + return gst_caps_ref (GST_PAD_TEMPLATE_CAPS (templ)); } /** diff --git a/gst/gstpad.h b/gst/gstpad.h index 1b34597..b29d470 100644 --- a/gst/gstpad.h +++ b/gst/gstpad.h @@ -146,7 +146,7 @@ typedef const GstFormat* (*GstPadFormatsFunction) (GstPad *pad); typedef const GstEventMask* (*GstPadEventMaskFunction) (GstPad *pad); typedef const GstQueryType* (*GstPadQueryTypeFunction) (GstPad *pad); -typedef GstPadLinkReturn (*GstPadLinkFunction) (GstPad *pad, GstCaps *caps); +typedef GstPadLinkReturn (*GstPadLinkFunction) (GstPad *pad, GstCaps *caps); typedef GstCaps* (*GstPadGetCapsFunction) (GstPad *pad, GstCaps *caps); typedef GstBufferPool* (*GstPadBufferPoolFunction) (GstPad *pad); @@ -276,7 +276,7 @@ struct _GstGhostPadClass { #define GST_PAD_PEER(pad) GST_PAD_CAST(GST_RPAD_PEER(GST_PAD_REALIZE(pad))) /* Some check functions (unused?) */ -#define GST_PAD_IS_LINKED(pad) (GST_PAD_PEER(pad) != NULL) +#define GST_PAD_IS_LINKED(pad) (GST_PAD_PEER(pad) != NULL) #define GST_PAD_IS_ACTIVE(pad) (!GST_FLAG_IS_SET(GST_PAD_REALIZE(pad), GST_PAD_DISABLED)) #define GST_PAD_IS_USABLE(pad) (GST_PAD_IS_LINKED (pad) && \ GST_PAD_IS_ACTIVE(pad) && GST_PAD_IS_ACTIVE(GST_PAD_PEER (pad))) @@ -301,22 +301,26 @@ typedef enum { #define GST_PAD_TEMPLATE_DIRECTION(templ) (((GstPadTemplate *)(templ))->direction) #define GST_PAD_TEMPLATE_PRESENCE(templ) (((GstPadTemplate *)(templ))->presence) #define GST_PAD_TEMPLATE_CAPS(templ) (((GstPadTemplate *)(templ))->caps) -#define GST_PAD_TEMPLATE_FIXED(templ) (((GstPadTemplate *)(templ))->fixed) -#define GST_PAD_TEMPLATE_IS_FIXED(templ) (GST_PAD_TEMPLATE_FIXED(templ) == TRUE) +typedef enum { + GST_PAD_TEMPLATE_FIXED = GST_OBJECT_FLAG_LAST, + + GST_PAD_TEMPLATE_FLAG_LAST = GST_OBJECT_FLAG_LAST + 4 +} GstPadTemplateFlags; + +#define GST_PAD_TEMPLATE_IS_FIXED(templ) (GST_FLAG_IS_SET(templ), GST_PAD_TEMPLATE_FIXED) struct _GstPadTemplate { - GstObject object; + GstObject object; gchar *name_template; - GstPadDirection direction; - GstPadPresence presence; + GstPadDirection direction; + GstPadPresence presence; GstCaps *caps; - gboolean fixed; }; struct _GstPadTemplateClass { - GstObjectClass parent_class; + GstObjectClass parent_class; /* signal callbacks */ void (*pad_created) (GstPadTemplate *templ, GstPad *pad); @@ -425,7 +429,7 @@ gboolean gst_pad_can_link_filtered (GstPad *srcpad, GstPad *s gboolean gst_pad_link (GstPad *srcpad, GstPad *sinkpad); gboolean gst_pad_link_filtered (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps); -void gst_pad_unlink (GstPad *srcpad, GstPad *sinkpad); +void gst_pad_unlink (GstPad *srcpad, GstPad *sinkpad); GstPad* gst_pad_get_peer (GstPad *pad); @@ -437,7 +441,7 @@ gboolean gst_pad_check_compatibility (GstPad *srcpad, GstPad *sinkpad); void gst_pad_set_getcaps_function (GstPad *pad, GstPadGetCapsFunction getcaps); GstPadLinkReturn gst_pad_proxy_link (GstPad *pad, GstCaps *caps); -gboolean gst_pad_relink_filtered (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps); +gboolean gst_pad_relink_filtered (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps); gboolean gst_pad_perform_negotiate (GstPad *srcpad, GstPad *sinkpad); gboolean gst_pad_try_relink_filtered (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps); GstCaps* gst_pad_get_allowed_caps (GstPad *pad); @@ -475,9 +479,9 @@ gboolean gst_pad_query (GstPad *pad, GstQueryType type, gboolean gst_pad_query_default (GstPad *pad, GstQueryType type, GstFormat *format, gint64 *value); -void gst_pad_set_internal_link_function(GstPad *pad, GstPadIntLinkFunction intlink); -GList* gst_pad_get_internal_links (GstPad *pad); -GList* gst_pad_get_internal_links_default (GstPad *pad); +void gst_pad_set_internal_link_function (GstPad *pad, GstPadIntLinkFunction intlink); +GList* gst_pad_get_internal_links (GstPad *pad); +GList* gst_pad_get_internal_links_default (GstPad *pad); /* misc helper functions */ gboolean gst_pad_dispatcher (GstPad *pad, GstPadDispatcherFunction dispatch, @@ -489,7 +493,7 @@ gboolean gst_pad_dispatcher (GstPad *pad, GstPadDispatcherFunction dispatch (gst_probe_dispatcher_remove_probe (&(GST_REAL_PAD (pad)-probedisp), probe)) #ifndef GST_DISABLE_LOADSAVE -void gst_pad_load_and_link (xmlNodePtr self, GstObject *parent); +void gst_pad_load_and_link (xmlNodePtr self, GstObject *parent); #endif diff --git a/gst/gstparse.c b/gst/gstparse.c index 2b9138b..ec2874a 100644 --- a/gst/gstparse.c +++ b/gst/gstparse.c @@ -262,6 +262,9 @@ make_links (graph_t *g, GError **error) a = c->src_pads; b = c->sink_pads; caps = c->caps; + gst_caps_ref (caps); + gst_caps_sink (caps); + gst_caps_debug (caps, "foo"); /* g_print ("a: %p, b: %p\n", a, b); */ if (a && b) { @@ -363,6 +366,7 @@ make_links (graph_t *g, GError **error) } } next: + gst_caps_unref (caps); l = g_list_next (l); } diff --git a/gst/gstprops.c b/gst/gstprops.c index 0dea80f..49a914b 100644 --- a/gst/gstprops.c +++ b/gst/gstprops.c @@ -25,10 +25,17 @@ #include "gstlog.h" #include "gstprops.h" +#include "gstmemchunk.h" + +/* #define GST_WITH_ALLOC_TRACE */ +#include "gsttrace.h" GType _gst_props_type; GType _gst_props_entry_type; +static GstAllocTrace *_props_trace; +static GstAllocTrace *_entries_trace; + #define GST_PROPS_ENTRY_IS_VARIABLE(a) (((GstPropsEntry*)(a))->propstype > GST_PROPS_VAR_TYPE) struct _GstPropsEntry { @@ -60,11 +67,8 @@ struct _GstPropsEntry { } data; }; -static GMemChunk *_gst_props_entries_chunk; -static GMutex *_gst_props_entries_chunk_lock; - -static GMemChunk *_gst_props_chunk; -static GMutex *_gst_props_chunk_lock; +static GstMemChunk *_gst_props_entries_chunk; +static GstMemChunk *_gst_props_chunk; static gboolean gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2); static GList* gst_props_list_copy (GList *propslist); @@ -84,9 +88,6 @@ transform_func (const GValue *src_value, const gchar *name = g_quark_to_string (entry->propid); switch (entry->propstype) { - case GST_PROPS_STRING_TYPE: - g_string_append_printf (result, "%s=(string) '%s'", name, entry->data.string_data.string); - break; case GST_PROPS_INT_TYPE: g_string_append_printf (result, "%s=(int) %d", name, entry->data.int_data); break; @@ -98,7 +99,10 @@ transform_func (const GValue *src_value, break; case GST_PROPS_BOOLEAN_TYPE: g_string_append_printf (result, "%s=(boolean) %s", name, - (entry->data.bool_data ? "TRUE" : "FALSE")); + (entry->data.bool_data ? "TRUE" : "FALSE")); + break; + case GST_PROPS_STRING_TYPE: + g_string_append_printf (result, "%s=(string) '%s'", name, entry->data.string_data.string); break; default: break; @@ -111,21 +115,20 @@ transform_func (const GValue *src_value, } } dest_value->data[0].v_pointer = result->str; + g_string_free (result, FALSE); } void _gst_props_initialize (void) { - _gst_props_entries_chunk = g_mem_chunk_new ("GstPropsEntries", - sizeof (GstPropsEntry), sizeof (GstPropsEntry) * 256, + _gst_props_entries_chunk = gst_mem_chunk_new ("GstPropsEntries", + sizeof (GstPropsEntry), sizeof (GstPropsEntry) * 1024, G_ALLOC_AND_FREE); - _gst_props_entries_chunk_lock = g_mutex_new (); - _gst_props_chunk = g_mem_chunk_new ("GstProps", + _gst_props_chunk = gst_mem_chunk_new ("GstProps", sizeof (GstProps), sizeof (GstProps) * 256, G_ALLOC_AND_FREE); - _gst_props_chunk_lock = g_mutex_new (); _gst_props_type = g_boxed_type_register_static ("GstProps", (GBoxedCopyFunc) gst_props_ref, @@ -138,6 +141,9 @@ _gst_props_initialize (void) _gst_props_entry_type = g_boxed_type_register_static ("GstPropsEntry", (GBoxedCopyFunc) gst_props_entry_copy, (GBoxedFreeFunc) gst_props_entry_destroy); + + _props_trace = gst_alloc_trace_register (GST_PROPS_TRACE_NAME); + _entries_trace = gst_alloc_trace_register (GST_PROPS_ENTRY_TRACE_NAME); } static void @@ -147,34 +153,34 @@ gst_props_debug_entry (GstPropsEntry *entry) switch (entry->propstype) { case GST_PROPS_INT_TYPE: - GST_DEBUG (GST_CAT_PROPERTIES, "%s: int %d", name, entry->data.int_data); + GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: int %d", entry, name, entry->data.int_data); break; case GST_PROPS_FLOAT_TYPE: - GST_DEBUG (GST_CAT_PROPERTIES, "%s: float %f", name, entry->data.float_data); + GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: float %f", entry, name, entry->data.float_data); break; case GST_PROPS_FOURCC_TYPE: - GST_DEBUG (GST_CAT_PROPERTIES, "%s: fourcc %c%c%c%c", name, + GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: fourcc %c%c%c%c", entry, name, (entry->data.fourcc_data>>0)&0xff, (entry->data.fourcc_data>>8)&0xff, (entry->data.fourcc_data>>16)&0xff, (entry->data.fourcc_data>>24)&0xff); break; case GST_PROPS_BOOLEAN_TYPE: - GST_DEBUG (GST_CAT_PROPERTIES, "%s: bool %d", name, entry->data.bool_data); + GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: bool %d", entry, name, entry->data.bool_data); break; case GST_PROPS_STRING_TYPE: - GST_DEBUG (GST_CAT_PROPERTIES, "%s: string \"%s\"", name, entry->data.string_data.string); + GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: string \"%s\"", entry, name, entry->data.string_data.string); break; case GST_PROPS_INT_RANGE_TYPE: - GST_DEBUG (GST_CAT_PROPERTIES, "%s: int range %d-%d", name, entry->data.int_range_data.min, + GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: int range %d-%d", entry, name, entry->data.int_range_data.min, entry->data.int_range_data.max); break; case GST_PROPS_FLOAT_RANGE_TYPE: - GST_DEBUG (GST_CAT_PROPERTIES, "%s: float range %f-%f", name, entry->data.float_range_data.min, + GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: float range %f-%f", entry, name, entry->data.float_range_data.min, entry->data.float_range_data.max); break; case GST_PROPS_LIST_TYPE: - GST_DEBUG (GST_CAT_PROPERTIES, "[list]"); + GST_DEBUG (GST_CAT_PROPERTIES, "%p: [list]", entry); { GList *entries = entry->data.list_data.entries; @@ -185,7 +191,7 @@ gst_props_debug_entry (GstPropsEntry *entry) } break; default: - g_warning ("unknown property type %d", entry->propstype); + g_warning ("unknown property type %d at %p", entry->propstype, entry); break; } } @@ -302,15 +308,16 @@ gst_props_alloc_entry (void) { GstPropsEntry *entry; - g_mutex_lock (_gst_props_entries_chunk_lock); - entry = g_mem_chunk_alloc (_gst_props_entries_chunk); - g_mutex_unlock (_gst_props_entries_chunk_lock); + entry = gst_mem_chunk_alloc (_gst_props_entries_chunk); + gst_alloc_trace_new (_entries_trace, entry); + + GST_DEBUG (GST_CAT_PROPERTIES, "new entry %p", entry); return entry; } -void -gst_props_entry_destroy (GstPropsEntry *entry) +static void +gst_props_entry_clean (GstPropsEntry *entry) { switch (entry->propstype) { case GST_PROPS_STRING_TYPE: @@ -330,9 +337,17 @@ gst_props_entry_destroy (GstPropsEntry *entry) default: break; } - g_mutex_lock (_gst_props_entries_chunk_lock); - g_mem_chunk_free (_gst_props_entries_chunk, entry); - g_mutex_unlock (_gst_props_entries_chunk_lock); +} + +void +gst_props_entry_destroy (GstPropsEntry *entry) +{ + GST_DEBUG (GST_CAT_PROPERTIES, "destroy entry %p", entry); + + gst_props_entry_clean (entry); + + gst_mem_chunk_free (_gst_props_entries_chunk, entry); + gst_alloc_trace_free (_entries_trace, entry); } /** @@ -347,18 +362,53 @@ gst_props_empty_new (void) { GstProps *props; - g_mutex_lock (_gst_props_chunk_lock); - props = g_mem_chunk_alloc (_gst_props_chunk); - g_mutex_unlock (_gst_props_chunk_lock); + props = gst_mem_chunk_alloc (_gst_props_chunk); + gst_alloc_trace_new (_props_trace, props); + + GST_DEBUG (GST_CAT_PROPERTIES, "new %p", props); props->properties = NULL; props->refcount = 1; - props->fixed = TRUE; + GST_PROPS_FLAG_SET (props, GST_PROPS_FLOATING); + GST_PROPS_FLAG_SET (props, GST_PROPS_FIXED); return props; } /** + * gst_props_replace: + * @oldprops: the props to take replace + * @newprops: the props to take replace + * + * Replace the pointer to the props, doing proper + * refcounting. + */ +void +gst_props_replace (GstProps **oldprops, GstProps *newprops) +{ + if (*oldprops != newprops) { + if (newprops) gst_props_ref (newprops); + if (*oldprops) gst_props_unref (*oldprops); + + *oldprops = newprops; + } +} + +/** + * gst_props_replace_sink: + * @oldprops: the props to take replace + * @newprops: the props to take replace + * + * Replace the pointer to the props and take ownership. + */ +void +gst_props_replace_sink (GstProps **oldprops, GstProps *newprops) +{ + gst_props_replace (oldprops, newprops); + gst_props_sink (newprops); +} + +/** * gst_props_add_entry: * @props: the property to add the entry to * @entry: the entry to add @@ -371,13 +421,53 @@ gst_props_add_entry (GstProps *props, GstPropsEntry *entry) g_return_if_fail (props); g_return_if_fail (entry); - if (props->fixed && GST_PROPS_ENTRY_IS_VARIABLE (entry)) { - props->fixed = FALSE; + if (GST_PROPS_IS_FIXED (props) && GST_PROPS_ENTRY_IS_VARIABLE (entry)) { + GST_PROPS_FLAG_UNSET (props, GST_PROPS_FIXED); } props->properties = g_list_insert_sorted (props->properties, entry, props_compare_func); } /** + * gst_props_remove_entry: + * @props: the property to remove the entry from + * @entry: the entry to remove + * + * Removes the given propsentry from the props. + */ +void +gst_props_remove_entry (GstProps *props, GstPropsEntry *entry) +{ + g_return_if_fail (props != NULL); + g_return_if_fail (entry != NULL); + + props->properties = g_list_remove (props->properties, entry); +} + +/** + * gst_props_remove_entry_by_name: + * @props: the property to remove the entry from + * @name: the name of the entry to remove + * + * Removes the propsentry with the given name from the props. + */ +void +gst_props_remove_entry_by_name (GstProps *props, const gchar *name) +{ + GList *lentry; + GQuark quark; + + g_return_if_fail (props != NULL); + g_return_if_fail (name != NULL); + + quark = g_quark_from_string (name); + + lentry = g_list_find_custom (props->properties, GINT_TO_POINTER (quark), props_find_func); + if (lentry) { + gst_props_remove_entry (props, (GstPropsEntry *)lentry->data); + } +} + +/** * gst_props_new: * @firstname: the first property name * @...: the property values @@ -413,6 +503,8 @@ gst_props_debug (GstProps *props) { GList *propslist = props->properties; + GST_DEBUG (GST_CAT_PROPERTIES, "props %p, refcount %d, flags %d", props, props->refcount, props->flags); + while (propslist) { GstPropsEntry *entry = (GstPropsEntry *)propslist->data; @@ -434,7 +526,7 @@ gst_props_debug (GstProps *props) * Returns: TRUE if the entries were merged, FALSE otherwise. */ static gboolean -gst_props_merge_int_entries(GstPropsEntry * newentry, GstPropsEntry * oldentry) +gst_props_merge_int_entries(GstPropsEntry *newentry, GstPropsEntry *oldentry) { gint new_min, new_max, old_min, old_max; gboolean can_merge = FALSE; @@ -501,21 +593,20 @@ gst_props_merge_int_entries(GstPropsEntry * newentry, GstPropsEntry * oldentry) * * Returns: a pointer to a list with the new entry added. */ -static GList * -gst_props_add_to_int_list (GList * entries, GstPropsEntry * newentry) +static GList* +gst_props_add_to_int_list (GList *entries, GstPropsEntry *newentry) { - GList * i; + GList *i; i = entries; while (i) { - GstPropsEntry * oldentry = (GstPropsEntry *)(i->data); + GstPropsEntry *oldentry = (GstPropsEntry *)(i->data); gboolean merged = gst_props_merge_int_entries(newentry, oldentry); if (merged) { /* replace the existing one with the merged one */ - g_mutex_lock (_gst_props_entries_chunk_lock); - g_mem_chunk_free (_gst_props_entries_chunk, oldentry); - g_mutex_unlock (_gst_props_entries_chunk_lock); + gst_props_entry_destroy (oldentry); + entries = g_list_remove_link (entries, i); g_list_free_1 (i); @@ -634,30 +725,24 @@ gst_props_newv (const gchar *firstname, va_list var_args) /* if list was of size 1, replace the list by a the item it contains */ if (g_list_length(list_entry->data.list_data.entries) == 1) { - GstPropsEntry * subentry = (GstPropsEntry *)(list_entry->data.list_data.entries->data); + GstPropsEntry *subentry = (GstPropsEntry *)(list_entry->data.list_data.entries->data); list_entry->propstype = subentry->propstype; list_entry->data = subentry->data; - g_mutex_lock (_gst_props_entries_chunk_lock); - g_mem_chunk_free (_gst_props_entries_chunk, subentry); - g_mutex_unlock (_gst_props_entries_chunk_lock); + gst_props_entry_destroy (subentry); } else { list_entry->data.list_data.entries = g_list_reverse (list_entry->data.list_data.entries); } - g_mutex_lock (_gst_props_entries_chunk_lock); - g_mem_chunk_free (_gst_props_entries_chunk, entry); - g_mutex_unlock (_gst_props_entries_chunk_lock); + gst_props_entry_destroy (entry); inlist = FALSE; list_entry = NULL; prop_name = va_arg (var_args, gchar*); continue; default: g_warning ("unknown property type found %d for '%s'\n", entry->propstype, prop_name); - g_mutex_lock (_gst_props_entries_chunk_lock); - g_mem_chunk_free (_gst_props_entries_chunk, entry); - g_mutex_unlock (_gst_props_entries_chunk_lock); + gst_props_entry_destroy (entry); break; } @@ -721,9 +806,8 @@ gst_props_set (GstProps *props, const gchar *name, ...) entry = (GstPropsEntry *)lentry->data; va_start (var_args, name); - + gst_props_entry_clean (entry); GST_PROPS_ENTRY_FILL (entry, var_args); - va_end (var_args); } else { @@ -740,17 +824,27 @@ gst_props_set (GstProps *props, const gchar *name, ...) * * Decrease the refcount of the property structure, destroying * the property if the refcount is 0. + * + * Returns: handle to unrefed props or NULL when it was + * destroyed. */ -void +GstProps* gst_props_unref (GstProps *props) { if (props == NULL) - return; + return NULL; + g_return_val_if_fail (props->refcount > 0, NULL); + + GST_DEBUG (GST_CAT_PROPERTIES, "unref %p (%d->%d)", props, props->refcount, props->refcount-1); props->refcount--; - if (props->refcount == 0) + if (props->refcount == 0) { gst_props_destroy (props); + return NULL; + } + + return props; } /** @@ -758,15 +852,44 @@ gst_props_unref (GstProps *props) * @props: the props to ref * * Increase the refcount of the property structure. + * + * Returns: handle to refed props. */ -void +GstProps* gst_props_ref (GstProps *props) { - g_return_if_fail (props != NULL); + if (props == NULL) + return NULL; + + g_return_val_if_fail (props->refcount > 0, NULL); + + GST_DEBUG (GST_CAT_PROPERTIES, "ref %p (%d->%d)", props, props->refcount, props->refcount+1); props->refcount++; + + return props; } +/** + * gst_props_sink: + * @props: the props to sink + * + * If the props if floating, decrease its refcount. Usually used + * with gst_props_ref() to take ownership of the props. + */ +void +gst_props_sink (GstProps *props) +{ + if (props == NULL) + return; + + GST_DEBUG (GST_CAT_PROPERTIES, "sink %p", props); + + if (GST_PROPS_IS_FLOATING (props)) { + GST_PROPS_FLAG_UNSET (props, GST_PROPS_FLOATING); + gst_props_unref (props); + } +} /** * gst_props_destroy: @@ -791,26 +914,31 @@ gst_props_destroy (GstProps *props) } g_list_free (props->properties); - g_mutex_lock (_gst_props_chunk_lock); - g_mem_chunk_free (_gst_props_chunk, props); - g_mutex_unlock (_gst_props_chunk_lock); + gst_mem_chunk_free (_gst_props_chunk, props); + gst_alloc_trace_free (_props_trace, props); } /* * copy entries */ GstPropsEntry* -gst_props_entry_copy (GstPropsEntry *entry) +gst_props_entry_copy (const GstPropsEntry *entry) { GstPropsEntry *newentry; newentry = gst_props_alloc_entry (); memcpy (newentry, entry, sizeof (GstPropsEntry)); - if (entry->propstype == GST_PROPS_LIST_TYPE) { - newentry->data.list_data.entries = gst_props_list_copy (entry->data.list_data.entries); - } - else if (entry->propstype == GST_PROPS_STRING_TYPE) { - newentry->data.string_data.string = g_strdup (entry->data.string_data.string); + + switch (entry->propstype) { + case GST_PROPS_LIST_TYPE: + newentry->data.list_data.entries = gst_props_list_copy (entry->data.list_data.entries); + break; + case GST_PROPS_STRING_TYPE: + newentry->data.string_data.string = g_strdup (entry->data.string_data.string); + break; + default: + /* FIXME more? */ + break; } return newentry; @@ -852,7 +980,7 @@ gst_props_copy (GstProps *props) new = gst_props_empty_new (); new->properties = gst_props_list_copy (props->properties); - new->fixed = props->fixed; + GST_PROPS_FLAGS (new) = GST_PROPS_FLAGS (props) | GST_PROPS_FLOATING; return new; } @@ -1076,7 +1204,7 @@ gst_props_getv (GstProps *props, gboolean safe, gchar *first_name, va_list var_a gboolean result; if (!entry) return FALSE; - GST_PROPS_ENTRY_READ (entry, var_args, FALSE, &result); + GST_PROPS_ENTRY_READ (entry, var_args, safe, &result); if (!result) return FALSE; first_name = va_arg (var_args, gchar *); @@ -1091,8 +1219,9 @@ gst_props_getv (GstProps *props, gboolean safe, gchar *first_name, va_list var_a * @...: a pointer to a datastructure that can hold the value. * * Gets the contents of the props into given key/value pairs. + * Make sure you pass a NULL terminated list. * - * Returns: TRUE is the props entry could be fetched. + * Returns: TRUE if all of the props entries could be fetched. */ gboolean gst_props_get (GstProps *props, gchar *first_name, ...) @@ -1115,7 +1244,7 @@ gst_props_get (GstProps *props, gchar *first_name, ...) * * Gets the contents of the props into given key/value pairs. * - * Returns: TRUE is the props entry could be fetched. + * Returns: TRUE if all of the props entries could be fetched. */ gboolean gst_props_get_safe (GstProps *props, gchar *first_name, ...) @@ -1138,7 +1267,7 @@ gst_props_get_safe (GstProps *props, gchar *first_name, ...) * Get the contents of the entry into the given gint. * * Returns: TRUE is the value could be fetched. FALSE if the - * entry is not of given type. + * entry is not of given type or did not exist. */ gboolean gst_props_entry_get_int (const GstPropsEntry *entry, gint *val) @@ -1154,7 +1283,7 @@ gst_props_entry_get_int (const GstPropsEntry *entry, gint *val) * Get the contents of the entry into the given gfloat. * * Returns: TRUE is the value could be fetched. FALSE if the - * entry is not of given type. + * entry is not of given type or did not exist. */ gboolean gst_props_entry_get_float (const GstPropsEntry *entry, gfloat *val) @@ -1170,7 +1299,7 @@ gst_props_entry_get_float (const GstPropsEntry *entry, gfloat *val) * Get the contents of the entry into the given guint32. * * Returns: TRUE is the value could be fetched. FALSE if the - * entry is not of given type. + * entry is not of given type or did not exist. */ gboolean gst_props_entry_get_fourcc_int (const GstPropsEntry *entry, guint32 *val) @@ -1186,7 +1315,7 @@ gst_props_entry_get_fourcc_int (const GstPropsEntry *entry, guint32 *val) * Get the contents of the entry into the given gboolean. * * Returns: TRUE is the value could be fetched. FALSE if the - * entry is not of given type. + * entry is not of given type or did not exist. */ gboolean gst_props_entry_get_boolean (const GstPropsEntry *entry, gboolean *val) @@ -1202,7 +1331,7 @@ gst_props_entry_get_boolean (const GstPropsEntry *entry, gboolean *val) * Get the contents of the entry into the given gchar*. * * Returns: TRUE is the value could be fetched. FALSE if the - * entry is not of given type. + * entry is not of given type or did not exist. */ gboolean gst_props_entry_get_string (const GstPropsEntry *entry, const gchar **val) @@ -1219,7 +1348,7 @@ gst_props_entry_get_string (const GstPropsEntry *entry, const gchar **val) * Get the contents of the entry into the given gints. * * Returns: TRUE is the value could be fetched. FALSE if the - * entry is not of given type. + * entry is not of given type or did not exist. */ gboolean gst_props_entry_get_int_range (const GstPropsEntry *entry, gint *min, gint *max) @@ -1236,7 +1365,7 @@ gst_props_entry_get_int_range (const GstPropsEntry *entry, gint *min, gint *max) * Get the contents of the entry into the given gfloats. * * Returns: TRUE is the value could be fetched. FALSE if the - * entry is not of given type. + * entry is not of given type or did not exist. */ gboolean gst_props_entry_get_float_range (const GstPropsEntry *entry, gfloat *min, gfloat *max) @@ -1252,7 +1381,7 @@ gst_props_entry_get_float_range (const GstPropsEntry *entry, gfloat *min, gfloat * Get the contents of the entry into the given GList. * * Returns: TRUE is the value could be fetched. FALSE if the - * entry is not of given type. + * entry is not of given type or did not exist. */ gboolean gst_props_entry_get_list (const GstPropsEntry *entry, const GList **val) @@ -1530,7 +1659,7 @@ gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2) if (intersectentry) { if (intersectentry->propstype == GST_PROPS_LIST_TYPE) { intersection = g_list_concat (intersection, - g_list_copy (intersectentry->data.list_data.entries)); + intersectentry->data.list_data.entries); /* set the list to NULL because the entries are concatenated to the above * list and we don't want to free them */ intersectentry->data.list_data.entries = NULL; @@ -1590,7 +1719,7 @@ gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2) result->propstype = GST_PROPS_LIST_TYPE; result->data.list_data.entries = NULL; while (entries) { - GstPropsEntry * this = (GstPropsEntry *)entries->data; + GstPropsEntry *this = (GstPropsEntry *)entries->data; if (this->propstype != GST_PROPS_INT_TYPE) { /* no hope, this list doesn't even contain ints! */ gst_props_entry_destroy (result); @@ -1598,18 +1727,24 @@ gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2) break; } if (this->data.int_data >= entry1->data.int_range_data.min && - this->data.int_data <= entry1->data.int_range_data.max) { - result->data.list_data.entries = g_list_append (result->data.list_data.entries, - gst_props_entry_copy (this)); + this->data.int_data <= entry1->data.int_range_data.max) + { + /* prepend and reverse at the end */ + result->data.list_data.entries = g_list_prepend (result->data.list_data.entries, + gst_props_entry_copy (this)); } entries = g_list_next (entries); } + if (result) { + result->data.list_data.entries = g_list_reverse (result->data.list_data.entries); + } break; } case GST_PROPS_INT_TYPE: { if (entry1->data.int_range_data.min <= entry2->data.int_data && - entry1->data.int_range_data.max >= entry2->data.int_data) { + entry1->data.int_range_data.max >= entry2->data.int_data) + { result = gst_props_entry_copy (entry2); } break; @@ -1644,7 +1779,8 @@ gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2) } case GST_PROPS_FLOAT_TYPE: if (entry1->data.float_range_data.min <= entry2->data.float_data && - entry1->data.float_range_data.max >= entry2->data.float_data) { + entry1->data.float_range_data.max >= entry2->data.float_data) + { result = gst_props_entry_copy (entry2); } default: @@ -1706,6 +1842,17 @@ gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2) return result; } +/* when running over the entries in sorted order we can + * optimize addition with _prepend and a reverse at the end */ +#define gst_props_entry_add_sorted_prepend(props, entry) \ +G_STMT_START { \ + /* avoid double evaluation of input */ \ + GstPropsEntry *toadd = (entry); \ + if (GST_PROPS_ENTRY_IS_VARIABLE (toadd)) \ + GST_PROPS_FLAG_UNSET ((props), GST_PROPS_FIXED); \ + props->properties = g_list_prepend ((props)->properties, toadd); \ +} G_STMT_END + /** * gst_props_intersect: * @props1: a property @@ -1714,7 +1861,8 @@ gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2) * Calculates the intersection bewteen two GstProps. * * Returns: a GstProps with the intersection or NULL if the - * intersection is empty. + * intersection is empty. The new GstProps is floating and must + * be unreffed afetr use. */ GstProps* gst_props_intersect (GstProps *props1, GstProps *props2) @@ -1725,11 +1873,10 @@ gst_props_intersect (GstProps *props1, GstProps *props2) GList *leftovers; GstPropsEntry *iprops = NULL; - intersection = gst_props_empty_new (); - intersection->fixed = TRUE; - g_return_val_if_fail (props1 != NULL, NULL); g_return_val_if_fail (props2 != NULL, NULL); + + intersection = gst_props_empty_new (); props1list = props1->properties; props2list = props2->properties; @@ -1742,74 +1889,47 @@ gst_props_intersect (GstProps *props1, GstProps *props2) entry2 = (GstPropsEntry *)props2list->data; while (entry1->propid < entry2->propid) { - GstPropsEntry *toadd; - - /* FIXME: this needs more explanation; - * I've had format "int" < format "int" ! */ - GST_DEBUG (GST_CAT_PROPERTIES, "source is more specific in \"%s\"", - g_quark_to_string (entry1->propid)); - - toadd = gst_props_entry_copy (entry1); - if (GST_PROPS_ENTRY_IS_VARIABLE (toadd)) - intersection->fixed = FALSE; - - intersection->properties = g_list_prepend (intersection->properties, toadd); + gst_props_entry_add_sorted_prepend (intersection, gst_props_entry_copy (entry1)); props1list = g_list_next (props1list); - if (props1list) - entry1 = (GstPropsEntry *)props1list->data; - else + if (!props1list) goto end; + + entry1 = (GstPropsEntry *)props1list->data; } while (entry1->propid > entry2->propid) { - GstPropsEntry *toadd; - - toadd = gst_props_entry_copy (entry2); - if (GST_PROPS_ENTRY_IS_VARIABLE (toadd)) - intersection->fixed = FALSE; - - intersection->properties = g_list_prepend (intersection->properties, toadd); + gst_props_entry_add_sorted_prepend (intersection, gst_props_entry_copy (entry2)); props2list = g_list_next (props2list); - if (props2list) - entry2 = (GstPropsEntry *)props2list->data; - else + if (!props2list) goto end; + + entry2 = (GstPropsEntry *)props2list->data; } /* at this point we are talking about the same property */ iprops = gst_props_entry_intersect (entry1, entry2); - - if (iprops) { - if (GST_PROPS_ENTRY_IS_VARIABLE (iprops)) - intersection->fixed = FALSE; - intersection->properties = g_list_prepend (intersection->properties, iprops); - } - else { + if (!iprops) { + /* common properties did not intersect, intersection is empty */ gst_props_unref (intersection); return NULL; } + gst_props_entry_add_sorted_prepend (intersection, iprops); + props1list = g_list_next (props1list); props2list = g_list_next (props2list); } end: - /* at this point one of the lists could contain leftover properties */ - if (props1list) - leftovers = props1list; - else if (props2list) + /* at this point one of the lists could contain leftover properties, while + * the other one is NULL */ + leftovers = props1list; + if (!leftovers) leftovers = props2list; - else - leftovers = NULL; while (leftovers) { - GstPropsEntry *entry; - - entry = (GstPropsEntry *) leftovers->data; - if (GST_PROPS_ENTRY_IS_VARIABLE (entry)) - intersection->fixed = FALSE; - intersection->properties = g_list_prepend (intersection->properties, gst_props_entry_copy (entry)); - + gst_props_entry_add_sorted_prepend (intersection, + gst_props_entry_copy ((GstPropsEntry *) leftovers->data)); leftovers = g_list_next (leftovers); } @@ -1825,7 +1945,8 @@ end: * Unrolls all lists in the given GstProps. This is usefull if you * want to loop over the props. * - * Returns: A GList with the unrolled props entries. + * Returns: A GList with the unrolled props entries. g_list_free + * after usage. */ GList* gst_props_normalize (GstProps *props) @@ -1850,11 +1971,11 @@ gst_props_normalize (GstProps *props) GstProps *newprops; GList *lentry; - newprops = gst_props_empty_new (); - newprops->properties = gst_props_list_copy (props->properties); + /* FIXME fixed flags is probably messed up here */ + newprops = gst_props_copy (props); lentry = g_list_find_custom (newprops->properties, GINT_TO_POINTER (list_entry->propid), props_find_func); if (lentry) { - GList *new_list = NULL; + GList *new_list; new_entry = (GstPropsEntry *) lentry->data; memcpy (new_entry, list_entry, sizeof (GstPropsEntry)); @@ -1863,6 +1984,7 @@ gst_props_normalize (GstProps *props) result = g_list_concat (new_list, result); } else { + /* FIXME append or prepend */ result = g_list_append (result, newprops); } @@ -1875,11 +1997,11 @@ gst_props_normalize (GstProps *props) entries = g_list_next (entries); } if (!result) { + /* no result, create list with input props */ result = g_list_prepend (result, props); } else { result = g_list_reverse (result); - gst_props_unref (props); } return result; } @@ -2073,9 +2195,7 @@ gst_props_load_thyself_func (xmlNodePtr field) entry->data.string_data.string = xmlGetProp (field, "value"); } else { - g_mutex_lock (_gst_props_entries_chunk_lock); - g_mem_chunk_free (_gst_props_entries_chunk, entry); - g_mutex_unlock (_gst_props_entries_chunk_lock); + gst_props_entry_destroy (entry); entry = NULL; } diff --git a/gst/gstprops.h b/gst/gstprops.h index c03ea59..11b355d 100644 --- a/gst/gstprops.h +++ b/gst/gstprops.h @@ -33,6 +33,8 @@ G_BEGIN_DECLS typedef struct _GstProps GstProps; extern GType _gst_props_type; +#define GST_PROPS_TRACE_NAME "GstProps" + #define GST_TYPE_PROPS (_gst_props_type) typedef enum { @@ -78,56 +80,91 @@ typedef enum { #define GST_PROPS_INT_NEGATIVE GST_PROPS_INT_RANGE(G_MININT,0) #define GST_PROPS_INT_ANY GST_PROPS_INT_RANGE(G_MININT,G_MAXINT) +/* propsentries are private */ typedef struct _GstPropsEntry GstPropsEntry; extern GType _gst_props_entry_type; +#define GST_PROPS_ENTRY_TRACE_NAME "GstPropsEntry" + #define GST_TYPE_PROPS_ENTRY (_gst_props_entry_type) +typedef enum { + GST_PROPS_FIXED = (1 << 0), /* props has no variable entries */ + GST_PROPS_FLOATING = (1 << 1) /* props is floating */ +} GstPropsFlags; + +#define GST_PROPS_FLAGS(props) ((props)->flags) +#define GST_PROPS_FLAG_IS_SET(props,flag) (GST_PROPS_FLAGS (props) & flag) +#define GST_PROPS_FLAG_SET(props,flag) (GST_PROPS_FLAGS (props) |= (flag)) +#define GST_PROPS_FLAG_UNSET(props,flag) (GST_PROPS_FLAGS (props) &= ~(flag)) + +#define GST_PROPS_REFCOUNT(props) ((props)->refcount) +#define GST_PROPS_PROPERTIES(props) ((props)->properties) + +#define GST_PROPS_IS_FIXED(props) (GST_PROPS_FLAGS (props) & GST_PROPS_FIXED) +#define GST_PROPS_IS_FLOATING(props) (GST_PROPS_FLAGS (props) & GST_PROPS_FLOATING) + struct _GstProps { - gint refcount; - gboolean fixed; + gint refcount; + gint flags; - GList *properties; /* real properties for this property */ + GList *properties; /* real property entries for this property */ }; /* initialize the subsystem */ void _gst_props_initialize (void); +/* creating new properties */ GstProps* gst_props_new (const gchar *firstname, ...); GstProps* gst_props_newv (const gchar *firstname, va_list var_args); GstProps* gst_props_empty_new (void); -void gst_props_unref (GstProps *props); -void gst_props_ref (GstProps *props); +/* replace pointer to props, doing proper refcounting */ +void gst_props_replace (GstProps **oldprops, GstProps *newprops); +void gst_props_replace_sink (GstProps **oldprops, GstProps *newprops); + +/* lifecycle management */ +GstProps* gst_props_unref (GstProps *props); +GstProps* gst_props_ref (GstProps *props); +void gst_props_sink (GstProps *props); void gst_props_destroy (GstProps *props); +/* dump property debug info to the log */ void gst_props_debug (GstProps *props); +/* copy */ GstProps* gst_props_copy (GstProps *props); GstProps* gst_props_copy_on_write (GstProps *props); -GstProps* gst_props_merge (GstProps *props, GstProps *tomerge); - +/* check if fromprops is subset of toprops */ gboolean gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops); + +/* operation on props */ +GstProps* gst_props_merge (GstProps *props, GstProps *tomerge); GstProps* gst_props_intersect (GstProps *props1, GstProps *props2); GList* gst_props_normalize (GstProps *props); +/* modify entries */ GstProps* gst_props_set (GstProps *props, const gchar *name, ...); gboolean gst_props_get (GstProps *props, gchar *first_name, ...); gboolean gst_props_get_safe (GstProps *props, gchar *first_name, ...); +/* query entries */ gboolean gst_props_has_property (GstProps *props, const gchar *name); gboolean gst_props_has_property_typed (GstProps *props, const gchar *name, GstPropsType type); gboolean gst_props_has_fixed_property (GstProps *props, const gchar *name); +/* add/get entries */ const GstPropsEntry* gst_props_get_entry (GstProps *props, const gchar *name); void gst_props_add_entry (GstProps *props, GstPropsEntry *entry); +void gst_props_remove_entry (GstProps *props, GstPropsEntry *entry); +void gst_props_remove_entry_by_name (GstProps *props, const gchar *name); /* working with props entries */ GstPropsEntry* gst_props_entry_new (const gchar *name, ...); void gst_props_entry_destroy (GstPropsEntry *entry); -GstPropsEntry* gst_props_entry_copy (GstPropsEntry *entry); +GstPropsEntry* gst_props_entry_copy (const GstPropsEntry *entry); GstPropsType gst_props_entry_get_type (const GstPropsEntry *entry); const gchar* gst_props_entry_get_name (const GstPropsEntry *entry); gboolean gst_props_entry_is_fixed (const GstPropsEntry *entry); -- 2.7.4