queue2: avoid ping-pong between 0% and 100% buffering messages
authorMatthew Waters <matthew@centricular.com>
Thu, 17 May 2018 11:09:36 +0000 (21:09 +1000)
committerEdward Hervey <bilboed@bilboed.com>
Wed, 7 Nov 2018 15:04:14 +0000 (15:04 +0000)
If upstream is pushing buffers larger than our limits, only 1 buffer
is ever in the queue at a time.  Once that single buffer has left the
queue, a 0% buffering message would be posted followed immediately by a
100% buffering message when the next buffer was inserted into the queue
a very short time later.  As per the recommendations, This would result
in the application pausing for a short while causing the appearance of
a short stutter.

The first step of a solution involves not posting a buffering message if
there is still data waiting on the sink pad for insertion into the queue.
This successfully drops the 0% messages from being posted however a
message is still posted on each transition to 100% when the new buffer
arrives resulting in a string of 100% buffering messages.  We silence
these by storing the last posted buffering percentage and only posting a
new message when it is different from or last posted message.

plugins/elements/gstqueue2.c
plugins/elements/gstqueue2.h

index bc3627f..f227a2b 100644 (file)
@@ -531,6 +531,7 @@ gst_queue2_init (GstQueue2 * queue)
 
   g_mutex_init (&queue->buffering_post_lock);
   queue->buffering_percent = 100;
+  queue->last_posted_buffering_percent = -1;
 
   /* tempfile related */
   queue->temp_template = NULL;
@@ -1056,17 +1057,31 @@ static GstMessage *
 gst_queue2_get_buffering_message (GstQueue2 * queue)
 {
   GstMessage *msg = NULL;
-
   if (queue->percent_changed) {
-    gint percent = queue->buffering_percent;
-
+    /* Don't change the buffering level if the sinkpad is waiting for
+     * space to become available.  This prevents the situation where,
+     * upstream is pushing buffers larger than our limits so only 1 buffer
+     * is ever in the queue at a time.
+     * Changing the level causes a buffering message to be posted saying that
+     * we are buffering which the application may pause to wait for another
+     * 100% buffering message which would be posted very soon after the
+     * waiting sink thread adds it's buffer to the queue */
+    /* FIXME: This situation above can still occur later if
+     * the sink pad is waiting to push a serialized event into the queue and
+     * the queue becomes empty for a short period of time. */
+    if (!queue->waiting_del
+        && queue->last_posted_buffering_percent != queue->buffering_percent) {
+      gint percent = queue->buffering_percent;
+
+      GST_DEBUG_OBJECT (queue, "Going to post buffering: %d%%", percent);
+      msg = gst_message_new_buffering (GST_OBJECT_CAST (queue), percent);
+
+      gst_message_set_buffering_stats (msg, queue->mode, queue->avg_in,
+          queue->avg_out, queue->buffering_left);
+
+      queue->last_posted_buffering_percent = percent;
+    }
     queue->percent_changed = FALSE;
-
-    GST_DEBUG_OBJECT (queue, "Going to post buffering: %d%%", percent);
-    msg = gst_message_new_buffering (GST_OBJECT_CAST (queue), percent);
-
-    gst_message_set_buffering_stats (msg, queue->mode, queue->avg_in,
-        queue->avg_out, queue->buffering_left);
   }
 
   return msg;
index fed3656..cd0ab2b 100644 (file)
@@ -119,6 +119,7 @@ struct _GstQueue2
   /* current buffering state */
   gboolean is_buffering;
   gint buffering_percent;
+  gint last_posted_buffering_percent;
 
   /* for measuring input/output rates */
   GTimer *in_timer;