appsink: fix timeout logic for gst_app_sink_try_pull_sample
authorTomáš Polomský <1155369-polomsky@users.noreply.gitlab.freedesktop.org>
Tue, 26 Nov 2024 05:40:34 +0000 (06:40 +0100)
committerBackport Bot <gitlab-backport-bot@gstreamer-foundation.org>
Wed, 27 Nov 2024 12:27:12 +0000 (12:27 +0000)
In case of gst_app_sink_try_pull_object returns an object instead of a sample,
the whole process must be restarted with the reduced timeout, otherwise requested
timeout could be easily exceeded.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7980>

subprojects/gst-plugins-base/gst-libs/gst/app/gstappsink.c

index eeb6d68c2548c35edd16f9c84872cc21b68ebe4a..506cc36861da3d9892acd6294d49d62892a267c4 100644 (file)
@@ -2002,6 +2002,20 @@ not_started:
 GstSample *
 gst_app_sink_try_pull_sample (GstAppSink * appsink, GstClockTime timeout)
 {
+  gboolean timeout_valid;
+  gint64 end_time, now;
+
+  /*
+   * 0 is valid but has a special meaning for gst_app_sink_try_pull_object which fetches
+   * a sample/event that is available without waiting. For 0, we don't want to deduct
+   * from the timeout to allow skipping all events and reading a sample directly.
+   */
+  timeout_valid = timeout != 0 && GST_CLOCK_TIME_IS_VALID (timeout);
+
+  if (timeout_valid)
+    end_time =
+        g_get_monotonic_time () + timeout / (GST_SECOND / G_TIME_SPAN_SECOND);
+
   while (TRUE) {
     GstMiniObject *obj;
 
@@ -2013,6 +2027,14 @@ gst_app_sink_try_pull_sample (GstAppSink * appsink, GstClockTime timeout)
       return GST_SAMPLE_CAST (obj);
     } else {
       gst_mini_object_unref (obj);
+      if (timeout_valid) {
+        now = g_get_monotonic_time ();
+        if (now >= end_time) {
+          /* timeout expired */
+          return NULL;
+        }
+        timeout = (end_time - now) * (GST_SECOND / G_TIME_SPAN_SECOND);
+      }
     }
   }
 }