validate: add non flushing seek support
authorVincent Penquerc'h <vincent.penquerch@collabora.co.uk>
Thu, 19 Feb 2015 13:12:50 +0000 (13:12 +0000)
committerVincent Penquerc'h <vincent.penquerch@collabora.co.uk>
Mon, 9 Mar 2015 10:06:34 +0000 (10:06 +0000)
and a couple scenarios using them

https://bugzilla.gnome.org/show_bug.cgi?id=744783

validate/data/Makefile.am
validate/data/seek_backward_non_flushing.scenario [new file with mode: 0644]
validate/data/seek_forward_non_flushing.scenario [new file with mode: 0644]
validate/gst/validate/gst-validate-scenario.c

index 1f4f4a4ffd2b8cfbb34439d01e798ceff272f97d..1a5411b764e08297932dcad64474e609b0e69c76 100644 (file)
@@ -1,7 +1,9 @@
 scenariosdir=${datadir}/gstreamer-$(GST_API_VERSION)/validate-scenario
 scenarios_DATA = simple_seeks.scenario \
                  seek_forward.scenario \
+                 seek_forward_non_flushing.scenario \
                  seek_backward.scenario \
+                 seek_backward_non_flushing.scenario \
                  seek_forward_backward.scenario \
                  reverse_playback.scenario \
                  fast_forward.scenario \
@@ -27,7 +29,9 @@ scenarios_DATA = simple_seeks.scenario \
 
 EXTRA_DIST = simple_seeks.scenario \
              seek_forward.scenario \
+             seek_forward_non_flushing.scenario \
              seek_backward.scenario \
+             seek_backward_non_flushing.scenario \
              seek_forward_backward.scenario \
              reverse_playback.scenario \
              fast_forward.scenario \
diff --git a/validate/data/seek_backward_non_flushing.scenario b/validate/data/seek_backward_non_flushing.scenario
new file mode 100644 (file)
index 0000000..4c4f280
--- /dev/null
@@ -0,0 +1,5 @@
+description, seek=true, duration=30, need-clock-sync=true, min-media-duration=15
+seek, name=Backward-seek, playback-time="min(5.0, (duration/4))", rate=1.0, start=0.0, flags=accurate
+seek, name=Backward-seek, playback-time="min(10.0, 2*(duration/4))", rate=1.0, start="min(5.0, duration/4)", flags=accurate
+seek, name=Backward-seek, playback-time="min(15.0, 3*(duration/4))", rate=1.0, start="min(10.0, 2*(duration/4))", flags=accurate
+stop, playback-time="min(15.0, 3*(duration/4))"
diff --git a/validate/data/seek_forward_non_flushing.scenario b/validate/data/seek_forward_non_flushing.scenario
new file mode 100644 (file)
index 0000000..2ee7078
--- /dev/null
@@ -0,0 +1,5 @@
+description, seek=true, duration=20, need-clock-sync=true, min-media-duration=30
+seek, name=First-forward-seek, playback-time="min(5.0, (duration/8))", start="min(10, 2*(duration/8))", flags=accurate
+seek, name=Second-forward-seek, playback-time="min(15.0, 3*(duration/8))", start="min(20, 4*(duration/8))", flags=accurate
+seek, name=Third-forward-seek, playback-time="min(25, 5*(duration/8))", start="min(30.0, 6*(duration/8))", flags=accurate
+stop, playback-time=35.0
index 0a92eebd870ebfe9645bfabcd9da8c31802c8654..d1a4ed0b97e881df37f58e891ce7453104865100 100644 (file)
@@ -113,6 +113,7 @@ struct _GstValidateScenarioPrivate
   GstClockTime segment_start;
   GstClockTime segment_stop;
   GstClockTime seek_pos_tol;
+  guint32 expected_seqnum;
 
   /* If we seeked in paused the position should be exactly what
    * the seek value was (if accurate) */
@@ -131,6 +132,8 @@ struct _GstValidateScenarioPrivate
   GstState target_state;
 
   GList *overrides;
+
+  guint segments_needed;
 };
 
 typedef struct KeyFileGroupName
@@ -430,6 +433,122 @@ gst_validate_action_get_clocktime (GstValidateScenario * scenario,
   return TRUE;
 }
 
