From fc40539f6d0835dfe45ee1faa8f3a2535769c41c Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Sun, 19 Sep 2021 13:13:15 +1000 Subject: [PATCH] Re-enable mfplat-streaming-support We had reverted the current upstream winegreamer commits to allow mfplat-streaming-support to be used within staging. Hopefully the patchset in question will be upstream shortly. --- ...amer-Fix-return-code-in-init_gst-fai.patch | 29 + ...amer-Replace-source-pad-interface-wi.patch | 614 ++++++++++++++++++ ...amer-Allocate-source-media-buffers-i.patch | 224 +++++++ ...amer-Duplicate-source-shutdown-path-.patch | 221 +++++++ ...amer-Properly-clean-up-from-failure-.patch | 140 ++++ ...amer-Factor-out-more-of-the-init_gst.patch | 160 +++++ patches/mfplat-reverts/definition | 2 + patches/mfplat-streaming-support/definition | 2 +- patches/patchinstall.sh | 85 +++ 9 files changed, 1476 insertions(+), 1 deletion(-) create mode 100644 patches/mfplat-reverts/0001-Revert-winegstreamer-Fix-return-code-in-init_gst-fai.patch create mode 100644 patches/mfplat-reverts/0002-Revert-winegstreamer-Replace-source-pad-interface-wi.patch create mode 100644 patches/mfplat-reverts/0003-Revert-winegstreamer-Allocate-source-media-buffers-i.patch create mode 100644 patches/mfplat-reverts/0004-Revert-winegstreamer-Duplicate-source-shutdown-path-.patch create mode 100644 patches/mfplat-reverts/0005-Revert-winegstreamer-Properly-clean-up-from-failure-.patch create mode 100644 patches/mfplat-reverts/0006-Revert-winegstreamer-Factor-out-more-of-the-init_gst.patch create mode 100644 patches/mfplat-reverts/definition diff --git a/patches/mfplat-reverts/0001-Revert-winegstreamer-Fix-return-code-in-init_gst-fai.patch b/patches/mfplat-reverts/0001-Revert-winegstreamer-Fix-return-code-in-init_gst-fai.patch new file mode 100644 index 00000000..78c71201 --- /dev/null +++ b/patches/mfplat-reverts/0001-Revert-winegstreamer-Fix-return-code-in-init_gst-fai.patch @@ -0,0 +1,29 @@ +From 28339597a00da381c079c9d4f46b67780511c267 Mon Sep 17 00:00:00 2001 +From: Alistair Leslie-Hughes +Date: Sun, 19 Sep 2021 13:07:56 +1000 +Subject: [PATCH 1/6] Revert "winegstreamer: Fix return code in init_gst + failure case." + +This reverts commit b9a7e961cdd39203866be38e90b1d901595d54ba. +--- + dlls/winegstreamer/quartz_parser.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c +index a8e7e3d979f..5299f4dc2ed 100644 +--- a/dlls/winegstreamer/quartz_parser.c ++++ b/dlls/winegstreamer/quartz_parser.c +@@ -982,10 +982,7 @@ static HRESULT parser_sink_connect(struct strmbase_sink *iface, IPin *peer, cons + goto err; + + if (!filter->init_gst(filter)) +- { +- hr = E_FAIL; + goto err; +- } + + for (i = 0; i < filter->source_count; ++i) + { +-- +2.33.0 + diff --git a/patches/mfplat-reverts/0002-Revert-winegstreamer-Replace-source-pad-interface-wi.patch b/patches/mfplat-reverts/0002-Revert-winegstreamer-Replace-source-pad-interface-wi.patch new file mode 100644 index 00000000..b40e530d --- /dev/null +++ b/patches/mfplat-reverts/0002-Revert-winegstreamer-Replace-source-pad-interface-wi.patch @@ -0,0 +1,614 @@ +From 1106d6f409e0876e72c73d71982519f5e6d7e1c5 Mon Sep 17 00:00:00 2001 +From: Alistair Leslie-Hughes +Date: Sun, 19 Sep 2021 13:08:01 +1000 +Subject: [PATCH 2/6] Revert "winegstreamer: Replace source pad interface with + GstAppSrc." + +This reverts commit 1aa359a100bae859b278007e8bf90673eebd7db0. +--- + dlls/winegstreamer/wg_parser.c | 425 ++++++++++++++++++++++++--------- + 1 file changed, 308 insertions(+), 117 deletions(-) + +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 6b6b033b879..f0815e37689 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -33,7 +33,6 @@ + #include + #include + #include +-#include + + /* GStreamer callbacks may be called on threads not created by Wine, and + * therefore cannot access the Wine TEB. This means that we must use GStreamer +@@ -50,20 +49,28 @@ struct wg_parser + struct wg_parser_stream **streams; + unsigned int stream_count; + +- GstElement *container, *appsrc, *decodebin; ++ GstElement *container, *decodebin; + GstBus *bus; ++ GstPad *my_src, *their_sink; ++ ++ guint64 file_size, start_offset, next_offset, stop_offset; ++ guint64 next_pull_offset; ++ ++ pthread_t push_thread; + + pthread_mutex_t mutex; + + pthread_cond_t init_cond; + bool no_more_pads, has_duration, error; + +- pthread_cond_t read_cond; ++ pthread_cond_t read_cond, read_done_cond; + struct + { ++ void *data; + uint64_t offset; + uint32_t size; +- bool pending; ++ bool done; ++ bool ret; + } read_request; + + bool flushing, sink_connected; +@@ -515,7 +522,7 @@ static bool CDECL wg_parser_get_next_read_offset(struct wg_parser *parser, + { + pthread_mutex_lock(&parser->mutex); + +- while (parser->sink_connected && !parser->read_request.pending) ++ while (parser->sink_connected && !parser->read_request.data) + pthread_cond_wait(&parser->read_cond, &parser->mutex); + + if (!parser->sink_connected) +@@ -534,69 +541,15 @@ static bool CDECL wg_parser_get_next_read_offset(struct wg_parser *parser, + static void CDECL wg_parser_push_data(struct wg_parser *parser, + const void *data, uint32_t size) + { +- GstMessage *message; +- GstFlowReturn ret; +- GstBuffer *buffer; +- GError *error; +- +- if (!data) +- { +- pthread_mutex_lock(&parser->mutex); +- +- if (parser->sink_connected) +- { +- error = g_error_new(G_FILE_ERROR, G_FILE_ERROR_FAILED, "WG-Parser client failed to read data at offset %" G_GUINT64_FORMAT, parser->read_request.offset); +- message = gst_message_new_error(NULL, error, ""); +- gst_bus_post(parser->bus, message); +- parser->read_request.pending = false; +- } +- +- pthread_mutex_unlock(&parser->mutex); +- return; +- } +- +- if (!size) +- { +- pthread_mutex_lock(&parser->mutex); +- +- if (parser->sink_connected) +- g_signal_emit_by_name(G_OBJECT(parser->appsrc), "end-of-stream", &ret); +- parser->read_request.pending = false; +- +- pthread_mutex_unlock(&parser->mutex); +- return; +- } +- +- /* We will always perform an extra blit here. We can avoid this in some +- * cases by wrapping a client-allocated buffer using +- * gst_buffer_new_wrapped(). However, releasing the memory is non-trivial, +- * since GStreamer will hold onto a reference for an arbitrarily long +- * period of time. Until there's evidence to suggest that the blit causes a +- * performance problem, leave it alone. */ +- buffer = gst_buffer_new_and_alloc(size); +- gst_buffer_fill(buffer, 0, data, size); +- + pthread_mutex_lock(&parser->mutex); +- +- if (!parser->sink_connected) +- { +- pthread_mutex_unlock(&parser->mutex); +- gst_buffer_unref(buffer); +- return; +- } +- +- assert(parser->read_request.pending); +- +- GST_BUFFER_OFFSET(buffer) = parser->read_request.offset; +- g_signal_emit_by_name(G_OBJECT(parser->appsrc), "push-buffer", buffer, &ret); +- +- /* In random-access mode, GST_FLOW_EOS shouldn't be returned. */ +- assert(ret == GST_FLOW_OK || ret == GST_FLOW_FLUSHING); +- if (ret == GST_FLOW_OK) +- parser->read_request.offset += size; +- +- parser->read_request.pending = false; ++ parser->read_request.size = size; ++ parser->read_request.done = true; ++ parser->read_request.ret = !!data; ++ if (data) ++ memcpy(parser->read_request.data, data, size); ++ parser->read_request.data = NULL; + pthread_mutex_unlock(&parser->mutex); ++ pthread_cond_signal(&parser->read_done_cond); + } + + static void CDECL wg_parser_set_unlimited_buffering(struct wg_parser *parser) +@@ -1251,56 +1204,196 @@ static void pad_removed_cb(GstElement *element, GstPad *pad, gpointer user) + g_free(name); + } + +-static void src_need_data(GstElement *appsrc, guint length, gpointer user) ++static GstFlowReturn src_getrange_cb(GstPad *pad, GstObject *parent, ++ guint64 offset, guint size, GstBuffer **buffer) + { +- struct wg_parser *parser = user; +- guint64 queued_bytes; ++ struct wg_parser *parser = gst_pad_get_element_private(pad); ++ GstBuffer *new_buffer = NULL; ++ GstMapInfo map_info; ++ bool ret; ++ ++ GST_LOG("pad %p, offset %" G_GINT64_MODIFIER "u, length %u, buffer %p.", pad, offset, size, *buffer); ++ ++ if (offset == GST_BUFFER_OFFSET_NONE) ++ offset = parser->next_pull_offset; ++ parser->next_pull_offset = offset + size; ++ ++ if (!*buffer) ++ *buffer = new_buffer = gst_buffer_new_and_alloc(size); ++ ++ gst_buffer_map(*buffer, &map_info, GST_MAP_WRITE); + + pthread_mutex_lock(&parser->mutex); + +- /* As of GStreamer 1.18, appsrc suffers from a race condition. When in +- * random access mode (and when underlyingly in pull mode), appsrc may +- * spuriously send multiple requests for the same offset and length. If it +- * receives the same buffer twice (or consecutive buffers), it will blindly +- * queue them and satisfy subsequent getrange requests from downstream +- * elements with the wrong buffers. +- * +- * Internally, this function is called inside of a loop, which also pops +- * buffers from the internal queue. Accordingly we can safely treat this +- * request as spurious by checking if we have already sent data; since the +- * data is consumed by this thread it will not have been consumed yet. +- * +- * The bug is documented in greater detail here: +- * +- * https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/issues/937 +- */ +- g_object_get(G_OBJECT(appsrc), "current-level-bytes", &queued_bytes, NULL); +- if (queued_bytes) ++ assert(!parser->read_request.data); ++ parser->read_request.data = map_info.data; ++ parser->read_request.offset = offset; ++ parser->read_request.size = size; ++ parser->read_request.done = false; ++ pthread_cond_signal(&parser->read_cond); ++ ++ /* Note that we don't unblock this wait on GST_EVENT_FLUSH_START. We expect ++ * the upstream pin to flush if necessary. We should never be blocked on ++ * read_thread() not running. */ ++ ++ while (!parser->read_request.done) ++ pthread_cond_wait(&parser->read_done_cond, &parser->mutex); ++ ++ ret = parser->read_request.ret; ++ gst_buffer_set_size(*buffer, parser->read_request.size); ++ ++ pthread_mutex_unlock(&parser->mutex); ++ ++ gst_buffer_unmap(*buffer, &map_info); ++ ++ GST_LOG("Request returned %d.", ret); ++ ++ if ((!ret || !size) && new_buffer) ++ gst_buffer_unref(new_buffer); ++ ++ if (ret) ++ return size ? GST_FLOW_OK : GST_FLOW_EOS; ++ return GST_FLOW_ERROR; ++} ++ ++static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) ++{ ++ struct wg_parser *parser = gst_pad_get_element_private(pad); ++ GstFormat format; ++ ++ GST_LOG("parser %p, type %s.", parser, GST_QUERY_TYPE_NAME(query)); ++ ++ switch (GST_QUERY_TYPE(query)) + { +- pthread_mutex_unlock(&parser->mutex); +- return; ++ case GST_QUERY_DURATION: ++ gst_query_parse_duration(query, &format, NULL); ++ if (format == GST_FORMAT_PERCENT) ++ { ++ gst_query_set_duration(query, GST_FORMAT_PERCENT, GST_FORMAT_PERCENT_MAX); ++ return TRUE; ++ } ++ else if (format == GST_FORMAT_BYTES) ++ { ++ gst_query_set_duration(query, GST_FORMAT_BYTES, parser->file_size); ++ return TRUE; ++ } ++ return FALSE; ++ ++ case GST_QUERY_SEEKING: ++ gst_query_parse_seeking (query, &format, NULL, NULL, NULL); ++ if (format != GST_FORMAT_BYTES) ++ { ++ GST_WARNING("Cannot seek using format \"%s\".", gst_format_get_name(format)); ++ return FALSE; ++ } ++ gst_query_set_seeking(query, GST_FORMAT_BYTES, 1, 0, parser->file_size); ++ return TRUE; ++ ++ case GST_QUERY_SCHEDULING: ++ gst_query_set_scheduling(query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1, 0); ++ gst_query_add_scheduling_mode(query, GST_PAD_MODE_PUSH); ++ gst_query_add_scheduling_mode(query, GST_PAD_MODE_PULL); ++ return TRUE; ++ ++ default: ++ GST_WARNING("Unhandled query type %s.", GST_QUERY_TYPE_NAME(query)); ++ return FALSE; + } ++} + +- parser->read_request.pending = true; +- parser->read_request.size = length; ++static void *push_data(void *arg) ++{ ++ struct wg_parser *parser = arg; ++ GstBuffer *buffer; ++ guint max_size; + +- pthread_cond_signal(&parser->read_cond); ++ GST_DEBUG("Starting push thread."); + +- pthread_mutex_unlock(&parser->mutex); ++ if (!(buffer = gst_buffer_new_allocate(NULL, 16384, NULL))) ++ { ++ GST_ERROR("Failed to allocate memory."); ++ return NULL; ++ } ++ ++ max_size = parser->stop_offset ? parser->stop_offset : parser->file_size; ++ ++ for (;;) ++ { ++ ULONG size; ++ int ret; ++ ++ if (parser->next_offset >= max_size) ++ break; ++ size = min(16384, max_size - parser->next_offset); ++ ++ if ((ret = src_getrange_cb(parser->my_src, NULL, parser->next_offset, size, &buffer)) < 0) ++ { ++ GST_ERROR("Failed to read data, ret %s.", gst_flow_get_name(ret)); ++ break; ++ } ++ ++ parser->next_offset += size; ++ ++ buffer->duration = buffer->pts = -1; ++ if ((ret = gst_pad_push(parser->my_src, buffer)) < 0) ++ { ++ GST_ERROR("Failed to push data, ret %s.", gst_flow_get_name(ret)); ++ break; ++ } ++ } ++ ++ gst_buffer_unref(buffer); ++ ++ gst_pad_push_event(parser->my_src, gst_event_new_eos()); ++ ++ GST_DEBUG("Stopping push thread."); ++ ++ return NULL; + } + +-static gboolean src_seek_data(GstElement *appsrc, guint64 offset, gpointer user) ++static gboolean activate_push(GstPad *pad, gboolean activate) + { +- struct wg_parser *parser = user; ++ struct wg_parser *parser = gst_pad_get_element_private(pad); + +- pthread_mutex_lock(&parser->mutex); ++ if (!activate) ++ { ++ if (parser->push_thread) ++ { ++ pthread_join(parser->push_thread, NULL); ++ parser->push_thread = 0; ++ } ++ } ++ else if (!parser->push_thread) ++ { ++ int ret; + +- assert(!parser->read_request.pending); +- parser->read_request.offset = offset; ++ if ((ret = pthread_create(&parser->push_thread, NULL, push_data, parser))) ++ { ++ GST_ERROR("Failed to create push thread: %s", strerror(errno)); ++ parser->push_thread = 0; ++ return FALSE; ++ } ++ } ++ return TRUE; ++} + +- pthread_mutex_unlock(&parser->mutex); ++static gboolean src_activate_mode_cb(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate) ++{ ++ struct wg_parser *parser = gst_pad_get_element_private(pad); + +- return true; ++ GST_DEBUG("%s source pad for parser %p in %s mode.", ++ activate ? "Activating" : "Deactivating", parser, gst_pad_mode_get_name(mode)); ++ ++ switch (mode) ++ { ++ case GST_PAD_MODE_PULL: ++ return TRUE; ++ case GST_PAD_MODE_PUSH: ++ return activate_push(pad, activate); ++ case GST_PAD_MODE_NONE: ++ break; ++ } ++ return FALSE; + } + + static GstBusSyncReply bus_handler_cb(GstBus *bus, GstMessage *msg, gpointer user) +@@ -1347,11 +1440,89 @@ static GstBusSyncReply bus_handler_cb(GstBus *bus, GstMessage *msg, gpointer use + return GST_BUS_DROP; + } + ++static gboolean src_perform_seek(struct wg_parser *parser, GstEvent *event) ++{ ++ BOOL thread = !!parser->push_thread; ++ GstSeekType cur_type, stop_type; ++ GstFormat seek_format; ++ GstEvent *flush_event; ++ GstSeekFlags flags; ++ gint64 cur, stop; ++ guint32 seqnum; ++ gdouble rate; ++ ++ gst_event_parse_seek(event, &rate, &seek_format, &flags, ++ &cur_type, &cur, &stop_type, &stop); ++ ++ if (seek_format != GST_FORMAT_BYTES) ++ { ++ GST_FIXME("Unhandled format \"%s\".", gst_format_get_name(seek_format)); ++ return FALSE; ++ } ++ ++ seqnum = gst_event_get_seqnum(event); ++ ++ /* send flush start */ ++ if (flags & GST_SEEK_FLAG_FLUSH) ++ { ++ flush_event = gst_event_new_flush_start(); ++ gst_event_set_seqnum(flush_event, seqnum); ++ gst_pad_push_event(parser->my_src, flush_event); ++ if (thread) ++ gst_pad_set_active(parser->my_src, 1); ++ } ++ ++ parser->next_offset = parser->start_offset = cur; ++ ++ /* and prepare to continue streaming */ ++ if (flags & GST_SEEK_FLAG_FLUSH) ++ { ++ flush_event = gst_event_new_flush_stop(TRUE); ++ gst_event_set_seqnum(flush_event, seqnum); ++ gst_pad_push_event(parser->my_src, flush_event); ++ if (thread) ++ gst_pad_set_active(parser->my_src, 1); ++ } ++ ++ return TRUE; ++} ++ ++static gboolean src_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) ++{ ++ struct wg_parser *parser = gst_pad_get_element_private(pad); ++ gboolean ret = TRUE; ++ ++ GST_LOG("parser %p, type \"%s\".", parser, GST_EVENT_TYPE_NAME(event)); ++ ++ switch (event->type) ++ { ++ case GST_EVENT_SEEK: ++ ret = src_perform_seek(parser, event); ++ break; ++ ++ case GST_EVENT_FLUSH_START: ++ case GST_EVENT_FLUSH_STOP: ++ case GST_EVENT_QOS: ++ case GST_EVENT_RECONFIGURE: ++ break; ++ ++ default: ++ GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event)); ++ ret = FALSE; ++ break; ++ } ++ gst_event_unref(event); ++ return ret; ++} ++ + static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_size) + { ++ GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("quartz_src", ++ GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); + unsigned int i; + int ret; + ++ parser->file_size = file_size; + parser->sink_connected = true; + + if (!parser->bus) +@@ -1363,16 +1534,15 @@ static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_s + 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); ++ parser->my_src = gst_pad_new_from_static_template(&src_template, "quartz-src"); ++ gst_pad_set_getrange_function(parser->my_src, src_getrange_cb); ++ gst_pad_set_query_function(parser->my_src, src_query_cb); ++ gst_pad_set_activatemode_function(parser->my_src, src_activate_mode_cb); ++ gst_pad_set_event_function(parser->my_src, src_event_cb); ++ gst_pad_set_element_private(parser->my_src, 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); +- +- parser->read_request.offset = 0; ++ parser->start_offset = parser->next_offset = parser->stop_offset = 0; ++ parser->next_pull_offset = 0; + parser->error = false; + + if (!parser->init_gst(parser)) +@@ -1468,11 +1638,18 @@ static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_s + + pthread_mutex_unlock(&parser->mutex); + ++ parser->next_offset = 0; + return S_OK; + + out: + if (parser->container) + gst_element_set_state(parser->container, GST_STATE_NULL); ++ if (parser->their_sink) ++ { ++ gst_pad_unlink(parser->my_src, parser->their_sink); ++ gst_object_unref(parser->their_sink); ++ parser->my_src = parser->their_sink = NULL; ++ } + + for (i = 0; i < parser->stream_count; ++i) + free_stream(parser->streams[i]); +@@ -1509,6 +1686,10 @@ static void CDECL wg_parser_disconnect(struct wg_parser *parser) + pthread_mutex_unlock(&parser->mutex); + + gst_element_set_state(parser->container, GST_STATE_NULL); ++ gst_pad_unlink(parser->my_src, parser->their_sink); ++ gst_object_unref(parser->my_src); ++ gst_object_unref(parser->their_sink); ++ parser->my_src = parser->their_sink = NULL; + + pthread_mutex_lock(&parser->mutex); + parser->sink_connected = false; +@@ -1530,6 +1711,7 @@ static void CDECL wg_parser_disconnect(struct wg_parser *parser) + static BOOL decodebin_parser_init_gst(struct wg_parser *parser) + { + GstElement *element; ++ int ret; + + if (!(element = create_element("decodebin", "base"))) + return FALSE; +@@ -1542,13 +1724,15 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) + g_signal_connect(element, "autoplug-select", G_CALLBACK(autoplug_select_cb), parser); + g_signal_connect(element, "no-more-pads", G_CALLBACK(no_more_pads_cb), parser); + ++ parser->their_sink = gst_element_get_static_pad(element, "sink"); ++ + pthread_mutex_lock(&parser->mutex); + parser->no_more_pads = false; + pthread_mutex_unlock(&parser->mutex); + +- if (!gst_element_link(parser->appsrc, parser->decodebin)) ++ if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0) + { +- GST_ERROR("Failed to link appsrc.\n"); ++ GST_ERROR("Failed to link pads, error %d.\n", ret); + return FALSE; + } + +@@ -1558,6 +1742,7 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) + static BOOL avi_parser_init_gst(struct wg_parser *parser) + { + GstElement *element; ++ int ret; + + if (!(element = create_element("avidemux", "good"))) + return FALSE; +@@ -1568,13 +1753,15 @@ static BOOL avi_parser_init_gst(struct wg_parser *parser) + g_signal_connect(element, "pad-removed", G_CALLBACK(pad_removed_cb), parser); + g_signal_connect(element, "no-more-pads", G_CALLBACK(no_more_pads_cb), parser); + ++ parser->their_sink = gst_element_get_static_pad(element, "sink"); ++ + pthread_mutex_lock(&parser->mutex); + parser->no_more_pads = false; + pthread_mutex_unlock(&parser->mutex); + +- if (!gst_element_link(parser->appsrc, element)) ++ if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0) + { +- GST_ERROR("Failed to link appsrc.\n"); ++ GST_ERROR("Failed to link pads, error %d.\n", ret); + return FALSE; + } + +@@ -1592,9 +1779,10 @@ static BOOL mpeg_audio_parser_init_gst(struct wg_parser *parser) + + gst_bin_add(GST_BIN(parser->container), element); + +- if (!gst_element_link(parser->appsrc, element)) ++ parser->their_sink = gst_element_get_static_pad(element, "sink"); ++ if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0) + { +- GST_ERROR("Failed to link appsrc.\n"); ++ GST_ERROR("Failed to link sink pads, error %d.\n", ret); + return FALSE; + } + +@@ -1625,9 +1813,10 @@ static BOOL wave_parser_init_gst(struct wg_parser *parser) + + gst_bin_add(GST_BIN(parser->container), element); + +- if (!gst_element_link(parser->appsrc, element)) ++ parser->their_sink = gst_element_get_static_pad(element, "sink"); ++ if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0) + { +- GST_ERROR("Failed to link appsrc.\n"); ++ GST_ERROR("Failed to link sink pads, error %d.\n", ret); + return FALSE; + } + +@@ -1658,6 +1847,7 @@ static struct wg_parser *wg_parser_create(void) + pthread_mutex_init(&parser->mutex, NULL); + pthread_cond_init(&parser->init_cond, NULL); + pthread_cond_init(&parser->read_cond, NULL); ++ pthread_cond_init(&parser->read_done_cond, NULL); + parser->flushing = true; + + GST_DEBUG("Created winegstreamer parser %p.\n", parser); +@@ -1711,6 +1901,7 @@ static void CDECL wg_parser_destroy(struct wg_parser *parser) + pthread_mutex_destroy(&parser->mutex); + pthread_cond_destroy(&parser->init_cond); + pthread_cond_destroy(&parser->read_cond); ++ pthread_cond_destroy(&parser->read_done_cond); + + free(parser); + } +-- +2.33.0 + diff --git a/patches/mfplat-reverts/0003-Revert-winegstreamer-Allocate-source-media-buffers-i.patch b/patches/mfplat-reverts/0003-Revert-winegstreamer-Allocate-source-media-buffers-i.patch new file mode 100644 index 00000000..5e73e444 --- /dev/null +++ b/patches/mfplat-reverts/0003-Revert-winegstreamer-Allocate-source-media-buffers-i.patch @@ -0,0 +1,224 @@ +From 2e341e32dd761e40c9045648b0edfabd9b49fc4e Mon Sep 17 00:00:00 2001 +From: Alistair Leslie-Hughes +Date: Sun, 19 Sep 2021 13:08:02 +1000 +Subject: [PATCH 3/6] Revert "winegstreamer: Allocate source media buffers in + the PE components." + +This reverts commit 8b7390f80d866435f06f2571a93bcd67c0947673. +--- + dlls/winegstreamer/gst_private.h | 7 +++---- + dlls/winegstreamer/media_source.c | 28 ++++------------------------ + dlls/winegstreamer/quartz_parser.c | 26 +++----------------------- + dlls/winegstreamer/wg_parser.c | 28 +++++++++++++--------------- + 4 files changed, 23 insertions(+), 66 deletions(-) + +diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h +index 49e06b31369..c29fc4a2437 100644 +--- a/dlls/winegstreamer/gst_private.h ++++ b/dlls/winegstreamer/gst_private.h +@@ -170,10 +170,9 @@ struct unix_funcs + void (CDECL *wg_parser_begin_flush)(struct wg_parser *parser); + void (CDECL *wg_parser_end_flush)(struct wg_parser *parser); + +- bool (CDECL *wg_parser_get_next_read_offset)(struct wg_parser *parser, +- uint64_t *offset, uint32_t *size); +- void (CDECL *wg_parser_push_data)(struct wg_parser *parser, +- const void *data, uint32_t size); ++ bool (CDECL *wg_parser_get_read_request)(struct wg_parser *parser, ++ void **data, uint64_t *offset, uint32_t *size); ++ void (CDECL *wg_parser_complete_read_request)(struct wg_parser *parser, bool ret); + + void (CDECL *wg_parser_set_unlimited_buffering)(struct wg_parser *parser); + +diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c +index 825bad8da27..95bdb9b488e 100644 +--- a/dlls/winegstreamer/media_source.c ++++ b/dlls/winegstreamer/media_source.c +@@ -530,11 +530,6 @@ static DWORD CALLBACK read_thread(void *arg) + { + struct media_source *source = arg; + IMFByteStream *byte_stream = source->byte_stream; +- uint32_t buffer_size = 0; +- uint64_t file_size; +- void *data = NULL; +- +- IMFByteStream_GetLength(byte_stream, &file_size); + + TRACE("Starting read thread for media source %p.\n", source); + +@@ -544,33 +539,18 @@ static DWORD CALLBACK read_thread(void *arg) + ULONG ret_size; + uint32_t size; + HRESULT hr; ++ void *data; + +- if (!unix_funcs->wg_parser_get_next_read_offset(source->wg_parser, &offset, &size)) ++ if (!unix_funcs->wg_parser_get_read_request(source->wg_parser, &data, &offset, &size)) + continue; + +- if (offset >= file_size) +- size = 0; +- else if (offset + size >= file_size) +- size = file_size - offset; +- +- if (size > buffer_size) +- { +- buffer_size = size; +- data = realloc(data, size); +- } +- +- ret_size = 0; +- + if (SUCCEEDED(hr = IMFByteStream_SetCurrentPosition(byte_stream, offset))) + hr = IMFByteStream_Read(byte_stream, data, size, &ret_size); +- if (FAILED(hr)) +- ERR("Failed to read %u bytes at offset %I64u, hr %#x.\n", size, offset, hr); +- else if (ret_size != size) ++ if (SUCCEEDED(hr) && ret_size != size) + ERR("Unexpected short read: requested %u bytes, got %u.\n", size, ret_size); +- unix_funcs->wg_parser_push_data(source->wg_parser, SUCCEEDED(hr) ? data : NULL, ret_size); ++ unix_funcs->wg_parser_complete_read_request(source->wg_parser, SUCCEEDED(hr)); + } + +- free(data); + TRACE("Media source is shutting down; exiting.\n"); + return 0; + } +diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c +index 5299f4dc2ed..09a916d7f5c 100644 +--- a/dlls/winegstreamer/quartz_parser.c ++++ b/dlls/winegstreamer/quartz_parser.c +@@ -785,11 +785,6 @@ static DWORD CALLBACK stream_thread(void *arg) + static DWORD CALLBACK read_thread(void *arg) + { + struct parser *filter = arg; +- LONGLONG file_size, unused; +- uint32_t buffer_size = 0; +- void *data = NULL; +- +- IAsyncReader_Length(filter->reader, &file_size, &unused); + + TRACE("Starting read thread for filter %p.\n", filter); + +@@ -798,29 +793,14 @@ static DWORD CALLBACK read_thread(void *arg) + uint64_t offset; + uint32_t size; + HRESULT hr; ++ void *data; + +- if (!unix_funcs->wg_parser_get_next_read_offset(filter->wg_parser, &offset, &size)) ++ if (!unix_funcs->wg_parser_get_read_request(filter->wg_parser, &data, &offset, &size)) + continue; +- +- if (offset >= file_size) +- size = 0; +- else if (offset + size >= file_size) +- size = file_size - offset; +- +- if (size > buffer_size) +- { +- buffer_size = size; +- data = realloc(data, size); +- } +- + hr = IAsyncReader_SyncRead(filter->reader, offset, size, data); +- if (FAILED(hr)) +- ERR("Failed to read %u bytes at offset %I64u, hr %#x.\n", size, offset, hr); +- +- unix_funcs->wg_parser_push_data(filter->wg_parser, SUCCEEDED(hr) ? data : NULL, size); ++ unix_funcs->wg_parser_complete_read_request(filter->wg_parser, SUCCEEDED(hr)); + } + +- free(data); + TRACE("Streaming stopped; exiting.\n"); + return 0; + } +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index f0815e37689..119cbffbd88 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -517,8 +517,8 @@ static void CDECL wg_parser_end_flush(struct wg_parser *parser) + pthread_mutex_unlock(&parser->mutex); + } + +-static bool CDECL wg_parser_get_next_read_offset(struct wg_parser *parser, +- uint64_t *offset, uint32_t *size) ++static bool CDECL wg_parser_get_read_request(struct wg_parser *parser, ++ void **data, uint64_t *offset, uint32_t *size) + { + pthread_mutex_lock(&parser->mutex); + +@@ -531,6 +531,7 @@ static bool CDECL wg_parser_get_next_read_offset(struct wg_parser *parser, + return false; + } + ++ *data = parser->read_request.data; + *offset = parser->read_request.offset; + *size = parser->read_request.size; + +@@ -538,15 +539,11 @@ static bool CDECL wg_parser_get_next_read_offset(struct wg_parser *parser, + return true; + } + +-static void CDECL wg_parser_push_data(struct wg_parser *parser, +- const void *data, uint32_t size) ++static void CDECL wg_parser_complete_read_request(struct wg_parser *parser, bool ret) + { + pthread_mutex_lock(&parser->mutex); +- parser->read_request.size = size; + parser->read_request.done = true; +- parser->read_request.ret = !!data; +- if (data) +- memcpy(parser->read_request.data, data, size); ++ parser->read_request.ret = ret; + parser->read_request.data = NULL; + pthread_mutex_unlock(&parser->mutex); + pthread_cond_signal(&parser->read_done_cond); +@@ -1217,6 +1214,10 @@ static GstFlowReturn src_getrange_cb(GstPad *pad, GstObject *parent, + if (offset == GST_BUFFER_OFFSET_NONE) + offset = parser->next_pull_offset; + parser->next_pull_offset = offset + size; ++ if (offset >= parser->file_size) ++ return GST_FLOW_EOS; ++ if (offset + size >= parser->file_size) ++ size = parser->file_size - offset; + + if (!*buffer) + *buffer = new_buffer = gst_buffer_new_and_alloc(size); +@@ -1240,7 +1241,6 @@ static GstFlowReturn src_getrange_cb(GstPad *pad, GstObject *parent, + pthread_cond_wait(&parser->read_done_cond, &parser->mutex); + + ret = parser->read_request.ret; +- gst_buffer_set_size(*buffer, parser->read_request.size); + + pthread_mutex_unlock(&parser->mutex); + +@@ -1248,12 +1248,10 @@ static GstFlowReturn src_getrange_cb(GstPad *pad, GstObject *parent, + + GST_LOG("Request returned %d.", ret); + +- if ((!ret || !size) && new_buffer) ++ if (!ret && new_buffer) + gst_buffer_unref(new_buffer); + +- if (ret) +- return size ? GST_FLOW_OK : GST_FLOW_EOS; +- return GST_FLOW_ERROR; ++ return ret ? GST_FLOW_OK : GST_FLOW_ERROR; + } + + static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) +@@ -1920,8 +1918,8 @@ static const struct unix_funcs funcs = + wg_parser_begin_flush, + wg_parser_end_flush, + +- wg_parser_get_next_read_offset, +- wg_parser_push_data, ++ wg_parser_get_read_request, ++ wg_parser_complete_read_request, + + wg_parser_set_unlimited_buffering, + +-- +2.33.0 + diff --git a/patches/mfplat-reverts/0004-Revert-winegstreamer-Duplicate-source-shutdown-path-.patch b/patches/mfplat-reverts/0004-Revert-winegstreamer-Duplicate-source-shutdown-path-.patch new file mode 100644 index 00000000..f6f60cdc --- /dev/null +++ b/patches/mfplat-reverts/0004-Revert-winegstreamer-Duplicate-source-shutdown-path-.patch @@ -0,0 +1,221 @@ +From ca25389c3980c848dc6094f84160079a4cf805f7 Mon Sep 17 00:00:00 2001 +From: Alistair Leslie-Hughes +Date: Sun, 19 Sep 2021 13:08:03 +1000 +Subject: [PATCH 4/6] Revert "winegstreamer: Duplicate source shutdown path + into constructor with leak fixes." + +This reverts commit 67734bfce31d6032cee1a8980a9022665e9e18fa. +--- + dlls/winegstreamer/gst_private.h | 1 - + dlls/winegstreamer/media_source.c | 102 +++++++++++------------------- + 2 files changed, 37 insertions(+), 66 deletions(-) + +diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h +index c29fc4a2437..c6c99b1dd55 100644 +--- a/dlls/winegstreamer/gst_private.h ++++ b/dlls/winegstreamer/gst_private.h +@@ -22,7 +22,6 @@ + #define __GST_PRIVATE_INCLUDED__ + + #include +-#include + #include + #include + #include +diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c +index 95bdb9b488e..01ab626254a 100644 +--- a/dlls/winegstreamer/media_source.c ++++ b/dlls/winegstreamer/media_source.c +@@ -733,12 +733,6 @@ static HRESULT new_media_stream(struct media_source *source, + object->IMFMediaStream_iface.lpVtbl = &media_stream_vtbl; + object->ref = 1; + +- if (FAILED(hr = MFCreateEventQueue(&object->event_queue))) +- { +- free(object); +- return hr; +- } +- + IMFMediaSource_AddRef(&source->IMFMediaSource_iface); + object->parent_source = source; + object->stream_id = stream_id; +@@ -747,11 +741,20 @@ static HRESULT new_media_stream(struct media_source *source, + object->eos = FALSE; + object->wg_stream = wg_stream; + ++ if (FAILED(hr = MFCreateEventQueue(&object->event_queue))) ++ goto fail; ++ + TRACE("Created stream object %p.\n", object); + + *out_stream = object; + + return S_OK; ++ ++fail: ++ WARN("Failed to construct media stream, hr %#x.\n", hr); ++ ++ IMFMediaStream_Release(&object->IMFMediaStream_iface); ++ return hr; + } + + static HRESULT media_stream_init_desc(struct media_stream *stream) +@@ -844,16 +847,10 @@ static HRESULT media_stream_init_desc(struct media_stream *stream) + goto done; + + if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &type_handler))) +- { +- IMFStreamDescriptor_Release(stream->descriptor); + goto done; +- } + + if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, stream_types[0]))) +- { +- IMFStreamDescriptor_Release(stream->descriptor); + goto done; +- } + + done: + if (type_handler) +@@ -1216,13 +1213,19 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) + + unix_funcs->wg_parser_disconnect(source->wg_parser); + +- source->read_thread_shutdown = true; +- WaitForSingleObject(source->read_thread, INFINITE); +- CloseHandle(source->read_thread); ++ if (source->read_thread) ++ { ++ source->read_thread_shutdown = true; ++ WaitForSingleObject(source->read_thread, INFINITE); ++ CloseHandle(source->read_thread); ++ } + +- IMFPresentationDescriptor_Release(source->pres_desc); +- IMFMediaEventQueue_Shutdown(source->event_queue); +- IMFByteStream_Release(source->byte_stream); ++ if (source->pres_desc) ++ IMFPresentationDescriptor_Release(source->pres_desc); ++ if (source->event_queue) ++ IMFMediaEventQueue_Shutdown(source->event_queue); ++ if (source->byte_stream) ++ IMFByteStream_Release(source->byte_stream); + + for (i = 0; i < source->stream_count; i++) + { +@@ -1230,18 +1233,23 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) + + stream->state = STREAM_SHUTDOWN; + +- IMFMediaEventQueue_Shutdown(stream->event_queue); +- IMFStreamDescriptor_Release(stream->descriptor); +- IMFMediaSource_Release(&stream->parent_source->IMFMediaSource_iface); ++ if (stream->event_queue) ++ IMFMediaEventQueue_Shutdown(stream->event_queue); ++ if (stream->descriptor) ++ IMFStreamDescriptor_Release(stream->descriptor); ++ if (stream->parent_source) ++ IMFMediaSource_Release(&stream->parent_source->IMFMediaSource_iface); + + IMFMediaStream_Release(&stream->IMFMediaStream_iface); + } + + unix_funcs->wg_parser_destroy(source->wg_parser); + +- free(source->streams); ++ if (source->stream_count) ++ free(source->streams); + +- MFUnlockWorkQueue(source->async_commands_queue); ++ if (source->async_commands_queue) ++ MFUnlockWorkQueue(source->async_commands_queue); + + return S_OK; + } +@@ -1266,7 +1274,6 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl = + static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_source **out_media_source) + { + IMFStreamDescriptor **descriptors = NULL; +- unsigned int stream_count = UINT_MAX; + struct media_source *object; + UINT64 total_pres_time = 0; + struct wg_parser *parser; +@@ -1330,15 +1337,15 @@ 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); ++ object->stream_count = unix_funcs->wg_parser_get_stream_count(parser); + +- if (!(object->streams = calloc(stream_count, sizeof(*object->streams)))) ++ if (!(object->streams = calloc(object->stream_count, sizeof(*object->streams)))) + { + hr = E_OUTOFMEMORY; + goto fail; + } + +- for (i = 0; i < stream_count; ++i) ++ for (i = 0; i < object->stream_count; ++i) + { + if (FAILED(hr = new_media_stream(object, unix_funcs->wg_parser_get_stream(parser, i), i, &object->streams[i]))) + goto fail; +@@ -1346,13 +1353,9 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ + if (FAILED(hr = media_stream_init_desc(object->streams[i]))) + { + ERR("Failed to finish initialization of media stream %p, hr %x.\n", object->streams[i], hr); +- IMFMediaSource_Release(&object->streams[i]->parent_source->IMFMediaSource_iface); +- IMFMediaEventQueue_Release(object->streams[i]->event_queue); +- free(object->streams[i]); ++ IMFMediaStream_Release(&object->streams[i]->IMFMediaStream_iface); + goto fail; + } +- +- object->stream_count++; + } + + /* init presentation descriptor */ +@@ -1389,39 +1392,8 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ + fail: + WARN("Failed to construct MFMediaSource, hr %#x.\n", hr); + +- if (descriptors) +- { +- for (i = 0; i < object->stream_count; i++) +- IMFStreamDescriptor_Release(descriptors[i]); +- free(descriptors); +- } +- for (i = 0; i < object->stream_count; i++) +- { +- struct media_stream *stream = object->streams[i]; +- +- IMFMediaEventQueue_Release(stream->event_queue); +- IMFStreamDescriptor_Release(stream->descriptor); +- IMFMediaSource_Release(&stream->parent_source->IMFMediaSource_iface); +- +- free(stream); +- } +- free(object->streams); +- if (stream_count != UINT_MAX) +- unix_funcs->wg_parser_disconnect(object->wg_parser); +- if (object->read_thread) +- { +- object->read_thread_shutdown = true; +- WaitForSingleObject(object->read_thread, INFINITE); +- CloseHandle(object->read_thread); +- } +- if (object->wg_parser) +- unix_funcs->wg_parser_destroy(object->wg_parser); +- if (object->async_commands_queue) +- MFUnlockWorkQueue(object->async_commands_queue); +- if (object->event_queue) +- IMFMediaEventQueue_Release(object->event_queue); +- IMFByteStream_Release(object->byte_stream); +- free(object); ++ free(descriptors); ++ IMFMediaSource_Release(&object->IMFMediaSource_iface); + return hr; + } + +-- +2.33.0 + diff --git a/patches/mfplat-reverts/0005-Revert-winegstreamer-Properly-clean-up-from-failure-.patch b/patches/mfplat-reverts/0005-Revert-winegstreamer-Properly-clean-up-from-failure-.patch new file mode 100644 index 00000000..2f0c9a25 --- /dev/null +++ b/patches/mfplat-reverts/0005-Revert-winegstreamer-Properly-clean-up-from-failure-.patch @@ -0,0 +1,140 @@ +From e648d762c2609321822334a9a8db8a2f5905b51d Mon Sep 17 00:00:00 2001 +From: Alistair Leslie-Hughes +Date: Sun, 19 Sep 2021 13:08:04 +1000 +Subject: [PATCH 5/6] Revert "winegstreamer: Properly clean up from failure in + wg_parser_connect()." + +This reverts commit 721b1eb2ebe5c3eaab8ac3fb1e4f4648cbee5b4d. +--- + dlls/winegstreamer/wg_parser.c | 76 ++++++++++------------------------ + 1 file changed, 23 insertions(+), 53 deletions(-) + +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index 119cbffbd88..bf5a51aeaf4 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -1034,30 +1034,6 @@ static struct wg_parser_stream *create_stream(struct wg_parser *parser) + return stream; + } + +-static void free_stream(struct wg_parser_stream *stream) +-{ +- if (stream->their_src) +- { +- if (stream->post_sink) +- { +- gst_pad_unlink(stream->their_src, stream->post_sink); +- gst_pad_unlink(stream->post_src, stream->my_sink); +- gst_object_unref(stream->post_src); +- gst_object_unref(stream->post_sink); +- stream->post_src = stream->post_sink = NULL; +- } +- else +- gst_pad_unlink(stream->their_src, stream->my_sink); +- gst_object_unref(stream->their_src); +- } +- gst_object_unref(stream->my_sink); +- +- pthread_cond_destroy(&stream->event_cond); +- pthread_cond_destroy(&stream->event_empty_cond); +- +- free(stream); +-} +- + static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) + { + struct wg_parser *parser = user; +@@ -1544,14 +1520,14 @@ static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_s + parser->error = false; + + if (!parser->init_gst(parser)) +- goto out; ++ return E_FAIL; + + 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; ++ return E_FAIL; + } + + pthread_mutex_lock(&parser->mutex); +@@ -1561,7 +1537,7 @@ static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_s + if (parser->error) + { + pthread_mutex_unlock(&parser->mutex); +- goto out; ++ return E_FAIL; + } + + for (i = 0; i < parser->stream_count; ++i) +@@ -1601,7 +1577,7 @@ static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_s + if (parser->error) + { + pthread_mutex_unlock(&parser->mutex); +- goto out; ++ return E_FAIL; + } + if (gst_pad_query_duration(stream->their_src, GST_FORMAT_TIME, &duration)) + { +@@ -1638,36 +1614,30 @@ static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_s + + parser->next_offset = 0; + return S_OK; ++} + +-out: +- if (parser->container) +- gst_element_set_state(parser->container, GST_STATE_NULL); +- if (parser->their_sink) +- { +- gst_pad_unlink(parser->my_src, parser->their_sink); +- gst_object_unref(parser->their_sink); +- parser->my_src = parser->their_sink = 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) ++static void free_stream(struct wg_parser_stream *stream) ++{ ++ if (stream->their_src) + { +- gst_element_set_bus(parser->container, NULL); +- gst_object_unref(parser->container); +- parser->container = NULL; ++ if (stream->post_sink) ++ { ++ gst_pad_unlink(stream->their_src, stream->post_sink); ++ gst_pad_unlink(stream->post_src, stream->my_sink); ++ gst_object_unref(stream->post_src); ++ gst_object_unref(stream->post_sink); ++ stream->post_src = stream->post_sink = NULL; ++ } ++ else ++ gst_pad_unlink(stream->their_src, stream->my_sink); ++ gst_object_unref(stream->their_src); + } ++ gst_object_unref(stream->my_sink); + +- pthread_mutex_lock(&parser->mutex); +- parser->sink_connected = false; +- pthread_mutex_unlock(&parser->mutex); +- pthread_cond_signal(&parser->read_cond); ++ pthread_cond_destroy(&stream->event_cond); ++ pthread_cond_destroy(&stream->event_empty_cond); + +- return E_FAIL; ++ free(stream); + } + + static void CDECL wg_parser_disconnect(struct wg_parser *parser) +-- +2.33.0 + diff --git a/patches/mfplat-reverts/0006-Revert-winegstreamer-Factor-out-more-of-the-init_gst.patch b/patches/mfplat-reverts/0006-Revert-winegstreamer-Factor-out-more-of-the-init_gst.patch new file mode 100644 index 00000000..d09ac202 --- /dev/null +++ b/patches/mfplat-reverts/0006-Revert-winegstreamer-Factor-out-more-of-the-init_gst.patch @@ -0,0 +1,160 @@ +From 6d496c2655531790cdfdb5869fd37b64ae405b8a Mon Sep 17 00:00:00 2001 +From: Alistair Leslie-Hughes +Date: Sun, 19 Sep 2021 13:08:05 +1000 +Subject: [PATCH 6/6] Revert "winegstreamer: Factor out more of the init_gst + callback into wg_parser_connect()." + +This reverts commit 830efe873a967dbbb0c9a65be6a66b124a5fa826. +--- + dlls/winegstreamer/wg_parser.c | 78 +++++++++++++++++++++++----------- + 1 file changed, 54 insertions(+), 24 deletions(-) + +diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c +index bf5a51aeaf4..cd12a23d0c8 100644 +--- a/dlls/winegstreamer/wg_parser.c ++++ b/dlls/winegstreamer/wg_parser.c +@@ -1494,7 +1494,6 @@ static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_s + GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("quartz_src", + GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); + unsigned int i; +- int ret; + + parser->file_size = file_size; + parser->sink_connected = true; +@@ -1517,29 +1516,12 @@ static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_s + + parser->start_offset = parser->next_offset = parser->stop_offset = 0; + parser->next_pull_offset = 0; +- parser->error = false; + + if (!parser->init_gst(parser)) + return E_FAIL; + +- 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"); +- return E_FAIL; +- } +- + 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); +- return E_FAIL; +- } +- + for (i = 0; i < parser->stream_count; ++i) + { + struct wg_parser_stream *stream = parser->streams[i]; +@@ -1695,7 +1677,7 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) + parser->their_sink = gst_element_get_static_pad(element, "sink"); + + pthread_mutex_lock(&parser->mutex); +- parser->no_more_pads = false; ++ parser->no_more_pads = parser->error = false; + pthread_mutex_unlock(&parser->mutex); + + if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0) +@@ -1704,6 +1686,24 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) + return FALSE; + } + ++ 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"); ++ return FALSE; ++ } ++ ++ 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); ++ return FALSE; ++ } ++ pthread_mutex_unlock(&parser->mutex); ++ + return TRUE; + } + +@@ -1724,7 +1724,7 @@ static BOOL avi_parser_init_gst(struct wg_parser *parser) + parser->their_sink = gst_element_get_static_pad(element, "sink"); + + pthread_mutex_lock(&parser->mutex); +- parser->no_more_pads = false; ++ parser->no_more_pads = parser->error = false; + pthread_mutex_unlock(&parser->mutex); + + if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0) +@@ -1733,6 +1733,24 @@ static BOOL avi_parser_init_gst(struct wg_parser *parser) + return FALSE; + } + ++ 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"); ++ return FALSE; ++ } ++ ++ 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); ++ return FALSE; ++ } ++ pthread_mutex_unlock(&parser->mutex); ++ + return TRUE; + } + +@@ -1763,9 +1781,15 @@ static BOOL mpeg_audio_parser_init_gst(struct wg_parser *parser) + GST_ERROR("Failed to link source pads, error %d.\n", ret); + return FALSE; + } +- gst_pad_set_active(stream->my_sink, 1); + +- parser->no_more_pads = true; ++ gst_pad_set_active(stream->my_sink, 1); ++ 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"); ++ return FALSE; ++ } + + return TRUE; + } +@@ -1798,9 +1822,15 @@ static BOOL wave_parser_init_gst(struct wg_parser *parser) + GST_ERROR("Failed to link source pads, error %d.\n", ret); + return FALSE; + } +- gst_pad_set_active(stream->my_sink, 1); + +- parser->no_more_pads = true; ++ gst_pad_set_active(stream->my_sink, 1); ++ 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"); ++ return FALSE; ++ } + + return TRUE; + } +-- +2.33.0 + diff --git a/patches/mfplat-reverts/definition b/patches/mfplat-reverts/definition new file mode 100644 index 00000000..bc488b8a --- /dev/null +++ b/patches/mfplat-reverts/definition @@ -0,0 +1,2 @@ +# This is just a revert of update mfplat patches until it's new versions +# of the mfplat have been merged upstream. diff --git a/patches/mfplat-streaming-support/definition b/patches/mfplat-streaming-support/definition index e91efdc2..9ca1daa3 100644 --- a/patches/mfplat-streaming-support/definition +++ b/patches/mfplat-streaming-support/definition @@ -1,2 +1,2 @@ Fixes: [49692] Multiple applications need a Media Foundation media source implementation -Disabled: True +Depends: mfplat-reverts diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index 96794d4b..05f3c583 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -138,6 +138,8 @@ patch_enable_all () enable_krnl386_exe16_Invalid_Console_Handles="$1" enable_libs_Unicode_Collation="$1" enable_loader_KeyboardLayouts="$1" + enable_mfplat_reverts="$1" + enable_mfplat_streaming_support="$1" enable_mmsystem_dll16_MIDIHDR_Refcount="$1" enable_mountmgr_DosDevices="$1" enable_mscoree_CorValidateImage="$1" @@ -454,6 +456,12 @@ patch_enable () loader-KeyboardLayouts) enable_loader_KeyboardLayouts="$2" ;; + mfplat-reverts) + enable_mfplat_reverts="$2" + ;; + mfplat-streaming-support) + enable_mfplat_streaming_support="$2" + ;; mmsystem.dll16-MIDIHDR_Refcount) enable_mmsystem_dll16_MIDIHDR_Refcount="$2" ;; @@ -1340,6 +1348,13 @@ if test "$enable_ntdll_WRITECOPY" -eq 1; then enable_ntdll_ForceBottomUpAlloc=1 fi +if test "$enable_mfplat_streaming_support" -eq 1; then + if test "$enable_mfplat_reverts" -gt 1; then + abort "Patchset mfplat-reverts disabled, but mfplat-streaming-support depends on that." + fi + enable_mfplat_reverts=1 +fi + if test "$enable_imm32_com_initialization" -eq 1; then if test "$enable_winex11__NET_ACTIVE_WINDOW" -gt 1; then abort "Patchset winex11-_NET_ACTIVE_WINDOW disabled, but imm32-com-initialization depends on that." @@ -2439,6 +2454,76 @@ if test "$enable_loader_KeyboardLayouts" -eq 1; then patch_apply loader-KeyboardLayouts/0002-user32-Improve-GetKeyboardLayoutList.patch fi +# Patchset mfplat-reverts +# | +# | Modified files: +# | * dlls/winegstreamer/gst_private.h, dlls/winegstreamer/media_source.c, dlls/winegstreamer/quartz_parser.c, +# | dlls/winegstreamer/wg_parser.c +# | +if test "$enable_mfplat_reverts" -eq 1; then + patch_apply mfplat-reverts/0001-Revert-winegstreamer-Fix-return-code-in-init_gst-fai.patch + patch_apply mfplat-reverts/0002-Revert-winegstreamer-Replace-source-pad-interface-wi.patch + patch_apply mfplat-reverts/0003-Revert-winegstreamer-Allocate-source-media-buffers-i.patch + patch_apply mfplat-reverts/0004-Revert-winegstreamer-Duplicate-source-shutdown-path-.patch + patch_apply mfplat-reverts/0005-Revert-winegstreamer-Properly-clean-up-from-failure-.patch + patch_apply mfplat-reverts/0006-Revert-winegstreamer-Factor-out-more-of-the-init_gst.patch +fi + +# Patchset mfplat-streaming-support +# | +# | This patchset has the following (direct or indirect) dependencies: +# | * mfplat-reverts +# | +# | This patchset fixes the following Wine bugs: +# | * [#49692] Multiple applications need a Media Foundation media source implementation +# | +# | Modified files: +# | * dlls/mf/topology.c, dlls/mfplat/main.c, dlls/winegstreamer/Makefile.in, dlls/winegstreamer/audioconvert.c, +# | dlls/winegstreamer/colorconvert.c, dlls/winegstreamer/decode_transform.c, dlls/winegstreamer/gst_private.h, +# | dlls/winegstreamer/media_source.c, dlls/winegstreamer/mfplat.c, dlls/winegstreamer/quartz_parser.c, +# | dlls/winegstreamer/wg_parser.c, dlls/winegstreamer/winegstreamer_classes.idl, include/mfidl.idl, include/wmcodecdsp.idl +# | +if test "$enable_mfplat_streaming_support" -eq 1; then + patch_apply mfplat-streaming-support/0001-winegstreamer-Activate-source-pad-in-push-mode-if-it.patch + patch_apply mfplat-streaming-support/0002-winegstreamer-Push-stream-start-and-segment-events-i.patch + patch_apply mfplat-streaming-support/0003-winegstreamer-Introduce-H.264-decoder-transform.patch + patch_apply mfplat-streaming-support/0004-winegstreamer-Implement-GetInputAvailableType-for-de.patch + patch_apply mfplat-streaming-support/0005-winegstreamer-Implement-GetOutputAvailableType-for-d.patch + patch_apply mfplat-streaming-support/0006-winegstreamer-Implement-SetInputType-for-decode-tran.patch + patch_apply mfplat-streaming-support/0007-winegstreamer-Implement-SetOutputType-for-decode-tra.patch + patch_apply mfplat-streaming-support/0008-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch + patch_apply mfplat-streaming-support/0009-winegstreamer-Add-push-mode-path-for-wg_parser.patch + patch_apply mfplat-streaming-support/0010-winegstreamer-Implement-Process-Input-Output-for-dec.patch + patch_apply mfplat-streaming-support/0011-winestreamer-Implement-ProcessMessage-for-decoder-tr.patch + patch_apply mfplat-streaming-support/0012-winegstreamer-Semi-stub-GetAttributes-for-decoder-tr.patch + patch_apply mfplat-streaming-support/0013-winegstreamer-Register-the-H.264-decoder-transform.patch + patch_apply mfplat-streaming-support/0014-winegstreamer-Introduce-AAC-decoder-transform.patch + patch_apply mfplat-streaming-support/0015-winegstreamer-Register-the-AAC-decoder-transform.patch + patch_apply mfplat-streaming-support/0016-winegstreamer-Rename-GStreamer-objects-to-be-more-ge.patch + patch_apply mfplat-streaming-support/0017-winegstreamer-Report-streams-backwards-in-media-sour.patch + patch_apply mfplat-streaming-support/0018-winegstreamer-Implement-Process-Input-Output-for-aud.patch + patch_apply mfplat-streaming-support/0019-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch + patch_apply mfplat-streaming-support/0020-winegstreamer-Semi-stub-Get-Attributes-functions-for.patch + patch_apply mfplat-streaming-support/0021-winegstreamer-Introduce-color-conversion-transform.patch + patch_apply mfplat-streaming-support/0022-winegstreamer-Register-the-color-conversion-transfor.patch + patch_apply mfplat-streaming-support/0023-winegstreamer-Implement-GetInputAvailableType-for-co.patch + patch_apply mfplat-streaming-support/0024-winegstreamer-Implement-SetInputType-for-color-conve.patch + patch_apply mfplat-streaming-support/0025-winegstreamer-Implement-GetOutputAvailableType-for-c.patch + patch_apply mfplat-streaming-support/0026-winegstreamer-Implement-SetOutputType-for-color-conv.patch + patch_apply mfplat-streaming-support/0027-winegstreamer-Implement-Process-Input-Output-for-col.patch + patch_apply mfplat-streaming-support/0028-winegstreamer-Implement-ProcessMessage-for-color-con.patch + patch_apply mfplat-streaming-support/0029-winegstreamer-Implement-Get-Input-Output-StreamInfo-.patch + patch_apply mfplat-streaming-support/0030-mf-topology-Forward-failure-from-SetOutputType-when-.patch + patch_apply mfplat-streaming-support/0031-winegstreamer-Handle-flush-command-in-audio-converst.patch + patch_apply mfplat-streaming-support/0032-winegstreamer-In-the-default-configuration-select-on.patch + patch_apply mfplat-streaming-support/0033-winegstreamer-Implement-MF_SD_LANGUAGE.patch + patch_apply mfplat-streaming-support/0034-winegstreamer-Only-require-videobox-element-for-pars.patch + patch_apply mfplat-streaming-support/0035-winegstreamer-Don-t-rely-on-max_size-in-unseekable-p.patch + patch_apply mfplat-streaming-support/0036-winegstreamer-Implement-MFT_MESSAGE_COMMAND_FLUSH-fo.patch + patch_apply mfplat-streaming-support/0037-winegstreamer-Default-Frame-size-if-one-isn-t-availa.patch + patch_apply mfplat-streaming-support/0038-mfplat-Stub-out-MFCreateDXGIDeviceManager-to-avoid-t.patch +fi + # Patchset mmsystem.dll16-MIDIHDR_Refcount # | # | This patchset fixes the following Wine bugs: