queue: Ignore thresholds if a query is queued
The queue gets filled by the tail, so a query will always be the tail
object, not the head object. Also add a _peek_tail_struct() method to the
GstQueueArray to enable looking at the tail.
With unit test to prevent future regression.
https://bugzilla.gnome.org/show_bug.cgi?id=762875
diff --git a/libs/gst/base/gstqueuearray.c b/libs/gst/base/gstqueuearray.c
index 0f8ed57..ebec179 100644
--- a/libs/gst/base/gstqueuearray.c
+++ b/libs/gst/base/gstqueuearray.c
@@ -339,6 +339,34 @@
}
/**
+ * gst_queue_array_peek_tail_struct: (skip)
+ * @array: a #GstQueueArray object
+ *
+ * Returns the tail of the queue @array, but does not remove it from the queue.
+ *
+ * Returns: The tail of the queue
+ *
+ * Since: 1.14
+ */
+gpointer
+gst_queue_array_peek_tail_struct (GstQueueArray * array)
+{
+ guint len, idx;
+
+ g_return_val_if_fail (array != NULL, NULL);
+
+ len = array->length;
+
+ /* empty array */
+ if (len == 0)
+ return NULL;
+
+ idx = (array->head + (len - 1)) % array->size;
+
+ return array->array + (array->elt_size * idx);
+}
+
+/**
* gst_queue_array_pop_tail: (skip)
* @array: a #GstQueueArray object
*
diff --git a/libs/gst/base/gstqueuearray.h b/libs/gst/base/gstqueuearray.h
index c05780e..5752320 100644
--- a/libs/gst/base/gstqueuearray.h
+++ b/libs/gst/base/gstqueuearray.h
@@ -83,6 +83,8 @@
gboolean gst_queue_array_drop_struct (GstQueueArray * array,
guint idx,
gpointer p_struct);
+GST_EXPORT
+gpointer gst_queue_array_peek_tail_struct (GstQueueArray * array);
G_END_DECLS
diff --git a/plugins/elements/gstqueue.c b/plugins/elements/gstqueue.c
index 431dcdc..a8753ea 100644
--- a/plugins/elements/gstqueue.c
+++ b/plugins/elements/gstqueue.c
@@ -1094,18 +1094,18 @@
static gboolean
gst_queue_is_empty (GstQueue * queue)
{
- GstQueueItem *head;
+ GstQueueItem *tail;
- head = gst_queue_array_peek_head_struct (queue->queue);
+ tail = gst_queue_array_peek_tail_struct (queue->queue);
- if (head == NULL)
+ if (tail == NULL)
return TRUE;
/* Only consider the queue empty if the minimum thresholds
- * are not reached and data is at the queue head. Otherwise
+ * are not reached and data is at the queue tail. Otherwise
* we would block forever on serialized queries.
*/
- if (!GST_IS_BUFFER (head->item) && !GST_IS_BUFFER_LIST (head->item))
+ if (!GST_IS_BUFFER (tail->item) && !GST_IS_BUFFER_LIST (tail->item))
return FALSE;
/* It is possible that a max size is reached before all min thresholds are.
diff --git a/tests/check/elements/queue.c b/tests/check/elements/queue.c
index 50f2896..a41ef64 100644
--- a/tests/check/elements/queue.c
+++ b/tests/check/elements/queue.c
@@ -906,6 +906,40 @@
GST_END_TEST;
+
+GST_START_TEST (test_serialized_query_with_threshold)
+{
+ GstQuery *query;
+ GstSegment segment;
+
+ gst_segment_init (&segment, GST_FORMAT_BYTES);
+
+ mysinkpad = gst_check_setup_sink_pad (queue, &sinktemplate);
+ gst_pad_set_event_function (mysinkpad, event_func);
+ gst_pad_set_active (mysinkpad, TRUE);
+
+ g_object_set (queue, "min-threshold-buffers", 10, NULL);
+
+ fail_unless (gst_element_set_state (queue,
+ GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+ "could not set to playing");
+
+ gst_pad_push_event (mysrcpad, gst_event_new_stream_start ("test"));
+ gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment));
+
+ gst_pad_push (mysrcpad, gst_buffer_new ());
+
+ query = gst_query_new_drain ();
+ gst_pad_peer_query (mysrcpad, query);
+ gst_query_unref (query);
+
+ fail_unless (gst_element_set_state (queue,
+ GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
+}
+
+GST_END_TEST;
+
+
static gpointer
push_event_thread_func (gpointer data)
{
@@ -1162,6 +1196,7 @@
tcase_add_test (tc_chain, test_time_level);
tcase_add_test (tc_chain, test_time_level_task_not_started);
tcase_add_test (tc_chain, test_queries_while_flushing);
+ tcase_add_test (tc_chain, test_serialized_query_with_threshold);
tcase_add_test (tc_chain, test_state_change_when_flushing);
#if 0
tcase_add_test (tc_chain, test_newsegment);