qa-scenario: add new scenario action - Pause
authorThiago Santos <thiago.sousa.santos@collabora.com>
Thu, 1 Aug 2013 12:35:59 +0000 (09:35 -0300)
committerThiago Santos <thiago.sousa.santos@collabora.com>
Thu, 1 Aug 2013 12:35:59 +0000 (09:35 -0300)
The pause action instructs the pipeline to go to paused state and then
return to playing. It has the argument 'duration', that indicates the
duration for which the pipeline will remain in paused

validate/gst/qa/gst-qa-report.c
validate/gst/qa/gst-qa-report.h
validate/gst/qa/gst-qa-scenario.c

index fa17632ff876bd79b6c7250c1665d0a5b124dd90..d03b183968e1ffa3a5f335486af4b0d7dac3fb95 100644 (file)
@@ -169,6 +169,9 @@ gst_qa_report_load_issues (void)
       _("seek event wasn't handled"), NULL, GST_QA_REPORT_LEVEL_CRITICAL);
   REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG,
       _("position after a seek is wrong"), NULL, GST_QA_REPORT_LEVEL_CRITICAL);
+
+  REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_STATE_CHANGE_FAILURE,
+      _("state change failed"), NULL, GST_QA_REPORT_LEVEL_CRITICAL);
 }
 
 void
index db33802bb85af2bb30cd6d92b646cec04e4e46aa..fe02745f47927db619603cb93a23591073751a9f 100644 (file)
@@ -54,6 +54,7 @@ typedef enum {
   GST_QA_AREA_QUERY,
   GST_QA_AREA_CAPS,
   GST_QA_AREA_SEEK,
+  GST_QA_AREA_STATE,
   GST_QA_AREA_OTHER=100,
 } GstQaReportArea;
 
@@ -86,6 +87,8 @@ typedef guintptr GstQaIssueId;
 #define GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED           (((GstQaIssueId) GST_QA_AREA_SEEK) << GST_QA_ISSUE_ID_SHIFT | 1)
 #define GST_QA_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG (((GstQaIssueId) GST_QA_AREA_SEEK) << GST_QA_ISSUE_ID_SHIFT | 2)
 
+#define GST_QA_ISSUE_ID_STATE_CHANGE_FAILURE (((GstQaIssueId) GST_QA_AREA_STATE) << GST_QA_ISSUE_ID_SHIFT | 1)
+
 #define GST_QA_ISSUE_ID_AREA(id) ((guintptr)(id >> GST_QA_ISSUE_ID_SHIFT))
 
 typedef struct {
index 3b40c4584a43349bed9c4ad8c6131da21adfaa01..943a777a65e880b1d18ee07277bd5c26f4ea4882 100644 (file)
@@ -62,6 +62,7 @@ typedef enum
 {
   SCENARIO_ACTION_UNKNOWN = 0,
   SCENARIO_ACTION_SEEK,
+  SCENARIO_ACTION_PAUSE,
 } ScenarioActionType;
 
 typedef struct _ScenarioAction
@@ -87,6 +88,13 @@ typedef struct _SeekInfo
 
 } SeekInfo;
 
+typedef struct _PauseInfo
+{
+  ScenarioAction action;
+
+  GstClockTime duration;
+} PauseInfo;
+
 struct _GstQaScenarioPrivate
 {
   GstElement *pipeline;
@@ -161,6 +169,18 @@ _new_seek_info (void)
   return info;
 }
 
+static PauseInfo *
+_new_pause_info (void)
+{
+  PauseInfo *pause = g_slice_new (PauseInfo);
+
+  _scenario_action_init (SCENARIO_ACTION (pause));
+  pause->action.type = SCENARIO_ACTION_PAUSE;
+  pause->duration = 0;
+
+  return pause;
+}
+
 static void
 _scenario_action_clear (ScenarioAction * act)
 {
@@ -174,6 +194,13 @@ _free_seek_info (SeekInfo * info)
   g_slice_free (SeekInfo, info);
 }
 
+static void
+_free_pause_info (PauseInfo * info)
+{
+  _scenario_action_clear (SCENARIO_ACTION (info));
+  g_slice_free (PauseInfo, info);
+}
+
 static void
 _free_scenario_action (ScenarioAction * act)
 {
@@ -181,6 +208,9 @@ _free_scenario_action (ScenarioAction * act)
     case SCENARIO_ACTION_SEEK:
       _free_seek_info ((SeekInfo *) act);
       break;
+    case SCENARIO_ACTION_PAUSE:
+      _free_pause_info ((PauseInfo *) act);
+      break;
     default:
       g_assert_not_reached ();
       _scenario_action_clear (act);
@@ -225,6 +255,31 @@ _parse_seek (GMarkupParseContext * context, const gchar * element_name,
   priv->seeks = g_list_append (priv->seeks, info);
 }
 
+static inline void
+_parse_pause (GMarkupParseContext * context, const gchar * element_name,
+    const gchar ** attribute_names, const gchar ** attribute_values,
+    GstQaScenario * scenario, GError ** error)
+{
+  GstQaScenarioPrivate *priv = scenario->priv;
+  const char *duration = NULL;
+  const char *playback_time = NULL;
+
+  PauseInfo *info = _new_pause_info ();
+
+  if (!g_markup_collect_attributes (element_name, attribute_names,
+          attribute_values, error,
+          G_MARKUP_COLLECT_STRDUP | G_MARKUP_COLLECT_OPTIONAL, "name",
+          &info->action.name, G_MARKUP_COLLECT_STRING, "playback_time",
+          &playback_time, G_MARKUP_COLLECT_STRING, "duration", &duration,
+          G_MARKUP_COLLECT_INVALID))
+    return;
+
+  if (playback_time)
+    info->action.playback_time = g_ascii_strtoull (playback_time, NULL, 10);
+  info->duration = g_ascii_strtoull (duration, NULL, 10);
+  priv->seeks = g_list_append (priv->seeks, info);
+}
+
 static void
 _parse_element_start (GMarkupParseContext * context, const gchar * element_name,
     const gchar ** attribute_names, const gchar ** attribute_values,
@@ -248,6 +303,9 @@ _parse_element_start (GMarkupParseContext * context, const gchar * element_name,
       if (g_strcmp0 (element_name, "seek") == 0) {
         _parse_seek (context, element_name, attribute_names,
             attribute_values, scenario, error);
+      } else if (g_strcmp0 (element_name, "pause") == 0) {
+        _parse_pause (context, element_name, attribute_names,
+            attribute_values, scenario, error);
       }
     }
   }
@@ -268,6 +326,57 @@ _parse_element_end (GMarkupParseContext * context, const gchar * element_name,
   }
 }
 
+static gboolean
+_pause_action_restore_playing (GstQaScenario * scenario)
+{
+  GstElement *pipeline = scenario->priv->pipeline;
+
+  if (gst_element_set_state (pipeline, GST_STATE_PLAYING) ==
+      GST_STATE_CHANGE_FAILURE) {
+    GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_STATE_CHANGE_FAILURE,
+        "Failed to set state to playing");
+  }
+
+  return FALSE;
+}
+
+static void
+_execute_action (GstQaScenario * scenario, ScenarioAction * act)
+{
+  GstQaScenarioPrivate *priv = scenario->priv;
+  GstElement *pipeline = scenario->priv->pipeline;
+
+  if (act->type == SCENARIO_ACTION_SEEK) {
+    SeekInfo *seek = (SeekInfo *) act;
+    GST_DEBUG ("seeking to: %" GST_TIME_FORMAT " stop: %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (seek->start), GST_TIME_ARGS (seek->stop));
+
+    if (gst_element_seek (pipeline, seek->rate,
+            seek->format, seek->flags,
+            seek->start_type, seek->start,
+            seek->stop_type, seek->stop) == FALSE) {
+      GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED,
+          "Could not seek to position %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (priv->seeked_position));
+    }
+    priv->seeked_position = seek->start;
+
+  } else if (act->type == SCENARIO_ACTION_PAUSE) {
+    PauseInfo *pause = (PauseInfo *) act;
+
+    GST_DEBUG ("Pausing for %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (pause->duration));
+
+    if (gst_element_set_state (pipeline, GST_STATE_PAUSED) ==
+        GST_STATE_CHANGE_FAILURE) {
+      GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_STATE_CHANGE_FAILURE,
+          "Failed to set state to paused");
+    }
+    g_timeout_add (pause->duration / GST_MSECOND,
+        (GSourceFunc) _pause_action_restore_playing, scenario);
+  }
+}
+
 static gboolean
 get_position (GstQaScenario * scenario)
 {
@@ -279,38 +388,27 @@ get_position (GstQaScenario * scenario)
 
   gst_element_query_position (pipeline, &format, &position);
 
-  tmp = scenario->priv->seeks;
-  GST_DEBUG ("Current position: %" GST_TIME_FORMAT, GST_TIME_ARGS (position));
-  while (tmp) {
-    SeekInfo *seek = tmp->data;
+  GST_LOG ("Current position: %" GST_TIME_FORMAT, GST_TIME_ARGS (position));
+  for (tmp = scenario->priv->seeks; tmp; tmp = g_list_next (tmp)) {
+    ScenarioAction *act = tmp->data;
 
-    if ((position >= (seek->action.playback_time - priv->seek_pos_tol))
-        && (position <= (seek->action.playback_time + priv->seek_pos_tol))) {
+    if ((position >= (act->playback_time - priv->seek_pos_tol))
+        && (position <= (act->playback_time + priv->seek_pos_tol))) {
 
+      /* TODO what about non flushing seeks? */
+      /* TODO why is this inside the action time if ? */
       if (GST_CLOCK_TIME_IS_VALID (priv->seeked_position))
         GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED,
             "Previous seek to %" GST_TIME_FORMAT " was not handled",
             GST_TIME_ARGS (priv->seeked_position));
 
-      GST_LOG ("seeking to: %" GST_TIME_FORMAT " stop: %" GST_TIME_FORMAT,
-          GST_TIME_ARGS (seek->start), GST_TIME_ARGS (seek->stop));
-
-      if (gst_element_seek (pipeline, seek->rate,
-              seek->format, seek->flags,
-              seek->start_type, seek->start,
-              seek->stop_type, seek->stop) == FALSE) {
-        GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED,
-            "Could not seek to position %" GST_TIME_FORMAT,
-            GST_TIME_ARGS (priv->seeked_position));
-      }
+      _execute_action (scenario, act);
 
-      priv->seeked_position = seek->start;
       priv->seeks = g_list_remove_link (priv->seeks, tmp);
-      g_slice_free (SeekInfo, seek);
+      _free_scenario_action (act);
       g_list_free (tmp);
       break;
     }
-    tmp = tmp->next;
   }
   return TRUE;
 }