- 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
This commit is contained in:
Wim Taymans 2003-02-02 19:58:11 +00:00
parent f05a353f5c
commit 6ad8197d61
8 changed files with 710 additions and 314 deletions

View file

@ -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,23 +141,62 @@ 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,20 +298,46 @@ 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++;
return 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;
}
@ -473,6 +549,23 @@ gst_caps_get_props (GstCaps *caps)
return caps->properties;
}
/**
* 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
@ -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);
}

View file

@ -30,28 +30,43 @@ G_BEGIN_DECLS
typedef struct _GstCaps GstCaps;
#define GST_CAPS_TRACE_NAME "GstCaps"
extern GType _gst_caps_type;
#define GST_TYPE_CAPS (_gst_caps_type)
typedef enum {
GST_CAPS_FIXED = (1 << 0), /* caps has no variable properties */
GST_CAPS_FLOATING = (1 << 1) /* caps is floating */
} GstCapsFlags;
#define GST_CAPS(caps) ((GstCaps *)(caps))
#define GST_CAPS_IS_FIXED(caps) ((caps)->fixed)
#define GST_CAPS_IS_CHAINED(caps) ((caps)->next)
#define GST_CAPS_FLAGS(caps) ((caps)->flags)
#define GST_CAPS_FLAG_IS_SET(caps,flag) (GST_CAPS_FLAGS (caps) & flag)
#define GST_CAPS_FLAG_SET(caps,flag) (GST_CAPS_FLAGS (caps) |= (flag))
#define GST_CAPS_FLAG_UNSET(caps,flag) (GST_CAPS_FLAGS (caps) &= ~(flag))
#define GST_CAPS_REFCOUNT(caps) ((caps)->refcount)
#define GST_CAPS_PROPERTIES(caps) ((caps)->properties)
#define GST_CAPS_NEXT(caps) ((caps)->next)
#define GST_CAPS_IS_FIXED(caps) (GST_CAPS_FLAGS (caps) & GST_CAPS_FIXED)
#define GST_CAPS_IS_FLOATING(caps) (GST_CAPS_FLAGS (caps) & GST_CAPS_FLOATING)
#define GST_CAPS_IS_CHAINED(caps) (GST_CAPS_NEXT (caps) != NULL)
/* CR1: id is an int corresponding to the quark for the mime type because
* it's really fast when doing a first-pass check for caps compatibility */
struct _GstCaps {
/* --- public --- */
gchar *name; /* the name of this caps */
guint16 id; /* type id (major type) representing
the mime type */
guint16 id; /* type id (major type) representing
the mime type, it's stored as a GQuark
for speed/space reasons */
guint refcount;
gboolean fixed; /* this caps doesn't contain variable properties */
guint16 flags; /* flags */
guint refcount;
GstProps *properties; /* properties for this capability */
GstCaps *next; /* not with a GList for efficiency */
};
@ -97,21 +112,30 @@ factoryname (void) \
}
#endif
/* get caps from a factory */
#define GST_CAPS_GET(fact) (fact)()
/* initialize the subsystem */
void _gst_caps_initialize (void);
/* creating new caps */
GstCaps* gst_caps_new (const gchar *name, const gchar *mime, GstProps *props);
GstCaps* gst_caps_new_id (const gchar *name, const guint16 id, GstProps *props);
/* replace pointer to caps, doing proper refcounting */
void gst_caps_replace (GstCaps **oldcaps, GstCaps *newcaps);
void gst_caps_replace_sink (GstCaps **oldcaps, GstCaps *newcaps);
/* caps lifecycle control */
GstCaps* gst_caps_unref (GstCaps *caps);
GstCaps* gst_caps_ref (GstCaps *caps);
void gst_caps_sink (GstCaps *caps);
void gst_caps_destroy (GstCaps *caps);
/* write debug lines to the log */
void gst_caps_debug (GstCaps *caps, const gchar *label);
/* copy caps */
GstCaps* gst_caps_copy (GstCaps *caps);
GstCaps* gst_caps_copy_1 (GstCaps *caps);
GstCaps* gst_caps_copy_on_write (GstCaps *caps);
@ -148,12 +172,18 @@ GstProps* gst_caps_get_props (GstCaps *caps);
GstCaps* gst_caps_get_by_name (GstCaps *caps, const gchar *name);
/* use and construct chained caps */
GstCaps* gst_caps_next (GstCaps *caps);
GstCaps* gst_caps_chain (GstCaps *caps, ...);
GstCaps* gst_caps_append (GstCaps *caps, GstCaps *capstoadd);
GstCaps* gst_caps_prepend (GstCaps *caps, GstCaps *capstoadd);
/* see if fromcaps is a subset of tocaps */
gboolean gst_caps_is_always_compatible (GstCaps *fromcaps, GstCaps *tocaps);
/* operations on caps */
GstCaps* gst_caps_intersect (GstCaps *caps1, GstCaps *caps2);
GstCaps* gst_caps_union (GstCaps *caps1, GstCaps *caps2);
GstCaps* gst_caps_normalize (GstCaps *caps);
#ifndef GST_DISABLE_LOADSAVE

