Commit b5c3e254 authored by Wim Taymans's avatar Wim Taymans

pad: remove getcaps and use caps query

Remove the getcaps function on the pad and use the CAPS query for
the same effect.
Add PROXY_CAPS to the pad flags. This instructs the default caps event and query
handlers to pass on the CAPS related queries and events. This simplifies a lot
of elements that passtrough caps negotiation.
Make two utility functions to proxy caps queries and aggregate the result. Needs
to use the pad forward function instead later.
Make the _query_peer_ utility functions use the gst_pad_peer_query() function to
make sure the probes are emited properly.
parent d162d97e
......@@ -1014,7 +1014,6 @@ gst_proxy_pad_iterate_internal_links_default
gst_proxy_pad_chain_default
gst_proxy_pad_chain_list_default
gst_proxy_pad_getrange_default
gst_proxy_pad_getcaps_default
gst_proxy_pad_unlink_default
<SUBSECTION Standard>
GstGhostPadClass
......@@ -1643,9 +1642,8 @@ GstPadUnlinkFunction
gst_pad_accept_caps
gst_pad_set_getcaps_function
GstPadGetCapsFunction
gst_pad_proxy_getcaps
gst_pad_proxy_query_caps
gst_pad_proxy_query_accept_caps
gst_pad_peer_accept_caps
......
......@@ -161,15 +161,14 @@ debug_dump_pad (GstPad * pad, const gchar * color_name,
}
}
if (details & GST_DEBUG_GRAPH_SHOW_STATES) {
gchar pad_flags[5];
gchar pad_flags[4];
const gchar *activation_mode = "-><";
/* check if pad flags */
pad_flags[0] = GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_BLOCKED) ? 'B' : 'b';
pad_flags[1] = GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_FLUSHING) ? 'F' : 'f';
pad_flags[2] = GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_IN_GETCAPS) ? 'G' : 'g';
pad_flags[3] = GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_BLOCKING) ? 'B' : 'b';
pad_flags[4] = '\0';
pad_flags[2] = GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_BLOCKING) ? 'B' : 'b';
pad_flags[3] = '\0';
fprintf (out,
"%s %s_%s [color=black, fillcolor=\"%s\", label=\"%s\\n[%c][%s]\", height=\"0.2\", style=\"%s\"];\n",
......
......@@ -1267,7 +1267,7 @@ gst_element_class_add_pad_template (GstElementClass * klass,
}
/* Take ownership of the floating ref */
g_object_ref_sink (templ);
gst_object_ref_sink (templ);
klass->padtemplates = g_list_append (klass->padtemplates, templ);
klass->numpadtemplates++;
......
......@@ -92,6 +92,87 @@ gst_proxy_pad_event_default (GstPad * pad, GstEvent * event)
return res;
}
static gboolean
gst_proxy_pad_query_caps (GstPad * pad, GstQuery * query)
{
gboolean res;
GstPad *target;
GstCaps *result;
GstPadTemplate *templ;
g_return_val_if_fail (GST_IS_PROXY_PAD (pad), FALSE);
templ = GST_PAD_PAD_TEMPLATE (pad);
target = gst_proxy_pad_get_target (pad);
if (target) {
/* if we have a real target, proxy the call */
res = gst_pad_query (target, query);
GST_DEBUG_OBJECT (pad, "get caps of target %s:%s : %" GST_PTR_FORMAT,
GST_DEBUG_PAD_NAME (target), query);
gst_object_unref (target);
/* filter against the template */
if (templ && res) {
GstCaps *filt, *tmp;
filt = GST_PAD_TEMPLATE_CAPS (templ);
if (filt) {
gst_query_parse_caps_result (query, &result);
tmp = gst_caps_intersect_full (result, filt, GST_CAPS_INTERSECT_FIRST);
gst_query_set_caps_result (query, tmp);
GST_DEBUG_OBJECT (pad,
"filtered against template gives %" GST_PTR_FORMAT, tmp);
gst_caps_unref (tmp);
}
}
} else {
GstCaps *filter;
res = TRUE;
gst_query_parse_caps (query, &filter);
/* else, if we have a template, use its caps. */
if (templ) {
result = GST_PAD_TEMPLATE_CAPS (templ);
GST_DEBUG_OBJECT (pad,
"using pad template %p with caps %p %" GST_PTR_FORMAT, templ, result,
result);
if (filter) {
GstCaps *intersection;
GST_DEBUG_OBJECT (pad, "intersect with filter");
intersection =
gst_caps_intersect_full (filter, result, GST_CAPS_INTERSECT_FIRST);
gst_query_set_caps_result (query, intersection);
gst_caps_unref (intersection);
} else {
gst_query_set_caps_result (query, result);
}
goto done;
}
/* If there's a filter, return that */
if (filter != NULL) {
GST_DEBUG_OBJECT (pad, "return filter");
gst_query_set_caps_result (query, filter);
goto done;
}
/* last resort, any caps */
GST_DEBUG_OBJECT (pad, "pad has no template, returning ANY");
result = gst_caps_new_any ();
gst_query_set_caps_result (query, result);
gst_caps_unref (result);
}
done:
return res;
}
/**
* gst_proxy_pad_query_default:
* @pad: a #GstPad to invoke the default query on.
......@@ -112,11 +193,11 @@ gst_proxy_pad_query_default (GstPad * pad, GstQuery * query)
g_return_val_if_fail (GST_IS_PROXY_PAD (pad), FALSE);
g_return_val_if_fail (GST_IS_QUERY (query), FALSE);
target = gst_proxy_pad_get_target (pad);
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_ACCEPT_CAPS:
{
target = gst_proxy_pad_get_target (pad);
if (target) {
res = gst_pad_query (target, query);
gst_object_unref (target);
......@@ -128,8 +209,14 @@ gst_proxy_pad_query_default (GstPad * pad, GstQuery * query)
}
break;
}
case GST_QUERY_CAPS:
{
res = gst_proxy_pad_query_caps (pad, query);
break;
}
default:
{
target = gst_proxy_pad_get_target (pad);
if (target) {
res = gst_pad_query (target, query);
gst_object_unref (target);
......@@ -256,119 +343,6 @@ gst_proxy_pad_getrange_default (GstPad * pad, guint64 offset, guint size,
return res;
}
/**
* gst_proxy_pad_getcaps_default:
* @pad: a #GstPad to get the capabilities of.
* @filter: a #GstCaps filter.
*
* Invoke the default getcaps function of the proxy pad.
*
* Returns: (transfer full): the caps of the pad with incremented ref-count
*
* Since: 0.10.36
*/
GstCaps *
gst_proxy_pad_getcaps_default (GstPad * pad, GstCaps * filter)
{
GstPad *target;
GstCaps *res;
GstPadTemplate *templ;
g_return_val_if_fail (GST_IS_PROXY_PAD (pad), NULL);
templ = GST_PAD_PAD_TEMPLATE (pad);
target = gst_proxy_pad_get_target (pad);
if (target) {
/* if we have a real target, proxy the call */
res = gst_pad_get_caps (target, filter);
GST_DEBUG_OBJECT (pad, "get caps of target %s:%s : %" GST_PTR_FORMAT,
GST_DEBUG_PAD_NAME (target), res);
gst_object_unref (target);
/* filter against the template */
if (templ && res) {
GstCaps *filt, *tmp;
filt = GST_PAD_TEMPLATE_CAPS (templ);
if (filt) {
tmp = gst_caps_intersect_full (res, filt, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (res);
res = tmp;
GST_DEBUG_OBJECT (pad,
"filtered against template gives %" GST_PTR_FORMAT, res);
}
}
} else {
/* else, if we have a template, use its caps. */
if (templ) {
res = GST_PAD_TEMPLATE_CAPS (templ);
GST_DEBUG_OBJECT (pad,
"using pad template %p with caps %p %" GST_PTR_FORMAT, templ, res,
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;
}
/* If there's a filter, return that */
if (filter != NULL) {
res = gst_caps_ref (filter);
goto done;
}
/* last resort, any caps */
GST_DEBUG_OBJECT (pad, "pad has no template, returning ANY");
res = gst_caps_new_any ();
}
done:
return res;
}
/**
* gst_proxy_pad_acceptcaps_default:
* @pad: a #GstPad to check
* @caps: a #GstCaps to check on the pad
*
* Invoke the default acceptcaps function of the proxy pad.
*
* Returns: TRUE if the pad can accept the caps.
*
* Since: 0.10.36
*/
gboolean
gst_proxy_pad_acceptcaps_default (GstPad * pad, GstCaps * caps)
{
GstPad *target;
gboolean res;
g_return_val_if_fail (GST_IS_PROXY_PAD (pad), FALSE);
g_return_val_if_fail (caps == NULL || GST_IS_CAPS (caps), FALSE);
target = gst_proxy_pad_get_target (pad);
if (target) {
res = gst_pad_accept_caps (target, caps);
gst_object_unref (target);
} else {
GST_DEBUG_OBJECT (pad, "no target");
/* We don't have a target, we return TRUE and we assume that any future
* target will be able to deal with any configured caps. */
res = TRUE;
}
return res;
}
static GstPad *
gst_proxy_pad_get_target (GstPad * pad)
{
......@@ -437,8 +411,6 @@ gst_proxy_pad_class_init (GstProxyPadClass * klass)
GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_event_default);
GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_query_default);
GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_iterate_internal_links_default);
GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_getcaps_default);
GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_acceptcaps_default);
GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_unlink_default);
GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_chain_default);
GST_DEBUG_REGISTER_FUNCPTR (gst_proxy_pad_chain_list_default);
......@@ -458,7 +430,6 @@ gst_proxy_pad_init (GstProxyPad * ppad)
gst_pad_set_iterate_internal_links_function (pad,
gst_proxy_pad_iterate_internal_links_default);
gst_pad_set_getcaps_function (pad, gst_proxy_pad_getcaps_default);
gst_pad_set_unlink_function (pad, gst_proxy_pad_unlink_default);
}
......
......@@ -68,8 +68,6 @@ GstIterator* gst_proxy_pad_iterate_internal_links_default (GstPad *pad);
GstFlowReturn gst_proxy_pad_chain_default (GstPad *pad, GstBuffer *buffer);
GstFlowReturn gst_proxy_pad_chain_list_default (GstPad *pad, GstBufferList *list);
GstFlowReturn gst_proxy_pad_getrange_default (GstPad *pad, guint64 offset, guint size, GstBuffer **buffer);
GstCaps* gst_proxy_pad_getcaps_default (GstPad *pad, GstCaps * filter);
gboolean gst_proxy_pad_acceptcaps_default (GstPad *pad, GstCaps *caps);
void gst_proxy_pad_unlink_default (GstPad * pad);
#define GST_TYPE_GHOST_PAD (gst_ghost_pad_get_type ())
......
......@@ -748,7 +748,7 @@ gst_object_set_parent (GstObject * object, GstObject * parent)
goto had_parent;
object->parent = parent;
g_object_ref_sink (object);
gst_object_ref_sink (object);
GST_OBJECT_UNLOCK (object);
/* FIXME, this does not work, the deep notify takes the lock from the parent
......
......@@ -139,7 +139,6 @@ static void gst_pad_set_property (GObject * object, guint prop_id,
static void gst_pad_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstCaps *gst_pad_get_caps_unlocked (GstPad * pad, GstCaps * filter);
static void gst_pad_set_pad_template (GstPad * pad, GstPadTemplate * templ);
static gboolean gst_pad_activate_default (GstPad * pad);
static GstFlowReturn gst_pad_chain_list_default (GstPad * pad,
......@@ -1503,42 +1502,6 @@ gst_pad_set_unlink_function (GstPad * pad, GstPadUnlinkFunction unlink)
GST_DEBUG_FUNCPTR_NAME (unlink));
}
/**
* gst_pad_set_getcaps_function:
* @pad: a #GstPad.
* @getcaps: the #GstPadGetCapsFunction to set.
*
* Sets the given getcaps function for the pad. @getcaps should return the
* allowable caps for a pad in the context of the element's state, its link to
* other elements, and the devices or files it has opened. These caps must be a
* subset of the pad template caps. In the NULL state with no links, @getcaps
* should ideally return the same caps as the pad template. In rare
* circumstances, an object property can affect the caps returned by @getcaps,
* but this is discouraged.
*
* You do not need to call this function if @pad's allowed caps are always the
* same as the pad template caps. This can only be true if the padtemplate
* has fixed simple caps.
*
* For most filters, the caps returned by @getcaps is directly affected by the
* allowed caps on other pads. For demuxers and decoders, the caps returned by
* the srcpad's getcaps function is directly related to the stream data. Again,
* @getcaps should return the most specific caps it reasonably can, since this
* helps with autoplugging.
*
* Note that the return value from @getcaps is owned by the caller, so the
* caller should unref the caps after usage.
*/
void
gst_pad_set_getcaps_function (GstPad * pad, GstPadGetCapsFunction getcaps)
{
g_return_if_fail (GST_IS_PAD (pad));
GST_PAD_GETCAPSFUNC (pad) = getcaps;
GST_CAT_DEBUG_OBJECT (GST_CAT_PADS, pad, "getcapsfunc set to %s",
GST_DEBUG_FUNCPTR_NAME (getcaps));
}
/**
* gst_pad_unlink:
* @srcpad: the source #GstPad to unlink.
......@@ -1679,8 +1642,12 @@ gst_pad_link_check_compatible_unlocked (GstPad * src, GstPad * sink,
/* Doing the expensive caps checking takes priority over only checking the template caps */
if (flags & GST_PAD_LINK_CHECK_CAPS) {
srccaps = gst_pad_get_caps_unlocked (src, NULL);
sinkcaps = gst_pad_get_caps_unlocked (sink, NULL);
GST_OBJECT_UNLOCK (src);
srccaps = gst_pad_get_caps (src, NULL);
GST_OBJECT_LOCK (src);
GST_OBJECT_UNLOCK (sink);
sinkcaps = gst_pad_get_caps (sink, NULL);
GST_OBJECT_LOCK (sink);
} else {
/* If one of the two pads doesn't have a template, consider the intersection
* as valid.*/
......@@ -2087,140 +2054,6 @@ gst_pad_get_pad_template (GstPad * pad)
return (templ ? gst_object_ref (templ) : NULL);
}
static GstCaps *
caps_with_getcaps (GstPad * pad, GstCaps * filter)
{
GstCaps *result;
if (GST_PAD_GETCAPSFUNC (pad) == NULL)
return NULL;
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
"dispatching to pad getcaps function with "
"filter %" GST_PTR_FORMAT, filter);
GST_OBJECT_FLAG_SET (pad, GST_PAD_IN_GETCAPS);
GST_OBJECT_UNLOCK (pad);
result = GST_PAD_GETCAPSFUNC (pad) (pad, filter);
GST_OBJECT_LOCK (pad);
GST_OBJECT_FLAG_UNSET (pad, GST_PAD_IN_GETCAPS);
if (G_UNLIKELY (result == NULL))
goto null_caps;
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
"pad getcaps returned %" GST_PTR_FORMAT, result);
#ifndef G_DISABLE_ASSERT
/* check that the returned caps are a real subset of the template caps */
if (GST_PAD_PAD_TEMPLATE (pad)) {
const GstCaps *templ_caps =
GST_PAD_TEMPLATE_CAPS (GST_PAD_PAD_TEMPLATE (pad));
if (!gst_caps_is_subset (result, templ_caps)) {
GstCaps *temp;
GST_CAT_ERROR_OBJECT (GST_CAT_CAPS, pad,
"pad returned caps %" GST_PTR_FORMAT
" which are not a real subset of its template caps %"
GST_PTR_FORMAT, result, templ_caps);
g_warning
("pad %s:%s returned caps which are not a real "
"subset of its template caps", GST_DEBUG_PAD_NAME (pad));
temp = gst_caps_intersect (templ_caps, result);
gst_caps_unref (result);
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
return result;
/* ERRORS */
null_caps:
{
g_critical ("pad %s:%s returned NULL caps from getcaps function",
GST_DEBUG_PAD_NAME (pad));
return NULL;
}
}
/* should be called with the pad LOCK held */
/* refs the caps, so caller is responsible for getting it unreffed */
static GstCaps *
gst_pad_get_caps_unlocked (GstPad * pad, GstCaps * filter)
{
GstCaps *result = NULL;
GstPadTemplate *templ;
gboolean fixed_caps;
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "get pad caps");
fixed_caps = GST_PAD_IS_FIXED_CAPS (pad);
if (fixed_caps) {
/* fixed caps, try the negotiated caps first */
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "fixed pad caps: trying pad caps");
if ((result = get_pad_caps (pad)))
goto filter_done;
}
/* try the getcaps function next */
if ((result = caps_with_getcaps (pad, filter)))
goto done;
if ((templ = GST_PAD_PAD_TEMPLATE (pad))) {
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "trying pad template caps");
if ((result = GST_PAD_TEMPLATE_CAPS (templ)))
goto filter_done;
}
if (!fixed_caps) {
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
"non-fixed pad caps: trying pad caps");
/* non fixed caps, try the negotiated caps */
if ((result = get_pad_caps (pad)))
goto filter_done;
}
/* this almost never happens */
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "pad has no caps");
result = gst_caps_new_empty ();
goto done;
filter_done:
/* run the filter on the result */
if (filter) {
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
"using 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, result);
} else {
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
"using caps %p %" GST_PTR_FORMAT, result, result);
result = gst_caps_ref (result);
}
done:
return result;
}
/**
* gst_pad_has_current_caps:
* @pad: a #GstPad to check
......@@ -2282,8 +2115,8 @@ gst_pad_get_current_caps (GstPad * pad)
* Note that this method doesn't necessarily return the caps set by
* gst_pad_set_caps() - use gst_pad_get_current_caps() for that instead.
* gst_pad_get_caps returns all possible caps a pad can operate with, using
* the pad's get_caps function;
* this returns the pad template caps if not explicitly set.
* the pad's CAPS query function, If the query fails, this function will return
* @filter, if not #NULL, otherwise ANY.
*
* When called on sinkpads @filter contains the caps that
* upstream could produce in the order preferred by upstream. When
......@@ -2300,17 +2133,24 @@ GstCaps *
gst_pad_get_caps (GstPad * pad, GstCaps * filter)
{
GstCaps *result = NULL;
GstQuery *query;
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_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "get pad caps");
result = gst_pad_get_caps_unlocked (pad, filter);
GST_OBJECT_UNLOCK (pad);
query = gst_query_new_caps (filter);
if (gst_pad_query (pad, query)) {
gst_query_parse_caps_result (query, &result);
gst_caps_ref (result);
GST_DEBUG_OBJECT (pad, "query returned %" GST_PTR_FORMAT, result);
} else if (filter) {
result = gst_caps_ref (filter);
} else {
result = gst_caps_new_any ();
}
gst_query_unref (query);
return result;
}
......@@ -2336,34 +2176,25 @@ gst_pad_get_caps (GstPad * pad, GstCaps * filter)
GstCaps *
gst_pad_peer_get_caps (GstPad * pad, GstCaps * filter)
{
GstPad *peerpad;
GstCaps *result = NULL;
GstQuery *query;
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_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "get peer caps");
peerpad = GST_PAD_PEER (pad);
if (G_UNLIKELY (peerpad == NULL))
goto no_peer;
gst_object_ref (peerpad);
GST_OBJECT_UNLOCK (pad);
result = gst_pad_get_caps (peerpad, filter);
gst_object_unref (peerpad);
query = gst_query_new_caps (filter);
if (gst_pad_peer_query (pad, query)) {
gst_query_parse_caps_result (query, &result);
gst_caps_ref (result);
GST_DEBUG_OBJECT (pad, "peer query returned %d", result);
} else if (filter) {
result = gst_caps_ref (filter);
} else {
result = gst_caps_new_any ();
}
gst_query_unref (query);
return result;
no_peer:
{
GST_OBJECT_UNLOCK (pad);
return NULL;
}
}
/**
......@@ -2378,7 +2209,7 @@ no_peer:
gboolean
gst_pad_accept_caps (GstPad * pad, GstCaps * caps)
{
gboolean res;
gboolean res = TRUE;
GstQuery *query;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
......@@ -2387,8 +2218,7 @@ gst_pad_accept_caps (GstPad * pad, GstCaps * caps)
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "accept caps of %p", caps);
query = gst_query_new_accept_caps (caps);
res = gst_pad_query (pad, query);
if (res) {
if (gst_pad_query (pad, query)) {
GST_DEBUG_OBJECT (pad, "query returned %d", res);
gst_query_parse_accept_caps_result (query, &res);
}
......@@ -2403,24 +2233,27 @@ gst_pad_accept_caps (GstPad * pad, GstCaps * caps)
* @caps: a #GstCaps to check on the pad
*
* Check if the peer of @pad accepts @caps. If @pad has no peer, this function
* returns FALSE.
* returns TRUE.
*
* Returns: TRUE if the peer of @pad can accept the caps or @pad has no peer.
*/
gboolean
gst_pad_peer_accept_caps (GstPad * pad, GstCaps * caps)
{
gboolean result;
gboolean res = TRUE;
GstQuery *query;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);