mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 09:10:36 +00:00
media: add GstNetTimeProvider support
Add a property to let the media provide a GstNetTimeProvider for its clock. Make methods to get the clock and nettimeprovider Add a x-gst-clock property to the SDP with the IP and port number of the nettime provider and also the current time of the clock. This should make it possible for (GStreamer) clients to slave their clock to the server clock.
This commit is contained in:
parent
1704018d5d
commit
36ff679558
4 changed files with 190 additions and 0 deletions
|
@ -45,6 +45,7 @@ libgstrtspserver_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDF
|
||||||
libgstrtspserver_@GST_API_VERSION@_la_LIBADD = \
|
libgstrtspserver_@GST_API_VERSION@_la_LIBADD = \
|
||||||
$(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \
|
$(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \
|
||||||
-lgstrtp-@GST_API_VERSION@ -lgstrtsp-@GST_API_VERSION@ \
|
-lgstrtp-@GST_API_VERSION@ -lgstrtsp-@GST_API_VERSION@ \
|
||||||
|
-lgstnet-@GST_API_VERSION@ \
|
||||||
-lgstsdp-@GST_API_VERSION@ \
|
-lgstsdp-@GST_API_VERSION@ \
|
||||||
-lgstapp-@GST_API_VERSION@ \
|
-lgstapp-@GST_API_VERSION@ \
|
||||||
$(GST_LIBS) $(GIO_LIBS) $(LIBM)
|
$(GST_LIBS) $(GIO_LIBS) $(LIBM)
|
||||||
|
|
|
@ -58,6 +58,9 @@ struct _GstRTSPMediaPrivate
|
||||||
GSource *source;
|
GSource *source;
|
||||||
guint id;
|
guint id;
|
||||||
|
|
||||||
|
gboolean time_provider;
|
||||||
|
GstNetTimeProvider *nettime;
|
||||||
|
|
||||||
gboolean is_live;
|
gboolean is_live;
|
||||||
gboolean seekable;
|
gboolean seekable;
|
||||||
gboolean buffering;
|
gboolean buffering;
|
||||||
|
@ -78,6 +81,7 @@ struct _GstRTSPMediaPrivate
|
||||||
//#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP_MCAST
|
//#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP_MCAST
|
||||||
#define DEFAULT_EOS_SHUTDOWN FALSE
|
#define DEFAULT_EOS_SHUTDOWN FALSE
|
||||||
#define DEFAULT_BUFFER_SIZE 0x80000
|
#define DEFAULT_BUFFER_SIZE 0x80000
|
||||||
|
#define DEFAULT_TIME_PROVIDER FALSE
|
||||||
|
|
||||||
/* define to dump received RTCP packets */
|
/* define to dump received RTCP packets */
|
||||||
#undef DUMP_STATS
|
#undef DUMP_STATS
|
||||||
|
@ -91,6 +95,7 @@ enum
|
||||||
PROP_EOS_SHUTDOWN,
|
PROP_EOS_SHUTDOWN,
|
||||||
PROP_BUFFER_SIZE,
|
PROP_BUFFER_SIZE,
|
||||||
PROP_ELEMENT,
|
PROP_ELEMENT,
|
||||||
|
PROP_TIME_PROVIDER,
|
||||||
PROP_LAST
|
PROP_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -165,6 +170,11 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
|
||||||
"The GstBin to use for streaming the media", GST_TYPE_ELEMENT,
|
"The GstBin to use for streaming the media", GST_TYPE_ELEMENT,
|
||||||
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
|
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
|
||||||
|
|
||||||
|
g_object_class_install_property (gobject_class, PROP_EOS_SHUTDOWN,
|
||||||
|
g_param_spec_boolean ("time-provider", "Time Provider",
|
||||||
|
"Use a NetTimeProvider for clients",
|
||||||
|
DEFAULT_TIME_PROVIDER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
gst_rtsp_media_signals[SIGNAL_NEW_STREAM] =
|
gst_rtsp_media_signals[SIGNAL_NEW_STREAM] =
|
||||||
g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
|
g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
|
||||||
G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL,
|
G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL,
|
||||||
|
@ -213,6 +223,7 @@ gst_rtsp_media_init (GstRTSPMedia * media)
|
||||||
priv->protocols = DEFAULT_PROTOCOLS;
|
priv->protocols = DEFAULT_PROTOCOLS;
|
||||||
priv->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
|
priv->eos_shutdown = DEFAULT_EOS_SHUTDOWN;
|
||||||
priv->buffer_size = DEFAULT_BUFFER_SIZE;
|
priv->buffer_size = DEFAULT_BUFFER_SIZE;
|
||||||
|
priv->time_provider = DEFAULT_TIME_PROVIDER;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -232,6 +243,8 @@ gst_rtsp_media_finalize (GObject * obj)
|
||||||
|
|
||||||
if (priv->pipeline)
|
if (priv->pipeline)
|
||||||
gst_object_unref (priv->pipeline);
|
gst_object_unref (priv->pipeline);
|
||||||
|
if (priv->nettime)
|
||||||
|
gst_object_unref (priv->nettime);
|
||||||
gst_object_unref (priv->element);
|
gst_object_unref (priv->element);
|
||||||
if (priv->auth)
|
if (priv->auth)
|
||||||
g_object_unref (priv->auth);
|
g_object_unref (priv->auth);
|
||||||
|
@ -269,6 +282,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid,
|
||||||
case PROP_BUFFER_SIZE:
|
case PROP_BUFFER_SIZE:
|
||||||
g_value_set_uint (value, gst_rtsp_media_get_buffer_size (media));
|
g_value_set_uint (value, gst_rtsp_media_get_buffer_size (media));
|
||||||
break;
|
break;
|
||||||
|
case PROP_TIME_PROVIDER:
|
||||||
|
g_value_set_boolean (value, gst_rtsp_media_is_time_provider (media));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
|
||||||
}
|
}
|
||||||
|
@ -299,6 +315,9 @@ gst_rtsp_media_set_property (GObject * object, guint propid,
|
||||||
case PROP_BUFFER_SIZE:
|
case PROP_BUFFER_SIZE:
|
||||||
gst_rtsp_media_set_buffer_size (media, g_value_get_uint (value));
|
gst_rtsp_media_set_buffer_size (media, g_value_get_uint (value));
|
||||||
break;
|
break;
|
||||||
|
case PROP_TIME_PROVIDER:
|
||||||
|
gst_rtsp_media_use_time_provider (media, g_value_get_boolean (value));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
|
||||||
}
|
}
|
||||||
|
@ -413,6 +432,7 @@ gst_rtsp_media_take_pipeline (GstRTSPMedia * media, GstPipeline * pipeline)
|
||||||
{
|
{
|
||||||
GstRTSPMediaPrivate *priv;
|
GstRTSPMediaPrivate *priv;
|
||||||
GstElement *old;
|
GstElement *old;
|
||||||
|
GstNetTimeProvider *nettime;
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_RTSP_MEDIA (media));
|
g_return_if_fail (GST_IS_RTSP_MEDIA (media));
|
||||||
g_return_if_fail (GST_IS_PIPELINE (pipeline));
|
g_return_if_fail (GST_IS_PIPELINE (pipeline));
|
||||||
|
@ -422,11 +442,16 @@ gst_rtsp_media_take_pipeline (GstRTSPMedia * media, GstPipeline * pipeline)
|
||||||
g_mutex_lock (&priv->lock);
|
g_mutex_lock (&priv->lock);
|
||||||
old = priv->pipeline;
|
old = priv->pipeline;
|
||||||
priv->pipeline = GST_ELEMENT_CAST (pipeline);
|
priv->pipeline = GST_ELEMENT_CAST (pipeline);
|
||||||
|
nettime = priv->nettime;
|
||||||
|
priv->nettime = NULL;
|
||||||
g_mutex_unlock (&priv->lock);
|
g_mutex_unlock (&priv->lock);
|
||||||
|
|
||||||
if (old)
|
if (old)
|
||||||
gst_object_unref (old);
|
gst_object_unref (old);
|
||||||
|
|
||||||
|
if (nettime)
|
||||||
|
gst_object_unref (nettime);
|
||||||
|
|
||||||
gst_object_ref (priv->element);
|
gst_object_ref (priv->element);
|
||||||
gst_bin_add (GST_BIN_CAST (pipeline), priv->element);
|
gst_bin_add (GST_BIN_CAST (pipeline), priv->element);
|
||||||
}
|
}
|
||||||
|
@ -669,6 +694,53 @@ gst_rtsp_media_get_buffer_size (GstRTSPMedia * media)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_media_use_time_provider:
|
||||||
|
* @media: a #GstRTSPMedia
|
||||||
|
*
|
||||||
|
* Set @media to provide a GstNetTimeProvider.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_rtsp_media_use_time_provider (GstRTSPMedia * media, gboolean time_provider)
|
||||||
|
{
|
||||||
|
GstRTSPMediaPrivate *priv;
|
||||||
|
|
||||||
|
g_return_if_fail (GST_IS_RTSP_MEDIA (media));
|
||||||
|
|
||||||
|
priv = media->priv;
|
||||||
|
|
||||||
|
g_mutex_lock (&priv->lock);
|
||||||
|
priv->time_provider = time_provider;
|
||||||
|
g_mutex_unlock (&priv->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_media_is_time_provider:
|
||||||
|
* @media: a #GstRTSPMedia
|
||||||
|
*
|
||||||
|
* Check if @media can provide a #GstNetTimeProvider for its pipeline clock.
|
||||||
|
*
|
||||||
|
* Use gst_rtsp_media_get_time_provider() to get the network clock.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if @media can provide a #GstNetTimeProvider.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gst_rtsp_media_is_time_provider (GstRTSPMedia * media)
|
||||||
|
{
|
||||||
|
GstRTSPMediaPrivate *priv;
|
||||||
|
gboolean res;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
|
||||||
|
|
||||||
|
priv = media->priv;
|
||||||
|
|
||||||
|
g_mutex_unlock (&priv->lock);
|
||||||
|
res = priv->time_provider;
|
||||||
|
g_mutex_unlock (&priv->lock);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_rtsp_media_set_auth:
|
* gst_rtsp_media_set_auth:
|
||||||
* @media: a #GstRTSPMedia
|
* @media: a #GstRTSPMedia
|
||||||
|
@ -1536,6 +1608,10 @@ finish_unprepare (GstRTSPMedia * media)
|
||||||
gst_bin_remove (GST_BIN (priv->pipeline), priv->rtpbin);
|
gst_bin_remove (GST_BIN (priv->pipeline), priv->rtpbin);
|
||||||
priv->rtpbin = NULL;
|
priv->rtpbin = NULL;
|
||||||
|
|
||||||
|
if (priv->nettime)
|
||||||
|
gst_object_unref (priv->nettime);
|
||||||
|
priv->nettime = NULL;
|
||||||
|
|
||||||
gst_object_unref (priv->pipeline);
|
gst_object_unref (priv->pipeline);
|
||||||
priv->pipeline = NULL;
|
priv->pipeline = NULL;
|
||||||
|
|
||||||
|
@ -1633,6 +1709,88 @@ is_busy:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* should be called with state-lock */
|
||||||
|
static GstClock *
|
||||||
|
get_clock_unlocked (GstRTSPMedia * media)
|
||||||
|
{
|
||||||
|
if (media->priv->status != GST_RTSP_MEDIA_STATUS_PREPARED) {
|
||||||
|
GST_DEBUG_OBJECT (media, "media was not prepared");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return gst_pipeline_get_clock (GST_PIPELINE_CAST (media->priv->pipeline));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_media_get_clock:
|
||||||
|
* @media: a #GstRTSPMedia
|
||||||
|
*
|
||||||
|
* Get the clock that is used by the pipeline in @media.
|
||||||
|
*
|
||||||
|
* @media must be prepared before this method returns a valid clock object.
|
||||||
|
*
|
||||||
|
* Returns: the #GstClock used by @media. unref after usage.
|
||||||
|
*/
|
||||||
|
GstClock *
|
||||||
|
gst_rtsp_media_get_clock (GstRTSPMedia * media)
|
||||||
|
{
|
||||||
|
GstClock *clock;
|
||||||
|
GstRTSPMediaPrivate *priv;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
|
||||||
|
|
||||||
|
priv = media->priv;
|
||||||
|
|
||||||
|
g_rec_mutex_lock (&priv->state_lock);
|
||||||
|
clock = get_clock_unlocked (media);
|
||||||
|
g_rec_mutex_unlock (&priv->state_lock);
|
||||||
|
|
||||||
|
return clock;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtsp_media_get_time_provider:
|
||||||
|
* @media: a #GstRTSPMedia
|
||||||
|
* @address: an address or NULL
|
||||||
|
* @port: a port or 0
|
||||||
|
*
|
||||||
|
* Get the #GstNetTimeProvider for the clock used by @media. The time provider
|
||||||
|
* will listen on @address and @port for client time requests.
|
||||||
|
*
|
||||||
|
* Returns: the #GstNetTimeProvider of @media.
|
||||||
|
*/
|
||||||
|
GstNetTimeProvider *
|
||||||
|
gst_rtsp_media_get_time_provider (GstRTSPMedia * media, const gchar * address,
|
||||||
|
guint16 port)
|
||||||
|
{
|
||||||
|
GstRTSPMediaPrivate *priv;
|
||||||
|
GstNetTimeProvider *provider = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
|
||||||
|
|
||||||
|
priv = media->priv;
|
||||||
|
|
||||||
|
g_rec_mutex_lock (&priv->state_lock);
|
||||||
|
if (priv->time_provider) {
|
||||||
|
if ((provider = priv->nettime) == NULL) {
|
||||||
|
GstClock *clock;
|
||||||
|
|
||||||
|
if (priv->time_provider && (clock = get_clock_unlocked (media))) {
|
||||||
|
provider = gst_net_time_provider_new (clock, address, port);
|
||||||
|
gst_object_unref (clock);
|
||||||
|
|
||||||
|
priv->nettime = provider;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_rec_mutex_unlock (&priv->state_lock);
|
||||||
|
|
||||||
|
if (provider)
|
||||||
|
gst_object_ref (provider);
|
||||||
|
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_rtsp_media_set_state:
|
* gst_rtsp_media_set_state:
|
||||||
* @media: a #GstRTSPMedia
|
* @media: a #GstRTSPMedia
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include <gst/rtsp/gstrtsprange.h>
|
#include <gst/rtsp/gstrtsprange.h>
|
||||||
#include <gst/rtsp/gstrtspurl.h>
|
#include <gst/rtsp/gstrtspurl.h>
|
||||||
|
#include <gst/net/gstnet.h>
|
||||||
|
|
||||||
#ifndef __GST_RTSP_MEDIA_H__
|
#ifndef __GST_RTSP_MEDIA_H__
|
||||||
#define __GST_RTSP_MEDIA_H__
|
#define __GST_RTSP_MEDIA_H__
|
||||||
|
@ -139,6 +140,10 @@ GstRTSPAddressPool * gst_rtsp_media_get_address_pool (GstRTSPMedia *media);
|
||||||
void gst_rtsp_media_set_buffer_size (GstRTSPMedia *media, guint size);
|
void gst_rtsp_media_set_buffer_size (GstRTSPMedia *media, guint size);
|
||||||
guint gst_rtsp_media_get_buffer_size (GstRTSPMedia *media);
|
guint gst_rtsp_media_get_buffer_size (GstRTSPMedia *media);
|
||||||
|
|
||||||
|
void gst_rtsp_media_use_time_provider (GstRTSPMedia *media, gboolean time_provider);
|
||||||
|
gboolean gst_rtsp_media_is_time_provider (GstRTSPMedia *media);
|
||||||
|
GstNetTimeProvider * gst_rtsp_media_get_time_provider (GstRTSPMedia *media,
|
||||||
|
const gchar *address, guint16 port);
|
||||||
|
|
||||||
/* prepare the media for playback */
|
/* prepare the media for playback */
|
||||||
gboolean gst_rtsp_media_prepare (GstRTSPMedia *media);
|
gboolean gst_rtsp_media_prepare (GstRTSPMedia *media);
|
||||||
|
@ -151,6 +156,8 @@ GstRTSPStream * gst_rtsp_media_create_stream (GstRTSPMedia *media,
|
||||||
GstPad *srcpad);
|
GstPad *srcpad);
|
||||||
|
|
||||||
/* dealing with the media */
|
/* dealing with the media */
|
||||||
|
GstClock * gst_rtsp_media_get_clock (GstRTSPMedia *media);
|
||||||
|
|
||||||
guint gst_rtsp_media_n_streams (GstRTSPMedia *media);
|
guint gst_rtsp_media_n_streams (GstRTSPMedia *media);
|
||||||
GstRTSPStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx);
|
GstRTSPStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx);
|
||||||
|
|
||||||
|
|
|
@ -158,6 +158,30 @@ gst_rtsp_sdp_from_media (GstSDPMessage * sdp, GstSDPInfo * info,
|
||||||
gst_caps_unref (caps);
|
gst_caps_unref (caps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
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 TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
|
|
Loading…
Reference in a new issue