mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-24 16:18:16 +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
|
static GstValidateExecuteActionReturn
|
||||||
_check_property (GstValidateScenario * scenario, GstValidateAction * action,
|
_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;
|
GValue cvalue = G_VALUE_INIT;
|
||||||
|
|
||||||
|
@ -1388,6 +1389,9 @@ _check_property (GstValidateScenario * scenario, GstValidateAction * action,
|
||||||
g_object_get_property (object, propname, &cvalue);
|
g_object_get_property (object, propname, &cvalue);
|
||||||
|
|
||||||
if (gst_value_compare (&cvalue, expected_value) != GST_VALUE_EQUAL) {
|
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 =
|
gchar *expected = gst_value_serialize (expected_value), *observed =
|
||||||
gst_value_serialize (&cvalue);
|
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),
|
gst_validate_object_set_property_full (GST_VALIDATE_REPORTER (scenario),
|
||||||
G_OBJECT (obj), paramspec->name, value, flags);
|
G_OBJECT (obj), paramspec->name, value, flags);
|
||||||
else
|
else
|
||||||
res = _check_property (scenario, action, obj, paramspec->name, value);
|
res = _check_property (scenario, action, obj, paramspec->name, value, TRUE);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
gst_clear_object (&obj);
|
gst_clear_object (&obj);
|
||||||
|
@ -2831,30 +2835,84 @@ stop_waiting (GstValidateAction * action)
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
typedef struct
|
||||||
stop_waiting_signal (GstStructure * data)
|
|
||||||
{
|
{
|
||||||
guint sigid = 0;
|
|
||||||
GstElement *target;
|
GstElement *target;
|
||||||
GstStructure *check = NULL;
|
|
||||||
GstValidateAction *action;
|
GstValidateAction *action;
|
||||||
GstValidateScenario *scenario;
|
guint sigid;
|
||||||
|
gboolean check_done;
|
||||||
|
gboolean check_property;
|
||||||
|
GMutex lock;
|
||||||
|
} WaitingSignalData;
|
||||||
|
|
||||||
gst_structure_get (data, "target", G_TYPE_POINTER, &target,
|
static WaitingSignalData *
|
||||||
"action", GST_TYPE_VALIDATE_ACTION, &action, "sigid", G_TYPE_UINT, &sigid,
|
waiting_signal_data_new (GstElement * target, GstValidateAction * action)
|
||||||
NULL);
|
{
|
||||||
gst_structure_free (data);
|
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);
|
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);
|
SCENARIO_LOCK (scenario);
|
||||||
g_signal_handler_disconnect (target,
|
g_signal_handler_disconnect (data->target,
|
||||||
sigid ? sigid : scenario->priv->signal_handler_id);
|
data->sigid ? data->sigid : scenario->priv->signal_handler_id);
|
||||||
if (!sigid)
|
if (!data->sigid)
|
||||||
scenario->priv->signal_handler_id = 0;
|
scenario->priv->signal_handler_id = 0;
|
||||||
|
data->sigid = 0;
|
||||||
SCENARIO_UNLOCK (scenario);
|
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,
|
if (gst_structure_get (action->structure, "check", GST_TYPE_STRUCTURE,
|
||||||
&check, NULL)) {
|
&check, NULL)) {
|
||||||
GstValidateAction *subact =
|
GstValidateAction *subact =
|
||||||
|
@ -2871,10 +2929,11 @@ stop_waiting_signal (GstStructure * data)
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_validate_action_set_done (action);
|
gst_validate_action_set_done (action);
|
||||||
gst_validate_action_unref (action);
|
|
||||||
_add_execute_actions_gsource (scenario);
|
_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
|
static GstValidateExecuteActionReturn
|
||||||
|
@ -2933,54 +2992,77 @@ _execute_wait_for_signal (GstValidateScenario * scenario,
|
||||||
{
|
{
|
||||||
gboolean non_blocking;
|
gboolean non_blocking;
|
||||||
GstValidateScenarioPrivate *priv = scenario->priv;
|
GstValidateScenarioPrivate *priv = scenario->priv;
|
||||||
const gchar *signal_name = gst_structure_get_string
|
gchar *signal_name = g_strdup (gst_structure_get_string
|
||||||
(action->structure, "signal-name");
|
(action->structure, "signal-name"));
|
||||||
|
const gchar *property_name = gst_structure_get_string
|
||||||
|
(action->structure, "property-name");
|
||||||
GList *targets = NULL;
|
GList *targets = NULL;
|
||||||
GstElement *target;
|
GstElement *target;
|
||||||
GstStructure *data;
|
WaitingSignalData *data;
|
||||||
GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK;
|
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);
|
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);
|
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.");
|
"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) {
|
if (priv->execute_actions_source_id) {
|
||||||
g_source_remove (priv->execute_actions_source_id);
|
g_source_remove (priv->execute_actions_source_id);
|
||||||
priv->execute_actions_source_id = 0;
|
priv->execute_actions_source_id = 0;
|
||||||
}
|
}
|
||||||
|
priv->signal_handler_id = g_signal_connect_data (target, signal_name,
|
||||||
target = targets->data;
|
(GCallback) stop_waiting_signal_cb, data,
|
||||||
data =
|
(GClosureNotify) waiting_signal_data_free, G_CONNECT_SWAPPED);
|
||||||
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);
|
|
||||||
|
|
||||||
non_blocking =
|
non_blocking =
|
||||||
gst_structure_get_boolean (action->structure, "non-blocking",
|
gst_structure_get_boolean (action->structure, "non-blocking",
|
||||||
&non_blocking);
|
&non_blocking);
|
||||||
if (non_blocking) {
|
if (non_blocking) {
|
||||||
gst_structure_set (data, "sigid", G_TYPE_UINT, priv->signal_handler_id,
|
data->sigid = priv->signal_handler_id;
|
||||||
NULL);
|
|
||||||
priv->signal_handler_id = 0;
|
priv->signal_handler_id = 0;
|
||||||
}
|
}
|
||||||
SCENARIO_UNLOCK (scenario);
|
SCENARIO_UNLOCK (scenario);
|
||||||
|
|
||||||
gst_object_unref (pipeline);
|
res =
|
||||||
g_list_free (targets);
|
non_blocking ? GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING :
|
||||||
|
|
||||||
|
|
||||||
return non_blocking ? GST_VALIDATE_EXECUTE_ACTION_NON_BLOCKING :
|
|
||||||
GST_VALIDATE_EXECUTE_ACTION_ASYNC;
|
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);
|
g_list_free_full (targets, gst_object_unref);
|
||||||
gst_object_unref (pipeline);
|
gst_object_unref (pipeline);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3015,6 +3097,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, "property-name")) {
|
||||||
|
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")) {
|
||||||
return _execute_wait_for_message (scenario, action);
|
return _execute_wait_for_message (scenario, action);
|
||||||
} else if (on_clock) {
|
} else if (on_clock) {
|
||||||
|
@ -3437,7 +3521,8 @@ _execute_set_or_check_property (GstValidateScenario * scenario,
|
||||||
ret = tmpres;
|
ret = tmpres;
|
||||||
} else {
|
} else {
|
||||||
ret =
|
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);
|
_check_scenario_is_done (scenario);
|
||||||
|
|
||||||
if (!gst_validate_parse_next_action_playback_time (scenario)) {
|
if (!gst_validate_parse_next_action_playback_time (scenario)) {
|
||||||
gst_validate_error_structure (scenario->priv->actions ? scenario->
|
gst_validate_error_structure (scenario->priv->actions ? scenario->priv->
|
||||||
priv->actions->data : NULL,
|
actions->data : NULL,
|
||||||
"Could not determine next action playback time!");
|
"Could not determine next action playback time!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7029,6 +7114,22 @@ register_action_types (void)
|
||||||
.types = "string",
|
.types = "string",
|
||||||
NULL
|
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",
|
.name = "non-blocking",
|
||||||
.description = "**Only for signals**."
|
.description = "**Only for signals**."
|
||||||
|
|
Loading…
Reference in a new issue