#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;
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,
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
{
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
*
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);
{
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);
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);
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++;
}
/**
+ * 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)
*
* Copies the caps.
*
- * Returns: a copy of the GstCaps structure.
+ * Returns: a floating copy of the GstCaps structure.
*/
GstCaps*
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)
{
g_return_if_fail (caps != NULL);
- if (caps->name)
- g_free (caps->name);
-
+ g_free (caps->name);
caps->name = g_strdup (name);
}
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;
}
}
/**
+ * 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
while (caps->next) {
caps = caps->next;
}
- caps->next = capstoadd;
+ gst_caps_replace_sink (&caps->next, capstoadd);
return orig;
}
while (capstoadd->next) {
capstoadd = capstoadd->next;
}
- capstoadd->next = caps;
+ gst_caps_replace_sink (&capstoadd->next, caps);
return orig;
}
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;
* 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)
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) {
}
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;
* 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;
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) {
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);
}
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 */
};
}
#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);
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
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);
}
*/
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++;
}
/* 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 */
*/
gboolean
gst_pad_can_link_filtered (GstPad *srcpad, GstPad *sinkpad,
- GstCaps *filtercaps)
+ GstCaps *filtercaps)
{
GstRealPad *realsrc, *realsink;
/* 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;
/* 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;
}
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);
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);
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 */
}
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");
}
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;
}
* @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.
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
{
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 */
{
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;
}
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",
* 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",
(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;
filtered_intersection = gst_caps_intersect (intersection,
filtercaps);
- /* get rid of the old intersection here */
gst_caps_unref (intersection);
if (!filtered_intersection) {
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:");
/* 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));
}
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);
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));
"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;
}
/**
g_return_val_if_fail (GST_RPAD_PEER (realsink) == realsrc, FALSE);
return gst_pad_try_relink_filtered_func (realsrc, realsink,
- filtercaps, TRUE);
+ filtercaps, TRUE);
}
/**
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;
}
*
* 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)
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);
*
* 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)
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;
}
*
* 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)
if (!caps)
return NULL;
- return gst_caps_get_by_name (caps, name);
+ return gst_caps_ref (gst_caps_get_by_name (caps, name));
}
/**
* 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)
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;
}
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;
}
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)))));
*/
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)
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 = "*";
}
{
}
+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
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;
}
*
* 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));
}
/**
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);
#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)))
#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);
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);
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);
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,
(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
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) {
}
}
next:
+ gst_caps_unref (caps);
l = g_list_next (l);
}
#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 {
} 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);
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;
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;
}
}
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,
_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
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;
}
break;
default:
- g_warning ("unknown property type %d", entry->propstype);
+ g_warning ("unknown property type %d at %p", entry->propstype, entry);
break;
}
}
{
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:
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);
}
/**
{
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
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
{
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;
* 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;
*
* 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);
/* 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;
}
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 {
*
* 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;
}
/**
* @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:
}
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;
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;
}
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 *);
* @...: 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, ...)
*
* 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, ...)
* 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)
* 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)
* 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)
* 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)
* 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)
* 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)
* 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)
* 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)
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;
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);
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;
}
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:
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
* 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)
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;
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);
}
* 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)
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));
result = g_list_concat (new_list, result);
}
else {
+ /* FIXME append or prepend */
result = g_list_append (result, newprops);
}
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;
}
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;
}
typedef struct _GstProps GstProps;
extern GType _gst_props_type;
+#define GST_PROPS_TRACE_NAME "GstProps"
+
#define GST_TYPE_PROPS (_gst_props_type)
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);