Commit befa41cd authored by Nirbheek Chauhan's avatar Nirbheek Chauhan 🐜 Committed by Sebastian Dröge

rtspsrc: Implement ONVIF backchannel support

Set backchannel=onvif to enable, and use the 'push-backchannel-sample'
action signal with the correct stream id.
parent d61066e6
......@@ -1294,6 +1294,7 @@ tests/examples/gtk/Makefile
This diff is collapsed.
......@@ -123,8 +123,8 @@ struct _GstRTSPStream {
GstElement *udpsink[2];
GstPad *rtcppad;
/* fakesrc for sending dummy data */
GstElement *fakesrc;
/* fakesrc for sending dummy data or appsrc for sending backchannel data */
GstElement *rtpsrc;
/* state */
guint port;
......@@ -161,6 +161,7 @@ struct _GstRTSPStream {
gchar *destination;
gboolean is_multicast;
guint ttl;
gboolean is_backchannel;
/* A unique and stable id we will use for the stream start event */
gchar *stream_id;
......@@ -254,6 +255,7 @@ struct _GstRTSPSrc {
guint64 max_ts_offset_adjustment;
gint64 max_ts_offset;
gboolean max_ts_offset_is_set;
gint backchannel;
/* state */
GstRTSPState state;
......@@ -298,6 +300,8 @@ struct _GstRTSPSrc {
struct _GstRTSPSrcClass {
GstBinClass parent_class;
GstFlowReturn (*push_backchannel_buffer) (GstRTSPSrc *src, guint id, GstSample *sample);
GType gst_rtspsrc_get_type(void);
......@@ -17,9 +17,9 @@ CAIRO_DIR=
SUBDIRS = audiofx equalizer $(GTK_DIR) $(JACK_DIR) level \
rtp shapewipe spectrum v4l2 $(CAIRO_DIR)
rtp rtsp shapewipe spectrum v4l2 $(CAIRO_DIR)
DIST_SUBDIRS = audiofx equalizer gtk jack level \
rtp shapewipe spectrum v4l2 cairo
rtp rtsp shapewipe spectrum v4l2 cairo
include $(top_srcdir)/common/parallel-subdirs.mak
......@@ -4,6 +4,7 @@ subdir('cairo')
#FIXME: subdir('qt')
noinst_PROGRAMS = test-onvif
test_onvif_CFLAGS = $(GST_CFLAGS)
test_onvif_LDADD = $(GST_LIBS)
executable('onvif-test', 'onvif-test.c',
dependencies: [gst_dep],
c_args : gst_plugins_good_args,
include_directories : [configinc],
install: false)
#include <gst/gst.h>
static GMainLoop *loop = NULL;
static GstElement *backpipe = NULL;
static gint stream_id = -1;
#define PCMU_CAPS "application/x-rtp, media=audio, payload=0, clock-rate=8000, encoding-name=PCMU"
static GstFlowReturn
new_sample (GstElement * appsink, GstElement * rtspsrc)
GstSample *sample;
GstFlowReturn ret = GST_FLOW_OK;
g_assert (stream_id != -1);
g_signal_emit_by_name (appsink, "pull-sample", &sample);
if (!sample)
goto out;
g_signal_emit_by_name (rtspsrc, "push-backchannel-buffer", stream_id, sample,
return ret;
static void
setup_backchannel_shoveler (GstElement * rtspsrc, GstCaps * caps)
GstElement *appsink;
backpipe = gst_parse_launch ("audiotestsrc is-live=true wave=red-noise ! "
"mulawenc ! rtppcmupay ! appsink name=out", NULL);
if (!backpipe)
g_error ("Could not setup backchannel pipeline");
appsink = gst_bin_get_by_name (GST_BIN (backpipe), "out");
g_object_set (G_OBJECT (appsink), "caps", caps, "emit-signals", TRUE, NULL);
g_signal_connect (appsink, "new-sample", G_CALLBACK (new_sample), rtspsrc);
g_print ("Playing backchannel shoveler\n");
gst_element_set_state (backpipe, GST_STATE_PLAYING);
static gboolean
remove_extra_fields (GQuark field_id, GValue * value G_GNUC_UNUSED,
gpointer user_data G_GNUC_UNUSED)
return !g_str_has_prefix (g_quark_to_string (field_id), "a-");
static gboolean
find_backchannel (GstElement * rtspsrc, guint idx, GstCaps * caps,
gpointer user_data G_GNUC_UNUSED)
GstStructure *s;
gchar *caps_str = gst_caps_to_string (caps);
g_print ("Selecting stream idx %u, caps %s\n", idx, caps_str);
g_free (caps_str);
s = gst_caps_get_structure (caps, 0);
if (gst_structure_has_field (s, "a-recvonly")) {
stream_id = idx;
caps = gst_caps_new_empty ();
s = gst_structure_copy (s);
gst_structure_set_name (s, "application/x-rtp");
gst_structure_filter_and_map_in_place (s, remove_extra_fields, NULL);
gst_caps_append_structure (caps, s);
setup_backchannel_shoveler (rtspsrc, caps);
return TRUE;
main (int argc, char *argv[])
GstElement *pipeline, *rtspsrc;
const gchar *location;
gst_init (&argc, &argv);
if (argc >= 2)
location = argv[1];
location = "rtsp://";
loop = g_main_loop_new (NULL, FALSE);
pipeline = gst_parse_launch ("rtspsrc backchannel=onvif debug=true name=r "
"r. ! queue ! decodebin ! queue ! xvimagesink async=false "
"r. ! queue ! decodebin ! queue ! pulsesink async=false ", NULL);
if (!pipeline)
g_error ("Failed to parse pipeline");
rtspsrc = gst_bin_get_by_name (GST_BIN (pipeline), "r");
g_object_set (G_OBJECT (rtspsrc), "location", location, NULL);
g_signal_connect (rtspsrc, "select-stream", G_CALLBACK (find_backchannel),
gst_element_set_state (pipeline, GST_STATE_PLAYING);
g_main_loop_run (loop);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment