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:
Sebastian Dröge 2023-10-19 20:45:09 +03:00 committed by GStreamer Marge Bot
parent 2956ba48fc
commit eae3ef7461
4 changed files with 99 additions and 7 deletions

View file

@ -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,

View file

@ -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;

View file

@ -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. */

View file

@ -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);