[PATCH 3/3] winegstreamer: Merge parser creation functions and wg_parser_connect.

Derek Lesho dlesho at codeweavers.com
Thu Sep 16 16:00:47 CDT 2021


Signed-off-by: Derek Lesho <dlesho at codeweavers.com>
---
 dlls/winegstreamer/gst_private.h   |  17 +-
 dlls/winegstreamer/media_source.c  |  11 +-
 dlls/winegstreamer/quartz_parser.c |  40 +--
 dlls/winegstreamer/wg_parser.c     | 405 ++++++++++++++---------------
 4 files changed, 238 insertions(+), 235 deletions(-)

diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index 22d9547ed72..23d800f6247 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -156,16 +156,21 @@ struct wg_parser_event
 };
 C_ASSERT(sizeof(struct wg_parser_event) == 40);
 
+enum wg_parser_type
+{
+    WG_DECODEBIN_PARSER,
+    WG_AVI_PARSER,
+    WG_MPEG_AUDIO_PARSER,
+    WG_WAVE_PARSER,
+};
+
+struct wg_parser;
+
 struct unix_funcs
 {
-    struct wg_parser *(CDECL *wg_decodebin_parser_create)(void);
-    struct wg_parser *(CDECL *wg_avi_parser_create)(void);
-    struct wg_parser *(CDECL *wg_mpeg_audio_parser_create)(void);
-    struct wg_parser *(CDECL *wg_wave_parser_create)(void);
+    struct wg_parser *(CDECL *wg_parser_create)(enum wg_parser_type parser_type, uint64_t file_size);
     void (CDECL *wg_parser_destroy)(struct wg_parser *parser);
 
-    HRESULT (CDECL *wg_parser_connect)(struct wg_parser *parser, uint64_t file_size);
-
     void (CDECL *wg_parser_begin_flush)(struct wg_parser *parser);
     void (CDECL *wg_parser_end_flush)(struct wg_parser *parser);
 
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index 6c2bf92e2a2..fa1ed002404 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -1324,7 +1324,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
     if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue)))
         goto fail;
 
