pad: keep the parent alive when requested
authorWim Taymans <wim.taymans@collabora.co.uk>
Wed, 16 Nov 2011 11:08:22 +0000 (12:08 +0100)
committerWim Taymans <wim.taymans@collabora.co.uk>
Wed, 16 Nov 2011 11:08:22 +0000 (12:08 +0100)
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.

gst/gstelement.c
gst/gstpad.c
gst/gstpad.h

index fb1bb54..6d7989f 100644 (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 */
index ab187fc..d63385e 100644 (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);
index f9bc1e7..f7050de 100644 (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))