View file

@ -122,11 +122,27 @@ gst_element_details_free (GstElementDetails *dp)
static void
gst_element_factory_cleanup (GstElementFactory *factory)
{
GList *padtemplates;
if (factory->details_dynamic) {
gst_element_details_free (factory->details);
factory->details_dynamic = FALSE;
}
padtemplates = factory->padtemplates;
while (padtemplates) {
GstPadTemplate *oldtempl = GST_PAD_TEMPLATE (padtemplates->data);
gst_object_unref (GST_OBJECT (oldtempl));
padtemplates = g_list_next (padtemplates);
}
g_list_free (factory->padtemplates);
factory->padtemplates = NULL;
factory->numpadtemplates = 0;
g_free (GST_PLUGIN_FEATURE (factory)->name);
}
@ -301,28 +317,14 @@ gst_element_factory_make_or_warn (const gchar *factoryname, const gchar *name)
*/
void
gst_element_factory_add_pad_template (GstElementFactory *factory,
GstPadTemplate *templ)
GstPadTemplate *templ)
{
GList *padtemplates;
g_return_if_fail (factory != NULL);
g_return_if_fail (templ != NULL);
padtemplates = factory->padtemplates;
gst_object_ref (GST_OBJECT (templ));
gst_object_sink (GST_OBJECT (templ));
while (padtemplates) {
GstPadTemplate *oldtempl = GST_PAD_TEMPLATE (padtemplates->data);
if (!strcmp (oldtempl->name_template, templ->name_template)) {
gst_object_unref (GST_OBJECT (oldtempl));
padtemplates->data = templ;
return;
}
padtemplates = g_list_next (padtemplates);
}
factory->padtemplates = g_list_append (factory->padtemplates, templ);
factory->numpadtemplates++;
}

View file

