diff --git a/subprojects/gst-devtools/validate/gst/validate/gst-validate-scenario.c b/subprojects/gst-devtools/validate/gst/validate/gst-validate-scenario.c index 2c937f730f..efdca8ffae 100644 --- a/subprojects/gst-devtools/validate/gst/validate/gst-validate-scenario.c +++ b/subprojects/gst-devtools/validate/gst/validate/gst-validate-scenario.c @@ -3257,14 +3257,22 @@ typedef struct guint sigid; gboolean check_done; gboolean check_property; + + gchar *parent_name; + gchar *object_name; + gchar *property_name; GMutex lock; } 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); + data->parent_name = parent_name; + data->object_name = object_name; + data->property_name = property_name; data->target = gst_object_ref (target); data->action = gst_validate_action_ref (action); @@ -3279,6 +3287,9 @@ waiting_signal_data_free (WaitingSignalData * data) g_assert (scenario); + g_free (data->object_name); + g_free (data->parent_name); + g_free (data->property_name); gst_object_unref (data->target); gst_validate_action_unref (data->action); g_free (data); @@ -3302,11 +3313,15 @@ waiting_signal_data_disconnect (WaitingSignalData * data, } static void -stop_waiting_signal_cb (WaitingSignalData * data) +stop_waiting_signal_cb (WaitingSignalData * data, GstObject * prop_object, + GParamSpec * prop, GstObject * object) { GstStructure *check = NULL; GstValidateAction *action = gst_validate_action_ref (data->action); 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); if (data->check_done) { @@ -3315,10 +3330,40 @@ stop_waiting_signal_cb (WaitingSignalData * data) 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); - if (data->check_property && - _check_property (scenario, action, data->target, - gst_structure_get_string (action->structure, "property-name"), + if (check_property && + _check_property (scenario, action, property_check_target, + property_name, gst_structure_get_value (action->structure, "property-value"), FALSE) != GST_VALIDATE_EXECUTE_ACTION_OK) { @@ -3326,6 +3371,7 @@ stop_waiting_signal_cb (WaitingSignalData * data) goto cleanup; } + data->check_done = TRUE; waiting_signal_data_disconnect (data, scenario); if (gst_structure_get (action->structure, "check", GST_TYPE_STRUCTURE, @@ -3349,6 +3395,7 @@ stop_waiting_signal_cb (WaitingSignalData * data) cleanup: gst_validate_action_unref (action); gst_clear_object (&scenario); + g_mutex_unlock (&data->lock); } static GstValidateExecuteActionReturn @@ -3418,21 +3465,56 @@ _execute_wait_for_signal (GstValidateScenario * scenario, const GValue *property_value = gst_structure_get_value (action->structure, "property-value"); 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; - REPORT_UNLESS (signal_name || property_name, done, - "No signal-name or property-name given for wait action"); - REPORT_UNLESS (!property_name || (property_name && property_value), done, - "`property-name` specified without a `property-value`"); - targets = _find_elements_defined_in_action (scenario, action); - REPORT_UNLESS ((g_list_length (targets) == 1), done, - "Could not find target element."); + 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); - gst_validate_printf (action, "Waiting for '%s'\n", - signal_name ? signal_name : property_name); + REPORT_UNLESS (object_prop_name[1], done, + "Property specification %s is missing a `::propename` part", + deep_property_path); - target = targets->data; - data = waiting_signal_data_new (target, action); + 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, + "No signal-name or property-name given for wait action"); + REPORT_UNLESS (!property_name || (property_name && property_value), done, + "`property-name` specified without a `property-value`"); + + targets = _find_elements_defined_in_action (scenario, action); + REPORT_UNLESS ((g_list_length (targets) == 1), done, + "Could not find target element."); + target = targets->data; + gst_validate_printf (action, "Waiting for '%s'\n", + signal_name ? signal_name : property_name); + } + + + data = + waiting_signal_data_new (target, action, parent_name, object_name, + deep_property_name); if (checking_property) { 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 : GST_VALIDATE_EXECUTE_ACTION_ASYNC; if (checking_property) { - GST_ERROR ("Checking property value"); - if (_check_property (scenario, action, target, property_name, + if (_check_property (scenario, action, data->target, property_name, property_value, FALSE) == GST_VALIDATE_EXECUTE_ACTION_OK) { data->check_done = TRUE; 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); if (gst_structure_has_field (action->structure, "signal-name")) { 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")) { return _execute_wait_for_signal (scenario, action); } else if (gst_structure_has_field (action->structure, "message-type")) { @@ -8146,6 +8229,19 @@ register_action_types (void) .types = "structure", 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} }), "Waits for signal 'signal-name', message 'message-type', or during 'duration' seconds",