#define N_STACK_ALLOCATE_PROBES (16)
-static void
-probe_hook_marshal (GHook * hook, ProbeMarshall * data)
+/* A helper that checks if a probe was already
+ * in the called_probes list, and adds it if
+ * not. Used to avoid calling probes a 2nd time when
+ * looping again after probe removal */
+static gboolean
+check_probe_already_called (GHook * hook, ProbeMarshall * data)
{
- GstPad *pad = data->pad;
- GstPadProbeInfo *info = data->info;
- GstPadProbeType type, flags;
- GstPadProbeCallback callback;
- GstPadProbeReturn ret;
- gpointer original_data;
guint i;
/* if we have called this callback, do nothing. But only check
if (data->retry) {
for (i = 0; i < data->n_called_probes; i++) {
if (data->called_probes[i] == hook->hook_id) {
- GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
- "hook %lu already called", hook->hook_id);
- return;
+ return TRUE;
}
}
}
}
data->called_probes[data->n_called_probes++] = hook->hook_id;
+ /* This probe was not alraedy called */
+ return FALSE;
+}
+
+static void
+probe_hook_marshal (GHook * hook, ProbeMarshall * data)
+{
+ GstPad *pad = data->pad;
+ GstPadProbeInfo *info = data->info;
+ GstPadProbeType type, flags;
+ GstPadProbeCallback callback;
+ GstPadProbeReturn ret;
+ gpointer original_data;
+
flags = hook->flags >> G_HOOK_FLAG_USER_SHIFT;
type = info->type;
original_data = info->data;
(flags & GST_PAD_PROBE_TYPE_EVENT_FLUSH & type) == 0)
goto no_match;
+ if (check_probe_already_called (hook, data)) {
+ /* Reset marshalled = TRUE here, because the probe
+ * was already called and set it the first time around,
+ * and we may want to keep blocking on it.
+ *
+ * https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/658
+ */
+ data->marshalled = TRUE;
+ goto already_called;
+ }
+
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
"hook %lu with flags 0x%08x matches", hook->hook_id, flags);
- data->marshalled = TRUE;
-
callback = (GstPadProbeCallback) hook->func;
- if (callback == NULL)
+ if (callback == NULL) {
+ /* No callback is equivalent to just returning GST_PAD_PROBE_OK */
+ data->marshalled = TRUE;
return;
+ }
info->id = hook->hook_id;
GST_OBJECT_LOCK (pad);
+ /* If the probe callback asked for the
+ * probe to be removed, don't set the marshalled flag
+ * otherwise, you can get a case where you return
+ * GST_PAD_PROBE_REMOVE from a buffer probe and
+ * then the pad blocks anyway if there's any other
+ * blocking probes installed.
+ *
+ * https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/658
+ */
+ if (ret != GST_PAD_PROBE_REMOVE)
+ data->marshalled = TRUE;
+
if ((flags & GST_PAD_PROBE_TYPE_IDLE))
pad->priv->idle_running--;
hook->hook_id, flags, info->type);
return;
}
+already_called:
+ {
+ GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad,
+ "hook %lu already called", hook->hook_id);
+ return;
+ }
}
/* a probe that does not take or return any data */
data.info = info;
data.pass = FALSE;
data.handled = FALSE;
- data.marshalled = FALSE;
data.dropped = FALSE;
/* We stack-allocate for N_STACK_ALLOCATE_PROBES hooks as a first step. If more are needed,
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, pad, "do probes");
cookie = pad->priv->probe_list_cookie;
+ /* Clear the marshalled flag before doing callbacks. Only if
+ * there are matching callbacks still will it get set */
+ data.marshalled = FALSE;
+
g_hook_list_marshal (&pad->probes, TRUE,
(GHookMarshaller) probe_hook_marshal, &data);