validate: scenario: Add an action type to forward stream from an appsink to an appsrc

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5803>
This commit is contained in:
Thibault Saunier 2023-12-12 08:58:05 -03:00 committed by GStreamer Marge Bot
parent fd4cd3d85f
commit aad06b091e
5 changed files with 190 additions and 2 deletions

View file

@ -59,6 +59,7 @@
#include "gst-validate-internal.h" #include "gst-validate-internal.h"
#include "validate.h" #include "validate.h"
#include <gst/controller/controller.h> #include <gst/controller/controller.h>
#include <gst/app/app.h>
#include <gst/validate/gst-validate-override.h> #include <gst/validate/gst-validate-override.h>
#include <gst/validate/gst-validate-override-registry.h> #include <gst/validate/gst-validate-override-registry.h>
#include <gst/validate/gst-validate-pipeline-monitor.h> #include <gst/validate/gst-validate-pipeline-monitor.h>
@ -7043,7 +7044,8 @@ subscenario_done_cb (GstBus * bus, GstMessage * message, gpointer data)
} }
static GstValidateExecuteActionReturn 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; const gchar *pipeline_desc = NULL, *scenario_name = NULL, *name = NULL;
GError *error = NULL; GError *error = NULL;
@ -7116,6 +7118,102 @@ done:
return res; 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: * gst_validate_action_get_scenario:
@ -8193,6 +8291,26 @@ register_action_types (void)
"queues a eos event in an appsrc.", "queues a eos event in an appsrc.",
GST_VALIDATE_ACTION_TYPE_NONE); 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, REGISTER_ACTION_TYPE ("flush", _execute_flush,
((GstValidateActionParameter []) ((GstValidateActionParameter [])
{ {

View file

@ -56,7 +56,7 @@ gst_validate_enums = gnome.mkenums('gstvalidateenumtypes',
install_header : true, install_header : true,
install_dir : join_paths(get_option('includedir'), 'gstreamer-1.0/gst/validate')) 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] gio_dep, gmodule_dep, gst_pbutils_dep, mathlib, json_dep]
gstvalidate = library('gstvalidate-@0@'.format(apiversion), gstvalidate = library('gstvalidate-@0@'.format(apiversion),
sources: gstvalidate_sources + gst_validate_enums + runner_file, sources: gstvalidate_sources + gst_validate_enums + runner_file,

View file

@ -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

View file

@ -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)

View file

@ -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)