diff --git a/gst/rtpmanager/gstrtpjitterbuffer.c b/gst/rtpmanager/gstrtpjitterbuffer.c index 64f05dc41f..8574f1743f 100644 --- a/gst/rtpmanager/gstrtpjitterbuffer.c +++ b/gst/rtpmanager/gstrtpjitterbuffer.c @@ -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; diff --git a/gst/rtpmanager/rtpjitterbuffer.c b/gst/rtpmanager/rtpjitterbuffer.c index a706d6283a..f1187e2b69 100644 --- a/gst/rtpmanager/rtpjitterbuffer.c +++ b/gst/rtpmanager/rtpjitterbuffer.c @@ -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; +} diff --git a/gst/rtpmanager/rtpjitterbuffer.h b/gst/rtpmanager/rtpjitterbuffer.h index 4d3c6fe16e..16db644720 100644 --- a/gst/rtpmanager/rtpjitterbuffer.h +++ b/gst/rtpmanager/rtpjitterbuffer.h @@ -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__ */