rtpjitterbuffer: Add a faststart-min-packets property

When set this property will allow the jitterbuffer to start delivering
packets as soon as N most recent packets have consecutive seqnum. A
faststart-min-packets of zero disables this feature. This heuristic is
also used in rtpsource which implements the probation mechanism and a
similar heuristic is used to handle long gaps.

https://bugzilla.gnome.org/show_bug.cgi?id=769536
This commit is contained in:
Nicolas Dufresne 2017-06-22 15:34:42 -04:00
parent 244c7017ee
commit bbe0053f8a
3 changed files with 107 additions and 1 deletions

View file

@ -149,6 +149,7 @@ enum
#define DEFAULT_MAX_DROPOUT_TIME 60000
#define DEFAULT_MAX_MISORDER_TIME 2000
#define DEFAULT_RFC7273_SYNC FALSE
#define DEFAULT_FASTSTART_MIN_PACKETS 0
#define DEFAULT_AUTO_RTX_DELAY (20 * GST_MSECOND)
#define DEFAULT_AUTO_RTX_TIMEOUT (40 * GST_MSECOND)
@ -177,7 +178,8 @@ enum
PROP_MAX_RTCP_RTP_TIME_DIFF,
PROP_MAX_DROPOUT_TIME,
PROP_MAX_MISORDER_TIME,
PROP_RFC7273_SYNC
PROP_RFC7273_SYNC,
PROP_FASTSTART_MIN_PACKETS
};
#define JBUF_LOCK(priv) G_STMT_START { \
@ -294,6 +296,7 @@ struct _GstRtpJitterBufferPrivate
gint max_rtcp_rtp_time_diff;
guint32 max_dropout_time;
guint32 max_misorder_time;
guint faststart_min_packets;
/* the last seqnum we pushed out */
guint32 last_popped_seqnum;
@ -851,6 +854,23 @@ gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass)
"(requires clock and offset to be provided)", DEFAULT_RFC7273_SYNC,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstRtpJitterBuffer:faststart-min-packets
*
* The number of consecutive packets needed to start (set to 0 to
* disable faststart. The jitterbuffer will by default start after the
* latency has elapsed)
*
* Since: 1.14
*/
g_object_class_install_property (gobject_class, PROP_FASTSTART_MIN_PACKETS,
g_param_spec_uint ("faststart-min-packets", "Faststart minimum packets",
"The number of consecutive packets needed to start (set to 0 to "
"disable faststart. The jitterbuffer will by default start after "
"the latency has elapsed)",
0, G_MAXUINT, DEFAULT_FASTSTART_MIN_PACKETS,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstRtpJitterBuffer::request-pt-map:
* @buffer: the object which received the signal
@ -975,6 +995,7 @@ gst_rtp_jitter_buffer_init (GstRtpJitterBuffer * jitterbuffer)
priv->max_rtcp_rtp_time_diff = DEFAULT_MAX_RTCP_RTP_TIME_DIFF;
priv->max_dropout_time = DEFAULT_MAX_DROPOUT_TIME;
priv->max_misorder_time = DEFAULT_MAX_MISORDER_TIME;
priv->faststart_min_packets = DEFAULT_FASTSTART_MIN_PACKETS;
priv->last_dts = -1;
priv->last_rtptime = -1;
@ -2784,6 +2805,37 @@ gst_rtp_jitter_buffer_reset (GstRtpJitterBuffer * jitterbuffer,
return ret;
}
static gboolean
gst_rtp_jitter_buffer_fast_start (GstRtpJitterBuffer * jitterbuffer)
{
GstRtpJitterBufferPrivate *priv;
RTPJitterBufferItem *item;
TimerData *timer;
priv = jitterbuffer->priv;
if (priv->faststart_min_packets == 0)
return FALSE;
item = rtp_jitter_buffer_peek (priv->jbuf);
if (!item)
return FALSE;
timer = find_timer (jitterbuffer, item->seqnum);
if (!timer || timer->type != TIMER_TYPE_DEADLINE)
return FALSE;
if (rtp_jitter_buffer_can_fast_start (priv->jbuf,
priv->faststart_min_packets)) {
GST_INFO_OBJECT (jitterbuffer, "We found %i consecutive packet, start now",
priv->faststart_min_packets);
timer->timeout = -1;
return TRUE;
}
return FALSE;
}
static GstFlowReturn
gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent,
GstBuffer * buffer)
@ -3096,6 +3148,10 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent,
goto duplicate;
}
/* Trigger fast start if needed */
if (gst_rtp_jitter_buffer_fast_start (jitterbuffer))
head = TRUE;
/* update timers */
update_timers (jitterbuffer, seqnum, dts, pts, do_next_seqnum,
GST_BUFFER_IS_RETRANSMISSION (buffer), timer);
@ -4514,6 +4570,11 @@ gst_rtp_jitter_buffer_set_property (GObject * object,
g_value_get_boolean (value));
JBUF_UNLOCK (priv);
break;
case PROP_FASTSTART_MIN_PACKETS:
JBUF_LOCK (priv);
priv->faststart_min_packets = g_value_get_uint (value);
JBUF_UNLOCK (priv);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -4650,6 +4711,11 @@ gst_rtp_jitter_buffer_get_property (GObject * object,
rtp_jitter_buffer_get_rfc7273_sync (priv->jbuf));
JBUF_UNLOCK (priv);
break;
case PROP_FASTSTART_MIN_PACKETS:
JBUF_LOCK (priv);
g_value_set_uint (value, priv->faststart_min_packets);
JBUF_UNLOCK (priv);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;

View file

@ -1257,3 +1257,41 @@ rtp_jitter_buffer_get_sync (RTPJitterBuffer * jbuf, guint64 * rtptime,
if (last_rtptime)
*last_rtptime = jbuf->last_rtptime;
}
/**
* rtp_jitter_buffer_can_fast_start:
* @jbuf: an #RTPJitterBuffer
* @num_packets: Number of consecutive packets needed
*
* Check if in the queue if there is enough packets with consecutive seqnum in
* order to start delivering them.
*
* Returns: %TRUE if the required number of consecutive packets was found.
*/
gboolean
rtp_jitter_buffer_can_fast_start (RTPJitterBuffer * jbuf, gint num_packet)
{
gboolean ret = TRUE;
RTPJitterBufferItem *last_item = NULL, *item;
gint i;
if (rtp_jitter_buffer_num_packets (jbuf) < num_packet)
return FALSE;
item = rtp_jitter_buffer_peek (jbuf);
for (i = 0; i < num_packet; i++) {
if (G_LIKELY (last_item)) {
guint16 expected_seqnum = last_item->seqnum + 1;
if (expected_seqnum != item->seqnum) {
ret = FALSE;
break;
}
}
last_item = item;
item = (RTPJitterBufferItem *) last_item->next;
}
return ret;
}

View file

@ -192,4 +192,6 @@ void rtp_jitter_buffer_get_sync (RTPJitterBuffer *jbuf,
GstClockTime rtp_jitter_buffer_calculate_pts (RTPJitterBuffer * jbuf, GstClockTime dts, gboolean estimated_dts,
guint32 rtptime, GstClockTime base_time);
gboolean rtp_jitter_buffer_can_fast_start (RTPJitterBuffer * jbuf, gint num_packet);
#endif /* __RTP_JITTER_BUFFER_H__ */