mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-26 18:20:44 +00:00
rtpjitterbuffer: Add new rfc7273-use-system-clock property
When this property is used, it is assumed that the system clock is synced close enough to the media clock used by an RFC7273 stream. As long as both clocks are at most a few seconds from each other this will give the correct results and avoids having to create an actual network clock that has to sync first. If the system clock is actually synchronized to the media clock then everything will behave exactly the same, otherwise the reference timestamp meta will be correct but the buffer timestamps will be off by the difference between the two clocks. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5512>
This commit is contained in:
parent
2956ba48fc
commit
eae3ef7461
4 changed files with 99 additions and 7 deletions
|
@ -18773,6 +18773,18 @@
|
|||
"type": "gboolean",
|
||||
"writable": true
|
||||
},
|
||||
"rfc7273-use-system-clock": {
|
||||
"blurb": "Use system clock as RFC7273 media clock (requires system clock to be synced externally)",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "false",
|
||||
"mutable": "null",
|
||||
"readable": true,
|
||||
"type": "gboolean",
|
||||
"writable": true
|
||||
},
|
||||
"rtx-deadline": {
|
||||
"blurb": "The deadline for a valid RTX request in milliseconds. (-1 automatic)",
|
||||
"conditionally-available": false,
|
||||
|
|
|
@ -158,6 +158,7 @@ enum
|
|||
#define DEFAULT_ADD_REFERENCE_TIMESTAMP_META FALSE
|
||||
#define DEFAULT_FASTSTART_MIN_PACKETS 0
|
||||
#define DEFAULT_SYNC_INTERVAL 0
|
||||
#define DEFAULT_RFC7273_USE_SYSTEM_CLOCK FALSE
|
||||
|
||||
#define DEFAULT_AUTO_RTX_DELAY (20 * GST_MSECOND)
|
||||
#define DEFAULT_AUTO_RTX_TIMEOUT (40 * GST_MSECOND)
|
||||
|
@ -193,6 +194,7 @@ enum
|
|||
PROP_ADD_REFERENCE_TIMESTAMP_META,
|
||||
PROP_FASTSTART_MIN_PACKETS,
|
||||
PROP_SYNC_INTERVAL,
|
||||
PROP_RFC7273_USE_SYSTEM_CLOCK,
|
||||
};
|
||||
|
||||
#define JBUF_LOCK(priv) G_STMT_START { \
|
||||
|
@ -337,6 +339,7 @@ struct _GstRtpJitterBufferPrivate
|
|||
guint faststart_min_packets;
|
||||
gboolean add_reference_timestamp_meta;
|
||||
guint sync_interval;
|
||||
gboolean rfc7273_use_system_clock;
|
||||
|
||||
/* Reference for GstReferenceTimestampMeta */
|
||||
GstCaps *reference_timestamp_caps;
|
||||
|
@ -997,6 +1000,33 @@ gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass)
|
|||
0, G_MAXUINT, DEFAULT_SYNC_INTERVAL,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* GstRtpJitterBuffer:rfc7273-use-system-clock:
|
||||
*
|
||||
* Uses the system clock as media clock in RFC7273 mode instead of
|
||||
* instantiating an NTP or PTP clock.
|
||||
*
|
||||
* This will always provide the correct sender timestamps in the
|
||||
* `GstReferenceTimestampMeta` as long as the system clock is synced to the
|
||||
* actual media clock with at most a few seconds difference.
|
||||
*
|
||||
* PTS on outgoing buffers would be as accurate as the synchronization
|
||||
* between the actual media clock and the system clock.
|
||||
*
|
||||
* This can be useful if only recovery of the original sender timestamps is
|
||||
* needed and syncing to a PTP/NTP clock would be unnecessarily complex, or
|
||||
* if the system clock already is synchronized to the correct clock and
|
||||
* doing it another time inside GStreamer would be unnecessary.
|
||||
*
|
||||
* Since: 1.24
|
||||
*/
|
||||
g_object_class_install_property (gobject_class, PROP_RFC7273_USE_SYSTEM_CLOCK,
|
||||
g_param_spec_boolean ("rfc7273-use-system-clock",
|
||||
"Use system clock as RFC7273 clock",
|
||||
"Use system clock as RFC7273 media clock (requires system clock "
|
||||
"to be synced externally)", DEFAULT_RFC7273_USE_SYSTEM_CLOCK,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* GstRtpJitterBuffer::request-pt-map:
|
||||
* @buffer: the object which received the signal
|
||||
|
@ -1128,6 +1158,7 @@ gst_rtp_jitter_buffer_init (GstRtpJitterBuffer * jitterbuffer)
|
|||
priv->faststart_min_packets = DEFAULT_FASTSTART_MIN_PACKETS;
|
||||
priv->add_reference_timestamp_meta = DEFAULT_ADD_REFERENCE_TIMESTAMP_META;
|
||||
priv->sync_interval = DEFAULT_SYNC_INTERVAL;
|
||||
priv->rfc7273_use_system_clock = DEFAULT_RFC7273_USE_SYSTEM_CLOCK;
|
||||
|
||||
priv->ts_offset_remainder = 0;
|
||||
priv->last_dts = -1;
|
||||
|
@ -1594,12 +1625,16 @@ gst_jitter_buffer_sink_parse_caps (GstRtpJitterBuffer * jitterbuffer,
|
|||
GST_TIME_ARGS (priv->npt_start), GST_TIME_ARGS (priv->npt_stop));
|
||||
|
||||
if ((ts_refclk = gst_structure_get_string (caps_struct, "a-ts-refclk"))) {
|
||||
gboolean use_system_clock;
|
||||
GstClock *clock = NULL;
|
||||
guint64 clock_offset = -1;
|
||||
gint64 clock_correction = 0;
|
||||
|
||||
GST_DEBUG_OBJECT (jitterbuffer, "Have timestamp reference clock %s",
|
||||
ts_refclk);
|
||||
|
||||
use_system_clock = priv->rfc7273_use_system_clock;
|
||||
|
||||
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");
|
||||
|
@ -1629,7 +1664,15 @@ gst_jitter_buffer_sink_parse_caps (GstRtpJitterBuffer * jitterbuffer,
|
|||
else
|
||||
hostname = g_strdup (host);
|
||||
|
||||
clock = gst_ntp_clock_new (NULL, hostname, port, 0);
|
||||
if (use_system_clock) {
|
||||
clock =
|
||||
g_object_new (GST_TYPE_SYSTEM_CLOCK, "clock-type",
|
||||
GST_CLOCK_TYPE_REALTIME, NULL);
|
||||
/* difference between UNIX epoch and NTP epoch */
|
||||
clock_correction = GST_RTP_NTP_UNIX_OFFSET * GST_SECOND;
|
||||
} else {
|
||||
clock = gst_ntp_clock_new (NULL, hostname, port, 0);
|
||||
}
|
||||
|
||||
ts_meta_ref = gst_caps_new_simple ("timestamp/x-ntp",
|
||||
"host", G_TYPE_STRING, hostname, "port", G_TYPE_INT, port, NULL);
|
||||
|
@ -1644,7 +1687,15 @@ gst_jitter_buffer_sink_parse_caps (GstRtpJitterBuffer * jitterbuffer,
|
|||
if (domainstr[0] != ':' || sscanf (domainstr, ":%u", &domain) != 1)
|
||||
domain = 0;
|
||||
|
||||
clock = gst_ptp_clock_new (NULL, domain);
|
||||
if (use_system_clock) {
|
||||
clock =
|
||||
g_object_new (GST_TYPE_SYSTEM_CLOCK, "clock-type",
|
||||
GST_CLOCK_TYPE_REALTIME, NULL);
|
||||
/* difference between UNIX and PTP/TAI (37 leap seconds as of October 2023) */
|
||||
clock_correction = 37 * GST_SECOND;
|
||||
} else {
|
||||
clock = gst_ptp_clock_new (NULL, domain);
|
||||
}
|
||||
|
||||
ts_meta_ref = gst_caps_new_simple ("timestamp/x-ptp",
|
||||
"version", G_TYPE_STRING, "IEEE1588-2008",
|
||||
|
@ -1652,7 +1703,14 @@ gst_jitter_buffer_sink_parse_caps (GstRtpJitterBuffer * jitterbuffer,
|
|||
} else if (!g_strcmp0 (ts_refclk, "local")) {
|
||||
ts_meta_ref = gst_caps_new_empty_simple ("timestamp/x-ntp");
|
||||
} else {
|
||||
GST_FIXME_OBJECT (jitterbuffer, "Unsupported timestamp reference clock");
|
||||
if (use_system_clock) {
|
||||
clock =
|
||||
g_object_new (GST_TYPE_SYSTEM_CLOCK, "clock-type",
|
||||
GST_CLOCK_TYPE_REALTIME, NULL);
|
||||
} else {
|
||||
GST_FIXME_OBJECT (jitterbuffer,
|
||||
"Unsupported timestamp reference clock");
|
||||
}
|
||||
}
|
||||
|
||||
if ((mediaclk = gst_structure_get_string (caps_struct, "a-mediaclk"))) {
|
||||
|
@ -1668,9 +1726,10 @@ gst_jitter_buffer_sink_parse_caps (GstRtpJitterBuffer * jitterbuffer,
|
|||
}
|
||||
}
|
||||
|
||||
rtp_jitter_buffer_set_media_clock (priv->jbuf, clock, clock_offset);
|
||||
rtp_jitter_buffer_set_media_clock (priv->jbuf, clock, clock_offset,
|
||||
clock_correction);
|
||||
} else {
|
||||
rtp_jitter_buffer_set_media_clock (priv->jbuf, NULL, -1);
|
||||
rtp_jitter_buffer_set_media_clock (priv->jbuf, NULL, -1, 0);
|
||||
ts_meta_ref = gst_caps_new_empty_simple ("timestamp/x-ntp");
|
||||
}
|
||||
|
||||
|
@ -5211,6 +5270,12 @@ gst_rtp_jitter_buffer_set_property (GObject * object,
|
|||
priv->sync_interval = g_value_get_uint (value);
|
||||
JBUF_UNLOCK (priv);
|
||||
break;
|
||||
case PROP_RFC7273_USE_SYSTEM_CLOCK:
|
||||
JBUF_LOCK (priv);
|
||||
priv->rfc7273_use_system_clock = g_value_get_boolean (value);
|
||||
JBUF_UNLOCK (priv);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -5377,6 +5442,11 @@ gst_rtp_jitter_buffer_get_property (GObject * object,
|
|||
g_value_set_uint (value, priv->sync_interval);
|
||||
JBUF_UNLOCK (priv);
|
||||
break;
|
||||
case PROP_RFC7273_USE_SYSTEM_CLOCK:
|
||||
JBUF_LOCK (priv);
|
||||
g_value_set_boolean (value, priv->rfc7273_use_system_clock);
|
||||
JBUF_UNLOCK (priv);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
|
|
@ -288,7 +288,7 @@ media_clock_synced_cb (GstClock * clock, gboolean synced,
|
|||
*/
|
||||
void
|
||||
rtp_jitter_buffer_set_media_clock (RTPJitterBuffer * jbuf, GstClock * clock,
|
||||
guint64 clock_offset)
|
||||
guint64 clock_offset, gint64 clock_correction)
|
||||
{
|
||||
g_mutex_lock (&jbuf->clock_lock);
|
||||
if (jbuf->media_clock) {
|
||||
|
@ -300,6 +300,7 @@ rtp_jitter_buffer_set_media_clock (RTPJitterBuffer * jbuf, GstClock * clock,
|
|||
}
|
||||
jbuf->media_clock = clock;
|
||||
jbuf->media_clock_offset = clock_offset;
|
||||
jbuf->media_clock_correction = clock_correction;
|
||||
|
||||
if (jbuf->pipeline_clock && jbuf->media_clock) {
|
||||
if (same_clock (jbuf->pipeline_clock, jbuf->media_clock)) {
|
||||
|
@ -763,6 +764,7 @@ rtp_jitter_buffer_calculate_pts (RTPJitterBuffer * jbuf, GstClockTime dts,
|
|||
GstClockTime gstrtptime, pts;
|
||||
GstClock *media_clock, *pipeline_clock;
|
||||
guint64 media_clock_offset;
|
||||
gint64 media_clock_correction;
|
||||
gboolean rfc7273_mode;
|
||||
|
||||
*p_ntp_time = GST_CLOCK_TIME_NONE;
|
||||
|
@ -809,6 +811,7 @@ rtp_jitter_buffer_calculate_pts (RTPJitterBuffer * jbuf, GstClockTime dts,
|
|||
pipeline_clock =
|
||||
jbuf->pipeline_clock ? gst_object_ref (jbuf->pipeline_clock) : NULL;
|
||||
media_clock_offset = jbuf->media_clock_offset;
|
||||
media_clock_correction = jbuf->media_clock_correction;
|
||||
g_mutex_unlock (&jbuf->clock_lock);
|
||||
|
||||
gstrtptime =
|
||||
|
@ -944,6 +947,7 @@ rtp_jitter_buffer_calculate_pts (RTPJitterBuffer * jbuf, GstClockTime dts,
|
|||
|
||||
/* Current NTP clock estimation */
|
||||
ntptime = gst_clock_get_internal_time (media_clock);
|
||||
ntptime += media_clock_correction;
|
||||
|
||||
/* Current RTP time based on the estimated NTP clock and the corresponding
|
||||
* RTP time period start */
|
||||
|
@ -1038,6 +1042,11 @@ rtp_jitter_buffer_calculate_pts (RTPJitterBuffer * jbuf, GstClockTime dts,
|
|||
|
||||
*p_ntp_time = ntptime;
|
||||
|
||||
if (media_clock_correction < 0 || ntptime >= media_clock_correction)
|
||||
ntptime -= media_clock_correction;
|
||||
else
|
||||
ntptime = 0;
|
||||
|
||||
/* Packet timestamp converted to the pipeline clock.
|
||||
* Note that this includes again inaccuracy caused by the estimation of
|
||||
* the NTP vs. pipeline clock. */
|
||||
|
|
|
@ -108,6 +108,7 @@ struct _RTPJitterBuffer {
|
|||
GstClock *media_clock;
|
||||
gulong media_clock_synced_id;
|
||||
guint64 media_clock_offset;
|
||||
gint64 media_clock_correction;
|
||||
|
||||
gboolean rfc7273_sync;
|
||||
};
|
||||
|
@ -172,7 +173,7 @@ void rtp_jitter_buffer_set_delay (RTPJitterBuffer *jbuf,
|
|||
void rtp_jitter_buffer_set_clock_rate (RTPJitterBuffer *jbuf, guint32 clock_rate);
|
||||
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_media_clock (RTPJitterBuffer *jbuf, GstClock * clock, guint64 clock_offset, gint64 clock_correction);
|
||||
void rtp_jitter_buffer_set_pipeline_clock (RTPJitterBuffer *jbuf, GstClock * clock);
|
||||
|
||||
gboolean rtp_jitter_buffer_get_rfc7273_sync (RTPJitterBuffer *jbuf);
|
||||
|
|
Loading…
Reference in a new issue