mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-19 08:11:16 +00:00
qa-scenario: add new scenario action - Pause
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
This commit is contained in:
parent
60b0c7383f
commit
caba58c029
3 changed files with 124 additions and 20 deletions
|
@ -169,6 +169,9 @@ gst_qa_report_load_issues (void)
|
||||||
_("seek event wasn't handled"), NULL, GST_QA_REPORT_LEVEL_CRITICAL);
|
_("seek event wasn't handled"), NULL, GST_QA_REPORT_LEVEL_CRITICAL);
|
||||||
REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG,
|
REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG,
|
||||||
_("position after a seek is wrong"), NULL, GST_QA_REPORT_LEVEL_CRITICAL);
|
_("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
|
void
|
||||||
|
|
|
@ -54,6 +54,7 @@ typedef enum {
|
||||||
GST_QA_AREA_QUERY,
|
GST_QA_AREA_QUERY,
|
||||||
GST_QA_AREA_CAPS,
|
GST_QA_AREA_CAPS,
|
||||||
GST_QA_AREA_SEEK,
|
GST_QA_AREA_SEEK,
|
||||||
|
GST_QA_AREA_STATE,
|
||||||
GST_QA_AREA_OTHER=100,
|
GST_QA_AREA_OTHER=100,
|
||||||
} GstQaReportArea;
|
} 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_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_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))
|
#define GST_QA_ISSUE_ID_AREA(id) ((guintptr)(id >> GST_QA_ISSUE_ID_SHIFT))
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -62,6 +62,7 @@ typedef enum
|
||||||
{
|
{
|
||||||
SCENARIO_ACTION_UNKNOWN = 0,
|
SCENARIO_ACTION_UNKNOWN = 0,
|
||||||
SCENARIO_ACTION_SEEK,
|
SCENARIO_ACTION_SEEK,
|
||||||
|
SCENARIO_ACTION_PAUSE,
|
||||||
} ScenarioActionType;
|
} ScenarioActionType;
|
||||||
|
|
||||||
typedef struct _ScenarioAction
|
typedef struct _ScenarioAction
|
||||||
|
@ -87,6 +88,13 @@ typedef struct _SeekInfo
|
||||||
|
|
||||||
} SeekInfo;
|
} SeekInfo;
|
||||||
|
|
||||||
|
typedef struct _PauseInfo
|
||||||
|
{
|
||||||
|
ScenarioAction action;
|
||||||
|
|
||||||
|
GstClockTime duration;
|
||||||
|
} PauseInfo;
|
||||||
|
|
||||||
struct _GstQaScenarioPrivate
|
struct _GstQaScenarioPrivate
|
||||||
{
|
{
|
||||||
GstElement *pipeline;
|
GstElement *pipeline;
|
||||||
|
@ -161,6 +169,18 @@ _new_seek_info (void)
|
||||||
return info;
|
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
|
static void
|
||||||
_scenario_action_clear (ScenarioAction * act)
|
_scenario_action_clear (ScenarioAction * act)
|
||||||
{
|
{
|
||||||
|
@ -174,6 +194,13 @@ _free_seek_info (SeekInfo * info)
|
||||||
g_slice_free (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
|
static void
|
||||||
_free_scenario_action (ScenarioAction * act)
|
_free_scenario_action (ScenarioAction * act)
|
||||||
{
|
{
|
||||||
|
@ -181,6 +208,9 @@ _free_scenario_action (ScenarioAction * act)
|
||||||
case SCENARIO_ACTION_SEEK:
|
case SCENARIO_ACTION_SEEK:
|
||||||
_free_seek_info ((SeekInfo *) act);
|
_free_seek_info ((SeekInfo *) act);
|
||||||
break;
|
break;
|
||||||
|
case SCENARIO_ACTION_PAUSE:
|
||||||
|
_free_pause_info ((PauseInfo *) act);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
_scenario_action_clear (act);
|
_scenario_action_clear (act);
|
||||||
|
@ -225,6 +255,31 @@ _parse_seek (GMarkupParseContext * context, const gchar * element_name,
|
||||||
priv->seeks = g_list_append (priv->seeks, info);
|
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
|
static void
|
||||||
_parse_element_start (GMarkupParseContext * context, const gchar * element_name,
|
_parse_element_start (GMarkupParseContext * context, const gchar * element_name,
|
||||||
const gchar ** attribute_names, const gchar ** attribute_values,
|
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) {
|
if (g_strcmp0 (element_name, "seek") == 0) {
|
||||||
_parse_seek (context, element_name, attribute_names,
|
_parse_seek (context, element_name, attribute_names,
|
||||||
attribute_values, scenario, error);
|
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
|
static gboolean
|
||||||
get_position (GstQaScenario * scenario)
|
get_position (GstQaScenario * scenario)
|
||||||
{
|
{
|
||||||
|
@ -279,38 +388,27 @@ get_position (GstQaScenario * scenario)
|
||||||
|
|
||||||
gst_element_query_position (pipeline, &format, &position);
|
gst_element_query_position (pipeline, &format, &position);
|
||||||
|
|
||||||
tmp = scenario->priv->seeks;
|
GST_LOG ("Current position: %" GST_TIME_FORMAT, GST_TIME_ARGS (position));
|
||||||
GST_DEBUG ("Current position: %" GST_TIME_FORMAT, GST_TIME_ARGS (position));
|
for (tmp = scenario->priv->seeks; tmp; tmp = g_list_next (tmp)) {
|
||||||
while (tmp) {
|
ScenarioAction *act = tmp->data;
|
||||||
SeekInfo *seek = tmp->data;
|
|
||||||
|
|
||||||
if ((position >= (seek->action.playback_time - priv->seek_pos_tol))
|
if ((position >= (act->playback_time - priv->seek_pos_tol))
|
||||||
&& (position <= (seek->action.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))
|
if (GST_CLOCK_TIME_IS_VALID (priv->seeked_position))
|
||||||
GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED,
|
GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED,
|
||||||
"Previous seek to %" GST_TIME_FORMAT " was not handled",
|
"Previous seek to %" GST_TIME_FORMAT " was not handled",
|
||||||
GST_TIME_ARGS (priv->seeked_position));
|
GST_TIME_ARGS (priv->seeked_position));
|
||||||
|
|
||||||
GST_LOG ("seeking to: %" GST_TIME_FORMAT " stop: %" GST_TIME_FORMAT,
|
_execute_action (scenario, act);
|
||||||
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;
|
|
||||||
priv->seeks = g_list_remove_link (priv->seeks, tmp);
|
priv->seeks = g_list_remove_link (priv->seeks, tmp);
|
||||||
g_slice_free (SeekInfo, seek);
|
_free_scenario_action (act);
|
||||||
g_list_free (tmp);
|
g_list_free (tmp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tmp = tmp->next;
|
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue