mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-07 16:08:51 +00:00
jitterbuffer: make sure time does not go backwards
When we construct a timestamp that would result in a timestamp that is earlier than when the packet was received, reset the skew calculation as this is probably a sign that the sender restarted or paused. Fixes #593354
This commit is contained in:
parent
bfb1260af4
commit
8d924611e7
3 changed files with 36 additions and 22 deletions
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Farsight Voice+Video library
|
* Farsight Voice+Video library
|
||||||
*
|
*
|
||||||
* Copyright 2007 Collabora Ltd,
|
* Copyright 2007 Collabora Ltd,
|
||||||
* Copyright 2007 Nokia Corporation
|
* Copyright 2007 Nokia Corporation
|
||||||
* @author: Philippe Kalaf <philippe.kalaf@collabora.co.uk>.
|
* @author: Philippe Kalaf <philippe.kalaf@collabora.co.uk>.
|
||||||
* Copyright 2007 Wim Taymans <wim.taymans@gmail.com>
|
* Copyright 2007 Wim Taymans <wim.taymans@gmail.com>
|
||||||
|
@ -30,17 +30,17 @@
|
||||||
* from a network source. It will also wait for missing packets up to a
|
* from a network source. It will also wait for missing packets up to a
|
||||||
* configurable time limit using the #GstRtpJitterBuffer:latency property.
|
* configurable time limit using the #GstRtpJitterBuffer:latency property.
|
||||||
* Packets arriving too late are considered to be lost packets.
|
* Packets arriving too late are considered to be lost packets.
|
||||||
*
|
*
|
||||||
* This element acts as a live element and so adds #GstRtpJitterBuffer:latency
|
* This element acts as a live element and so adds #GstRtpJitterBuffer:latency
|
||||||
* to the pipeline.
|
* to the pipeline.
|
||||||
*
|
*
|
||||||
* The element needs the clock-rate of the RTP payload in order to estimate the
|
* The element needs the clock-rate of the RTP payload in order to estimate the
|
||||||
* delay. This information is obtained either from the caps on the sink pad or,
|
* delay. This information is obtained either from the caps on the sink pad or,
|
||||||
* when no caps are present, from the #GstRtpJitterBuffer::request-pt-map signal.
|
* when no caps are present, from the #GstRtpJitterBuffer::request-pt-map signal.
|
||||||
* To clear the previous pt-map use the #GstRtpJitterBuffer::clear-pt-map signal.
|
* To clear the previous pt-map use the #GstRtpJitterBuffer::clear-pt-map signal.
|
||||||
*
|
*
|
||||||
* This element will automatically be used inside gstrtpbin.
|
* This element will automatically be used inside gstrtpbin.
|
||||||
*
|
*
|
||||||
* <refsect2>
|
* <refsect2>
|
||||||
* <title>Example pipelines</title>
|
* <title>Example pipelines</title>
|
||||||
* |[
|
* |[
|
||||||
|
@ -300,7 +300,7 @@ gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GstRtpJitterBuffer::latency:
|
* GstRtpJitterBuffer::latency:
|
||||||
*
|
*
|
||||||
* The maximum latency of the jitterbuffer. Packets will be kept in the buffer
|
* The maximum latency of the jitterbuffer. Packets will be kept in the buffer
|
||||||
* for at most this time.
|
* for at most this time.
|
||||||
*/
|
*/
|
||||||
|
@ -310,8 +310,8 @@ gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass)
|
||||||
G_PARAM_READWRITE));
|
G_PARAM_READWRITE));
|
||||||
/**
|
/**
|
||||||
* GstRtpJitterBuffer::drop-on-latency:
|
* GstRtpJitterBuffer::drop-on-latency:
|
||||||
*
|
*
|
||||||
* Drop oldest buffers when the queue is completely filled.
|
* Drop oldest buffers when the queue is completely filled.
|
||||||
*/
|
*/
|
||||||
g_object_class_install_property (gobject_class, PROP_DROP_ON_LATENCY,
|
g_object_class_install_property (gobject_class, PROP_DROP_ON_LATENCY,
|
||||||
g_param_spec_boolean ("drop-on-latency",
|
g_param_spec_boolean ("drop-on-latency",
|
||||||
|
@ -320,7 +320,7 @@ gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass)
|
||||||
DEFAULT_DROP_ON_LATENCY, G_PARAM_READWRITE));
|
DEFAULT_DROP_ON_LATENCY, G_PARAM_READWRITE));
|
||||||
/**
|
/**
|
||||||
* GstRtpJitterBuffer::ts-offset:
|
* GstRtpJitterBuffer::ts-offset:
|
||||||
*
|
*
|
||||||
* Adjust GStreamer output buffer timestamps in the jitterbuffer with offset.
|
* Adjust GStreamer output buffer timestamps in the jitterbuffer with offset.
|
||||||
* This is mainly used to ensure interstream synchronisation.
|
* This is mainly used to ensure interstream synchronisation.
|
||||||
*/
|
*/
|
||||||
|
@ -332,7 +332,7 @@ gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GstRtpJitterBuffer::do-lost:
|
* GstRtpJitterBuffer::do-lost:
|
||||||
*
|
*
|
||||||
* Send out a GstRTPPacketLost event downstream when a packet is considered
|
* Send out a GstRTPPacketLost event downstream when a packet is considered
|
||||||
* lost.
|
* lost.
|
||||||
*/
|
*/
|
||||||
|
@ -761,7 +761,7 @@ gst_rtp_jitter_buffer_flush_start (GstRtpJitterBuffer * jitterbuffer)
|
||||||
GST_DEBUG_OBJECT (jitterbuffer, "Disabling pop on queue");
|
GST_DEBUG_OBJECT (jitterbuffer, "Disabling pop on queue");
|
||||||
/* this unblocks any waiting pops on the src pad task */
|
/* this unblocks any waiting pops on the src pad task */
|
||||||
JBUF_SIGNAL (priv);
|
JBUF_SIGNAL (priv);
|
||||||
/* unlock clock, we just unschedule, the entry will be released by the
|
/* unlock clock, we just unschedule, the entry will be released by the
|
||||||
* locking streaming thread. */
|
* locking streaming thread. */
|
||||||
if (priv->clock_id) {
|
if (priv->clock_id) {
|
||||||
gst_clock_id_unschedule (priv->clock_id);
|
gst_clock_id_unschedule (priv->clock_id);
|
||||||
|
@ -1211,7 +1211,7 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
* 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, buffer, timestamp,
|
if (G_UNLIKELY (!rtp_jitter_buffer_insert (priv->jbuf, buffer, timestamp,
|
||||||
priv->clock_rate, &tail)))
|
priv->clock_rate, (priv->latency_ms * GST_MSECOND), &tail)))
|
||||||
goto duplicate;
|
goto duplicate;
|
||||||
|
|
||||||
/* signal addition of new buffer when the _loop is waiting. */
|
/* signal addition of new buffer when the _loop is waiting. */
|
||||||
|
|
|
@ -183,7 +183,7 @@ rtp_jitter_buffer_resync (RTPJitterBuffer * jbuf, GstClockTime time,
|
||||||
*
|
*
|
||||||
* Both the window and the weighting used for averaging influence the accuracy
|
* Both the window and the weighting used for averaging influence the accuracy
|
||||||
* of the drift estimation. Finding the correct parameters turns out to be a
|
* of the drift estimation. Finding the correct parameters turns out to be a
|
||||||
* compromise between accuracy and inertia.
|
* compromise between accuracy and inertia.
|
||||||
*
|
*
|
||||||
* We use a 2 second window or up to 512 data points, which is statistically big
|
* We use a 2 second window or up to 512 data points, which is statistically big
|
||||||
* enough to catch spikes (FIXME, detect spikes).
|
* enough to catch spikes (FIXME, detect spikes).
|
||||||
|
@ -195,7 +195,7 @@ rtp_jitter_buffer_resync (RTPJitterBuffer * jbuf, GstClockTime time,
|
||||||
*/
|
*/
|
||||||
static GstClockTime
|
static GstClockTime
|
||||||
calculate_skew (RTPJitterBuffer * jbuf, guint32 rtptime, GstClockTime time,
|
calculate_skew (RTPJitterBuffer * jbuf, guint32 rtptime, GstClockTime time,
|
||||||
guint32 clock_rate)
|
guint32 clock_rate, GstClockTime max_delay)
|
||||||
{
|
{
|
||||||
guint64 ext_rtptime;
|
guint64 ext_rtptime;
|
||||||
guint64 send_diff, recv_diff;
|
guint64 send_diff, recv_diff;
|
||||||
|
@ -278,7 +278,7 @@ calculate_skew (RTPJitterBuffer * jbuf, guint32 rtptime, GstClockTime time,
|
||||||
* changed too quickly we have to resync because the server likely restarted
|
* changed too quickly we have to resync because the server likely restarted
|
||||||
* its timestamps. */
|
* its timestamps. */
|
||||||
if (ABS (delta - jbuf->skew) > GST_SECOND) {
|
if (ABS (delta - jbuf->skew) > GST_SECOND) {
|
||||||
GST_WARNING ("delta %" GST_TIME_FORMAT " too big, reset skew",
|
GST_WARNING ("delta - skew: %" GST_TIME_FORMAT " too big, reset skew",
|
||||||
GST_TIME_ARGS (delta - jbuf->skew));
|
GST_TIME_ARGS (delta - jbuf->skew));
|
||||||
rtp_jitter_buffer_resync (jbuf, time, gstrtptime, ext_rtptime, TRUE);
|
rtp_jitter_buffer_resync (jbuf, time, gstrtptime, ext_rtptime, TRUE);
|
||||||
send_diff = 0;
|
send_diff = 0;
|
||||||
|
@ -386,6 +386,18 @@ no_skew:
|
||||||
out_time = jbuf->prev_out_time;
|
out_time = jbuf->prev_out_time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (out_time + max_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),
|
||||||
|
max_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;
|
||||||
|
|
||||||
|
@ -404,6 +416,7 @@ no_skew:
|
||||||
* @buf: a buffer
|
* @buf: a buffer
|
||||||
* @time: a running_time when this buffer was received in nanoseconds
|
* @time: a running_time when this buffer was received in nanoseconds
|
||||||
* @clock_rate: the clock-rate of the payload of @buf
|
* @clock_rate: the clock-rate of the payload of @buf
|
||||||
|
* @max_delay: the maximum lateness of @buf
|
||||||
* @tail: TRUE when the tail element changed.
|
* @tail: TRUE when the tail element changed.
|
||||||
*
|
*
|
||||||
* Inserts @buf into the packet queue of @jbuf. The sequence number of the
|
* Inserts @buf into the packet queue of @jbuf. The sequence number of the
|
||||||
|
@ -415,7 +428,8 @@ no_skew:
|
||||||
*/
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
rtp_jitter_buffer_insert (RTPJitterBuffer * jbuf, GstBuffer * buf,
|
rtp_jitter_buffer_insert (RTPJitterBuffer * jbuf, GstBuffer * buf,
|
||||||
GstClockTime time, guint32 clock_rate, gboolean * tail)
|
GstClockTime time, guint32 clock_rate, GstClockTime max_delay,
|
||||||
|
gboolean * tail)
|
||||||
{
|
{
|
||||||
GList *list;
|
GList *list;
|
||||||
guint32 rtptime;
|
guint32 rtptime;
|
||||||
|
@ -449,7 +463,7 @@ rtp_jitter_buffer_insert (RTPJitterBuffer * jbuf, GstBuffer * buf,
|
||||||
* receive time, this function will retimestamp @buf with the skew corrected
|
* receive time, this function will retimestamp @buf with the skew corrected
|
||||||
* running time. */
|
* running time. */
|
||||||
rtptime = gst_rtp_buffer_get_timestamp (buf);
|
rtptime = gst_rtp_buffer_get_timestamp (buf);
|
||||||
time = calculate_skew (jbuf, rtptime, time, clock_rate);
|
time = calculate_skew (jbuf, rtptime, time, clock_rate, max_delay);
|
||||||
GST_BUFFER_TIMESTAMP (buf) = time;
|
GST_BUFFER_TIMESTAMP (buf) = time;
|
||||||
|
|
||||||
/* It's more likely that the packet was inserted in the front of the buffer */
|
/* It's more likely that the packet was inserted in the front of the buffer */
|
||||||
|
|
|
@ -82,9 +82,10 @@ RTPJitterBuffer* rtp_jitter_buffer_new (void);
|
||||||
void rtp_jitter_buffer_reset_skew (RTPJitterBuffer *jbuf);
|
void rtp_jitter_buffer_reset_skew (RTPJitterBuffer *jbuf);
|
||||||
|
|
||||||
gboolean rtp_jitter_buffer_insert (RTPJitterBuffer *jbuf, GstBuffer *buf,
|
gboolean rtp_jitter_buffer_insert (RTPJitterBuffer *jbuf, GstBuffer *buf,
|
||||||
GstClockTime time,
|
GstClockTime time,
|
||||||
guint32 clock_rate,
|
guint32 clock_rate,
|
||||||
gboolean *tail);
|
GstClockTime max_delay,
|
||||||
|
gboolean *tail);
|
||||||
GstBuffer * rtp_jitter_buffer_peek (RTPJitterBuffer *jbuf);
|
GstBuffer * rtp_jitter_buffer_peek (RTPJitterBuffer *jbuf);
|
||||||
GstBuffer * rtp_jitter_buffer_pop (RTPJitterBuffer *jbuf);
|
GstBuffer * rtp_jitter_buffer_pop (RTPJitterBuffer *jbuf);
|
||||||
|
|
||||||
|
@ -95,7 +96,6 @@ guint32 rtp_jitter_buffer_get_ts_diff (RTPJitterBuffer *jbuf)
|
||||||
|
|
||||||
void rtp_jitter_buffer_get_sync (RTPJitterBuffer *jbuf, guint64 *rtptime,
|
void rtp_jitter_buffer_get_sync (RTPJitterBuffer *jbuf, guint64 *rtptime,
|
||||||
guint64 *timestamp, guint32 *clock_rate,
|
guint64 *timestamp, guint32 *clock_rate,
|
||||||
guint64 *last_rtptime);
|
guint64 *last_rtptime);
|
||||||
|
|
||||||
|
|
||||||
#endif /* __RTP_JITTER_BUFFER_H__ */
|
#endif /* __RTP_JITTER_BUFFER_H__ */
|
||||||
|
|
Loading…
Reference in a new issue