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
This commit is contained in:
Olivier Crête 2018-03-01 16:19:09 -05:00
parent 9e44738ae7
commit 23b32d5600
4 changed files with 70 additions and 5 deletions

View file

@ -338,6 +338,34 @@ gst_queue_array_peek_tail (GstQueueArray * array)
return *(gpointer *) (array->array + (sizeof (gpointer) * idx));
}
/**
* 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

View file

@ -83,6 +83,8 @@ GST_EXPORT
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

View file

@ -1094,18 +1094,18 @@ out_flushing:
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.

View file

@ -906,6 +906,40 @@ GST_START_TEST (test_queries_while_flushing)
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 @@ queue_suite (void)
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);