-    if (!(parser = unix_funcs->wg_decodebin_parser_create()))
+    if (!(parser = unix_funcs->wg_parser_create(WG_DECODEBIN_PARSER, file_size)))
     {
         hr = E_OUTOFMEMORY;
         goto fail;
@@ -1335,9 +1335,6 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
 
     object->state = SOURCE_OPENING;
 
-    if (FAILED(hr = unix_funcs->wg_parser_connect(parser, file_size)))
-        goto fail;
-
     /* In Media Foundation, sources may read from any media source stream
      * without fear of blocking due to buffering limits on another. Trailmakers,
      * a Unity3D Engine game, only reads one sample from the audio stream (and
@@ -1346,7 +1343,11 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_
      * leak occurs with native. */
     unix_funcs->wg_parser_set_unlimited_buffering(parser);
 
-    stream_count = unix_funcs->wg_parser_get_stream_count(parser);
+    if (!(stream_count = unix_funcs->wg_parser_get_stream_count(parser)))
+    {
+        hr = E_FAIL;
+        goto fail;
+    }
 
     if (!(object->streams = calloc(stream_count, sizeof(*object->streams))))
     {
diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c
index bf69a881d57..f21c820b21a 100644
--- a/dlls/winegstreamer/quartz_parser.c
+++ b/dlls/winegstreamer/quartz_parser.c
@@ -59,7 +59,7 @@ struct parser
 
     HANDLE read_thread;
 
-    struct wg_parser * (*parser_create)(void);
+    enum wg_parser_type parser_type;
     BOOL (*init_gst)(struct parser *filter);
     HRESULT (*source_query_accept)(struct parser_source *pin, const AM_MEDIA_TYPE *mt);
     HRESULT (*source_get_media_type)(struct parser_source *pin, unsigned int index, AM_MEDIA_TYPE *mt);
@@ -974,17 +974,14 @@ static HRESULT parser_sink_connect(struct strmbase_sink *iface, IPin *peer, cons
 
     IAsyncReader_Length(filter->reader, &file_size, &unused);
 
-    if (!(filter->wg_parser = filter->parser_create()))
+    if (!(filter->wg_parser = unix_funcs->wg_parser_create(filter->parser_type, file_size)))
     {
         hr = E_OUTOFMEMORY;
         goto err;
     }
 
-    filter->sink_connected = true;
     filter->read_thread = CreateThread(NULL, 0, read_thread, filter, 0, NULL);
 
-    if (FAILED(hr = unix_funcs->wg_parser_connect(filter->wg_parser, file_size)))
-        goto err;
 
     if (!filter->init_gst(filter))
     {
@@ -1000,6 +997,8 @@ static HRESULT parser_sink_connect(struct strmbase_sink *iface, IPin *peer, cons
         pin->seek.llCurrent = 0;
     }
 
+    filter->sink_connected = true;
+
     return S_OK;
 err:
     GST_RemoveOutputPins(filter);
@@ -1039,7 +1038,7 @@ static BOOL decodebin_parser_filter_init_gst(struct parser *filter)
             return FALSE;
     }
 
-    return TRUE;
+    return !!stream_count;
 }
 
 static HRESULT decodebin_parser_source_query_accept(struct parser_source *pin, const AM_MEDIA_TYPE *mt)
@@ -1120,7 +1119,7 @@ HRESULT decodebin_parser_create(IUnknown *outer, IUnknown **out)
     if (!(object = calloc(1, sizeof(*object))))
         return E_OUTOFMEMORY;
 
-    object->parser_create = unix_funcs->wg_decodebin_parser_create;
+    object->parser_type = WG_DECODEBIN_PARSER;
 
     strmbase_filter_init(&object->filter, outer, &CLSID_decodebin_parser, &filter_ops);
     strmbase_sink_init(&object->sink, &object->filter, L"input pin", &sink_ops, NULL);
@@ -1553,9 +1552,6 @@ static HRESULT GST_RemoveOutputPins(struct parser *This)
 
     unix_funcs->wg_parser_destroy(This->wg_parser);
 
-    /* read_thread() needs to stay alive to service any read requests GStreamer
-     * sends, so we can only shut it down after GStreamer stops. */
-    This->sink_connected = false;
     WaitForSingleObject(This->read_thread, INFINITE);
     CloseHandle(This->read_thread);
 
@@ -1568,6 +1564,7 @@ static HRESULT GST_RemoveOutputPins(struct parser *This)
     This->source_count = 0;
     free(This->sources);
     This->sources = NULL;
+    This->sink_connected = false;
 
     BaseFilterImpl_IncrementPinVersion(&This->filter);
     return S_OK;
@@ -1603,11 +1600,12 @@ static const struct strmbase_sink_ops wave_parser_sink_ops =
 static BOOL wave_parser_filter_init_gst(struct parser *filter)
 {
     struct wg_parser *parser = filter->wg_parser;
+    struct wg_parser_stream *stream = unix_funcs->wg_parser_get_stream(parser, 0);
 
-    if (!create_pin(filter, unix_funcs->wg_parser_get_stream(parser, 0), L"output"))
+    if (!stream)
         return FALSE;
 
-    return TRUE;
+    return !!create_pin(filter, stream, L"output");
 }
 
 static HRESULT wave_parser_source_query_accept(struct parser_source *pin, const AM_MEDIA_TYPE *mt)
@@ -1647,7 +1645,7 @@ HRESULT wave_parser_create(IUnknown *outer, IUnknown **out)
     if (!(object = calloc(1, sizeof(*object))))
         return E_OUTOFMEMORY;
 
-    object->parser_create = unix_funcs->wg_wave_parser_create;
+    object->parser_type = WG_WAVE_PARSER;
 
     strmbase_filter_init(&object->filter, outer, &CLSID_WAVEParser, &filter_ops);
     strmbase_sink_init(&object->sink, &object->filter, L"input pin", &wave_parser_sink_ops, NULL);
@@ -1678,18 +1676,21 @@ static const struct strmbase_sink_ops avi_splitter_sink_ops =
 static BOOL avi_splitter_filter_init_gst(struct parser *filter)
 {
     struct wg_parser *parser = filter->wg_parser;
+    struct wg_parser_stream *stream;
     uint32_t i, stream_count;
     WCHAR source_name[20];
 
     stream_count = unix_funcs->wg_parser_get_stream_count(parser);
     for (i = 0; i < stream_count; ++i)
     {
+        if (!(stream = unix_funcs->wg_parser_get_stream(parser, i)))
+            return FALSE;
         swprintf(source_name, ARRAY_SIZE(source_name), L"Stream %02u", i);
-        if (!create_pin(filter, unix_funcs->wg_parser_get_stream(parser, i), source_name))
+        if (!create_pin(filter, stream, source_name))
             return FALSE;
     }
 
-    return TRUE;
+    return !!stream_count;
 }
 
 static HRESULT avi_splitter_source_query_accept(struct parser_source *pin, const AM_MEDIA_TYPE *mt)
@@ -1729,7 +1730,7 @@ HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out)
     if (!(object = calloc(1, sizeof(*object))))
         return E_OUTOFMEMORY;
 
-    object->parser_create = unix_funcs->wg_avi_parser_create;
+    object->parser_type = WG_AVI_PARSER;
 
     strmbase_filter_init(&object->filter, outer, &CLSID_AviSplitter, &filter_ops);
     strmbase_sink_init(&object->sink, &object->filter, L"input pin", &avi_splitter_sink_ops, NULL);
@@ -1765,11 +1766,12 @@ static const struct strmbase_sink_ops mpeg_splitter_sink_ops =
 static BOOL mpeg_splitter_filter_init_gst(struct parser *filter)
 {
     struct wg_parser *parser = filter->wg_parser;
+    struct wg_parser_stream *stream = unix_funcs->wg_parser_get_stream(parser, 0);
 
-    if (!create_pin(filter, unix_funcs->wg_parser_get_stream(parser, 0), L"Audio"))
+    if (!stream)
         return FALSE;
 
-    return TRUE;
+    return !!create_pin(filter, stream, L"Audio");
 }
 
 static HRESULT mpeg_splitter_source_query_accept(struct parser_source *pin, const AM_MEDIA_TYPE *mt)
@@ -1832,7 +1834,7 @@ HRESULT mpeg_splitter_create(IUnknown *outer, IUnknown **out)
     if (!(object = calloc(1, sizeof(*object))))
         return E_OUTOFMEMORY;
 
-    object->parser_create = unix_funcs->wg_mpeg_audio_parser_create;
+    object->parser_type = WG_MPEG_AUDIO_PARSER;
 
     strmbase_filter_init(&object->filter, outer, &CLSID_MPEG1Splitter, &mpeg_splitter_ops);
     strmbase_sink_init(&object->sink, &object->filter, L"Input", &mpeg_splitter_sink_ops, NULL);
diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c
index 5ab7991b0f2..2b2c8852303 100644
--- a/dlls/winegstreamer/wg_parser.c
+++ b/dlls/winegstreamer/wg_parser.c
@@ -45,8 +45,6 @@ GST_DEBUG_CATEGORY_STATIC(wine);
 
 struct wg_parser
 {
-    BOOL (*init_gst)(struct wg_parser *parser);
-
     struct wg_parser_stream **streams;
     unsigned int stream_count;
 
@@ -66,7 +64,7 @@ struct wg_parser
         bool pending;
     } read_request;
 
-    bool flushing, sink_connected;
+    bool flushing;
 };
 
 struct wg_parser_stream
