mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
validate:scenario: Replace the sub-action
with a foreach
action type
Sub-actions were really hard to use and conceptually weird. The implementation was ugly and made the code complex for nothing. Instead this commit introduces a `foreach` action type which allows repeating actions passed in an `actions` array the number of time specified by any `GstIntRange` value defined in the structure or its `repeat` field. This commit also makes sure that all action got through gst_validate_action_set_done upon finalization. + Cleanup surrounding code + Add tests Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-devtools/-/merge_requests/207>
This commit is contained in:
parent
e7355ea039
commit
9c08bfcaca
10 changed files with 528 additions and 206 deletions
|
@ -1,3 +1,8 @@
|
||||||
description, duration=0, summary="Set state to NULL->PLAYING->NULL 20 times", need-clock-sync=true, min-media-duration=1.0, live_content_compatible=True, handles-states=true, ignore-eos=true
|
description, duration=0, summary="Set state to NULL->PLAYING->NULL 20 times", need-clock-sync=true, min-media-duration=1.0, live_content_compatible=True, handles-states=true, ignore-eos=true
|
||||||
set-state, state="playing", sub-action="set-state, state=null", repeat=40
|
|
||||||
|
foreach, i=[0, 40],
|
||||||
|
actions = {
|
||||||
|
"set-state, state=playing",
|
||||||
|
"set-state, state=null",
|
||||||
|
}
|
||||||
stop;
|
stop;
|
||||||
|
|
|
@ -47,7 +47,7 @@ void register_action_types (void);
|
||||||
* as we used to have to print actions in the action execution function
|
* as we used to have to print actions in the action execution function
|
||||||
* and this is done by the scenario itself now */
|
* and this is done by the scenario itself now */
|
||||||
G_GNUC_INTERNAL gboolean _action_check_and_set_printed (GstValidateAction *action);
|
G_GNUC_INTERNAL gboolean _action_check_and_set_printed (GstValidateAction *action);
|
||||||
G_GNUC_INTERNAL gboolean gst_validate_action_is_subaction (GstValidateAction *action);
|
G_GNUC_INTERNAL gboolean gst_validate_action_get_level (GstValidateAction *action);
|
||||||
G_GNUC_INTERNAL gboolean gst_validate_scenario_check_and_set_needs_clock_sync (GList *structures, GstStructure **meta);
|
G_GNUC_INTERNAL gboolean gst_validate_scenario_check_and_set_needs_clock_sync (GList *structures, GstStructure **meta);
|
||||||
|
|
||||||
#define GST_VALIDATE_SCENARIO_SUFFIX ".scenario"
|
#define GST_VALIDATE_SCENARIO_SUFFIX ".scenario"
|
||||||
|
|
|
@ -834,27 +834,36 @@ gst_validate_printf (gpointer source, const gchar * format, ...)
|
||||||
va_end (var_args);
|
va_end (var_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
GString *str;
|
||||||
|
gint indent;
|
||||||
|
gint printed;
|
||||||
|
} PrintActionFieldData;
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
_append_value (GQuark field_id, const GValue * value, GString * string)
|
_append_value (GQuark field_id, const GValue * value, PrintActionFieldData * d)
|
||||||
{
|
{
|
||||||
gchar *val_str = NULL;
|
gchar *val_str = NULL;
|
||||||
|
const gchar *fieldname = g_quark_to_string (field_id);
|
||||||
|
|
||||||
if (g_strcmp0 (g_quark_to_string (field_id), "sub-action") == 0)
|
if (g_str_has_prefix (fieldname, "__") && g_str_has_suffix (fieldname, "__"))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
if (g_strcmp0 (g_quark_to_string (field_id), "repeat") == 0)
|
if (g_strcmp0 (fieldname, "repeat") == 0)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
d->printed++;
|
||||||
if (G_VALUE_TYPE (value) == GST_TYPE_CLOCK_TIME)
|
if (G_VALUE_TYPE (value) == GST_TYPE_CLOCK_TIME)
|
||||||
val_str = g_strdup_printf ("%" GST_TIME_FORMAT,
|
val_str = g_strdup_printf ("%" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (g_value_get_uint64 (value)));
|
GST_TIME_ARGS (g_value_get_uint64 (value)));
|
||||||
else
|
else
|
||||||
val_str = gst_value_serialize (value);
|
val_str = gst_value_serialize (value);
|
||||||
|
|
||||||
g_string_append (string, "\n - ");
|
g_string_append_printf (d->str, "\n%*c - ", d->indent, ' ');
|
||||||
g_string_append (string, g_quark_to_string (field_id));
|
g_string_append (d->str, fieldname);
|
||||||
g_string_append_len (string, "=", 1);
|
g_string_append_len (d->str, "=", 1);
|
||||||
g_string_append (string, val_str);
|
g_string_append (d->str, val_str);
|
||||||
|
|
||||||
g_free (val_str);
|
g_free (val_str);
|
||||||
|
|
||||||
|
@ -874,26 +883,24 @@ gst_validate_print_action (GstValidateAction * action, const gchar * message)
|
||||||
GString *string = NULL;
|
GString *string = NULL;
|
||||||
|
|
||||||
if (message == NULL) {
|
if (message == NULL) {
|
||||||
gint nrepeats;
|
gint indent = (gst_validate_action_get_level (action) * 2);
|
||||||
|
PrintActionFieldData d = { NULL, indent, 0 };
|
||||||
string = g_string_new (NULL);
|
d.str = string = g_string_new (NULL);
|
||||||
|
|
||||||
if (gst_validate_action_is_subaction (action))
|
|
||||||
g_string_append_printf (string, "(subaction)");
|
|
||||||
|
|
||||||
if (gst_structure_get_int (action->structure, "repeat", &nrepeats))
|
|
||||||
g_string_append_printf (string, "(%d/%d)", nrepeats - action->repeat + 1,
|
|
||||||
nrepeats);
|
|
||||||
|
|
||||||
g_string_append_printf (string, "%s",
|
g_string_append_printf (string, "%s",
|
||||||
gst_structure_get_name (action->structure));
|
gst_structure_get_name (action->structure));
|
||||||
|
|
||||||
g_string_append_len (string, " ( ", 3);
|
if (GST_VALIDATE_ACTION_N_REPEATS (action))
|
||||||
gst_structure_foreach (action->structure,
|
g_string_append_printf (string, " [%s=%d/%d]",
|
||||||
(GstStructureForeachFunc) _append_value, string);
|
GST_VALIDATE_ACTION_RANGE_NAME (action) ?
|
||||||
|
GST_VALIDATE_ACTION_RANGE_NAME (action) : "repeat", action->repeat,
|
||||||
|
GST_VALIDATE_ACTION_N_REPEATS (action));
|
||||||
|
|
||||||
if (gst_structure_n_fields (action->structure))
|
g_string_append (string, " ( ");
|
||||||
g_string_append (string, "\n)\n");
|
gst_structure_foreach (action->structure,
|
||||||
|
(GstStructureForeachFunc) _append_value, &d);
|
||||||
|
if (d.printed)
|
||||||
|
g_string_append_printf (string, "\n%*c)\n", indent, ' ');
|
||||||
else
|
else
|
||||||
g_string_append (string, ")\n");
|
g_string_append (string, ")\n");
|
||||||
message = string->str;
|
message = string->str;
|
||||||
|
@ -980,12 +987,15 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args)
|
||||||
if (source) {
|
if (source) {
|
||||||
if (*(GType *) source == GST_TYPE_VALIDATE_ACTION) {
|
if (*(GType *) source == GST_TYPE_VALIDATE_ACTION) {
|
||||||
GstValidateAction *action = (GstValidateAction *) source;
|
GstValidateAction *action = (GstValidateAction *) source;
|
||||||
|
gint indent = gst_validate_action_get_level (action) * 2;
|
||||||
|
|
||||||
if (_action_check_and_set_printed (action))
|
if (_action_check_and_set_printed (action))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
g_string_assign (string, "\nExecuting ");
|
if (!indent)
|
||||||
|
g_string_assign (string, "Executing ");
|
||||||
|
else
|
||||||
|
g_string_append_printf (string, "%*c↳ Executing ", indent - 2, ' ');
|
||||||
} else if (*(GType *) source == GST_TYPE_VALIDATE_ACTION_TYPE) {
|
} else if (*(GType *) source == GST_TYPE_VALIDATE_ACTION_TYPE) {
|
||||||
gint i;
|
gint i;
|
||||||
gint n_params;
|
gint n_params;
|
||||||
|
|
|
@ -345,28 +345,37 @@ gst_validate_report_action (GstValidateReporter * reporter,
|
||||||
const gchar * format, ...)
|
const gchar * format, ...)
|
||||||
{
|
{
|
||||||
va_list var_args;
|
va_list var_args;
|
||||||
gint nrepeats;
|
GString *f;
|
||||||
gchar *f, *repeat = NULL;
|
|
||||||
|
|
||||||
if (action && gst_structure_get_int (action->structure, "repeat", &nrepeats))
|
if (!action) {
|
||||||
repeat =
|
f = g_string_new (format);
|
||||||
g_strdup_printf (" (repeat: %d/%d)", nrepeats - action->repeat + 1,
|
goto done;
|
||||||
nrepeats);
|
}
|
||||||
|
|
||||||
f = action ? g_strdup_printf ("\n> %s:%d%s\n> %d | %s\n> %*c|\n",
|
f = g_string_new (NULL);
|
||||||
GST_VALIDATE_ACTION_FILENAME (action),
|
g_string_append_printf (f, "\n> %s:%d", GST_VALIDATE_ACTION_FILENAME (action),
|
||||||
GST_VALIDATE_ACTION_LINENO (action), repeat ? repeat : "",
|
GST_VALIDATE_ACTION_LINENO (action));
|
||||||
GST_VALIDATE_ACTION_LINENO (action), format,
|
|
||||||
(gint) floor (log10 (abs ((GST_VALIDATE_ACTION_LINENO (action))))) + 1,
|
|
||||||
' ')
|
|
||||||
: g_strdup (format);
|
|
||||||
|
|
||||||
|
if (GST_VALIDATE_ACTION_N_REPEATS (action))
|
||||||
|
g_string_append_printf (f, " (repeat: %d/%d)",
|
||||||
|
action->repeat, GST_VALIDATE_ACTION_N_REPEATS (action));
|
||||||
|
|
||||||
|
g_string_append_printf (f, "\n%s", GST_VALIDATE_ACTION_DEBUG (action));
|
||||||
|
if (gst_validate_action_get_level (action)) {
|
||||||
|
gchar *subaction_str = gst_structure_to_string (action->structure);
|
||||||
|
|
||||||
|
g_string_append_printf (f, "\n |-> %s", subaction_str);
|
||||||
|
g_free (subaction_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_string_append_printf (f, "\n >\n > %s", format);
|
||||||
|
|
||||||
|
done:
|
||||||
va_start (var_args, format);
|
va_start (var_args, format);
|
||||||
gst_validate_report_valist (reporter, issue_id, f, var_args);
|
gst_validate_report_valist (reporter, issue_id, f->str, var_args);
|
||||||
va_end (var_args);
|
va_end (var_args);
|
||||||
|
|
||||||
g_free (f);
|
g_string_free (f, TRUE);
|
||||||
g_free (repeat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -374,9 +374,11 @@ struct _GstValidateActionPrivate
|
||||||
GstValidateExecuteActionReturn state; /* Actually ActionState */
|
GstValidateExecuteActionReturn state; /* Actually ActionState */
|
||||||
gboolean printed;
|
gboolean printed;
|
||||||
gboolean executing_last_subaction;
|
gboolean executing_last_subaction;
|
||||||
|
gboolean subaction_level;
|
||||||
gboolean optional;
|
gboolean optional;
|
||||||
|
|
||||||
GstClockTime execution_time;
|
GstClockTime execution_time;
|
||||||
|
GstClockTime execution_duration;
|
||||||
GstClockTime timeout;
|
GstClockTime timeout;
|
||||||
|
|
||||||
GWeakRef scenario;
|
GWeakRef scenario;
|
||||||
|
@ -457,6 +459,31 @@ _action_copy (GstValidateAction * act)
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const gchar *
|
||||||
|
gst_validate_action_return_get_name (GstValidateActionReturn r)
|
||||||
|
{
|
||||||
|
switch (r) {
|
||||||
|
case GST_VALIDATE_EXECUTE_ACTION_ERROR:
|
||||||
|
return "ERROR";
|
||||||
|
case GST_VALIDATE_EXECUTE_ACTION_OK:
|
||||||
|
return "OK";
|
||||||
|
case GST_VALIDATE_EXECUTE_ACTION_ASYNC:
|
||||||
|
return "ASYNC";
|
||||||
|
case GST_VALIDATE_EXECUTE_ACTION_INTERLACED:
|
||||||
|
return "INTERLACED";
|
||||||
|
case GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED:
|
||||||
|
return "ERROR(reported)";
|
||||||
|
case GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS:
|
||||||
|
return "IN_PROGRESS";
|
||||||
|
case GST_VALIDATE_EXECUTE_ACTION_NONE:
|
||||||
|
return "NONE";
|
||||||
|
case GST_VALIDATE_EXECUTE_ACTION_SKIP:
|
||||||
|
return "SKIP";
|
||||||
|
}
|
||||||
|
g_assert_not_reached ();
|
||||||
|
return "???";
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_action_free (GstValidateAction * action)
|
_action_free (GstValidateAction * action)
|
||||||
{
|
{
|
||||||
|
@ -508,6 +535,7 @@ gst_validate_action_new (GstValidateScenario * scenario,
|
||||||
gst_validate_action_init (action);
|
gst_validate_action_init (action);
|
||||||
action->playback_time = GST_CLOCK_TIME_NONE;
|
action->playback_time = GST_CLOCK_TIME_NONE;
|
||||||
action->priv->timeout = GST_CLOCK_TIME_NONE;
|
action->priv->timeout = GST_CLOCK_TIME_NONE;
|
||||||
|
action->priv->state = GST_VALIDATE_EXECUTE_ACTION_NONE;
|
||||||
action->type = action_type->name;
|
action->type = action_type->name;
|
||||||
action->repeat = -1;
|
action->repeat = -1;
|
||||||
|
|
||||||
|
@ -541,11 +569,10 @@ _action_check_and_set_printed (GstValidateAction * action)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gint
|
||||||
gst_validate_action_is_subaction (GstValidateAction * action)
|
gst_validate_action_get_level (GstValidateAction * action)
|
||||||
{
|
{
|
||||||
return !gst_structure_is_equal (action->structure,
|
return action->priv->subaction_level;
|
||||||
action->priv->main_structure);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* GstValidateActionType implementation */
|
/* GstValidateActionType implementation */
|
||||||
|
@ -1186,7 +1213,7 @@ _set_timed_value (GQuark field_id, const GValue * gvalue,
|
||||||
const gchar *unused_fields[] =
|
const gchar *unused_fields[] =
|
||||||
{ "binding-type", "source-type", "interpolation-mode",
|
{ "binding-type", "source-type", "interpolation-mode",
|
||||||
"timestamp", "__scenario__", "__action__", "__res__", "repeat",
|
"timestamp", "__scenario__", "__action__", "__res__", "repeat",
|
||||||
"sub-action", "playback-time", NULL
|
"playback-time", NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
if (g_strv_contains (unused_fields, field))
|
if (g_strv_contains (unused_fields, field))
|
||||||
|
@ -1348,7 +1375,7 @@ _set_or_check_properties (GQuark field_id, const GValue * value,
|
||||||
GParamSpec *paramspec = NULL;
|
GParamSpec *paramspec = NULL;
|
||||||
const gchar *field = g_quark_to_string (field_id);
|
const gchar *field = g_quark_to_string (field_id);
|
||||||
const gchar *unused_fields[] = { "__scenario__", "__action__", "__res__",
|
const gchar *unused_fields[] = { "__scenario__", "__action__", "__res__",
|
||||||
"sub-action", "playback-time", "repeat", NULL
|
"playback-time", "repeat", NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
if (g_strv_contains (unused_fields, field))
|
if (g_strv_contains (unused_fields, field))
|
||||||
|
@ -2381,6 +2408,27 @@ gst_validate_parse_next_action_playback_time (GstValidateScenario * self)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_foreach_find_iterator (GQuark field_id, GValue * value,
|
||||||
|
GstValidateAction * action)
|
||||||
|
{
|
||||||
|
if (!g_strcmp0 (g_quark_to_string (field_id), "actions"))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (!GST_VALUE_HOLDS_INT_RANGE (value))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (GST_VALIDATE_ACTION_RANGE_NAME (action)) {
|
||||||
|
gst_validate_error_structure (action, "Found several ranges in structure, "
|
||||||
|
"it is not supported");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_VALIDATE_ACTION_RANGE_NAME (action) = g_quark_to_string (field_id);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
GstValidateExecuteActionReturn
|
GstValidateExecuteActionReturn
|
||||||
gst_validate_execute_action (GstValidateActionType * action_type,
|
gst_validate_execute_action (GstValidateActionType * action_type,
|
||||||
GstValidateAction * action)
|
GstValidateAction * action)
|
||||||
|
@ -2395,6 +2443,11 @@ gst_validate_execute_action (GstValidateActionType * action_type,
|
||||||
|
|
||||||
if (action_type->prepare) {
|
if (action_type->prepare) {
|
||||||
res = action_type->prepare (action);
|
res = action_type->prepare (action);
|
||||||
|
if (res == GST_VALIDATE_EXECUTE_ACTION_SKIP) {
|
||||||
|
gst_validate_print_action (action, NULL);
|
||||||
|
return GST_VALIDATE_EXECUTE_ACTION_OK;
|
||||||
|
}
|
||||||
|
|
||||||
if (res != GST_VALIDATE_EXECUTE_ACTION_OK) {
|
if (res != GST_VALIDATE_EXECUTE_ACTION_OK) {
|
||||||
GST_ERROR_OBJECT (scenario, "Action %" GST_PTR_FORMAT
|
GST_ERROR_OBJECT (scenario, "Action %" GST_PTR_FORMAT
|
||||||
" could not be prepared", action->structure);
|
" could not be prepared", action->structure);
|
||||||
|
@ -2412,18 +2465,6 @@ gst_validate_execute_action (GstValidateActionType * action_type,
|
||||||
res = action_type->execute (scenario, action);
|
res = action_type->execute (scenario, action);
|
||||||
gst_object_unref (scenario);
|
gst_object_unref (scenario);
|
||||||
|
|
||||||
if (!gst_structure_has_field (action->structure, "sub-action")) {
|
|
||||||
gst_structure_free (action->structure);
|
|
||||||
action->priv->printed = FALSE;
|
|
||||||
action->structure = gst_structure_copy (action->priv->main_structure);
|
|
||||||
|
|
||||||
if (!(action->name = gst_structure_get_string (action->structure, "name")))
|
|
||||||
action->name = "";
|
|
||||||
|
|
||||||
if (res == GST_VALIDATE_EXECUTE_ACTION_ASYNC)
|
|
||||||
action->priv->executing_last_subaction = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2540,75 +2581,24 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action,
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstValidateExecuteActionReturn
|
static gboolean
|
||||||
_execute_sub_action_action (GstValidateAction * action)
|
gst_validate_scenario_execute_next_or_restart_looping (GstValidateScenario *
|
||||||
|
scenario)
|
||||||
{
|
{
|
||||||
const gchar *subaction_str;
|
/* Recurse to the next action if it is possible
|
||||||
GstStructure *subaction_struct = NULL;
|
* to execute right away */
|
||||||
GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK;
|
if (!scenario->priv->execute_on_idle) {
|
||||||
GstValidateScenario *scenario = NULL;
|
GST_DEBUG_OBJECT (scenario, "linking next action execution");
|
||||||
|
|
||||||
if (action->priv->executing_last_subaction) {
|
|
||||||
action->priv->executing_last_subaction = FALSE;
|
|
||||||
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
scenario = gst_validate_action_get_scenario (action);
|
|
||||||
g_assert (scenario);
|
|
||||||
subaction_str = gst_structure_get_string (action->structure, "sub-action");
|
|
||||||
if (subaction_str) {
|
|
||||||
subaction_struct = gst_structure_from_string (subaction_str, NULL);
|
|
||||||
|
|
||||||
if (subaction_struct == NULL) {
|
|
||||||
GST_VALIDATE_REPORT_ACTION (scenario, action, SCENARIO_FILE_MALFORMED,
|
|
||||||
"Sub action %s could not be parsed", subaction_str);
|
|
||||||
|
|
||||||
res = GST_VALIDATE_EXECUTE_ACTION_ERROR;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return execute_next_action (scenario);
|
||||||
} else {
|
} else {
|
||||||
gst_structure_get (action->structure, "sub-action", GST_TYPE_STRUCTURE,
|
_add_execute_actions_gsource (scenario);
|
||||||
&subaction_struct, NULL);
|
GST_DEBUG_OBJECT (scenario, "Executing only on idle, waiting for"
|
||||||
|
" next dispatch");
|
||||||
}
|
}
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
if (subaction_struct) {
|
|
||||||
if (action->structure) {
|
|
||||||
GST_INFO_OBJECT (scenario, "Clearing old action structure");
|
|
||||||
gst_structure_free (action->structure);
|
|
||||||
}
|
|
||||||
|
|
||||||
res = _fill_action (scenario, action, subaction_struct, FALSE);
|
|
||||||
if (res == GST_VALIDATE_EXECUTE_ACTION_ERROR) {
|
|
||||||
GST_VALIDATE_REPORT_ACTION (scenario, action,
|
|
||||||
SCENARIO_ACTION_EXECUTION_ERROR,
|
|
||||||
"Sub action %" GST_PTR_FORMAT " could not be filled",
|
|
||||||
subaction_struct);
|
|
||||||
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!GST_CLOCK_TIME_IS_VALID (action->playback_time)) {
|
|
||||||
GstValidateActionType *action_type = _find_action_type (action->type);
|
|
||||||
|
|
||||||
action->priv->printed = FALSE;
|
|
||||||
res = gst_validate_execute_action (action_type, action);
|
|
||||||
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
if (scenario)
|
|
||||||
gst_object_unref (scenario);
|
|
||||||
if (subaction_struct)
|
|
||||||
gst_structure_free (subaction_struct);
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* This is the main action execution function
|
/* This is the main action execution function
|
||||||
* it checks whether it is time to run the next action
|
* it checks whether it is time to run the next action
|
||||||
* and if it is the case executes it.
|
* and if it is the case executes it.
|
||||||
|
@ -2620,7 +2610,6 @@ done:
|
||||||
static gboolean
|
static gboolean
|
||||||
execute_next_action_full (GstValidateScenario * scenario, GstMessage * message)
|
execute_next_action_full (GstValidateScenario * scenario, GstMessage * message)
|
||||||
{
|
{
|
||||||
GList *tmp;
|
|
||||||
gdouble rate = 1.0;
|
gdouble rate = 1.0;
|
||||||
GstClockTime position = -1;
|
GstClockTime position = -1;
|
||||||
GstValidateAction *act = NULL;
|
GstValidateAction *act = NULL;
|
||||||
|
@ -2642,13 +2631,39 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message)
|
||||||
if (scenario->priv->actions)
|
if (scenario->priv->actions)
|
||||||
act = scenario->priv->actions->data;
|
act = scenario->priv->actions->data;
|
||||||
|
|
||||||
if (act) {
|
if (!act)
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
|
||||||
if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS) {
|
switch (act->priv->state) {
|
||||||
|
case GST_VALIDATE_EXECUTE_ACTION_NONE:
|
||||||
|
break;
|
||||||
|
case GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS:
|
||||||
|
GST_INFO_OBJECT (scenario, "Action %s:%d still running",
|
||||||
|
GST_VALIDATE_ACTION_FILENAME (act), GST_VALIDATE_ACTION_LINENO (act));
|
||||||
return G_SOURCE_CONTINUE;
|
return G_SOURCE_CONTINUE;
|
||||||
} else if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_OK) {
|
case GST_VALIDATE_EXECUTE_ACTION_ERROR:
|
||||||
tmp = priv->actions;
|
GST_VALIDATE_REPORT_ACTION (scenario, act,
|
||||||
priv->actions = g_list_remove_link (priv->actions, tmp);
|
SCENARIO_ACTION_EXECUTION_ERROR, "Action %s failed", act->type);
|
||||||
|
case GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED:
|
||||||
|
case GST_VALIDATE_EXECUTE_ACTION_OK:
|
||||||
|
{
|
||||||
|
gchar *repeat = NULL;
|
||||||
|
|
||||||
|
if (GST_VALIDATE_ACTION_N_REPEATS (act))
|
||||||
|
repeat =
|
||||||
|
g_strdup_printf ("[%d/%d]", act->repeat,
|
||||||
|
GST_VALIDATE_ACTION_N_REPEATS (act));
|
||||||
|
|
||||||
|
gst_validate_printf (NULL,
|
||||||
|
"%*c⇨ Action %s '%s' %s (duration: %" GST_TIME_FORMAT ")\n\n",
|
||||||
|
(act->priv->subaction_level * 2) - 1, ' ',
|
||||||
|
gst_structure_get_name (act->priv->main_structure),
|
||||||
|
gst_validate_action_return_get_name (act->priv->state),
|
||||||
|
repeat ? repeat : "", GST_TIME_ARGS (act->priv->execution_duration));
|
||||||
|
g_free (repeat);
|
||||||
|
|
||||||
|
priv->actions = g_list_remove (priv->actions, act);
|
||||||
|
gst_validate_action_unref (act);
|
||||||
|
|
||||||
if (!gst_validate_parse_next_action_playback_time (scenario)) {
|
if (!gst_validate_parse_next_action_playback_time (scenario)) {
|
||||||
gst_validate_error_structure (priv->actions ? priv->
|
gst_validate_error_structure (priv->actions ? priv->
|
||||||
|
@ -2662,16 +2677,15 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message)
|
||||||
GST_INFO_OBJECT (scenario, "Action %" GST_PTR_FORMAT " is DONE now"
|
GST_INFO_OBJECT (scenario, "Action %" GST_PTR_FORMAT " is DONE now"
|
||||||
" executing next", act->structure);
|
" executing next", act->structure);
|
||||||
|
|
||||||
gst_validate_action_unref (act);
|
|
||||||
g_list_free (tmp);
|
|
||||||
|
|
||||||
if (scenario->priv->actions) {
|
if (scenario->priv->actions) {
|
||||||
act = scenario->priv->actions->data;
|
act = scenario->priv->actions->data;
|
||||||
} else {
|
} else {
|
||||||
_check_scenario_is_done (scenario);
|
_check_scenario_is_done (scenario);
|
||||||
act = NULL;
|
act = NULL;
|
||||||
}
|
}
|
||||||
} else if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_ASYNC) {
|
break;
|
||||||
|
}
|
||||||
|
case GST_VALIDATE_EXECUTE_ACTION_ASYNC:
|
||||||
if (GST_CLOCK_TIME_IS_VALID (act->priv->timeout)) {
|
if (GST_CLOCK_TIME_IS_VALID (act->priv->timeout)) {
|
||||||
GstClockTime etime =
|
GstClockTime etime =
|
||||||
gst_util_get_timestamp () - act->priv->execution_time;
|
gst_util_get_timestamp () - act->priv->execution_time;
|
||||||
|
@ -2691,7 +2705,8 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message)
|
||||||
act->structure);
|
act->structure);
|
||||||
|
|
||||||
return G_SOURCE_CONTINUE;
|
return G_SOURCE_CONTINUE;
|
||||||
}
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message) {
|
if (message) {
|
||||||
|
@ -2721,68 +2736,25 @@ execute_next_action_full (GstValidateScenario * scenario, GstMessage * message)
|
||||||
gst_structure_remove_field (act->structure, "on-message");
|
gst_structure_remove_field (act->structure, "on-message");
|
||||||
|
|
||||||
act->priv->state = gst_validate_execute_action (type, act);
|
act->priv->state = gst_validate_execute_action (type, act);
|
||||||
if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_ERROR) {
|
switch (act->priv->state) {
|
||||||
gchar *str = gst_structure_to_string (act->structure);
|
case GST_VALIDATE_EXECUTE_ACTION_ASYNC:
|
||||||
|
GST_DEBUG_OBJECT (scenario, "Remove source, waiting for action"
|
||||||
|
" to be done.");
|
||||||
|
|
||||||
GST_VALIDATE_REPORT_ACTION (scenario, act,
|
SCENARIO_LOCK (scenario);
|
||||||
SCENARIO_ACTION_EXECUTION_ERROR, "Could not execute %s", str);
|
priv->execute_actions_source_id = 0;
|
||||||
|
SCENARIO_UNLOCK (scenario);
|
||||||
|
|
||||||
g_free (str);
|
return G_SOURCE_CONTINUE;
|
||||||
}
|
case GST_VALIDATE_EXECUTE_ACTION_INTERLACED:
|
||||||
|
|
||||||
if (act->priv->state == GST_VALIDATE_EXECUTE_ACTION_OK) {
|
|
||||||
act->priv->state = _execute_sub_action_action (act);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (act->priv->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) {
|
|
||||||
tmp = priv->actions;
|
|
||||||
priv->actions = g_list_remove_link (priv->actions, tmp);
|
|
||||||
|
|
||||||
if (!gst_validate_parse_next_action_playback_time (scenario)) {
|
|
||||||
gst_validate_error_structure (priv->actions ? priv->actions->data : NULL,
|
|
||||||
"Could not determine next action playback time!");
|
|
||||||
|
|
||||||
return G_SOURCE_REMOVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (act->priv->state != GST_VALIDATE_EXECUTE_ACTION_INTERLACED)
|
|
||||||
gst_validate_action_unref (act);
|
|
||||||
else {
|
|
||||||
SCENARIO_LOCK (scenario);
|
SCENARIO_LOCK (scenario);
|
||||||
priv->interlaced_actions = g_list_append (priv->interlaced_actions, act);
|
priv->interlaced_actions = g_list_append (priv->interlaced_actions, act);
|
||||||
SCENARIO_UNLOCK (scenario);
|
SCENARIO_UNLOCK (scenario);
|
||||||
}
|
return gst_validate_scenario_execute_next_or_restart_looping (scenario);
|
||||||
|
default:
|
||||||
if (priv->actions == NULL)
|
gst_validate_action_set_done (act);
|
||||||
_check_scenario_is_done (scenario);
|
|
||||||
|
|
||||||
g_list_free (tmp);
|
|
||||||
|
|
||||||
/* Recurse to the next action if it is possible
|
|
||||||
* to execute right away */
|
|
||||||
if (!scenario->priv->execute_on_idle) {
|
|
||||||
GST_DEBUG_OBJECT (scenario, "linking next action execution");
|
|
||||||
|
|
||||||
return execute_next_action (scenario);
|
|
||||||
} else {
|
|
||||||
_add_execute_actions_gsource (scenario);
|
|
||||||
GST_DEBUG_OBJECT (scenario, "Executing only on idle, waiting for"
|
|
||||||
" next dispatch");
|
|
||||||
|
|
||||||
return G_SOURCE_CONTINUE;
|
return G_SOURCE_CONTINUE;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
GST_DEBUG_OBJECT (scenario, "Remove source, waiting for action"
|
|
||||||
" to be done.");
|
|
||||||
|
|
||||||
SCENARIO_LOCK (scenario);
|
|
||||||
priv->execute_actions_source_id = 0;
|
|
||||||
SCENARIO_UNLOCK (scenario);
|
|
||||||
|
|
||||||
return G_SOURCE_CONTINUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return G_SOURCE_CONTINUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -3157,6 +3129,24 @@ _execute_check_action_type_calls (GstValidateScenario * scenario,
|
||||||
"%s called %d times instead of expected %d", type, t->priv->n_calls, n);
|
"%s called %d times instead of expected %d", type, t->priv->n_calls, n);
|
||||||
|
|
||||||
|
|
||||||
|
done:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstValidateExecuteActionReturn
|
||||||
|
_execute_check_subaction_level (GstValidateScenario * scenario,
|
||||||
|
GstValidateAction * action)
|
||||||
|
{
|
||||||
|
GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK;
|
||||||
|
gint n;
|
||||||
|
|
||||||
|
REPORT_UNLESS (gst_structure_get_int (action->structure, "level", &n),
|
||||||
|
done, "No `n`!");
|
||||||
|
REPORT_UNLESS (gst_validate_action_get_level (action) == n, done,
|
||||||
|
"Expected subaction level %d, got %d", n,
|
||||||
|
gst_validate_action_get_level (action));
|
||||||
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -3679,7 +3669,9 @@ gst_validate_action_default_prepare_func (GstValidateAction * action)
|
||||||
|
|
||||||
if (GST_VALIDATE_ACTION_N_REPEATS (action))
|
if (GST_VALIDATE_ACTION_N_REPEATS (action))
|
||||||
gst_structure_set (scenario->priv->vars,
|
gst_structure_set (scenario->priv->vars,
|
||||||
"repeat", G_TYPE_INT, action->repeat, NULL);
|
GST_VALIDATE_ACTION_RANGE_NAME (action) ?
|
||||||
|
GST_VALIDATE_ACTION_RANGE_NAME (action) : "repeat", G_TYPE_INT,
|
||||||
|
action->repeat, NULL);
|
||||||
gst_validate_structure_resolve_variables (action, action->structure,
|
gst_validate_structure_resolve_variables (action, action->structure,
|
||||||
scenario->priv->vars);
|
scenario->priv->vars);
|
||||||
for (i = 0; type->parameters[i].name; i++) {
|
for (i = 0; type->parameters[i].name; i++) {
|
||||||
|
@ -3710,6 +3702,136 @@ gst_validate_set_property_prepare_func (GstValidateAction * action)
|
||||||
return gst_validate_action_default_prepare_func (action);
|
return gst_validate_action_default_prepare_func (action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GList *
|
||||||
|
add_gvalue_to_list_as_struct (gpointer source, GList * list, const GValue * v)
|
||||||
|
{
|
||||||
|
if (G_VALUE_HOLDS_STRING (v)) {
|
||||||
|
GstStructure *structure =
|
||||||
|
gst_structure_new_from_string (g_value_get_string (v));
|
||||||
|
|
||||||
|
if (!structure)
|
||||||
|
gst_validate_error_structure (source, "Invalid structure: %s",
|
||||||
|
g_value_get_string (v));
|
||||||
|
|
||||||
|
return g_list_append (list, structure);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GST_VALUE_HOLDS_STRUCTURE (v))
|
||||||
|
return g_list_append (list,
|
||||||
|
gst_structure_copy (gst_value_get_structure (v)));
|
||||||
|
|
||||||
|
|
||||||
|
gst_validate_error_structure (source, "Expected a string or a structure,"
|
||||||
|
" got %s instead", gst_value_serialize (v));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GList *
|
||||||
|
gst_validate_utils_get_structures (gpointer source,
|
||||||
|
GstStructure * str, const gchar * fieldname)
|
||||||
|
{
|
||||||
|
guint i, size;
|
||||||
|
GList *res = NULL;
|
||||||
|
const GValue *value = gst_structure_get_value (str, fieldname);
|
||||||
|
|
||||||
|
if (!value)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (G_VALUE_HOLDS_STRING (value) || GST_VALUE_HOLDS_STRUCTURE (value))
|
||||||
|
return add_gvalue_to_list_as_struct (source, res, value);
|
||||||
|
|
||||||
|
if (!GST_VALUE_HOLDS_LIST (value)) {
|
||||||
|
g_error ("%s must have type list of structure/string (or a string), "
|
||||||
|
"e.g. %s={ [struct1, a=val1], [struct2, a=val2] }, got: \"%s\" in %s",
|
||||||
|
fieldname, fieldname, gst_value_serialize (value),
|
||||||
|
gst_structure_to_string (str));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = gst_value_list_get_size (value);
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
res =
|
||||||
|
add_gvalue_to_list_as_struct (source, res,
|
||||||
|
gst_value_list_get_value (value, i));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstValidateExecuteActionReturn
|
||||||
|
gst_validate_foreach_prepare (GstValidateAction * action)
|
||||||
|
{
|
||||||
|
gint it, i;
|
||||||
|
gint min = 0, max = 1, step = 1;
|
||||||
|
GstValidateScenario *scenario;
|
||||||
|
GList *actions, *tmp;
|
||||||
|
|
||||||
|
scenario = gst_validate_action_get_scenario (action);
|
||||||
|
g_assert (scenario);
|
||||||
|
_update_well_known_vars (scenario);
|
||||||
|
gst_validate_action_setup_repeat (scenario, action);
|
||||||
|
|
||||||
|
GST_VALIDATE_ACTION_RANGE_NAME (action) = NULL;
|
||||||
|
gst_structure_foreach (action->structure,
|
||||||
|
(GstStructureForeachFunc) _foreach_find_iterator, action);
|
||||||
|
|
||||||
|
/* Allow using the repeat field here too */
|
||||||
|
if (!GST_VALIDATE_ACTION_RANGE_NAME (action)
|
||||||
|
&& !GST_VALIDATE_ACTION_N_REPEATS (action))
|
||||||
|
gst_validate_error_structure (action, "Missing range specifier field.");
|
||||||
|
|
||||||
|
if (GST_VALIDATE_ACTION_RANGE_NAME (action)) {
|
||||||
|
const GValue *range = gst_structure_get_value (action->structure,
|
||||||
|
GST_VALIDATE_ACTION_RANGE_NAME (action));
|
||||||
|
min = gst_value_get_int_range_min (range);
|
||||||
|
max = gst_value_get_int_range_max (range);
|
||||||
|
step = gst_value_get_int_range_step (range);
|
||||||
|
|
||||||
|
if (min % step != 0)
|
||||||
|
gst_validate_error_structure (action,
|
||||||
|
"Range min[%d] must be a multiple of step[%d].", min, step);
|
||||||
|
|
||||||
|
if (max % step != 0)
|
||||||
|
gst_validate_error_structure (action,
|
||||||
|
"Range max[%d] must be a multiple of step[%d].", max, step);
|
||||||
|
} else {
|
||||||
|
min = action->repeat;
|
||||||
|
max = action->repeat + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
actions = gst_validate_utils_get_structures (action, action->structure,
|
||||||
|
"actions");
|
||||||
|
i = g_list_index (scenario->priv->actions, action);
|
||||||
|
for (it = min; it < max; it = it + step) {
|
||||||
|
for (tmp = actions; tmp; tmp = tmp->next) {
|
||||||
|
GstValidateAction *subaction;
|
||||||
|
GstStructure *nstruct = gst_structure_copy (tmp->data);
|
||||||
|
|
||||||
|
subaction = gst_validate_action_new (scenario,
|
||||||
|
_find_action_type (gst_structure_get_name (nstruct)), nstruct, FALSE);
|
||||||
|
GST_VALIDATE_ACTION_RANGE_NAME (subaction) =
|
||||||
|
GST_VALIDATE_ACTION_RANGE_NAME (action);
|
||||||
|
GST_VALIDATE_ACTION_FILENAME (subaction) =
|
||||||
|
g_strdup (GST_VALIDATE_ACTION_FILENAME (action));
|
||||||
|
GST_VALIDATE_ACTION_DEBUG (subaction) =
|
||||||
|
g_strdup (GST_VALIDATE_ACTION_DEBUG (action));
|
||||||
|
GST_VALIDATE_ACTION_LINENO (subaction) =
|
||||||
|
GST_VALIDATE_ACTION_LINENO (action);
|
||||||
|
subaction->repeat = it;
|
||||||
|
subaction->priv->subaction_level = action->priv->subaction_level + 1;
|
||||||
|
GST_VALIDATE_ACTION_N_REPEATS (subaction) = max;
|
||||||
|
scenario->priv->actions =
|
||||||
|
g_list_insert (scenario->priv->actions, subaction, i++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_list_free_full (actions, (GDestroyNotify) gst_structure_free);
|
||||||
|
|
||||||
|
scenario->priv->actions = g_list_remove (scenario->priv->actions, action);
|
||||||
|
gst_structure_remove_field (action->structure, "actions");
|
||||||
|
|
||||||
|
gst_object_unref (scenario);
|
||||||
|
return GST_VALIDATE_EXECUTE_ACTION_SKIP;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_check_waiting_for_message (GstValidateScenario * scenario,
|
_check_waiting_for_message (GstValidateScenario * scenario,
|
||||||
GstMessage * message)
|
GstMessage * message)
|
||||||
|
@ -4138,7 +4260,7 @@ gst_validate_scenario_load_structures (GstValidateScenario * scenario,
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_validate_error_structure (structure,
|
gst_validate_error_structure (structure,
|
||||||
"We do not handle action types %s", type);
|
"Unknown action type: '%s'", type);
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5635,13 +5757,13 @@ static gboolean
|
||||||
_action_set_done (GstValidateAction * action)
|
_action_set_done (GstValidateAction * action)
|
||||||
{
|
{
|
||||||
JsonBuilder *jbuild;
|
JsonBuilder *jbuild;
|
||||||
GstClockTime execution_duration;
|
|
||||||
GstValidateScenario *scenario = gst_validate_action_get_scenario (action);
|
GstValidateScenario *scenario = gst_validate_action_get_scenario (action);
|
||||||
|
|
||||||
if (scenario == NULL || !action->priv->pending_set_done)
|
if (scenario == NULL || !action->priv->pending_set_done)
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
|
|
||||||
execution_duration = gst_util_get_timestamp () - action->priv->execution_time;
|
action->priv->execution_duration =
|
||||||
|
gst_util_get_timestamp () - action->priv->execution_time;
|
||||||
|
|
||||||
jbuild = json_builder_new ();
|
jbuild = json_builder_new ();
|
||||||
json_builder_begin_object (jbuild);
|
json_builder_begin_object (jbuild);
|
||||||
|
@ -5651,25 +5773,27 @@ _action_set_done (GstValidateAction * action)
|
||||||
json_builder_add_string_value (jbuild, action->type);
|
json_builder_add_string_value (jbuild, action->type);
|
||||||
json_builder_set_member_name (jbuild, "execution-duration");
|
json_builder_set_member_name (jbuild, "execution-duration");
|
||||||
json_builder_add_double_value (jbuild,
|
json_builder_add_double_value (jbuild,
|
||||||
((gdouble) execution_duration / GST_SECOND));
|
((gdouble) action->priv->execution_duration / GST_SECOND));
|
||||||
json_builder_end_object (jbuild);
|
json_builder_end_object (jbuild);
|
||||||
|
|
||||||
gst_validate_send (json_builder_get_root (jbuild));
|
gst_validate_send (json_builder_get_root (jbuild));
|
||||||
g_object_unref (jbuild);
|
g_object_unref (jbuild);
|
||||||
|
|
||||||
gst_validate_printf (NULL, " -> Action %s done (duration: %" GST_TIME_FORMAT
|
|
||||||
")\n", action->type, GST_TIME_ARGS (execution_duration));
|
|
||||||
action->priv->execution_time = GST_CLOCK_TIME_NONE;
|
|
||||||
action->priv->state = _execute_sub_action_action (action);
|
|
||||||
|
|
||||||
if (action->priv->state != GST_VALIDATE_EXECUTE_ACTION_ASYNC) {
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (scenario, "Sub action executed ASYNC");
|
|
||||||
execute_next_action (scenario);
|
|
||||||
}
|
|
||||||
gst_object_unref (scenario);
|
|
||||||
|
|
||||||
action->priv->pending_set_done = FALSE;
|
action->priv->pending_set_done = FALSE;
|
||||||
|
switch (action->priv->state) {
|
||||||
|
case GST_VALIDATE_EXECUTE_ACTION_ASYNC:
|
||||||
|
case GST_VALIDATE_EXECUTE_ACTION_INTERLACED:
|
||||||
|
case GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS:
|
||||||
|
case GST_VALIDATE_EXECUTE_ACTION_NONE:
|
||||||
|
action->priv->state = GST_VALIDATE_EXECUTE_ACTION_OK;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gst_structure_free (action->structure);
|
||||||
|
action->structure = gst_structure_copy (action->priv->main_structure);
|
||||||
|
gst_validate_scenario_execute_next_or_restart_looping (scenario);
|
||||||
|
gst_object_unref (scenario);
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6844,9 +6968,25 @@ register_action_types (void)
|
||||||
}),
|
}),
|
||||||
"Check current pipeline position.\n", GST_VALIDATE_ACTION_TYPE_NONE);
|
"Check current pipeline position.\n", GST_VALIDATE_ACTION_TYPE_NONE);
|
||||||
|
|
||||||
|
REGISTER_ACTION_TYPE("foreach", NULL,
|
||||||
|
((GstValidateActionParameter[]) {
|
||||||
|
{ .name = "actions",
|
||||||
|
.description = "The array of actions to repeat",
|
||||||
|
.mandatory = TRUE,
|
||||||
|
.types = "strv",
|
||||||
|
NULL },
|
||||||
|
{ NULL } }),
|
||||||
|
"Run actions defined in the `actions` array the number of times specified\n"
|
||||||
|
" with a GstIntRange `i=[start, end, step]` parameter passed in, one and only\n"
|
||||||
|
" range is required as parameter.",
|
||||||
|
GST_VALIDATE_ACTION_TYPE_NONE);
|
||||||
|
type->prepare = gst_validate_foreach_prepare;
|
||||||
|
|
||||||
/* Internal actions types to test the validate scenario implementation */
|
/* Internal actions types to test the validate scenario implementation */
|
||||||
REGISTER_ACTION_TYPE("priv_check-action-type-calls",
|
REGISTER_ACTION_TYPE("priv_check-action-type-calls",
|
||||||
_execute_check_action_type_calls, NULL, NULL, 0);
|
_execute_check_action_type_calls, NULL, NULL, 0);
|
||||||
|
REGISTER_ACTION_TYPE("priv_check-subaction-level",
|
||||||
|
_execute_check_subaction_level, NULL, NULL, 0);
|
||||||
/* *INDENT-ON* */
|
/* *INDENT-ON* */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,8 +57,11 @@ typedef enum
|
||||||
GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED,
|
GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED,
|
||||||
GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS,
|
GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS,
|
||||||
GST_VALIDATE_EXECUTE_ACTION_NONE,
|
GST_VALIDATE_EXECUTE_ACTION_NONE,
|
||||||
|
GST_VALIDATE_EXECUTE_ACTION_SKIP,
|
||||||
} GstValidateActionReturn;
|
} GstValidateActionReturn;
|
||||||
|
|
||||||
|
const gchar *gst_validate_action_return_get_name (GstValidateActionReturn r);
|
||||||
|
|
||||||
/* TODO 2.0 -- Make it an actual enum type */
|
/* TODO 2.0 -- Make it an actual enum type */
|
||||||
#define GstValidateExecuteActionReturn gint
|
#define GstValidateExecuteActionReturn gint
|
||||||
|
|
||||||
|
@ -93,6 +96,7 @@ typedef struct _GstValidateActionPrivate GstValidateActionPrivate;
|
||||||
#define GST_VALIDATE_ACTION_FILENAME(action) (((GstValidateAction*) action)->ABI.abi.filename)
|
#define GST_VALIDATE_ACTION_FILENAME(action) (((GstValidateAction*) action)->ABI.abi.filename)
|
||||||
#define GST_VALIDATE_ACTION_DEBUG(action) (((GstValidateAction*) action)->ABI.abi.debug)
|
#define GST_VALIDATE_ACTION_DEBUG(action) (((GstValidateAction*) action)->ABI.abi.debug)
|
||||||
#define GST_VALIDATE_ACTION_N_REPEATS(action) (((GstValidateAction*) action)->ABI.abi.n_repeats)
|
#define GST_VALIDATE_ACTION_N_REPEATS(action) (((GstValidateAction*) action)->ABI.abi.n_repeats)
|
||||||
|
#define GST_VALIDATE_ACTION_RANGE_NAME(action) (((GstValidateAction*) action)->ABI.abi.rangename)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GstValidateAction:
|
* GstValidateAction:
|
||||||
|
@ -133,6 +137,7 @@ struct _GstValidateAction
|
||||||
gchar *filename;
|
gchar *filename;
|
||||||
gchar *debug;
|
gchar *debug;
|
||||||
gint n_repeats;
|
gint n_repeats;
|
||||||
|
const gchar *rangename;
|
||||||
} abi;
|
} abi;
|
||||||
} ABI;
|
} ABI;
|
||||||
};
|
};
|
||||||
|
|
47
validate/tests/launcher_tests/foreach.validatetest
Normal file
47
validate/tests/launcher_tests/foreach.validatetest
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
meta,
|
||||||
|
handles-states=true,
|
||||||
|
args = {
|
||||||
|
"videotestsrc pattern=ball animation-mode=frames num-buffers=30 ! video/x-raw,framerate=10/1 ! $(videosink) name=sink sync=true",
|
||||||
|
},
|
||||||
|
expected-issues = {
|
||||||
|
"expected-issue,
|
||||||
|
level=critical,
|
||||||
|
issue-id=scenario::execution-error,
|
||||||
|
details=\"Pipeline position doesn.t match expectations got 0:00:00.100000000 instead of.*\"",
|
||||||
|
"expected-issue,
|
||||||
|
level=critical,
|
||||||
|
issue-id=scenario::execution-error,
|
||||||
|
details=\"Pipeline position doesn.t match expectations got 0:00:00.200000000 instead of.*\"",
|
||||||
|
}
|
||||||
|
|
||||||
|
pause;
|
||||||
|
|
||||||
|
foreach, n=[0, 2],
|
||||||
|
actions = {
|
||||||
|
"seek, start=\"$(position)+0.1\", flags=\"accurate+flush\"",
|
||||||
|
"check-position, expected-position=\"expr($(n)*0.01)\"", # expected to fail
|
||||||
|
}
|
||||||
|
|
||||||
|
priv_check-action-type-calls, type=seek, n=2
|
||||||
|
priv_check-action-type-calls, type=check-position, n=2
|
||||||
|
|
||||||
|
foreach, n=[0, 6],
|
||||||
|
actions = {
|
||||||
|
"seek, start=\"$(position)+0.1\", flags=\"accurate+flush\"",
|
||||||
|
"check-position, expected-position=\"expr((3 + $(n)) * 0.1)\"",
|
||||||
|
}
|
||||||
|
|
||||||
|
priv_check-action-type-calls, type=seek, n=8
|
||||||
|
priv_check-action-type-calls, type=check-position, n=8
|
||||||
|
check-position, expected-position=0.8
|
||||||
|
|
||||||
|
foreach, n=[9, 11],
|
||||||
|
actions = {
|
||||||
|
"seek, start=\"$(position)+0.1\", flags=\"accurate+flush\"",
|
||||||
|
"check-position, expected-position=\"expr($(n)*0.1)\"",
|
||||||
|
}
|
||||||
|
priv_check-action-type-calls, type=seek, n=10
|
||||||
|
# We called it once manually
|
||||||
|
priv_check-action-type-calls, type=check-position, n=11
|
||||||
|
check-position, expected-position=1.0
|
||||||
|
stop
|
|
@ -0,0 +1,24 @@
|
||||||
|
event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE, group-id=(uint)1;
|
||||||
|
event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE, group-id=(uint)1;
|
||||||
|
event caps: video/x-raw, format=(string)AYUV64, width=(int)320, height=(int)240, framerate=(fraction)10/1, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive;
|
||||||
|
event caps: video/x-raw, format=(string)AYUV64, width=(int)320, height=(int)240, framerate=(fraction)10/1, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive;
|
||||||
|
event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000
|
||||||
|
event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000
|
||||||
|
buffer: checksum=5d4a9a9aa2038170a66bb2c675a16672fe70efbe, pts=0:00:00.000000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta
|
||||||
|
buffer: checksum=5d4a9a9aa2038170a66bb2c675a16672fe70efbe, pts=0:00:00.000000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta
|
||||||
|
event flush-start: (no structure)
|
||||||
|
event flush-start: (no structure)
|
||||||
|
event flush-stop: GstEventFlushStop, reset-time=(boolean)true;
|
||||||
|
event flush-stop: GstEventFlushStop, reset-time=(boolean)true;
|
||||||
|
event segment: format=TIME, start=0:00:00.100000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.100000000, base=0:00:00.000000000, position=0:00:00.100000000
|
||||||
|
event segment: format=TIME, start=0:00:00.100000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.100000000, base=0:00:00.000000000, position=0:00:00.100000000
|
||||||
|
buffer: checksum=ace920a5c387c5d216c7bf4fdc83df6ac9d2656e, pts=0:00:00.100000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta
|
||||||
|
buffer: checksum=ace920a5c387c5d216c7bf4fdc83df6ac9d2656e, pts=0:00:00.100000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta
|
||||||
|
event flush-start: (no structure)
|
||||||
|
event flush-start: (no structure)
|
||||||
|
event flush-stop: GstEventFlushStop, reset-time=(boolean)true;
|
||||||
|
event flush-stop: GstEventFlushStop, reset-time=(boolean)true;
|
||||||
|
event segment: format=TIME, start=0:00:00.200000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.200000000, base=0:00:00.000000000, position=0:00:00.200000000
|
||||||
|
event segment: format=TIME, start=0:00:00.200000000, offset=0:00:00.000000000, stop=none, flags=0x01, time=0:00:00.200000000, base=0:00:00.000000000, position=0:00:00.200000000
|
||||||
|
buffer: checksum=b4a5b43f70ad1a1adb1f5e414b39d6bfb5718373, pts=0:00:00.200000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta
|
||||||
|
buffer: checksum=b4a5b43f70ad1a1adb1f5e414b39d6bfb5718373, pts=0:00:00.200000000, dur=0:00:00.100000000, flags=discont, meta=GstVideoMeta
|
51
validate/tests/launcher_tests/foreach_deep.validatetest
Normal file
51
validate/tests/launcher_tests/foreach_deep.validatetest
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
meta,
|
||||||
|
handles-states=true,
|
||||||
|
args = {
|
||||||
|
"videotestsrc pattern=ball animation-mode=frames num-buffers=30 ! video/x-raw,framerate=10/1 ! $(videosink) name=sink sync=true",
|
||||||
|
},
|
||||||
|
expected-issues = {
|
||||||
|
"expected-issue, level=critical, issue-id=scenario::execution-error,
|
||||||
|
details=\"Pipeline position doesn.t match expectations got 0:00:00.100000000 instead of.*\"",
|
||||||
|
"expected-issue, level=critical, issue-id=scenario::execution-error,
|
||||||
|
details=\"Pipeline position doesn.t match expectations got 0:00:00.200000000 instead of.*\"",
|
||||||
|
"expected-issue, level=critical, issue-id=scenario::execution-error,
|
||||||
|
details=\"Expected subaction level 4, got 3\"",
|
||||||
|
"expected-issue, level=critical, issue-id=scenario::execution-error,
|
||||||
|
details=\"Expected subaction level 4, got 3\"",
|
||||||
|
"expected-issue, level=critical, issue-id=scenario::execution-error,
|
||||||
|
details=\"Expected subaction level 5, got 4\"",
|
||||||
|
"expected-issue, level=critical, issue-id=scenario::execution-error,
|
||||||
|
details=\"Expected subaction level 5, got 4\"",
|
||||||
|
}
|
||||||
|
|
||||||
|
pause;
|
||||||
|
|
||||||
|
|
||||||
|
foreach, n=[0, 2],
|
||||||
|
actions = {
|
||||||
|
"seek, start=\"$(position)+0.1\", flags=\"accurate+flush\"",
|
||||||
|
"check-position, expected-position=\"expr($(n)*0.01)\"", # Expected failling subaction!
|
||||||
|
}
|
||||||
|
|
||||||
|
priv_check-action-type-calls, type=seek, n=2
|
||||||
|
priv_check-action-type-calls, type=check-position, n=2
|
||||||
|
|
||||||
|
foreach, n=[0, 2],
|
||||||
|
actions = {
|
||||||
|
"seek, start=\"$(position)+0.1\", flags=\"accurate+flush\"",
|
||||||
|
"priv_check-subaction-level, level=1",
|
||||||
|
"foreach, n=[0, 1],
|
||||||
|
actions={
|
||||||
|
\"priv_check-subaction-level, level=2\",
|
||||||
|
\"foreach, j=[0, 1], actions={
|
||||||
|
\\\"priv_check-subaction-level, level=4\\\", # Failling... twice
|
||||||
|
\\\"priv_check-subaction-level, level=3\\\",
|
||||||
|
\\\"foreach, j=[0, 1], actions={
|
||||||
|
\\\\\\\"priv_check-subaction-level, level=4\\\\\\\",
|
||||||
|
\\\\\\\"priv_check-subaction-level, level=5\\\\\\\", # Failling... twice
|
||||||
|
}\\\",
|
||||||
|
}\",
|
||||||
|
}",
|
||||||
|
}
|
||||||
|
priv_check-action-type-calls, type=seek, n=4
|
||||||
|
stop
|
31
validate/tests/launcher_tests/foreach_repeat.validatetest
Normal file
31
validate/tests/launcher_tests/foreach_repeat.validatetest
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
meta,
|
||||||
|
handles-states=true,
|
||||||
|
args = {
|
||||||
|
"videotestsrc name=src pattern=ball animation-mode=frames num-buffers=30 ! video/x-raw,framerate=10/1 ! $(videosink) name=sink sync=true",
|
||||||
|
}
|
||||||
|
|
||||||
|
pause;
|
||||||
|
|
||||||
|
foreach, repeat="max(1, 2)",
|
||||||
|
actions = {
|
||||||
|
"seek, start=\"$(position)+0.1\", flags=\"accurate+flush\"",
|
||||||
|
"check-position, expected-position=\"expr((1+$(repeat))*0.1)\"",
|
||||||
|
}
|
||||||
|
|
||||||
|
priv_check-action-type-calls, type=seek, n=2
|
||||||
|
priv_check-action-type-calls, type=check-position, n=2
|
||||||
|
|
||||||
|
foreach,
|
||||||
|
repeat=2,
|
||||||
|
pattern=[0, 10, 5],
|
||||||
|
actions = {
|
||||||
|
"set-properties, src::horizontal-speed=\"$(pattern)\"",
|
||||||
|
"check-properties, src::horizontal-speed=\"$(pattern)\"",
|
||||||
|
}
|
||||||
|
|
||||||
|
check-properties, src::horizontal-speed=5
|
||||||
|
priv_check-action-type-calls, type=set-properties, n=4
|
||||||
|
priv_check-action-type-calls, type=check-properties, n=5
|
||||||
|
priv_check-action-type-calls, type=seek, n=2
|
||||||
|
priv_check-action-type-calls, type=check-position, n=2
|
||||||
|
stop
|
Loading…
Reference in a new issue