mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-18 14:26:43 +00:00
validate:scenario: Simplify the way we override appsrc src pad chain
When pushing several buffers while the pipeline is in NULL state, meaning that the action are executed "interlaced", previous code was deadlocking. This new implementation makes it so the override is always on and we expect all buffers to go through to be associated to a function, which is a safe assumption. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3052>
This commit is contained in:
parent
fdfa70997b
commit
d2b4e7a38e
1 changed files with 65 additions and 46 deletions
|
@ -1,8 +1,10 @@
|
|||
/* GStreamer
|
||||
|
||||
*
|
||||
* Copyright (C) 2013 Collabora Ltd.
|
||||
* Author: Thibault Saunier <thibault.saunier@collabora.com>
|
||||
* Copyright (C) 2018-2020 Igalia S.L
|
||||
* Copyright (C) 2018-2022 Igalia S.L
|
||||
* Author: Thibault Saunier <tsaunier@igalia.com>
|
||||
|
||||
*
|
||||
* gst-validate-scenario.c - Validate Scenario class
|
||||
|
@ -346,9 +348,12 @@ _reporter_iface_init (GstValidateReporterInterface * iface)
|
|||
iface->get_pipeline = _get_pipeline;
|
||||
}
|
||||
|
||||
static GQuark chain_qdata;
|
||||
G_DEFINE_TYPE_WITH_CODE (GstValidateScenario, gst_validate_scenario,
|
||||
GST_TYPE_OBJECT, G_ADD_PRIVATE (GstValidateScenario)
|
||||
G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, _reporter_iface_init));
|
||||
G_IMPLEMENT_INTERFACE (GST_TYPE_VALIDATE_REPORTER, _reporter_iface_init)
|
||||
chain_qdata = g_quark_from_static_string ("__validate_scenario_chain_data")
|
||||
);
|
||||
|
||||
/* GstValidateAction implementation */
|
||||
static GType _gst_validate_action_type = 0;
|
||||
|
@ -3494,80 +3499,94 @@ out:
|
|||
|
||||
}
|
||||
|
||||
typedef struct _ChainWrapperFunctionData ChainWrapperFunctionData;
|
||||
typedef GstFlowReturn (*ChainWrapperFunction) (GstPad * pad, GstObject * parent,
|
||||
GstBuffer * buffer, gpointer * user_data, gboolean * remove_wrapper);
|
||||
GstBuffer * buffer, ChainWrapperFunctionData * data);
|
||||
|
||||
typedef struct _ChainWrapperFunctionData
|
||||
struct _ChainWrapperFunctionData
|
||||
{
|
||||
GstPadChainFunction wrapped_chain_func;
|
||||
gpointer wrapped_chain_data;
|
||||
GDestroyNotify wrapped_chain_notify;
|
||||
ChainWrapperFunction wrapper_function;
|
||||
gpointer wrapper_function_user_data;
|
||||
} ChainWrapperFunctionData;
|
||||
|
||||
GMutex actions_lock;
|
||||
GList *actions;
|
||||
|
||||
};
|
||||
|
||||
static void
|
||||
chain_wrapper_function_free (ChainWrapperFunctionData * data)
|
||||
{
|
||||
g_list_free_full (data->actions, (GDestroyNotify) gst_validate_action_unref);
|
||||
g_mutex_clear (&data->actions_lock);
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
_pad_chain_wrapper (GstPad * pad, GstObject * parent, GstBuffer * buffer)
|
||||
{
|
||||
ChainWrapperFunctionData *data = pad->chaindata;
|
||||
GstFlowReturn ret;
|
||||
gboolean remove_wrapper = FALSE;
|
||||
ChainWrapperFunctionData *data =
|
||||
g_object_get_qdata (G_OBJECT (pad), chain_qdata);
|
||||
|
||||
pad->chainfunc = data->wrapped_chain_func;
|
||||
pad->chaindata = data->wrapped_chain_data;
|
||||
pad->chainnotify = data->wrapped_chain_notify;
|
||||
|
||||
ret = data->wrapper_function (pad, parent, buffer,
|
||||
data->wrapper_function_user_data, &remove_wrapper);
|
||||
|
||||
if (!remove_wrapper) {
|
||||
/* The chain function may have changed during the calling (e.g. if it was
|
||||
* a nested wrapper that decided to remove itself) so we need to update the
|
||||
* wrapped function just in case. */
|
||||
data->wrapped_chain_func = pad->chainfunc;
|
||||
data->wrapped_chain_data = pad->chaindata;
|
||||
data->wrapped_chain_notify = pad->chainnotify;
|
||||
|
||||
/* Restore the wrapper as chain function */
|
||||
pad->chainfunc = _pad_chain_wrapper;
|
||||
pad->chaindata = data;
|
||||
pad->chainnotify = g_free;
|
||||
} else
|
||||
g_free (data);
|
||||
|
||||
return ret;
|
||||
return data->wrapper_function (pad, parent, buffer,
|
||||
g_object_get_qdata (G_OBJECT (pad), chain_qdata));
|
||||
}
|
||||
|
||||
static void
|
||||
wrap_pad_chain_function (GstPad * pad, ChainWrapperFunction new_function,
|
||||
gpointer user_data)
|
||||
GstValidateAction * action)
|
||||
{
|
||||
ChainWrapperFunctionData *data = g_new (ChainWrapperFunctionData, 1);
|
||||
data->wrapped_chain_func = pad->chainfunc;
|
||||
data->wrapped_chain_data = pad->chaindata;
|
||||
data->wrapped_chain_notify = pad->chainnotify;
|
||||
data->wrapper_function = new_function;
|
||||
data->wrapper_function_user_data = user_data;
|
||||
ChainWrapperFunctionData *data =
|
||||
g_object_get_qdata (G_OBJECT (pad), chain_qdata);
|
||||
|
||||
if (data) {
|
||||
g_mutex_lock (&data->actions_lock);
|
||||
data->actions = g_list_append (data->actions, action);
|
||||
g_mutex_unlock (&data->actions_lock);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
data = g_new0 (ChainWrapperFunctionData, 1);
|
||||
data->actions = g_list_append (data->actions, action);
|
||||
|
||||
g_object_set_qdata_full (G_OBJECT (pad), chain_qdata, data,
|
||||
(GDestroyNotify) chain_wrapper_function_free);
|
||||
|
||||
data->wrapped_chain_func = pad->chainfunc;
|
||||
data->wrapper_function = new_function;
|
||||
pad->chainfunc = _pad_chain_wrapper;
|
||||
pad->chaindata = data;
|
||||
pad->chainnotify = g_free;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
appsrc_push_chain_wrapper (GstPad * pad, GstObject * parent, GstBuffer * buffer,
|
||||
gpointer * user_data, gboolean * remove_wrapper)
|
||||
appsrc_push_chain_wrapper (GstPad * pad, GstObject * parent,
|
||||
GstBuffer * buffer, ChainWrapperFunctionData * data)
|
||||
{
|
||||
GstValidateAction *action = (GstValidateAction *) user_data;
|
||||
GstValidateScenario *scenario = gst_validate_action_get_scenario (action);
|
||||
GstValidateAction *action;
|
||||
GstValidateScenario *scenario;
|
||||
GstFlowReturn ret;
|
||||
|
||||
g_mutex_lock (&data->actions_lock);
|
||||
if (data->actions) {
|
||||
action = data->actions->data;
|
||||
data->actions = g_list_remove (data->actions, action);
|
||||
g_mutex_unlock (&data->actions_lock);
|
||||
|
||||
scenario = gst_validate_action_get_scenario (action);
|
||||
} else {
|
||||
g_mutex_unlock (&data->actions_lock);
|
||||
|
||||
return data->wrapped_chain_func (pad, parent, buffer);
|
||||
}
|
||||
|
||||
GST_VALIDATE_SCENARIO_EOS_HANDLING_LOCK (scenario);
|
||||
ret = pad->chainfunc (pad, parent, buffer);
|
||||
ret = data->wrapped_chain_func (pad, parent, buffer);
|
||||
gst_validate_action_set_done (action);
|
||||
gst_validate_action_unref (action);
|
||||
*remove_wrapper = TRUE;
|
||||
GST_VALIDATE_SCENARIO_EOS_HANDLING_UNLOCK (scenario);
|
||||
g_object_unref (scenario);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue