mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-22 16:26:39 +00:00
validate: scenario: Add a way to wait for a property to reach a specified value
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5666>
This commit is contained in:
parent
158f469de6
commit
ca584da58d
1 changed files with 144 additions and 43 deletions
|
@ -1380,7 +1380,8 @@ _set_timed_value_property (GstValidateScenario * scenario,
|
|||
|
||||
static GstValidateExecuteActionReturn
|
||||
_check_property (GstValidateScenario * scenario, GstValidateAction * action,
|
||||
gpointer object, const gchar * propname, const GValue * expected_value)
|
||||
gpointer object, const gchar * propname, const GValue * expected_value,
|
||||
gboolean report_error)
|
||||
{
|
||||
GValue cvalue = G_VALUE_INIT;
|
||||
|
||||
|
@ -1388,6 +1389,9 @@ _check_property (GstValidateScenario * scenario, GstValidateAction * action,
|
|||
g_object_get_property (object, propname, &cvalue);
|
||||
|
||||
if (gst_value_compare (&cvalue, expected_value) != GST_VALUE_EQUAL) {
|
||||
if (!report_error)
|
||||
return GST_VALIDATE_EXECUTE_ACTION_ERROR;
|
||||
|
||||
gchar *expected = gst_value_serialize (expected_value), *observed =
|
||||
gst_value_serialize (&cvalue);
|
||||
|
||||
|
@ -1450,7 +1454,7 @@ _set_or_check_properties (GQuark field_id, const GValue * value,
|
|||
gst_validate_object_set_property_full (GST_VALIDATE_REPORTER (scenario),
|
||||
G_OBJECT (obj), paramspec->name, value, flags);
|
||||
else
|
||||
res = _check_property (scenario, action, obj, paramspec->name, value);
|
||||
res = _check_property (scenario, action, obj, paramspec->name, value, TRUE);
|
||||
|
||||
done:
|
||||
gst_clear_object (&obj);
|
||||
|
@ -2831,30 +2835,84 @@ stop_waiting (GstValidateAction * action)
|
|||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
stop_waiting_signal (GstStructure * data)
|
||||
typedef struct
|
||||
{
|
||||
guint sigid = 0;
|
||||
GstElement *target;
|
||||
GstStructure *check = NULL;
|
||||
GstValidateAction *action;
|
||||
GstValidateScenario *scenario;
|
||||
guint sigid;
|
||||
gboolean check_done;
|
||||
gboolean check_property;
|
||||
GMutex lock;
|
||||
} WaitingSignalData;
|
||||
|
||||
gst_structure_get (data, "target", G_TYPE_POINTER, &target,
|
||||
"action", GST_TYPE_VALIDATE_ACTION, &action, "sigid", G_TYPE_UINT, &sigid,
|
||||
NULL);
|
||||
gst_structure_free (data);
|
||||
static WaitingSignalData *
|
||||
waiting_signal_data_new (GstElement * target, GstValidateAction * action)
|
||||
{
|
||||
WaitingSignalData *data = g_new0 (WaitingSignalData, 1);
|
||||
|
||||
scenario = gst_validate_action_get_scenario (action);
|
||||
data->target = gst_object_ref (target);
|
||||
data->action = gst_validate_action_ref (action);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static void
|
||||
waiting_signal_data_free (WaitingSignalData * data)
|
||||
{
|
||||
GstValidateScenario *scenario =
|
||||
gst_validate_action_get_scenario (data->action);
|
||||
|
||||
g_assert (scenario);
|
||||
|
||||
gst_object_unref (data->target);
|
||||
gst_validate_action_unref (data->action);
|
||||
g_free (data);
|
||||
|
||||
gst_object_unref (scenario);
|
||||
}
|
||||
|
||||
static void
|
||||
waiting_signal_data_disconnect (WaitingSignalData * data,
|
||||
GstValidateScenario * scenario)
|
||||
{
|
||||
g_assert (scenario);
|
||||
SCENARIO_LOCK (scenario);
|
||||
g_signal_handler_disconnect (target,
|
||||
sigid ? sigid : scenario->priv->signal_handler_id);
|
||||
if (!sigid)
|
||||
g_signal_handler_disconnect (data->target,
|
||||
data->sigid ? data->sigid : scenario->priv->signal_handler_id);
|
||||
if (!data->sigid)
|
||||
scenario->priv->signal_handler_id = 0;
|
||||
data->sigid = 0;
|
||||
SCENARIO_UNLOCK (scenario);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
stop_waiting_signal_cb (WaitingSignalData * data)
|
||||
{
|
||||
GstStructure *check = NULL;
|
||||
GstValidateAction *action = gst_validate_action_ref (data->action);
|
||||
GstValidateScenario *scenario = NULL;
|
||||
|
||||
g_mutex_lock (&data->lock);
|
||||
if (data->check_done) {
|
||||
GST_INFO_OBJECT (data->action, "Check already done, ignoring signal");
|
||||
g_mutex_unlock (&data->lock);
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
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"),
|
||||
gst_structure_get_value (action->structure, "property-value"),
|
||||
FALSE) != GST_VALIDATE_EXECUTE_ACTION_OK) {
|
||||
|
||||
GST_INFO_OBJECT (scenario, "Property check failed, keep waiting");
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
waiting_signal_data_disconnect (data, scenario);
|
||||
if (gst_structure_get (action->structure, "check", GST_TYPE_STRUCTURE,
|
||||
&check, NULL)) {
|
||||
GstValidateAction *subact =
|
||||
|
@ -2871,10 +2929,11 @@ stop_waiting_signal (GstStructure * data)
|
|||
}
|
||||
|
||||
gst_validate_action_set_done (action);
|
||||
gst_validate_action_unref (action);
|
||||
_add_execute_actions_gsource (scenario);
|
||||
gst_object_unref (scenario);
|
||||
gst_object_unref (target);
|
||||
|
||||
cleanup:
|
||||
gst_validate_action_unref (action);
|
||||
gst_clear_object (&scenario);
|
||||
}
|
||||
|
||||
static GstValidateExecuteActionReturn
|
||||
|
@ -2933,54 +2992,77 @@ _execute_wait_for_signal (GstValidateScenario * scenario,
|
|||
{
|
||||
gboolean non_blocking;
|
||||
GstValidateScenarioPrivate *priv = scenario->priv;
|
||||
const gchar *signal_name = gst_structure_get_string
|
||||
(action->structure, "signal-name");
|
||||
gchar *signal_name = g_strdup (gst_structure_get_string
|
||||
(action->structure, "signal-name"));
|
||||
const gchar *property_name = gst_structure_get_string
|
||||
(action->structure, "property-name");
|
||||
GList *targets = NULL;
|
||||
GstElement *target;
|
||||
GstStructure *data;
|
||||
WaitingSignalData *data;
|
||||
GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK;
|
||||
const GValue *property_value =
|
||||
gst_structure_get_value (action->structure, "property-value");
|
||||
DECLARE_AND_GET_PIPELINE (scenario, action);
|
||||
gboolean checking_property = signal_name == NULL;
|
||||
|
||||
REPORT_UNLESS (signal_name, err, "No signal-name given for wait action");
|
||||
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), err,
|
||||
REPORT_UNLESS ((g_list_length (targets) == 1), done,
|
||||
"Could not find target element.");
|
||||
|
||||
gst_validate_printf (action, "Waiting for '%s' signal\n", signal_name);
|
||||
gst_validate_printf (action, "Waiting for '%s'\n",
|
||||
signal_name ? signal_name : property_name);
|
||||
|
||||
target = targets->data;
|
||||
data = waiting_signal_data_new (target, action);
|
||||
|
||||
if (checking_property) {
|
||||
signal_name = g_strdup_printf ("notify::%s", property_name);
|
||||
g_mutex_lock (&data->lock);
|
||||
}
|
||||
|
||||
SCENARIO_LOCK (scenario);
|
||||
if (priv->execute_actions_source_id) {
|
||||
g_source_remove (priv->execute_actions_source_id);
|
||||
priv->execute_actions_source_id = 0;
|
||||
}
|
||||
|
||||
target = targets->data;
|
||||
data =
|
||||
gst_structure_new ("a", "action", GST_TYPE_VALIDATE_ACTION, action,
|
||||
"target", G_TYPE_POINTER, target, NULL);
|
||||
SCENARIO_LOCK (scenario);
|
||||
priv->signal_handler_id = g_signal_connect_swapped (target, signal_name,
|
||||
(GCallback) stop_waiting_signal, data);
|
||||
priv->signal_handler_id = g_signal_connect_data (target, signal_name,
|
||||
(GCallback) stop_waiting_signal_cb, data,
|
||||
(GClosureNotify) waiting_signal_data_free, G_CONNECT_SWAPPED);
|
||||
|
||||
non_blocking =
|
||||
gst_structure_get_boolean (action->structure, "non-blocking",
|
||||
&non_blocking);
|
||||
if (non_blocking) {
|
||||
gst_structure_set (data, "sigid", G_TYPE_UINT, priv->signal_handler_id,
|
||||
NULL);
|
||||
data->sigid = priv->signal_handler_id;
|
||||
priv->signal_handler_id = 0;
|
||||
}
|
||||
SCENARIO_UNLOCK (scenario);
|
||||
|
||||
gst_object_unref (pipeline);
|
||||
g_list_free (targets);
|
||||
|
||||
|
||||
return non_blocking ? GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING :
|
||||
res =
|
||||
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,
|
||||
property_value, FALSE) == GST_VALIDATE_EXECUTE_ACTION_OK) {
|
||||
data->check_done = TRUE;
|
||||
waiting_signal_data_disconnect (data, scenario);
|
||||
|
||||
err:
|
||||
GST_ERROR ("Property check done, returning OK");
|
||||
res = GST_VALIDATE_EXECUTE_ACTION_OK;
|
||||
}
|
||||
g_mutex_unlock (&data->lock);
|
||||
}
|
||||
|
||||
done:
|
||||
g_free (signal_name);
|
||||
g_list_free_full (targets, gst_object_unref);
|
||||
gst_object_unref (pipeline);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -3015,6 +3097,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, "property-name")) {
|
||||
return _execute_wait_for_signal (scenario, action);
|
||||
} else if (gst_structure_has_field (action->structure, "message-type")) {
|
||||
return _execute_wait_for_message (scenario, action);
|
||||
} else if (on_clock) {
|
||||
|
@ -3437,7 +3521,8 @@ _execute_set_or_check_property (GstValidateScenario * scenario,
|
|||
ret = tmpres;
|
||||
} else {
|
||||
ret =
|
||||
_check_property (scenario, action, l->data, property, property_value);
|
||||
_check_property (scenario, action, l->data, property, property_value,
|
||||
TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6334,8 +6419,8 @@ _action_set_done (GstValidateAction * action)
|
|||
_check_scenario_is_done (scenario);
|
||||
|
||||
if (!gst_validate_parse_next_action_playback_time (scenario)) {
|
||||
gst_validate_error_structure (scenario->priv->actions ? scenario->
|
||||
priv->actions->data : NULL,
|
||||
gst_validate_error_structure (scenario->priv->actions ? scenario->priv->
|
||||
actions->data : NULL,
|
||||
"Could not determine next action playback time!");
|
||||
}
|
||||
|
||||
|
@ -7029,6 +7114,22 @@ register_action_types (void)
|
|||
.types = "string",
|
||||
NULL
|
||||
},
|
||||
{
|
||||
.name = "property-name",
|
||||
.description = "The name of the property to wait for value to be set to what is specified by @property-value.",
|
||||
.mandatory = FALSE,
|
||||
.types = "string",
|
||||
NULL
|
||||
},
|
||||
{
|
||||
.name = "property-value",
|
||||
.description = "The value of the property to be waiting."
|
||||
"\n Example: "
|
||||
"\n `wait, property-name=current-uri, property-value=file:///some/value.mp4, target-element-name=uridecodebin`",
|
||||
.mandatory = FALSE,
|
||||
.types = "string",
|
||||
NULL
|
||||
},
|
||||
{
|
||||
.name = "non-blocking",
|
||||
.description = "**Only for signals**."
|
||||
|
|
Loading…
Reference in a new issue