diff options
author | Sebastian Dröge <sebastian@centricular.com> | 2017-09-25 19:41:05 +0300 |
---|---|---|
committer | Sebastian Dröge <sebastian@centricular.com> | 2018-02-09 11:08:26 +0200 |
commit | 2f7820ace68903aa8ecf175d3e8ed6b2f4e248fc (patch) | |
tree | a3119b6175809a69b1b2e61dd9a1539ed7798fab | |
parent | 0a8a00396628dd43714ffe495192d748d8f7f402 (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.sgml | 4 | ||||
-rw-r--r-- | docs/libs/gst-rtsp-server-sections.txt | 107 | ||||
-rw-r--r-- | examples/.gitignore | 1 | ||||
-rw-r--r-- | examples/Makefile.am | 10 | ||||
-rw-r--r-- | examples/test-onvif-backchannel.c | 71 | ||||
-rw-r--r-- | gst/rtsp-server/Makefile.am | 12 | ||||
-rw-r--r-- | gst/rtsp-server/rtsp-media.h | 1 | ||||
-rw-r--r-- | gst/rtsp-server/rtsp-onvif-client.c | 100 | ||||
-rw-r--r-- | gst/rtsp-server/rtsp-onvif-client.h | 57 | ||||
-rw-r--r-- | gst/rtsp-server/rtsp-onvif-media-factory.c | 491 | ||||
-rw-r--r-- | gst/rtsp-server/rtsp-onvif-media-factory.h | 77 | ||||
-rw-r--r-- | gst/rtsp-server/rtsp-onvif-media.c | 330 | ||||
-rw-r--r-- | gst/rtsp-server/rtsp-onvif-media.h | 66 | ||||
-rw-r--r-- | gst/rtsp-server/rtsp-onvif-server.c | 100 | ||||
-rw-r--r-- | gst/rtsp-server/rtsp-onvif-server.h | 65 | ||||
-rw-r--r-- | gst/rtsp-server/rtsp-sdp.c | 8 | ||||
-rw-r--r-- | gst/rtsp-server/rtsp-sdp.h | 4 |
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__ */ |