mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-29 18:48:44 +00:00
queue2: Add higher-resolution low/high-watermark properties
low/high-watermark are of type double, and given in range 0.0-1.0. This makes it possible to set low/high watermarks with greater resolution, which is useful with large queue2 max sizes and watermarks like 0.5%. Also adding a test to check the fill and watermark level behavior. https://bugzilla.gnome.org/show_bug.cgi?id=769449
This commit is contained in:
parent
e0f1a9e618
commit
db66cb51b3
3 changed files with 122 additions and 15 deletions
|
@ -117,6 +117,8 @@ enum
|
|||
#define DEFAULT_USE_RATE_ESTIMATE TRUE
|
||||
#define DEFAULT_LOW_PERCENT 10
|
||||
#define DEFAULT_HIGH_PERCENT 99
|
||||
#define DEFAULT_LOW_WATERMARK 0.01
|
||||
#define DEFAULT_HIGH_WATERMARK 0.99
|
||||
#define DEFAULT_TEMP_REMOVE TRUE
|
||||
#define DEFAULT_RING_BUFFER_MAX_SIZE 0
|
||||
|
||||
|
@ -134,6 +136,8 @@ enum
|
|||
PROP_USE_RATE_ESTIMATE,
|
||||
PROP_LOW_PERCENT,
|
||||
PROP_HIGH_PERCENT,
|
||||
PROP_LOW_WATERMARK,
|
||||
PROP_HIGH_WATERMARK,
|
||||
PROP_TEMP_TEMPLATE,
|
||||
PROP_TEMP_LOCATION,
|
||||
PROP_TEMP_REMOVE,
|
||||
|
@ -161,7 +165,12 @@ enum
|
|||
* 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
|
||||
/* Using a buffering level range of 0..1000000 to allow for a
|
||||
* resolution in ppm (1 ppm = 0.0001%) */
|
||||
#define MAX_BUFFERING_LEVEL 1000000
|
||||
|
||||
/* How much 1% makes up in the buffer level range */
|
||||
#define BUF_LEVEL_PERCENT_FACTOR ((MAX_BUFFERING_LEVEL) / 100)
|
||||
|
||||
#define GST_QUEUE2_CLEAR_LEVEL(l) G_STMT_START { \
|
||||
l.buffers = 0; \
|
||||
|
@ -375,13 +384,25 @@ gst_queue2_class_init (GstQueue2Class * klass)
|
|||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (gobject_class, PROP_LOW_PERCENT,
|
||||
g_param_spec_int ("low-percent", "Low percent",
|
||||
"Low threshold for buffering to start. Only used if use-buffering is True",
|
||||
0, 100, DEFAULT_LOW_PERCENT,
|
||||
"Low threshold for buffering to start. Only used if use-buffering is True "
|
||||
"(Deprecated: use low-watermark instead)",
|
||||
0, 100, DEFAULT_LOW_WATERMARK * 100,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (gobject_class, PROP_HIGH_PERCENT,
|
||||
g_param_spec_int ("high-percent", "High percent",
|
||||
"High threshold for buffering to finish. Only used if use-buffering is True "
|
||||
"(Deprecated: use high-watermark instead)",
|
||||
0, 100, DEFAULT_HIGH_WATERMARK * 100,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (gobject_class, PROP_LOW_WATERMARK,
|
||||
g_param_spec_double ("low-watermark", "Low watermark",
|
||||
"Low threshold for buffering to start. Only used if use-buffering is True",
|
||||
0.0, 1.0, DEFAULT_LOW_WATERMARK,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (gobject_class, PROP_HIGH_WATERMARK,
|
||||
g_param_spec_double ("high-watermark", "High watermark",
|
||||
"High threshold for buffering to finish. Only used if use-buffering is True",
|
||||
0, 100, DEFAULT_HIGH_PERCENT,
|
||||
0.0, 1.0, DEFAULT_HIGH_WATERMARK,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_TEMP_TEMPLATE,
|
||||
|
@ -484,8 +505,8 @@ gst_queue2_init (GstQueue2 * queue)
|
|||
queue->max_level.rate_time = DEFAULT_MAX_SIZE_TIME;
|
||||
queue->use_buffering = DEFAULT_USE_BUFFERING;
|
||||
queue->use_rate_estimate = DEFAULT_USE_RATE_ESTIMATE;
|
||||
queue->low_percent = DEFAULT_LOW_PERCENT;
|
||||
queue->high_percent = DEFAULT_HIGH_PERCENT;
|
||||
queue->low_watermark = DEFAULT_LOW_WATERMARK * MAX_BUFFERING_LEVEL;
|
||||
queue->high_watermark = DEFAULT_HIGH_WATERMARK * MAX_BUFFERING_LEVEL;
|
||||
|
||||
gst_segment_init (&queue->sink_segment, GST_FORMAT_TIME);
|
||||
gst_segment_init (&queue->src_segment, GST_FORMAT_TIME);
|
||||
|
@ -926,7 +947,7 @@ get_buffering_level (GstQueue2 * queue, gboolean * is_buffering,
|
|||
{
|
||||
gint buflevel, buflevel2;
|
||||
|
||||
if (queue->high_percent <= 0) {
|
||||
if (queue->high_watermark <= 0) {
|
||||
if (buffering_level)
|
||||
*buffering_level = MAX_BUFFERING_LEVEL;
|
||||
if (is_buffering)
|
||||
|
@ -992,7 +1013,7 @@ convert_to_buffering_percent (GstQueue2 * queue, gint buffering_level)
|
|||
|
||||
/* scale so that if buffering_level equals the high watermark,
|
||||
* the percentage is 100% */
|
||||
percent = buffering_level * 100 / queue->high_percent;
|
||||
percent = buffering_level * 100 / queue->high_watermark;
|
||||
/* clip */
|
||||
if (percent > 100)
|
||||
percent = 100;
|
||||
|
@ -1096,7 +1117,7 @@ update_buffering (GstQueue2 * queue)
|
|||
} else {
|
||||
/* we were not buffering, check if we need to start buffering if we drop
|
||||
* below the low threshold */
|
||||
if (buffering_level < queue->low_percent) {
|
||||
if (buffering_level < queue->low_watermark) {
|
||||
queue->is_buffering = TRUE;
|
||||
SET_PERCENT (queue, percent);
|
||||
}
|
||||
|
@ -3730,10 +3751,17 @@ gst_queue2_set_property (GObject * object,
|
|||
queue->use_rate_estimate = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_LOW_PERCENT:
|
||||
queue->low_percent = g_value_get_int (value);
|
||||
queue->low_watermark = g_value_get_int (value) * BUF_LEVEL_PERCENT_FACTOR;
|
||||
break;
|
||||
case PROP_HIGH_PERCENT:
|
||||
queue->high_percent = g_value_get_int (value);
|
||||
queue->high_watermark =
|
||||
g_value_get_int (value) * BUF_LEVEL_PERCENT_FACTOR;
|
||||
break;
|
||||
case PROP_LOW_WATERMARK:
|
||||
queue->low_watermark = g_value_get_double (value) * MAX_BUFFERING_LEVEL;
|
||||
break;
|
||||
case PROP_HIGH_WATERMARK:
|
||||
queue->high_watermark = g_value_get_double (value) * MAX_BUFFERING_LEVEL;
|
||||
break;
|
||||
case PROP_TEMP_TEMPLATE:
|
||||
gst_queue2_set_temp_template (queue, g_value_get_string (value));
|
||||
|
@ -3790,10 +3818,18 @@ gst_queue2_get_property (GObject * object,
|
|||
g_value_set_boolean (value, queue->use_rate_estimate);
|
||||
break;
|
||||
case PROP_LOW_PERCENT:
|
||||
g_value_set_int (value, queue->low_percent);
|
||||
g_value_set_int (value, queue->low_watermark / BUF_LEVEL_PERCENT_FACTOR);
|
||||
break;
|
||||
case PROP_HIGH_PERCENT:
|
||||
g_value_set_int (value, queue->high_percent);
|
||||
g_value_set_int (value, queue->high_watermark / BUF_LEVEL_PERCENT_FACTOR);
|
||||
break;
|
||||
case PROP_LOW_WATERMARK:
|
||||
g_value_set_double (value, queue->low_watermark /
|
||||
(gdouble) MAX_BUFFERING_LEVEL);
|
||||
break;
|
||||
case PROP_HIGH_WATERMARK:
|
||||
g_value_set_double (value, queue->high_watermark /
|
||||
(gdouble) MAX_BUFFERING_LEVEL);
|
||||
break;
|
||||
case PROP_TEMP_TEMPLATE:
|
||||
g_value_set_string (value, queue->temp_template);
|
||||
|
|
|
@ -109,8 +109,10 @@ struct _GstQueue2
|
|||
gboolean use_tags_bitrate;
|
||||
gboolean use_rate_estimate;
|
||||
GstClockTime buffering_interval;
|
||||
gint low_percent; /* low/high watermarks for buffering */
|
||||
gint high_percent;
|
||||
|
||||
/* low/high watermarks for buffering */
|
||||
gint low_watermark;
|
||||
gint high_watermark;
|
||||
|
||||
/* current buffering state */
|
||||
gboolean is_buffering;
|
||||
|
|
|
@ -207,6 +207,74 @@ GST_START_TEST (test_simple_create_destroy)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
#define CHECK_FOR_BUFFERING_MSG(PIPELINE, EXPECTED_PERC) \
|
||||
G_STMT_START { \
|
||||
gint buf_perc; \
|
||||
GstMessage *msg; \
|
||||
GST_LOG ("waiting for %d%% buffering message", (EXPECTED_PERC)); \
|
||||
msg = gst_bus_poll (GST_ELEMENT_BUS (PIPELINE), \
|
||||
GST_MESSAGE_BUFFERING | GST_MESSAGE_ERROR, -1); \
|
||||
fail_if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR, \
|
||||
"Expected BUFFERING message, got ERROR message"); \
|
||||
gst_message_parse_buffering (msg, &buf_perc); \
|
||||
gst_message_unref (msg); \
|
||||
fail_unless (buf_perc == (EXPECTED_PERC), \
|
||||
"Got incorrect percentage: %d%% expected: %d%%", buf_perc, \
|
||||
(EXPECTED_PERC)); \
|
||||
} G_STMT_END
|
||||
|
||||
GST_START_TEST (test_watermark_and_fill_level)
|
||||
{
|
||||
/* This test checks the behavior of the fill level and
|
||||
* the low/high watermarks. It also checks if the
|
||||
* low/high-percent and low/high-watermark properties
|
||||
* are coupled together properly. */
|
||||
|
||||
GstElement *pipe, *input, *output, *queue2;
|
||||
gint low_perc, high_perc;
|
||||
|
||||
pipe = gst_pipeline_new ("pipeline");
|
||||
|
||||
input = gst_element_factory_make ("fakesrc", NULL);
|
||||
fail_unless (input != NULL, "failed to create 'fakesrc' element");
|
||||
/* Configure fakesrc to send one single buffer with 50000 bytes,
|
||||
* which makes 50000 / 1000000 = 50% of the max queue2 size. */
|
||||
g_object_set (input, "num-buffers", 1, "sizetype", 2, "sizemax", 50000, NULL);
|
||||
|
||||
output = gst_element_factory_make ("fakesink", NULL);
|
||||
fail_unless (output != NULL, "failed to create 'fakesink' element");
|
||||
|
||||
queue2 = setup_queue2 (pipe, input, output);
|
||||
g_object_set (queue2,
|
||||
"use-buffering", (gboolean) TRUE,
|
||||
"max-size-bytes", (guint) 1000000,
|
||||
"max-size-buffers", (guint) 0,
|
||||
"max-size-time", (guint64) 0,
|
||||
"low-watermark", (gdouble) 0.01, "high-watermark", (gdouble) 0.10, NULL);
|
||||
|
||||
g_object_get (queue2, "low-percent", &low_perc,
|
||||
"high-percent", &high_perc, NULL);
|
||||
|
||||
/* Check that low/high-watermark and low/high-percent are
|
||||
* coupled properly. (low/high-percent are deprecated and
|
||||
* exist for backwards compatibility.) */
|
||||
fail_unless_equals_int (low_perc, 1);
|
||||
fail_unless_equals_int (high_perc, 10);
|
||||
|
||||
gst_element_set_state (pipe, GST_STATE_PLAYING);
|
||||
|
||||
/* First buffering message will contain 0% (the initial state).
|
||||
* Second buffering message contain 50% after the single
|
||||
* buffer from fakesrc is pushed downstream. */
|
||||
CHECK_FOR_BUFFERING_MSG (pipe, 0);
|
||||
CHECK_FOR_BUFFERING_MSG (pipe, 50);
|
||||
|
||||
gst_element_set_state (pipe, GST_STATE_NULL);
|
||||
gst_object_unref (pipe);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static gpointer
|
||||
push_buffer (GstPad * sinkpad)
|
||||
{
|
||||
|
@ -384,6 +452,7 @@ queue2_suite (void)
|
|||
tcase_add_test (tc_chain, test_simple_pipeline_ringbuffer);
|
||||
tcase_add_test (tc_chain, test_simple_shutdown_while_running);
|
||||
tcase_add_test (tc_chain, test_simple_shutdown_while_running_ringbuffer);
|
||||
tcase_add_test (tc_chain, test_watermark_and_fill_level);
|
||||
tcase_add_test (tc_chain, test_filled_read);
|
||||
tcase_add_test (tc_chain, test_percent_overflow);
|
||||
tcase_add_test (tc_chain, test_small_ring_buffer);
|
||||
|
|
Loading…
Reference in a new issue