From 74a3be350d346908d4a09790ccedfa96bcb0e3cc Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 8 Oct 2009 19:23:53 +0200 Subject: [PATCH] rtpbin: do more accurate buffer offsets Return the next timestamp in the jitterbuffer. Use the min-timestamp of the jitterbuffers to calculate an offset so that the next timestamp is pushed with a timestamp equal to running_time. Start producing timestamps from 0 in the buffering case too. --- gst/rtpmanager/gstrtpbin-marshal.list | 2 +- gst/rtpmanager/gstrtpbin.c | 58 ++++++++++++++++++--------- gst/rtpmanager/gstrtpjitterbuffer.c | 24 +++++++---- gst/rtpmanager/gstrtpjitterbuffer.h | 2 +- gst/rtpmanager/rtpjitterbuffer.c | 13 ++---- 5 files changed, 61 insertions(+), 38 deletions(-) diff --git a/gst/rtpmanager/gstrtpbin-marshal.list b/gst/rtpmanager/gstrtpbin-marshal.list index 1f6d2b73f1..01b530be41 100644 --- a/gst/rtpmanager/gstrtpbin-marshal.list +++ b/gst/rtpmanager/gstrtpbin-marshal.list @@ -6,4 +6,4 @@ VOID:UINT,OBJECT VOID:UINT VOID:UINT,UINT VOID:OBJECT,OBJECT -VOID:BOOL,UINT64 +UINT64:BOOL,UINT64 diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c index 86db344b30..49284fa415 100644 --- a/gst/rtpmanager/gstrtpbin.c +++ b/gst/rtpmanager/gstrtpbin.c @@ -1783,6 +1783,7 @@ gst_rtp_bin_handle_message (GstBin * bin, GstMessage * message) GSList *sessions, *streams, *elements = NULL; GstRtpBinStream *stream; gboolean change = FALSE, active = FALSE; + GstClockTime min_out_time; gst_message_parse_buffering (message, &percent); @@ -1847,7 +1848,7 @@ gst_rtp_bin_handle_message (GstBin * bin, GstMessage * message) if (G_UNLIKELY (change)) { GstClock *clock; guint64 running_time = 0; - guint64 elapsed = 0; + guint64 offset = 0; /* figure out the running time when we have a clock */ if (G_LIKELY ((clock = @@ -1858,35 +1859,52 @@ gst_rtp_bin_handle_message (GstBin * bin, GstMessage * message) base_time = gst_element_get_base_time (GST_ELEMENT_CAST (bin)); running_time = now - base_time; } + GST_DEBUG_OBJECT (bin, + "running time now %" GST_TIME_FORMAT, + GST_TIME_ARGS (running_time)); - if (!active) { - /* remember the time when we started buffering */ - rtpbin->buffer_start = running_time; - } else { - /* calculate time spent in buffering */ - if (running_time > rtpbin->buffer_start) - elapsed = running_time - rtpbin->buffer_start; - else - elapsed = 0; - /* subtract latency, if we paused for less time than the latency we - * are fine. */ - if (elapsed > rtpbin->latency_ns) - elapsed -= rtpbin->latency_ns; - else - elapsed = 0; + /* when we reactivate, calculate the offsets so that all streams have + * an output time that is at least as big as the running_time */ + offset = 0; + if (active) { + if (running_time > rtpbin->buffer_start) { + offset = running_time - rtpbin->buffer_start; + if (offset >= rtpbin->latency_ns) + offset -= rtpbin->latency_ns; + else + offset = 0; + } } + min_out_time = -1; while (G_LIKELY (elements)) { GstElement *element = elements->data; + GstClockTime last_out; + + g_signal_emit_by_name (element, "set-active", active, offset, + &last_out); + + if (!active) { + if (last_out == -1) + last_out = 0; + if (last_out < min_out_time) + min_out_time = last_out; + } GST_DEBUG_OBJECT (bin, - "setting %p to %d, elapsed %" GST_TIME_FORMAT, element, active, - GST_TIME_ARGS (elapsed)); - g_signal_emit_by_name (element, "set-active", active, elapsed, - NULL); + "setting %p to %d, offset %" GST_TIME_FORMAT ", last %" + GST_TIME_FORMAT, element, active, GST_TIME_ARGS (offset), + GST_TIME_ARGS (last_out)); + gst_object_unref (element); elements = g_slist_delete_link (elements, elements); } + GST_DEBUG_OBJECT (bin, + "min out time %" GST_TIME_FORMAT, GST_TIME_ARGS (min_out_time)); + + /* the buffer_start is the min out time of all paused jitterbuffers */ + if (!active) + rtpbin->buffer_start = min_out_time; } } GST_BIN_CLASS (parent_class)->handle_message (bin, message); diff --git a/gst/rtpmanager/gstrtpjitterbuffer.c b/gst/rtpmanager/gstrtpjitterbuffer.c index 7fb1e73310..ed87762380 100644 --- a/gst/rtpmanager/gstrtpjitterbuffer.c +++ b/gst/rtpmanager/gstrtpjitterbuffer.c @@ -268,7 +268,7 @@ static gboolean gst_rtp_jitter_buffer_query (GstPad * pad, GstQuery * query); static void gst_rtp_jitter_buffer_clear_pt_map (GstRtpJitterBuffer * jitterbuffer); -static void +static GstClockTime gst_rtp_jitter_buffer_set_active (GstRtpJitterBuffer * jitterbuffer, gboolean active, guint64 base_time); @@ -412,12 +412,14 @@ gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass) * * Start pushing out packets with the given base time. This signal is only * useful in buffering mode. + * + * Returns: the time of the last pushed packet. */ gst_rtp_jitter_buffer_signals[SIGNAL_SET_ACTIVE] = g_signal_new ("set-active", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstRtpJitterBufferClass, set_active), NULL, NULL, - gst_rtp_bin_marshal_VOID__BOOL_UINT64, G_TYPE_NONE, 2, G_TYPE_BOOLEAN, + gst_rtp_bin_marshal_UINT64__BOOL_UINT64, G_TYPE_UINT64, 2, G_TYPE_BOOLEAN, G_TYPE_UINT64); gstelement_class->change_state = @@ -647,29 +649,37 @@ gst_rtp_jitter_buffer_clear_pt_map (GstRtpJitterBuffer * jitterbuffer) JBUF_UNLOCK (priv); } -static void +static GstClockTime gst_rtp_jitter_buffer_set_active (GstRtpJitterBuffer * jbuf, gboolean active, - guint64 elapsed) + guint64 offset) { GstRtpJitterBufferPrivate *priv; + GstClockTime last_out; + GstBuffer *head; priv = jbuf->priv; JBUF_LOCK (priv); - GST_DEBUG_OBJECT (jbuf, "setting active %d with elapsed %" GST_TIME_FORMAT, - active, GST_TIME_ARGS (elapsed)); + GST_DEBUG_OBJECT (jbuf, "setting active %d with offset %" GST_TIME_FORMAT, + active, GST_TIME_ARGS (offset)); if (active != priv->active) { /* add the amount of time spent in paused to the output offset. All * outgoing buffers will have this offset applied to their timestamps in * order to make them arrive in time in the sink. */ - priv->out_offset += elapsed; + priv->out_offset = offset; GST_DEBUG_OBJECT (jbuf, "out offset %" GST_TIME_FORMAT, GST_TIME_ARGS (priv->out_offset)); priv->active = active; JBUF_SIGNAL (priv); } + if ((head = rtp_jitter_buffer_peek (priv->jbuf))) { + last_out = GST_BUFFER_TIMESTAMP (head); + } else + last_out = priv->last_out_time; JBUF_UNLOCK (priv); + + return last_out; } static GstCaps * diff --git a/gst/rtpmanager/gstrtpjitterbuffer.h b/gst/rtpmanager/gstrtpjitterbuffer.h index b4f2330bf8..9cda5d47a3 100644 --- a/gst/rtpmanager/gstrtpjitterbuffer.h +++ b/gst/rtpmanager/gstrtpjitterbuffer.h @@ -77,7 +77,7 @@ struct _GstRtpJitterBufferClass /* actions */ void (*clear_pt_map) (GstRtpJitterBuffer *buffer); - void (*set_active) (GstRtpJitterBuffer *buffer, gboolean active, guint64 elapsed); + GstClockTime (*set_active) (GstRtpJitterBuffer *buffer, gboolean active, guint64 elapsed); /*< private > */ gpointer _gst_reserved[GST_PADDING]; diff --git a/gst/rtpmanager/rtpjitterbuffer.c b/gst/rtpmanager/rtpjitterbuffer.c index 00ee0acc2b..d6a4d3756b 100644 --- a/gst/rtpmanager/rtpjitterbuffer.c +++ b/gst/rtpmanager/rtpjitterbuffer.c @@ -596,21 +596,16 @@ rtp_jitter_buffer_insert (RTPJitterBuffer * jbuf, GstBuffer * buf, rtptime = gst_rtp_buffer_get_timestamp (buf); switch (jbuf->mode) { case RTP_JITTER_BUFFER_MODE_NONE: + case RTP_JITTER_BUFFER_MODE_BUFFER: /* send 0 as the first timestamp and -1 for the other ones. This will - * interpollate them from the RTP timestamps with a 0 origin. */ + * interpollate them from the RTP timestamps with a 0 origin. In buffering + * mode we will adjust the outgoing timestamps according to the amount of + * time we spent buffering. */ if (jbuf->base_time == -1) time = 0; else time = -1; break; - case RTP_JITTER_BUFFER_MODE_BUFFER: - /* send -1 for all timestamps except the first one. This will make the - * timestamps increase according to the RTP timestamps. When in buffering - * mode we will adjust the outgoing timestamps relative with how long we - * buffered */ - if (jbuf->base_time != -1) - time = -1; - break; case RTP_JITTER_BUFFER_MODE_SLAVE: default: break;