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.
This commit is contained in:
Wim Taymans 2010-01-27 17:57:55 +01:00
parent e6e287cdcc
commit 8bbfd94c25
4 changed files with 119 additions and 36 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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

View file

@ -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);