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.
This commit is contained in:
Wim Taymans 2009-10-08 19:23:53 +02:00
parent 3efcc0fbc1
commit 74a3be350d
5 changed files with 61 additions and 38 deletions

View file

@ -6,4 +6,4 @@ VOID:UINT,OBJECT
VOID:UINT VOID:UINT
VOID:UINT,UINT VOID:UINT,UINT
VOID:OBJECT,OBJECT VOID:OBJECT,OBJECT
VOID:BOOL,UINT64 UINT64:BOOL,UINT64

View file

@ -1783,6 +1783,7 @@ gst_rtp_bin_handle_message (GstBin * bin, GstMessage * message)
GSList *sessions, *streams, *elements = NULL; GSList *sessions, *streams, *elements = NULL;
GstRtpBinStream *stream; GstRtpBinStream *stream;
gboolean change = FALSE, active = FALSE; gboolean change = FALSE, active = FALSE;
GstClockTime min_out_time;
gst_message_parse_buffering (message, &percent); gst_message_parse_buffering (message, &percent);
@ -1847,7 +1848,7 @@ gst_rtp_bin_handle_message (GstBin * bin, GstMessage * message)
if (G_UNLIKELY (change)) { if (G_UNLIKELY (change)) {
GstClock *clock; GstClock *clock;
guint64 running_time = 0; guint64 running_time = 0;
guint64 elapsed = 0; guint64 offset = 0;
/* figure out the running time when we have a clock */ /* figure out the running time when we have a clock */
if (G_LIKELY ((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)); base_time = gst_element_get_base_time (GST_ELEMENT_CAST (bin));
running_time = now - base_time; running_time = now - base_time;
} }
GST_DEBUG_OBJECT (bin,
"running time now %" GST_TIME_FORMAT,
GST_TIME_ARGS (running_time));
if (!active) { /* when we reactivate, calculate the offsets so that all streams have
/* remember the time when we started buffering */ * an output time that is at least as big as the running_time */
rtpbin->buffer_start = running_time; offset = 0;
} else { if (active) {
/* calculate time spent in buffering */ if (running_time > rtpbin->buffer_start) {
if (running_time > rtpbin->buffer_start) offset = running_time - rtpbin->buffer_start;
elapsed = running_time - rtpbin->buffer_start; if (offset >= rtpbin->latency_ns)
else offset -= rtpbin->latency_ns;
elapsed = 0; else
/* subtract latency, if we paused for less time than the latency we offset = 0;
* are fine. */ }
if (elapsed > rtpbin->latency_ns)
elapsed -= rtpbin->latency_ns;
else
elapsed = 0;
} }
min_out_time = -1;
while (G_LIKELY (elements)) { while (G_LIKELY (elements)) {
GstElement *element = elements->data; 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, GST_DEBUG_OBJECT (bin,
"setting %p to %d, elapsed %" GST_TIME_FORMAT, element, active, "setting %p to %d, offset %" GST_TIME_FORMAT ", last %"
GST_TIME_ARGS (elapsed)); GST_TIME_FORMAT, element, active, GST_TIME_ARGS (offset),
g_signal_emit_by_name (element, "set-active", active, elapsed, GST_TIME_ARGS (last_out));
NULL);
gst_object_unref (element); gst_object_unref (element);
elements = g_slist_delete_link (elements, elements); 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); GST_BIN_CLASS (parent_class)->handle_message (bin, message);

View file

@ -268,7 +268,7 @@ static gboolean gst_rtp_jitter_buffer_query (GstPad * pad, GstQuery * query);
static void static void
gst_rtp_jitter_buffer_clear_pt_map (GstRtpJitterBuffer * jitterbuffer); gst_rtp_jitter_buffer_clear_pt_map (GstRtpJitterBuffer * jitterbuffer);
static void static GstClockTime
gst_rtp_jitter_buffer_set_active (GstRtpJitterBuffer * jitterbuffer, gst_rtp_jitter_buffer_set_active (GstRtpJitterBuffer * jitterbuffer,
gboolean active, guint64 base_time); 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 * Start pushing out packets with the given base time. This signal is only
* useful in buffering mode. * useful in buffering mode.
*
* Returns: the time of the last pushed packet.
*/ */
gst_rtp_jitter_buffer_signals[SIGNAL_SET_ACTIVE] = gst_rtp_jitter_buffer_signals[SIGNAL_SET_ACTIVE] =
g_signal_new ("set-active", G_TYPE_FROM_CLASS (klass), g_signal_new ("set-active", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GstRtpJitterBufferClass, set_active), NULL, NULL, 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); G_TYPE_UINT64);
gstelement_class->change_state = gstelement_class->change_state =
@ -647,29 +649,37 @@ gst_rtp_jitter_buffer_clear_pt_map (GstRtpJitterBuffer * jitterbuffer)
JBUF_UNLOCK (priv); JBUF_UNLOCK (priv);
} }
static void static GstClockTime
gst_rtp_jitter_buffer_set_active (GstRtpJitterBuffer * jbuf, gboolean active, gst_rtp_jitter_buffer_set_active (GstRtpJitterBuffer * jbuf, gboolean active,
guint64 elapsed) guint64 offset)
{ {
GstRtpJitterBufferPrivate *priv; GstRtpJitterBufferPrivate *priv;
GstClockTime last_out;
GstBuffer *head;
priv = jbuf->priv; priv = jbuf->priv;
JBUF_LOCK (priv); JBUF_LOCK (priv);
GST_DEBUG_OBJECT (jbuf, "setting active %d with elapsed %" GST_TIME_FORMAT, GST_DEBUG_OBJECT (jbuf, "setting active %d with offset %" GST_TIME_FORMAT,
active, GST_TIME_ARGS (elapsed)); active, GST_TIME_ARGS (offset));
if (active != priv->active) { if (active != priv->active) {
/* add the amount of time spent in paused to the output offset. All /* add the amount of time spent in paused to the output offset. All
* outgoing buffers will have this offset applied to their timestamps in * outgoing buffers will have this offset applied to their timestamps in
* order to make them arrive in time in the sink. */ * 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_DEBUG_OBJECT (jbuf, "out offset %" GST_TIME_FORMAT,
GST_TIME_ARGS (priv->out_offset)); GST_TIME_ARGS (priv->out_offset));
priv->active = active; priv->active = active;
JBUF_SIGNAL (priv); 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); JBUF_UNLOCK (priv);
return last_out;
} }
static GstCaps * static GstCaps *

View file

@ -77,7 +77,7 @@ struct _GstRtpJitterBufferClass
/* actions */ /* actions */
void (*clear_pt_map) (GstRtpJitterBuffer *buffer); 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 > */ /*< private > */
gpointer _gst_reserved[GST_PADDING]; gpointer _gst_reserved[GST_PADDING];

View file

@ -596,21 +596,16 @@ rtp_jitter_buffer_insert (RTPJitterBuffer * jbuf, GstBuffer * buf,
rtptime = gst_rtp_buffer_get_timestamp (buf); rtptime = gst_rtp_buffer_get_timestamp (buf);
switch (jbuf->mode) { switch (jbuf->mode) {
case RTP_JITTER_BUFFER_MODE_NONE: 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 /* 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) if (jbuf->base_time == -1)
time = 0; time = 0;
else else
time = -1; time = -1;
break; 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: case RTP_JITTER_BUFFER_MODE_SLAVE:
default: default:
break; break;