Commit 3e11ce43 authored by Wim Taymans's avatar Wim Taymans

jitterbuffer: improve EOS handling

Make a new method to disable the jitterbuffer buffering.
Rework the update_estimated_eos() method. Calculate how much time
there is left to play. If we have less than the delay of the
jitterbuffer, we disabled buffering because we might never be able to
fill the complete jitterbuffer again.
If we receive an EOS event, disable buffering. We will drain the
buffer and eventually push the EOS event out.
When we reach the estimated NPT timeout and we didn't receive an EOS
event, make one and queue it so that it can be pushed.

Fixes https://bugzilla.gnome.org/show_bug.cgi?id=728017
parent 38a486b3
......@@ -1184,6 +1184,7 @@ gst_rtp_jitter_buffer_flush_stop (GstRtpJitterBuffer * jitterbuffer)
priv->last_rtptime = -1;
GST_DEBUG_OBJECT (jitterbuffer, "flush and reset jitterbuffer");
rtp_jitter_buffer_flush (priv->jbuf, (GFunc) free_item, NULL);
rtp_jitter_buffer_disable_buffering (priv->jbuf, FALSE);
rtp_jitter_buffer_reset_skew (priv->jbuf);
remove_all_timers (jitterbuffer);
JBUF_UNLOCK (priv);
......@@ -1378,6 +1379,7 @@ queue_event (GstRtpJitterBuffer * jitterbuffer, GstEvent * event)
break;
case GST_EVENT_EOS:
priv->eos = TRUE;
rtp_jitter_buffer_disable_buffering (priv->jbuf, TRUE);
break;
default:
break;
......@@ -1575,14 +1577,6 @@ check_buffering_percent (GstRtpJitterBuffer * jitterbuffer, gint percent)
if (percent == -1)
return NULL;
if (priv->eos || (priv->npt_stop != -1 &&
priv->npt_stop - priv->npt_start <=
rtp_jitter_buffer_get_delay (priv->jbuf))) {
GST_DEBUG_OBJECT (jitterbuffer, "short stream; faking full buffer");
rtp_jitter_buffer_set_buffering (priv->jbuf, FALSE);
percent = 100;
}
/* Post a buffering message */
if (priv->last_percent != percent) {
priv->last_percent = percent;
......@@ -2387,45 +2381,61 @@ static void
update_estimated_eos (GstRtpJitterBuffer * jitterbuffer,
RTPJitterBufferItem * item)
{
guint64 total, elapsed, left, estimated;
GstClockTime out_time;
GstRtpJitterBufferPrivate *priv = jitterbuffer->priv;
if (priv->npt_stop != -1 && priv->ext_timestamp != -1
&& priv->clock_base != -1 && priv->clock_rate > 0) {
guint64 elapsed, estimated;
elapsed = compute_elapsed (jitterbuffer, item);
if (elapsed > priv->last_elapsed || !priv->last_elapsed) {
guint64 left;
GstClockTime out_time;
if (priv->npt_stop == -1 || priv->ext_timestamp == -1
|| priv->clock_base == -1 || priv->clock_rate <= 0)
return;
priv->last_elapsed = elapsed;
/* compute the elapsed time */
elapsed = compute_elapsed (jitterbuffer, item);
left = priv->npt_stop - priv->npt_start;
GST_LOG_OBJECT (jitterbuffer, "left %" GST_TIME_FORMAT,
GST_TIME_ARGS (left));
/* do nothing if elapsed time doesn't increment */
if (priv->last_elapsed && elapsed <= priv->last_elapsed)
return;
out_time = item->dts;
priv->last_elapsed = elapsed;
if (elapsed > 0)
estimated = gst_util_uint64_scale (out_time, left, elapsed);
else {
/* if there is almost nothing left,
* we may never advance enough to end up in the above case */
if (left < GST_SECOND)
estimated = GST_SECOND;
else
estimated = -1;
}
/* this is the total time we need to play */
total = priv->npt_stop - priv->npt_start;
GST_LOG_OBJECT (jitterbuffer, "total %" GST_TIME_FORMAT,
GST_TIME_ARGS (total));
GST_LOG_OBJECT (jitterbuffer, "elapsed %" GST_TIME_FORMAT ", estimated %"
GST_TIME_FORMAT, GST_TIME_ARGS (elapsed), GST_TIME_ARGS (estimated));
/* this is how much time there is left */
if (total > elapsed)
left = total - elapsed;
else
left = 0;
/* if we have less time left that the size of the buffer, we will not
* be able to keep it filled, disabled buffering then */
if (left < rtp_jitter_buffer_get_delay (priv->jbuf)) {
GST_DEBUG_OBJECT (jitterbuffer, "left %" GST_TIME_FORMAT
", disable buffering close to EOS", GST_TIME_ARGS (left));
rtp_jitter_buffer_disable_buffering (priv->jbuf, TRUE);
}
/* this is the current time as running-time */
out_time = item->dts;
if (elapsed > 0)
estimated = gst_util_uint64_scale (out_time, total, elapsed);
else {
/* if there is almost nothing left,
* we may never advance enough to end up in the above case */
if (total < GST_SECOND)
estimated = GST_SECOND;
else
estimated = -1;
}
GST_LOG_OBJECT (jitterbuffer, "elapsed %" GST_TIME_FORMAT ", estimated %"
GST_TIME_FORMAT, GST_TIME_ARGS (elapsed), GST_TIME_ARGS (estimated));
if (estimated != -1 && priv->estimated_eos != estimated) {
set_timer (jitterbuffer, TIMER_TYPE_EOS, -1, estimated);
priv->estimated_eos = estimated;
}
}
if (estimated != -1 && priv->estimated_eos != estimated) {
set_timer (jitterbuffer, TIMER_TYPE_EOS, -1, estimated);
priv->estimated_eos = estimated;
}
}
......@@ -2787,6 +2797,10 @@ do_eos_timeout (GstRtpJitterBuffer * jitterbuffer, TimerData * timer,
GST_INFO_OBJECT (jitterbuffer, "got the NPT timeout");
remove_timer (jitterbuffer, timer);
if (!priv->eos) {
/* there was no EOS in the buffer, put one in there now */
queue_event (jitterbuffer, gst_event_new_eos ());
}
JBUF_SIGNAL_EVENT (priv);
return TRUE;
......
......@@ -226,6 +226,19 @@ rtp_jitter_buffer_reset_skew (RTPJitterBuffer * jbuf)
GST_DEBUG ("reset skew correction");
}
/**
* rtp_jitter_buffer_disable_buffering:
* @jbuf: an #RTPJitterBuffer
* @disabled: the new state
*
* Enable or disable buffering on @jbuf.
*/
void
rtp_jitter_buffer_disable_buffering (RTPJitterBuffer * jbuf, gboolean disabled)
{
jbuf->buffering_disabled = disabled;
}
static void
rtp_jitter_buffer_resync (RTPJitterBuffer * jbuf, GstClockTime time,
GstClockTime gstrtptime, guint64 ext_rtptime, gboolean reset_skew)
......@@ -297,9 +310,14 @@ update_buffer_level (RTPJitterBuffer * jbuf, gint * percent)
level = get_buffer_level (jbuf);
GST_DEBUG ("buffer level %" GST_TIME_FORMAT, GST_TIME_ARGS (level));
if (jbuf->buffering_disabled) {
GST_DEBUG ("buffering is disabled");
level = jbuf->high_level;
}
if (jbuf->buffering) {
post = TRUE;
if (level > jbuf->high_level) {
if (level >= jbuf->high_level) {
GST_DEBUG ("buffering finished");
jbuf->buffering = FALSE;
}
......@@ -850,7 +868,7 @@ rtp_jitter_buffer_flush (RTPJitterBuffer * jbuf, GFunc free_func,
gboolean
rtp_jitter_buffer_is_buffering (RTPJitterBuffer * jbuf)
{
return jbuf->buffering;
return jbuf->buffering && !jbuf->buffering_disabled;
}
/**
......@@ -883,6 +901,9 @@ rtp_jitter_buffer_get_percent (RTPJitterBuffer * jbuf)
if (G_UNLIKELY (jbuf->high_level == 0))
return 100;
if (G_UNLIKELY (jbuf->buffering_disabled))
return 100;
level = get_buffer_level (jbuf);
percent = (level * 100 / jbuf->high_level);
percent = MIN (percent, 100);
......
......@@ -100,6 +100,7 @@ struct _RTPJitterBuffer {
gint64 window_min;
gint64 skew;
gint64 prev_send_diff;
gboolean buffering_disabled;
};
struct _RTPJitterBufferClass {
......@@ -153,6 +154,9 @@ void rtp_jitter_buffer_reset_skew (RTPJitterBuffer *jbuf)
gboolean rtp_jitter_buffer_insert (RTPJitterBuffer *jbuf,
RTPJitterBufferItem *item,
gboolean *tail, gint *percent);
void rtp_jitter_buffer_disable_buffering (RTPJitterBuffer *jbuf, gboolean disabled);
RTPJitterBufferItem * rtp_jitter_buffer_peek (RTPJitterBuffer *jbuf);
RTPJitterBufferItem * rtp_jitter_buffer_pop (RTPJitterBuffer *jbuf, gint *percent);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment