rtpjitterbuffer: Add RFC7273 media clock handling

https://bugzilla.gnome.org/show_bug.cgi?id=762259
This commit is contained in:
Sebastian Dröge 2016-01-05 16:15:16 +02:00
parent fd7964e746
commit df247f091c
7 changed files with 499 additions and 88 deletions

View file

@ -298,6 +298,7 @@ enum
#define DEFAULT_MAX_RTCP_RTP_TIME_DIFF 1000 #define DEFAULT_MAX_RTCP_RTP_TIME_DIFF 1000
#define DEFAULT_MAX_DROPOUT_TIME 60000 #define DEFAULT_MAX_DROPOUT_TIME 60000
#define DEFAULT_MAX_MISORDER_TIME 2000 #define DEFAULT_MAX_MISORDER_TIME 2000
#define DEFAULT_RFC7273_SYNC FALSE
enum enum
{ {
@ -320,7 +321,8 @@ enum
PROP_RTCP_SYNC_SEND_TIME, PROP_RTCP_SYNC_SEND_TIME,
PROP_MAX_RTCP_RTP_TIME_DIFF, PROP_MAX_RTCP_RTP_TIME_DIFF,
PROP_MAX_DROPOUT_TIME, PROP_MAX_DROPOUT_TIME,
PROP_MAX_MISORDER_TIME PROP_MAX_MISORDER_TIME,
PROP_RFC7273_SYNC
}; };
#define GST_RTP_BIN_RTCP_SYNC_TYPE (gst_rtp_bin_rtcp_sync_get_type()) #define GST_RTP_BIN_RTCP_SYNC_TYPE (gst_rtp_bin_rtcp_sync_get_type())
@ -1621,6 +1623,7 @@ create_stream (GstRtpBinSession * session, guint32 ssrc)
rtpbin->max_rtcp_rtp_time_diff, NULL); rtpbin->max_rtcp_rtp_time_diff, NULL);
g_object_set (buffer, "max-dropout-time", rtpbin->max_dropout_time, g_object_set (buffer, "max-dropout-time", rtpbin->max_dropout_time,
"max-misorder-time", rtpbin->max_misorder_time, NULL); "max-misorder-time", rtpbin->max_misorder_time, NULL);
g_object_set (buffer, "rfc7273-sync", rtpbin->rfc7273_sync, NULL);
g_signal_emit (rtpbin, gst_rtp_bin_signals[SIGNAL_NEW_JITTERBUFFER], 0, g_signal_emit (rtpbin, gst_rtp_bin_signals[SIGNAL_NEW_JITTERBUFFER], 0,
buffer, session->id, ssrc); buffer, session->id, ssrc);
@ -2314,6 +2317,12 @@ gst_rtp_bin_class_init (GstRtpBinClass * klass)
0, G_MAXUINT, DEFAULT_MAX_MISORDER_TIME, 0, G_MAXUINT, DEFAULT_MAX_MISORDER_TIME,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_RFC7273_SYNC,
g_param_spec_boolean ("rfc7273-sync", "Sync on RFC7273 clock",
"Synchronize received streams to the RFC7273 clock "
"(requires clock and offset to be provided)", DEFAULT_RFC7273_SYNC,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_bin_change_state); gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_bin_change_state);
gstelement_class->request_new_pad = gstelement_class->request_new_pad =
GST_DEBUG_FUNCPTR (gst_rtp_bin_request_new_pad); GST_DEBUG_FUNCPTR (gst_rtp_bin_request_new_pad);
@ -2383,6 +2392,7 @@ gst_rtp_bin_init (GstRtpBin * rtpbin)
rtpbin->max_rtcp_rtp_time_diff = DEFAULT_MAX_RTCP_RTP_TIME_DIFF; rtpbin->max_rtcp_rtp_time_diff = DEFAULT_MAX_RTCP_RTP_TIME_DIFF;
rtpbin->max_dropout_time = DEFAULT_MAX_DROPOUT_TIME; rtpbin->max_dropout_time = DEFAULT_MAX_DROPOUT_TIME;
rtpbin->max_misorder_time = DEFAULT_MAX_MISORDER_TIME; rtpbin->max_misorder_time = DEFAULT_MAX_MISORDER_TIME;
rtpbin->rfc7273_sync = DEFAULT_RFC7273_SYNC;
/* some default SDES entries */ /* some default SDES entries */
cname = g_strdup_printf ("user%u@host-%x", g_random_int (), g_random_int ()); cname = g_strdup_printf ("user%u@host-%x", g_random_int (), g_random_int ());
@ -2599,6 +2609,11 @@ gst_rtp_bin_set_property (GObject * object, guint prop_id,
gst_rtp_bin_propagate_property_to_session (rtpbin, "max-dropout-time", gst_rtp_bin_propagate_property_to_session (rtpbin, "max-dropout-time",
value); value);
break; break;
case PROP_RFC7273_SYNC:
rtpbin->rfc7273_sync = g_value_get_boolean (value);
gst_rtp_bin_propagate_property_to_jitterbuffer (rtpbin,
"rfc7273-sync", value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -2681,6 +2696,8 @@ gst_rtp_bin_get_property (GObject * object, guint prop_id,
case PROP_MAX_MISORDER_TIME: case PROP_MAX_MISORDER_TIME:
g_value_set_uint (value, rtpbin->max_misorder_time); g_value_set_uint (value, rtpbin->max_misorder_time);
break; break;
case PROP_RFC7273_SYNC:
g_value_set_boolean (value, rtpbin->rfc7273_sync);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);

View file

@ -73,6 +73,7 @@ struct _GstRtpBin {
gint max_rtcp_rtp_time_diff; gint max_rtcp_rtp_time_diff;
guint32 max_dropout_time; guint32 max_dropout_time;
guint32 max_misorder_time; guint32 max_misorder_time;
gboolean rfc7273_sync;
/* a list of session */ /* a list of session */
GSList *sessions; GSList *sessions;

View file

@ -100,8 +100,10 @@
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <string.h> #include <string.h>
#include <gst/rtp/gstrtpbuffer.h> #include <gst/rtp/gstrtpbuffer.h>
#include <gst/net/net.h>
#include "gstrtpjitterbuffer.h" #include "gstrtpjitterbuffer.h"
#include "rtpjitterbuffer.h" #include "rtpjitterbuffer.h"
@ -141,6 +143,7 @@ enum
#define DEFAULT_MAX_RTCP_RTP_TIME_DIFF 1000 #define DEFAULT_MAX_RTCP_RTP_TIME_DIFF 1000
#define DEFAULT_MAX_DROPOUT_TIME 60000 #define DEFAULT_MAX_DROPOUT_TIME 60000
#define DEFAULT_MAX_MISORDER_TIME 2000 #define DEFAULT_MAX_MISORDER_TIME 2000
#define DEFAULT_RFC7273_SYNC FALSE
#define DEFAULT_AUTO_RTX_DELAY (20 * GST_MSECOND) #define DEFAULT_AUTO_RTX_DELAY (20 * GST_MSECOND)
#define DEFAULT_AUTO_RTX_TIMEOUT (40 * GST_MSECOND) #define DEFAULT_AUTO_RTX_TIMEOUT (40 * GST_MSECOND)
@ -166,7 +169,8 @@ enum
PROP_STATS, PROP_STATS,
PROP_MAX_RTCP_RTP_TIME_DIFF, PROP_MAX_RTCP_RTP_TIME_DIFF,
PROP_MAX_DROPOUT_TIME, PROP_MAX_DROPOUT_TIME,
PROP_MAX_MISORDER_TIME PROP_MAX_MISORDER_TIME,
PROP_RFC7273_SYNC
}; };
#define JBUF_LOCK(priv) (g_mutex_lock (&(priv)->jbuf_lock)) #define JBUF_LOCK(priv) (g_mutex_lock (&(priv)->jbuf_lock))
@ -413,6 +417,8 @@ static GstPad *gst_rtp_jitter_buffer_request_new_pad (GstElement * element,
static void gst_rtp_jitter_buffer_release_pad (GstElement * element, static void gst_rtp_jitter_buffer_release_pad (GstElement * element,
GstPad * pad); GstPad * pad);
static GstClock *gst_rtp_jitter_buffer_provide_clock (GstElement * element); static GstClock *gst_rtp_jitter_buffer_provide_clock (GstElement * element);
static gboolean gst_rtp_jitter_buffer_set_clock (GstElement * element,
GstClock * clock);
/* pad overrides */ /* pad overrides */
static GstCaps *gst_rtp_jitter_buffer_getcaps (GstPad * pad, GstCaps * filter); static GstCaps *gst_rtp_jitter_buffer_getcaps (GstPad * pad, GstCaps * filter);
@ -745,6 +751,12 @@ gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass)
DEFAULT_MAX_RTCP_RTP_TIME_DIFF, DEFAULT_MAX_RTCP_RTP_TIME_DIFF,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_RFC7273_SYNC,
g_param_spec_boolean ("rfc7273-sync", "Sync on RFC7273 clock",
"Synchronize received streams to the RFC7273 clock "
"(requires clock and offset to be provided)", DEFAULT_RFC7273_SYNC,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/** /**
* GstRtpJitterBuffer::request-pt-map: * GstRtpJitterBuffer::request-pt-map:
* @buffer: the object which received the signal * @buffer: the object which received the signal
@ -820,6 +832,8 @@ gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass)
GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_release_pad); GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_release_pad);
gstelement_class->provide_clock = gstelement_class->provide_clock =
GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_provide_clock); GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_provide_clock);
gstelement_class->set_clock =
GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_set_clock);
gst_element_class_add_static_pad_template (gstelement_class, gst_element_class_add_static_pad_template (gstelement_class,
&gst_rtp_jitter_buffer_src_template); &gst_rtp_jitter_buffer_src_template);
@ -1129,6 +1143,16 @@ gst_rtp_jitter_buffer_provide_clock (GstElement * element)
return gst_system_clock_obtain (); return gst_system_clock_obtain ();
} }
static gboolean
gst_rtp_jitter_buffer_set_clock (GstElement * element, GstClock * clock)
{
GstRtpJitterBuffer *jitterbuffer = GST_RTP_JITTER_BUFFER (element);
rtp_jitter_buffer_set_pipeline_clock (jitterbuffer->priv->jbuf, clock);
return GST_ELEMENT_CLASS (parent_class)->set_clock (element, clock);
}
static void static void
gst_rtp_jitter_buffer_clear_pt_map (GstRtpJitterBuffer * jitterbuffer) gst_rtp_jitter_buffer_clear_pt_map (GstRtpJitterBuffer * jitterbuffer)
{ {
@ -1233,6 +1257,7 @@ gst_jitter_buffer_sink_parse_caps (GstRtpJitterBuffer * jitterbuffer,
GstStructure *caps_struct; GstStructure *caps_struct;
guint val; guint val;
GstClockTime tval; GstClockTime tval;
const gchar *ts_refclk, *mediaclk;
priv = jitterbuffer->priv; priv = jitterbuffer->priv;
@ -1297,6 +1322,75 @@ gst_jitter_buffer_sink_parse_caps (GstRtpJitterBuffer * jitterbuffer,
"npt start/stop: %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT, "npt start/stop: %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
GST_TIME_ARGS (priv->npt_start), GST_TIME_ARGS (priv->npt_stop)); GST_TIME_ARGS (priv->npt_start), GST_TIME_ARGS (priv->npt_stop));
if ((ts_refclk = gst_structure_get_string (caps_struct, "a-ts-refclk"))) {
GstClock *clock = NULL;
guint64 clock_offset = -1;
GST_DEBUG_OBJECT (jitterbuffer, "Have timestamp reference clock %s",
ts_refclk);
if (g_str_has_prefix (ts_refclk, "ntp=")) {
if (g_str_has_prefix (ts_refclk, "ntp=/traceable/")) {
GST_FIXME_OBJECT (jitterbuffer, "Can't handle traceable NTP clocks");
} else {
const gchar *host, *portstr;
gchar *hostname;
guint port;
host = ts_refclk + sizeof ("ntp=") - 1;
if (host[0] == '[') {
/* IPv6 */
portstr = strchr (host, ']');
if (portstr && portstr[1] == ':')
portstr = portstr + 1;
else
portstr = NULL;
} else {
portstr = strrchr (host, ':');
}
if (!portstr || sscanf (portstr, ":%u", &port) != 1)
port = 123;
if (portstr)
hostname = g_strndup (host, (portstr - host));
else
hostname = g_strdup (host);
clock = gst_ntp_clock_new (NULL, hostname, port, 0);
g_free (hostname);
}
} else if (g_str_has_prefix (ts_refclk, "ptp=IEEE1588-2008:")) {
const gchar *domainstr =
ts_refclk + sizeof ("ptp=IEEE1588-2008:XX-XX-XX-XX-XX-XX-XX-XX") - 1;
guint domain;
if (domainstr[0] != ':' || sscanf (domainstr, ":%u", &domain) != 1)
domain = 0;
clock = gst_ptp_clock_new (NULL, domain);
} else {
GST_FIXME_OBJECT (jitterbuffer, "Unsupported timestamp reference clock");
}
if ((mediaclk = gst_structure_get_string (caps_struct, "a-mediaclk"))) {
GST_DEBUG_OBJECT (jitterbuffer, "Got media clock %s", mediaclk);
if (!g_str_has_prefix (mediaclk, "direct=")
|| sscanf (mediaclk, "direct=%" G_GUINT64_FORMAT, &clock_offset) != 1)
GST_FIXME_OBJECT (jitterbuffer, "Unsupported media clock");
if (strstr (mediaclk, "rate=") != NULL) {
GST_FIXME_OBJECT (jitterbuffer, "Rate property not supported");
clock_offset = -1;
}
}
rtp_jitter_buffer_set_media_clock (priv->jbuf, clock, clock_offset);
} else {
rtp_jitter_buffer_set_media_clock (priv->jbuf, NULL, -1);
}
return TRUE; return TRUE;
/* ERRORS */ /* ERRORS */
@ -1566,7 +1660,7 @@ queue_event (GstRtpJitterBuffer * jitterbuffer, GstEvent * event)
GST_DEBUG_OBJECT (jitterbuffer, "adding event"); GST_DEBUG_OBJECT (jitterbuffer, "adding event");
item = alloc_item (event, ITEM_TYPE_EVENT, -1, -1, -1, 0, -1); item = alloc_item (event, ITEM_TYPE_EVENT, -1, -1, -1, 0, -1);
rtp_jitter_buffer_insert (priv->jbuf, item, &head, NULL); rtp_jitter_buffer_insert (priv->jbuf, item, &head, NULL, -1);
if (head) if (head)
JBUF_SIGNAL_EVENT (priv); JBUF_SIGNAL_EVENT (priv);
@ -2625,7 +2719,7 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent,
RTPJitterBufferItem *item; RTPJitterBufferItem *item;
item = alloc_item (l->data, ITEM_TYPE_EVENT, -1, -1, -1, 0, -1); item = alloc_item (l->data, ITEM_TYPE_EVENT, -1, -1, -1, 0, -1);
rtp_jitter_buffer_insert (priv->jbuf, item, &head, NULL); rtp_jitter_buffer_insert (priv->jbuf, item, &head, NULL, -1);
} }
g_list_free (events); g_list_free (events);
@ -2741,7 +2835,8 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent,
* FALSE if a packet with the same seqnum was already in the queue, meaning we * FALSE if a packet with the same seqnum was already in the queue, meaning we
* have a duplicate. */ * have a duplicate. */
if (G_UNLIKELY (!rtp_jitter_buffer_insert (priv->jbuf, item, if (G_UNLIKELY (!rtp_jitter_buffer_insert (priv->jbuf, item,
&head, &percent))) &head, &percent,
gst_element_get_base_time (GST_ELEMENT_CAST (jitterbuffer)))))
goto duplicate; goto duplicate;
/* update timers */ /* update timers */
@ -3311,7 +3406,7 @@ do_lost_timeout (GstRtpJitterBuffer * jitterbuffer, TimerData * timer,
"retry", G_TYPE_UINT, num_rtx_retry, NULL)); "retry", G_TYPE_UINT, num_rtx_retry, NULL));
item = alloc_item (event, ITEM_TYPE_LOST, -1, -1, seqnum, lost_packets, -1); item = alloc_item (event, ITEM_TYPE_LOST, -1, -1, seqnum, lost_packets, -1);
rtp_jitter_buffer_insert (priv->jbuf, item, &head, NULL); rtp_jitter_buffer_insert (priv->jbuf, item, &head, NULL, -1);
/* remove timer now */ /* remove timer now */
remove_timer (jitterbuffer, timer); remove_timer (jitterbuffer, timer);
@ -3780,7 +3875,7 @@ gst_rtp_jitter_buffer_sink_query (GstPad * pad, GstObject * parent,
RTP_JITTER_BUFFER_MODE_BUFFER) { RTP_JITTER_BUFFER_MODE_BUFFER) {
GST_DEBUG_OBJECT (jitterbuffer, "adding serialized query"); GST_DEBUG_OBJECT (jitterbuffer, "adding serialized query");
item = alloc_item (query, ITEM_TYPE_QUERY, -1, -1, -1, 0, -1); item = alloc_item (query, ITEM_TYPE_QUERY, -1, -1, -1, 0, -1);
rtp_jitter_buffer_insert (priv->jbuf, item, &head, NULL); rtp_jitter_buffer_insert (priv->jbuf, item, &head, NULL, -1);
if (head) if (head)
JBUF_SIGNAL_EVENT (priv); JBUF_SIGNAL_EVENT (priv);
JBUF_WAIT_QUERY (priv, out_flushing); JBUF_WAIT_QUERY (priv, out_flushing);
@ -4018,6 +4113,12 @@ gst_rtp_jitter_buffer_set_property (GObject * object,
priv->max_misorder_time = g_value_get_uint (value); priv->max_misorder_time = g_value_get_uint (value);
JBUF_UNLOCK (priv); JBUF_UNLOCK (priv);
break; break;
case PROP_RFC7273_SYNC:
JBUF_LOCK (priv);
rtp_jitter_buffer_set_rfc7273_sync (priv->jbuf,
g_value_get_boolean (value));
JBUF_UNLOCK (priv);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -4138,6 +4239,12 @@ gst_rtp_jitter_buffer_get_property (GObject * object,
g_value_set_uint (value, priv->max_misorder_time); g_value_set_uint (value, priv->max_misorder_time);
JBUF_UNLOCK (priv); JBUF_UNLOCK (priv);
break; break;
case PROP_RFC7273_SYNC:
JBUF_LOCK (priv);
g_value_set_boolean (value,
rtp_jitter_buffer_get_rfc7273_sync (priv->jbuf));
JBUF_UNLOCK (priv);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;

View file

@ -85,6 +85,8 @@ rtp_jitter_buffer_class_init (RTPJitterBufferClass * klass)
static void static void
rtp_jitter_buffer_init (RTPJitterBuffer * jbuf) rtp_jitter_buffer_init (RTPJitterBuffer * jbuf)
{ {
g_mutex_init (&jbuf->clock_lock);
jbuf->packets = g_queue_new (); jbuf->packets = g_queue_new ();
jbuf->mode = RTP_JITTER_BUFFER_MODE_SLAVE; jbuf->mode = RTP_JITTER_BUFFER_MODE_SLAVE;
@ -98,8 +100,19 @@ rtp_jitter_buffer_finalize (GObject * object)
jbuf = RTP_JITTER_BUFFER_CAST (object); jbuf = RTP_JITTER_BUFFER_CAST (object);
if (jbuf->media_clock_synced_id)
g_signal_handler_disconnect (jbuf->media_clock,
jbuf->media_clock_synced_id);
if (jbuf->media_clock)
gst_object_unref (jbuf->media_clock);
if (jbuf->pipeline_clock)
gst_object_unref (jbuf->pipeline_clock);
g_queue_free (jbuf->packets); g_queue_free (jbuf->packets);
g_mutex_clear (&jbuf->clock_lock);
G_OBJECT_CLASS (rtp_jitter_buffer_parent_class)->finalize (object); G_OBJECT_CLASS (rtp_jitter_buffer_parent_class)->finalize (object);
} }
@ -199,6 +212,110 @@ rtp_jitter_buffer_get_clock_rate (RTPJitterBuffer * jbuf)
return jbuf->clock_rate; return jbuf->clock_rate;
} }
static void
media_clock_synced_cb (GstClock * clock, gboolean synced,
RTPJitterBuffer * jbuf)
{
GstClockTime internal, external;
g_mutex_lock (&jbuf->clock_lock);
if (jbuf->pipeline_clock) {
internal = gst_clock_get_internal_time (jbuf->media_clock);
external = gst_clock_get_time (jbuf->pipeline_clock);
gst_clock_set_calibration (jbuf->media_clock, internal, external, 1, 1);
}
g_mutex_unlock (&jbuf->clock_lock);
}
/**
* rtp_jitter_buffer_set_media_clock:
* @jbuf: an #RTPJitterBuffer
* @clock: (transfer full): media #GstClock
* @clock_offset: RTP time at clock epoch or -1
*
* Sets the media clock for the media and the clock offset
*
*/
void
rtp_jitter_buffer_set_media_clock (RTPJitterBuffer * jbuf, GstClock * clock,
guint64 clock_offset)
{
g_mutex_lock (&jbuf->clock_lock);
if (jbuf->media_clock) {
if (jbuf->media_clock_synced_id)
g_signal_handler_disconnect (jbuf->media_clock,
jbuf->media_clock_synced_id);
jbuf->media_clock_synced_id = 0;
gst_object_unref (jbuf->media_clock);
}
jbuf->media_clock = clock;
jbuf->media_clock_offset = clock_offset;
if (jbuf->pipeline_clock && jbuf->media_clock &&
jbuf->pipeline_clock != jbuf->media_clock) {
jbuf->media_clock_synced_id =
g_signal_connect (jbuf->media_clock, "synced",
G_CALLBACK (media_clock_synced_cb), jbuf);
if (gst_clock_is_synced (jbuf->media_clock)) {
GstClockTime internal, external;
internal = gst_clock_get_internal_time (jbuf->media_clock);
external = gst_clock_get_time (jbuf->pipeline_clock);
gst_clock_set_calibration (jbuf->media_clock, internal, external, 1, 1);
}
gst_clock_set_master (jbuf->media_clock, jbuf->pipeline_clock);
}
g_mutex_unlock (&jbuf->clock_lock);
}
/**
* rtp_jitter_buffer_set_pipeline_clock:
* @jbuf: an #RTPJitterBuffer
* @clock: pipeline #GstClock
*
* Sets the pipeline clock
*
*/
void
rtp_jitter_buffer_set_pipeline_clock (RTPJitterBuffer * jbuf, GstClock * clock)
{
g_mutex_lock (&jbuf->clock_lock);
if (jbuf->pipeline_clock)
gst_object_unref (jbuf->pipeline_clock);
jbuf->pipeline_clock = clock ? gst_object_ref (clock) : NULL;
if (jbuf->pipeline_clock && jbuf->media_clock &&
jbuf->pipeline_clock != jbuf->media_clock) {
if (gst_clock_is_synced (jbuf->media_clock)) {
GstClockTime internal, external;
internal = gst_clock_get_internal_time (jbuf->media_clock);
external = gst_clock_get_time (jbuf->pipeline_clock);
gst_clock_set_calibration (jbuf->media_clock, internal, external, 1, 1);
}
gst_clock_set_master (jbuf->media_clock, jbuf->pipeline_clock);
}
g_mutex_unlock (&jbuf->clock_lock);
}
gboolean
rtp_jitter_buffer_get_rfc7273_sync (RTPJitterBuffer * jbuf)
{
return jbuf->rfc7273_sync;
}
void
rtp_jitter_buffer_set_rfc7273_sync (RTPJitterBuffer * jbuf,
gboolean rfc7273_sync)
{
jbuf->rfc7273_sync = rfc7273_sync;
}
/** /**
* rtp_jitter_buffer_reset_skew: * rtp_jitter_buffer_reset_skew:
* @jbuf: an #RTPJitterBuffer * @jbuf: an #RTPJitterBuffer
@ -211,6 +328,7 @@ rtp_jitter_buffer_reset_skew (RTPJitterBuffer * jbuf)
jbuf->base_time = -1; jbuf->base_time = -1;
jbuf->base_rtptime = -1; jbuf->base_rtptime = -1;
jbuf->base_extrtp = -1; jbuf->base_extrtp = -1;
jbuf->media_clock_base_time = -1;
jbuf->ext_rtptime = -1; jbuf->ext_rtptime = -1;
jbuf->last_rtptime = -1; jbuf->last_rtptime = -1;
jbuf->window_pos = 0; jbuf->window_pos = 0;
@ -220,6 +338,7 @@ rtp_jitter_buffer_reset_skew (RTPJitterBuffer * jbuf)
jbuf->prev_send_diff = -1; jbuf->prev_send_diff = -1;
jbuf->prev_out_time = -1; jbuf->prev_out_time = -1;
jbuf->need_resync = TRUE; jbuf->need_resync = TRUE;
GST_DEBUG ("reset skew correction"); GST_DEBUG ("reset skew correction");
} }
@ -241,6 +360,7 @@ rtp_jitter_buffer_resync (RTPJitterBuffer * jbuf, GstClockTime time,
GstClockTime gstrtptime, guint64 ext_rtptime, gboolean reset_skew) GstClockTime gstrtptime, guint64 ext_rtptime, gboolean reset_skew)
{ {
jbuf->base_time = time; jbuf->base_time = time;
jbuf->media_clock_base_time = -1;
jbuf->base_rtptime = gstrtptime; jbuf->base_rtptime = gstrtptime;
jbuf->base_extrtp = ext_rtptime; jbuf->base_extrtp = ext_rtptime;
jbuf->prev_out_time = -1; jbuf->prev_out_time = -1;
@ -406,55 +526,18 @@ update_buffer_level (RTPJitterBuffer * jbuf, gint * percent)
* Returns: @time adjusted with the clock skew. * Returns: @time adjusted with the clock skew.
*/ */
static GstClockTime static GstClockTime
calculate_skew (RTPJitterBuffer * jbuf, guint32 rtptime, GstClockTime time) calculate_skew (RTPJitterBuffer * jbuf, guint64 ext_rtptime,
GstClockTime gstrtptime, GstClockTime time)
{ {
guint64 ext_rtptime;
guint64 send_diff, recv_diff; guint64 send_diff, recv_diff;
gint64 delta; gint64 delta;
gint64 old; gint64 old;
gint pos, i; gint pos, i;
GstClockTime gstrtptime, out_time; GstClockTime out_time;
guint64 slope; guint64 slope;
ext_rtptime = gst_rtp_buffer_ext_timestamp (&jbuf->ext_rtptime, rtptime); /* elapsed time at sender */
send_diff = gstrtptime - jbuf->base_rtptime;
if (jbuf->last_rtptime != -1 && ext_rtptime == jbuf->last_rtptime)
return jbuf->prev_out_time;
gstrtptime =
gst_util_uint64_scale_int (ext_rtptime, GST_SECOND, jbuf->clock_rate);
/* keep track of the last extended rtptime */
jbuf->last_rtptime = ext_rtptime;
send_diff = 0;
if (G_LIKELY (jbuf->base_rtptime != -1)) {
/* check elapsed time in RTP units */
if (G_LIKELY (gstrtptime >= jbuf->base_rtptime)) {
send_diff = gstrtptime - jbuf->base_rtptime;
} else {
/* elapsed time at sender, timestamps can go backwards and thus be
* smaller than our base time, schedule to take a new base time in
* that case. */
GST_WARNING ("backward timestamps at server, schedule resync");
jbuf->need_resync = TRUE;
send_diff = 0;
}
}
/* need resync, lock on to time and gstrtptime if we can, otherwise we
* do with the previous values */
if (G_UNLIKELY (jbuf->need_resync && time != -1)) {
GST_INFO ("resync to time %" GST_TIME_FORMAT ", rtptime %"
GST_TIME_FORMAT, GST_TIME_ARGS (time), GST_TIME_ARGS (gstrtptime));
rtp_jitter_buffer_resync (jbuf, time, gstrtptime, ext_rtptime, FALSE);
send_diff = 0;
}
GST_DEBUG ("extrtp %" G_GUINT64_FORMAT ", gstrtp %" GST_TIME_FORMAT ", base %"
GST_TIME_FORMAT ", send_diff %" GST_TIME_FORMAT, ext_rtptime,
GST_TIME_ARGS (gstrtptime), GST_TIME_ARGS (jbuf->base_rtptime),
GST_TIME_ARGS (send_diff));
/* we don't have an arrival timestamp so we can't do skew detection. we /* we don't have an arrival timestamp so we can't do skew detection. we
* should still apply a timestamp based on RTP timestamp and base_time */ * should still apply a timestamp based on RTP timestamp and base_time */
@ -574,40 +657,9 @@ no_skew:
} else { } else {
out_time += jbuf->skew; out_time += jbuf->skew;
} }
/* check if timestamps are not going backwards, we can only check this if we
* have a previous out time and a previous send_diff */
if (G_LIKELY (jbuf->prev_out_time != -1 && jbuf->prev_send_diff != -1)) {
/* now check for backwards timestamps */
if (G_UNLIKELY (
/* if the server timestamps went up and the out_time backwards */
(send_diff > jbuf->prev_send_diff
&& out_time < jbuf->prev_out_time) ||
/* if the server timestamps went backwards and the out_time forwards */
(send_diff < jbuf->prev_send_diff
&& out_time > jbuf->prev_out_time) ||
/* if the server timestamps did not change */
send_diff == jbuf->prev_send_diff)) {
GST_DEBUG ("backwards timestamps, using previous time");
out_time = jbuf->prev_out_time;
}
}
if (time != -1 && out_time + jbuf->delay < time) {
/* if we are going to produce a timestamp that is later than the input
* timestamp, we need to reset the jitterbuffer. Likely the server paused
* temporarily */
GST_DEBUG ("out %" GST_TIME_FORMAT " + %" G_GUINT64_FORMAT " < time %"
GST_TIME_FORMAT ", reset jitterbuffer", GST_TIME_ARGS (out_time),
jbuf->delay, GST_TIME_ARGS (time));
rtp_jitter_buffer_resync (jbuf, time, gstrtptime, ext_rtptime, TRUE);
out_time = time;
send_diff = 0;
}
} else } else
out_time = -1; out_time = -1;
jbuf->prev_out_time = out_time;
jbuf->prev_send_diff = send_diff;
GST_DEBUG ("skew %" G_GINT64_FORMAT ", out %" GST_TIME_FORMAT, GST_DEBUG ("skew %" G_GINT64_FORMAT ", out %" GST_TIME_FORMAT,
jbuf->skew, GST_TIME_ARGS (out_time)); jbuf->skew, GST_TIME_ARGS (out_time));
@ -642,6 +694,7 @@ queue_do_insert (RTPJitterBuffer * jbuf, GList * list, GList * item)
* @item: an #RTPJitterBufferItem to insert * @item: an #RTPJitterBufferItem to insert
* @head: TRUE when the head element changed. * @head: TRUE when the head element changed.
* @percent: the buffering percent after insertion * @percent: the buffering percent after insertion
* @base_time: base time of the pipeline
* *
* Inserts @item into the packet queue of @jbuf. The sequence number of the * Inserts @item into the packet queue of @jbuf. The sequence number of the
* packet will be used to sort the packets. This function takes ownerhip of * packet will be used to sort the packets. This function takes ownerhip of
@ -655,12 +708,16 @@ queue_do_insert (RTPJitterBuffer * jbuf, GList * list, GList * item)
*/ */
gboolean gboolean
rtp_jitter_buffer_insert (RTPJitterBuffer * jbuf, RTPJitterBufferItem * item, rtp_jitter_buffer_insert (RTPJitterBuffer * jbuf, RTPJitterBufferItem * item,
gboolean * head, gint * percent) gboolean * head, gint * percent, GstClockTime base_time)
{ {
GList *list, *event = NULL; GList *list, *event = NULL;
guint32 rtptime; guint32 rtptime;
guint64 ext_rtptime;
guint16 seqnum; guint16 seqnum;
GstClockTime dts; GstClockTime gstrtptime, dts;
GstClock *media_clock, *pipeline_clock;
guint64 media_clock_offset;
gboolean rfc7273_mode;
g_return_val_if_fail (jbuf != NULL, FALSE); g_return_val_if_fail (jbuf != NULL, FALSE);
g_return_val_if_fail (item != NULL, FALSE); g_return_val_if_fail (item != NULL, FALSE);
@ -737,6 +794,37 @@ rtp_jitter_buffer_insert (RTPJitterBuffer * jbuf, RTPJitterBufferItem * item,
} }
} }
/* Return the last time if we got the same RTP timestamp again */
ext_rtptime = gst_rtp_buffer_ext_timestamp (&jbuf->ext_rtptime, rtptime);
if (jbuf->last_rtptime != -1 && ext_rtptime == jbuf->last_rtptime) {
item->pts = jbuf->prev_out_time;
goto append;
}
/* keep track of the last extended rtptime */
jbuf->last_rtptime = ext_rtptime;
g_mutex_lock (&jbuf->clock_lock);
media_clock = jbuf->media_clock ? gst_object_ref (jbuf->media_clock) : NULL;
pipeline_clock =
jbuf->pipeline_clock ? gst_object_ref (jbuf->pipeline_clock) : NULL;
media_clock_offset = jbuf->media_clock_offset;
g_mutex_unlock (&jbuf->clock_lock);
gstrtptime =
gst_util_uint64_scale_int (ext_rtptime, GST_SECOND, jbuf->clock_rate);
if (G_LIKELY (jbuf->base_rtptime != -1)) {
/* check elapsed time in RTP units */
if (gstrtptime < jbuf->base_rtptime) {
/* elapsed time at sender, timestamps can go backwards and thus be
* smaller than our base time, schedule to take a new base time in
* that case. */
GST_WARNING ("backward timestamps at server, schedule resync");
jbuf->need_resync = TRUE;
}
}
switch (jbuf->mode) { switch (jbuf->mode) {
case RTP_JITTER_BUFFER_MODE_NONE: case RTP_JITTER_BUFFER_MODE_NONE:
case RTP_JITTER_BUFFER_MODE_BUFFER: case RTP_JITTER_BUFFER_MODE_BUFFER:
@ -752,16 +840,178 @@ rtp_jitter_buffer_insert (RTPJitterBuffer * jbuf, RTPJitterBufferItem * item,
case RTP_JITTER_BUFFER_MODE_SYNCED: case RTP_JITTER_BUFFER_MODE_SYNCED:
/* synchronized clocks, take first timestamp as base, use RTP timestamps /* synchronized clocks, take first timestamp as base, use RTP timestamps
* to interpolate */ * to interpolate */
if (jbuf->base_time != -1) if (jbuf->base_time != -1 && !jbuf->need_resync)
dts = -1; dts = -1;
break; break;
case RTP_JITTER_BUFFER_MODE_SLAVE: case RTP_JITTER_BUFFER_MODE_SLAVE:
default: default:
break; break;
} }
/* do skew calculation by measuring the difference between rtptime and the
* receive dts, this function will return the skew corrected rtptime. */ /* need resync, lock on to time and gstrtptime if we can, otherwise we
item->pts = calculate_skew (jbuf, rtptime, dts); * do with the previous values */
if (G_UNLIKELY (jbuf->need_resync && dts != -1)) {
GST_INFO ("resync to time %" GST_TIME_FORMAT ", rtptime %"
GST_TIME_FORMAT, GST_TIME_ARGS (time), GST_TIME_ARGS (gstrtptime));
rtp_jitter_buffer_resync (jbuf, dts, gstrtptime, ext_rtptime, FALSE);
}
GST_DEBUG ("extrtp %" G_GUINT64_FORMAT ", gstrtp %" GST_TIME_FORMAT ", base %"
GST_TIME_FORMAT ", send_diff %" GST_TIME_FORMAT, ext_rtptime,
GST_TIME_ARGS (gstrtptime), GST_TIME_ARGS (jbuf->base_rtptime),
GST_TIME_ARGS (gstrtptime - jbuf->base_rtptime));
rfc7273_mode = media_clock && pipeline_clock
&& gst_clock_is_synced (media_clock);
if (rfc7273_mode && jbuf->mode == RTP_JITTER_BUFFER_MODE_SLAVE
&& (media_clock_offset == -1 || !jbuf->rfc7273_sync)) {
GstClockTime internal, external;
GstClockTime rate_num, rate_denom;
GstClockTime nsrtptimediff, rtpntptime, rtpsystime;
gst_clock_get_calibration (media_clock, &internal, &external, &rate_num,
&rate_denom);
/* Slave to the RFC7273 media clock instead of trying to estimate it
* based on receive times and RTP timestamps */
if (jbuf->media_clock_base_time == -1) {
if (jbuf->base_time != -1) {
jbuf->media_clock_base_time =
gst_clock_unadjust_with_calibration (media_clock,
jbuf->base_time + base_time, internal, external, rate_num,
rate_denom);
} else {
if (dts != -1)
jbuf->media_clock_base_time =
gst_clock_unadjust_with_calibration (media_clock, dts + base_time,
internal, external, rate_num, rate_denom);
else
jbuf->media_clock_base_time =
gst_clock_get_internal_time (media_clock);
jbuf->base_rtptime = gstrtptime;
}
}
if (gstrtptime > jbuf->base_rtptime)
nsrtptimediff = gstrtptime - jbuf->base_rtptime;
else
nsrtptimediff = 0;
rtpntptime = nsrtptimediff + jbuf->media_clock_base_time;
rtpsystime =
gst_clock_adjust_with_calibration (media_clock, rtpntptime, internal,
external, rate_num, rate_denom);
if (rtpsystime > base_time)
item->pts = rtpsystime - base_time;
else
item->pts = 0;
GST_DEBUG ("RFC7273 clock time %" GST_TIME_FORMAT ", out %" GST_TIME_FORMAT,
GST_TIME_ARGS (rtpsystime), GST_TIME_ARGS (item->pts));
} else if (rfc7273_mode && (jbuf->mode == RTP_JITTER_BUFFER_MODE_SLAVE
|| jbuf->mode == RTP_JITTER_BUFFER_MODE_SYNCED)
&& media_clock_offset != -1 && jbuf->rfc7273_sync) {
GstClockTime ntptime, rtptime_tmp;
GstClockTime ntprtptime, rtpsystime;
GstClockTime internal, external;
GstClockTime rate_num, rate_denom;
/* Don't do any of the dts related adjustments further down */
dts = -1;
/* Calculate the actual clock time on the sender side based on the
* RFC7273 clock and convert it to our pipeline clock
*/
gst_clock_get_calibration (media_clock, &internal, &external, &rate_num,
&rate_denom);
ntptime = gst_clock_get_internal_time (media_clock);
ntprtptime = gst_util_uint64_scale (ntptime, jbuf->clock_rate, GST_SECOND);
ntprtptime += media_clock_offset;
ntprtptime &= 0xffffffff;
rtptime_tmp = rtptime;
/* Check for wraparounds, we assume that the diff between current RTP
* timestamp and current media clock time can't be bigger than
* 2**31 clock units */
if (ntprtptime > rtptime_tmp && ntprtptime - rtptime_tmp >= 0x80000000)
rtptime_tmp += G_GUINT64_CONSTANT (0x100000000);
else if (rtptime_tmp > ntprtptime && rtptime_tmp - ntprtptime >= 0x80000000)
ntprtptime += G_GUINT64_CONSTANT (0x100000000);
if (ntprtptime > rtptime_tmp)
ntptime -=
gst_util_uint64_scale (ntprtptime - rtptime_tmp, jbuf->clock_rate,
GST_SECOND);
else
ntptime +=
gst_util_uint64_scale (rtptime_tmp - ntprtptime, jbuf->clock_rate,
GST_SECOND);
rtpsystime =
gst_clock_adjust_with_calibration (media_clock, ntptime, internal,
external, rate_num, rate_denom);
/* All this assumes that the pipeline has enough additional
* latency to cover for the network delay */
if (rtpsystime > base_time)
item->pts = rtpsystime - base_time;
else
item->pts = 0;
GST_DEBUG ("RFC7273 clock time %" GST_TIME_FORMAT ", out %" GST_TIME_FORMAT,
GST_TIME_ARGS (rtpsystime), GST_TIME_ARGS (item->pts));
} else {
/* If we used the RFC7273 clock before and not anymore,
* we need to resync it later again */
jbuf->media_clock_base_time = -1;
/* do skew calculation by measuring the difference between rtptime and the
* receive dts, this function will return the skew corrected rtptime. */
item->pts = calculate_skew (jbuf, ext_rtptime, gstrtptime, dts);
}
/* check if timestamps are not going backwards, we can only check this if we
* have a previous out time and a previous send_diff */
if (G_LIKELY (item->pts != -1 && jbuf->prev_out_time != -1
&& jbuf->prev_send_diff != -1)) {
/* now check for backwards timestamps */
if (G_UNLIKELY (
/* if the server timestamps went up and the out_time backwards */
(gstrtptime - jbuf->base_rtptime > jbuf->prev_send_diff
&& item->pts < jbuf->prev_out_time) ||
/* if the server timestamps went backwards and the out_time forwards */
(gstrtptime - jbuf->base_rtptime < jbuf->prev_send_diff
&& item->pts > jbuf->prev_out_time) ||
/* if the server timestamps did not change */
gstrtptime - jbuf->base_rtptime == jbuf->prev_send_diff)) {
GST_DEBUG ("backwards timestamps, using previous time");
item->pts = jbuf->prev_out_time;
}
}
if (dts != -1 && item->pts + jbuf->delay < dts) {
/* if we are going to produce a timestamp that is later than the input
* timestamp, we need to reset the jitterbuffer. Likely the server paused
* temporarily */
GST_DEBUG ("out %" GST_TIME_FORMAT " + %" G_GUINT64_FORMAT " < time %"
GST_TIME_FORMAT ", reset jitterbuffer", GST_TIME_ARGS (item->pts),
jbuf->delay, GST_TIME_ARGS (time));
rtp_jitter_buffer_resync (jbuf, dts, gstrtptime, ext_rtptime, TRUE);
item->pts = dts;
}
jbuf->prev_out_time = item->pts;
jbuf->prev_send_diff = gstrtptime - jbuf->base_rtptime;
if (media_clock)
gst_object_unref (media_clock);
if (pipeline_clock)
gst_object_unref (pipeline_clock);
append: append:
queue_do_insert (jbuf, list, (GList *) item); queue_do_insert (jbuf, list, (GList *) item);

View file

@ -89,6 +89,7 @@ struct _RTPJitterBuffer {
gboolean need_resync; gboolean need_resync;
GstClockTime base_time; GstClockTime base_time;
GstClockTime base_rtptime; GstClockTime base_rtptime;
GstClockTime media_clock_base_time;
guint32 clock_rate; guint32 clock_rate;
GstClockTime base_extrtp; GstClockTime base_extrtp;
GstClockTime prev_out_time; GstClockTime prev_out_time;
@ -102,6 +103,14 @@ struct _RTPJitterBuffer {
gint64 skew; gint64 skew;
gint64 prev_send_diff; gint64 prev_send_diff;
gboolean buffering_disabled; gboolean buffering_disabled;
GMutex clock_lock;
GstClock *pipeline_clock;
GstClock *media_clock;
gulong media_clock_synced_id;
guint64 media_clock_offset;
gboolean rfc7273_sync;
}; };
struct _RTPJitterBufferClass { struct _RTPJitterBufferClass {
@ -150,11 +159,18 @@ void rtp_jitter_buffer_set_delay (RTPJitterBuffer *jbuf,
void rtp_jitter_buffer_set_clock_rate (RTPJitterBuffer *jbuf, guint32 clock_rate); void rtp_jitter_buffer_set_clock_rate (RTPJitterBuffer *jbuf, guint32 clock_rate);
guint32 rtp_jitter_buffer_get_clock_rate (RTPJitterBuffer *jbuf); guint32 rtp_jitter_buffer_get_clock_rate (RTPJitterBuffer *jbuf);
void rtp_jitter_buffer_set_media_clock (RTPJitterBuffer *jbuf, GstClock * clock, guint64 clock_offset);
void rtp_jitter_buffer_set_pipeline_clock (RTPJitterBuffer *jbuf, GstClock * clock);
gboolean rtp_jitter_buffer_get_rfc7273_sync (RTPJitterBuffer *jbuf);
void rtp_jitter_buffer_set_rfc7273_sync (RTPJitterBuffer *jbuf, gboolean rfc7273_sync);
void rtp_jitter_buffer_reset_skew (RTPJitterBuffer *jbuf); void rtp_jitter_buffer_reset_skew (RTPJitterBuffer *jbuf);
gboolean rtp_jitter_buffer_insert (RTPJitterBuffer *jbuf, gboolean rtp_jitter_buffer_insert (RTPJitterBuffer *jbuf,
RTPJitterBufferItem *item, RTPJitterBufferItem *item,
gboolean *head, gint *percent); gboolean *head, gint *percent,
GstClockTime base_time);
void rtp_jitter_buffer_disable_buffering (RTPJitterBuffer *jbuf, gboolean disabled); void rtp_jitter_buffer_disable_buffering (RTPJitterBuffer *jbuf, gboolean disabled);

View file

@ -227,6 +227,7 @@ gst_rtsp_src_ntp_time_source_get_type (void)
#define DEFAULT_NTP_TIME_SOURCE NTP_TIME_SOURCE_NTP #define DEFAULT_NTP_TIME_SOURCE NTP_TIME_SOURCE_NTP
#define DEFAULT_USER_AGENT "GStreamer/" PACKAGE_VERSION #define DEFAULT_USER_AGENT "GStreamer/" PACKAGE_VERSION
#define DEFAULT_MAX_RTCP_RTP_TIME_DIFF 1000 #define DEFAULT_MAX_RTCP_RTP_TIME_DIFF 1000
#define DEFAULT_RFC7273_SYNC FALSE
enum enum
{ {
@ -265,7 +266,8 @@ enum
PROP_DO_RETRANSMISSION, PROP_DO_RETRANSMISSION,
PROP_NTP_TIME_SOURCE, PROP_NTP_TIME_SOURCE,
PROP_USER_AGENT, PROP_USER_AGENT,
PROP_MAX_RTCP_RTP_TIME_DIFF PROP_MAX_RTCP_RTP_TIME_DIFF,
PROP_RFC7273_SYNC
}; };
#define GST_TYPE_RTSP_NAT_METHOD (gst_rtsp_nat_method_get_type()) #define GST_TYPE_RTSP_NAT_METHOD (gst_rtsp_nat_method_get_type())
@ -732,6 +734,12 @@ gst_rtspsrc_class_init (GstRTSPSrcClass * klass)
DEFAULT_MAX_RTCP_RTP_TIME_DIFF, DEFAULT_MAX_RTCP_RTP_TIME_DIFF,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_RFC7273_SYNC,
g_param_spec_boolean ("rfc7273-sync", "Sync on RFC7273 clock",
"Synchronize received streams to the RFC7273 clock "
"(requires clock and offset to be provided)", DEFAULT_RFC7273_SYNC,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/** /**
* GstRTSPSrc::handle-request: * GstRTSPSrc::handle-request:
* @rtspsrc: a #GstRTSPSrc * @rtspsrc: a #GstRTSPSrc
@ -879,6 +887,7 @@ gst_rtspsrc_init (GstRTSPSrc * src)
src->ntp_time_source = DEFAULT_NTP_TIME_SOURCE; src->ntp_time_source = DEFAULT_NTP_TIME_SOURCE;
src->user_agent = g_strdup (DEFAULT_USER_AGENT); src->user_agent = g_strdup (DEFAULT_USER_AGENT);
src->max_rtcp_rtp_time_diff = DEFAULT_MAX_RTCP_RTP_TIME_DIFF; src->max_rtcp_rtp_time_diff = DEFAULT_MAX_RTCP_RTP_TIME_DIFF;
src->rfc7273_sync = DEFAULT_RFC7273_SYNC;
/* get a list of all extensions */ /* get a list of all extensions */
src->extensions = gst_rtsp_ext_list_get (); src->extensions = gst_rtsp_ext_list_get ();
@ -1158,6 +1167,9 @@ gst_rtspsrc_set_property (GObject * object, guint prop_id, const GValue * value,
case PROP_MAX_RTCP_RTP_TIME_DIFF: case PROP_MAX_RTCP_RTP_TIME_DIFF:
rtspsrc->max_rtcp_rtp_time_diff = g_value_get_int (value); rtspsrc->max_rtcp_rtp_time_diff = g_value_get_int (value);
break; break;
case PROP_RFC7273_SYNC:
rtspsrc->rfc7273_sync = g_value_get_boolean (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -1304,6 +1316,9 @@ gst_rtspsrc_get_property (GObject * object, guint prop_id, GValue * value,
case PROP_MAX_RTCP_RTP_TIME_DIFF: case PROP_MAX_RTCP_RTP_TIME_DIFF:
g_value_set_int (value, rtspsrc->max_rtcp_rtp_time_diff); g_value_set_int (value, rtspsrc->max_rtcp_rtp_time_diff);
break; break;
case PROP_RFC7273_SYNC:
g_value_set_boolean (value, rtspsrc->rfc7273_sync);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -2988,6 +3003,10 @@ gst_rtspsrc_stream_configure_manager (GstRTSPSrc * src, GstRTSPStream * stream,
g_object_set (src->manager, "ntp-sync", src->ntp_sync, NULL); g_object_set (src->manager, "ntp-sync", src->ntp_sync, NULL);
} }
if (g_object_class_find_property (klass, "rfc7273-sync")) {
g_object_set (src->manager, "rfc7273-sync", src->rfc7273_sync, NULL);
}
if (src->use_pipeline_clock) { if (src->use_pipeline_clock) {
if (g_object_class_find_property (klass, "use-pipeline-clock")) { if (g_object_class_find_property (klass, "use-pipeline-clock")) {
g_object_set (src->manager, "use-pipeline-clock", TRUE, NULL); g_object_set (src->manager, "use-pipeline-clock", TRUE, NULL);

View file

@ -239,6 +239,7 @@ struct _GstRTSPSrc {
gint ntp_time_source; gint ntp_time_source;
gchar *user_agent; gchar *user_agent;
GstClockTime max_rtcp_rtp_time_diff; GstClockTime max_rtcp_rtp_time_diff;
gboolean rfc7273_sync;
/* state */ /* state */
GstRTSPState state; GstRTSPState state;