mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-20 07:16:55 +00:00
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:
parent
1e1ea38b8e
commit
e0f1a9e618
1 changed files with 72 additions and 37 deletions
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue