mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-22 09:41:07 +00:00
validate: Add a deep-property-path
parameter to the wait
signal
Allowing wait actions to wait on any property of any element in the pipeline, even for elements that might be added later in the pipeline. This also works for pads which can be pretty useful Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7700>
This commit is contained in:
parent
2c88bbf07f
commit
302797a965
1 changed files with 115 additions and 19 deletions
|
@ -3257,14 +3257,22 @@ typedef struct
|
||||||
guint sigid;
|
guint sigid;
|
||||||
gboolean check_done;
|
gboolean check_done;
|
||||||
gboolean check_property;
|
gboolean check_property;
|
||||||
|
|
||||||
|
gchar *parent_name;
|
||||||
|
gchar *object_name;
|
||||||
|
gchar *property_name;
|
||||||
GMutex lock;
|
GMutex lock;
|
||||||
} WaitingSignalData;
|
} WaitingSignalData;
|
||||||
|
|
||||||
static WaitingSignalData *
|
static WaitingSignalData *
|
||||||
waiting_signal_data_new (GstElement * target, GstValidateAction * action)
|
waiting_signal_data_new (GstElement * target, GstValidateAction * action,
|
||||||
|
gchar * parent_name, gchar * object_name, gchar * property_name)
|
||||||
{
|
{
|
||||||
WaitingSignalData *data = g_new0 (WaitingSignalData, 1);
|
WaitingSignalData *data = g_new0 (WaitingSignalData, 1);
|
||||||
|
|
||||||
|
data->parent_name = parent_name;
|
||||||
|
data->object_name = object_name;
|
||||||
|
data->property_name = property_name;
|
||||||
data->target = gst_object_ref (target);
|
data->target = gst_object_ref (target);
|
||||||
data->action = gst_validate_action_ref (action);
|
data->action = gst_validate_action_ref (action);
|
||||||
|
|
||||||
|
@ -3279,6 +3287,9 @@ waiting_signal_data_free (WaitingSignalData * data)
|
||||||
|
|
||||||
g_assert (scenario);
|
g_assert (scenario);
|
||||||
|
|
||||||
|
g_free (data->object_name);
|
||||||
|
g_free (data->parent_name);
|
||||||
|
g_free (data->property_name);
|
||||||
gst_object_unref (data->target);
|
gst_object_unref (data->target);
|
||||||
gst_validate_action_unref (data->action);
|
gst_validate_action_unref (data->action);
|
||||||
g_free (data);
|
g_free (data);
|
||||||
|
@ -3302,11 +3313,15 @@ waiting_signal_data_disconnect (WaitingSignalData * data,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
stop_waiting_signal_cb (WaitingSignalData * data)
|
stop_waiting_signal_cb (WaitingSignalData * data, GstObject * prop_object,
|
||||||
|
GParamSpec * prop, GstObject * object)
|
||||||
{
|
{
|
||||||
GstStructure *check = NULL;
|
GstStructure *check = NULL;
|
||||||
GstValidateAction *action = gst_validate_action_ref (data->action);
|
GstValidateAction *action = gst_validate_action_ref (data->action);
|
||||||
GstValidateScenario *scenario = NULL;
|
GstValidateScenario *scenario = NULL;
|
||||||
|
const gchar *property_name = NULL;
|
||||||
|
gboolean check_property = data->check_property;
|
||||||
|
GstObject *property_check_target = GST_OBJECT_CAST (data->target);
|
||||||
|
|
||||||
g_mutex_lock (&data->lock);
|
g_mutex_lock (&data->lock);
|
||||||
if (data->check_done) {
|
if (data->check_done) {
|
||||||
|
@ -3315,10 +3330,40 @@ stop_waiting_signal_cb (WaitingSignalData * data)
|
||||||
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data->object_name) {
|
||||||
|
if (g_strcmp0 (data->object_name, GST_OBJECT_NAME (prop_object)) != 0) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_strcmp0 (data->property_name, prop->name) != 0) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->parent_name) {
|
||||||
|
GstObject *parent = gst_object_get_parent (prop_object);
|
||||||
|
|
||||||
|
if (parent && g_strcmp0 (data->parent_name, GST_OBJECT_NAME (parent))) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_clear_object (&parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
property_check_target = prop_object;
|
||||||
|
property_name = data->property_name;
|
||||||
|
check_property =
|
||||||
|
gst_structure_has_field (action->structure, "property-value");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
property_name =
|
||||||
|
gst_structure_get_string (action->structure, "property-name");
|
||||||
|
}
|
||||||
|
|
||||||
scenario = gst_validate_action_get_scenario (data->action);
|
scenario = gst_validate_action_get_scenario (data->action);
|
||||||
if (data->check_property &&
|
if (check_property &&
|
||||||
_check_property (scenario, action, data->target,
|
_check_property (scenario, action, property_check_target,
|
||||||
gst_structure_get_string (action->structure, "property-name"),
|
property_name,
|
||||||
gst_structure_get_value (action->structure, "property-value"),
|
gst_structure_get_value (action->structure, "property-value"),
|
||||||
FALSE) != GST_VALIDATE_EXECUTE_ACTION_OK) {
|
FALSE) != GST_VALIDATE_EXECUTE_ACTION_OK) {
|
||||||
|
|
||||||
|
@ -3326,6 +3371,7 @@ stop_waiting_signal_cb (WaitingSignalData * data)
|
||||||
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
data->check_done = TRUE;
|
||||||
|
|
||||||
waiting_signal_data_disconnect (data, scenario);
|
waiting_signal_data_disconnect (data, scenario);
|
||||||
if (gst_structure_get (action->structure, "check", GST_TYPE_STRUCTURE,
|
if (gst_structure_get (action->structure, "check", GST_TYPE_STRUCTURE,
|
||||||
|
@ -3349,6 +3395,7 @@ stop_waiting_signal_cb (WaitingSignalData * data)
|
||||||
cleanup:
|
cleanup:
|
||||||
gst_validate_action_unref (action);
|
gst_validate_action_unref (action);
|
||||||
gst_clear_object (&scenario);
|
gst_clear_object (&scenario);
|
||||||
|
g_mutex_unlock (&data->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstValidateExecuteActionReturn
|
static GstValidateExecuteActionReturn
|
||||||
|
@ -3418,21 +3465,56 @@ _execute_wait_for_signal (GstValidateScenario * scenario,
|
||||||
const GValue *property_value =
|
const GValue *property_value =
|
||||||
gst_structure_get_value (action->structure, "property-value");
|
gst_structure_get_value (action->structure, "property-value");
|
||||||
DECLARE_AND_GET_PIPELINE (scenario, action);
|
DECLARE_AND_GET_PIPELINE (scenario, action);
|
||||||
gboolean checking_property = signal_name == NULL;
|
const gchar *deep_property_path =
|
||||||
|
gst_structure_get_string (action->structure, "deep-property-path");
|
||||||
|
gboolean checking_property = signal_name == NULL
|
||||||
|
&& deep_property_path == NULL;
|
||||||
|
gchar *parent_name = NULL, *object_name = NULL, *deep_property_name = NULL;
|
||||||
|
|
||||||
|
if (deep_property_path && *deep_property_path) {
|
||||||
|
gchar **elem_pad_name = g_strsplit (deep_property_path, ".", 2);
|
||||||
|
gchar **object_prop_name =
|
||||||
|
g_strsplit (elem_pad_name[1] ? elem_pad_name[1] : elem_pad_name[0],
|
||||||
|
"::",
|
||||||
|
-1);
|
||||||
|
|
||||||
|
REPORT_UNLESS (object_prop_name[1], done,
|
||||||
|
"Property specification %s is missing a `::propename` part",
|
||||||
|
deep_property_path);
|
||||||
|
|
||||||
|
deep_property_name = g_strdup (object_prop_name[1]);
|
||||||
|
object_name = g_strdup (object_prop_name[0]);
|
||||||
|
if (elem_pad_name[1]) {
|
||||||
|
parent_name = g_strdup (elem_pad_name[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strfreev (elem_pad_name);
|
||||||
|
g_strfreev (object_prop_name);
|
||||||
|
|
||||||
|
target = gst_object_ref (pipeline);
|
||||||
|
signal_name = g_strdup ("deep-notify");
|
||||||
|
|
||||||
|
gst_validate_printf (action, "Waiting for 'deep-notify::%s'\n",
|
||||||
|
deep_property_name);
|
||||||
|
} else {
|
||||||
|
|
||||||
REPORT_UNLESS (signal_name || property_name, done,
|
REPORT_UNLESS (signal_name || property_name, done,
|
||||||
"No signal-name or property-name given for wait action");
|
"No signal-name or property-name given for wait action");
|
||||||
REPORT_UNLESS (!property_name || (property_name && property_value), done,
|
REPORT_UNLESS (!property_name || (property_name && property_value), done,
|
||||||
"`property-name` specified without a `property-value`");
|
"`property-name` specified without a `property-value`");
|
||||||
|
|
||||||
targets = _find_elements_defined_in_action (scenario, action);
|
targets = _find_elements_defined_in_action (scenario, action);
|
||||||
REPORT_UNLESS ((g_list_length (targets) == 1), done,
|
REPORT_UNLESS ((g_list_length (targets) == 1), done,
|
||||||
"Could not find target element.");
|
"Could not find target element.");
|
||||||
|
target = targets->data;
|
||||||
gst_validate_printf (action, "Waiting for '%s'\n",
|
gst_validate_printf (action, "Waiting for '%s'\n",
|
||||||
signal_name ? signal_name : property_name);
|
signal_name ? signal_name : property_name);
|
||||||
|
}
|
||||||
|
|
||||||
target = targets->data;
|
|
||||||
data = waiting_signal_data_new (target, action);
|
data =
|
||||||
|
waiting_signal_data_new (target, action, parent_name, object_name,
|
||||||
|
deep_property_name);
|
||||||
|
|
||||||
if (checking_property) {
|
if (checking_property) {
|
||||||
signal_name = g_strdup_printf ("notify::%s", property_name);
|
signal_name = g_strdup_printf ("notify::%s", property_name);
|
||||||
|
@ -3461,8 +3543,7 @@ _execute_wait_for_signal (GstValidateScenario * scenario,
|
||||||
non_blocking ? GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING :
|
non_blocking ? GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING :
|
||||||
GST_VALIDATE_EXECUTE_ACTION_ASYNC;
|
GST_VALIDATE_EXECUTE_ACTION_ASYNC;
|
||||||
if (checking_property) {
|
if (checking_property) {
|
||||||
GST_ERROR ("Checking property value");
|
if (_check_property (scenario, action, data->target, property_name,
|
||||||
if (_check_property (scenario, action, target, property_name,
|
|
||||||
property_value, FALSE) == GST_VALIDATE_EXECUTE_ACTION_OK) {
|
property_value, FALSE) == GST_VALIDATE_EXECUTE_ACTION_OK) {
|
||||||
data->check_done = TRUE;
|
data->check_done = TRUE;
|
||||||
waiting_signal_data_disconnect (data, scenario);
|
waiting_signal_data_disconnect (data, scenario);
|
||||||
|
@ -3558,6 +3639,8 @@ _execute_wait (GstValidateScenario * scenario, GstValidateAction * action)
|
||||||
gst_structure_get_boolean (action->structure, "on-clock", &on_clock);
|
gst_structure_get_boolean (action->structure, "on-clock", &on_clock);
|
||||||
if (gst_structure_has_field (action->structure, "signal-name")) {
|
if (gst_structure_has_field (action->structure, "signal-name")) {
|
||||||
return _execute_wait_for_signal (scenario, action);
|
return _execute_wait_for_signal (scenario, action);
|
||||||
|
} else if (gst_structure_has_field (action->structure, "deep-property-path")) {
|
||||||
|
return _execute_wait_for_signal (scenario, action);
|
||||||
} else if (gst_structure_has_field (action->structure, "property-name")) {
|
} else if (gst_structure_has_field (action->structure, "property-name")) {
|
||||||
return _execute_wait_for_signal (scenario, action);
|
return _execute_wait_for_signal (scenario, action);
|
||||||
} else if (gst_structure_has_field (action->structure, "message-type")) {
|
} else if (gst_structure_has_field (action->structure, "message-type")) {
|
||||||
|
@ -8146,6 +8229,19 @@ register_action_types (void)
|
||||||
.types = "structure",
|
.types = "structure",
|
||||||
NULL
|
NULL
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "deep-property-path",
|
||||||
|
.description = "The property to wait to be set on the object inside the pipeline that matches"
|
||||||
|
" the path defined as:\n\n"
|
||||||
|
"```\n"
|
||||||
|
"element-name.padname::property-name=new-value\n"
|
||||||
|
"```\n\n"
|
||||||
|
"> NOTE: `.padname` is not needed if setting a property on an element\n\n",
|
||||||
|
.mandatory = FALSE,
|
||||||
|
.types = "string",
|
||||||
|
NULL
|
||||||
|
},
|
||||||
|
|
||||||
{NULL}
|
{NULL}
|
||||||
}),
|
}),
|
||||||
"Waits for signal 'signal-name', message 'message-type', or during 'duration' seconds",
|
"Waits for signal 'signal-name', message 'message-type', or during 'duration' seconds",
|
||||||
|
|
Loading…
Reference in a new issue