queue: Ignore thresholds if a query is queued
authorOlivier Crête <olivier.crete@collabora.com>
Thu, 1 Mar 2018 21:19:09 +0000 (16:19 -0500)
committerOlivier Crête <olivier.crete@collabora.com>
Thu, 1 Mar 2018 21:31:57 +0000 (16:31 -0500)
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
libs/gst/base/gstqueuearray.h
plugins/elements/gstqueue.c
tests/check/elements/queue.c

index 0f8ed57..ebec179 100644 (file)
@@ -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
  *
index c05780e..5752320 100644 (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
 
index 431dcdc..a8753ea 100644 (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.
index 50f2896..a41ef64 100644 (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);