@ -842,15 +842,15 @@ gst_pad_unlink (GstPad *srcpad,
/* reset the filters, both filters are refcounted once */
if (GST_RPAD_FILTER (realsrc)) {
gst_caps_unref (GST_RPAD_FILTER (realsrc));
GST_RPAD_FILTER (realsink) = NULL;
GST_RPAD_FILTER (realsrc) = NULL;
gst_caps_replace (&GST_RPAD_FILTER (realsink), NULL);
gst_caps_replace (&GST_RPAD_FILTER (realsrc), NULL);
}
/* now tell the scheduler */
if (src_sched && src_sched == sink_sched) {
gst_scheduler_pad_unlink (src_sched,
GST_PAD_CAST (realsrc), GST_PAD_CAST (realsink));
GST_PAD_CAST (realsrc),
GST_PAD_CAST (realsink));
}
/* hold a reference, as they can go away in the signal handlers */
@ -906,7 +906,7 @@ gst_pad_check_schedulers (GstRealPad *realsrc, GstRealPad *realsink)
*/
gboolean
gst_pad_can_link_filtered (GstPad *srcpad, GstPad *sinkpad,
GstCaps *filtercaps)
GstCaps *filtercaps)
{
GstRealPad *realsrc, *realsink;
@ -1041,7 +1041,7 @@ gst_pad_link_filtered (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps)
/* try to negotiate the pads, we don't need to clear the caps here */
if (!gst_pad_try_relink_filtered_func (realsrc, realsink,
filtercaps, FALSE)) {
filtercaps, FALSE)) {
GST_DEBUG (GST_CAT_CAPS, "relink_filtered_func failed, can't link");
GST_RPAD_PEER (realsrc) = NULL;
@ -1063,13 +1063,11 @@ gst_pad_link_filtered (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps)
/* now tell the scheduler */
if (src_sched && src_sched == sink_sched) {
gst_scheduler_pad_link (src_sched,
GST_PAD_CAST (realsrc), GST_PAD_CAST (realsink));
GST_PAD_CAST (realsrc), GST_PAD_CAST (realsink));
}
GST_INFO (GST_CAT_PADS, "linked %s:%s and %s:%s, successful",
GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (sinkpad));
gst_caps_debug (gst_pad_get_caps (GST_PAD_CAST (realsrc)),
"caps of newly linked src pad");
return TRUE;
}
@ -1271,7 +1269,7 @@ gst_pad_get_ghost_pad_list (GstPad *pad)
static GstPadLinkReturn
gst_pad_try_set_caps_func (GstRealPad *pad, GstCaps *caps, gboolean notify)
{
GstCaps *oldcaps, *allowed = NULL;
GstCaps *allowed = NULL;
GstPadTemplate *template;
GstElement *parent = GST_PAD_PARENT (pad);
@ -1290,8 +1288,9 @@ gst_pad_try_set_caps_func (GstRealPad *pad, GstCaps *caps, gboolean notify)
GST_INFO (GST_CAT_CAPS, "trying to set caps %p on pad %s:%s",
caps, GST_DEBUG_PAD_NAME (pad));
/* first see if we have to check against a filter */
if (!(allowed = GST_RPAD_FILTER (pad))) {
/* first see if we have to check against a filter, we ref the caps here as we're
* going to unref it later on */
if (!(allowed = gst_caps_ref (GST_RPAD_FILTER (pad)))) {
/* no filter, make sure we check against the padtemplate then */
if ((template = gst_pad_get_pad_template (GST_PAD_CAST (pad)))) {
allowed = gst_pad_template_get_caps (template);
@ -1312,10 +1311,12 @@ gst_pad_try_set_caps_func (GstRealPad *pad, GstCaps *caps, gboolean notify)
gst_caps_debug (caps, "caps themselves (attemped to set)");
gst_caps_debug (allowed,
"allowed caps that did not agree with caps");
gst_caps_unref (allowed);
return GST_PAD_LINK_REFUSED;
}
/* caps checks out fine, we can unref the intersection now */
gst_caps_unref (intersection);
gst_caps_unref (allowed);
/* given that the caps are fixed, we know that their intersection with the
* padtemplate caps is the same as caps itself */
}
@ -1383,10 +1384,7 @@ gst_pad_try_set_caps_func (GstRealPad *pad, GstCaps *caps, gboolean notify)
GST_INFO (GST_CAT_CAPS, "setting caps on pad %s:%s",
GST_DEBUG_PAD_NAME (pad));
/* if we got this far all is ok, remove the old caps, set the new one */
oldcaps = GST_PAD_CAPS (pad);
if (caps) gst_caps_ref (caps);
GST_PAD_CAPS (pad) = caps;
if (oldcaps) gst_caps_unref (oldcaps);
gst_caps_replace_sink (&GST_PAD_CAPS (pad), caps);
g_object_notify (G_OBJECT (pad), "caps");
}
@ -1394,6 +1392,8 @@ gst_pad_try_set_caps_func (GstRealPad *pad, GstCaps *caps, gboolean notify)
GST_INFO (GST_CAT_CAPS,
"caps are not fixed on pad %s:%s, not setting them yet",
GST_DEBUG_PAD_NAME (pad));
return GST_PAD_LINK_DELAYED;
}
return GST_PAD_LINK_OK;
}
@ -1403,7 +1403,8 @@ gst_pad_try_set_caps_func (GstRealPad *pad, GstCaps *caps, gboolean notify)
* @pad: a #GstPad to try to set the caps on.
* @caps: the #GstCaps to set.
*
* Tries to set the caps on the given pad.
* Tries to set the caps on the given pad. Ownership is always taken
* of the caps, so you will need to unref non-floating caps.
*
* Returns: A #GstPadLinkReturn value indicating whether the caps
* could be set.
@ -1422,15 +1423,21 @@ gst_pad_try_set_caps (GstPad *pad, GstCaps *caps)
gst_caps_debug (caps, "caps that we are trying to set");
/* try to take ownership */
gst_caps_ref (caps);
gst_caps_sink (caps);
/* setting non fixed caps on a pad is not allowed */
if (!GST_CAPS_IS_FIXED (caps)) {
GST_INFO (GST_CAT_CAPS,
"trying to set unfixed caps on pad %s:%s, not allowed",
GST_DEBUG_PAD_NAME (realpad));
GST_INFO (GST_CAT_CAPS,
"trying to set unfixed caps on pad %s:%s, not allowed",
GST_DEBUG_PAD_NAME (realpad));
g_warning ("trying to set non fixed caps on pad %s:%s, not allowed",
GST_DEBUG_PAD_NAME (realpad));
gst_caps_debug (caps, "unfixed caps");
return GST_PAD_LINK_DELAYED;
set_retval = GST_PAD_LINK_DELAYED;
goto done;
}
/* if we have a peer try to set the caps, notifying the peerpad
@ -1439,7 +1446,7 @@ gst_pad_try_set_caps (GstPad *pad, GstCaps *caps)
{
GST_INFO (GST_CAT_CAPS, "tried to set caps on peerpad %s:%s but couldn't, return value %d",
GST_DEBUG_PAD_NAME (peer), set_retval);
return set_retval;
goto done;
}
/* then try to set our own caps, we don't need to be notified */
@ -1447,12 +1454,16 @@ gst_pad_try_set_caps (GstPad *pad, GstCaps *caps)
{
GST_INFO (GST_CAT_CAPS, "tried to set own caps on pad %s:%s but couldn't, return value %d",
GST_DEBUG_PAD_NAME (realpad), set_retval);
return set_retval;
goto done;
}
GST_INFO (GST_CAT_CAPS, "succeeded setting caps %p on pad %s:%s, return value %d",
caps, GST_DEBUG_PAD_NAME (realpad), set_retval);
g_assert (GST_PAD_CAPS (pad));
done:
/* if we took ownership, the caps will be freed */
gst_caps_unref (caps);
return set_retval;
}
@ -1486,10 +1497,10 @@ gst_pad_try_relink_filtered_func (GstRealPad *srcpad, GstRealPad *sinkpad,
GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
/* FIXME does this leak? */
GST_PAD_CAPS (GST_PAD (realsrc)) = NULL;
GST_PAD_CAPS (GST_PAD (realsink)) = NULL;
GST_RPAD_FILTER (realsrc) = NULL;
GST_RPAD_FILTER (realsink) = NULL;
gst_caps_replace (&GST_PAD_CAPS (GST_PAD (realsrc)), NULL);
gst_caps_replace (&GST_PAD_CAPS (GST_PAD (realsink)), NULL);
gst_caps_replace (&GST_RPAD_FILTER (realsrc), NULL);
gst_caps_replace (&GST_RPAD_FILTER (realsink), NULL);
}
else {
GST_INFO (GST_CAT_PADS, "start relink filtered %s:%s and %s:%s",
@ -1515,6 +1526,9 @@ gst_pad_try_relink_filtered_func (GstRealPad *srcpad, GstRealPad *sinkpad,
* this means they have no common format */
GST_INFO (GST_CAT_PADS, "pads %s:%s and %s:%s have no common type",
GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
/* make sure any floating caps from gst_pad_get_caps are freed here */
gst_caps_sink (srccaps);
gst_caps_sink (sinkcaps);
return FALSE;
} else {
GST_INFO (GST_CAT_PADS, "pads %s:%s and %s:%s intersected to %s caps",
@ -1523,6 +1537,10 @@ gst_pad_try_relink_filtered_func (GstRealPad *srcpad, GstRealPad *sinkpad,
(GST_CAPS_IS_FIXED (intersection) ? "fixed" : "variable") :
"NULL"));
/* we don't need those anymore, as the caps can be floating */
gst_caps_sink (srccaps);
gst_caps_sink (sinkcaps);
/* then filter this against the app filter */
if (filtercaps) {
GstCaps *filtered_intersection;
@ -1530,7 +1548,6 @@ gst_pad_try_relink_filtered_func (GstRealPad *srcpad, GstRealPad *sinkpad,
filtered_intersection = gst_caps_intersect (intersection,
filtercaps);
/* get rid of the old intersection here */
gst_caps_unref (intersection);
if (!filtered_intersection) {
@ -1542,8 +1559,8 @@ gst_pad_try_relink_filtered_func (GstRealPad *srcpad, GstRealPad *sinkpad,
intersection = filtered_intersection;
/* keep a reference to the app caps */
GST_RPAD_APPFILTER (realsink) = filtercaps;
GST_RPAD_APPFILTER (realsrc) = filtercaps;
gst_caps_replace_sink (&GST_RPAD_APPFILTER (realsink), filtercaps);
gst_caps_replace_sink (&GST_RPAD_APPFILTER (realsrc), filtercaps);
}
}
GST_DEBUG (GST_CAT_CAPS, "setting filter for link to:");
@ -1551,8 +1568,9 @@ gst_pad_try_relink_filtered_func (GstRealPad *srcpad, GstRealPad *sinkpad,
/* both the app filter and the filter, while stored on both peer pads,
* are equal to the same thing on both */
GST_RPAD_FILTER (realsrc) = intersection;
GST_RPAD_FILTER (realsink) = intersection;
gst_caps_replace_sink (&GST_RPAD_FILTER (realsrc), intersection);
gst_caps_replace_sink (&GST_RPAD_FILTER (realsink), intersection);
gst_caps_unref (intersection);
return gst_pad_perform_negotiate (GST_PAD (realsrc), GST_PAD (realsink));
}
@ -1572,6 +1590,9 @@ gst_pad_perform_negotiate (GstPad *srcpad, GstPad *sinkpad)
GstCaps *intersection, *filtered_intersection;
GstRealPad *realsrc, *realsink;
GstCaps *srccaps, *sinkcaps, *filter;
gboolean res = TRUE;
GstElement *parent;
g_return_val_if_fail (srcpad != NULL, FALSE);
g_return_val_if_fail (sinkpad != NULL, FALSE);
@ -1582,6 +1603,20 @@ gst_pad_perform_negotiate (GstPad *srcpad, GstPad *sinkpad)
g_return_val_if_fail (GST_RPAD_PEER (realsrc) != NULL, FALSE);
g_return_val_if_fail (GST_RPAD_PEER (realsink) == realsrc, FALSE);
/* shortcut negotiation */
parent = GST_PAD_PARENT (realsrc);
if (parent && GST_STATE (parent) < GST_STATE_READY) {
GST_DEBUG (GST_CAT_CAPS, "parent %s of pad %s:%s is not READY",
GST_ELEMENT_NAME (parent), GST_DEBUG_PAD_NAME (realsrc));
return TRUE;
}
parent = GST_PAD_PARENT (realsink);
if (parent && GST_STATE (parent) < GST_STATE_READY) {
GST_DEBUG (GST_CAT_CAPS, "parent %s of pad %s:%s is not READY",
GST_ELEMENT_NAME (parent), GST_DEBUG_PAD_NAME (realsink));
return TRUE;
}
GST_INFO (GST_CAT_PADS, "perform negotiate for link %s:%s-%s:%s",
GST_DEBUG_PAD_NAME (realsrc), GST_DEBUG_PAD_NAME (realsink));
@ -1605,28 +1640,39 @@ gst_pad_perform_negotiate (GstPad *srcpad, GstPad *sinkpad)
"sink caps, awaiting negotiation, after applying filter");
intersection = gst_caps_intersect (srccaps, sinkcaps);
filtered_intersection = gst_caps_intersect (intersection, filter);
if (filtered_intersection) {
gst_caps_unref (intersection);
intersection = filtered_intersection;
}
gst_caps_unref (intersection);
/* no negotiation is performed if the pads have filtercaps */
if (intersection) {
GstPadLinkReturn res;
if (filtered_intersection) {
GstPadLinkReturn link_res;
res = gst_pad_try_set_caps_func (realsrc, intersection, TRUE);
if (res == GST_PAD_LINK_REFUSED)
return FALSE;
if (res == GST_PAD_LINK_DONE)
return TRUE;
link_res = gst_pad_try_set_caps_func (realsrc, filtered_intersection, TRUE);
if (link_res == GST_PAD_LINK_REFUSED)
goto error;
if (link_res == GST_PAD_LINK_DONE)
goto success;
res = gst_pad_try_set_caps_func (realsink, intersection, TRUE);
if (res == GST_PAD_LINK_REFUSED)
return FALSE;
if (res == GST_PAD_LINK_DONE)
return TRUE;
link_res = gst_pad_try_set_caps_func (realsink, filtered_intersection, TRUE);
if (link_res == GST_PAD_LINK_REFUSED)
goto error;
if (link_res == GST_PAD_LINK_DONE)
goto success;
}
return TRUE;
/* no filtered_intersection, some pads had caps and ther was a filter */
else if ((srccaps || sinkcaps) && filter) {
goto error;
}
success:
cleanup:
gst_caps_sink (srccaps);
gst_caps_sink (sinkcaps);
gst_caps_unref (filtered_intersection);
return res;
error:
res = FALSE;
goto cleanup;
}
/**
@ -1656,7 +1702,7 @@ gst_pad_try_relink_filtered (GstPad *srcpad, GstPad *sinkpad,
g_return_val_if_fail (GST_RPAD_PEER (realsink) == realsrc, FALSE);
return gst_pad_try_relink_filtered_func (realsrc, realsink,
filtercaps, TRUE);
filtercaps, TRUE);
}
/**
@ -1686,8 +1732,9 @@ gst_pad_relink_filtered (GstPad *srcpad, GstPad *sinkpad,
g_return_val_if_fail (GST_RPAD_PEER (realsrc) != NULL, FALSE);
g_return_val_if_fail (GST_RPAD_PEER (realsink) == realsrc, FALSE);
if (! gst_pad_try_relink_filtered_func (realsrc, realsink,
filtercaps, TRUE)) {
if (!gst_pad_try_relink_filtered_func (realsrc, realsink,
filtercaps, TRUE))
{
gst_pad_unlink (srcpad, GST_PAD (GST_PAD_PEER (srcpad)));
return FALSE;
}
@ -1729,7 +1776,9 @@ gst_pad_proxy_link (GstPad *pad, GstCaps *caps)
*
* Gets the capabilities of this pad.
*
* Returns: the #GstCaps of this pad.
* Returns: the #GstCaps of this pad. This function potentially
* returns a floating caps, so use gst_caps_sink to get rid of
* it.
*/
GstCaps*
gst_pad_get_caps (GstPad *pad)
@ -1744,6 +1793,8 @@ gst_pad_get_caps (GstPad *pad)
GST_DEBUG (GST_CAT_CAPS, "get pad caps of %s:%s (%p)",
GST_DEBUG_PAD_NAME (realpad), realpad);
/* note that we will not _ref the caps here as this function might be
* called recursively */
if (GST_PAD_CAPS (realpad)) {
GST_DEBUG (GST_CAT_CAPS, "using pad real caps %p", GST_PAD_CAPS (realpad));
return GST_PAD_CAPS (realpad);
@ -1769,7 +1820,8 @@ gst_pad_get_caps (GstPad *pad)
*
* Gets the template capabilities of this pad.
*
* Returns: the template #GstCaps of this pad.
* Returns: the template #GstCaps of this pad, unref the caps
* if you no longer need it.
*/
GstCaps*
gst_pad_get_pad_template_caps (GstPad *pad)
@ -1778,7 +1830,7 @@ gst_pad_get_pad_template_caps (GstPad *pad)
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
if (GST_PAD_PAD_TEMPLATE (pad))
return GST_PAD_TEMPLATE_CAPS (GST_PAD_PAD_TEMPLATE (pad));
return gst_caps_ref (GST_PAD_TEMPLATE_CAPS (GST_PAD_PAD_TEMPLATE (pad)));
return NULL;
}
@ -1790,7 +1842,8 @@ gst_pad_get_pad_template_caps (GstPad *pad)
*
* Gets the capability with the given name from this pad template.
*
* Returns: the #GstCaps, or NULL if not found or in case of an error.
* Returns: the #GstCaps, or NULL if not found or in case of an error. unref
* the caps if you no longer need it.
*/
GstCaps*
gst_pad_template_get_caps_by_name (GstPadTemplate *templ, const gchar *name)
@ -1803,7 +1856,7 @@ gst_pad_template_get_caps_by_name (GstPadTemplate *templ, const gchar *name)
if (!caps)
return NULL;
return gst_caps_get_by_name (caps, name);
return gst_caps_ref (gst_caps_get_by_name (caps, name));
}
/**
@ -1866,7 +1919,8 @@ gst_pad_get_peer (GstPad *pad)
* Gets the capabilities of the allowed media types that can
* flow through this pad. The caller must free the resulting caps.
*
* Returns: a newly allocated copy of the allowed #GstCaps.
* Returns: the allowed #GstCaps of the pad link. unref the caps if
* you no longer need it.
*/
GstCaps*
gst_pad_get_allowed_caps (GstPad *pad)
@ -1879,7 +1933,7 @@ gst_pad_get_allowed_caps (GstPad *pad)
GST_DEBUG (GST_CAT_PROPERTIES, "get allowed caps of %s:%s",
GST_DEBUG_PAD_NAME (pad));
caps = gst_caps_copy (GST_RPAD_FILTER (pad));
caps = gst_caps_ref (GST_RPAD_FILTER (pad));
return caps;
}
@ -1909,7 +1963,7 @@ gst_pad_recalc_allowed_caps (GstPad *pad)
peer = GST_RPAD_PEER (pad);
if (peer)
return gst_pad_try_relink_filtered (pad, GST_PAD (peer),
GST_RPAD_APPFILTER (pad));
GST_RPAD_APPFILTER (pad));
return TRUE;
}
@ -1992,6 +2046,9 @@ gst_real_pad_dispose (GObject *object)
g_list_free (GST_REAL_PAD(pad)->ghostpads);
}
gst_caps_replace (&GST_PAD_CAPS (pad), NULL);
gst_caps_replace (&GST_RPAD_APPFILTER (pad), NULL);
if (GST_IS_ELEMENT (GST_OBJECT_PARENT (pad))) {
GST_DEBUG (GST_CAT_REFCOUNTING, "removing pad from element '%s'",
GST_OBJECT_NAME (GST_OBJECT (GST_ELEMENT (GST_OBJECT_PARENT (pad)))));
@ -2319,6 +2376,7 @@ gst_pad_selectv (GstPad *pad, ...)
*/
static void gst_pad_template_class_init (GstPadTemplateClass *klass);
static void gst_pad_template_init (GstPadTemplate *templ);
static void gst_pad_template_dispose (GObject *object);
GType
gst_pad_template_get_type (void)
@ -2356,6 +2414,8 @@ gst_pad_template_class_init (GstPadTemplateClass *klass)
NULL, NULL, gst_marshal_VOID__POINTER, G_TYPE_NONE, 1,
G_TYPE_POINTER);
gobject_class->dispose = gst_pad_template_dispose;
gstobject_class->path_string_separator = "*";
}
@ -2364,6 +2424,17 @@ gst_pad_template_init (GstPadTemplate *templ)
{
}
static void
gst_pad_template_dispose (GObject *object)
{
GstPadTemplate *templ = GST_PAD_TEMPLATE (object);
g_free (GST_PAD_TEMPLATE_NAME_TEMPLATE (templ));
gst_caps_unref (GST_PAD_TEMPLATE_CAPS (templ));
G_OBJECT_CLASS (padtemplate_parent_class)->dispose (object);
}
/* ALWAYS padtemplates cannot have conversion specifications, it doesn't make
* sense.
* SOMETIMES padtemplates can do whatever they want, they are provided by the
@ -2442,14 +2513,19 @@ gst_pad_template_new (const gchar *name_template,
va_start (var_args, caps);
GST_FLAG_SET (GST_OBJECT (new), GST_PAD_TEMPLATE_FIXED);
while (caps) {
new->fixed &= caps->fixed;
thecaps = gst_caps_append (thecaps, gst_caps_ref (caps));
if (!GST_CAPS_IS_FIXED (caps)) {
GST_FLAG_UNSET (GST_OBJECT (new), GST_PAD_TEMPLATE_FIXED);
}
thecaps = gst_caps_append (thecaps, caps);
caps = va_arg (var_args, GstCaps*);
}
va_end (var_args);
GST_PAD_TEMPLATE_CAPS (new) = thecaps;
gst_caps_ref (thecaps);
gst_caps_sink (thecaps);
return new;
}
@ -2460,14 +2536,15 @@ gst_pad_template_new (const gchar *name_template,
*
* Gets the capabilities of the pad template.
*
* Returns: the #GstCaps of the pad template.
* Returns: the #GstCaps of the pad template. unref the caps
* after use.
*/
GstCaps*
gst_pad_template_get_caps (GstPadTemplate *templ)
{
g_return_val_if_fail (templ != NULL, NULL);
return GST_PAD_TEMPLATE_CAPS (templ);
return gst_caps_ref (GST_PAD_TEMPLATE_CAPS (templ));
}
/**

View file

@ -146,7 +146,7 @@ typedef const GstFormat* (*GstPadFormatsFunction) (GstPad *pad);
typedef const GstEventMask* (*GstPadEventMaskFunction) (GstPad *pad);
typedef const GstQueryType* (*GstPadQueryTypeFunction) (GstPad *pad);
typedef GstPadLinkReturn (*GstPadLinkFunction) (GstPad *pad, GstCaps *caps);
typedef GstPadLinkReturn (*GstPadLinkFunction) (GstPad *pad, GstCaps *caps);
typedef GstCaps* (*GstPadGetCapsFunction) (GstPad *pad, GstCaps *caps);
typedef GstBufferPool* (*GstPadBufferPoolFunction) (GstPad *pad);
@ -276,7 +276,7 @@ struct _GstGhostPadClass {
#define GST_PAD_PEER(pad) GST_PAD_CAST(GST_RPAD_PEER(GST_PAD_REALIZE(pad)))
/* Some check functions (unused?) */
#define GST_PAD_IS_LINKED(pad) (GST_PAD_PEER(pad) != NULL)
#define GST_PAD_IS_LINKED(pad) (GST_PAD_PEER(pad) != NULL)
#define GST_PAD_IS_ACTIVE(pad) (!GST_FLAG_IS_SET(GST_PAD_REALIZE(pad), GST_PAD_DISABLED))
#define GST_PAD_IS_USABLE(pad) (GST_PAD_IS_LINKED (pad) && \
GST_PAD_IS_ACTIVE(pad) && GST_PAD_IS_ACTIVE(GST_PAD_PEER (pad)))
@ -301,22 +301,26 @@ typedef enum {
#define GST_PAD_TEMPLATE_DIRECTION(templ) (((GstPadTemplate *)(templ))->direction)
#define GST_PAD_TEMPLATE_PRESENCE(templ) (((GstPadTemplate *)(templ))->presence)
#define GST_PAD_TEMPLATE_CAPS(templ) (((GstPadTemplate *)(templ))->caps)
#define GST_PAD_TEMPLATE_FIXED(templ) (((GstPadTemplate *)(templ))->fixed)
#define GST_PAD_TEMPLATE_IS_FIXED(templ) (GST_PAD_TEMPLATE_FIXED(templ) == TRUE)
typedef enum {
GST_PAD_TEMPLATE_FIXED = GST_OBJECT_FLAG_LAST,
GST_PAD_TEMPLATE_FLAG_LAST = GST_OBJECT_FLAG_LAST + 4
} GstPadTemplateFlags;
#define GST_PAD_TEMPLATE_IS_FIXED(templ) (GST_FLAG_IS_SET(templ), GST_PAD_TEMPLATE_FIXED)
struct _GstPadTemplate {
GstObject object;
GstObject object;
gchar *name_template;
GstPadDirection direction;
GstPadPresence presence;
GstPadDirection direction;
GstPadPresence presence;
GstCaps *caps;
gboolean fixed;
};
struct _GstPadTemplateClass {
GstObjectClass parent_class;
GstObjectClass parent_class;
/* signal callbacks */
void (*pad_created) (GstPadTemplate *templ, GstPad *pad);
@ -425,7 +429,7 @@ gboolean gst_pad_can_link_filtered (GstPad *srcpad, GstPad *s
gboolean gst_pad_link (GstPad *srcpad, GstPad *sinkpad);
gboolean gst_pad_link_filtered (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps);
void gst_pad_unlink (GstPad *srcpad, GstPad *sinkpad);
void gst_pad_unlink (GstPad *srcpad, GstPad *sinkpad);
GstPad* gst_pad_get_peer (GstPad *pad);
@ -437,7 +441,7 @@ gboolean gst_pad_check_compatibility (GstPad *srcpad, GstPad *sinkpad);
void gst_pad_set_getcaps_function (GstPad *pad, GstPadGetCapsFunction getcaps);
GstPadLinkReturn gst_pad_proxy_link (GstPad *pad, GstCaps *caps);
gboolean gst_pad_relink_filtered (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps);
gboolean gst_pad_relink_filtered (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps);
gboolean gst_pad_perform_negotiate (GstPad *srcpad, GstPad *sinkpad);
gboolean gst_pad_try_relink_filtered (GstPad *srcpad, GstPad *sinkpad, GstCaps *filtercaps);
GstCaps* gst_pad_get_allowed_caps (GstPad *pad);
@ -475,9 +479,9 @@ gboolean gst_pad_query (GstPad *pad, GstQueryType type,
gboolean gst_pad_query_default (GstPad *pad, GstQueryType type,
GstFormat *format, gint64 *value);
void gst_pad_set_internal_link_function(GstPad *pad, GstPadIntLinkFunction intlink);
GList* gst_pad_get_internal_links (GstPad *pad);
GList* gst_pad_get_internal_links_default (GstPad *pad);
void gst_pad_set_internal_link_function (GstPad *pad, GstPadIntLinkFunction intlink);
GList* gst_pad_get_internal_links (GstPad *pad);
GList* gst_pad_get_internal_links_default (GstPad *pad);
/* misc helper functions */
gboolean gst_pad_dispatcher (GstPad *pad, GstPadDispatcherFunction dispatch,
@ -489,7 +493,7 @@ gboolean gst_pad_dispatcher (GstPad *pad, GstPadDispatcherFunction dispatch
(gst_probe_dispatcher_remove_probe (&(GST_REAL_PAD (pad)-probedisp), probe))
#ifndef GST_DISABLE_LOADSAVE
void gst_pad_load_and_link (xmlNodePtr self, GstObject *parent);
void gst_pad_load_and_link (xmlNodePtr self, GstObject *parent);
#endif

View file

@ -262,6 +262,9 @@ make_links (graph_t *g, GError **error)
a = c->src_pads;
b = c->sink_pads;
caps = c->caps;
gst_caps_ref (caps);
gst_caps_sink (caps);
gst_caps_debug (caps, "foo");
/* g_print ("a: %p, b: %p\n", a, b); */
if (a && b) {
@ -363,6 +366,7 @@ make_links (graph_t *g, GError **error)
}
}
next:
gst_caps_unref (caps);
l = g_list_next (l);
}

View file

@ -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,17 +362,52 @@ 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
@ -371,12 +421,52 @@ 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
@ -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;
}

View file

@ -33,6 +33,8 @@ G_BEGIN_DECLS
typedef struct _GstProps GstProps;
extern GType _gst_props_type;
#define GST_PROPS_TRACE_NAME "GstProps"
#define GST_TYPE_PROPS (_gst_props_type)
typedef enum {
@ -78,56 +80,91 @@ typedef enum {
#define GST_PROPS_INT_NEGATIVE GST_PROPS_INT_RANGE(G_MININT,0)
#define GST_PROPS_INT_ANY GST_PROPS_INT_RANGE(G_MININT,G_MAXINT)
/* propsentries are private */
typedef struct _GstPropsEntry GstPropsEntry;
extern GType _gst_props_entry_type;
#define GST_PROPS_ENTRY_TRACE_NAME "GstPropsEntry"
#define GST_TYPE_PROPS_ENTRY (_gst_props_entry_type)
struct _GstProps {
gint refcount;
gboolean fixed;
typedef enum {
GST_PROPS_FIXED = (1 << 0), /* props has no variable entries */
GST_PROPS_FLOATING = (1 << 1) /* props is floating */
} GstPropsFlags;
GList *properties; /* real properties for this property */
#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;
gint flags;
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);