validate:scenario: Enhance variable implementation
authorThibault Saunier <tsaunier@igalia.com>
Sun, 3 Feb 2019 23:05:36 +0000 (20:05 -0300)
committerThibault Saunier <tsaunier@gnome.org>
Fri, 15 Feb 2019 14:19:03 +0000 (14:19 +0000)
- Stop arbitrarily consider params as ClockTime based on their names
  but add a convetion that the `.type` field of the ActionType should
  end by `(GstClockTime)` when it is a clock time.

21 files changed:
validate/data/scenarios/alternate_fast_backward_forward.scenario
validate/data/scenarios/fast_backward.scenario
validate/data/scenarios/fast_forward.scenario
validate/data/scenarios/includes/default-seek-flags.scenario
validate/data/scenarios/reverse_playback.scenario
validate/data/scenarios/rtsp_overrides/includes/default-seek-flags.scenario
validate/data/scenarios/scrub_backward_seeking.scenario
validate/data/scenarios/scrub_backward_seeking_full.scenario
validate/data/scenarios/scrub_forward_seeking.scenario
validate/data/scenarios/scrub_forward_seeking_full.scenario
validate/data/scenarios/seek_backward.scenario
validate/data/scenarios/seek_forward.scenario
validate/data/scenarios/seek_forward_backward.scenario
validate/data/scenarios/seek_with_stop.scenario
validate/data/scenarios/simple_seeks.scenario
validate/data/scenarios/update_start.scenario
validate/data/scenarios/update_stop.scenario
validate/gst/validate/gst-validate-scenario.c
validate/gst/validate/gst-validate-scenario.h
validate/tests/check/meson.build
validate/tests/check/validate/scenario.c [new file with mode: 0644]

index ac2aca0..5913898 100644 (file)
@@ -1,14 +1,14 @@
 description, duration=55.0, min-media-duration=470.0, seek=true, reverse-playback=true
 include,location=includes/default-seek-flags.scenario
-seek, name=backward-seek,      playback-time=0.0,   rate=-1.0,  start=0.0, stop=310.0, flags="$(default-flags)"
-seek, name=forward-seek,       playback-time=305.0, rate=1.0,   start=305.0, flags="$(default-flags)"
-seek, name=Fast-forward-seek,  playback-time=310.0, rate=2.0,   start=310.0, flags="$(default-flags)"
-seek, name=Fast-backward-seek, playback-time=320.0, rate=-2.0,  start=0.0, stop=320.0, flags="$(default-flags)"
-seek, name=Fast-forward-seek,  playback-time=310.0, rate=4.0,   start=310.0, flags="$(default-flags)"
-seek, name=Fast-backward-seek, playback-time=330.0, rate=-4.0,  start=0.0, stop=330.0, flags="$(default-flags)"
-seek, name=Fast-forward-seek,  playback-time=310.0, rate=8.0,   start=310.0, flags="$(default-flags)"
-seek, name=Fast-backward-seek, playback-time=350.0, rate=-8.0,  start=0.0, stop=350.0, flags="$(default-flags)"
-seek, name=Fast-forward-seek,  playback-time=310.0, rate=16.0,  start=310.0, flags="$(default-flags)"
-seek, name=Fast-backward-seek, playback-time=390.0, rate=-16.0, start=0.0, stop=390.0, flags="$(default-flags)"
-seek, name=Fast-forward-seek,  playback-time=310.0, rate=32.0,  start=310.0, flags="$(default-flags)"
-seek, name=Fast-backward-seek, playback-time=470.0, rate=-32.0, start=310.0, stop=470.0, flags="$(default-flags)"
+seek, name=backward-seek,      playback-time=0.0,   rate=-1.0,  start=0.0, stop=310.0, flags="$(default_flags)"
+seek, name=forward-seek,       playback-time=305.0, rate=1.0,   start=305.0, flags="$(default_flags)"
+seek, name=Fast-forward-seek,  playback-time=310.0, rate=2.0,   start=310.0, flags="$(default_flags)"
+seek, name=Fast-backward-seek, playback-time=320.0, rate=-2.0,  start=0.0, stop=320.0, flags="$(default_flags)"
+seek, name=Fast-forward-seek,  playback-time=310.0, rate=4.0,   start=310.0, flags="$(default_flags)"
+seek, name=Fast-backward-seek, playback-time=330.0, rate=-4.0,  start=0.0, stop=330.0, flags="$(default_flags)"
+seek, name=Fast-forward-seek,  playback-time=310.0, rate=8.0,   start=310.0, flags="$(default_flags)"
+seek, name=Fast-backward-seek, playback-time=350.0, rate=-8.0,  start=0.0, stop=350.0, flags="$(default_flags)"
+seek, name=Fast-forward-seek,  playback-time=310.0, rate=16.0,  start=310.0, flags="$(default_flags)"
+seek, name=Fast-backward-seek, playback-time=390.0, rate=-16.0, start=0.0, stop=390.0, flags="$(default_flags)"
+seek, name=Fast-forward-seek,  playback-time=310.0, rate=32.0,  start=310.0, flags="$(default_flags)"
+seek, name=Fast-backward-seek, playback-time=470.0, rate=-32.0, start=310.0, stop=470.0, flags="$(default_flags)"
index c339049..c51b430 100644 (file)
@@ -1,7 +1,7 @@
 description, duration=30.0, minfo-media-duration=310.0, seek=true, reverse-playback=true, need-clock-sync=true, min-media-duration=310.0
 include,location=includes/default-seek-flags.scenario
