From ccc3f8d696905b97ea531cecbf8b85cb8cdfc1c6 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Mon, 2 Sep 2013 11:11:15 -0400 Subject: [PATCH] scenario: add a track switch command, and an audio track switch test The "switch-track" command can be used to switch tracks. The "type" argument selects which track type to change (can be "audio", "video", or "text"). The "index" argument selects which track of this type to use: it can be either a number, which will be the Nth track of the given type, or a number with a "+" or "-" prefix, which means a relative change (eg, "+1" means "next track", "-1" means "previous track"). Conflicts: validate/gst/validate/gst-validate-scenario.c --- validate/data/Makefile.am | 6 +- validate/data/switch_audio_track.scenario | 1 + validate/gst/validate/gst-validate-scenario.c | 178 +++++++++++++++++- 3 files changed, 182 insertions(+), 3 deletions(-) create mode 100644 validate/data/switch_audio_track.scenario diff --git a/validate/data/Makefile.am b/validate/data/Makefile.am index 3a53c0259d..4f887533b5 100644 --- a/validate/data/Makefile.am +++ b/validate/data/Makefile.am @@ -7,7 +7,8 @@ scenarios_DATA = simple_seeks.scenario \ fast_forward.scenario \ fast_backward.scenario \ alternate_fast_backward_forward.scenario \ - pause_resume.scenario + pause_resume.scenario \ + switch_audio_track.scenario EXTRA_DIST = simple_seeks.scenario \ seek_forward.scenario \ @@ -17,4 +18,5 @@ EXTRA_DIST = simple_seeks.scenario \ fast_forward.scenario \ fast_backward.scenario \ alternate_fast_backward_forward.scenario \ - pause_resume.scenario + pause_resume.scenario \ + switch_audio_track.scenario diff --git a/validate/data/switch_audio_track.scenario b/validate/data/switch_audio_track.scenario new file mode 100644 index 0000000000..427de5b8dd --- /dev/null +++ b/validate/data/switch_audio_track.scenario @@ -0,0 +1 @@ +switch-track, name=Next-audio-track, playback_time=5.0, type=audio, index=(string)+1 diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index 34d8b6fe74..b1f0263a16 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -252,6 +252,179 @@ _execute_eos (GstValidateScenario * scenario, GstValidateAction * action) gst_event_new_eos ()); } +static int +find_input_selector (GValue * velement, const gchar *type) +{ + GstElement *element = g_value_get_object (velement); + + if (G_OBJECT_TYPE (element) == g_type_from_name ("GstInputSelector")) { + GstPad *srcpad = gst_element_get_static_pad (element, "src"); + + if (srcpad) { + GstCaps *caps = gst_pad_query_caps (srcpad, NULL); + + if (caps) { + const char *mime = + gst_structure_get_name (gst_caps_get_structure (caps, 0)); + gboolean found = FALSE; + + if (g_strcmp0 (type, "audio") == 0) + found = g_str_has_prefix (mime, "audio/"); + else if (g_strcmp0 (type, "video") == 0) + found = g_str_has_prefix (mime, "video/") + && !g_str_has_prefix (mime, "video/x-dvd-subpicture"); + else if (g_strcmp0 (type, "text") == 0) + found = g_str_has_prefix (mime, "text/") + || g_str_has_prefix (mime, "subtitle/") + || g_str_has_prefix (mime, "video/x-dvd-subpicture"); + + gst_object_unref (srcpad); + if (found) + return 0; + } + } + } + return !0; +} + +static GstElement * +find_input_selector_with_type (GstBin * bin, const gchar *type) +{ + GValue result = {0, }; + GstElement *input_selector = NULL; + GstIterator *iterator = gst_bin_iterate_recurse (bin); + + if (gst_iterator_find_custom (iterator, + (GCompareFunc) find_input_selector, &result, (gpointer) type)) { + input_selector = g_value_get_object (&result); + } + gst_iterator_free (iterator); + + return input_selector; +} + +static GstPad * +find_nth_sink_pad (GstElement * element, int index) +{ + GstIterator *iterator; + gboolean done = FALSE; + GstPad *pad = NULL; + int dec_index = index; + GValue data = { 0, }; + + iterator = gst_element_iterate_sink_pads (element); + while (!done) { + switch (gst_iterator_next (iterator, &data)) { + case GST_ITERATOR_OK: + if (!dec_index--) { + done = TRUE; + pad = g_value_get_object (&data); + break; + } + g_value_reset (&data); + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (iterator); + dec_index = index; + break; + case GST_ITERATOR_ERROR: + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (iterator); + return pad; +} + +static int +find_sink_pad_index (GstElement * element, GstPad * pad) +{ + GstIterator *iterator; + gboolean done = FALSE; + int index = 0; + GValue data = { 0, }; + + iterator = gst_element_iterate_sink_pads (element); + while (!done) { + switch (gst_iterator_next (iterator, &data)) { + case GST_ITERATOR_OK: + if (pad == g_value_get_object (&data)) { + done = TRUE; + } else { + index++; + } + g_value_reset (&data); + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync (iterator); + index = 0; + break; + case GST_ITERATOR_ERROR: + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + gst_iterator_free (iterator); + return index; +} + +static gboolean +_execute_switch_track (GstValidateScenario * scenario, GstValidateAction * action) +{ + guint index; + gboolean relative = FALSE; + const gchar *type, *str_index; + GstElement *input_selector; + + if (!(type = gst_structure_get_string (action->structure, "type"))) + type = "audio"; + + /* First find an input selector that has the right type */ + input_selector = find_input_selector_with_type (GST_BIN (scenario->priv->pipeline), type); + if (input_selector) { + GstPad *pad; + + if ((str_index = gst_structure_get_string (action->structure, "index"))) { + if (!gst_structure_get_uint (action->structure, "index", &index)) { + GST_WARNING ("No index given, defaulting to +1"); + index = 1; + relative = TRUE; + } + } else { + relative = strchr ("+-", str_index[0]) != NULL; + index = g_ascii_strtoll (str_index, NULL, 10); + } + + if (relative) { /* We are changing track relatively to current track */ + int npads; + + g_object_get (input_selector, "active-pad", &pad, "n-pads", &npads, NULL); + if (pad) { + int current_index = find_sink_pad_index (input_selector, pad); + + index = (current_index + index) % npads; + gst_object_unref (pad); + } + } + + g_print ("Switching to track number: %i\n", index); + pad = find_nth_sink_pad (input_selector, index); + g_object_set (input_selector, "active-pad", pad, NULL); + gst_object_unref (pad); + gst_object_unref (input_selector); + + return TRUE; + } + + /* No selector found -> Failed */ + return FALSE; +} static gboolean get_position (GstValidateScenario * scenario) @@ -303,7 +476,9 @@ get_position (GstValidateScenario * scenario) return TRUE; func = g_hash_table_lookup (action_types_table, act->type); - func (scenario, act); + if (!func (scenario, act)) + GST_WARNING_OBJECT (scenario, "Could not execute %" GST_PTR_FORMAT, + act->structure); tmp = priv->actions; priv->actions = g_list_remove_link (priv->actions, tmp); @@ -671,4 +846,5 @@ init_scenarios (void) gst_validate_add_action_type ("pause",_execute_pause); gst_validate_add_action_type ("play",_execute_play); gst_validate_add_action_type ("eos",_execute_eos); + gst_validate_add_action_type ("switch-track", _execute_switch_track); }