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 b2cca73b1a..9fc52fdcda 100644 --- a/subprojects/gst-devtools/validate/gst/validate/gst-validate-scenario.c +++ b/subprojects/gst-devtools/validate/gst/validate/gst-validate-scenario.c @@ -59,6 +59,7 @@ #include "gst-validate-internal.h" #include "validate.h" #include +#include #include #include #include @@ -7043,7 +7044,8 @@ subscenario_done_cb (GstBus * bus, GstMessage * message, gpointer data) } static GstValidateExecuteActionReturn -_create_sub_pipeline (GstValidateScenario * scenario, GstValidateAction * action) +_create_sub_pipeline (GstValidateScenario * scenario, + GstValidateAction * action) { const gchar *pipeline_desc = NULL, *scenario_name = NULL, *name = NULL; GError *error = NULL; @@ -7116,6 +7118,102 @@ done: return res; } +static GstFlowReturn +forward_appsink_to_appsrc_new_sample (GstAppSink * appsink, gpointer user_data) +{ + GstAppSrc *appsrc = GST_APP_SRC (user_data); + + GstSample *sample = gst_app_sink_pull_sample (appsink); + if (!sample) { + return GST_FLOW_ERROR; + } + + GstFlowReturn ret = gst_app_src_push_sample (appsrc, sample); + gst_sample_unref (sample); + + return ret; +} + +static void +forward_appsink_to_appsrc_eos (GstAppSink * appsink, gpointer user_data) +{ + GstAppSrc *appsrc = GST_APP_SRC (user_data); + + gst_app_src_end_of_stream (GST_APP_SRC (appsrc)); +} + +static GstValidateExecuteActionReturn +_execute_forward_appsink_to_appsrc (GstValidateScenario * scenario, + GstValidateAction * action) +{ + GstElement *sink = NULL, *src = NULL; + GstElement *sink_pipeline = NULL, *src_pipeline = NULL; + gchar **src_pipeline_element = NULL, **sink_pipeline_element = NULL; + GstValidateExecuteActionReturn res = GST_VALIDATE_EXECUTE_ACTION_OK; + + const gchar *sink_name = gst_structure_get_string (action->structure, "sink"); + const gchar *src_name = gst_structure_get_string (action->structure, "src"); + + sink_pipeline_element = g_strsplit (sink_name, "/", 2); + if (sink_pipeline_element[1]) { + sink_pipeline = + gst_validate_scenario_get_sub_pipeline (scenario, + sink_pipeline_element[0]); + + REPORT_UNLESS (sink_pipeline, done, "Could not find subpipeline `%s`", + sink_pipeline_element[0]); + } else { + sink_pipeline = gst_validate_scenario_get_pipeline (scenario); + } + + src_pipeline_element = g_strsplit (src_name, "/", 2); + if (src_pipeline_element[1]) { + src_pipeline = + gst_validate_scenario_get_sub_pipeline (scenario, + src_pipeline_element[0]); + + REPORT_UNLESS (sink_pipeline, done, "Could not find subpipeline `%s`", + src_pipeline_element[0]); + } else { + src_pipeline = gst_validate_scenario_get_pipeline (scenario); + } + + REPORT_UNLESS (((sink = + gst_bin_get_by_name (GST_BIN (sink_pipeline), + sink_pipeline_element[1] ? sink_pipeline_element[1] : + sink_name)) + && GST_IS_APP_SINK (sink)), done, + "Could not find appsink '%s' (%" GST_PTR_FORMAT ") in %" GST_PTR_FORMAT, + sink_name, sink, sink_pipeline); + REPORT_UNLESS (((src = + gst_bin_get_by_name (GST_BIN (src_pipeline), + src_pipeline_element[1] ? src_pipeline_element[1] : src_name)) + && GST_IS_APP_SRC (src)), done, + "Could not find appsrc '%s' (%" GST_PTR_FORMAT ") in %" GST_PTR_FORMAT, + src_name, src, src_pipeline); + + GstAppSinkCallbacks callbacks = { + .eos = forward_appsink_to_appsrc_eos, + .new_preroll = NULL, + .new_sample = forward_appsink_to_appsrc_new_sample + }; + + gst_app_sink_set_callbacks (GST_APP_SINK (sink), &callbacks, + gst_object_ref (src), gst_object_unref); + +done: + if (src_pipeline_element) + g_strfreev (src_pipeline_element); + if (sink_pipeline_element) + g_strfreev (sink_pipeline_element); + gst_clear_object (&src_pipeline); + gst_clear_object (&sink_pipeline); + gst_clear_object (&src); + gst_clear_object (&sink); + + return res; +} + /** * gst_validate_action_get_scenario: @@ -8193,6 +8291,26 @@ register_action_types (void) "queues a eos event in an appsrc.", GST_VALIDATE_ACTION_TYPE_NONE); + REGISTER_ACTION_TYPE ("appsink-forward-to-appsrc", _execute_forward_appsink_to_appsrc, + ((GstValidateActionParameter []) + { + { + .name = "sink", + .description = "the name of the appsink to forward samples/events from", + .mandatory = TRUE, + .types = "string" + }, + { + .name = "src", + .description = "the name of the appsrc to forward samples/events to", + .mandatory = TRUE, + .types = "string" + }, + {NULL} + }), + "queues a eos event in an appsrc.", + GST_VALIDATE_ACTION_TYPE_NONE); + REGISTER_ACTION_TYPE ("flush", _execute_flush, ((GstValidateActionParameter []) { diff --git a/subprojects/gst-devtools/validate/gst/validate/meson.build b/subprojects/gst-devtools/validate/gst/validate/meson.build index 4ddc1d96c9..45347444e1 100644 --- a/subprojects/gst-devtools/validate/gst/validate/meson.build +++ b/subprojects/gst-devtools/validate/gst/validate/meson.build @@ -56,7 +56,7 @@ gst_validate_enums = gnome.mkenums('gstvalidateenumtypes', install_header : true, install_dir : join_paths(get_option('includedir'), 'gstreamer-1.0/gst/validate')) -validate_deps = [gst_check_dep, gst_dep, gst_controller_dep, gstbase_dep, +validate_deps = [gst_check_dep, gst_dep, gst_controller_dep, gstbase_dep, gstapp_dep, gio_dep, gmodule_dep, gst_pbutils_dep, mathlib, json_dep] gstvalidate = library('gstvalidate-@0@'.format(apiversion), sources: gstvalidate_sources + gst_validate_enums + runner_file, diff --git a/subprojects/gst-devtools/validate/tests/launcher_tests/appsink_forward.validatetest b/subprojects/gst-devtools/validate/tests/launcher_tests/appsink_forward.validatetest new file mode 100644 index 0000000000..ac939446eb --- /dev/null +++ b/subprojects/gst-devtools/validate/tests/launcher_tests/appsink_forward.validatetest @@ -0,0 +1,53 @@ +set-globals, + appsrc_props="handle-segment-change=true \ + automatic-eos=false \ + min-latency=0 \ + max-latency=-1 \ + format=time \ + is-live=true \ + max-buffers=0 \ + max-bytes=0 \ + max-time=5000000000 \ + leaky-type=downstream" + +meta, + args = { + "appsrc name=src $(appsrc_props) ! videoconvert ! $(videosink) name=sink", + }, + configs = { + "$(validateflow), pad=source-sink:sink, buffers-checksum=as-id, ignored-event-types={ tag, stream-start }", + "$(validateflow), pad=selector-sink:sink, buffers-checksum=as-id, ignored-event-types={ tag, stream-start }", + }, + handles-states=true, + ignore-eos=true + +# Source pipeline +create-sub-pipeline, + name=source, + desc="videotestsrc num-buffers=5 name=src ! video/x-raw,framerate=30/1,format=I420,width=320,height=240 ! timeoverlay ! appsink name=source-sink sync=true max-buffers=10 drop=true", + scenario={ + [meta], + } + +# "selector" pipeline +create-sub-pipeline, + name=selector, + desc="appsrc name=selector-src1 $(appsrc_props) ! input-selector ! appsink name=selector-sink sync=true max-buffers=10 drop=true", + scenario={ + [meta], + } + +appsink-forward-to-appsrc, + sink=source/source-sink, + src=selector/selector-src1 + +appsink-forward-to-appsrc, + sink=selector/selector-sink, + src=src + +play + +wait, subpipeline-done=source +wait, subpipeline-done=selector + +stop diff --git a/subprojects/gst-devtools/validate/tests/launcher_tests/appsink_forward/flow-expectations/log-selector-sink-sink-expected b/subprojects/gst-devtools/validate/tests/launcher_tests/appsink_forward/flow-expectations/log-selector-sink-sink-expected new file mode 100644 index 0000000000..c190facbe9 --- /dev/null +++ b/subprojects/gst-devtools/validate/tests/launcher_tests/appsink_forward/flow-expectations/log-selector-sink-sink-expected @@ -0,0 +1,8 @@ +event caps: video/x-raw, format=(string)I420, framerate=(fraction)30/1, height=(int)240, interlace-mode=(string)progressive, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, width=(int)320; +event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000 +buffer: content-id=0, pts=0:00:00.000000000, dur=0:00:00.033333333, flags=discont +buffer: content-id=1, pts=0:00:00.033333333, dur=0:00:00.033333333 +buffer: content-id=2, pts=0:00:00.066666666, dur=0:00:00.033333334 +buffer: content-id=3, pts=0:00:00.100000000, dur=0:00:00.033333333 +buffer: content-id=4, pts=0:00:00.133333333, dur=0:00:00.033333333 +event eos: (no structure) diff --git a/subprojects/gst-devtools/validate/tests/launcher_tests/appsink_forward/flow-expectations/log-source-sink-sink-expected b/subprojects/gst-devtools/validate/tests/launcher_tests/appsink_forward/flow-expectations/log-source-sink-sink-expected new file mode 100644 index 0000000000..1252e00452 --- /dev/null +++ b/subprojects/gst-devtools/validate/tests/launcher_tests/appsink_forward/flow-expectations/log-source-sink-sink-expected @@ -0,0 +1,9 @@ +event caps: video/x-raw(memory:SystemMemory, meta:GstVideoOverlayComposition), format=(string)I420, framerate=(fraction)30/1, height=(int)240, interlace-mode=(string)progressive, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, width=(int)320; +event caps: video/x-raw, format=(string)I420, framerate=(fraction)30/1, height=(int)240, interlace-mode=(string)progressive, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, width=(int)320; +event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000 +buffer: content-id=0, pts=0:00:00.000000000, dur=0:00:00.033333333, flags=discont +buffer: content-id=1, pts=0:00:00.033333333, dur=0:00:00.033333333 +buffer: content-id=2, pts=0:00:00.066666666, dur=0:00:00.033333334 +buffer: content-id=3, pts=0:00:00.100000000, dur=0:00:00.033333333 +buffer: content-id=4, pts=0:00:00.133333333, dur=0:00:00.033333333 +event eos: (no structure)