From 8bbfd94c253598d9a80cf5a8b14d5f4f7af37694 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 27 Jan 2010 17:57:55 +0100 Subject: [PATCH] rtpbin: more buffering work When deactivating jitterbuffers when the buffering starts, keep the current percent of the jitterbuffer and also set the jitterbuffer in the buffering state so that we know when it's filled again. Add property to get the buffering percentage of the jitterbuffer. --- gst/rtpmanager/gstrtpbin.c | 56 ++++++++++++++---------- gst/rtpmanager/gstrtpjitterbuffer.c | 28 ++++++++++++ gst/rtpmanager/rtpjitterbuffer.c | 68 ++++++++++++++++++++++++----- gst/rtpmanager/rtpjitterbuffer.h | 3 +- 4 files changed, 119 insertions(+), 36 deletions(-) diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c index 49284fa415..407c366bde 100644 --- a/gst/rtpmanager/gstrtpbin.c +++ b/gst/rtpmanager/gstrtpbin.c @@ -1771,7 +1771,6 @@ gst_rtp_bin_handle_message (GstBin * bin, GstMessage * message) gst_structure_set ((GstStructure *) s, "session", G_TYPE_UINT, sess->id, NULL); } - GST_RTP_BIN_UNLOCK (rtpbin); } GST_BIN_CLASS (parent_class)->handle_message (bin, message); break; @@ -1780,7 +1779,7 @@ gst_rtp_bin_handle_message (GstBin * bin, GstMessage * message) { gint percent; gint min_percent = 100; - GSList *sessions, *streams, *elements = NULL; + GSList *sessions, *streams; GstRtpBinStream *stream; gboolean change = FALSE, active = FALSE; GstClockTime min_out_time; @@ -1808,7 +1807,6 @@ gst_rtp_bin_handle_message (GstBin * bin, GstMessage * message) for (streams = session->streams; streams; streams = g_slist_next (streams)) { GstRtpBinStream *stream = (GstRtpBinStream *) streams->data; - GstElement *element = stream->buffer; GST_DEBUG_OBJECT (bin, "stream %p percent %d", stream, stream->percent); @@ -1816,8 +1814,6 @@ gst_rtp_bin_handle_message (GstBin * bin, GstMessage * message) /* find min percent */ if (min_percent > stream->percent) min_percent = stream->percent; - - elements = g_slist_prepend (elements, gst_object_ref (element)); } GST_RTP_SESSION_UNLOCK (session); } @@ -1863,6 +1859,8 @@ gst_rtp_bin_handle_message (GstBin * bin, GstMessage * message) "running time now %" GST_TIME_FORMAT, GST_TIME_ARGS (running_time)); + GST_RTP_BIN_LOCK (rtpbin); + /* 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; @@ -1876,28 +1874,38 @@ gst_rtp_bin_handle_message (GstBin * bin, GstMessage * message) } } + /* pause all streams */ min_out_time = -1; - while (G_LIKELY (elements)) { - GstElement *element = elements->data; - GstClockTime last_out; + for (sessions = rtpbin->sessions; sessions; + sessions = g_slist_next (sessions)) { + GstRtpBinSession *session = (GstRtpBinSession *) sessions->data; - g_signal_emit_by_name (element, "set-active", active, offset, - &last_out); + GST_RTP_SESSION_LOCK (session); + for (streams = session->streams; streams; + streams = g_slist_next (streams)) { + GstRtpBinStream *stream = (GstRtpBinStream *) streams->data; + GstElement *element = stream->buffer; + guint64 last_out; - if (!active) { - if (last_out == -1) - last_out = 0; - if (last_out < min_out_time) - min_out_time = last_out; + g_signal_emit_by_name (element, "set-active", active, offset, + &last_out); + + if (!active) { + g_object_get (element, "percent", &stream->percent, NULL); + + 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, offset %" GST_TIME_FORMAT ", last %" + GST_TIME_FORMAT ", percent %d", element, active, + GST_TIME_ARGS (offset), GST_TIME_ARGS (last_out), + stream->percent); } - - GST_DEBUG_OBJECT (bin, - "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_RTP_SESSION_UNLOCK (session); } GST_DEBUG_OBJECT (bin, "min out time %" GST_TIME_FORMAT, GST_TIME_ARGS (min_out_time)); @@ -1905,6 +1913,8 @@ gst_rtp_bin_handle_message (GstBin * bin, GstMessage * message) /* the buffer_start is the min out time of all paused jitterbuffers */ if (!active) rtpbin->buffer_start = min_out_time; + + GST_RTP_BIN_UNLOCK (rtpbin); } } GST_BIN_CLASS (parent_class)->handle_message (bin, message); diff --git a/gst/rtpmanager/gstrtpjitterbuffer.c b/gst/rtpmanager/gstrtpjitterbuffer.c index e480252ade..ddadd97ab6 100644 --- a/gst/rtpmanager/gstrtpjitterbuffer.c +++ b/gst/rtpmanager/gstrtpjitterbuffer.c @@ -94,6 +94,7 @@ enum #define DEFAULT_TS_OFFSET 0 #define DEFAULT_DO_LOST FALSE #define DEFAULT_MODE RTP_JITTER_BUFFER_MODE_SLAVE +#define DEFAULT_PERCENT 0 enum { @@ -103,6 +104,7 @@ enum PROP_TS_OFFSET, PROP_DO_LOST, PROP_MODE, + PROP_PERCENT, PROP_LAST }; @@ -355,6 +357,15 @@ gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass) g_param_spec_enum ("mode", "Mode", "Control the buffering algorithm in use", RTP_TYPE_JITTER_BUFFER_MODE, DEFAULT_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstRtpJitterBuffer::percent: + * + * The percent of the jitterbuffer that is filled. + */ + g_object_class_install_property (gobject_class, PROP_PERCENT, + g_param_spec_int ("percent", "percent", + "The buffer filled percent", 0, 100, + 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** * GstRtpJitterBuffer::request-pt-map: * @buffer: the object which received the signal @@ -673,6 +684,9 @@ gst_rtp_jitter_buffer_set_active (GstRtpJitterBuffer * jbuf, gboolean active, priv->active = active; JBUF_SIGNAL (priv); } + if (!active) { + rtp_jitter_buffer_set_buffering (priv->jbuf, TRUE); + } if ((head = rtp_jitter_buffer_peek (priv->jbuf))) { /* head buffer timestamp and offset gives our output time */ last_out = GST_BUFFER_TIMESTAMP (head) + priv->ts_offset; @@ -2131,6 +2145,20 @@ gst_rtp_jitter_buffer_get_property (GObject * object, g_value_set_enum (value, rtp_jitter_buffer_get_mode (priv->jbuf)); JBUF_UNLOCK (priv); break; + case PROP_PERCENT: + { + gint percent; + + JBUF_LOCK (priv); + if (priv->srcresult != GST_FLOW_OK) + percent = 100; + else + percent = rtp_jitter_buffer_get_percent (priv->jbuf); + + g_value_set_int (value, percent); + 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 d6a4d3756b..7e018d2677 100644 --- a/gst/rtpmanager/rtpjitterbuffer.c +++ b/gst/rtpmanager/rtpjitterbuffer.c @@ -162,7 +162,7 @@ rtp_jitter_buffer_set_delay (RTPJitterBuffer * jbuf, GstClockTime delay) jbuf->high_level = (delay * 90) / 100; GST_DEBUG ("delay %" GST_TIME_FORMAT ", min %" GST_TIME_FORMAT ", max %" - GST_TIME_FORMAT, GST_TIME_ARGS (jbuf->level), + GST_TIME_FORMAT, GST_TIME_ARGS (jbuf->delay), GST_TIME_ARGS (jbuf->low_level), GST_TIME_ARGS (jbuf->high_level)); } @@ -209,17 +209,17 @@ rtp_jitter_buffer_resync (RTPJitterBuffer * jbuf, GstClockTime time, } } -static void -update_buffer_level (RTPJitterBuffer * jbuf, gint * percent) +static guint64 +get_buffer_level (RTPJitterBuffer * jbuf) { GstBuffer *high_buf, *low_buf; - gboolean post = FALSE; + guint64 level; high_buf = g_queue_peek_head (jbuf->packets); low_buf = g_queue_peek_tail (jbuf->packets); if (!high_buf || !low_buf || high_buf == low_buf) { - jbuf->level = 0; + level = 0; } else { guint64 high_ts, low_ts; @@ -227,20 +227,30 @@ update_buffer_level (RTPJitterBuffer * jbuf, gint * percent) low_ts = GST_BUFFER_TIMESTAMP (low_buf); if (high_ts > low_ts) - jbuf->level = high_ts - low_ts; + level = high_ts - low_ts; else - jbuf->level = 0; + level = 0; } - GST_DEBUG ("buffer level %" GST_TIME_FORMAT, GST_TIME_ARGS (jbuf->level)); + return level; +} + +static void +update_buffer_level (RTPJitterBuffer * jbuf, gint * percent) +{ + gboolean post = FALSE; + guint64 level; + + level = get_buffer_level (jbuf); + GST_DEBUG ("buffer level %" GST_TIME_FORMAT, GST_TIME_ARGS (level)); if (jbuf->buffering) { post = TRUE; - if (jbuf->level > jbuf->high_level) { + if (level > jbuf->high_level) { GST_DEBUG ("buffering finished"); jbuf->buffering = FALSE; } } else { - if (jbuf->level < jbuf->low_level) { + if (level < jbuf->low_level) { GST_DEBUG ("buffering started"); jbuf->buffering = TRUE; post = TRUE; @@ -250,7 +260,7 @@ update_buffer_level (RTPJitterBuffer * jbuf, gint * percent) gint perc; if (jbuf->buffering) { - perc = (jbuf->level * 100 / jbuf->high_level); + perc = (level * 100 / jbuf->high_level); perc = MIN (perc, 100); } else { perc = 100; @@ -323,7 +333,7 @@ update_buffer_level (RTPJitterBuffer * jbuf, gint * percent) */ static GstClockTime calculate_skew (RTPJitterBuffer * jbuf, guint32 rtptime, GstClockTime time, - guint32 clock_rate, GstClockTime max_delay) + guint32 clock_rate) { guint64 ext_rtptime; guint64 send_diff, recv_diff; @@ -723,6 +733,40 @@ rtp_jitter_buffer_is_buffering (RTPJitterBuffer * jbuf) return jbuf->buffering; } +/** + * rtp_jitter_buffer_set_buffering: + * @jbuf: an #RTPJitterBuffer + * @buffering: the new buffering state + * + * Forces @jbuf to go into the buffering state. + */ +void +rtp_jitter_buffer_set_buffering (RTPJitterBuffer * jbuf, gboolean buffering) +{ + jbuf->buffering = buffering; +} + +/** + * rtp_jitter_buffer_get_percent: + * @jbuf: an #RTPJitterBuffer + * + * Get the buffering percent of the jitterbuffer. + * + * Returns: the buffering percent + */ +gint +rtp_jitter_buffer_get_percent (RTPJitterBuffer * jbuf) +{ + gint percent; + guint64 level; + + level = get_buffer_level (jbuf); + percent = (level * 100 / jbuf->high_level); + percent = MIN (percent, 100); + + return percent; +} + /** * rtp_jitter_buffer_num_packets: * @jbuf: an #RTPJitterBuffer diff --git a/gst/rtpmanager/rtpjitterbuffer.h b/gst/rtpmanager/rtpjitterbuffer.h index 310cec0a25..85bf9775de 100644 --- a/gst/rtpmanager/rtpjitterbuffer.h +++ b/gst/rtpmanager/rtpjitterbuffer.h @@ -75,7 +75,6 @@ struct _RTPJitterBuffer { /* for buffering */ gboolean buffering; - guint64 level; guint64 low_level; guint64 high_level; @@ -123,6 +122,8 @@ GstBuffer * rtp_jitter_buffer_pop (RTPJitterBuffer *jbuf, void rtp_jitter_buffer_flush (RTPJitterBuffer *jbuf); gboolean rtp_jitter_buffer_is_buffering (RTPJitterBuffer * jbuf); +void rtp_jitter_buffer_set_buffering (RTPJitterBuffer * jbuf, gboolean buffering); +gint rtp_jitter_buffer_get_percent (RTPJitterBuffer * jbuf); guint rtp_jitter_buffer_num_packets (RTPJitterBuffer *jbuf); guint32 rtp_jitter_buffer_get_ts_diff (RTPJitterBuffer *jbuf);