@@ -478,13 +476,59 @@ static bool wg_format_compare(const struct wg_format *a, const struct wg_format
     return false;
 }
 
+static bool wg_parser_initialize(struct wg_parser *parser)
+{
+    unsigned int i;
+    int ret;
+
+    ret = gst_element_get_state(parser->container, NULL, NULL, -1);
+    if (ret == GST_STATE_CHANGE_FAILURE)
+    {
+        GST_ERROR("Failed to play stream.\n");
+        return 0;
+    }
+
+    pthread_mutex_lock(&parser->mutex);
+    while (!parser->no_more_pads && !parser->error)
+        pthread_cond_wait(&parser->state_cond, &parser->mutex);
+    if (parser->error)
+    {
+        pthread_mutex_unlock(&parser->mutex);
+        GST_ERROR("Failed to play stream.\n");
+        return 0;
+    }
+
+    for (i = 0; i < parser->stream_count; i++)
+    {
+        struct wg_parser_stream *stream = parser->streams[i];
+
+        while (!stream->has_caps && !parser->error)
+            pthread_cond_wait(&parser->state_cond, &parser->mutex);
+
+        if (parser->error)
+        {
+            pthread_mutex_unlock(&parser->mutex);
+            return 0;
+        }
+    }
+
+    pthread_mutex_unlock(&parser->mutex);
+    return 1;
+}
+
 static uint32_t CDECL wg_parser_get_stream_count(struct wg_parser *parser)
 {
+    if (!wg_parser_initialize(parser))
+        return 0;
+
     return parser->stream_count;
 }
 
 static struct wg_parser_stream * CDECL wg_parser_get_stream(struct wg_parser *parser, uint32_t index)
 {
+    if (!wg_parser_initialize(parser))
+        return 0;
+
     return parser->streams[index];
 }
 
@@ -492,6 +536,9 @@ static void CDECL wg_parser_begin_flush(struct wg_parser *parser)
 {
     unsigned int i;
 
+    if (!wg_parser_initialize(parser))
+        return;
+
     pthread_mutex_lock(&parser->mutex);
     parser->flushing = true;
     pthread_mutex_unlock(&parser->mutex);
@@ -708,6 +755,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 UINT64_MAX;
+        }
+        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;
 }
 
@@ -1069,6 +1197,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;
 }
@@ -1336,153 +1466,6 @@ static GstBusSyncReply bus_handler_cb(GstBus *bus, GstMessage *msg, gpointer use
     return GST_BUS_DROP;
 }
 
-static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_size)
-{
-    unsigned int i;
-    int ret;
-
-    if (!parser->bus)
-    {
-        parser->bus = gst_bus_new();
-        gst_bus_set_sync_handler(parser->bus, bus_handler_cb, parser, NULL);
-    }
-
-    parser->container = gst_bin_new(NULL);
-    gst_element_set_bus(parser->container, parser->bus);
-
-    if (!(parser->appsrc = create_element("appsrc", "base")))
-        return E_FAIL;
-    gst_bin_add(GST_BIN(parser->container), parser->appsrc);
-
-    g_object_set(parser->appsrc, "stream-type", GST_APP_STREAM_TYPE_RANDOM_ACCESS, NULL);
-    g_object_set(parser->appsrc, "size", file_size, NULL);
-    g_signal_connect(parser->appsrc, "need-data", G_CALLBACK(src_need_data), parser);
-    g_signal_connect(parser->appsrc, "seek-data", G_CALLBACK(src_seek_data), parser);
-
-    parser->read_request.offset = 0;
-    parser->error = false;
-
-    if (!parser->init_gst(parser))
-        goto out;
-
-    gst_element_set_state(parser->container, GST_STATE_PAUSED);
-    ret = gst_element_get_state(parser->container, NULL, NULL, -1);
-    if (ret == GST_STATE_CHANGE_FAILURE)
-    {
-        GST_ERROR("Failed to play stream.\n");
-        goto out;
-    }
-
-    pthread_mutex_lock(&parser->mutex);
-
-    while (!parser->no_more_pads && !parser->error)
-        pthread_cond_wait(&parser->init_cond, &parser->mutex);
-    if (parser->error)
-    {
-        pthread_mutex_unlock(&parser->mutex);
-        goto out;
-    }
-
-    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)
-            {
-                pthread_mutex_unlock(&parser->mutex);
-                goto out;
-            }
-            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);
-
-    parser->sink_connected = true;
-    return S_OK;
-
-out:
-    if (parser->container)
-        gst_element_set_state(parser->container, GST_STATE_NULL);
-
-    for (i = 0; i < parser->stream_count; ++i)
-        free_stream(parser->streams[i]);
-    parser->stream_count = 0;
-    free(parser->streams);
-    parser->streams = NULL;
-
-    if (parser->container)
-    {
-        gst_element_set_bus(parser->container, NULL);
-        gst_object_unref(parser->container);
-        parser->container = NULL;
-    }
-
-    pthread_mutex_lock(&parser->mutex);
-    parser->sink_connected = false;
-    pthread_mutex_unlock(&parser->mutex);
-    pthread_cond_signal(&parser->read_cond);
-
-    return E_FAIL;
-}
-
 static BOOL decodebin_parser_init_gst(struct wg_parser *parser)
 {
     GstElement *element;
@@ -1564,7 +1547,6 @@ static BOOL mpeg_audio_parser_init_gst(struct wg_parser *parser)
         return FALSE;
     }
     gst_pad_set_active(stream->my_sink, 1);