+static GstPadProbeReturn
+_check_new_segment_done (GstPad * pad, GstPadProbeInfo * info,
+    GstValidateAction * action)
+{
+  GstEvent *event = GST_EVENT (info->data);
+  if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
+    if (GST_EVENT_SEQNUM (event) == action->scenario->priv->expected_seqnum) {
+      if (!--action->scenario->priv->segments_needed) {
+        gst_validate_action_set_done (action);
+        return GST_PAD_PROBE_REMOVE;
+      }
+    }
+  }
+
+  return GST_PAD_PROBE_OK;
+}
+
+static GstObject *
+_find_any_object (GstIterator * iter)
+{
+  GstObject *object = NULL;
+  gboolean done = FALSE;
+  GValue data = { 0, };
+
+  while (!done) {
+    switch (gst_iterator_next (iter, &data)) {
+      case GST_ITERATOR_OK:
+      {
+        object = g_value_get_object (&data);
+        gst_object_ref (object);
+        g_value_reset (&data);
+        done = TRUE;
+        break;
+      }
+      case GST_ITERATOR_RESYNC:
+        gst_iterator_resync (iter);
+        break;
+      case GST_ITERATOR_DONE:
+        done = TRUE;
+        break;
+      case GST_ITERATOR_ERROR:
+        g_assert_not_reached ();
+        done = TRUE;
+        break;
+    }
+  }
+  g_value_unset (&data);
+  gst_iterator_free (iter);
+
+  return object;
+}
+
+static guint
+_run_for_all_sinks (GstValidateScenario * scenario,
+    void (*f) (GstValidateScenario *, GstElement *, gpointer),
+    gpointer userdata)
+{
+  GstElement *sink = NULL;
+  gboolean done = FALSE;
+  GValue data = { 0, };
+  GstIterator *iter;
+  guint nsinks = 0;
+
+  iter = gst_bin_iterate_sinks (GST_BIN (scenario->pipeline));
+  while (!done) {
+    switch (gst_iterator_next (iter, &data)) {
+      case GST_ITERATOR_OK:
+      {
+        sink = GST_ELEMENT (g_value_get_object (&data));
+        (*f) (scenario, sink, userdata);
+        g_value_reset (&data);
+        ++nsinks;
+        break;
+      }
+      case GST_ITERATOR_RESYNC:
+        gst_iterator_resync (iter);
+        break;
+      case GST_ITERATOR_DONE:
+        done = TRUE;
+        break;
+      case GST_ITERATOR_ERROR:
+        g_assert_not_reached ();
+        done = TRUE;
+        break;
+    }
+  }
+  g_value_unset (&data);
+  gst_iterator_free (iter);
+
+  return nsinks;
+}
+
+static GstPad *
+_find_any_sink_pad (GstElement * e)
+{
+  return GST_PAD (_find_any_object (gst_element_iterate_sink_pads (e)));
+}
+
+static void
+_add_segment_check_probe (GstValidateScenario * scenario, GstElement * sink,
+    gpointer data)
+{
+  GstPad *sinkpad;
+  GstValidateAction *action = data;
+
+  sinkpad = _find_any_sink_pad (sink);
+  if (sinkpad) {
+    gst_pad_add_probe (sinkpad,
+        GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
+        (GstPadProbeCallback) _check_new_segment_done, action, NULL);
+    gst_object_unref (sinkpad);
+  } else {
+    GST_WARNING_OBJECT (scenario, "No sink pad found on sink");
+  }
+}
+
 /**
  * gst_validate_scenario_execute_seek:
  * @scenario: The #GstValidateScenario for which to execute a seek action
@@ -466,6 +585,7 @@ gst_validate_scenario_execute_seek (GstValidateScenario * scenario,
   if (gst_element_send_event (scenario->pipeline, seek)) {
     gst_event_replace (&priv->last_seek, seek);
     priv->seek_flags = flags;
+    priv->expected_seqnum = GST_EVENT_SEQNUM (seek);
   } else {
     GST_VALIDATE_REPORT (scenario, EVENT_SEEK_NOT_HANDLED,
         "Could not execute seek: '(position %" GST_TIME_FORMAT
@@ -478,6 +598,15 @@ gst_validate_scenario_execute_seek (GstValidateScenario * scenario,
   }
   gst_event_unref (seek);
 
+  /* Flushing seeks will be deemed done when an ASYNC_DONE message gets
+     received on the bus. We don't get one for non flushing seeks though,
+     so we look for a new segment event with a matching seqnum. */
+  if (ret != GST_VALIDATE_EXECUTE_ACTION_ERROR
+      && !(flags & GST_SEEK_FLAG_FLUSH)) {
+    action->scenario->priv->segments_needed =
+        _run_for_all_sinks (scenario, _add_segment_check_probe, action);
+  }
+
   return ret;
 }