pad: more sticky events work
authorWim Taymans <wim.taymans@collabora.co.uk>
Tue, 3 May 2011 16:58:18 +0000 (18:58 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Tue, 3 May 2011 16:58:18 +0000 (18:58 +0200)
Copy the sticky events from the srcpad to the sinkpad when linking pads. Set the
STICKY_PENDING flag to make sure that the sticky events are dispatched before
pushing the next buffer to the element.

gst/gstevent.h
gst/gstpad.c
gst/gstpad.h

index 53210bf..e65c30f 100644 (file)
@@ -61,8 +61,9 @@ typedef enum {
 #define GST_EVENT_TYPE_BOTH \
     (GST_EVENT_TYPE_UPSTREAM | GST_EVENT_TYPE_DOWNSTREAM)
 
+#define GST_EVENT_MAX_STICKY    16
 #define GST_EVENT_STICKY_SHIFT  8
-#define GST_EVENT_NUM_SHIFT     16
+#define GST_EVENT_NUM_SHIFT     (GST_EVENT_STICKY_SHIFT + 4)
 
 /**
  * GST_EVENT_MAKE_TYPE:
@@ -78,7 +79,8 @@ typedef enum {
 
 #define FLAG(name) GST_EVENT_TYPE_##name
 
-#define GST_EVENT_STICKY_IDX(ev)  ((GST_EVENT_TYPE(ev) >> GST_EVENT_STICKY_SHIFT) & 0xff)
+
+#define GST_EVENT_STICKY_IDX(ev)  ((GST_EVENT_TYPE(ev) >> GST_EVENT_STICKY_SHIFT) & 0xf)
 
 /**
  * GstEventType:
index a0d8091..96ad674 100644 (file)
@@ -378,7 +378,7 @@ clear_sticky_events (GstPad * pad)
 {
   guint i;
 
-  for (i = 0; i < 16; i++) {
+  for (i = 0; i < GST_EVENT_MAX_STICKY; i++) {
     GstEvent **eventp = &pad->sticky[i];
     gst_event_replace (eventp, NULL);
   }
@@ -679,6 +679,9 @@ gst_pad_set_active (GstPad * pad, gboolean active)
         GST_DEBUG_OBJECT (pad, "activating pad from none");
         ret = (GST_PAD_ACTIVATEFUNC (pad)) (pad);
         break;
+      default:
+        GST_DEBUG_OBJECT (pad, "unknown activation mode!");
+        break;
     }
   } else {
     switch (old) {
@@ -694,6 +697,9 @@ gst_pad_set_active (GstPad * pad, gboolean active)
         GST_DEBUG_OBJECT (pad, "deactivating pad from none");
         ret = TRUE;
         break;
+      default:
+        GST_DEBUG_OBJECT (pad, "unknown activation mode!");
+        break;
     }
   }
 
@@ -1687,6 +1693,9 @@ gst_pad_unlink (GstPad * srcpad, GstPad * sinkpad)
   GST_PAD_PEER (srcpad) = NULL;
   GST_PAD_PEER (sinkpad) = NULL;
 
+  /* clear the events on the sinkpad */
+  clear_sticky_events (sinkpad);
+
   GST_OBJECT_UNLOCK (sinkpad);
   GST_OBJECT_UNLOCK (srcpad);
 
@@ -2004,6 +2013,7 @@ gst_pad_link_full (GstPad * srcpad, GstPad * sinkpad, GstPadLinkCheck flags)
 {
   GstPadLinkReturn result;
   GstElement *parent;
+  guint i;
 
   g_return_val_if_fail (GST_IS_PAD (srcpad), GST_PAD_LINK_REFUSED);
   g_return_val_if_fail (GST_PAD_IS_SRC (srcpad), GST_PAD_LINK_WRONG_DIRECTION);
@@ -2033,6 +2043,15 @@ gst_pad_link_full (GstPad * srcpad, GstPad * sinkpad, GstPadLinkCheck flags)
   GST_PAD_PEER (srcpad) = sinkpad;
   GST_PAD_PEER (sinkpad) = srcpad;
 
+  /* copy the events */
+  for (i = 0; i < GST_EVENT_MAX_STICKY; i++) {
+    GstEvent **eventp = &sinkpad->sticky[i], *event;
+
+    if ((event = srcpad->sticky[i]))
+      GST_OBJECT_FLAG_SET (sinkpad, GST_PAD_STICKY_PENDING);
+    gst_event_replace (eventp, event);
+  }
+
   GST_OBJECT_UNLOCK (sinkpad);
   GST_OBJECT_UNLOCK (srcpad);
 
@@ -3440,6 +3459,7 @@ gst_pad_chain_data_unchecked (GstPad * pad, gboolean is_buffer, void *data,
 
   GST_PAD_STREAM_LOCK (pad);
 
+again:
   GST_OBJECT_LOCK (pad);
   if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
     goto flushing;
@@ -3448,6 +3468,38 @@ gst_pad_chain_data_unchecked (GstPad * pad, gboolean is_buffer, void *data,
   caps_changed = caps && caps != GST_PAD_CAPS (pad);
 
   emit_signal = GST_PAD_DO_BUFFER_SIGNALS (pad) > 0;
+
+  if (G_UNLIKELY (GST_PAD_IS_STICKY_PENDING (pad))) {
+    GstPadEventFunction eventfunc;
+
+    if (G_LIKELY ((eventfunc = GST_PAD_EVENTFUNC (pad)))) {
+      GstEvent *events[GST_EVENT_MAX_STICKY];
+      GstEvent *event;
+      guint i;
+
+      /* need to make a copy because when we release the object lock, things
+       * could just change */
+      for (i = 0; i < GST_EVENT_MAX_STICKY; i++) {
+        if ((event = pad->sticky[i]))
+          events[i] = gst_event_ref (event);
+        else
+          events[i] = NULL;
+      }
+      /* clear the flag */
+      GST_OBJECT_FLAG_UNSET (pad, GST_PAD_STICKY_PENDING);
+      GST_OBJECT_UNLOCK (pad);
+
+      /* and push */
+      GST_DEBUG_OBJECT (pad, "pushing sticky events");
+      for (i = 0; i < GST_EVENT_MAX_STICKY; i++) {
+        if ((event = events[i]))
+          eventfunc (pad, event);
+      }
+      /* and restart, we released the lock things might have changed */
+      goto again;
+    }
+  }
+
   GST_OBJECT_UNLOCK (pad);
 
   /* see if the signal should be emited, we emit before caps nego as
@@ -4463,9 +4515,10 @@ gst_pad_push_event (GstPad * pad, GstEvent * event)
 
   /* store the event on the pad, but only on srcpads */
   if (GST_PAD_IS_SRC (pad) && GST_EVENT_IS_STICKY (event)) {
-    GstEvent **eventp = &pad->sticky[GST_EVENT_STICKY_IDX (event)];
-    GST_LOG_OBJECT (pad, "storing sticky event %s",
-        GST_EVENT_TYPE_NAME (event));
+    guint idx = GST_EVENT_STICKY_IDX (event);
+    GstEvent **eventp = &pad->sticky[idx];
+    GST_LOG_OBJECT (pad, "storing sticky event %s at index %u",
+        GST_EVENT_TYPE_NAME (event), idx);
     gst_event_replace (eventp, event);
   }
 
index 19def6b..619ddff 100644 (file)
@@ -509,18 +509,20 @@ typedef enum {
  * @GST_PAD_IN_GETCAPS: GstPadGetCapsFunction() is running now
  * @GST_PAD_IN_SETCAPS: GstPadSetCapsFunction() is running now
  * @GST_PAD_BLOCKING: is pad currently blocking on a buffer or event
+ * @GST_PAD_STICKY_PENDING: sticky events should be pushed
  * @GST_PAD_FLAG_LAST: offset to define more flags
  *
  * Pad state flags
  */
 typedef enum {
-  GST_PAD_BLOCKED       = (GST_OBJECT_FLAG_LAST << 0),
-  GST_PAD_FLUSHING      = (GST_OBJECT_FLAG_LAST << 1),
-  GST_PAD_IN_GETCAPS    = (GST_OBJECT_FLAG_LAST << 2),
-  GST_PAD_IN_SETCAPS    = (GST_OBJECT_FLAG_LAST << 3),
-  GST_PAD_BLOCKING     = (GST_OBJECT_FLAG_LAST << 4),
+  GST_PAD_BLOCKED        = (GST_OBJECT_FLAG_LAST << 0),
+  GST_PAD_FLUSHING       = (GST_OBJECT_FLAG_LAST << 1),
+  GST_PAD_IN_GETCAPS     = (GST_OBJECT_FLAG_LAST << 2),
+  GST_PAD_IN_SETCAPS     = (GST_OBJECT_FLAG_LAST << 3),
+  GST_PAD_BLOCKING      = (GST_OBJECT_FLAG_LAST << 4),
+  GST_PAD_STICKY_PENDING = (GST_OBJECT_FLAG_LAST << 5),
   /* padding */
-  GST_PAD_FLAG_LAST     = (GST_OBJECT_FLAG_LAST << 8)
+  GST_PAD_FLAG_LAST      = (GST_OBJECT_FLAG_LAST << 16)
 } GstPadFlags;
 
 /* FIXME: this awful circular dependency need to be resolved properly (see padtemplate.h) */
@@ -614,7 +616,7 @@ struct _GstPad {
   GstPadCheckGetRangeFunction   checkgetrangefunc;
   GstPadGetRangeFunction        getrangefunc;
   GstPadEventFunction           eventfunc;
-  GstEvent                      *sticky[16];
+  GstEvent                      *sticky[GST_EVENT_MAX_STICKY];
 
   GstActivateMode               mode;
 
@@ -697,6 +699,7 @@ struct _GstPadClass {
 #define GST_PAD_IS_FLUSHING(pad)       (GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_FLUSHING))
 #define GST_PAD_IS_IN_GETCAPS(pad)     (GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_IN_GETCAPS))
 #define GST_PAD_IS_IN_SETCAPS(pad)     (GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_IN_SETCAPS))
+#define GST_PAD_IS_STICKY_PENDING(pad) (GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_STICKY_PENDING))
 #define GST_PAD_IS_SRC(pad)            (GST_PAD_DIRECTION(pad) == GST_PAD_SRC)
 #define GST_PAD_IS_SINK(pad)           (GST_PAD_DIRECTION(pad) == GST_PAD_SINK)