rtpbin: Allow synchronizing against RTP-Info without having received any RTCP

Previously the information was provided from rtpjitterbuffer to rtpbin
only once the first RTCP SR was received, which is not necessary at all
as all required information is available from the caps already.

Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1162

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6543>
This commit is contained in:
Sebastian Dröge 2024-04-17 17:31:28 +03:00 committed by GStreamer Marge Bot
parent 8bfba72ea4
commit 95a0649945
2 changed files with 103 additions and 0 deletions

View file

@ -1652,6 +1652,9 @@ gst_rtp_bin_associate (GstRtpBin * bin, GstRtpBinStream * stream,
rtp_info_sync = TRUE; rtp_info_sync = TRUE;
GST_DEBUG_OBJECT (bin, "Doing RTP-Info sync"); GST_DEBUG_OBJECT (bin, "Doing RTP-Info sync");
} else if (!client->cname) {
GST_DEBUG_OBJECT (bin, "Have no CNAME yet");
return;
} else { } else {
GST_DEBUG_OBJECT (bin, "Doing RTCP sync"); GST_DEBUG_OBJECT (bin, "Doing RTCP sync");
} }
@ -1661,6 +1664,9 @@ gst_rtp_bin_associate (GstRtpBin * bin, GstRtpBinStream * stream,
if (!GST_CLOCK_TIME_IS_VALID (npt_start)) { if (!GST_CLOCK_TIME_IS_VALID (npt_start)) {
GST_DEBUG_OBJECT (bin, "invalidated sync data, bailing out"); GST_DEBUG_OBJECT (bin, "invalidated sync data, bailing out");
return; return;
} else if (!client->cname) {
GST_DEBUG_OBJECT (bin, "Have no CNAME yet");
return;
} }
rtp_info_sync = TRUE; rtp_info_sync = TRUE;
@ -1987,6 +1993,22 @@ gst_rtp_bin_handle_sync (GstElement * jitterbuffer, GstStructure * s,
if (!gst_structure_get_uint64 (s, "sr-ext-rtptime", &extrtptime) if (!gst_structure_get_uint64 (s, "sr-ext-rtptime", &extrtptime)
|| !gst_structure_has_field_typed (s, "sr-buffer", GST_TYPE_BUFFER)) { || !gst_structure_has_field_typed (s, "sr-buffer", GST_TYPE_BUFFER)) {
/* Do initial RTSP sync if allowed */
if (npt_start != GST_CLOCK_TIME_NONE
&& gst_structure_get_uint (s, "ssrc", &ssrc)) {
GST_DEBUG_OBJECT (bin, "handle sync from RTSP information for SSRC %08x",
ssrc);
if (ssrc != stream->ssrc)
return;
GST_RTP_BIN_LOCK (bin);
gst_rtp_bin_associate (bin, stream, cname ? strlen (cname) : 0,
(const guint8 *) cname, GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE,
base_rtptime, base_time, clock_rate, clock_base, npt_start);
GST_RTP_BIN_UNLOCK (bin);
return;
}
/* invalid structure */ /* invalid structure */
return; return;
} }

View file

@ -396,6 +396,7 @@ struct _GstRtpJitterBufferPrivate
gint32 clock_rate; gint32 clock_rate;
gint64 clock_base; gint64 clock_base;
gint64 ts_offset_remainder; gint64 ts_offset_remainder;
gboolean rtsp_sync_done;
/* when we are shutting down */ /* when we are shutting down */
GstFlowReturn srcresult; GstFlowReturn srcresult;
@ -582,6 +583,7 @@ gst_rtp_jitter_buffer_set_active (GstRtpJitterBuffer * jitterbuffer,
static void do_handle_sync (GstRtpJitterBuffer * jitterbuffer); static void do_handle_sync (GstRtpJitterBuffer * jitterbuffer);
static void do_handle_sync_inband (GstRtpJitterBuffer * jitterbuffer, static void do_handle_sync_inband (GstRtpJitterBuffer * jitterbuffer,
guint64 ntpnstime); guint64 ntpnstime);
static void do_handle_sync_rtsp (GstRtpJitterBuffer * jitterbuffer);
static void unschedule_current_timer (GstRtpJitterBuffer * jitterbuffer); static void unschedule_current_timer (GstRtpJitterBuffer * jitterbuffer);
@ -1219,6 +1221,7 @@ gst_rtp_jitter_buffer_init (GstRtpJitterBuffer * jitterbuffer)
rtp_jitter_buffer_set_delay (priv->jbuf, priv->latency_ns); rtp_jitter_buffer_set_delay (priv->jbuf, priv->latency_ns);
rtp_jitter_buffer_set_buffering (priv->jbuf, FALSE); rtp_jitter_buffer_set_buffering (priv->jbuf, FALSE);
priv->active = TRUE; priv->active = TRUE;
priv->rtsp_sync_done = FALSE;
priv->srcpad = priv->srcpad =
gst_pad_new_from_static_template (&gst_rtp_jitter_buffer_src_template, gst_pad_new_from_static_template (&gst_rtp_jitter_buffer_src_template,
@ -1461,6 +1464,7 @@ gst_rtp_jitter_buffer_clear_pt_map (GstRtpJitterBuffer * jitterbuffer)
/* do not clear current content, but refresh state for new arrival */ /* do not clear current content, but refresh state for new arrival */
GST_DEBUG_OBJECT (jitterbuffer, "reset jitterbuffer"); GST_DEBUG_OBJECT (jitterbuffer, "reset jitterbuffer");
rtp_jitter_buffer_reset_skew (priv->jbuf); rtp_jitter_buffer_reset_skew (priv->jbuf);
priv->rtsp_sync_done = FALSE;
JBUF_UNLOCK (priv); JBUF_UNLOCK (priv);
} }
@ -1652,6 +1656,8 @@ gst_jitter_buffer_sink_parse_caps (GstRtpJitterBuffer * jitterbuffer,
else else
priv->npt_stop = -1; priv->npt_stop = -1;
priv->rtsp_sync_done = FALSE;
GST_DEBUG_OBJECT (jitterbuffer, GST_DEBUG_OBJECT (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));
@ -1855,6 +1861,7 @@ gst_rtp_jitter_buffer_flush_stop (GstRtpJitterBuffer * jitterbuffer)
rtp_jitter_buffer_flush (priv->jbuf, NULL, NULL); rtp_jitter_buffer_flush (priv->jbuf, NULL, NULL);
rtp_jitter_buffer_disable_buffering (priv->jbuf, FALSE); rtp_jitter_buffer_disable_buffering (priv->jbuf, FALSE);
rtp_jitter_buffer_reset_skew (priv->jbuf); rtp_jitter_buffer_reset_skew (priv->jbuf);
priv->rtsp_sync_done = FALSE;
rtp_timer_queue_remove_all (priv->timers); rtp_timer_queue_remove_all (priv->timers);
g_queue_foreach (&priv->gap_packets, (GFunc) gst_buffer_unref, NULL); g_queue_foreach (&priv->gap_packets, (GFunc) gst_buffer_unref, NULL);
g_queue_clear (&priv->gap_packets); g_queue_clear (&priv->gap_packets);
@ -3074,6 +3081,7 @@ gst_rtp_jitter_buffer_reset (GstRtpJitterBuffer * jitterbuffer,
rtp_timer_queue_remove_all (priv->timers); rtp_timer_queue_remove_all (priv->timers);
priv->discont = TRUE; priv->discont = TRUE;
priv->last_popped_seqnum = -1; priv->last_popped_seqnum = -1;
priv->rtsp_sync_done = FALSE;
if (priv->gap_packets.head) { if (priv->gap_packets.head) {
GstBuffer *gap_buffer = priv->gap_packets.head->data; GstBuffer *gap_buffer = priv->gap_packets.head->data;
@ -3643,6 +3651,9 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent,
update_rtx_timers (jitterbuffer, seqnum, dts, pts, do_next_seqnum, is_rtx, update_rtx_timers (jitterbuffer, seqnum, dts, pts, do_next_seqnum, is_rtx,
g_steal_pointer (&timer)); g_steal_pointer (&timer));
if (priv->seqnum_base != -1)
do_handle_sync_rtsp (jitterbuffer);
/* we had an unhandled SR, handle it now */ /* we had an unhandled SR, handle it now */
if (priv->last_sr) if (priv->last_sr)
do_handle_sync (jitterbuffer); do_handle_sync (jitterbuffer);
@ -4635,6 +4646,76 @@ pause:
} }
} }
static void
do_handle_sync_rtsp (GstRtpJitterBuffer * jitterbuffer)
{
GstRtpJitterBufferPrivate *priv;
guint64 base_rtptime, base_time;
guint32 clock_rate;
guint64 clock_base;
guint64 npt_start;
priv = jitterbuffer->priv;
if (priv->rtsp_sync_done)
return;
/* no RTSP information in the caps */
if (priv->clock_base == -1 || priv->npt_start == -1) {
priv->rtsp_sync_done = TRUE;
return;
}
/* get the last values from the jitterbuffer */
rtp_jitter_buffer_get_sync (priv->jbuf, &base_rtptime, &base_time,
&clock_rate, NULL);
/* clock-base is the RTP timestamp at npt-start */
npt_start = priv->npt_start;
clock_base = priv->clock_base;
GST_DEBUG_OBJECT (jitterbuffer,
"NPT start %" GST_TIME_FORMAT ", clock-base %" G_GUINT64_FORMAT ", base %"
GST_TIME_FORMAT ", base RTP time %" G_GUINT64_FORMAT ", clock-rate %"
G_GUINT32_FORMAT, GST_TIME_ARGS (npt_start), clock_base,
GST_TIME_ARGS (base_time), base_rtptime, clock_rate);
if (base_rtptime == -1 || clock_rate == -1 || base_time == -1) {
GST_ERROR_OBJECT (jitterbuffer,
"No base RTP time, clock rate or base time");
priv->rtsp_sync_done = TRUE;
return;
}
GstStructure *s;
GList *l;
s = gst_structure_new ("application/x-rtp-sync",
"base-rtptime", G_TYPE_UINT64, base_rtptime,
"base-time", G_TYPE_UINT64, base_time,
"clock-rate", G_TYPE_UINT, clock_rate,
"clock-base", G_TYPE_UINT64, clock_base & G_MAXUINT32,
"npt-start", G_TYPE_UINT64, npt_start,
"ssrc", G_TYPE_UINT, priv->last_ssrc, NULL);
for (l = priv->cname_ssrc_mappings; l; l = l->next) {
const CNameSSRCMapping *map = l->data;
if (map->ssrc == priv->last_ssrc) {
gst_structure_set (s, "cname", G_TYPE_STRING, map->cname, NULL);
break;
}
}
GST_DEBUG_OBJECT (jitterbuffer, "signaling sync");
JBUF_UNLOCK (priv);
g_signal_emit (jitterbuffer,
gst_rtp_jitter_buffer_signals[SIGNAL_HANDLE_SYNC], 0, s);
JBUF_LOCK (priv);
gst_structure_free (s);
priv->rtsp_sync_done = TRUE;
}
static void static void
do_handle_sync_inband (GstRtpJitterBuffer * jitterbuffer, guint64 ntpnstime) do_handle_sync_inband (GstRtpJitterBuffer * jitterbuffer, guint64 ntpnstime)
{ {