-
     parser->no_more_pads = true;
 
     return TRUE;
@@ -1598,61 +1580,82 @@ static BOOL wave_parser_init_gst(struct wg_parser *parser)
         return FALSE;
     }
     gst_pad_set_active(stream->my_sink, 1);
-
     parser->no_more_pads = true;
 
     return TRUE;
 }
 
-static struct wg_parser *wg_parser_create(void)
+static struct wg_parser * CDECL wg_parser_create(enum wg_parser_type parser_type, uint64_t file_size)
 {
     struct wg_parser *parser;
+    BOOL ret;
 
     if (!(parser = calloc(1, sizeof(*parser))))
         return NULL;
 
+    if (!(parser->appsrc = create_element("appsrc", "base")))
+    {
+        free(parser);
+        return NULL;
+    }
+
     pthread_mutex_init(&parser->mutex, NULL);
     pthread_cond_init(&parser->state_cond, NULL);
     pthread_cond_init(&parser->read_cond, NULL);
     parser->flushing = true;
 
-    GST_DEBUG("Created winegstreamer parser %p.\n", parser);
-    return parser;
-}
+    parser->bus = gst_bus_new();
+    gst_bus_set_sync_handler(parser->bus, bus_handler_cb, parser, NULL);
 
-static struct wg_parser * CDECL wg_decodebin_parser_create(void)
-{
-    struct wg_parser *parser;
+    parser->container = gst_bin_new(NULL);
+    gst_element_set_bus(parser->container, parser->bus);
 
-    if ((parser = wg_parser_create()))
-        parser->init_gst = decodebin_parser_init_gst;
-    return parser;
-}
+    gst_bin_add(GST_BIN(parser->container), parser->appsrc);
 
-static struct wg_parser * CDECL wg_avi_parser_create(void)
-{
-    struct wg_parser *parser;
+    g_object_set(parser->appsrc, "stream-type", GST_APP_STREAM_TYPE_RANDOM_ACCESS, NULL);
+    g_object_set(parser->appsrc, "size", file_size, NULL);
+    g_signal_connect(parser->appsrc, "need-data", G_CALLBACK(src_need_data), parser);
+    g_signal_connect(parser->appsrc, "seek-data", G_CALLBACK(src_seek_data), parser);
 
-    if ((parser = wg_parser_create()))
-        parser->init_gst = avi_parser_init_gst;
-    return parser;
-}
+    parser->read_request.offset = 0;
 
