[PATCH v2 4/6] winegstreamer: Move fetching of stream duration to the designated function.

Derek Lesho dlesho at codeweavers.com
Fri Sep 17 14:58:56 CDT 2021


In push mode parsers, we won't want to retrieve the duration.

Signed-off-by: Derek Lesho <dlesho at codeweavers.com>
---
 dlls/winegstreamer/wg_parser.c | 145 +++++++++++++++++++--------------
 1 file changed, 86 insertions(+), 59 deletions(-)

diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c
index 98b7491998b..f751463a548 100644
--- a/dlls/winegstreamer/wg_parser.c
+++ b/dlls/winegstreamer/wg_parser.c
@@ -503,70 +503,14 @@ static bool wg_parser_initialize(struct wg_parser *parser)
     for (i = 0; i < parser->stream_count; ++i)
     {
         struct wg_parser_stream *stream = parser->streams[i];
-        gint64 duration;
 
         while (!stream->has_caps && !parser->error)
             pthread_cond_wait(&parser->state_cond, &parser->mutex);
 
-        /* GStreamer doesn't actually provide any guarantees about when duration
-         * is available, even for seekable streams. It's basically built for
-         * applications that don't care, e.g. movie players that can display
-         * a duration once it's available, and update it visually if a better
-         * estimate is found. This doesn't really match well with DirectShow or
-         * Media Foundation, which both expect duration to be available
-         * immediately on connecting, so we have to use some complex heuristics
-         * to try to actually get a usable duration.
-         *
-         * Some elements (avidemux, wavparse, qtdemux) record duration almost
-         * immediately, before fixing caps. Such elements don't send
-         * duration-changed messages. Therefore always try querying duration
-         * after caps have been found.
-         *
-         * Some elements (mpegaudioparse) send duration-changed. In the case of
-         * a mp3 stream without seek tables it will not be sent immediately, but
-         * only after enough frames have been parsed to form an estimate. They
-         * may send it multiple times with increasingly accurate estimates, but
-         * unfortunately we have no way of knowing whether another estimate will
-         * be sent, so we always take the first one. We assume that if the
-         * duration is not immediately available then the element will always
-         * send duration-changed.
-         */
-
-        for (;;)
+        if (parser->error)
         {
-            if (parser->error)
-            {
-                pthread_mutex_unlock(&parser->mutex);
-                return 0;
-            }
-            if (gst_pad_query_duration(stream->their_src, GST_FORMAT_TIME, &duration))
-            {
-                stream->duration = duration / 100;
-                break;
-            }
-
-            if (stream->eos)
-            {
-                stream->duration = 0;
-                GST_WARNING("Failed to query duration.\n");
-                break;
-            }
-
-            /* Elements based on GstBaseParse send duration-changed before
-             * actually updating the duration in GStreamer versions prior
-             * to 1.17.1. See <gstreamer.git:d28e0b4147fe7073b2>. So after
-             * receiving duration-changed we have to continue polling until
-             * the query succeeds. */
-            if (parser->has_duration)
-            {
-                pthread_mutex_unlock(&parser->mutex);
-                g_usleep(10000);
-                pthread_mutex_lock(&parser->mutex);
-            }
-            else
-            {
-                pthread_cond_wait(&parser->state_cond, &parser->mutex);
-            }
+            pthread_mutex_unlock(&parser->mutex);
+            return 0;
         }
     }
 
@@ -812,6 +756,87 @@ static void CDECL wg_parser_stream_release_buffer(struct wg_parser_stream *strea
 
 static uint64_t CDECL wg_parser_stream_get_duration(struct wg_parser_stream *stream)
 {
+    struct wg_parser *parser = stream->parser;
+    gint64 duration;
+
+    pthread_mutex_lock(&parser->mutex);
+
+    if (stream->duration != UINT64_MAX)
+    {
+        pthread_mutex_unlock(&parser->mutex);
+        return stream->duration;
+    }
+
+    if (!parser->flushing)
+    {
+        GST_WARNING("Parser must be flushing to retrieve duration.\n");
+        pthread_mutex_unlock(&parser->mutex);
+        return UINT64_MAX;
+    }
+
+    /* GStreamer doesn't actually provide any guarantees about when duration
+        * is available, even for seekable streams. It's basically built for
+        * applications that don't care, e.g. movie players that can display
+        * a duration once it's available, and update it visually if a better
+        * estimate is found. This doesn't really match well with DirectShow or
+        * Media Foundation, which both expect duration to be available
+        * immediately on connecting, so we have to use some complex heuristics
+        * to try to actually get a usable duration.
+        *
+        * Some elements (avidemux, wavparse, qtdemux) record duration almost
+        * immediately, before fixing caps. Such elements don't send
+        * duration-changed messages. Therefore always try querying duration
+        * after caps have been found.
+        *
+        * Some elements (mpegaudioparse) send duration-changed. In the case of
+        * a mp3 stream without seek tables it will not be sent immediately, but
+        * only after enough frames have been parsed to form an estimate. They
+        * may send it multiple times with increasingly accurate estimates, but
+        * unfortunately we have no way of knowing whether another estimate will
+        * be sent, so we always take the first one. We assume that if the
+        * duration is not immediately available then the element will always
+        * send duration-changed.
+        */
+
+    for (;;)
+    {
+        if (parser->error)
+        {
+            pthread_mutex_unlock(&parser->mutex);
+            return 0;
+        }
+        if (gst_pad_query_duration(stream->their_src, GST_FORMAT_TIME, &duration))
+        {
+            stream->duration = duration / 100;
+            break;
+        }
+
+        if (stream->eos)
+        {
+            stream->duration = 0;
+            GST_WARNING("Failed to query duration.\n");
+            break;
+        }
+
+        /* Elements based on GstBaseParse send duration-changed before
+            * actually updating the duration in GStreamer versions prior
+            * to 1.17.1. See <gstreamer.git:d28e0b4147fe7073b2>. So after
+            * receiving duration-changed we have to continue polling until
+            * the query succeeds. */
+        if (parser->has_duration)
+        {
+            pthread_mutex_unlock(&parser->mutex);
+            g_usleep(10000);
+            pthread_mutex_lock(&parser->mutex);
+        }
+        else
+        {
+            pthread_cond_wait(&parser->state_cond, &parser->mutex);
+        }
+    }
+
+    pthread_mutex_unlock(&parser->mutex);
+
     return stream->duration;
 }
 
@@ -1173,6 +1198,8 @@ static struct wg_parser_stream *create_stream(struct wg_parser *parser)
     gst_pad_set_event_function(stream->my_sink, sink_event_cb);
     gst_pad_set_query_function(stream->my_sink, sink_query_cb);
 
+    stream->duration = UINT64_MAX;
+
     parser->streams[parser->stream_count++] = stream;
     return stream;
 }
-- 
2.33.0




More information about the wine-devel mailing list