summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Dröge <sebastian@centricular.com>2017-09-25 19:41:05 +0300
committerSebastian Dröge <sebastian@centricular.com>2018-02-09 11:08:26 +0200
commit2f7820ace68903aa8ecf175d3e8ed6b2f4e248fc (patch)
treea3119b6175809a69b1b2e61dd9a1539ed7798fab
parent0a8a00396628dd43714ffe495192d748d8f7f402 (diff)
rtsp: Add support for ONVIF backchannel
This adds a new RTSP server, client, media-factory and media subclass for handling the specifics of the backchannel. Ideally this later can be extended with other ONVIF specific features.
-rw-r--r--docs/libs/gst-rtsp-server-docs.sgml4
-rw-r--r--docs/libs/gst-rtsp-server-sections.txt107
-rw-r--r--examples/.gitignore1
-rw-r--r--examples/Makefile.am10
-rw-r--r--examples/test-onvif-backchannel.c71
-rw-r--r--gst/rtsp-server/Makefile.am12
-rw-r--r--gst/rtsp-server/rtsp-media.h1
-rw-r--r--gst/rtsp-server/rtsp-onvif-client.c100
-rw-r--r--gst/rtsp-server/rtsp-onvif-client.h57
-rw-r--r--gst/rtsp-server/rtsp-onvif-media-factory.c491
-rw-r--r--gst/rtsp-server/rtsp-onvif-media-factory.h77
-rw-r--r--gst/rtsp-server/rtsp-onvif-media.c330
-rw-r--r--gst/rtsp-server/rtsp-onvif-media.h66
-rw-r--r--gst/rtsp-server/rtsp-onvif-server.c100
-rw-r--r--gst/rtsp-server/rtsp-onvif-server.h65
-rw-r--r--gst/rtsp-server/rtsp-sdp.c8
-rw-r--r--gst/rtsp-server/rtsp-sdp.h4
17 files changed, 1497 insertions, 7 deletions
diff --git a/docs/libs/gst-rtsp-server-docs.sgml b/docs/libs/gst-rtsp-server-docs.sgml
index 06141f8..26c2a51 100644
--- a/docs/libs/gst-rtsp-server-docs.sgml
+++ b/docs/libs/gst-rtsp-server-docs.sgml
@@ -33,6 +33,10 @@
<xi:include href="xml/rtsp-token.xml"/>
<xi:include href="xml/rtsp-permissions.xml"/>
<xi:include href="xml/rtsp-params.xml"/>
+ <xi:include href="xml/rtsp-onvif-server.xml"/>
+ <xi:include href="xml/rtsp-onvif-client.xml"/>
+ <xi:include href="xml/rtsp-onvif-media-factory.xml"/>
+ <xi:include href="xml/rtsp-onvif-media.xml"/>
</chapter>
<chapter id="rtsp-server-hierarchy">
diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt
index 3299fd7..a8fa790 100644
--- a/docs/libs/gst-rtsp-server-sections.txt
+++ b/docs/libs/gst-rtsp-server-sections.txt
@@ -182,7 +182,9 @@ gst_rtsp_media_set_latency
gst_rtsp_media_get_latency
gst_rtsp_media_setup_sdp
+gst_rtsp_media_setup_sdp_full
gst_rtsp_media_handle_sdp
+gst_rtsp_media_handle_sdp_full
<SUBSECTION MediaPrepare>
gst_rtsp_media_prepare
@@ -281,7 +283,9 @@ gst_rtsp_media_factory_set_media_gtype
gst_rtsp_media_factory_get_media_gtype
gst_rtsp_media_factory_construct
+gst_rtsp_media_factory_construct_full
gst_rtsp_media_factory_create_element
+gst_rtsp_media_factory_create_element_full
<SUBSECTION Standard>
GST_RTSP_MEDIA_FACTORY_CAST
@@ -735,3 +739,106 @@ GST_TYPE_RTSP_TOKEN
gst_rtsp_token_get_type
</SECTION>
+<SECTION>
+<FILE>rtsp-onvif-server</FILE>
+<TITLE>GstRTSPOnvifServer</TITLE>
+GstRTSPOnvifServer
+GstRTSPOnvifServerClass
+
+gst_rtsp_onvif_server_new
+
+GST_RTSP_ONVIF_BACKCHANNEL_REQUIREMENT
+<SUBSECTION Standard>
+gst_rtsp_onvif_server_get_type
+GST_TYPE_RTSP_ONVIF_SERVER
+GST_RTSP_ONVIF_SERVER
+GST_RTSP_ONVIF_SERVER_CAST
+GST_RTSP_ONVIF_SERVER_CLASS
+GST_RTSP_ONVIF_SERVER_CLASS_CAST
+GST_RTSP_ONVIF_SERVER_GET_CLASS
+GST_IS_RTSP_ONVIF_SERVER
+GST_IS_RTSP_ONVIF_SERVER_CLASS
+</SECTION>
+
+<SECTION>
+<FILE>rtsp-onvif-server</FILE>
+<TITLE>GstRTSPOnvifServer</TITLE>
+GstRTSPOnvifServer
+GstRTSPOnvifServerClass
+
+gst_rtsp_onvif_server_new
+<SUBSECTION Standard>
+gst_rtsp_onvif_server_get_type
+GST_TYPE_RTSP_ONVIF_SERVER
+GST_RTSP_ONVIF_SERVER
+GST_RTSP_ONVIF_SERVER_CAST
+GST_RTSP_ONVIF_SERVER_CLASS
+GST_RTSP_ONVIF_SERVER_CLASS_CAST
+GST_RTSP_ONVIF_SERVER_GET_CLASS
+GST_IS_RTSP_ONVIF_SERVER
+GST_IS_RTSP_ONVIF_SERVER_CLASS
+</SECTION>
+
+<SECTION>
+<FILE>rtsp-onvif-client</FILE>
+<TITLE>GstRTSPOnvifClient</TITLE>
+GstRTSPOnvifClient
+GstRTSPOnvifClientClass
+<SUBSECTION Standard>
+gst_rtsp_onvif_client_get_type
+GST_TYPE_RTSP_ONVIF_CLIENT
+GST_RTSP_ONVIF_CLIENT
+GST_RTSP_ONVIF_CLIENT_CAST
+GST_RTSP_ONVIF_CLIENT_CLASS
+GST_RTSP_ONVIF_CLIENT_CLASS_CAST
+GST_RTSP_ONVIF_CLIENT_GET_CLASS
+GST_IS_RTSP_ONVIF_CLIENT
+GST_IS_RTSP_ONVIF_CLIENT_CLASS
+</SECTION>
+
+<SECTION>
+<FILE>rtsp-onvif-media-factory</FILE>
+<TITLE>GstRTSPOnvifMediaFactory</TITLE>
+GstRTSPOnvifMediaFactory
+GstRTSPOnvifMediaFactoryClass
+
+gst_rtsp_onvif_media_factory_new
+gst_rtsp_onvif_media_factory_has_backchannel_support
+gst_rtsp_onvif_media_factory_set_backchannel_bandwidth
+gst_rtsp_onvif_media_factory_get_backchannel_bandwidth
+gst_rtsp_onvif_media_factory_set_backchannel_launch
+gst_rtsp_onvif_media_factory_get_backchannel_launch
+<SUBSECTION Standard>
+GstRTSPOnvifMediaFactoryPrivate
+gst_rtsp_onvif_media_factory_get_type
+GST_TYPE_RTSP_ONVIF_MEDIA_FACTORY
+GST_RTSP_ONVIF_MEDIA_FACTORY
+GST_RTSP_ONVIF_MEDIA_FACTORY_CAST
+GST_RTSP_ONVIF_MEDIA_FACTORY_CLASS
+GST_RTSP_ONVIF_MEDIA_FACTORY_CLASS_CAST
+GST_RTSP_ONVIF_MEDIA_FACTORY_GET_CLASS
+GST_IS_RTSP_ONVIF_MEDIA_FACTORY
+GST_IS_RTSP_ONVIF_MEDIA_FACTORY_CLASS
+</SECTION>
+
+<SECTION>
+<FILE>rtsp-onvif-media</FILE>
+<TITLE>GstRTSPOnvifMedia</TITLE>
+GstRTSPOnvifMedia
+GstRTSPOnvifMediaClass
+
+gst_rtsp_onvif_media_collect_backchannel
+gst_rtsp_onvif_media_get_backchannel_bandwidth
+gst_rtsp_onvif_media_set_backchannel_bandwidth
+<SUBSECTION Standard>
+GstRTSPOnvifMediaPrivate
+gst_rtsp_onvif_media_get_type
+GST_TYPE_RTSP_ONVIF_MEDIA
+GST_RTSP_ONVIF_MEDIA
+GST_RTSP_ONVIF_MEDIA_CAST
+GST_RTSP_ONVIF_MEDIA_CLASS
+GST_RTSP_ONVIF_MEDIA_CLASS_CAST
+GST_RTSP_ONVIF_MEDIA_GET_CLASS
+GST_IS_RTSP_ONVIF_MEDIA
+GST_IS_RTSP_ONVIF_MEDIA_CLASS
+</SECTION>
diff --git a/examples/.gitignore b/examples/.gitignore
index 0907268..d9df57c 100644
--- a/examples/.gitignore
+++ b/examples/.gitignore
@@ -13,3 +13,4 @@ test-uri
test-auth
test-netclock
test-netclock-client
+test-onvif-backchannel
diff --git a/examples/Makefile.am b/examples/Makefile.am
index a76f909..43f811a 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -2,7 +2,8 @@ noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme \
test-launch test-sdp test-uri test-auth test-auth-digest \
test-multicast test-multicast2 test-appsrc \
test-video-rtx test-record test-record-auth \
- test-netclock test-netclock-client
+ test-netclock test-netclock-client \
+ test-onvif-backchannel
#INCLUDES = -I$(top_srcdir) -I$(srcdir)
@@ -28,3 +29,10 @@ test_netclock_client_LDADD = \
$(LDADD) \
$(GST_NET_LIBS)
+test_onvif_backchannel_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(GST_PLUGINS_BASE_CFLAGS)
+test_onvif_backchannel_LDADD = \
+ $(LDADD) \
+ $(GST_PLUGINS_BASE_LIBS) -lgstrtsp-1.0 -lgstsdp-1.0
+
diff --git a/examples/test-onvif-backchannel.c b/examples/test-onvif-backchannel.c
new file mode 100644
index 0000000..906c10b
--- /dev/null
+++ b/examples/test-onvif-backchannel.c
@@ -0,0 +1,71 @@
+/* GStreamer
+ * Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/gst.h>
+#include <gst/rtsp-server/rtsp-onvif-server.h>
+
+#include <string.h>
+
+int
+main (int argc, char *argv[])
+{
+ GMainLoop *loop;
+ GstRTSPServer *server;
+ GstRTSPMountPoints *mounts;
+ GstRTSPMediaFactory *factory;
+
+ gst_init (&argc, &argv);
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ /* create a server instance */
+ server = gst_rtsp_onvif_server_new ();
+
+ /* get the mount points for this server, every server has a default object
+ * that be used to map uri mount points to media factories */
+ mounts = gst_rtsp_server_get_mount_points (server);
+
+ /* make a media factory for a test stream. The default media factory can use
+ * gst-launch syntax to create pipelines.
+ * any launch line works as long as it contains elements named pay%d. Each
+ * element with pay%d names will be a stream */
+ factory = gst_rtsp_onvif_media_factory_new ();
+ gst_rtsp_media_factory_set_launch (factory,
+ "( videotestsrc is-live=true ! x264enc ! rtph264pay name=pay0 pt=96 audiotestsrc is-live=true ! mulawenc ! rtppcmupay name=pay1 )");
+ gst_rtsp_onvif_media_factory_set_backchannel_launch
+ (GST_RTSP_ONVIF_MEDIA_FACTORY (factory),
+ "( capsfilter caps=\"application/x-rtp, media=audio, payload=0, clock-rate=8000, encoding-name=PCMU\" name=depay_backchannel ! rtppcmudepay ! fakesink async=false )");
+ gst_rtsp_media_factory_set_shared (factory, FALSE);
+ gst_rtsp_media_factory_set_media_gtype (factory, GST_TYPE_RTSP_ONVIF_MEDIA);
+
+ /* attach the test factory to the /test url */
+ gst_rtsp_mount_points_add_factory (mounts, "/test", factory);
+
+ /* don't need the ref to the mapper anymore */
+ g_object_unref (mounts);
+
+ /* attach the server to the default maincontext */
+ gst_rtsp_server_attach (server, NULL);
+
+ /* start serving */
+ g_print ("stream ready at rtsp://127.0.0.1:8554/test\n");
+ g_main_loop_run (loop);
+
+ return 0;
+}
diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am
index 224b48b..95b239f 100644
--- a/gst/rtsp-server/Makefile.am
+++ b/gst/rtsp-server/Makefile.am
@@ -17,7 +17,11 @@ public_headers = \
rtsp-session-pool.h \
rtsp-token.h \
rtsp-client.h \
- rtsp-server.h
+ rtsp-server.h \
+ rtsp-onvif-server.h \
+ rtsp-onvif-client.h \
+ rtsp-onvif-media-factory.h \
+ rtsp-onvif-media.h
c_sources = \
rtsp-auth.c \
@@ -38,7 +42,11 @@ c_sources = \
rtsp-session-pool.c \
rtsp-token.c \
rtsp-client.c \
- rtsp-server.c
+ rtsp-server.c \
+ rtsp-onvif-server.c \
+ rtsp-onvif-client.c \
+ rtsp-onvif-media-factory.c \
+ rtsp-onvif-media.c
noinst_HEADERS =
diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h
index e4c95f1..ae332ff 100644
--- a/gst/rtsp-server/rtsp-media.h
+++ b/gst/rtsp-server/rtsp-media.h
@@ -332,7 +332,6 @@ gboolean gst_rtsp_media_setup_sdp (GstRTSPMedia * media, Gst
GST_EXPORT
gboolean gst_rtsp_media_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp);
-
/* creating streams */
GST_EXPORT
diff --git a/gst/rtsp-server/rtsp-onvif-client.c b/gst/rtsp-server/rtsp-onvif-client.c
new file mode 100644
index 0000000..2fb50fa
--- /dev/null
+++ b/gst/rtsp-server/rtsp-onvif-client.c
@@ -0,0 +1,100 @@
+/* GStreamer
+ * Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "rtsp-onvif-client.h"
+#include "rtsp-onvif-server.h"
+#include "rtsp-onvif-media-factory.h"
+
+G_DEFINE_TYPE (GstRTSPOnvifClient, gst_rtsp_onvif_client, GST_TYPE_RTSP_CLIENT);
+
+static gchar *
+gst_rtsp_onvif_client_check_requirements (GstRTSPClient * client,
+ GstRTSPContext * ctx, gchar ** requirements)
+{
+ GstRTSPMountPoints *mount_points = NULL;
+ GstRTSPMediaFactory *factory = NULL;
+ gchar *path = NULL;
+ gboolean has_backchannel = FALSE;
+ GString *unsupported = g_string_new ("");
+
+ while (*requirements) {
+ if (strcmp (*requirements, GST_RTSP_ONVIF_BACKCHANNEL_REQUIREMENT) == 0) {
+ has_backchannel = TRUE;
+ } else {
+ if (unsupported->len)
+ g_string_append (unsupported, ", ");
+ g_string_append (unsupported, *requirements);
+ }
+ requirements++;
+ }
+
+ if (unsupported->len)
+ goto out;
+
+ mount_points = gst_rtsp_client_get_mount_points (client);
+ if (!(path = gst_rtsp_mount_points_make_path (mount_points, ctx->uri)))
+ goto out;
+
+ if (!(factory = gst_rtsp_mount_points_match (mount_points, path, NULL)))
+ goto out;
+
+ if (has_backchannel && !GST_IS_RTSP_ONVIF_MEDIA_FACTORY (factory)) {
+ if (unsupported->len)
+ g_string_append (unsupported, ", ");
+ g_string_append (unsupported, GST_RTSP_ONVIF_BACKCHANNEL_REQUIREMENT);
+ } else if (has_backchannel) {
+ GstRTSPOnvifMediaFactory *onvif_factory =
+ GST_RTSP_ONVIF_MEDIA_FACTORY (factory);
+
+ if (!gst_rtsp_onvif_media_factory_has_backchannel_support (onvif_factory)) {
+ if (unsupported->len)
+ g_string_append (unsupported, ", ");
+ g_string_append (unsupported, GST_RTSP_ONVIF_BACKCHANNEL_REQUIREMENT);
+ }
+ }
+
+out:
+ if (path)
+ g_free (path);
+ if (factory)
+ g_object_unref (factory);
+ if (mount_points)
+ g_object_unref (mount_points);
+
+ return g_string_free (unsupported, FALSE);
+}
+
+static void
+gst_rtsp_onvif_client_class_init (GstRTSPOnvifClientClass * klass)
+{
+ GstRTSPClientClass *client_klass = (GstRTSPClientClass *) klass;
+
+ client_klass->check_requirements = gst_rtsp_onvif_client_check_requirements;
+}
+
+static void
+gst_rtsp_onvif_client_init (GstRTSPOnvifClient * client)
+{
+}
diff --git a/gst/rtsp-server/rtsp-onvif-client.h b/gst/rtsp-server/rtsp-onvif-client.h
new file mode 100644
index 0000000..0dc4e98
--- /dev/null
+++ b/gst/rtsp-server/rtsp-onvif-client.h
@@ -0,0 +1,57 @@
+/* GStreamer
+ * Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTSP_ONVIF_CLIENT_H__
+#define __GST_RTSP_ONVIF_CLIENT_H__
+
+#include <gst/gst.h>
+#include "rtsp-client.h"
+
+#define GST_TYPE_RTSP_ONVIF_CLIENT (gst_rtsp_onvif_client_get_type ())
+#define GST_IS_RTSP_ONVIF_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_ONVIF_CLIENT))
+#define GST_IS_RTSP_ONVIF_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_ONVIF_CLIENT))
+#define GST_RTSP_ONVIF_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_ONVIF_CLIENT, GstRTSPOnvifClientClass))
+#define GST_RTSP_ONVIF_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_ONVIF_CLIENT, GstRTSPOnvifClient))
+#define GST_RTSP_ONVIF_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_ONVIF_CLIENT, GstRTSPOnvifClientClass))
+#define GST_RTSP_ONVIF_CLIENT_CAST(obj) ((GstRTSPOnvifClient*)(obj))
+#define GST_RTSP_ONVIF_CLIENT_CLASS_CAST(klass) ((GstRTSPOnvifClientClass*)(klass))
+
+typedef struct GstRTSPOnvifClientClass GstRTSPOnvifClientClass;
+typedef struct GstRTSPOnvifClient GstRTSPOnvifClient;
+
+struct GstRTSPOnvifClientClass
+{
+ GstRTSPClientClass parent;
+
+ /*< private >*/
+ gpointer _gst_reserved[GST_PADDING_LARGE];
+};
+
+struct GstRTSPOnvifClient
+{
+ GstRTSPClient parent;
+
+ /*< private >*/
+ gpointer _gst_reserved[GST_PADDING];
+};
+
+GST_EXPORT
+GType gst_rtsp_onvif_client_get_type (void);
+
+#endif /* __GST_RTSP_ONVIF_CLIENT_H__ */
diff --git a/gst/rtsp-server/rtsp-onvif-media-factory.c b/gst/rtsp-server/rtsp-onvif-media-factory.c
new file mode 100644
index 0000000..a200f1d
--- /dev/null
+++ b/gst/rtsp-server/rtsp-onvif-media-factory.c
@@ -0,0 +1,491 @@
+/* GStreamer
+ * Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:rtsp-onvif-media-factory
+ * @short_description: A factory for ONVIF media pipelines
+ * @see_also: #GstRTSPMediaFactory, #GstRTSPOnvifMedia
+ *
+ * The #GstRTSPOnvifMediaFactory is responsible for creating or recycling
+ * #GstRTSPMedia objects based on the passed URL. Different to
+ * #GstRTSPMediaFactory, this supports special ONVIF features and can create
+ * #GstRTSPOnvifMedia in addition to normal #GstRTSPMedia.
+ *
+ * Special ONVIF features that are currently supported is a backchannel for
+ * the client to send back media to the server in a normal PLAY media, see
+ * gst_rtsp_onvif_media_factory_set_backchannel_launch() and
+ * gst_rtsp_onvif_media_factory_set_backchannel_bandwidth().
+ *
+ * Since: 1.14
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "rtsp-onvif-media-factory.h"
+#include "rtsp-onvif-media.h"
+#include "rtsp-onvif-server.h"
+
+struct GstRTSPOnvifMediaFactoryPrivate
+{
+ GMutex lock;
+ gchar *backchannel_launch;
+ guint backchannel_bandwidth;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPOnvifMediaFactory,
+ gst_rtsp_onvif_media_factory, GST_TYPE_RTSP_MEDIA_FACTORY);
+
+static gboolean
+requires_backchannel (GstRTSPMessage * msg)
+{
+ GstRTSPResult res;
+ gint i;
+ gchar *reqs = NULL;
+
+ i = 0;
+ do {
+ res = gst_rtsp_message_get_header (msg, GST_RTSP_HDR_REQUIRE, &reqs, i++);
+
+ if (res == GST_RTSP_ENOTIMPL)
+ break;
+
+ if (strcmp (reqs, GST_RTSP_ONVIF_BACKCHANNEL_REQUIREMENT) == 0)
+ return TRUE;
+ } while (TRUE);
+
+ return FALSE;
+}
+
+static gchar *
+gst_rtsp_onvif_media_factory_gen_key (GstRTSPMediaFactory * factory,
+ const GstRTSPUrl * url)
+{
+ GstRTSPContext *ctx = gst_rtsp_context_get_current ();
+ GstRTSPMessage *msg = ctx->request;
+
+ /* Only medias where no backchannel was requested can be shared */
+ if (requires_backchannel (msg))
+ return NULL;
+
+ return
+ GST_RTSP_MEDIA_FACTORY_CLASS
+ (gst_rtsp_onvif_media_factory_parent_class)->gen_key (factory, url);
+}
+
+static GstRTSPMedia *
+gst_rtsp_onvif_media_factory_construct (GstRTSPMediaFactory * factory,
+ const GstRTSPUrl * url)
+{
+ GstRTSPMedia *media;
+ GstElement *element, *pipeline;
+ GstRTSPMediaFactoryClass *klass;
+ GType media_gtype;
+ gboolean got_backchannel_stream;
+ GstRTSPContext *ctx = gst_rtsp_context_get_current ();
+
+ /* Mostly a copy of the default implementation but with backchannel support below,
+ * unfortunately we can't re-use the default one because of how the virtual
+ * method is define */
+
+ /* Everything but play is unsupported */
+ if (gst_rtsp_media_factory_get_transport_mode (factory) !=
+ GST_RTSP_TRANSPORT_MODE_PLAY)
+ return NULL;
+
+ /* we only support onvif media here: otherwise a plain GstRTSPMediaFactory
+ * could've been used as well */
+ media_gtype = gst_rtsp_media_factory_get_media_gtype (factory);
+ if (!g_type_is_a (media_gtype, GST_TYPE_RTSP_ONVIF_MEDIA))
+ return NULL;
+
+ klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
+
+ if (!klass->create_pipeline)
+ goto no_create;
+
+ element = gst_rtsp_media_factory_create_element (factory, url);
+ if (element == NULL)
+ goto no_element;
+
+ /* create a new empty media */
+ media =
+ g_object_new (media_gtype, "element", element,
+ "transport-mode", GST_RTSP_TRANSPORT_MODE_PLAY, NULL);
+
+ /* this adds the non-backchannel streams */
+ gst_rtsp_media_collect_streams (media);
+
+ /* this adds the backchannel stream */
+ got_backchannel_stream =
+ gst_rtsp_onvif_media_collect_backchannel (GST_RTSP_ONVIF_MEDIA (media));
+ /* FIXME: This should not happen! We checked for that before */
+ if (requires_backchannel (ctx->request) && !got_backchannel_stream) {
+ g_object_unref (media);
+ return NULL;
+ }
+
+ pipeline = klass->create_pipeline (factory, media);
+ if (pipeline == NULL)
+ goto no_pipeline;
+
+ gst_rtsp_onvif_media_set_backchannel_bandwidth (GST_RTSP_ONVIF_MEDIA (media),
+ GST_RTSP_ONVIF_MEDIA_FACTORY (factory)->priv->backchannel_bandwidth);
+
+ return media;
+
+ /* ERRORS */
+no_create:
+ {
+ g_critical ("no create_pipeline function");
+ return NULL;
+ }
+no_element:
+ {
+ g_critical ("could not create element");
+ return NULL;
+ }
+no_pipeline:
+ {
+ g_critical ("can't create pipeline");
+ g_object_unref (media);
+ return NULL;
+ }
+}
+
+static GstElement *
+gst_rtsp_onvif_media_factory_create_element (GstRTSPMediaFactory * factory,
+ const GstRTSPUrl * url)
+{
+ GstElement *element;
+ GError *error = NULL;
+ gchar *launch;
+ GstRTSPContext *ctx = gst_rtsp_context_get_current ();
+
+ /* Mostly a copy of the default implementation but with backchannel support below,
+ * unfortunately we can't re-use the default one because of how the virtual
+ * method is define */
+
+ launch = gst_rtsp_media_factory_get_launch (factory);
+
+ /* we need a parse syntax */
+ if (launch == NULL)
+ goto no_launch;
+
+ /* parse the user provided launch line */
+ element =
+ gst_parse_launch_full (launch, NULL, GST_PARSE_FLAG_PLACE_IN_BIN, &error);
+ if (element == NULL)
+ goto parse_error;
+
+ g_free (launch);
+
+ if (error != NULL) {
+ /* a recoverable error was encountered */
+ GST_WARNING ("recoverable parsing error: %s", error->message);
+ g_error_free (error);
+ }
+
+ /* add backchannel pipeline part, if requested */
+ if (requires_backchannel (ctx->request)) {
+ GstRTSPOnvifMediaFactory *onvif_factory =
+ GST_RTSP_ONVIF_MEDIA_FACTORY (factory);
+ GstElement *backchannel_bin;
+ GstElement *backchannel_depay;
+ GstPad *depay_pad, *depay_ghostpad;
+
+ launch =
+ gst_rtsp_onvif_media_factory_get_backchannel_launch (onvif_factory);
+ if (launch == NULL)
+ goto no_launch_backchannel;
+
+ backchannel_bin =
+ gst_parse_bin_from_description_full (launch, FALSE, NULL,
+ GST_PARSE_FLAG_PLACE_IN_BIN, &error);
+ if (backchannel_bin == NULL)
+ goto parse_error_backchannel;
+
+ g_free (launch);
+
+ if (error != NULL) {
+ /* a recoverable error was encountered */
+ GST_WARNING ("recoverable parsing error: %s", error->message);
+ g_error_free (error);
+ }
+
+ gst_object_set_name (GST_OBJECT (backchannel_bin), "onvif-backchannel");
+
+ backchannel_depay =
+ gst_bin_get_by_name (GST_BIN (backchannel_bin), "depay_backchannel");
+ if (!backchannel_depay) {
+ gst_object_unref (backchannel_bin);
+ goto wrongly_formatted_backchannel_bin;
+ }
+
+ depay_pad = gst_element_get_static_pad (backchannel_depay, "sink");
+ if (!depay_pad) {
+ gst_object_unref (backchannel_depay);
+ gst_object_unref (backchannel_bin);
+ goto wrongly_formatted_backchannel_bin;
+ }
+
+ depay_ghostpad = gst_ghost_pad_new ("sink", depay_pad);
+ gst_element_add_pad (backchannel_bin, depay_ghostpad);
+
+ gst_bin_add (GST_BIN (element), backchannel_bin);
+ }
+
+ return element;
+
+ /* ERRORS */
+no_launch:
+ {
+ g_critical ("no launch line specified");
+ g_free (launch);
+ return NULL;
+ }
+parse_error:
+ {
+ g_critical ("could not parse launch syntax (%s): %s", launch,
+ (error ? error->message : "unknown reason"));
+ if (error)
+ g_error_free (error);
+ g_free (launch);
+ return NULL;
+ }
+no_launch_backchannel:
+ {
+ g_critical ("no backchannel launch line specified");
+ gst_object_unref (element);
+ return NULL;
+ }
+parse_error_backchannel:
+ {
+ g_critical ("could not parse backchannel launch syntax (%s): %s", launch,
+ (error ? error->message : "unknown reason"));
+ if (error)
+ g_error_free (error);
+ g_free (launch);
+ gst_object_unref (element);
+ return NULL;
+ }
+
+wrongly_formatted_backchannel_bin:
+ {
+ g_critical ("invalidly formatted backchannel bin");
+
+ gst_object_unref (element);
+ return NULL;
+ }
+}
+
+static gboolean
+ gst_rtsp_onvif_media_factory_has_backchannel_support_default
+ (GstRTSPOnvifMediaFactory * factory)
+{
+ /* No locking here, we just check if it's non-NULL */
+ return factory->priv->backchannel_launch != NULL;
+}
+
+static void
+gst_rtsp_onvif_media_factory_finalize (GObject * object)
+{
+ GstRTSPOnvifMediaFactory *factory = GST_RTSP_ONVIF_MEDIA_FACTORY (object);
+
+ g_free (factory->priv->backchannel_launch);
+ factory->priv->backchannel_launch = NULL;
+
+ g_mutex_clear (&factory->priv->lock);
+
+ return
+ G_OBJECT_CLASS (gst_rtsp_onvif_media_factory_parent_class)->finalize
+ (object);
+}
+
+static void
+gst_rtsp_onvif_media_factory_class_init (GstRTSPOnvifMediaFactoryClass * klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstRTSPMediaFactoryClass *factory_klass = (GstRTSPMediaFactoryClass *) klass;
+
+ gobject_class->finalize = gst_rtsp_onvif_media_factory_finalize;
+
+ factory_klass->gen_key = gst_rtsp_onvif_media_factory_gen_key;
+ factory_klass->construct = gst_rtsp_onvif_media_factory_construct;
+ factory_klass->create_element = gst_rtsp_onvif_media_factory_create_element;
+
+ klass->has_backchannel_support =
+ gst_rtsp_onvif_media_factory_has_backchannel_support_default;
+}
+
+static void
+gst_rtsp_onvif_media_factory_init (GstRTSPOnvifMediaFactory * factory)
+{
+ factory->priv = gst_rtsp_onvif_media_factory_get_instance_private (factory);
+ g_mutex_init (&factory->priv->lock);
+}
+
+/**
+ * gst_rtsp_onvif_media_factory_set_backchannel_launch:
+ * @factory: a #GstRTSPMediaFactory
+ * @launch: the launch description
+ *
+ * The gst_parse_launch() line to use for constructing the ONVIF backchannel
+ * pipeline in the default prepare vmethod if requested by the client.
+ *
+ * The pipeline description should return a GstBin as the toplevel element
+ * which can be accomplished by enclosing the description with brackets '('
+ * ')'.
+ *
+ * The description should return a pipeline with a single depayloader named
+ * depay_backchannel. A caps query on the depayloader's sinkpad should return
+ * all possible, complete RTP caps that are going to be supported. At least
+ * the payload type, clock-rate and encoding-name need to be specified.
+ *
+ * Since: 1.14
+ */
+void
+gst_rtsp_onvif_media_factory_set_backchannel_launch (GstRTSPOnvifMediaFactory *
+ factory, const gchar * launch)
+{
+ g_return_if_fail (GST_IS_RTSP_ONVIF_MEDIA_FACTORY (factory));
+
+ g_mutex_lock (&factory->priv->lock);
+ g_free (factory->priv->backchannel_launch);
+ factory->priv->backchannel_launch = g_strdup (launch);
+ g_mutex_unlock (&factory->priv->lock);
+}
+
+/**
+ * gst_rtsp_onvif_media_factory_get_backchannel_launch:
+ * @factory: a #GstRTSPMediaFactory
+ *
+ * Get the gst_parse_launch() pipeline description that will be used in the
+ * default prepare vmethod for generating the ONVIF backchannel pipeline.
+ *
+ * Returns: (transfer full): the configured backchannel launch description. g_free() after
+ * usage.
+ *
+ * Since: 1.14
+ */
+gchar *
+gst_rtsp_onvif_media_factory_get_backchannel_launch (GstRTSPOnvifMediaFactory *
+ factory)
+{
+ gchar *launch;
+
+ g_return_val_if_fail (GST_IS_RTSP_ONVIF_MEDIA_FACTORY (factory), NULL);
+
+ g_mutex_lock (&factory->priv->lock);
+ launch = g_strdup (factory->priv->backchannel_launch);
+ g_mutex_unlock (&factory->priv->lock);
+
+ return launch;
+}
+
+/**
+ * gst_rtsp_onvif_media_factory_has_backchannel_support:
+ * @factory: a #GstRTSPMediaFactory
+ *
+ * Returns %TRUE if an ONVIF backchannel is supported by the media factory.
+ *
+ * Returns: %TRUE if an ONVIF backchannel is supported by the media factory.
+ *
+ * Since: 1.14
+ */
+gboolean
+gst_rtsp_onvif_media_factory_has_backchannel_support (GstRTSPOnvifMediaFactory *
+ factory)
+{
+ GstRTSPOnvifMediaFactoryClass *klass;
+
+ g_return_val_if_fail (GST_IS_RTSP_ONVIF_MEDIA_FACTORY (factory), FALSE);
+
+ klass = GST_RTSP_ONVIF_MEDIA_FACTORY_GET_CLASS (factory);
+
+ if (klass->has_backchannel_support)
+ return klass->has_backchannel_support (factory);
+
+ return FALSE;
+}
+
+/**
+ * gst_rtsp_onvif_media_factory_set_backchannel_bandwidth:
+ * @factory: a #GstRTSPMediaFactory
+ * @bandwidth: the bandwidth in bits per second
+ *
+ * Set the configured/supported bandwidth of the ONVIF backchannel pipeline in
+ * bits per second.
+ *
+ * Since: 1.14
+ */
+void
+gst_rtsp_onvif_media_factory_set_backchannel_bandwidth (GstRTSPOnvifMediaFactory
+ * factory, guint bandwidth)
+{
+ g_return_if_fail (GST_IS_RTSP_ONVIF_MEDIA_FACTORY (factory));
+
+ g_mutex_lock (&factory->priv->lock);
+ factory->priv->backchannel_bandwidth = bandwidth;
+ g_mutex_unlock (&factory->priv->lock);
+}
+
+/**
+ * gst_rtsp_onvif_media_factory_get_backchannel_bandwidth:
+ * @factory: a #GstRTSPMediaFactory
+ *
+ * Get the configured/supported bandwidth of the ONVIF backchannel pipeline in
+ * bits per second.
+ *
+ * Returns: the configured/supported backchannel bandwidth.
+ *
+ * Since: 1.14
+ */
+guint
+gst_rtsp_onvif_media_factory_get_backchannel_bandwidth (GstRTSPOnvifMediaFactory
+ * factory)
+{
+ guint bandwidth;
+
+ g_return_val_if_fail (GST_IS_RTSP_ONVIF_MEDIA_FACTORY (factory), 0);
+
+ g_mutex_lock (&factory->priv->lock);
+ bandwidth = factory->priv->backchannel_bandwidth;
+ g_mutex_unlock (&factory->priv->lock);
+
+ return bandwidth;
+}
+
+/**
+ * gst_rtsp_onvif_media_factory_new:
+ *
+ * Create a new #GstRTSPOnvifMediaFactory
+ *
+ * Returns: A new #GstRTSPOnvifMediaFactory
+ *
+ * Since: 1.14
+ */
+GstRTSPMediaFactory *
+gst_rtsp_onvif_media_factory_new (void)
+{
+ return g_object_new (GST_TYPE_RTSP_ONVIF_MEDIA_FACTORY, NULL);
+}
diff --git a/gst/rtsp-server/rtsp-onvif-media-factory.h b/gst/rtsp-server/rtsp-onvif-media-factory.h
new file mode 100644
index 0000000..5468748
--- /dev/null
+++ b/gst/rtsp-server/rtsp-onvif-media-factory.h
@@ -0,0 +1,77 @@
+/* GStreamer
+ * Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTSP_ONVIF_MEDIA_FACTORY_H__
+#define __GST_RTSP_ONVIF_MEDIA_FACTORY_H__
+
+#include <gst/gst.h>
+#include "rtsp-media-factory.h"
+
+#define GST_TYPE_RTSP_ONVIF_MEDIA_FACTORY (gst_rtsp_onvif_media_factory_get_type ())
+#define GST_IS_RTSP_ONVIF_MEDIA_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_ONVIF_MEDIA_FACTORY))
+#define GST_IS_RTSP_ONVIF_MEDIA_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_ONVIF_MEDIA_FACTORY))
+#define GST_RTSP_ONVIF_MEDIA_FACTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_ONVIF_MEDIA_FACTORY, GstRTSPOnvifMediaFactoryClass))
+#define GST_RTSP_ONVIF_MEDIA_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_ONVIF_MEDIA_FACTORY, GstRTSPOnvifMediaFactory))
+#define GST_RTSP_ONVIF_MEDIA_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_ONVIF_MEDIA_FACTORY, GstRTSPOnvifMediaFactoryClass))
+#define GST_RTSP_ONVIF_MEDIA_FACTORY_CAST(obj) ((GstRTSPOnvifMediaFactory*)(obj))
+#define GST_RTSP_ONVIF_MEDIA_FACTORY_CLASS_CAST(klass) ((GstRTSPOnvifMediaFactoryClass*)(klass))
+
+typedef struct GstRTSPOnvifMediaFactoryClass GstRTSPOnvifMediaFactoryClass;
+typedef struct GstRTSPOnvifMediaFactory GstRTSPOnvifMediaFactory;
+typedef struct GstRTSPOnvifMediaFactoryPrivate GstRTSPOnvifMediaFactoryPrivate;
+
+struct GstRTSPOnvifMediaFactoryClass
+{
+ GstRTSPMediaFactoryClass parent;
+ gboolean (*has_backchannel_support) (GstRTSPOnvifMediaFactory * factory);
+
+ /*< private >*/
+ gpointer _gst_reserved[GST_PADDING_LARGE];
+};
+
+struct GstRTSPOnvifMediaFactory
+{
+ GstRTSPMediaFactory parent;
+ GstRTSPOnvifMediaFactoryPrivate *priv;
+
+ /*< private >*/
+ gpointer _gst_reserved[GST_PADDING];
+};
+
+GST_EXPORT
+GType gst_rtsp_onvif_media_factory_get_type (void);
+
+GST_EXPORT
+GstRTSPMediaFactory *gst_rtsp_onvif_media_factory_new (void);
+
+GST_EXPORT
+void gst_rtsp_onvif_media_factory_set_backchannel_launch (GstRTSPOnvifMediaFactory *
+ factory, const gchar * launch);
+GST_EXPORT
+gchar * gst_rtsp_onvif_media_factory_get_backchannel_launch (GstRTSPOnvifMediaFactory * factory);
+
+GST_EXPORT
+gboolean gst_rtsp_onvif_media_factory_has_backchannel_support (GstRTSPOnvifMediaFactory * factory);
+
+GST_EXPORT
+void gst_rtsp_onvif_media_factory_set_backchannel_bandwidth (GstRTSPOnvifMediaFactory * factory, guint bandwidth);
+GST_EXPORT
+guint gst_rtsp_onvif_media_factory_get_backchannel_bandwidth (GstRTSPOnvifMediaFactory * factory);
+
+#endif /* __GST_RTSP_ONVIF_MEDIA_FACTORY_H__ */
diff --git a/gst/rtsp-server/rtsp-onvif-media.c b/gst/rtsp-server/rtsp-onvif-media.c
new file mode 100644
index 0000000..8cd7261
--- /dev/null
+++ b/gst/rtsp-server/rtsp-onvif-media.c
@@ -0,0 +1,330 @@
+/* GStreamer
+ * Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:rtsp-onvif-media
+ * @short_description: The ONVIF media pipeline
+ * @see_also: #GstRTSPMedia, #GstRTSPOnvifMediaFactory, #GstRTSPStream, #GstRTSPSession,
+ * #GstRTSPSessionMedia
+ *
+ * a #GstRTSPOnvifMedia contains the complete GStreamer pipeline to manage the
+ * streaming to the clients. The actual data transfer is done by the
+ * #GstRTSPStream objects that are created and exposed by the #GstRTSPMedia.
+ *
+ * On top of #GstRTSPMedia this subclass adds special ONVIF features.
+ * Special ONVIF features that are currently supported is a backchannel for
+ * the client to send back media to the server in a normal PLAY media. To
+ * handle the ONVIF backchannel, a #GstRTSPOnvifMediaFactory and
+ * #GstRTSPOnvifServer has to be used.
+ *
+ * Since: 1.14
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "rtsp-onvif-media.h"
+
+struct GstRTSPOnvifMediaPrivate
+{
+ GMutex lock;
+ guint backchannel_bandwidth;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPOnvifMedia, gst_rtsp_onvif_media,
+ GST_TYPE_RTSP_MEDIA);
+
+static gboolean
+gst_rtsp_onvif_media_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp,
+ GstSDPInfo * info)
+{
+ guint i, n_streams;
+ gchar *rangestr;
+ gboolean res;
+
+ /* Mostly a copy of gst_rtsp_sdp_from_media() which handles the backchannel
+ * stream separately and adds sendonly/recvonly attributes to each media
+ */
+
+ n_streams = gst_rtsp_media_n_streams (media);
+
+ rangestr = gst_rtsp_media_get_range_string (media, FALSE, GST_RTSP_RANGE_NPT);
+ if (rangestr == NULL)
+ goto not_prepared;
+
+ gst_sdp_message_add_attribute (sdp, "range", rangestr);
+ g_free (rangestr);
+
+ res = TRUE;
+ for (i = 0; res && (i < n_streams); i++) {
+ GstRTSPStream *stream;
+ GstCaps *caps = NULL;
+ GstRTSPProfile profiles;
+ guint mask;
+ gboolean res;
+ GstPad *sinkpad = NULL;
+ guint n_caps, j;
+
+ /* Mostly a copy of gst_rtsp_sdp_from_stream() which handles the
+ * backchannel stream separately */
+
+ stream = gst_rtsp_media_get_stream (media, i);
+
+ if ((sinkpad = gst_rtsp_stream_get_sinkpad (stream))) {
+ caps = gst_pad_query_caps (sinkpad, NULL);
+ } else {
+ caps = gst_rtsp_stream_get_caps (stream);
+ }
+
+ if (caps == NULL) {
+ GST_ERROR ("stream %p has no caps", stream);
+ res = FALSE;
+ if (sinkpad)
+ gst_object_unref (sinkpad);
+ break;
+ } else if (!sinkpad && !gst_caps_is_fixed (caps)) {
+ GST_ERROR ("stream %p has unfixed caps", stream);
+ res = FALSE;
+ gst_caps_unref (caps);
+ break;
+ }
+
+ n_caps = gst_caps_get_size (caps);
+ for (j = 0; res && j < n_caps; j++) {
+ GstStructure *s = gst_caps_get_structure (caps, j);
+ GstCaps *media_caps = gst_caps_new_full (gst_structure_copy (s), NULL);
+
+ if (!gst_caps_is_fixed (media_caps)) {
+ GST_ERROR ("media caps for stream %p are not all fixed", stream);
+ res = FALSE;
+ gst_caps_unref (media_caps);
+ break;
+ }
+
+ /* make a new media for each profile */
+ profiles = gst_rtsp_stream_get_profiles (stream);
+ mask = 1;
+ res = TRUE;
+ while (res && (profiles >= mask)) {
+ GstRTSPProfile prof = profiles & mask;
+
+ if (prof) {
+ res = gst_rtsp_sdp_make_media (sdp, info, stream, media_caps, prof);
+ if (res) {
+ GstSDPMedia *smedia =
+ &g_array_index (sdp->medias, GstSDPMedia, sdp->medias->len - 1);
+
+ if (sinkpad) {
+ GstRTSPOnvifMedia *onvif_media = GST_RTSP_ONVIF_MEDIA (media);
+
+ gst_sdp_media_add_attribute (smedia, "sendonly", "");
+ if (onvif_media->priv->backchannel_bandwidth > 0)
+ gst_sdp_media_add_bandwidth (smedia, GST_SDP_BWTYPE_AS,
+ onvif_media->priv->backchannel_bandwidth);
+ } else {
+ gst_sdp_media_add_attribute (smedia, "recvonly", "");
+ }
+ }
+ }
+
+ mask <<= 1;
+ }
+
+ if (sinkpad) {
+ GstStructure *s = gst_caps_get_structure (media_caps, 0);
+ gint pt = -1;
+
+ if (!gst_structure_get_int (s, "payload", &pt) || pt < 0) {
+ GST_ERROR ("stream %p has no payload type", stream);
+ res = FALSE;
+ gst_caps_unref (media_caps);
+ gst_object_unref (sinkpad);
+ break;
+ }
+
+ gst_rtsp_stream_set_pt_map (stream, pt, media_caps);
+ }
+
+ gst_caps_unref (media_caps);
+ }
+
+ gst_caps_unref (caps);
+ if (sinkpad)
+ gst_object_unref (sinkpad);
+ }
+
+ {
+ GstNetTimeProvider *provider;
+
+ if ((provider =
+ gst_rtsp_media_get_time_provider (media, info->server_ip, 0))) {
+ GstClock *clock;
+ gchar *address, *str;
+ gint port;
+
+ g_object_get (provider, "clock", &clock, "address", &address, "port",
+ &port, NULL);
+
+ str = g_strdup_printf ("GstNetTimeProvider %s %s:%d %" G_GUINT64_FORMAT,
+ g_type_name (G_TYPE_FROM_INSTANCE (clock)), address, port,
+ gst_clock_get_time (clock));
+
+ gst_sdp_message_add_attribute (sdp, "x-gst-clock", str);
+ g_free (str);
+ gst_object_unref (clock);
+ g_free (address);
+ gst_object_unref (provider);
+ }
+ }
+
+ return res;
+
+ /* ERRORS */
+not_prepared:
+ {
+ GST_ERROR ("media %p is not prepared", media);
+ return FALSE;
+ }
+}
+
+static void
+gst_rtsp_onvif_media_finalize (GObject * object)
+{
+ GstRTSPOnvifMedia *media = GST_RTSP_ONVIF_MEDIA (object);
+
+ g_mutex_clear (&media->priv->lock);
+
+ return G_OBJECT_CLASS (gst_rtsp_onvif_media_parent_class)->finalize (object);
+}
+
+static void
+gst_rtsp_onvif_media_class_init (GstRTSPOnvifMediaClass * klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstRTSPMediaClass *media_class = (GstRTSPMediaClass *) klass;
+
+ gobject_class->finalize = gst_rtsp_onvif_media_finalize;
+
+ media_class->setup_sdp = gst_rtsp_onvif_media_setup_sdp;
+}
+
+static void
+gst_rtsp_onvif_media_init (GstRTSPOnvifMedia * media)
+{
+ media->priv = gst_rtsp_onvif_media_get_instance_private (media);
+ g_mutex_init (&media->priv->lock);
+}
+
+/**
+ * gst_rtsp_onvif_media_collect_backchannel:
+ * @media: a #GstRTSPOnvifMedia
+ *
+ * Find the ONVIF backchannel depayloader element. It should be named
+ * 'depay_backchannel', be placed in a bin called 'onvif-backchannel'
+ * and return all supported RTP caps on a caps query. Complete RTP caps with
+ * at least the payload type, clock-rate and encoding-name are required.
+ *
+ * A new #GstRTSPStream is created for the backchannel if found.
+ *
+ * Returns: %TRUE if a backchannel stream could be found and created
+ *
+ * Since: 1.14
+ */
+gboolean
+gst_rtsp_onvif_media_collect_backchannel (GstRTSPOnvifMedia * media)
+{
+ GstElement *element, *backchannel_bin = NULL;
+ GstPad *pad = NULL;
+ gboolean ret = FALSE;
+
+ g_return_val_if_fail (GST_IS_RTSP_ONVIF_MEDIA (media), FALSE);
+
+ element = gst_rtsp_media_get_element (GST_RTSP_MEDIA (media));
+ if (!element)
+ return ret;
+
+ backchannel_bin =
+ gst_bin_get_by_name (GST_BIN (element), "onvif-backchannel");
+ if (!backchannel_bin)
+ goto out;
+
+ pad = gst_element_get_static_pad (backchannel_bin, "sink");
+ if (!pad)
+ goto out;
+
+ gst_rtsp_media_create_stream (GST_RTSP_MEDIA (media), backchannel_bin, pad);
+ ret = TRUE;
+
+out:
+ if (pad)
+ gst_object_unref (pad);
+ if (backchannel_bin)
+ gst_object_unref (backchannel_bin);
+ gst_object_unref (element);
+
+ return ret;
+}
+
+/**
+ * gst_rtsp_onvif_media_set_backchannel_bandwidth:
+ * @factory: a #GstRTSPMedia
+ * @bandwidth: the bandwidth in bits per second
+ *
+ * Set the configured/supported bandwidth of the ONVIF backchannel pipeline in
+ * bits per second.
+ *
+ * Since: 1.14
+ */
+void
+gst_rtsp_onvif_media_set_backchannel_bandwidth (GstRTSPOnvifMedia * media,
+ guint bandwidth)
+{
+ g_return_if_fail (GST_IS_RTSP_ONVIF_MEDIA (media));
+
+ g_mutex_lock (&media->priv->lock);
+ media->priv->backchannel_bandwidth = bandwidth;
+ g_mutex_unlock (&media->priv->lock);
+}
+
+/**
+ * gst_rtsp_onvif_media_get_backchannel_bandwidth:
+ * @factory: a #GstRTSPMedia
+ *
+ * Get the configured/supported bandwidth of the ONVIF backchannel pipeline in
+ * bits per second.
+ *
+ * Returns: the configured/supported backchannel bandwidth.
+ *
+ * Since: 1.14
+ */
+guint
+gst_rtsp_onvif_media_get_backchannel_bandwidth (GstRTSPOnvifMedia * media)
+{
+ guint bandwidth;
+
+ g_return_val_if_fail (GST_IS_RTSP_ONVIF_MEDIA (media), 0);
+
+ g_mutex_lock (&media->priv->lock);
+ bandwidth = media->priv->backchannel_bandwidth;
+ g_mutex_unlock (&media->priv->lock);
+
+ return bandwidth;
+}
diff --git a/gst/rtsp-server/rtsp-onvif-media.h b/gst/rtsp-server/rtsp-onvif-media.h
new file mode 100644
index 0000000..a45c11e
--- /dev/null
+++ b/gst/rtsp-server/rtsp-onvif-media.h
@@ -0,0 +1,66 @@
+/* GStreamer
+ * Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTSP_ONVIF_MEDIA_H__
+#define __GST_RTSP_ONVIF_MEDIA_H__
+
+#include <gst/gst.h>
+#include "rtsp-media.h"
+
+#define GST_TYPE_RTSP_ONVIF_MEDIA (gst_rtsp_onvif_media_get_type ())
+#define GST_IS_RTSP_ONVIF_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_ONVIF_MEDIA))
+#define GST_IS_RTSP_ONVIF_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_ONVIF_MEDIA))
+#define GST_RTSP_ONVIF_MEDIA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_ONVIF_MEDIA, GstRTSPOnvifMediaClass))
+#define GST_RTSP_ONVIF_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_ONVIF_MEDIA, GstRTSPOnvifMedia))
+#define GST_RTSP_ONVIF_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_ONVIF_MEDIA, GstRTSPOnvifMediaClass))
+#define GST_RTSP_ONVIF_MEDIA_CAST(obj) ((GstRTSPOnvifMedia*)(obj))
+#define GST_RTSP_ONVIF_MEDIA_CLASS_CAST(klass) ((GstRTSPOnvifMediaClass*)(klass))
+
+typedef struct GstRTSPOnvifMediaClass GstRTSPOnvifMediaClass;
+typedef struct GstRTSPOnvifMedia GstRTSPOnvifMedia;
+typedef struct GstRTSPOnvifMediaPrivate GstRTSPOnvifMediaPrivate;
+
+struct GstRTSPOnvifMediaClass
+{
+ GstRTSPMediaClass parent;
+
+ /*< private >*/
+ gpointer _gst_reserved[GST_PADDING_LARGE];
+};
+
+struct GstRTSPOnvifMedia
+{
+ GstRTSPMedia parent;
+ GstRTSPOnvifMediaPrivate *priv;
+
+ /*< private >*/
+ gpointer _gst_reserved[GST_PADDING];
+};
+
+GST_EXPORT
+GType gst_rtsp_onvif_media_get_type (void);
+GST_EXPORT
+gboolean gst_rtsp_onvif_media_collect_backchannel (GstRTSPOnvifMedia * media);
+
+GST_EXPORT
+void gst_rtsp_onvif_media_set_backchannel_bandwidth (GstRTSPOnvifMedia * media, guint bandwidth);
+GST_EXPORT
+guint gst_rtsp_onvif_media_get_backchannel_bandwidth (GstRTSPOnvifMedia * media);
+
+#endif /* __GST_RTSP_ONVIF_MEDIA_H__ */
diff --git a/gst/rtsp-server/rtsp-onvif-server.c b/gst/rtsp-server/rtsp-onvif-server.c
new file mode 100644
index 0000000..3c3c6f4
--- /dev/null
+++ b/gst/rtsp-server/rtsp-onvif-server.c
@@ -0,0 +1,100 @@
+/* GStreamer
+ * Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:rtsp-onvif-server
+ * @short_description: The main server object
+ * @see_also: #GstRTSPOnvifMediaFactory, #GstRTSPClient
+ *
+ * The server object is the object listening for connections on a port and
+ * creating #GstRTSPOnvifClient objects to handle those connections.
+ *
+ * The only different to #GstRTSPServer is that #GstRTSPOnvifServer creates
+ * #GstRTSPOnvifClient that have special handling for ONVIF specific features,
+ * like a backchannel that allows clients to send back media to the server.
+ *
+ * Since: 1.14
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "rtsp-onvif-server.h"
+#include "rtsp-onvif-client.h"
+
+G_DEFINE_TYPE (GstRTSPOnvifServer, gst_rtsp_onvif_server, GST_TYPE_RTSP_SERVER);
+
+static GstRTSPClient *
+gst_rtsp_onvif_server_create_client (GstRTSPServer * server)
+{
+ GstRTSPClient *client;
+ GstRTSPSessionPool *session_pool;
+ GstRTSPMountPoints *mount_points;
+ GstRTSPAuth *auth;
+ GstRTSPThreadPool *thread_pool;
+
+ /* a new client connected, create a session to handle the client. */
+ client = g_object_new (GST_TYPE_RTSP_ONVIF_CLIENT, NULL);
+
+ /* set the session pool that this client should use */
+ session_pool = gst_rtsp_server_get_session_pool (server);
+ gst_rtsp_client_set_session_pool (client, session_pool);
+ g_object_unref (session_pool);
+ /* set the mount points that this client should use */
+ mount_points = gst_rtsp_server_get_mount_points (server);
+ gst_rtsp_client_set_mount_points (client, mount_points);
+ g_object_unref (mount_points);
+ /* set authentication manager */
+ auth = gst_rtsp_server_get_auth (server);
+ gst_rtsp_client_set_auth (client, auth);
+ if (auth)
+ g_object_unref (auth);
+ /* set threadpool */
+ thread_pool = gst_rtsp_server_get_thread_pool (server);
+ gst_rtsp_client_set_thread_pool (client, thread_pool);
+ g_object_unref (thread_pool);
+
+ return client;
+}
+
+/**
+ * gst_rtsp_onvif_server_new:
+ *
+ * Create a new #GstRTSPOnvifServer instance.
+ *
+ * Returns: (transfer full): a new #GstRTSPOnvifServer
+ */
+GstRTSPServer *
+gst_rtsp_onvif_server_new (void)
+{
+ return g_object_new (GST_TYPE_RTSP_ONVIF_SERVER, NULL);
+}
+
+static void
+gst_rtsp_onvif_server_class_init (GstRTSPOnvifServerClass * klass)
+{
+ GstRTSPServerClass *server_klass = (GstRTSPServerClass *) klass;
+
+ server_klass->create_client = gst_rtsp_onvif_server_create_client;
+}
+
+static void
+gst_rtsp_onvif_server_init (GstRTSPOnvifServer * server)
+{
+}
diff --git a/gst/rtsp-server/rtsp-onvif-server.h b/gst/rtsp-server/rtsp-onvif-server.h
new file mode 100644
index 0000000..56bd9dc
--- /dev/null
+++ b/gst/rtsp-server/rtsp-onvif-server.h
@@ -0,0 +1,65 @@
+/* GStreamer
+ * Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTSP_ONVIF_SERVER_H__
+#define __GST_RTSP_ONVIF_SERVER_H__
+
+#include <gst/gst.h>
+#include "rtsp-server.h"
+
+#define GST_TYPE_RTSP_ONVIF_SERVER (gst_rtsp_onvif_server_get_type ())
+#define GST_IS_RTSP_ONVIF_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_ONVIF_SERVER))
+#define GST_IS_RTSP_ONVIF_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_ONVIF_SERVER))
+#define GST_RTSP_ONVIF_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_ONVIF_SERVER, GstRTSPOnvifServerClass))
+#define GST_RTSP_ONVIF_SERVER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_ONVIF_SERVER, GstRTSPOnvifServer))
+#define GST_RTSP_ONVIF_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_ONVIF_SERVER, GstRTSPOnvifServerClass))
+#define GST_RTSP_ONVIF_SERVER_CAST(obj) ((GstRTSPOnvifServer*)(obj))
+#define GST_RTSP_ONVIF_SERVER_CLASS_CAST(klass) ((GstRTSPOnvifServerClass*)(klass))
+
+typedef struct GstRTSPOnvifServerClass GstRTSPOnvifServerClass;
+typedef struct GstRTSPOnvifServer GstRTSPOnvifServer;
+
+struct GstRTSPOnvifServerClass
+{
+ GstRTSPServerClass parent;
+
+ /*< private >*/
+ gpointer _gst_reserved[GST_PADDING_LARGE];
+};
+
+struct GstRTSPOnvifServer
+{
+ GstRTSPServer parent;
+
+ /*< private >*/
+ gpointer _gst_reserved[GST_PADDING];
+};
+
+GST_EXPORT
+GType gst_rtsp_onvif_server_get_type (void);
+GST_EXPORT
+GstRTSPServer *gst_rtsp_onvif_server_new (void);
+
+#define GST_RTSP_ONVIF_BACKCHANNEL_REQUIREMENT "www.onvif.org/ver20/backchannel"
+
+#include "rtsp-onvif-client.h"
+#include "rtsp-onvif-media-factory.h"
+#include "rtsp-onvif-media.h"
+
+#endif /* __GST_RTSP_ONVIF_SERVER_H__ */
diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c
index b037b28..ff55c02 100644
--- a/gst/rtsp-server/rtsp-sdp.c
+++ b/gst/rtsp-server/rtsp-sdp.c
@@ -70,6 +70,8 @@ update_sdp_from_tags (GstRTSPStream * stream, GstSDPMedia * stream_media)
GstPad *src_pad;
src_pad = gst_rtsp_stream_get_srcpad (stream);
+ if (!src_pad)
+ return;
gst_pad_sticky_events_foreach (src_pad, get_info_from_tags, stream_media);
@@ -179,8 +181,8 @@ cleanup:
}
}
-static gboolean
-make_media (GstSDPMessage * sdp, GstSDPInfo * info,
+gboolean
+gst_rtsp_sdp_make_media (GstSDPMessage * sdp, GstSDPInfo * info,
GstRTSPStream * stream, GstCaps * caps, GstRTSPProfile profile)
{
GstSDPMedia *smedia;
@@ -557,7 +559,7 @@ gst_rtsp_sdp_from_stream (GstSDPMessage * sdp, GstSDPInfo * info,
GstRTSPProfile prof = profiles & mask;
if (prof)
- res = make_media (sdp, info, stream, caps, prof);
+ res = gst_rtsp_sdp_make_media (sdp, info, stream, caps, prof);
mask <<= 1;
}
diff --git a/gst/rtsp-server/rtsp-sdp.h b/gst/rtsp-server/rtsp-sdp.h
index 50cafe8..8683e32 100644
--- a/gst/rtsp-server/rtsp-sdp.h
+++ b/gst/rtsp-server/rtsp-sdp.h
@@ -40,6 +40,10 @@ gboolean gst_rtsp_sdp_from_media (GstSDPMessage *sdp, GstSDPInfo *in
GST_EXPORT
gboolean gst_rtsp_sdp_from_stream (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPStream *stream);
+GST_EXPORT
+gboolean
+gst_rtsp_sdp_make_media (GstSDPMessage * sdp, GstSDPInfo * info, GstRTSPStream * stream, GstCaps * caps, GstRTSPProfile profile);
+
G_END_DECLS
#endif /* __GST_RTSP_SDP_H__ */