diff --git a/gst/gstelement.c b/gst/gstelement.c index fb1bb543c0..6d7989f611 100644 --- a/gst/gstelement.c +++ b/gst/gstelement.c @@ -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 */ diff --git a/gst/gstpad.c b/gst/gstpad.c index ab187fc06b..d63385e3bd 100644 --- a/gst/gstpad.c +++ b/gst/gstpad.c @@ -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); diff --git a/gst/gstpad.h b/gst/gstpad.h index f9bc1e7af2..f7050de0ca 100644 --- a/gst/gstpad.h +++ b/gst/gstpad.h @@ -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))