diff --git a/subprojects/gst-devtools/validate/gst/validate/doc/meta-features-rank.md b/subprojects/gst-devtools/validate/gst/validate/doc/meta-features-rank.md
new file mode 100644
index 0000000000..e1f24a9783
--- /dev/null
+++ b/subprojects/gst-devtools/validate/gst/validate/doc/meta-features-rank.md
@@ -0,0 +1,16 @@
+The `features-rank` field is an array of structures that defines how to
+override `GstPluginFeature::rank` to ensure some features will be used,
+or at contrary won't be used.
+
+For example:
+
+``` yaml
+features-rank = {
+ [mandatory, glvideomixer=9999],
+ [optional, someoptionalfeature=0],
+},
+```
+
+One could also use the `set-feature-rank` scenario action, but that
+happens after GStreamer or other components are initialized which might
+be a problem in some cases.
diff --git a/subprojects/gst-devtools/validate/gst/validate/gst-validate-internal.h b/subprojects/gst-devtools/validate/gst/validate/gst-validate-internal.h
index c6134709c2..7fede688ae 100644
--- a/subprojects/gst-devtools/validate/gst/validate/gst-validate-internal.h
+++ b/subprojects/gst-devtools/validate/gst/validate/gst-validate-internal.h
@@ -64,6 +64,7 @@ G_GNUC_INTERNAL void gst_validate_deinit_runner (void);
G_GNUC_INTERNAL void gst_validate_report_deinit (void);
G_GNUC_INTERNAL gboolean gst_validate_send (JsonNode * root);
G_GNUC_INTERNAL void gst_validate_set_test_file_globals (GstStructure* meta, const gchar* testfile, gboolean use_fakesinks);
+G_GNUC_INTERNAL gboolean gst_validate_structure_file_field_is_metadata (const GstIdStr *field_id);
G_GNUC_INTERNAL gboolean gst_validate_get_test_file_scenario (GList** structs, const gchar** scenario_name, gchar** original_name);
G_GNUC_INTERNAL GstValidateScenario* gst_validate_scenario_from_structs (GstValidateRunner* runner, GstElement* pipeline, GList* structures,
const gchar* origin_file);
diff --git a/subprojects/gst-devtools/validate/gst/validate/gst-validate-scenario.c b/subprojects/gst-devtools/validate/gst/validate/gst-validate-scenario.c
index 0827168057..2c937f730f 100644
--- a/subprojects/gst-devtools/validate/gst/validate/gst-validate-scenario.c
+++ b/subprojects/gst-devtools/validate/gst/validate/gst-validate-scenario.c
@@ -7698,6 +7698,9 @@ register_action_types (void)
GBytes *meta_expected_issues_doc =
g_resource_lookup_data (resource, "/validate/doc/meta-expected-issues.md",
G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
+ GBytes *meta_features_rank_doc =
+ g_resource_lookup_data (resource, "/validate/doc/meta-features-rank.md",
+ G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
/* *INDENT-OFF* */
REGISTER_ACTION_TYPE ("meta", NULL,
@@ -7874,12 +7877,31 @@ register_action_types (void)
.possible_variables = NULL,
.def = "{}"
},
+ {
+ .name="features-rank",
+ .description=g_bytes_get_data (meta_features_rank_doc, NULL),
+ .mandatory = FALSE,
+ .types = "bool",
+ .possible_variables = NULL,
+ .def = "false"
+ },
+ {
+ .name="monitor-all-pipelines",
+ .description="This should only be used in `.validatetest` files, and allows forcing to monitor "
+ "all pipelines instead of only the one the tools wanted to monitor, for example to "
+ "use `validateflow` on auxilary pipelines",
+ .mandatory = FALSE,
+ .types = "bool",
+ .possible_variables = NULL,
+ .def = "false"
+ },
{NULL}
}),
"Scenario metadata.\n\nNOTE: it used to be called \"description\"",
GST_VALIDATE_ACTION_TYPE_CONFIG);
g_bytes_unref (meta_config_doc);
g_bytes_unref (meta_expected_issues_doc);
+ g_bytes_unref (meta_features_rank_doc);
REGISTER_ACTION_TYPE ("seek", _execute_seek,
((GstValidateActionParameter []) {
diff --git a/subprojects/gst-devtools/validate/gst/validate/gst-validate-utils.c b/subprojects/gst-devtools/validate/gst/validate/gst-validate-utils.c
index 72886b380a..39ae8063e0 100644
--- a/subprojects/gst-devtools/validate/gst/validate/gst-validate-utils.c
+++ b/subprojects/gst-devtools/validate/gst/validate/gst-validate-utils.c
@@ -1352,9 +1352,8 @@ done:
g_clear_pointer (&match_info, g_match_info_free);
}
-static gboolean
-_structure_set_variables (const GstIdStr * fieldname, GValue * value,
- ReplaceData * data)
+gboolean
+gst_validate_structure_file_field_is_metadata (const GstIdStr * fieldname)
{
static const gchar *skip_fields[] = {
"__filename__",
@@ -1363,7 +1362,15 @@ _structure_set_variables (const GstIdStr * fieldname, GValue * value,
NULL,
};
- if (fieldname && g_strv_contains (skip_fields, gst_id_str_as_str (fieldname)))
+ return fieldname
+ && g_strv_contains (skip_fields, gst_id_str_as_str (fieldname));
+}
+
+static gboolean
+_structure_set_variables (const GstIdStr * fieldname, GValue * value,
+ ReplaceData * data)
+{
+ if (gst_validate_structure_file_field_is_metadata (fieldname))
return TRUE;
if (GST_VALUE_HOLDS_LIST (value)) {
diff --git a/subprojects/gst-devtools/validate/gst/validate/gst-validate-utils.h b/subprojects/gst-devtools/validate/gst/validate/gst-validate-utils.h
index 3ae12ba317..91d3e7879c 100644
--- a/subprojects/gst-devtools/validate/gst/validate/gst-validate-utils.h
+++ b/subprojects/gst-devtools/validate/gst/validate/gst-validate-utils.h
@@ -93,6 +93,7 @@ GST_VALIDATE_API
void gst_validate_structure_resolve_variables (gpointer source, GstStructure *structure, GstStructure *local_variables,
GstValidateStructureResolveVariablesFlags flags);
void gst_validate_structure_set_variables_from_struct_file(GstStructure* vars, const gchar* struct_file);
+GST_VALIDATE_API
void gst_validate_set_globals(GstStructure* structure);
GST_VALIDATE_API
gboolean gst_validate_fail_on_missing_plugin(void);
diff --git a/subprojects/gst-devtools/validate/gst/validate/validate.c b/subprojects/gst-devtools/validate/gst/validate/validate.c
index ce9d36ffba..d142ea5b83 100644
--- a/subprojects/gst-devtools/validate/gst/validate/validate.c
+++ b/subprojects/gst-devtools/validate/gst/validate/validate.c
@@ -26,6 +26,7 @@
* @short_description: Initialize GstValidate
*/
+#include "gst/gstidstr.h"
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif /* HAVE_CONFIG_H */
@@ -265,16 +266,23 @@ get_structures_from_array_in_meta (const gchar * fieldname)
if (!meta)
return NULL;
- res = get_structures_from_array (meta, fieldname);
- if (res)
- return res;
-
gst_structure_get (meta,
"__lineno__", G_TYPE_INT, ¤t_lineno,
"__debug__", G_TYPE_STRING, &debug,
"__filename__", G_TYPE_STRING, &filename, NULL);
- strs = gst_validate_utils_get_strv (meta, fieldname);
+ res = get_structures_from_array (meta, fieldname);
+ if (res) {
+ for (GList * tmp = res; tmp; tmp = tmp->next) {
+ gst_structure_set (tmp->data,
+ "__lineno__", G_TYPE_INT, current_lineno,
+ "__filename__", G_TYPE_STRING, filename,
+ "__debug__", G_TYPE_STRING, debug, NULL);
+ }
+ goto done;
+ }
+
+ strs = gst_validate_utils_get_strv (meta, fieldname);
if (strs) {
gint i;
@@ -294,6 +302,7 @@ get_structures_from_array_in_meta (const gchar * fieldname)
}
}
+done:
g_free (filename);
g_free (debug);
g_strfreev (strs);
@@ -612,6 +621,46 @@ validate_test_include_paths (const gchar * includer_file)
return env_configdir;
}
+static gboolean
+_set_feature_rank (const GstIdStr * fieldname, GValue * value,
+ GstStructure * structure)
+{
+ GstRegistry *registry = gst_registry_get ();
+ guint rank = 0;
+
+ if (gst_validate_structure_file_field_is_metadata (fieldname))
+ return TRUE;
+
+ if (G_VALUE_TYPE (value) == G_TYPE_UINT) {
+ rank = (guint) g_value_get_uint (value);
+ } else if (G_VALUE_TYPE (value) == G_TYPE_INT) {
+ rank = g_value_get_int (value);
+ } else {
+ gst_validate_error_structure (structure,
+ "Invalid value %s for field '%s' (expecting int) in the 'features-rank' structure",
+ G_VALUE_TYPE_NAME (value), gst_value_serialize (value));
+
+ return FALSE;
+ }
+
+ GstPluginFeature *feature =
+ gst_registry_lookup_feature (registry, gst_id_str_as_str (fieldname));
+ if (!feature) {
+ if (gst_structure_has_name (structure, "mandatory")) {
+ gst_validate_error_structure (structure,
+ "Feature `%s` not found while its ranks has been requested to be set to %d",
+ gst_id_str_as_str (fieldname), rank);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ gst_plugin_feature_set_rank (feature, rank);
+
+ return TRUE;
+}
+
/* Only the first monitor pipeline will be used */
GstStructure *
gst_validate_setup_test_file (const gchar * testfile, gboolean use_fakesinks)
@@ -653,6 +702,21 @@ gst_validate_setup_test_file (const gchar * testfile, gboolean use_fakesinks)
register_action_types ();
gst_validate_scenario_check_and_set_needs_clock_sync (testfile_structs, &res);
+ GList *feature_ranks_def =
+ get_structures_from_array_in_meta ("features-rank");
+ for (GList * tmp = feature_ranks_def; tmp; tmp = tmp->next) {
+ GstStructure *feature_ranks = tmp->data;
+ if (!gst_structure_has_name (feature_ranks, "mandatory")
+ && !gst_structure_has_name (feature_ranks, "optional")) {
+ gst_validate_error_structure (res,
+ "Feature rank structures should have either `mandatory` or `optional` as a name, got: %s",
+ gst_structure_to_string (feature_ranks));
+ return NULL;
+ }
+ gst_structure_filter_and_map_in_place_id_str (feature_ranks,
+ (GstStructureFilterMapIdStrFunc) _set_feature_rank, feature_ranks);
+ }
+
gst_validate_set_test_file_globals (res, global_testfile, use_fakesinks);
gst_validate_structure_resolve_variables (NULL, res, NULL, 0);
diff --git a/subprojects/gst-devtools/validate/gst/validate/validate.res b/subprojects/gst-devtools/validate/gst/validate/validate.res
index 1568b88d40..987c4b56f8 100644
--- a/subprojects/gst-devtools/validate/gst/validate/validate.res
+++ b/subprojects/gst-devtools/validate/gst/validate/validate.res
@@ -3,6 +3,7 @@
doc/meta-configs.md
doc/meta-expected-issues.md
+ doc/meta-features-rank.md
diff --git a/subprojects/gst-editing-services/tools/ges-launcher.c b/subprojects/gst-editing-services/tools/ges-launcher.c
index 17cb98d570..9dfa8d802e 100644
--- a/subprojects/gst-editing-services/tools/ges-launcher.c
+++ b/subprojects/gst-editing-services/tools/ges-launcher.c
@@ -33,6 +33,10 @@
#include "utils.h"
#include "ges-launcher-kb.h"
+#ifdef HAVE_GST_VALIDATE
+#include
+#endif
+
typedef enum
{
GST_PLAY_TRICK_MODE_NONE = 0,
@@ -321,6 +325,19 @@ _parse_track_type (const gchar * option_name, const gchar * value,
return TRUE;
}
+
+#ifdef HAVE_GST_VALIDATE
+static gboolean
+_parse_test_file (const gchar * option_name, const gchar * value,
+ GESLauncherParsedOptions * opts, GError ** error)
+{
+ opts->testfile = g_strdup (value);
+ gst_validate_init_debug ();
+ gst_validate_setup_test_file (opts->testfile, FALSE);
+ return TRUE;
+}
+#endif
+
static gboolean
_set_track_restriction_caps (GESTrack * track, const gchar * caps_str)
{
@@ -1037,6 +1054,8 @@ bus_message_cb (GstBus * bus, GstMessage * message, GESLauncher * self)
break;
}
case GST_MESSAGE_EOS:
+ GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (self->priv->pipeline),
+ GST_DEBUG_GRAPH_SHOW_ALL, "ges-launch.eos");
if (!self->priv->parsed_options.ignore_eos) {
ges_ok ("\nDone\n");
g_application_quit (G_APPLICATION (self));
@@ -1177,7 +1196,8 @@ _run_pipeline (GESLauncher * self)
bus = gst_pipeline_get_bus (GST_PIPELINE (self->priv->pipeline));
gst_bus_add_signal_watch (bus);
- g_signal_connect (bus, "message", G_CALLBACK (bus_message_cb), self);
+ g_signal_connect_object (bus, "message", G_CALLBACK (bus_message_cb), self,
+ 0);
g_application_hold (G_APPLICATION (self));
@@ -1433,7 +1453,7 @@ ges_launcher_parse_options (GESLauncher * self,
"Specify the track restriction caps of the audio track.",
},
#ifdef HAVE_GST_VALIDATE
- {"set-test-file", 0, 0, G_OPTION_ARG_STRING, &opts->testfile,
+ {"set-test-file", 0, 0, G_OPTION_ARG_CALLBACK, &_parse_test_file,
"ges-launch-1.0 exposes gst-validate functionalities, such as test files and scenarios."
" Scenarios describe actions to execute, such as seeks or setting of "
"properties. "
diff --git a/subprojects/gst-editing-services/tools/ges-validate.c b/subprojects/gst-editing-services/tools/ges-validate.c
index 5ea786ed01..692c9cf438 100644
--- a/subprojects/gst-editing-services/tools/ges-validate.c
+++ b/subprojects/gst-editing-services/tools/ges-validate.c
@@ -138,7 +138,14 @@ ges_validate_activate (GstPipeline * pipeline, GESLauncher * launcher,
if (opts->testfile) {
if (opts->scenario)
g_error ("Can not specify scenario and testfile at the same time");
- gst_validate_setup_test_file (opts->testfile, opts->mute);
+ if (!opts->mute) {
+ gst_validate_set_globals (gst_structure_new ("globals",
+ "videosink", G_TYPE_STRING,
+ opts->videosink ? opts->videosink : "autovideosink", "audiosink",
+ G_TYPE_STRING,
+ opts->audiosink ? opts->audiosink : "autoaudiosink", NULL)
+ );
+ }
} else if (opts->scenario) {
if (g_strcmp0 (opts->scenario, "none")) {
gchar *scenario_name =