From 23b32d56008d364257d1d186da52650cb4475aa4 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Olivier=20Cr=C3=AAte?= Date: Thu, 1 Mar 2018 16:19:09 -0500 Subject: [PATCH] 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 --- libs/gst/base/gstqueuearray.c | 28 ++++++++++++++++++++++++++++ libs/gst/base/gstqueuearray.h | 2 ++ plugins/elements/gstqueue.c | 10 +++++----- tests/check/elements/queue.c | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 70 insertions(+), 5 deletions(-) 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 (GstQueueArray * array) } /** + * 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 @@ 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 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 @@ 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. 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_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); -- 2.7.4