-static struct wg_parser * CDECL wg_mpeg_audio_parser_create(void)
-{
-    struct wg_parser *parser;
+    switch (parser_type)
+    {
+        case WG_DECODEBIN_PARSER:
+            ret = decodebin_parser_init_gst(parser);
+            break;
+        case WG_AVI_PARSER:
+            ret = avi_parser_init_gst(parser);
+            break;
+        case WG_MPEG_AUDIO_PARSER:
+            ret = mpeg_audio_parser_init_gst(parser);
+            break;
+        case WG_WAVE_PARSER:
+            ret = wave_parser_init_gst(parser);
+            break;
+        default:
+            assert(0);
+    }
 
-    if ((parser = wg_parser_create()))
-        parser->init_gst = mpeg_audio_parser_init_gst;
-    return parser;
-}
+    if (!ret)
+    {
+        gst_element_set_bus(parser->container, NULL);
+        gst_object_unref(parser->container);
 
-static struct wg_parser * CDECL wg_wave_parser_create(void)
-{
-    struct wg_parser *parser;
+        gst_bus_set_sync_handler(parser->bus, NULL, NULL, NULL);
+        gst_object_unref(parser->bus);
+
+        pthread_mutex_destroy(&parser->mutex);
+        pthread_cond_destroy(&parser->state_cond);
+        pthread_cond_destroy(&parser->read_cond);
+
+        free(parser);
+        return NULL;
+    }
+
+    gst_element_set_state(parser->container, GST_STATE_PAUSED);
 
-    if ((parser = wg_parser_create()))
-        parser->init_gst = wave_parser_init_gst;
+    GST_DEBUG("Created winegstreamer parser %p.\n", parser);
     return parser;
 }
 
@@ -1666,28 +1669,25 @@ static void CDECL wg_parser_destroy(struct wg_parser *parser)
     pthread_cond_wait(&parser->state_cond, &parser->mutex);
     pthread_mutex_unlock(&parser->mutex);
 
-    if (parser->sink_connected)
+    /* Unblock all of our streams. */
+    pthread_mutex_lock(&parser->mutex);
+    for (i = 0; i < parser->stream_count; ++i)
     {
-        /* Unblock all of our streams. */
-        pthread_mutex_lock(&parser->mutex);
-        for (i = 0; i < parser->stream_count; ++i)
-        {
-            parser->streams[i]->flushing = true;
-            pthread_cond_signal(&parser->streams[i]->event_empty_cond);
-        }
-        pthread_mutex_unlock(&parser->mutex);
+        parser->streams[i]->flushing = true;
+        pthread_cond_signal(&parser->streams[i]->event_empty_cond);
+    }
+    pthread_mutex_unlock(&parser->mutex);
 
-        gst_element_set_state(parser->container, GST_STATE_NULL);
+    gst_element_set_state(parser->container, GST_STATE_NULL);
 
-        for (i = 0; i < parser->stream_count; ++i)
-            free_stream(parser->streams[i]);
+    for (i = 0; i < parser->stream_count; ++i)
+        free_stream(parser->streams[i]);
 
-        parser->stream_count = 0;
-        free(parser->streams);
+    parser->stream_count = 0;
+    free(parser->streams);
 
-        gst_element_set_bus(parser->container, NULL);
-        gst_object_unref(parser->container);
-    }
+    gst_element_set_bus(parser->container, NULL);
+    gst_object_unref(parser->container);
 
     gst_bus_set_sync_handler(parser->bus, NULL, NULL, NULL);
     gst_object_unref(parser->bus);
@@ -1701,14 +1701,9 @@ static void CDECL wg_parser_destroy(struct wg_parser *parser)
 
 static const struct unix_funcs funcs =
 {
-    wg_decodebin_parser_create,
-    wg_avi_parser_create,
-    wg_mpeg_audio_parser_create,
-    wg_wave_parser_create,
+    wg_parser_create,
     wg_parser_destroy,
 
-    wg_parser_connect,
-
     wg_parser_begin_flush,
     wg_parser_end_flush,
 
-- 
2.33.0




More information about the wine-devel mailing list