-seek, name=Fast-backward-seek, playback-time=0.0,   rate=-2.0,  start=0.0, stop=310.0, flags="$(default-flags)"
-seek, name=Fast-backward-seek, playback-time=300.0, rate=-4.0,  start=0.0, stop=300.0, flags="$(default-flags)"
-seek, name=Fast-backward-seek, playback-time=280.0, rate=-8.0,  start=0.0, stop=280.0, flags="$(default-flags)"
-seek, name=Fast-backward-seek, playback-time=240.0, rate=-16.0, start=0.0, stop=240.0, flags="$(default-flags)"
-seek, name=Fast-backward-seek, playback-time=160.0, rate=-32.0, start=0.0, stop=160.0, flags="$(default-flags)"
+seek, name=Fast-backward-seek, playback-time=0.0,   rate=-2.0,  start=0.0, stop=310.0, flags="$(default_flags)"
+seek, name=Fast-backward-seek, playback-time=300.0, rate=-4.0,  start=0.0, stop=300.0, flags="$(default_flags)"
+seek, name=Fast-backward-seek, playback-time=280.0, rate=-8.0,  start=0.0, stop=280.0, flags="$(default_flags)"
+seek, name=Fast-backward-seek, playback-time=240.0, rate=-16.0, start=0.0, stop=240.0, flags="$(default_flags)"
+seek, name=Fast-backward-seek, playback-time=160.0, rate=-32.0, start=0.0, stop=160.0, flags="$(default_flags)"
index 1475647..9969a5d 100644 (file)
@@ -1,8 +1,8 @@
 description, duration=25.0, seek=true, need-clock-sync=true, min-media-duration=5.0
 include,location=includes/default-seek-flags.scenario
-seek, name=Fast-forward-seek, playback-time=0.0, rate=2.0,  start=0.0, flags="$(default-flags)"
-seek, name=Fast-forward-seek, playback-time="min(10.0, $duration * 0.0625)", rate=4.0,  start=0.0, flags="$(default-flags)"
-seek, name=Fast-forward-seek, playback-time="min(20.0, $duration * 0.125)", rate=8.0,  start=0.0, flags="$(default-flags)"
-seek, name=Fast-forward-seek, playback-time="min(40.0, $duration * 0.25)", rate=16.0, start=0.0, flags="$(default-flags)"
-seek, name=Fast-forward-seek, playback-time="min(80.0, $duration * 0.50)", rate=32.0, start=0.0, flags="$(default-flags)"
-stop, playback-time="min($duration - 0.3, 160.0)"
+seek, name=Fast-forward-seek, playback-time=0.0, rate=2.0,  start=0.0, flags="$(default_flags)"
+seek, name=Fast-forward-seek, playback-time="min(10.0, $(duration) * 0.0625)", rate=4.0,  start=0.0, flags="$(default_flags)"
+seek, name=Fast-forward-seek, playback-time="min(20.0, $(duration) * 0.125)", rate=8.0,  start=0.0, flags="$(default_flags)"
+seek, name=Fast-forward-seek, playback-time="min(40.0, $(duration) * 0.25)", rate=16.0, start=0.0, flags="$(default_flags)"
+seek, name=Fast-forward-seek, playback-time="min(80.0, $(duration) * 0.50)", rate=32.0, start=0.0, flags="$(default_flags)"
+stop, playback-time="min($(duration) - 0.3, 160.0)"
index 612dddf..90e02cd 100644 (file)
@@ -1,3 +1,3 @@
 description, seek=true, reverse-playback=true
 include,location=includes/default-seek-flags.scenario
-seek, name=Reverse-seek, playback-time=0.0, rate=-1.0, start="max($duration - 15.0, 0.0)", stop=$(duration), flags="$(default-flags)"
+seek, name=Reverse-seek, playback-time=0.0, rate=-1.0, start="max($(duration) - 15.0, 0.0)", stop="$(duration)", flags="$(default_flags)"
index d2fd34f..3a8ff47 100644 (file)
@@ -1,8 +1,8 @@
 description, seek=true, handles-states=true, needs_preroll=true
 include,location=includes/default-seek-flags.scenario
 pause, playback-time=0.0
-seek, playback-time=0.0, start="$duration - 0.5", flags="$(default-flags)"
-seek, playback-time=0.0, start=position-0.1, repeat="min(10, ($duration - 0.6))/0.1", flags="$(default-flags)"
+seek, playback-time=0.0, start="$(duration) - 0.5", flags="$(default_flags)"
+seek, playback-time=0.0, start=position-0.1, repeat="min(10, ($(duration) - 0.6))/0.1", flags="$(default_flags)"
 play, playback-time=0.0
 stop, playback-time=1.0
 
index 19f802b..7cb1f7a 100644 (file)
@@ -1,8 +1,8 @@
 description, seek=true, handles-states=true, needs_preroll=true
 include,location=includes/default-seek-flags.scenario
 pause, playback-time=0.0
-seek, playback-time=0.0, start="$duration - 0.5", flags="$(default-flags)"
-seek, playback-time=0.0, start=position-0.1, repeat="($duration - 0.6)/0.1", flags="$(default-flags)"
+seek, playback-time=0.0, start="$(duration) - 0.5", flags="$(default_flags)"
+seek, playback-time=0.0, start=position-0.1, repeat="($(duration) - 0.6)/0.1", flags="$(default_flags)"
 play, playback-time=0.0
 stop, playback-time=1.0
 
index 58e3ab1..814dce4 100644 (file)
@@ -1,6 +1,6 @@
 description, seek=true, handles-states=true, needs_preroll=true
 include,location=includes/default-seek-flags.scenario
 pause, playback-time=0.0
-seek, playback-time=0.0, start=position+0.1, repeat="min(10, ($duration - 0.5))/0.1", flags="$(default-flags)"
+seek, playback-time=0.0, start=position+0.1, repeat="min(10, ($(duration) - 0.5) / 0.1)", flags="$(default_flags)"
 play, playback-time=0.0
 stop, playback-time=1.0
index e50821f..d83c8b1 100644 (file)
@@ -1,6 +1,6 @@
 description, seek=true, handles-states=true, needs_preroll=true
 include,location=includes/default-seek-flags.scenario
 pause, playback-time=0.0
-seek, playback-time=0.0, start=position+0.1, repeat="($duration - 0.5)/0.1", flags="$(default-flags)"
+seek, playback-time=0.0, start=position+0.1, repeat="($(duration) - 0.5)/0.1", flags="$(default_flags)"
 play, playback-time=0.0
 stop, playback-time=1.0
index 31da4a3..25e1ad6 100644 (file)
@@ -1,6 +1,6 @@
 description, seek=true, duration=30, need-clock-sync=true
 include,location=includes/default-seek-flags.scenario
-seek, name=Backward-seek, playback-time="min(5.0, ($duration / 4))", rate=1.0, start=0.0, flags="$(default-flags)"
-seek, name=Backward-seek, playback-time="min(10.0, 2*($duration / 4))", rate=1.0, start="min(5.0, $duration / 4)", flags="$(default-flags)"
-seek, name=Backward-seek, playback-time="min(15.0, 3*($duration / 4))", rate=1.0, start="min(10.0, 2*($duration / 4))", flags="$(default-flags)"
-stop, playback-time="min(15.0, 3*($duration / 4))"
+seek, name=Backward-seek, playback-time="min(5.0, ($(duration) / 4))", rate=1.0, start=0.0, flags="$(default_flags)"
+seek, name=Backward-seek, playback-time="min(10.0, 2*($(duration) / 4))", rate=1.0, start="min(5.0, $(duration) / 4)", flags="$(default_flags)"
+seek, name=Backward-seek, playback-time="min(15.0, 3*($(duration) / 4))", rate=1.0, start="min(10.0, 2*($(duration) / 4))", flags="$(default_flags)"
+stop, playback-time="min(15.0, 3*($(duration) / 4))"
index dc3af11..c5b290f 100644 (file)
@@ -1,7 +1,6 @@
 description, seek=true, duration=20, need-clock-sync=true
 include,location=includes/default-seek-flags.scenario
-set-vars, test=(string)5.0
-seek, name=First-forward-seek, playback-time="min($test, ($duration/8))", start="min(10, 2*($duration/8))", flags="$(default-flags)"
-seek, name=Second-forward-seek, playback-time="min(15.0, 3*($duration/8))", start="min(20, 4*($duration/8))", flags="$(default-flags)"
-seek, name=Third-forward-seek, playback-time="min(25, 5*($duration/8))", start="min(30.0, 6*($duration/8))", flags="$(default-flags)"
+seek, name=First-forward-seek, playback-time="min(5.0, ($(duration)/8))", start="min(10, 2*($(duration)/8))", flags="$(default_flags)"
+seek, name=Second-forward-seek, playback-time="min(15.0, 3*($(duration)/8))", start="min(20, 4*($(duration)/8))", flags="$(default_flags)"
+seek, name=Third-forward-seek, playback-time="min(25, 5*($(duration)/8))", start="min(30.0, 6*($(duration)/8))", flags="$(default_flags)"
 stop, playback-time=35.0
index 2540d2a..4b669af 100644 (file)
@@ -1,10 +1,10 @@
 description, seek=true, duration=40, min-media-duration=45.0
 include,location=includes/default-seek-flags.scenario
-seek, name=Forward-seek,       playback-time=0.0,    rate=1.0, start=5.0,             flags="$(default-flags)"
-seek, name=Backward-seek,      playback-time=10.0,   rate=1.0, start=0.0,             flags="$(default-flags)"
-seek, name=Backward-seek,      playback-time=5.0,    rate=1.0, start=25.0, stop=-1,   flags="$(default-flags)"
-seek, name=Backward-seek,      playback-time=30.0,   rate=1.0, start=0.0,             flags="$(default-flags)"
-seek, name=Forward-seek,       playback-time=5.0,    rate=1.0, start=15.0,            flags="$(default-flags)"
-seek, name=Forward-seek,       playback-time=20.0,   rate=1.0, start=35.0,            flags="$(default-flags)"
-seek, name=Backward-seek,      playback-time=40.0,   rate=1.0, start=25.0,            flags="$(default-flags)"
-seek, name=Last-backward-seek, playback-time=30.0,    rate=1.0, start=5.0,  stop=10.0, flags="$(default-flags)"
+seek, name=Forward-seek,       playback-time=0.0,    rate=1.0, start=5.0,             flags="$(default_flags)"
+seek, name=Backward-seek,      playback-time=10.0,   rate=1.0, start=0.0,             flags="$(default_flags)"
+seek, name=Backward-seek,      playback-time=5.0,    rate=1.0, start=25.0, stop=-1,   flags="$(default_flags)"
+seek, name=Backward-seek,      playback-time=30.0,   rate=1.0, start=0.0,             flags="$(default_flags)"
+seek, name=Forward-seek,       playback-time=5.0,    rate=1.0, start=15.0,            flags="$(default_flags)"
+seek, name=Forward-seek,       playback-time=20.0,   rate=1.0, start=35.0,            flags="$(default_flags)"
+seek, name=Backward-seek,      playback-time=40.0,   rate=1.0, start=25.0,            flags="$(default_flags)"
+seek, name=Last-backward-seek, playback-time=30.0,    rate=1.0, start=5.0,  stop=10.0, flags="$(default_flags)"
index fba84ae..b4b7e3f 100644 (file)
@@ -1,3 +1,3 @@
 description, seek=true, duration=5.0, need_clock_sync=true, min-media-duration=2
 include,location=includes/default-seek-flags.scenario
