pad: keep the parent alive when requested

Add a new pad flag NEED_PARENT that ensures that the parent of a pad is
reffed and not NULL when the event, query and internal links functions
are called.
When a pad is added to an element automatically make sure the NEED_PARENT flag
is enabled.
This commit is contained in:
Wim Taymans 2011-11-16 12:08:22 +01:00
parent a641b0ce39
commit fe3af1d67b
3 changed files with 71 additions and 1 deletions

View file

@ -706,6 +706,7 @@ gst_element_add_pad (GstElement * element, GstPad * pad)
GST_CAT_INFO_OBJECT (GST_CAT_ELEMENT_PADS, element, "adding pad '%s'",
GST_STR_NULL (pad_name));
flushing = GST_PAD_IS_FLUSHING (pad);
GST_OBJECT_FLAG_SET (pad, GST_PAD_NEED_PARENT);
GST_OBJECT_UNLOCK (pad);
/* then check to see if there's already a pad by that name here */

View file

@ -2192,6 +2192,20 @@ not_accepted:
}
}
#define ACQUIRE_PARENT(pad, parent, label) \
G_STMT_START { \
if (G_LIKELY ((parent = GST_OBJECT_PARENT (pad)))) \
gst_object_ref (parent); \
else if (G_LIKELY (GST_PAD_NEEDS_PARENT (pad))) \
goto label; \
} G_STMT_END
#define RELEASE_PARENT(parent) \
G_STMT_START { \
if (G_LIKELY (parent)) \
gst_object_unref (parent); \
} G_STMT_END
/* function to send all pending events on the sinkpad to the event
* function and collect the results. This function should be called with
* the object lock. The object lock might be released by this function.
@ -2199,18 +2213,19 @@ not_accepted:
static GstFlowReturn
gst_pad_update_events (GstPad * pad)
{
GstObject *parent;
GstFlowReturn ret = GST_FLOW_OK;
guint i;
GstPadEventFunction eventfunc;
GstEvent *event;
gboolean caps_notify = FALSE;
PadEvent *ev;
if (G_UNLIKELY ((eventfunc = GST_PAD_EVENTFUNC (pad)) == NULL))
goto no_function;
for (i = 0; i < GST_EVENT_MAX_STICKY; i++) {
gboolean res;
PadEvent *ev;
ev = &pad->priv->events[i];
@ -2218,11 +2233,15 @@ gst_pad_update_events (GstPad * pad)
if ((event = gst_event_steal (&ev->pending)) == NULL)
continue;
ACQUIRE_PARENT (pad, parent, no_parent);
gst_event_ref (event);
GST_OBJECT_UNLOCK (pad);
res = do_event_function (pad, event, eventfunc, &caps_notify);
RELEASE_PARENT (parent);
/* things could have changed while we release the lock, check if we still
* are handling the same event, if we don't something changed and we have
* to try again. FIXME. we need a cookie here. FIXME, we also want to remove
@ -2253,6 +2272,12 @@ no_function:
GST_DEBUG_PAD_NAME (pad));
return GST_FLOW_NOT_SUPPORTED;
}
no_parent:
{
GST_DEBUG_OBJECT (pad, "pad has no parent");
gst_event_take (&ev->pending, event);
return GST_FLOW_WRONG_STATE;
}
}
/**
@ -2451,13 +2476,28 @@ GstIterator *
gst_pad_iterate_internal_links (GstPad * pad)
{
GstIterator *res = NULL;
GstObject *parent;
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
GST_OBJECT_LOCK (pad);
ACQUIRE_PARENT (pad, parent, no_parent);
GST_OBJECT_UNLOCK (pad);
if (GST_PAD_ITERINTLINKFUNC (pad))
res = GST_PAD_ITERINTLINKFUNC (pad) (pad);
RELEASE_PARENT (parent);
return res;
/* ERRORS */
no_parent:
{
GST_DEBUG_OBJECT (pad, "no parent");
GST_OBJECT_UNLOCK (pad);
return FALSE;
}
}
/**
@ -3115,6 +3155,7 @@ done:
gboolean
gst_pad_query (GstPad * pad, GstQuery * query)
{
GstObject *parent;
gboolean res;
GstPadQueryFunction func;
GstPadProbeType type;
@ -3135,6 +3176,8 @@ gst_pad_query (GstPad * pad, GstQuery * query)
PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_PUSH |
GST_PAD_PROBE_TYPE_BLOCK, query, probe_stopped);
PROBE_PUSH (pad, type | GST_PAD_PROBE_TYPE_PUSH, query, probe_stopped);
ACQUIRE_PARENT (pad, parent, no_parent);
GST_OBJECT_UNLOCK (pad);
if ((func = GST_PAD_QUERYFUNC (pad)) == NULL)
@ -3142,6 +3185,8 @@ gst_pad_query (GstPad * pad, GstQuery * query)
res = func (pad, query);
RELEASE_PARENT (parent);
GST_DEBUG_OBJECT (pad, "sent query %p (%s), result %d", query,
GST_QUERY_TYPE_NAME (query), res);
@ -3154,6 +3199,13 @@ gst_pad_query (GstPad * pad, GstQuery * query)
return res;
/* ERRORS */
no_parent:
{
GST_DEBUG_OBJECT (pad, "had no parent");
GST_OBJECT_UNLOCK (pad);
return FALSE;
}
no_func:
{
GST_DEBUG_OBJECT (pad, "had no query function");
@ -4252,13 +4304,17 @@ gst_pad_send_event (GstPad * pad, GstEvent * event)
* note that a sticky event has already been updated above */
if (G_LIKELY (!needs_events || !sticky)) {
GstPadEventFunction eventfunc;
GstObject *parent;
if (G_UNLIKELY ((eventfunc = GST_PAD_EVENTFUNC (pad)) == NULL))
goto no_function;
ACQUIRE_PARENT (pad, parent, no_parent);
GST_OBJECT_UNLOCK (pad);
result = eventfunc (pad, event);
RELEASE_PARENT (parent);
}
if (need_unlock)
@ -4294,6 +4350,15 @@ no_function:
gst_event_unref (event);
return FALSE;
}
no_parent:
{
GST_DEBUG_OBJECT (pad, "no parent");
GST_OBJECT_UNLOCK (pad);
if (need_unlock)
GST_PAD_STREAM_UNLOCK (pad);
gst_event_unref (event);
return FALSE;
}
flushing:
{
GST_OBJECT_UNLOCK (pad);

View file

@ -558,6 +558,8 @@ typedef GstFlowReturn (*GstPadStickyEventsForeachFunction) (GstPad *pad, GstEve
* @GST_PAD_PROXY_CAPS: the default event and query handler will forward
* all events and queries to the internally linked pads
* instead of discarding them.
* @GST_PAD_NEED_PARENT: ensure that there is a parent object before calling
* into the pad callbacks.
* @GST_PAD_FLAG_LAST: offset to define more flags
*
* Pad state flags
@ -570,6 +572,7 @@ typedef enum {
GST_PAD_NEED_EVENTS = (GST_OBJECT_FLAG_LAST << 4),
GST_PAD_FIXED_CAPS = (GST_OBJECT_FLAG_LAST << 5),
GST_PAD_PROXY_CAPS = (GST_OBJECT_FLAG_LAST << 6),
GST_PAD_NEED_PARENT = (GST_OBJECT_FLAG_LAST << 7),
/* padding */
GST_PAD_FLAG_LAST = (GST_OBJECT_FLAG_LAST << 16)
} GstPadFlags;
@ -710,6 +713,7 @@ struct _GstPadClass {
#define GST_PAD_NEEDS_RECONFIGURE(pad) (GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_NEED_RECONFIGURE))
#define GST_PAD_NEEDS_EVENTS(pad) (GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_NEED_EVENTS))
#define GST_PAD_IS_FIXED_CAPS(pad) (GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_FIXED_CAPS))
#define GST_PAD_NEEDS_PARENT(pad) (GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_NEED_PARENT))
#define GST_PAD_IS_PROXY_CAPS(pad) (GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_PROXY_CAPS))
#define GST_PAD_SET_PROXY_CAPS(pad) (GST_OBJECT_FLAG_SET (pad, GST_PAD_PROXY_CAPS))