mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 08:46:40 +00:00
onvif: encapsulate onvif part into a bin
...and thus do not let onvif affect pipelines latency https://bugzilla.gnome.org/show_bug.cgi?id=797174
This commit is contained in:
parent
982efec468
commit
7b5e232a9e
5 changed files with 439 additions and 2 deletions
|
@ -31,6 +31,7 @@ c_sources = \
|
|||
rtsp-params.c \
|
||||
rtsp-sdp.c \
|
||||
rtsp-thread-pool.c \
|
||||
rtsp-latency-bin.c \
|
||||
rtsp-media.c \
|
||||
rtsp-media-factory.c \
|
||||
rtsp-media-factory-uri.c \
|
||||
|
|
|
@ -3,6 +3,7 @@ rtsp_server_sources = [
|
|||
'rtsp-auth.c',
|
||||
'rtsp-client.c',
|
||||
'rtsp-context.c',
|
||||
'rtsp-latency-bin.c',
|
||||
'rtsp-media.c',
|
||||
'rtsp-media-factory.c',
|
||||
'rtsp-media-factory-uri.c',
|
||||
|
|
357
gst/rtsp-server/rtsp-latency-bin.c
Normal file
357
gst/rtsp-server/rtsp-latency-bin.c
Normal file
|
@ -0,0 +1,357 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2018 Ognyan Tonchev <ognyan@axis.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 <gst/gst.h>
|
||||
#include "rtsp-latency-bin.h"
|
||||
|
||||
#define GST_RTSP_LATENCY_BIN_GET_PRIVATE(obj) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_RTSP_LATENCY_BIN_TYPE, GstRTSPLatencyBinPrivate))
|
||||
|
||||
struct _GstRTSPLatencyBinPrivate
|
||||
{
|
||||
GstPad *sinkpad;
|
||||
GstElement *element;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_ELEMENT,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (rtsp_latency_bin_debug);
|
||||
#define GST_CAT_DEFAULT rtsp_latency_bin_debug
|
||||
|
||||
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
static void gst_rtsp_latency_bin_get_property (GObject * object, guint propid,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
static void gst_rtsp_latency_bin_set_property (GObject * object, guint propid,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static gboolean gst_rtsp_latency_bin_element_query (GstElement * element,
|
||||
GstQuery * query);
|
||||
static gboolean gst_rtsp_latency_bin_element_event (GstElement * element,
|
||||
GstEvent * event);
|
||||
static void gst_rtsp_latency_bin_message_handler (GstBin * bin,
|
||||
GstMessage * message);
|
||||
static gboolean gst_rtsp_latency_bin_add_element (GstRTSPLatencyBin *
|
||||
latency_bin, GstElement * element);
|
||||
static GstStateChangeReturn gst_rtsp_latency_bin_change_state (GstElement *
|
||||
element, GstStateChange transition);
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPLatencyBin, gst_rtsp_latency_bin,
|
||||
GST_TYPE_BIN);
|
||||
|
||||
static void
|
||||
gst_rtsp_latency_bin_class_init (GstRTSPLatencyBinClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_klass = G_OBJECT_CLASS (klass);
|
||||
GstElementClass *gstelement_klass = GST_ELEMENT_CLASS (klass);
|
||||
GstBinClass *gstbin_klass = GST_BIN_CLASS (klass);
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (rtsp_latency_bin_debug,
|
||||
"rtsplatencybin", 0, "GstRTSPLatencyBin");
|
||||
|
||||
gobject_klass->get_property = gst_rtsp_latency_bin_get_property;
|
||||
gobject_klass->set_property = gst_rtsp_latency_bin_set_property;
|
||||
|
||||
g_object_class_install_property (gobject_klass, PROP_ELEMENT,
|
||||
g_param_spec_object ("element", "The Element",
|
||||
"The GstElement to prevent from affecting piplines latency",
|
||||
GST_TYPE_ELEMENT, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
|
||||
|
||||
gstelement_klass->change_state =
|
||||
GST_DEBUG_FUNCPTR (gst_rtsp_latency_bin_change_state);
|
||||
gstelement_klass->query =
|
||||
GST_DEBUG_FUNCPTR (gst_rtsp_latency_bin_element_query);
|
||||
gstelement_klass->send_event =
|
||||
GST_DEBUG_FUNCPTR (gst_rtsp_latency_bin_element_event);
|
||||
|
||||
gstbin_klass->handle_message =
|
||||
GST_DEBUG_FUNCPTR (gst_rtsp_latency_bin_message_handler);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_rtsp_latency_bin_init (GstRTSPLatencyBin * latency_bin)
|
||||
{
|
||||
GST_OBJECT_FLAG_SET (latency_bin, GST_ELEMENT_FLAG_SINK);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_rtsp_latency_bin_get_property (GObject * object, guint propid,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstRTSPLatencyBin *latency_bin = GST_RTSP_LATENCY_BIN (object);
|
||||
GstRTSPLatencyBinPrivate *priv =
|
||||
GST_RTSP_LATENCY_BIN_GET_PRIVATE (latency_bin);
|
||||
|
||||
switch (propid) {
|
||||
case PROP_ELEMENT:
|
||||
g_value_set_object (value, priv->element);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_rtsp_latency_bin_set_property (GObject * object, guint propid,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstRTSPLatencyBin *latency_bin = GST_RTSP_LATENCY_BIN (object);
|
||||
|
||||
switch (propid) {
|
||||
case PROP_ELEMENT:
|
||||
if (!gst_rtsp_latency_bin_add_element (latency_bin,
|
||||
g_value_get_object (value))) {
|
||||
GST_WARNING_OBJECT (latency_bin, "Could not add the element");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_rtsp_latency_bin_add_element (GstRTSPLatencyBin * latency_bin,
|
||||
GstElement * element)
|
||||
{
|
||||
GstRTSPLatencyBinPrivate *priv =
|
||||
GST_RTSP_LATENCY_BIN_GET_PRIVATE (latency_bin);
|
||||
GstPad *pad;
|
||||
GstPadTemplate *templ;
|
||||
|
||||
GST_DEBUG_OBJECT (latency_bin, "Adding element to latencybin : %s",
|
||||
GST_ELEMENT_NAME (element));
|
||||
|
||||
if (!element) {
|
||||
goto no_element;
|
||||
}
|
||||
|
||||
/* add the element to ourself */
|
||||
gst_object_ref (element);
|
||||
gst_bin_add (GST_BIN (latency_bin), element);
|
||||
priv->element = element;
|
||||
|
||||
/* add ghost pad first */
|
||||
templ = gst_static_pad_template_get (&sinktemplate);
|
||||
priv->sinkpad = gst_ghost_pad_new_no_target_from_template ("sink", templ);
|
||||
gst_object_unref (templ);
|
||||
g_assert (priv->sinkpad);
|
||||
|
||||
gst_element_add_pad (GST_ELEMENT (latency_bin), priv->sinkpad);
|
||||
|
||||
/* and link it to our element */
|
||||
pad = gst_element_get_static_pad (element, "sink");
|
||||
if (!pad) {
|
||||
goto no_sink_pad;
|
||||
}
|
||||
|
||||
if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (priv->sinkpad), pad)) {
|
||||
goto set_target_failed;
|
||||
}
|
||||
|
||||
gst_object_unref (pad);
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORs */
|
||||
no_element:
|
||||
{
|
||||
GST_WARNING_OBJECT (latency_bin, "No element, not adding");
|
||||
return FALSE;
|
||||
}
|
||||
no_sink_pad:
|
||||
{
|
||||
GST_WARNING_OBJECT (latency_bin, "The element has no sink pad");
|
||||
return FALSE;
|
||||
}
|
||||
set_target_failed:
|
||||
{
|
||||
GST_WARNING_OBJECT (latency_bin, "Could not set target pad");
|
||||
gst_object_unref (pad);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gst_rtsp_latency_bin_element_query (GstElement * element,
|
||||
GstQuery * query)
|
||||
{
|
||||
gboolean ret = TRUE;
|
||||
|
||||
GST_LOG_OBJECT (element, "got query %s", GST_QUERY_TYPE_NAME (query));
|
||||
|
||||
switch (GST_QUERY_TYPE (query)) {
|
||||
case GST_QUERY_LATENCY:
|
||||
/* ignoring latency query, we do not want our element to affect latency on
|
||||
* the rest of the pipeline */
|
||||
GST_DEBUG_OBJECT (element, "ignoring latency query");
|
||||
gst_query_set_latency (query, FALSE, 0, -1);
|
||||
break;
|
||||
default:
|
||||
ret =
|
||||
GST_ELEMENT_CLASS (gst_rtsp_latency_bin_parent_class)->query (
|
||||
GST_ELEMENT (element), query);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_rtsp_latency_bin_element_event (GstElement * element,
|
||||
GstEvent * event)
|
||||
{
|
||||
gboolean ret = TRUE;
|
||||
|
||||
GST_LOG_OBJECT (element, "got event %s", GST_EVENT_TYPE_NAME (event));
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_LATENCY:
|
||||
/* ignoring latency event, we will configure latency on our element when
|
||||
* going to PLAYING */
|
||||
GST_DEBUG_OBJECT (element, "ignoring latency event");
|
||||
gst_event_unref (event);
|
||||
break;
|
||||
default:
|
||||
ret = GST_ELEMENT_CLASS (
|
||||
gst_rtsp_latency_bin_parent_class)->send_event (
|
||||
GST_ELEMENT (element), event);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_rtsp_latency_bin_recalculate_latency (GstRTSPLatencyBin * latency_bin)
|
||||
{
|
||||
GstRTSPLatencyBinPrivate *priv =
|
||||
GST_RTSP_LATENCY_BIN_GET_PRIVATE (latency_bin);
|
||||
GstEvent *latency;
|
||||
GstQuery *query;
|
||||
GstClockTime min_latency;
|
||||
|
||||
GST_DEBUG_OBJECT (latency_bin, "Recalculating latency");
|
||||
|
||||
if (!priv->element) {
|
||||
GST_WARNING_OBJECT (latency_bin, "We do not have an element");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
query = gst_query_new_latency ();
|
||||
|
||||
if (!gst_element_query (priv->element, query)) {
|
||||
GST_WARNING_OBJECT (latency_bin, "Latency query failed");
|
||||
gst_query_unref (query);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gst_query_parse_latency (query, NULL, &min_latency, NULL);
|
||||
gst_query_unref (query);
|
||||
|
||||
GST_LOG_OBJECT (latency_bin, "Got min_latency from stream: %"
|
||||
GST_TIME_FORMAT, GST_TIME_ARGS (min_latency));
|
||||
|
||||
latency = gst_event_new_latency (min_latency);
|
||||
if (!gst_element_send_event (priv->element, latency)) {
|
||||
GST_WARNING_OBJECT (latency_bin, "Sending latency event to stream failed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_rtsp_latency_bin_message_handler (GstBin * bin, GstMessage * message)
|
||||
{
|
||||
GstRTSPLatencyBin *latency_bin = GST_RTSP_LATENCY_BIN (bin);
|
||||
|
||||
GST_LOG_OBJECT (bin, "Got message %s", GST_MESSAGE_TYPE_NAME (message));
|
||||
|
||||
switch (GST_MESSAGE_TYPE (message)) {
|
||||
case GST_MESSAGE_LATENCY:{
|
||||
if (!gst_rtsp_latency_bin_recalculate_latency (latency_bin)) {
|
||||
GST_WARNING_OBJECT (latency_bin, "Could not recalculate latency");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
GST_BIN_CLASS (gst_rtsp_latency_bin_parent_class)->handle_message (
|
||||
bin, message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static GstStateChangeReturn
|
||||
gst_rtsp_latency_bin_change_state (GstElement * element, GstStateChange
|
||||
transition)
|
||||
{
|
||||
GstRTSPLatencyBin *latency_bin = GST_RTSP_LATENCY_BIN (element);
|
||||
GstStateChangeReturn ret;
|
||||
|
||||
GST_LOG_OBJECT (latency_bin, "Changing state %s",
|
||||
gst_state_change_get_name (transition));
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
||||
case GST_STATE_CHANGE_PLAYING_TO_PLAYING:
|
||||
if (!gst_rtsp_latency_bin_recalculate_latency (latency_bin)) {
|
||||
GST_WARNING_OBJECT (latency_bin, "Could not recalculate latency");
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = GST_ELEMENT_CLASS (gst_rtsp_latency_bin_parent_class)->change_state
|
||||
(element, transition);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_rtsp_latency_bin_new:
|
||||
* @element: (transfer full): a #GstElement
|
||||
*
|
||||
* Create a bin that encapsulates an @element and prevents it from affecting
|
||||
* latency on the whole pipeline.
|
||||
*
|
||||
* Returns: A newly created #GstRTSPLatencyBin element, or %NULL on failure
|
||||
*/
|
||||
GstElement *
|
||||
gst_rtsp_latency_bin_new (GstElement * element)
|
||||
{
|
||||
GstElement *gst_rtsp_latency_bin;
|
||||
|
||||
g_return_val_if_fail (element, NULL);
|
||||
|
||||
gst_rtsp_latency_bin = g_object_new (GST_RTSP_LATENCY_BIN_TYPE, "element",
|
||||
element, NULL);
|
||||
gst_object_unref (element);
|
||||
return gst_rtsp_latency_bin;
|
||||
}
|
59
gst/rtsp-server/rtsp-latency-bin.h
Normal file
59
gst/rtsp-server/rtsp-latency-bin.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2018 Ognyan Tonchev <ognyan@axis.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_LATENCY_BIN_H__
|
||||
#define __GST_RTSP_LATENCY_BIN_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include "rtsp-server-prelude.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GstRTSPLatencyBin GstRTSPLatencyBin;
|
||||
typedef struct _GstRTSPLatencyBinClass GstRTSPLatencyBinClass;
|
||||
typedef struct _GstRTSPLatencyBinPrivate GstRTSPLatencyBinPrivate;
|
||||
|
||||
#define GST_RTSP_LATENCY_BIN_TYPE (gst_rtsp_latency_bin_get_type ())
|
||||
#define IS_GST_RTSP_LATENCY_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_RTSP_LATENCY_BIN_TYPE))
|
||||
#define IS_GST_RTSP_LATENCY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_RTSP_LATENCY_BIN_TYPE))
|
||||
#define GST_RTSP_LATENCY_BIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_RTSP_LATENCY_BIN_TYPE, GstRTSPLatencyBinClass))
|
||||
#define GST_RTSP_LATENCY_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_RTSP_LATENCY_BIN_TYPE, GstRTSPLatencyBin))
|
||||
#define GST_RTSP_LATENCY_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_RTSP_LATENCY_BIN_TYPE, GstRTSPLatencyBinClass))
|
||||
#define GST_RTSP_LATENCY_BIN_CAST(obj) ((GstRTSPLatencyBin*)(obj))
|
||||
#define GST_RTSP_LATENCY_BIN_CLASS_CAST(klass) ((GstRTSPLatencyBinClass*)(klass))
|
||||
|
||||
struct _GstRTSPLatencyBin {
|
||||
GstBin parent;
|
||||
|
||||
GstRTSPLatencyBinPrivate *priv;
|
||||
};
|
||||
|
||||
struct _GstRTSPLatencyBinClass {
|
||||
GstBinClass parent_class;
|
||||
};
|
||||
|
||||
GST_RTSP_SERVER_API
|
||||
GType gst_rtsp_latency_bin_get_type (void);
|
||||
|
||||
GST_RTSP_SERVER_API
|
||||
GstElement * gst_rtsp_latency_bin_new (GstElement * element);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_RTSP_LATENCY_BIN_H__ */
|
|
@ -42,6 +42,7 @@
|
|||
#endif
|
||||
|
||||
#include "rtsp-onvif-media.h"
|
||||
#include "rtsp-latency-bin.h"
|
||||
|
||||
struct GstRTSPOnvifMediaPrivate
|
||||
{
|
||||
|
@ -251,6 +252,7 @@ gboolean
|
|||
gst_rtsp_onvif_media_collect_backchannel (GstRTSPOnvifMedia * media)
|
||||
{
|
||||
GstElement *element, *backchannel_bin = NULL;
|
||||
GstElement *latency_bin;
|
||||
GstPad *pad = NULL;
|
||||
gboolean ret = FALSE;
|
||||
|
||||
|
@ -265,11 +267,28 @@ gst_rtsp_onvif_media_collect_backchannel (GstRTSPOnvifMedia * media)
|
|||
if (!backchannel_bin)
|
||||
goto out;
|
||||
|
||||
pad = gst_element_get_static_pad (backchannel_bin, "sink");
|
||||
/* We don't want the backchannel element, which is a receiver, to affect
|
||||
* latency on the complete pipeline. That's why we remove it from the
|
||||
* pipeline and add it to a @GstRTSPLatencyBin which will prevent it from
|
||||
* messing up pipelines latency. The extra reference is needed so that it
|
||||
* is not freed in case the pipeline holds the the only ref to it.
|
||||
*
|
||||
* TODO: a more generic solution should be implemented in
|
||||
* gst_rtsp_media_collect_streams() where all receivers are encapsulated
|
||||
* in a @GstRTSPLatencyBin in cases when there are senders too. */
|
||||
gst_object_ref (backchannel_bin);
|
||||
gst_bin_remove (GST_BIN (element), backchannel_bin);
|
||||
|
||||
latency_bin = gst_rtsp_latency_bin_new (backchannel_bin);
|
||||
g_assert (latency_bin);
|
||||
|
||||
gst_bin_add (GST_BIN (element), latency_bin);
|
||||
|
||||
pad = gst_element_get_static_pad (latency_bin, "sink");
|
||||
if (!pad)
|
||||
goto out;
|
||||
|
||||
gst_rtsp_media_create_stream (GST_RTSP_MEDIA (media), backchannel_bin, pad);
|
||||
gst_rtsp_media_create_stream (GST_RTSP_MEDIA (media), latency_bin, pad);
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
|
|
Loading…
Reference in a new issue