Commit 9c08bfca authored by Thibault Saunier's avatar Thibault Saunier 🌵 Committed by GStreamer Marge Bot

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: <gstreamer/gst-devtools!207>
parent e7355ea0
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;
......@@ -47,7 +47,7 @@ void register_action_types (void);
* as we used to have to print actions in the action execution function
* and this is done by the scenario itself now */
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);
#define GST_VALIDATE_SCENARIO_SUFFIX ".scenario"
......
......@@ -834,27 +834,36 @@ gst_validate_printf (gpointer source, const gchar * format, ...)
va_end (var_args);
}
typedef struct
{
GString *str;
gint indent;
gint printed;
} PrintActionFieldData;
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;
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;
if (g_strcmp0 (g_quark_to_string (field_id), "repeat") == 0)
if (g_strcmp0 (fieldname, "repeat") == 0)
return TRUE;
d->printed++;
if (G_VALUE_TYPE (value) == GST_TYPE_CLOCK_TIME)
val_str = g_strdup_printf ("%" GST_TIME_FORMAT,
GST_TIME_ARGS (g_value_get_uint64 (value)));
else
val_str = gst_value_serialize (value);
g_string_append (string, "\n - ");
g_string_append (string, g_quark_to_string (field_id));
g_string_append_len (string, "=", 1);
g_string_append (string, val_str);
g_string_append_printf (d->str, "\n%*c - ", d->indent, ' ');
g_string_append (d->str, fieldname);
g_string_append_len (d->str, "=", 1);
g_string_append (d->str, val_str);
g_free (val_str);
......@@ -874,26 +883,24 @@ gst_validate_print_action (GstValidateAction * action, const gchar * message)
GString *string = NULL;
if (message == NULL) {
gint nrepeats;
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);
gint indent = (gst_validate_action_get_level (action) * 2);
PrintActionFieldData d = { NULL, indent, 0 };
d.str = string = g_string_new (NULL);
g_string_append_printf (string, "%s",
gst_structure_get_name (action->structure));
g_string_append_len (string, " ( ", 3);
gst_structure_foreach (action->structure,
(GstStructureForeachFunc) _append_value, string);
if (GST_VALIDATE_ACTION_N_REPEATS (action))
g_string_append_printf (string, " [%s=%d/%d]",
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, "\n)\n");
g_string_append (string, " ( ");
gst_structure_foreach (action->structure,
(GstStructureForeachFunc) _append_value, &d);
if (d.printed)
g_string_append_printf (string, "\n%*c)\n", indent, ' ');
else
g_string_append (string, ")\n");
message = string->str;
......@@ -980,12 +987,15 @@ gst_validate_printf_valist (gpointer source, const gchar * format, va_list args)
if (source) {
if (*(GType *) source == GST_TYPE_VALIDATE_ACTION) {
GstValidateAction *action = (GstValidateAction *) source;
gint indent = gst_validate_action_get_level (action) * 2;
if (_action_check_and_set_printed (action))
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) {
gint i;
gint n_params;
......
......@@ -345,28 +345,37 @@ gst_validate_report_action (GstValidateReporter * reporter,
const gchar * format, ...)
{
va_list var_args;
gint nrepeats;
gchar *f, *repeat = NULL;
if (action && gst_structure_get_int (action->structure, "repeat", &nrepeats))
repeat =
g_strdup_printf (" (repeat: %d/%d)", nrepeats - action->repeat + 1,
nrepeats);
f = action ? g_strdup_printf ("\n> %s:%d%s\n> %d | %s\n> %*c|\n",
GST_VALIDATE_ACTION_FILENAME (action),
GST_VALIDATE_ACTION_LINENO (action), repeat ? repeat : "",
GST_VALIDATE_ACTION_LINENO (action), format,
(gint) floor (log10 (abs ((GST_VALIDATE_ACTION_LINENO (action))))) + 1,
' ')
: g_strdup (format);
GString *f;
if (!action) {
f = g_string_new (format);
goto done;
}
f = g_string_new (NULL);
g_string_append_printf (f, "\n> %s:%d", GST_VALIDATE_ACTION_FILENAME (action),
GST_VALIDATE_ACTION_LINENO (action));
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);
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);
g_free (f);
g_free (repeat);
g_string_free (f, TRUE);
}
void
......
......@@ -57,8 +57,11 @@ typedef enum
GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED,
GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS,
GST_VALIDATE_EXECUTE_ACTION_NONE,
GST_VALIDATE_EXECUTE_ACTION_SKIP,
} GstValidateActionReturn;
const gchar *gst_validate_action_return_get_name (GstValidateActionReturn r);
/* TODO 2.0 -- Make it an actual enum type */
#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_DEBUG(action) (((GstValidateAction*) action)->ABI.abi.debug)
#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:
......@@ -133,6 +137,7 @@ struct _GstValidateAction
gchar *filename;
gchar *debug;
gint n_repeats;
const gchar *rangename;
} abi;
} ABI;
};
......
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
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
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
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
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment