diff --git a/docs/gst-validate-test-file.md b/docs/gst-validate-test-file.md index 4494db0882..6328aa0ab7 100644 --- a/docs/gst-validate-test-file.md +++ b/docs/gst-validate-test-file.md @@ -28,8 +28,8 @@ The `meta` format: ## Tool arguments -In the case of [`gst-validate`](gst-validate.md) it **has to** contain a -`gst-validate-args` field with `gst-validate` argv arguments like: +In the case of [`gst-validate`](gst-validate.md) it **has to** contain an +`args` field with `gst-validate` argv arguments like: ``` yaml # This is the default tool so it is not mandatory for the `gst-validate` tool @@ -49,7 +49,7 @@ usual [config](gst-validate-config.md) files contain. For example: -``` json +``` yaml configs = { # Set videotestsrc0 pattern value to `blue` "core, action=set-property, target-element-name=videotestsrc0, property-name=pattern, property-value=blue", diff --git a/meson.build b/meson.build index 199cb72fe1..842d296cab 100644 --- a/meson.build +++ b/meson.build @@ -67,11 +67,9 @@ gst_pbutils_dep = dependency('gstreamer-pbutils-' + apiversion, version : gst_re fallback : ['gst-plugins-base', 'pbutils_dep']) gst_video_dep = dependency('gstreamer-video-' + apiversion, version : gst_req, fallback : ['gst-plugins-base', 'video_dep']) -if host_machine.system() != 'windows' - gst_check_dep = dependency('gstreamer-check-1.0', version : gst_req, - required : get_option('tests'), - fallback : ['gstreamer', 'gst_check_dep']) -endif +gst_check_dep = dependency('gstreamer-check-1.0', version : gst_req, + required : get_option('validate'), + fallback : ['gstreamer', 'gst_check_dep']) glib_dep = dependency('glib-2.0', version : '>=2.32.0', fallback: ['glib', 'libglib_dep']) @@ -146,7 +144,7 @@ i18n = import('i18n') python_mod = import('python') python3 = python_mod.find_installation() -if get_option('validate') +if not get_option('validate').disabled() subdir('validate') endif diff --git a/meson_options.txt b/meson_options.txt index 10a14190dc..6d06623544 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,4 +1,4 @@ -option('validate', type : 'boolean', value : true, +option('validate', type : 'feature', value : 'auto', description : 'Build GstValidate') option('debug_viewer', type : 'boolean', value : true, description : 'Build GstDebugViewer') diff --git a/validate/gst/validate/gst-validate-scenario.c b/validate/gst/validate/gst-validate-scenario.c index b2a5ce8cee..e095ff3e65 100644 --- a/validate/gst/validate/gst-validate-scenario.c +++ b/validate/gst/validate/gst-validate-scenario.c @@ -47,6 +47,7 @@ #include #include +#include #include "gst-validate-internal.h" #include "gst-validate-scenario.h" #include "gst-validate-reporter.h" @@ -178,6 +179,8 @@ struct _GstValidateScenarioPrivate GstStructure *vars; GWeakRef ref_pipeline; + + GstTestClock *clock; }; typedef struct KeyFileGroupName @@ -610,6 +613,10 @@ gboolean gst_validate_action_get_clocktime (GstValidateScenario * scenario, GstValidateAction * action, const gchar * name, GstClockTime * retval) { + + if (!gst_structure_has_field (action->structure, name)) + return FALSE; + if (!gst_validate_utils_get_clocktime (action->structure, name, retval)) { gdouble val; gchar *error = NULL, *strval; @@ -1710,12 +1717,12 @@ static gboolean _should_execute_action (GstValidateScenario * scenario, GstValidateAction * act, GstClockTime position, gdouble rate) { - GstElement *pipeline; + GstElement *pipeline = NULL; if (!act) { GST_DEBUG_OBJECT (scenario, "No action to execute"); - return FALSE; + goto no; } pipeline = gst_validate_scenario_get_pipeline (scenario); @@ -1776,7 +1783,7 @@ yes: return TRUE; no: - gst_object_unref (pipeline); + gst_clear_object (&pipeline); return FALSE; } @@ -3512,6 +3519,9 @@ gst_validate_scenario_load_structures (GstValidateScenario * scenario, goto failed; } + if (!g_strcmp0 (type, "crank-clock") && !priv->clock) + priv->clock = GST_TEST_CLOCK (gst_test_clock_new ()); + if (action_type->parameters) { guint i; @@ -3833,6 +3843,7 @@ gst_validate_scenario_init (GstValidateScenario * scenario) g_weak_ref_init (&scenario->priv->ref_pipeline, NULL); priv->max_latency = GST_CLOCK_TIME_NONE; priv->max_dropped = -1; + priv->clock = NULL; g_mutex_init (&priv->lock); } @@ -3852,6 +3863,8 @@ gst_validate_scenario_dispose (GObject * object) priv->bus = NULL; } + gst_object_replace ((GstObject **) & priv->clock, NULL); + G_OBJECT_CLASS (gst_validate_scenario_parent_class)->dispose (object); } @@ -4013,6 +4026,11 @@ gst_validate_scenario_new (GstValidateRunner * GST_OBJECT_NAME (pipeline)); g_weak_ref_init (&scenario->priv->ref_pipeline, pipeline); + if (scenario->priv->clock) { + gst_element_set_clock (pipeline, GST_CLOCK_CAST (scenario->priv->clock)); + gst_pipeline_use_clock (GST_PIPELINE (pipeline), + GST_CLOCK_CAST (scenario->priv->clock)); + } gst_validate_reporter_set_name (GST_VALIDATE_REPORTER (scenario), g_strdup (scenario_name)); @@ -4637,6 +4655,56 @@ done: return GST_PAD_PROBE_OK; } +static GstValidateExecuteActionReturn +_execute_crank_clock (GstValidateScenario * scenario, + GstValidateAction * action) +{ + GstClockTime expected_diff, expected_time; + GstClockTime prev_time = + gst_clock_get_time (GST_CLOCK (scenario->priv->clock)); + + if (!gst_test_clock_crank (scenario->priv->clock)) { + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, "Cranking clock failed"); + + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + + if (gst_validate_action_get_clocktime (scenario, action, + "expected-elapsed-time", &expected_diff)) { + GstClockTime elapsed = + gst_clock_get_time (GST_CLOCK (scenario->priv->clock)) - prev_time; + + if (expected_diff != elapsed) { + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, + "Elapsed time during test clock cranking different than expected," + " waited for %" GST_TIME_FORMAT " instead of the expected %" + GST_TIME_FORMAT, GST_TIME_ARGS (elapsed), + GST_TIME_ARGS (expected_diff)); + + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + } + + if (gst_validate_action_get_clocktime (scenario, action, "expected-time", + &expected_time)) { + GstClockTime time = gst_clock_get_time (GST_CLOCK (scenario->priv->clock)); + + if (expected_time != time) { + GST_VALIDATE_REPORT_ACTION (scenario, action, + SCENARIO_ACTION_EXECUTION_ERROR, + "Clock time after cranking different than expected," + " got %" GST_TIME_FORMAT " instead of the expected %" GST_TIME_FORMAT, + GST_TIME_ARGS (time), GST_TIME_ARGS (expected_time)); + + return GST_VALIDATE_EXECUTE_ACTION_ERROR_REPORTED; + } + } + + return GST_VALIDATE_EXECUTE_ACTION_OK; +} + static gboolean _execute_request_key_unit (GstValidateScenario * scenario, GstValidateAction * action) @@ -5242,7 +5310,7 @@ register_action_types (void) .mandatory = FALSE, .types = "boolean", .possible_variables = NULL, - .def = "false" + .def = "true if some action requires a playback-time false otherwise" }, { .name = "min-media-duration", @@ -5820,6 +5888,29 @@ register_action_types (void) " for example", GST_VALIDATE_ACTION_TYPE_INTERLACED); + REGISTER_ACTION_TYPE ("crank-clock", _execute_crank_clock, + ((GstValidateActionParameter []) { + { + .name = "expected-time", + .description = "Expected clock time after cranking", + .mandatory = FALSE, + .types = "GstClockTime", + NULL + }, + { + .name = "expected-elapsed-time", + .description = "Check time elapsed during the clock cranking", + .mandatory = FALSE, + .types = "GstClockTime", + NULL + }, + }), "Crank the clock, possibly checking how much time was supposed to be waited on the clock" + " and/or the clock running time after the crank." + " Using one `crank-clock` action in a scenario implies that the scenario is driving the " + " clock and a #GstTestClock will be used. The user will need to crank it the number of " + " time required (using the `repeat` parameter comes handy here).", + GST_VALIDATE_ACTION_TYPE_NEEDS_CLOCK); + REGISTER_ACTION_TYPE ("video-request-key-unit", _execute_request_key_unit, ((GstValidateActionParameter []) { { diff --git a/validate/gst/validate/meson.build b/validate/gst/validate/meson.build index 107ea7d0fc..090ec78565 100644 --- a/validate/gst/validate/meson.build +++ b/validate/gst/validate/meson.build @@ -61,7 +61,7 @@ gstvalidate = library('gstvalidate-1.0', include_directories : [inc_dirs], install: true, c_args : [gst_c_args] + ['-D_GNU_SOURCE'], - dependencies : [gst_dep, gstbase_dep, glib_dep, gio_dep, + dependencies : [gst_check_dep, gst_dep, gstbase_dep, glib_dep, gio_dep, gmodule_dep, gst_pbutils_dep, mathlib, json_dep]) gstvalidatetracer = library('gstvalidatetracer', @@ -70,7 +70,7 @@ gstvalidatetracer = library('gstvalidatetracer', install: true, c_args : [gst_c_args] + ['-D__GST_VALIDATE_PLUGIN', '-D_GNU_SOURCE'], install_dir : plugins_install_dir, - dependencies : [gst_dep, gstbase_dep, glib_dep, gio_dep, gmodule_dep, + dependencies : [gst_check_dep, gst_dep, gstbase_dep, glib_dep, gio_dep, gmodule_dep, gst_pbutils_dep, mathlib, json_dep]) validate_gen_sources = [] @@ -90,7 +90,7 @@ if build_gir 'Gst-' + apiversion, 'GstPbutils-' + apiversion], install : true, - dependencies : [gst_dep, gstbase_dep, glib_dep, gio_dep, gst_pbutils_dep], + dependencies : [gst_dep, gstbase_dep, glib_dep, gio_dep, gst_pbutils_dep, gst_check_dep], extra_args : gst_validate_gir_extra_args, ) validate_gen_sources += [validate_gir]