queue2: Distinguish between buffering percentage and buffering level

To make the code clearer, and to facilitate future improvements, introduce
a distinction between the buffering level and the buffering percentage.

Buffering level: the queue's current fill level. The low/high watermarks
are in this range.

Buffering percentage: percentage relative to the low/high watermarks
(0% = low watermark, 100% = high watermark).

To that end, get_buffering_percent() is renamed to get_buffering_level(),
and the code at the end that transforms to the buffering percentage is
factored out into a new convert_to_buffering_percent() function. Also,
the buffering level range is parameterized by adding a new constant called
MAX_BUFFERING_LEVEL.

https://bugzilla.gnome.org/show_bug.cgi?id=769449
This commit is contained in:
Carlos Rafael Giani 2016-08-03 15:27:40 +02:00 committed by Sebastian Dröge
parent 1e1ea38b8e
commit e0f1a9e618

View file

@ -142,6 +142,27 @@ enum
PROP_LAST PROP_LAST
}; };
/* Explanation for buffer levels and percentages:
*
* The buffering_level functions here return a value in a normalized range
* that specifies the queue's current fill level. The range goes from 0 to
* MAX_BUFFERING_LEVEL. The low/high watermarks also use this same range.
*
* This is not to be confused with the buffering_percent value, which is
* a *relative* quantity - relative to the low/high watermarks.
* buffering_percent = 0% means buffering_level is at the low watermark.
* buffering_percent = 100% means buffering_level is at the high watermark.
* buffering_percent is used for determining if the fill level has reached
* the high watermark, and for producing BUFFERING messages. This value
* always uses a 0..100 range (since it is a percentage).
*
* To avoid future confusions, whenever "buffering level" is mentioned, it
* refers to the absolute level which is in the 0..MAX_BUFFERING_LEVEL
* range. Whenever "buffering_percent" is mentioned, it refers to the
* percentage value that is relative to the low/high watermark. */
#define MAX_BUFFERING_LEVEL 100
#define GST_QUEUE2_CLEAR_LEVEL(l) G_STMT_START { \ #define GST_QUEUE2_CLEAR_LEVEL(l) G_STMT_START { \
l.buffers = 0; \ l.buffers = 0; \
l.bytes = 0; \ l.bytes = 0; \
@ -882,7 +903,8 @@ apply_buffer_list (GstQueue2 * queue, GstBufferList * buffer_list,
} }
static inline gint static inline gint
get_percent (guint64 cur_level, guint64 max_level, guint64 alt_max) normalize_to_buffering_level (guint64 cur_level, guint64 max_level,
guint64 alt_max)
{ {
guint64 p; guint64 p;
@ -890,33 +912,34 @@ get_percent (guint64 cur_level, guint64 max_level, guint64 alt_max)
return 0; return 0;
if (alt_max > 0) if (alt_max > 0)
p = gst_util_uint64_scale (cur_level, 100, MIN (max_level, alt_max)); p = gst_util_uint64_scale (cur_level, MAX_BUFFERING_LEVEL,
MIN (max_level, alt_max));
else else
p = gst_util_uint64_scale (cur_level, 100, max_level); p = gst_util_uint64_scale (cur_level, MAX_BUFFERING_LEVEL, max_level);
return MIN (p, 100); return MIN (p, MAX_BUFFERING_LEVEL);
} }
static gboolean static gboolean
get_buffering_percent (GstQueue2 * queue, gboolean * is_buffering, get_buffering_level (GstQueue2 * queue, gboolean * is_buffering,
gint * percent) gint * buffering_level)
{ {
gint perc, perc2; gint buflevel, buflevel2;
if (queue->high_percent <= 0) { if (queue->high_percent <= 0) {
if (percent) if (buffering_level)
*percent = 100; *buffering_level = MAX_BUFFERING_LEVEL;
if (is_buffering) if (is_buffering)
*is_buffering = FALSE; *is_buffering = FALSE;
return FALSE; return FALSE;
} }
#define GET_PERCENT(format,alt_max) \ #define GET_BUFFER_LEVEL_FOR_QUANTITY(format,alt_max) \
get_percent(queue->cur_level.format,queue->max_level.format,(alt_max)) normalize_to_buffering_level (queue->cur_level.format,queue->max_level.format,(alt_max))
if (queue->is_eos) { if (queue->is_eos) {
/* on EOS we are always 100% full, we set the var here so that it we can /* on EOS we are always 100% full, we set the var here so that it we can
* reuse the logic below to stop buffering */ * reuse the logic below to stop buffering */
perc = 100; buflevel = MAX_BUFFERING_LEVEL;
GST_LOG_OBJECT (queue, "we are EOS"); GST_LOG_OBJECT (queue, "we are EOS");
} else { } else {
GST_LOG_OBJECT (queue, GST_LOG_OBJECT (queue,
@ -924,50 +947,59 @@ get_buffering_percent (GstQueue2 * queue, gboolean * is_buffering,
queue->cur_level.bytes, GST_TIME_ARGS (queue->cur_level.time), queue->cur_level.bytes, GST_TIME_ARGS (queue->cur_level.time),
queue->cur_level.buffers); queue->cur_level.buffers);
/* figure out the percent we are filled, we take the max of all formats. */ /* figure out the buffering level we are filled, we take the max of all formats. */
if (!QUEUE_IS_USING_RING_BUFFER (queue)) { if (!QUEUE_IS_USING_RING_BUFFER (queue)) {
perc = GET_PERCENT (bytes, 0); buflevel = GET_BUFFER_LEVEL_FOR_QUANTITY (bytes, 0);
} else { } else {
guint64 rb_size = queue->ring_buffer_max_size; guint64 rb_size = queue->ring_buffer_max_size;
perc = GET_PERCENT (bytes, rb_size); buflevel = GET_BUFFER_LEVEL_FOR_QUANTITY (bytes, rb_size);
} }
perc2 = GET_PERCENT (time, 0); buflevel2 = GET_BUFFER_LEVEL_FOR_QUANTITY (time, 0);
perc = MAX (perc, perc2); buflevel = MAX (buflevel, buflevel2);
perc2 = GET_PERCENT (buffers, 0); buflevel2 = GET_BUFFER_LEVEL_FOR_QUANTITY (buffers, 0);
perc = MAX (perc, perc2); buflevel = MAX (buflevel, buflevel2);
/* also apply the rate estimate when we need to */ /* also apply the rate estimate when we need to */
if (queue->use_rate_estimate) { if (queue->use_rate_estimate) {
perc2 = GET_PERCENT (rate_time, 0); buflevel2 = GET_BUFFER_LEVEL_FOR_QUANTITY (rate_time, 0);
perc = MAX (perc, perc2); buflevel = MAX (buflevel, buflevel2);
} }
/* Don't get to 0% unless we're really empty */ /* Don't get to 0% unless we're really empty */
if (queue->cur_level.bytes > 0) if (queue->cur_level.bytes > 0)
perc = MAX (1, perc); buflevel = MAX (1, buflevel);
} }
#undef GET_PERCENT #undef GET_BUFFER_LEVEL_FOR_QUANTITY
if (is_buffering) if (is_buffering)
*is_buffering = queue->is_buffering; *is_buffering = queue->is_buffering;
/* scale to high percent so that it becomes the 100% mark */ if (buffering_level)
perc = perc * 100 / queue->high_percent; *buffering_level = buflevel;
/* clip */
if (perc > 100)
perc = 100;
if (percent) GST_DEBUG_OBJECT (queue, "buffering %d, level %d", queue->is_buffering,
*percent = perc; buflevel);
GST_DEBUG_OBJECT (queue, "buffering %d, percent %d", queue->is_buffering,
perc);
return TRUE; return TRUE;
} }
static gint
convert_to_buffering_percent (GstQueue2 * queue, gint buffering_level)
{
int percent;
/* scale so that if buffering_level equals the high watermark,
* the percentage is 100% */
percent = buffering_level * 100 / queue->high_percent;
/* clip */
if (percent > 100)
percent = 100;
return percent;
}
static void static void
get_buffering_stats (GstQueue2 * queue, gint percent, GstBufferingMode * mode, get_buffering_stats (GstQueue2 * queue, gint percent, GstBufferingMode * mode,
gint * avg_in, gint * avg_out, gint64 * buffering_left) gint * avg_in, gint * avg_out, gint64 * buffering_left)
@ -1043,16 +1075,18 @@ gst_queue2_post_buffering (GstQueue2 * queue)
static void static void
update_buffering (GstQueue2 * queue) update_buffering (GstQueue2 * queue)
{ {
gint percent; gint buffering_level, percent;
/* Ensure the variables used to calculate buffering state are up-to-date. */ /* Ensure the variables used to calculate buffering state are up-to-date. */
if (queue->current) if (queue->current)
update_cur_level (queue, queue->current); update_cur_level (queue, queue->current);
update_in_rates (queue, FALSE); update_in_rates (queue, FALSE);
if (!get_buffering_percent (queue, NULL, &percent)) if (!get_buffering_level (queue, NULL, &buffering_level))
return; return;
percent = convert_to_buffering_percent (queue, buffering_level);
if (queue->is_buffering) { if (queue->is_buffering) {
/* if we were buffering see if we reached the high watermark */ /* if we were buffering see if we reached the high watermark */
if (percent >= 100) if (percent >= 100)
@ -1062,7 +1096,7 @@ update_buffering (GstQueue2 * queue)
} else { } else {
/* we were not buffering, check if we need to start buffering if we drop /* we were not buffering, check if we need to start buffering if we drop
* below the low threshold */ * below the low threshold */
if (percent < queue->low_percent) { if (buffering_level < queue->low_percent) {
queue->is_buffering = TRUE; queue->is_buffering = TRUE;
SET_PERCENT (queue, percent); SET_PERCENT (queue, percent);
} }
@ -3137,7 +3171,8 @@ gst_queue2_handle_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
GST_DEBUG_OBJECT (queue, "query buffering"); GST_DEBUG_OBJECT (queue, "query buffering");
get_buffering_percent (queue, &is_buffering, &percent); get_buffering_level (queue, &is_buffering, &percent);
percent = convert_to_buffering_percent (queue, percent);
gst_query_set_buffering_percent (query, is_buffering, percent); gst_query_set_buffering_percent (query, is_buffering, percent);
get_buffering_stats (queue, percent, &mode, &avg_in, &avg_out, get_buffering_stats (queue, percent, &mode, &avg_in, &avg_out,