-seek, playback-time=1.0, start=0.0, stop="min(5.0, duration-1.0)", flags="$(default-flags)"
+seek, playback-time=1.0, start=0.0, stop="min(5.0, duration-1.0)", flags="$(default_flags)"
index ede357e..ca41f6c 100644 (file)
@@ -1,5 +1,5 @@
 description, seek=true, duration=5.0
 include,location=includes/default-seek-flags.scenario
-seek, playback-time=1.0, rate=1.0, start=2.0, flags="$(default-flags)"
-seek, playback-time=3.0, rate=1.0, start=0.0, flags="$(default-flags)"
-seek, playback-time=1.0, rate=1.0, start=2.0, stop=3.0, flags="$(default-flags)"
+seek, playback-time=1.0, rate=1.0, start=2.0, flags="$(default_flags)"
+seek, playback-time=3.0, rate=1.0, start=0.0, flags="$(default_flags)"
+seek, playback-time=1.0, rate=1.0, start=2.0, stop=3.0, flags="$(default_flags)"
index a5dc962..846f4db 100644 (file)
@@ -1,3 +1,3 @@
 description, summary="Use the set seek type to seek at 5 seconds after 2 seconds", seek=true
 include,location=includes/default-seek-flags.scenario
-seek, playback-time=2.0, rate=1.0, start_type=set, start=5.0, stop_type=none, stop=0.0, flags="$(default-flags)"
+seek, playback-time=2.0, rate=1.0, start_type=set, start=5.0, stop_type=none, stop=0.0, flags="$(default_flags)"
index 8c1bd03..584e16d 100644 (file)
@@ -1,4 +1,4 @@
 description, summary="Use the set seek type to seek at 0 secs stop 10secs after 5 secs", seek=true
 description, duration=15.0, seek=true
 include,location=includes/default-seek-flags.scenario
-seek, playback-time=5.0, rate=1.0, start_type=none, start=0.0, stop_type=set, stop=10.0, flags="$(default-flags)"
+seek, playback-time=5.0, rate=1.0, start_type=none, start=0.0, stop_type=set, stop=10.0, flags="$(default_flags)"
index c50215d..a462925 100644 (file)
@@ -2,7 +2,8 @@
  *
  * Copyright (C) 2013 Collabora Ltd.
  *  Author: Thibault Saunier <thibault.saunier@collabora.com>
- * Copyright (C) 2018 Thibault Saunier <tsaunier@igalia.com>
+ * Copyright (C) 2018-2019 Igalia S.L
+
  *
  * gst-validate-scenario.c - Validate Scenario class
  *
@@ -124,6 +125,8 @@ struct _GstValidateScenarioPrivate
   GList *interlaced_actions;    /* MT safe. Protected with SCENARIO_LOCK */
   GList *on_addition_actions;   /* MT safe. Protected with SCENARIO_LOCK */
 
+  gboolean needs_playback_parsing;
+
   /*  List of action that need parsing when reaching ASYNC_DONE
    *  most probably to be able to query duration */
 
@@ -340,7 +343,7 @@ gst_validate_action_init (GstValidateAction * action)
   g_weak_ref_init (&action->priv->scenario, NULL);
 }
 
-static void
+void
 gst_validate_action_unref (GstValidateAction * action)
 {
   gst_mini_object_unref (GST_MINI_OBJECT (action));
@@ -442,93 +445,115 @@ _find_action_type (const gchar * type_name)
   return NULL;
 }
 
-static gboolean
-_set_variable_func (const gchar * name, double *value, gpointer user_data)
+static void
+_update_well_known_vars (GstValidateScenario * scenario)
 {
-  gboolean res;
-  const gchar *value_str;
-  gchar *tmp;
-  GstValidateScenario *scenario = GST_VALIDATE_SCENARIO (user_data);
+  gint64 duration, position;
+  gdouble dduration, dposition;
   GstElement *pipeline = gst_validate_scenario_get_pipeline (scenario);
 
-  if (!pipeline) {
-    GST_ERROR_OBJECT (scenario, "No pipeline set anymore!");
-
-    return FALSE;
-  }
+  gst_structure_remove_fields (scenario->priv->vars, "position", "duration",
+      NULL);
 
-  if (!g_strcmp0 (name, "$duration") || !g_strcmp0 (name, "duration")) {
-    gint64 duration;
-
-    if (!(res =
-            gst_element_query_duration (pipeline, GST_FORMAT_TIME, &duration))
-        || !GST_CLOCK_TIME_IS_VALID (duration)) {
-      GstValidateMonitor *monitor =
-          (GstValidateMonitor *) (g_object_get_data ((GObject *)
-              pipeline, "validate-monitor"));
-      GST_WARNING_OBJECT (scenario,
-          "Could not query duration. Trying to get duration from media-info");
-      if (monitor && monitor->media_descriptor)
-        duration =
-            gst_validate_media_descriptor_get_duration
-            (monitor->media_descriptor);
-      else {
-        GST_ERROR_OBJECT (scenario, "Media-info not set");
-        if (!res)
-          goto fail;
-      }
-    }
+  if (!pipeline)
+    return;
 
-    if (!GST_CLOCK_TIME_IS_VALID (duration))
-      *value = G_MAXDOUBLE;
-    else
-      *value = ((double) duration / GST_SECOND);
+  if (!gst_element_query_duration (pipeline, GST_FORMAT_TIME, &duration) ||
+      !GST_CLOCK_TIME_IS_VALID (duration)) {
+    GstValidateMonitor *monitor =
+        (GstValidateMonitor *) (g_object_get_data ((GObject *)
+            pipeline, "validate-monitor"));
+    GST_INFO_OBJECT (scenario,
+        "Could not query duration. Trying to get duration from media-info");
+    if (monitor && monitor->media_descriptor)
+      duration =
+          gst_validate_media_descriptor_get_duration
+          (monitor->media_descriptor);
+  }
 
-    goto done;
-  } else if (!g_strcmp0 (name, "$position") || !g_strcmp0 (name, "position")) {
-    gint64 position;
+  if (!GST_CLOCK_TIME_IS_VALID (duration))
+    dduration = G_MAXDOUBLE;
+  else
+    dduration = ((double) duration / GST_SECOND);
 
-    if (!gst_element_query_position (pipeline, GST_FORMAT_TIME, &position)) {
-      GST_WARNING_OBJECT (scenario, "Could not query position");
-      goto fail;
-    }
+  gst_structure_set (scenario->priv->vars, "duration", G_TYPE_DOUBLE, dduration,
+      NULL);
+  if (gst_element_query_position (pipeline, GST_FORMAT_TIME, &position)) {
 
     if (!GST_CLOCK_TIME_IS_VALID (position))
-      *value = G_MAXDOUBLE;
+      dposition = G_MAXDOUBLE;
     else
-      *value = ((double) position / GST_SECOND);
+      dposition = ((double) position / GST_SECOND);
 
-    goto done;
+    gst_structure_set (scenario->priv->vars, "position", G_TYPE_DOUBLE,
+        dposition, NULL);
+  } else {
+    GST_WARNING_OBJECT (scenario, "Could not query position");
   }
+}
+
+static gchar *
+_replace_variables_in_string (GstValidateScenario * scenario,
+    GstValidateAction * action, const gchar * in_string)
+{
+  GRegex *regex;
+  gint varname_len;
+  GMatchInfo *match_info;
+  const gchar *var_value;
+  gchar *tmpstring, *string = g_strdup (in_string);
+
+  _update_well_known_vars (scenario);
+  regex = g_regex_new ("\\$\\((\\w+)\\)", 0, 0, NULL);
+  g_regex_match (regex, string, 0, &match_info);
+  while (g_match_info_matches (match_info)) {
+    GRegex *replace_regex;
+    gchar *tmp, *varname, *pvarname = g_match_info_fetch (match_info, 0);
+
+    varname_len = strlen (pvarname);
+    varname = g_malloc (sizeof (gchar) * varname_len - 3);
+    strncpy (varname, &pvarname[2], varname_len - 3);
+    varname[varname_len - 3] = '\0';
 
-  if (name[0] != '$') {
-    g_error ("Variable name %s is invalid as it doesn't start with $", name);
+    if (gst_structure_has_field_typed (scenario->priv->vars, varname,
+            G_TYPE_DOUBLE)) {
+      var_value = varname;
+    } else {
+      var_value = gst_structure_get_string (scenario->priv->vars, varname);
+      if (!var_value) {
+        g_error ("Trying to use undefined variable : %s (%s)", varname,
+            gst_structure_to_string (scenario->priv->vars));
 
-    goto fail;
-  }
+        return NULL;
+      }
+    }
 
-  if (gst_structure_get_double (scenario->priv->vars, &name[1], value))
-    goto done;
+    tmp = g_strdup_printf ("\\$\\(%s\\)", varname);
+    replace_regex = g_regex_new (tmp, 0, 0, NULL);
+    tmpstring = string;
+    string = g_regex_replace (replace_regex, string, -1, 0, var_value, 0, NULL);
 
-  value_str = gst_structure_get_string (scenario->priv->vars, &name[1]);
-  *value = g_strtod (value_str, &tmp);
-  if (tmp[0] != '\0') {
-    gchar *vars = gst_structure_to_string (scenario->priv->vars);
-    g_error ("Variable name: %s=%s is not a double (%s)", name, value_str,
-        vars);
-    g_free (vars);
+    GST_INFO_OBJECT (action, "Setting variable %s to %s", varname, var_value);
+    g_free (tmpstring);
+    g_regex_unref (replace_regex);
+    g_free (pvarname);
 
-    goto fail;
+    g_match_info_next (match_info, NULL);
   }
+  g_match_info_free (match_info);
+  g_regex_unref (regex);
 
+  return string;
+}
 
-done:
-  gst_object_unref (pipeline);
-  return TRUE;
+static gboolean
+_set_variable_func (const gchar * name, double *value, gpointer user_data)
+{
+  GstValidateScenario *scenario = (GstValidateScenario *) user_data;
 
-fail:
-  gst_object_unref (pipeline);
-  return FALSE;
+  if (!gst_structure_get_double (scenario->priv->vars, name, value))
+    return FALSE;
+
+  return TRUE;
 }
 
 /* Check that @list doesn't contain any non-optional actions */
@@ -587,20 +612,27 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario,
 {
   if (!gst_validate_utils_get_clocktime (action->structure, name, retval)) {
     gdouble val;
-    gchar *error = NULL;
-    const gchar *strval;
+    gchar *error = NULL, *strval;
+    const gchar *tmpvalue = gst_structure_get_string (action->structure, name);
 
-    if (!(strval = gst_structure_get_string (action->structure, name))) {
-      GST_INFO_OBJECT (scenario, "Could not find %s", name);
+    if (!tmpvalue) {
+      GST_INFO_OBJECT (scenario, "Could not find %s (%" GST_PTR_FORMAT ")",
+          name, action->structure);
       return -1;
     }
 
-    val = gst_validate_utils_parse_expression (strval, _set_variable_func,
-        scenario, &error);
+    strval = _replace_variables_in_string (scenario, action, tmpvalue);
+    if (!strval)
+      return FALSE;
 
+    val =
+        gst_validate_utils_parse_expression (strval, _set_variable_func,
+        scenario, &error);
     if (error) {
-      GST_WARNING ("Error while parsing %s: %s", strval, error);
+      GST_WARNING ("Error while parsing %s: %s (%" GST_PTR_FORMAT ")",
+          strval, error, scenario->priv->vars);
       g_free (error);
+      g_free (strval);
 
       return FALSE;
     } else if (val == -1.0) {
@@ -609,6 +641,8 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario,
       *retval = val * GST_SECOND;
       *retval = GST_ROUND_UP_4 (*retval);
     }
+    gst_structure_set (action->structure, name, G_TYPE_UINT64, *retval, NULL);
+    g_free (strval);
 
     return TRUE;
   }
@@ -1737,9 +1771,8 @@ gst_validate_parse_next_action_playback_time (GstValidateScenario * self)
   GstValidateAction *action;
   GstValidateScenarioPrivate *priv = self->priv;
 
-  if (!priv->actions) {
+  if (!priv->actions)
     return TRUE;
-  }
 
   action = (GstValidateAction *) priv->actions->data;
   if (!action->priv->needs_playback_parsing)
@@ -1785,7 +1818,6 @@ gst_validate_execute_action (GstValidateActionType * action_type,
   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);
@@ -1811,7 +1843,7 @@ _fill_action (GstValidateScenario * scenario, GstValidateAction * action,
   GstValidateActionType *action_type;
   const gchar *str_playback_time = NULL;
   GstValidateScenarioPrivate *priv = scenario ? scenario->priv : NULL;
-  GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK;
+  GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_NONE;
   gboolean optional, needs_parsing;
 
   action->type = gst_structure_get_name (structure);
@@ -2075,19 +2107,6 @@ execute_next_action (GstValidateScenario * scenario)
 
   type = _find_action_type (act->type);
 
-  if (act->repeat == -1 &&
-      !gst_structure_get_int (act->structure, "repeat", &act->repeat)) {
-    gchar *error = NULL;
-    const gchar *repeat_expr = gst_structure_get_string (act->structure,
-        "repeat");
-
-    if (repeat_expr) {
-      act->repeat =
-          gst_validate_utils_parse_expression (repeat_expr,
-          _set_variable_func, scenario, &error);
-    }
-  }
-
   GST_DEBUG_OBJECT (scenario, "Executing %" GST_PTR_FORMAT
       " at %" GST_TIME_FORMAT, act->structure, GST_TIME_ARGS (position));
   priv->seeked_in_pause = FALSE;
@@ -2867,9 +2886,8 @@ static gboolean
 _structure_set_variables (GQuark field_id, GValue * value,
     GstValidateAction * action)
 {
+  gchar *str;
   GstValidateScenario *scenario;
-  const gchar *var_value, *pvarname;
-  gint varname_len;
 
   if (!G_VALUE_HOLDS_STRING (value))
     return TRUE;
@@ -2878,26 +2896,14 @@ _structure_set_variables (GQuark field_id, GValue * value,
   if (!scenario)
     return TRUE;
 
-  pvarname = g_value_get_string (value);
-  varname_len = strlen (pvarname);
-  if (varname_len > 3 && pvarname[0] == '$' && pvarname[1] == '('
-      && pvarname[varname_len - 1] == ')') {
-    gchar *varname = g_malloc (sizeof (gchar) * varname_len - 3);
-    strncpy (varname, &pvarname[2], varname_len - 3);
-    varname[varname_len - 3] = '\0';
-
-    var_value = gst_structure_get_string (scenario->priv->vars, varname);
-    if (!var_value) {
-      g_error ("Trying to use undefined variable : %s", pvarname);
-
-      return TRUE;
-    }
-
-    GST_INFO_OBJECT (action, "Setting variable %s to %s", varname, var_value);
-    g_value_set_string (value, var_value);
+  str =
+      _replace_variables_in_string (scenario, action,
+      g_value_get_string (value));
+  if (str) {
+    g_value_set_string (value, str);
+    g_free (str);
   }
-
-  g_clear_object (&scenario);
+  gst_object_unref (scenario);
 
   return TRUE;
 }
@@ -2905,30 +2911,64 @@ _structure_set_variables (GQuark field_id, GValue * value,
 static gboolean
 gst_validate_action_default_prepare_func (GstValidateAction * action)
 {
-  gulong i;
-  GstClockTime time;
-  const gchar *vars[] = { "duration", "start", "stop" };
+  gint i;
+  GstClockTime tmp;
+  gchar *repeat_expr;
+  gchar *error = NULL;
+  GstValidateActionType *type = gst_validate_get_action_type (action->type);
   GstValidateScenario *scenario = gst_validate_action_get_scenario (action);
 
-  for (i = 0; i < G_N_ELEMENTS (vars); i++) {
-    gint res = gst_validate_action_get_clocktime (scenario, action, vars[i],
-        &time);
-    if (res == FALSE) {
-      GST_ERROR_OBJECT (scenario, "Could not get clocktime for"
-          " variable %s", vars[i]);
+  gst_structure_filter_and_map_in_place (action->structure,
+      (GstStructureFilterMapFunc) _structure_set_variables, action);
 
-      gst_object_unref (scenario);
-      return FALSE;
-    } else if (res == -1) {
-      continue;
-    }
+  for (i = 0; type->parameters[i].name; i++) {
+    if (g_str_has_suffix (type->parameters[i].types, "(GstClockTime)"))
+      gst_validate_action_get_clocktime (scenario, action,
+          type->parameters[i].name, &tmp);
+  }
 
-    gst_structure_set (action->structure, vars[i], GST_TYPE_CLOCK_TIME,
-        time, NULL);
+  if (action->repeat > 0) {
+    GST_ERROR ("Repeat already set!");
+    return TRUE;
   }
-  gst_object_unref (scenario);
-  gst_structure_filter_and_map_in_place (action->structure,
-      (GstStructureFilterMapFunc) _structure_set_variables, action);
+
+  if (!gst_structure_has_field (action->structure, "repeat"))
+    return TRUE;
+
+  if (gst_structure_get_int (action->structure, "repeat", &action->repeat))
+    return TRUE;
+
+  if (gst_structure_get_double (action->structure, "repeat",
+          (gdouble *) & action->repeat))
+    return TRUE;
+
+  repeat_expr =
+      g_strdup (gst_structure_get_string (action->structure, "repeat"));
+  if (!repeat_expr) {
+    g_error ("Invalid value for 'repeat' in %s",
+        gst_structure_to_string (action->structure));
+
+    return FALSE;
+  }
+
+  action->repeat =
+      gst_validate_utils_parse_expression (repeat_expr, _set_variable_func,
+      scenario, &error);
+  if (error) {
+    g_error ("Invalid value for 'repeat' in %s: %s",
+        gst_structure_to_string (action->structure), error);
+
+    return FALSE;
+  }
+  g_free (repeat_expr);
+
+  gst_structure_set (action->structure, "repeat", G_TYPE_INT, action->repeat,
+      NULL);
+  gst_structure_set (action->priv->main_structure, "repeat", G_TYPE_INT,
+      action->repeat, NULL);
+
+  if (scenario)
+    gst_object_unref (scenario);
 
   return TRUE;
 }
@@ -3030,8 +3070,11 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario)
 
       }
 
-      if (!gst_validate_parse_next_action_playback_time (scenario))
-        return FALSE;
+      if (scenario->priv->needs_playback_parsing) {
+        scenario->priv->needs_playback_parsing = FALSE;
+        if (!gst_validate_parse_next_action_playback_time (scenario))
+          return FALSE;
+      }
       _add_execute_actions_gsource (scenario);
       break;
     case GST_MESSAGE_STATE_CHANGED:
@@ -3145,9 +3188,9 @@ message_cb (GstBus * bus, GstMessage * message, GstValidateScenario * scenario)
       GST_DEBUG_OBJECT (scenario, "Got EOS; generate 'stop' action");
 
       stop_action_type = _find_action_type ("stop");
+      s = gst_structure_from_string ("stop, generated-after-eos=true;", NULL);
       stop_action = gst_validate_action_new (scenario, stop_action_type,
-          gst_structure_from_string ("stop, generated-after-eos=true;", NULL),
-          FALSE);
+          s, FALSE);
       gst_structure_free (s);
       gst_validate_execute_action (stop_action_type, stop_action);
       gst_mini_object_unref (GST_MINI_OBJECT (stop_action));
@@ -3607,6 +3650,7 @@ gst_validate_scenario_init (GstValidateScenario * scenario)
   priv->segment_stop = GST_CLOCK_TIME_NONE;
   priv->action_execution_interval = 10;
   priv->vars = gst_structure_new_empty ("vars");
+  priv->needs_playback_parsing = TRUE;
   g_weak_ref_init (&scenario->priv->ref_pipeline, NULL);
   priv->max_latency = GST_CLOCK_TIME_NONE;
   priv->max_dropped = -1;
@@ -4235,8 +4279,8 @@ _action_set_done (GstValidateAction * action)
   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");
 
+    GST_DEBUG_OBJECT (scenario, "Sub action executed ASYNC");
     execute_next_action (scenario);
   }
   gst_object_unref (scenario);
@@ -4667,7 +4711,7 @@ init_scenarios (void)
           .name = "start",
           .description = "The starting value of the seek",
           .mandatory = TRUE,
-          .types = "double or string",
+          .types = "double or string (GstClockTime)",
           .possible_variables = "position: The current position in the stream\n"
             "duration: The duration of the stream",
            NULL
@@ -4693,7 +4737,7 @@ init_scenarios (void)
           "  [none, set, end]",
           .mandatory = FALSE,
           .types = "string",
-        .possible_variables = NULL,
+          .possible_variables = NULL,
           .def = "set"
         },
         {
@@ -4705,10 +4749,14 @@ init_scenarios (void)
           .possible_variables = NULL,
           .def = "set"
         },
-        {"stop", "The stop value of the seek", FALSE, "double or ",
-          "position: The current position in the stream\n"
-            "duration: The duration of the stream"
-            "GST_CLOCK_TIME_NONE",
+        {
+          .name = "stop",
+          .description = "The stop value of the seek",
+          .mandatory = FALSE,
+          .types = "double or string (GstClockTime)",
+          .possible_variables = "position: The current position in the stream\n"
+            "duration: The duration of the stream",
+          .def ="GST_CLOCK_TIME_NONE",
         },
         {NULL}
       }),
@@ -4783,6 +4831,7 @@ init_scenarios (void)
           .name = "duration",
           .description = "the duration while no other action will be executed",
           .mandatory = FALSE,
+          .types = "double or string (GstClockTime)",
           NULL},
         {
           .name = "target-element-name",
@@ -5144,6 +5193,7 @@ init_scenarios (void)
       gst_structure_set_name (plug_conf, action_typename);
 
       action = gst_validate_action_new (NULL, atype, plug_conf, FALSE);
+      gst_validate_action_unref (action);
     }
   }
 }
index 337de6f..39ac488 100644 (file)
@@ -47,7 +47,8 @@ typedef enum
   GST_VALIDATE_EXECUTE_ACTION_ASYNC,
   GST_VALIDATE_EXECUTE_ACTION_INTERLACED,
   GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED,
-  GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS
+  GST_VALIDATE_EXECUTE_ACTION_IN_PROGRESS,
+  GST_VALIDATE_EXECUTE_ACTION_NONE,
 } GstValidateActionReturn;
 
 /* TODO 2.0 -- Make it an actual enum type */
@@ -124,6 +125,8 @@ GstValidateAction   * gst_validate_action_new          (GstValidateScenario * sc
                                                         GstValidateActionType * action_type,
                                                         GstStructure *structure,
                                                         gboolean add_to_lists);
+GST_VALIDATE_API
+void gst_validate_action_unref             (GstValidateAction * action);
 
 #define GST_TYPE_VALIDATE_ACTION            (gst_validate_action_get_type ())
 #define GST_IS_VALIDATE_ACTION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VALIDATE_ACTION))
@@ -214,8 +217,11 @@ gboolean gst_validate_print_action_types (const gchar ** wanted_types, gint num_
  * @mandatory: Whether the parameter is mandatory for
  *             a specific action type
  * @types: The types the parameter can take described as a
- * string. It can be precisely describing how the typing works
+ *         string. It can be precisely describing how the typing works
  *         using '\n' between the various acceptable types.
+ *         NOTE: The types should end with `(GstClockTime)` if its final
+ *         type is a GstClockTime, this way it will be processed when preparing
+ *         the actions.
  * @possible_variables: The name of the variables that can be
  *                      used to compute the value of the parameter.
  *                      For example for the start value of a seek
index d5861fc..471a673 100644 (file)
@@ -3,7 +3,8 @@ validate_tests = [
   ['validate/padmonitor'],
   ['validate/monitoring'],
   ['validate/reporting'],
-  ['validate/overrides']
+  ['validate/overrides'],
+  ['validate/scenario']
 ]
 
 test_defines = [
@@ -38,6 +39,7 @@ foreach t : validate_tests
         c_args : gst_c_args + test_defines,
         include_directories : [inc_dirs],
         dependencies : [validate_dep, gst_check_dep],
+        link_with: gstvalidate
     )
     env.set('GST_REGISTRY',
             '@0@/@1@.registry'.format(meson.current_build_dir(), test_name))
diff --git a/validate/tests/check/validate/scenario.c b/validate/tests/check/validate/scenario.c
new file mode 100644 (file)
index 0000000..a6299aa
--- /dev/null
@@ -0,0 +1,62 @@
+#include <gst/check/gstcheck.h>
+#include <glib/gstdio.h>
+#include <gst/validate/validate.h>
+
+GST_START_TEST (test_expression_parser)
+{
+  GstClockTime start;
+  GstValidateRunner *runner = gst_validate_runner_new ();
+  GstValidateActionType *set_vars = gst_validate_get_action_type ("set-vars");
+  GstValidateActionType *seek_type = gst_validate_get_action_type ("seek");
+  GstValidateScenario *scenario =
+      g_object_new (GST_TYPE_VALIDATE_SCENARIO, "validate-runner",
+      runner, NULL);
+  GstValidateAction *action;
+
+  fail_unless (seek_type);
+
+  action = gst_validate_action_new (scenario, set_vars,
+      gst_structure_from_string
+      ("set-vars, a=(string)\"50\", b=(string)\"70\", default_flags=flush",
+          NULL), FALSE);
+  fail_unless_equals_int (gst_validate_execute_action (set_vars, action),
+      GST_VALIDATE_EXECUTE_ACTION_OK);
+  gst_validate_action_unref (action);
+
+  action = gst_validate_action_new (scenario, seek_type,
+      gst_structure_from_string
+      ("seek, start=\"min($(a), $(b))\", flags=\"$(default_flags)\"", NULL),
+      FALSE);
+  fail_unless (action);
+
+  fail_unless (seek_type->prepare (action));
+  fail_unless (gst_validate_action_get_clocktime (scenario, action, "start",
+          &start));
+  fail_unless_equals_uint64 (start, 50 * GST_SECOND);
+  gst_validate_action_unref (action);
+
+  gst_object_unref (runner);
+}
+
+GST_END_TEST;
+
+static Suite *
+gst_validate_suite (void)
+{
+  Suite *s = suite_create ("registry");
+  TCase *tc_chain = tcase_create ("registry");
+  suite_add_tcase (s, tc_chain);
+
+  if (atexit (gst_validate_deinit) != 0) {
+    GST_ERROR ("failed to set gst_validate_deinit as exit function");
+  }
+
+  g_setenv ("GST_VALIDATE_REPORTING_DETAILS", "all", TRUE);
+  gst_validate_init ();
+  tcase_add_test (tc_chain, test_expression_parser);
+  gst_validate_deinit ();
+
+  return s;
+}
+
+GST_CHECK_MAIN (gst_validate);