From: Derek Lesho Subject: [PATCH 3/3] winegstreamer: Merge parser creation functions and wg_parser_connect. Message-Id: <20210916210047.1845028-3-dlesho@codeweavers.com> Date: Thu, 16 Sep 2021 17:00:47 -0400 In-Reply-To: <20210916210047.1845028-1-dlesho@codeweavers.com> References: <20210916210047.1845028-1-dlesho@codeweavers.com> Signed-off-by: Derek Lesho --- 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 . 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 . 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