gst: Add a filter caps parameter to all get_caps() functions

This is used to pass the possible caps and preferences to
the pad and to allow better negotiation decisions.
This commit is contained in:
Sebastian Dröge 2011-05-10 17:56:33 +02:00
parent bdbc069348
commit 3fa1594aaf
6 changed files with 126 additions and 38 deletions

View file

@ -84,6 +84,10 @@ The 0.11 porting guide
Removed GST_PAD_CAPS() use gst_pad_get_current_caps() to get a handle to the Removed GST_PAD_CAPS() use gst_pad_get_current_caps() to get a handle to the
currently configured caps. currently configured caps.
GstPadGetCapsFunction, gst_pad_get_caps(), gst_pad_peer_get_caps(),
gst_pad_proxy_getcaps() now takes a GstCaps* parameter to inform
the other side about the possible caps and preferences.
* GstMiniObject * GstMiniObject
A miniobject is now a simple refcounted structure holding the information A miniobject is now a simple refcounted structure holding the information
common to buffers, events, messages, queries and caps. common to buffers, events, messages, queries and caps.

View file

@ -188,7 +188,7 @@ gst_proxy_pad_do_checkgetrange (GstPad * pad)
} }
static GstCaps * static GstCaps *
gst_proxy_pad_do_getcaps (GstPad * pad) gst_proxy_pad_do_getcaps (GstPad * pad, GstCaps * filter)
{ {
GstPad *target = gst_proxy_pad_get_target (pad); GstPad *target = gst_proxy_pad_get_target (pad);
GstCaps *res; GstCaps *res;
@ -196,7 +196,7 @@ gst_proxy_pad_do_getcaps (GstPad * pad)
if (target) { if (target) {
/* if we have a real target, proxy the call */ /* if we have a real target, proxy the call */
res = gst_pad_get_caps (target); res = gst_pad_get_caps (target, filter);
GST_DEBUG_OBJECT (pad, "get caps of target %s:%s : %" GST_PTR_FORMAT, GST_DEBUG_OBJECT (pad, "get caps of target %s:%s : %" GST_PTR_FORMAT,
GST_DEBUG_PAD_NAME (target), res); GST_DEBUG_PAD_NAME (target), res);
@ -209,7 +209,7 @@ gst_proxy_pad_do_getcaps (GstPad * pad)
filt = GST_PAD_TEMPLATE_CAPS (templ); filt = GST_PAD_TEMPLATE_CAPS (templ);
if (filt) { if (filt) {
tmp = gst_caps_intersect (filt, res); tmp = gst_caps_intersect_full (res, filt, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (res); gst_caps_unref (res);
res = tmp; res = tmp;
GST_DEBUG_OBJECT (pad, GST_DEBUG_OBJECT (pad,
@ -224,6 +224,15 @@ gst_proxy_pad_do_getcaps (GstPad * pad)
"using pad template %p with caps %p %" GST_PTR_FORMAT, templ, res, "using pad template %p with caps %p %" GST_PTR_FORMAT, templ, res,
res); res);
res = gst_caps_ref (res); res = gst_caps_ref (res);
if (filter) {
GstCaps *intersection =
gst_caps_intersect_full (filter, res, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (res);
res = intersection;
}
goto done; goto done;
} }

View file

@ -124,7 +124,7 @@ static void gst_pad_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec); GValue * value, GParamSpec * pspec);
static GstFlowReturn handle_pad_block (GstPad * pad); static GstFlowReturn handle_pad_block (GstPad * pad);
static GstCaps *gst_pad_get_caps_unlocked (GstPad * pad); static GstCaps *gst_pad_get_caps_unlocked (GstPad * pad, GstCaps * filter);
static void gst_pad_set_pad_template (GstPad * pad, GstPadTemplate * templ); static void gst_pad_set_pad_template (GstPad * pad, GstPadTemplate * templ);
static gboolean gst_pad_activate_default (GstPad * pad); static gboolean gst_pad_activate_default (GstPad * pad);
static gboolean gst_pad_acceptcaps_default (GstPad * pad, GstCaps * caps); static gboolean gst_pad_acceptcaps_default (GstPad * pad, GstCaps * caps);
@ -1796,8 +1796,8 @@ gst_pad_link_check_compatible_unlocked (GstPad * src, GstPad * sink,
/* Doing the expensive caps checking takes priority over only checking the template caps */ /* Doing the expensive caps checking takes priority over only checking the template caps */
if (flags & GST_PAD_LINK_CHECK_CAPS) { if (flags & GST_PAD_LINK_CHECK_CAPS) {
srccaps = gst_pad_get_caps_unlocked (src); srccaps = gst_pad_get_caps_unlocked (src, NULL);
sinkcaps = gst_pad_get_caps_unlocked (sink); sinkcaps = gst_pad_get_caps_unlocked (sink, NULL);
} else { } else {
/* If one of the two pads doesn't have a template, consider the intersection /* If one of the two pads doesn't have a template, consider the intersection
* as valid.*/ * as valid.*/
@ -2188,7 +2188,7 @@ gst_pad_get_pad_template (GstPad * pad)
/* should be called with the pad LOCK held */ /* should be called with the pad LOCK held */
/* refs the caps, so caller is responsible for getting it unreffed */ /* refs the caps, so caller is responsible for getting it unreffed */
static GstCaps * static GstCaps *
gst_pad_get_caps_unlocked (GstPad * pad) gst_pad_get_caps_unlocked (GstPad * pad, GstCaps * filter)
{ {
GstCaps *result = NULL; GstCaps *result = NULL;
GstPadTemplate *templ; GstPadTemplate *templ;
@ -2200,11 +2200,12 @@ gst_pad_get_caps_unlocked (GstPad * pad)
if (!fixed_caps && GST_PAD_GETCAPSFUNC (pad)) { if (!fixed_caps && GST_PAD_GETCAPSFUNC (pad)) {
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
"dispatching to pad getcaps function"); "dispatching to pad getcaps function with "
"filter %" GST_PTR_FORMAT, filter);
GST_OBJECT_FLAG_SET (pad, GST_PAD_IN_GETCAPS); GST_OBJECT_FLAG_SET (pad, GST_PAD_IN_GETCAPS);
GST_OBJECT_UNLOCK (pad); GST_OBJECT_UNLOCK (pad);
result = GST_PAD_GETCAPSFUNC (pad) (pad); result = GST_PAD_GETCAPSFUNC (pad) (pad, filter);
GST_OBJECT_LOCK (pad); GST_OBJECT_LOCK (pad);
GST_OBJECT_FLAG_UNSET (pad, GST_PAD_IN_GETCAPS); GST_OBJECT_FLAG_UNSET (pad, GST_PAD_IN_GETCAPS);
@ -2234,29 +2235,80 @@ gst_pad_get_caps_unlocked (GstPad * pad)
result = temp; result = temp;
} }
} }
if (filter) {
if (!gst_caps_is_subset (result, filter)) {
GstCaps *temp;
GST_CAT_ERROR_OBJECT (GST_CAT_CAPS, pad,
"pad returned caps %" GST_PTR_FORMAT
" which are not a real subset of the filter caps %"
GST_PTR_FORMAT, result, filter);
g_warning ("pad %s:%s returned caps which are not a real "
"subset of the filter caps", GST_DEBUG_PAD_NAME (pad));
/* FIXME: Order? But shouldn't happen anyway... */
temp =
gst_caps_intersect_full (filter, result,
GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (result);
result = temp;
}
}
#endif #endif
goto done; goto done;
} }
} }
if (fixed_caps && (result = get_pad_caps (pad))) { if (fixed_caps && (result = get_pad_caps (pad))) {
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, if (filter) {
"using pad caps %p %" GST_PTR_FORMAT, result, result); GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
result = gst_caps_ref (result); "using pad caps %p %" GST_PTR_FORMAT " with filter %p %"
GST_PTR_FORMAT, result, result, filter, filter);
result =
gst_caps_intersect_full (filter, result, GST_CAPS_INTERSECT_FIRST);
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "result %p %" GST_PTR_FORMAT,
result);
} else {
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
"using pad caps %p %" GST_PTR_FORMAT, result, result);
result = gst_caps_ref (result);
}
goto done; goto done;
} }
if ((templ = GST_PAD_PAD_TEMPLATE (pad))) { if ((templ = GST_PAD_PAD_TEMPLATE (pad))) {
result = GST_PAD_TEMPLATE_CAPS (templ); result = GST_PAD_TEMPLATE_CAPS (templ);
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
"using pad template %p with caps %p %" GST_PTR_FORMAT, templ, result,
result);
result = gst_caps_ref (result); if (filter) {
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
"using pad template %p with caps %p %" GST_PTR_FORMAT
" and filter %p %" GST_PTR_FORMAT, templ, result, result, filter,
filter);
result =
gst_caps_intersect_full (filter, result, GST_CAPS_INTERSECT_FIRST);
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "result %p %" GST_PTR_FORMAT,
result);
} else {
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
"using pad template %p with caps %p %" GST_PTR_FORMAT, templ, result,
result);
result = gst_caps_ref (result);
}
goto done; goto done;
} }
if (!fixed_caps && (result = get_pad_caps (pad))) { if (!fixed_caps && (result = get_pad_caps (pad))) {
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, if (filter) {
"using pad caps %p %" GST_PTR_FORMAT, result, result); GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
result = gst_caps_ref (result); "using pad caps %p %" GST_PTR_FORMAT " with filter %p %"
GST_PTR_FORMAT, result, result, filter, filter);
result =
gst_caps_intersect_full (filter, result, GST_CAPS_INTERSECT_FIRST);
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "result %p %" GST_PTR_FORMAT,
result);
} else {
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
"using pad caps %p %" GST_PTR_FORMAT, result, result);
result = gst_caps_ref (result);
}
goto done; goto done;
} }
@ -2319,6 +2371,7 @@ gst_pad_get_current_caps (GstPad * pad)
/** /**
* gst_pad_get_caps: * gst_pad_get_caps:
* @pad: a #GstPad to get the capabilities of. * @pad: a #GstPad to get the capabilities of.
* @filter: suggested #GstCaps.
* *
* Gets the capabilities this pad can produce or consume. * Gets the capabilities this pad can produce or consume.
* Note that this method doesn't necessarily return the caps set by * Note that this method doesn't necessarily return the caps set by
@ -2327,23 +2380,30 @@ gst_pad_get_current_caps (GstPad * pad)
* the pad's get_caps function; * the pad's get_caps function;
* this returns the pad template caps if not explicitly set. * this returns the pad template caps if not explicitly set.
* *
* When called on sinkpads @filter contains the caps that
* upstream could produce in the order preferred by upstream. When
* called on srcpads @filter contains the caps accepted by
* downstream in the preffered order. @filter might be %NULL but
* if it is not %NULL the returned caps will be a subset of @filter.
*
* Note that this function does not return writable #GstCaps, use * Note that this function does not return writable #GstCaps, use
* gst_caps_make_writable() before modifying the caps. * gst_caps_make_writable() before modifying the caps.
* *
* Returns: the caps of the pad with incremented ref-count. * Returns: the caps of the pad with incremented ref-count.
*/ */
GstCaps * GstCaps *
gst_pad_get_caps (GstPad * pad) gst_pad_get_caps (GstPad * pad, GstCaps * filter)
{ {
GstCaps *result = NULL; GstCaps *result = NULL;
g_return_val_if_fail (GST_IS_PAD (pad), NULL); g_return_val_if_fail (GST_IS_PAD (pad), NULL);
g_return_val_if_fail (filter == NULL || GST_IS_CAPS (filter), NULL);
GST_OBJECT_LOCK (pad); GST_OBJECT_LOCK (pad);
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "get pad caps"); GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "get pad caps");
result = gst_pad_get_caps_unlocked (pad); result = gst_pad_get_caps_unlocked (pad, filter);
GST_OBJECT_UNLOCK (pad); GST_OBJECT_UNLOCK (pad);
@ -2354,20 +2414,28 @@ gst_pad_get_caps (GstPad * pad)
/** /**
* gst_pad_peer_get_caps: * gst_pad_peer_get_caps:
* @pad: a #GstPad to get the capabilities of. * @pad: a #GstPad to get the capabilities of.
* @filter: a #GstCaps filter.
* *
* Gets the capabilities of the peer connected to this pad. Similar to * Gets the capabilities of the peer connected to this pad. Similar to
* gst_pad_get_caps(). * gst_pad_get_caps().
* *
* When called on srcpads @filter contains the caps that
* upstream could produce in the order preferred by upstream. When
* called on sinkpads @filter contains the caps accepted by
* downstream in the preffered order. @filter might be %NULL but
* if it is not %NULL the returned caps will be a subset of @filter.
*
* Returns: the caps of the peer pad with incremented ref-count. This function * Returns: the caps of the peer pad with incremented ref-count. This function
* returns %NULL when there is no peer pad. * returns %NULL when there is no peer pad.
*/ */
GstCaps * GstCaps *
gst_pad_peer_get_caps (GstPad * pad) gst_pad_peer_get_caps (GstPad * pad, GstCaps * filter)
{ {
GstPad *peerpad; GstPad *peerpad;
GstCaps *result = NULL; GstCaps *result = NULL;
g_return_val_if_fail (GST_IS_PAD (pad), NULL); g_return_val_if_fail (GST_IS_PAD (pad), NULL);
g_return_val_if_fail (filter == NULL || GST_IS_CAPS (filter), NULL);
GST_OBJECT_LOCK (pad); GST_OBJECT_LOCK (pad);
@ -2380,7 +2448,7 @@ gst_pad_peer_get_caps (GstPad * pad)
gst_object_ref (peerpad); gst_object_ref (peerpad);
GST_OBJECT_UNLOCK (pad); GST_OBJECT_UNLOCK (pad);
result = gst_pad_get_caps (peerpad); result = gst_pad_get_caps (peerpad, filter);
gst_object_unref (peerpad); gst_object_unref (peerpad);
@ -2503,7 +2571,7 @@ gst_pad_acceptcaps_default (GstPad * pad, GstCaps * caps)
GST_DEBUG_OBJECT (pad, "caps %" GST_PTR_FORMAT, caps); GST_DEBUG_OBJECT (pad, "caps %" GST_PTR_FORMAT, caps);
allowed = gst_pad_get_caps (pad); allowed = gst_pad_get_caps (pad, NULL);
if (!allowed) if (!allowed)
goto nothing_allowed; goto nothing_allowed;
@ -2826,9 +2894,9 @@ gst_pad_get_allowed_caps (GstPad * pad)
gst_object_ref (peer); gst_object_ref (peer);
GST_OBJECT_UNLOCK (pad); GST_OBJECT_UNLOCK (pad);
mycaps = gst_pad_get_caps (pad); mycaps = gst_pad_get_caps (pad, NULL);
peercaps = gst_pad_get_caps (peer); peercaps = gst_pad_get_caps (peer, NULL);
gst_object_unref (peer); gst_object_unref (peer);
caps = gst_caps_intersect (mycaps, peercaps); caps = gst_caps_intersect (mycaps, peercaps);

View file

@ -420,6 +420,13 @@ typedef void (*GstPadUnlinkFunction) (GstPad *pad);
/** /**
* GstPadGetCapsFunction: * GstPadGetCapsFunction:
* @pad: the #GstPad to get the capabilities of. * @pad: the #GstPad to get the capabilities of.
* @filter: filter #GstCaps.
*
* When called on sinkpads @filter contains the caps that
* upstream could produce in the order preferred by upstream. When
* called on srcpads @filter contains the caps accepted by
* downstream in the preffered order. @filter might be %NULL but if
* it is not %NULL only a subset of @filter must be returned.
* *
* Returns a copy of the capabilities of the specified pad. By default this * Returns a copy of the capabilities of the specified pad. By default this
* function will return the pad template capabilities, but can optionally * function will return the pad template capabilities, but can optionally
@ -427,7 +434,7 @@ typedef void (*GstPadUnlinkFunction) (GstPad *pad);
* *
* Returns: a newly allocated copy #GstCaps of the pad. * Returns: a newly allocated copy #GstCaps of the pad.
*/ */
typedef GstCaps* (*GstPadGetCapsFunction) (GstPad *pad); typedef GstCaps* (*GstPadGetCapsFunction) (GstPad *pad, GstCaps *filter);
/** /**
* GstPadSetCapsFunction: * GstPadSetCapsFunction:
@ -845,12 +852,12 @@ G_CONST_RETURN GstCaps* gst_pad_get_pad_template_caps (GstPad *pad);
/* capsnego function for linked/unlinked pads */ /* capsnego function for linked/unlinked pads */
GstCaps * gst_pad_get_current_caps (GstPad * pad); GstCaps * gst_pad_get_current_caps (GstPad * pad);
gboolean gst_pad_has_current_caps (GstPad * pad); gboolean gst_pad_has_current_caps (GstPad * pad);
GstCaps * gst_pad_get_caps (GstPad * pad); GstCaps * gst_pad_get_caps (GstPad * pad, GstCaps *filter);
void gst_pad_fixate_caps (GstPad * pad, GstCaps *caps); void gst_pad_fixate_caps (GstPad * pad, GstCaps *caps);
gboolean gst_pad_accept_caps (GstPad * pad, GstCaps *caps); gboolean gst_pad_accept_caps (GstPad * pad, GstCaps *caps);
gboolean gst_pad_set_caps (GstPad * pad, GstCaps *caps); gboolean gst_pad_set_caps (GstPad * pad, GstCaps *caps);
GstCaps * gst_pad_peer_get_caps (GstPad * pad); GstCaps * gst_pad_peer_get_caps (GstPad * pad, GstCaps *filter);
gboolean gst_pad_peer_accept_caps (GstPad * pad, GstCaps *caps); gboolean gst_pad_peer_accept_caps (GstPad * pad, GstCaps *caps);
/* capsnego for linked pads */ /* capsnego for linked pads */

View file

@ -1140,7 +1140,7 @@ gst_element_get_compatible_pad (GstElement * element, GstPad * pad,
gboolean compatible; gboolean compatible;
/* Now check if the two pads' caps are compatible */ /* Now check if the two pads' caps are compatible */
temp = gst_pad_get_caps (pad); temp = gst_pad_get_caps (pad, NULL);
if (caps) { if (caps) {
intersection = gst_caps_intersect (temp, caps); intersection = gst_caps_intersect (temp, caps);
gst_caps_unref (temp); gst_caps_unref (temp);
@ -1148,7 +1148,7 @@ gst_element_get_compatible_pad (GstElement * element, GstPad * pad,
intersection = temp; intersection = temp;
} }
temp = gst_pad_get_caps (current); temp = gst_pad_get_caps (current, NULL);
compatible = gst_caps_can_intersect (temp, intersection); compatible = gst_caps_can_intersect (temp, intersection);
gst_caps_unref (temp); gst_caps_unref (temp);
gst_caps_unref (intersection); gst_caps_unref (intersection);
@ -1198,7 +1198,7 @@ gst_element_get_compatible_pad (GstElement * element, GstPad * pad,
/* try to create a new one */ /* try to create a new one */
/* requesting is a little crazy, we need a template. Let's create one */ /* requesting is a little crazy, we need a template. Let's create one */
/* FIXME: why not gst_pad_get_pad_template (pad); */ /* FIXME: why not gst_pad_get_pad_template (pad); */
templcaps = gst_pad_get_caps (pad); templcaps = gst_pad_get_caps (pad, NULL);
templ = gst_pad_template_new ((gchar *) GST_PAD_NAME (pad), templ = gst_pad_template_new ((gchar *) GST_PAD_NAME (pad),
GST_PAD_DIRECTION (pad), GST_PAD_ALWAYS, templcaps); GST_PAD_DIRECTION (pad), GST_PAD_ALWAYS, templcaps);
@ -2691,16 +2691,15 @@ gst_buffer_join (GstBuffer * buf1, GstBuffer * buf2)
return result; return result;
} }
static gboolean static gboolean
getcaps_fold_func (const GValue * vpad, GValue * ret, GstPad * orig) getcaps_fold_func (const GValue * vpad, GValue * ret, GstCaps * filter)
{ {
GstPad *pad = g_value_get_object (vpad); GstPad *pad = g_value_get_object (vpad);
gboolean empty = FALSE; gboolean empty = FALSE;
GstCaps *peercaps, *existing; GstCaps *peercaps, *existing;
existing = g_value_get_pointer (ret); existing = g_value_get_pointer (ret);
peercaps = gst_pad_peer_get_caps (pad); peercaps = gst_pad_peer_get_caps (pad, filter);
if (G_LIKELY (peercaps)) { if (G_LIKELY (peercaps)) {
GstCaps *intersection = gst_caps_intersect (existing, peercaps); GstCaps *intersection = gst_caps_intersect (existing, peercaps);
@ -2716,6 +2715,7 @@ getcaps_fold_func (const GValue * vpad, GValue * ret, GstPad * orig)
/** /**
* gst_pad_proxy_getcaps: * gst_pad_proxy_getcaps:
* @pad: a #GstPad to proxy. * @pad: a #GstPad to proxy.
* @filter: a #GstCaps filter.
* *
* Calls gst_pad_get_allowed_caps() for every other pad belonging to the * Calls gst_pad_get_allowed_caps() for every other pad belonging to the
* same element as @pad, and returns the intersection of the results. * same element as @pad, and returns the intersection of the results.
@ -2729,7 +2729,7 @@ getcaps_fold_func (const GValue * vpad, GValue * ret, GstPad * orig)
* Returns: (transfer full): the intersection of the other pads' allowed caps. * Returns: (transfer full): the intersection of the other pads' allowed caps.
*/ */
GstCaps * GstCaps *
gst_pad_proxy_getcaps (GstPad * pad) gst_pad_proxy_getcaps (GstPad * pad, GstCaps * filter)
{ {
GstElement *element; GstElement *element;
GstCaps *caps, *intersected; GstCaps *caps, *intersected;
@ -2760,7 +2760,7 @@ gst_pad_proxy_getcaps (GstPad * pad)
while (1) { while (1) {
res = res =
gst_iterator_fold (iter, (GstIteratorFoldFunction) getcaps_fold_func, gst_iterator_fold (iter, (GstIteratorFoldFunction) getcaps_fold_func,
&ret, pad); &ret, filter);
switch (res) { switch (res) {
case GST_ITERATOR_RESYNC: case GST_ITERATOR_RESYNC:
/* unref any value stored */ /* unref any value stored */

View file

@ -907,7 +907,7 @@ void gst_element_class_install_std_props (GstElementClass * klass,
/* pad functions */ /* pad functions */
void gst_pad_use_fixed_caps (GstPad *pad); void gst_pad_use_fixed_caps (GstPad *pad);
GstCaps* gst_pad_proxy_getcaps (GstPad * pad); GstCaps* gst_pad_proxy_getcaps (GstPad * pad, GstCaps * filter);
gboolean gst_pad_proxy_setcaps (GstPad * pad, GstCaps * caps); gboolean gst_pad_proxy_setcaps (GstPad * pad, GstCaps * caps);
GstElement* gst_pad_get_parent_element (GstPad *pad); GstElement* gst_pad_get_parent_element (GstPad *pad);