+typedef struct
+{
+ GstFlowReturn ret;
+
+ /* If TRUE and ret is not OK this means
+ * that pushing the EOS event failed
+ */
+ gboolean was_eos;
+} PushStickyData;
+
+/* should be called with pad LOCK */
+static gboolean
+push_sticky (GstPad * pad, PadEvent * ev, gpointer user_data)
+{
+ PushStickyData *data = user_data;
+ GstEvent *event = ev->event;
+
+ if (ev->received) {
+ GST_DEBUG_OBJECT (pad, "event %s was already received",
+ GST_EVENT_TYPE_NAME (event));
+ return TRUE;
+ }
+
+ data->ret = gst_pad_push_event_unchecked (pad, gst_event_ref (event),
+ GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM);
+
+ switch (data->ret) {
+ case GST_FLOW_OK:
+ ev->received = TRUE;
+ GST_DEBUG_OBJECT (pad, "event %s marked received",
+ GST_EVENT_TYPE_NAME (event));
+ break;
+ case GST_FLOW_NOT_LINKED:
+ /* not linked is not a problem, we are sticky so the event will be
+ * sent later but only for non-EOS events */
+ GST_DEBUG_OBJECT (pad, "pad was not linked");
+ if (GST_EVENT_TYPE (event) != GST_EVENT_EOS)
+ data->ret = GST_FLOW_OK;
+ /* fallthrough */
+ default:
+ GST_DEBUG_OBJECT (pad, "mark pending events");
+ GST_OBJECT_FLAG_SET (pad, GST_PAD_FLAG_PENDING_EVENTS);
+ break;
+ }
+
+ if (data->ret != GST_FLOW_OK && GST_EVENT_TYPE (event) == GST_EVENT_EOS)
+ data->was_eos = TRUE;
+
+ return data->ret == GST_FLOW_OK;
+}
+
+/* check sticky events and push them when needed. should be called
+ * with pad LOCK */
+static inline GstFlowReturn
+check_sticky (GstPad * pad)
+{
+ PushStickyData data = { GST_FLOW_OK, FALSE };
+
+ if (G_UNLIKELY (GST_PAD_HAS_PENDING_EVENTS (pad))) {
+ GST_OBJECT_FLAG_UNSET (pad, GST_PAD_FLAG_PENDING_EVENTS);
+
+ GST_DEBUG_OBJECT (pad, "pushing all sticky events");
+ events_foreach (pad, push_sticky, &data);
+
+ /* If there's an EOS event we must push it downstream
+ * even if sending a previous sticky event failed.
+ * Otherwise the pipeline might wait forever for EOS.
+ *
+ * Only do this if pushing another event than the EOS
+ * event failed.
+ */
+ if (data.ret != GST_FLOW_OK && !data.was_eos) {
+ PadEvent *ev = find_event_by_type (pad, GST_EVENT_EOS, 0);
+
+ if (ev && !ev->received) {
+ data.ret = gst_pad_push_event_unchecked (pad, gst_event_ref (ev->event),
+ GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM);
+ }
+ }
+ }
+ return data.ret;
+}
+