This patches apply on top of wine-7.0, with staging patches applied.
Easiest way to build this is to use something like wine-tkg, and apply this as user patches.
This patches apply on top of wine-7.0, with staging patches applied.
Easiest way to build this is to use something like wine-tkg, and apply this as user patches.
From 996f10c9857318f53a309924a18b03283a246d6a Mon Sep 17 00:00:00 2001 | |
From: Alistair Leslie-Hughes <[email protected]> | |
Date: Wed, 23 Feb 2022 12:23:34 +0300 | |
Subject: [PATCH 1/2] mfplat: Correctly calculate url scheme length. | |
When a url is passed in, for example "http://..." | |
We need to include the : in the scheme string not exclude it. | |
Signed-off-by: Alistair Leslie-Hughes <[email protected]> | |
Signed-off-by: Nikolay Sivov <[email protected]> | |
Signed-off-by: Alexandre Julliard <[email protected]> | |
--- | |
dlls/mfplat/main.c | 5 +++-- | |
1 file changed, 3 insertions(+), 2 deletions(-) | |
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c | |
index 5d5fbbe1bdd..0cc90f40699 100644 | |
--- a/dlls/mfplat/main.c | |
+++ b/dlls/mfplat/main.c | |
@@ -6172,10 +6172,11 @@ static HRESULT resolver_get_scheme_handler(const WCHAR *url, DWORD flags, IMFSch | |
if (ptr == url || *ptr != ':') | |
{ | |
url = fileschemeW; | |
- ptr = fileschemeW + ARRAY_SIZE(fileschemeW) - 1; | |
+ len = ARRAY_SIZE(fileschemeW) - 1; | |
} | |
+ else | |
+ len = ptr - url + 1; | |
- len = ptr - url; | |
scheme = malloc((len + 1) * sizeof(WCHAR)); | |
if (!scheme) | |
return E_OUTOFMEMORY; | |
-- | |
2.35.1 |
From f2dcdde5c19f0ac41ab2d7af41384c15fa4b885a Mon Sep 17 00:00:00 2001 | |
From: Yuxuan Shui <[email protected]> | |
Date: Tue, 5 Apr 2022 01:28:09 +0100 | |
Subject: [PATCH 2/2] mfplat: add generic scheme handler | |
Add a generic scheme handler supported by GStreamer's uridecodebin. This should support all | |
protocols supported by GStreamer's plugins. | |
Signed-off-by: Yuxuan Shui <[email protected]> | |
--- | |
dlls/mf/Makefile.in | 2 +- | |
dlls/mf/main.c | 175 +++++++++++++++++++------- | |
dlls/mf/mf.idl | 7 ++ | |
dlls/mf/mf.rgs | 12 ++ | |
dlls/mfplat/tests/mfplat.c | 6 + | |
dlls/winegstreamer/Makefile.in | 1 + | |
dlls/winegstreamer/gst_private.h | 3 +- | |
dlls/winegstreamer/media_source.c | 119 +++++++++++++----- | |
dlls/winegstreamer/quartz_parser.c | 2 +- | |
dlls/winegstreamer/wg_parser.c | 136 +++++++++++++++++--- | |
dlls/winegstreamer/winegstreamer.spec | 1 + | |
libs/mfuuid/mfuuid.c | 1 + | |
12 files changed, 370 insertions(+), 95 deletions(-) | |
diff --git a/dlls/mf/Makefile.in b/dlls/mf/Makefile.in | |
index 77d85ad041b..f06537c8087 100644 | |
--- a/dlls/mf/Makefile.in | |
+++ b/dlls/mf/Makefile.in | |
@@ -1,7 +1,7 @@ | |
MODULE = mf.dll | |
IMPORTLIB = mf | |
IMPORTS = advapi32 mfplat ole32 uuid mfuuid strmiids | |
-DELAYIMPORTS = evr user32 | |
+DELAYIMPORTS = evr user32 winegstreamer | |
EXTRADLLFLAGS = -Wb,--prefer-native | |
diff --git a/dlls/mf/main.c b/dlls/mf/main.c | |
index acbb8377e52..358b35e9550 100644 | |
--- a/dlls/mf/main.c | |
+++ b/dlls/mf/main.c | |
@@ -34,6 +34,9 @@ | |
WINE_DEFAULT_DEBUG_CHANNEL(mfplat); | |
extern const GUID CLSID_FileSchemePlugin; | |
+extern const GUID CLSID_GStreamerSchemePlugin; | |
+ | |
+HRESULT WINAPI winegstreamer_create_media_source_from_uri(const WCHAR *, IUnknown **); | |
struct activate_object | |
{ | |
@@ -547,7 +550,7 @@ static const IClassFactoryVtbl class_factory_vtbl = | |
class_factory_LockServer, | |
}; | |
-struct file_scheme_handler_result | |
+struct scheme_handler_result | |
{ | |
struct list entry; | |
IMFAsyncResult *result; | |
@@ -555,7 +558,7 @@ struct file_scheme_handler_result | |
IUnknown *object; | |
}; | |
-struct file_scheme_handler | |
+struct scheme_handler | |
{ | |
IMFSchemeHandler IMFSchemeHandler_iface; | |
IMFAsyncCallback IMFAsyncCallback_iface; | |
@@ -565,17 +568,17 @@ struct file_scheme_handler | |
CRITICAL_SECTION cs; | |
}; | |
-static struct file_scheme_handler *impl_from_IMFSchemeHandler(IMFSchemeHandler *iface) | |
+static struct scheme_handler *impl_from_IMFSchemeHandler(IMFSchemeHandler *iface) | |
{ | |
- return CONTAINING_RECORD(iface, struct file_scheme_handler, IMFSchemeHandler_iface); | |
+ return CONTAINING_RECORD(iface, struct scheme_handler, IMFSchemeHandler_iface); | |
} | |
-static struct file_scheme_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) | |
+static struct scheme_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) | |
{ | |
- return CONTAINING_RECORD(iface, struct file_scheme_handler, IMFAsyncCallback_iface); | |
+ return CONTAINING_RECORD(iface, struct scheme_handler, IMFAsyncCallback_iface); | |
} | |
-static HRESULT WINAPI file_scheme_handler_QueryInterface(IMFSchemeHandler *iface, REFIID riid, void **obj) | |
+static HRESULT WINAPI scheme_handler_QueryIntace(IMFSchemeHandler *iface, REFIID riid, void **obj) | |
{ | |
TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); | |
@@ -592,9 +595,9 @@ static HRESULT WINAPI file_scheme_handler_QueryInterface(IMFSchemeHandler *iface | |
return E_NOINTERFACE; | |
} | |
-static ULONG WINAPI file_scheme_handler_AddRef(IMFSchemeHandler *iface) | |
+static ULONG WINAPI scheme_handler_AddRef(IMFSchemeHandler *iface) | |
{ | |
- struct file_scheme_handler *handler = impl_from_IMFSchemeHandler(iface); | |
+ struct scheme_handler *handler = impl_from_IMFSchemeHandler(iface); | |
ULONG refcount = InterlockedIncrement(&handler->refcount); | |
TRACE("%p, refcount %u.\n", handler, refcount); | |
@@ -602,17 +605,17 @@ static ULONG WINAPI file_scheme_handler_AddRef(IMFSchemeHandler *iface) | |
return refcount; | |
} | |
-static ULONG WINAPI file_scheme_handler_Release(IMFSchemeHandler *iface) | |
+static ULONG WINAPI scheme_handler_Release(IMFSchemeHandler *iface) | |
{ | |
- struct file_scheme_handler *handler = impl_from_IMFSchemeHandler(iface); | |
+ struct scheme_handler *handler = impl_from_IMFSchemeHandler(iface); | |
ULONG refcount = InterlockedDecrement(&handler->refcount); | |
- struct file_scheme_handler_result *result, *next; | |
+ struct scheme_handler_result *result, *next; | |
TRACE("%p, refcount %u.\n", iface, refcount); | |
if (!refcount) | |
{ | |
- LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct file_scheme_handler_result, entry) | |
+ LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct scheme_handler_result, entry) | |
{ | |
list_remove(&result->entry); | |
IMFAsyncResult_Release(result->result); | |
@@ -695,10 +698,10 @@ static const IUnknownVtbl create_object_context_vtbl = | |
create_object_context_Release, | |
}; | |
-static HRESULT WINAPI file_scheme_handler_BeginCreateObject(IMFSchemeHandler *iface, const WCHAR *url, DWORD flags, | |
+static HRESULT WINAPI scheme_handler_BeginCreateObject(IMFSchemeHandler *iface, const WCHAR *url, DWORD flags, | |
IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state) | |
{ | |
- struct file_scheme_handler *handler = impl_from_IMFSchemeHandler(iface); | |
+ struct scheme_handler *handler = impl_from_IMFSchemeHandler(iface); | |
struct create_object_context *context; | |
IMFAsyncResult *caller, *item; | |
HRESULT hr; | |
@@ -751,18 +754,18 @@ static HRESULT WINAPI file_scheme_handler_BeginCreateObject(IMFSchemeHandler *if | |
return hr; | |
} | |
-static HRESULT WINAPI file_scheme_handler_EndCreateObject(IMFSchemeHandler *iface, IMFAsyncResult *result, | |
+static HRESULT WINAPI scheme_handler_EndCreateObject(IMFSchemeHandler *iface, IMFAsyncResult *result, | |
MF_OBJECT_TYPE *obj_type, IUnknown **object) | |
{ | |
- struct file_scheme_handler *handler = impl_from_IMFSchemeHandler(iface); | |
- struct file_scheme_handler_result *found = NULL, *cur; | |
+ struct scheme_handler *handler = impl_from_IMFSchemeHandler(iface); | |
+ struct scheme_handler_result *found = NULL, *cur; | |
HRESULT hr; | |
TRACE("%p, %p, %p, %p.\n", iface, result, obj_type, object); | |
EnterCriticalSection(&handler->cs); | |
- LIST_FOR_EACH_ENTRY(cur, &handler->results, struct file_scheme_handler_result, entry) | |
+ LIST_FOR_EACH_ENTRY(cur, &handler->results, struct scheme_handler_result, entry) | |
{ | |
if (result == cur->result) | |
{ | |
@@ -792,16 +795,16 @@ static HRESULT WINAPI file_scheme_handler_EndCreateObject(IMFSchemeHandler *ifac | |
return hr; | |
} | |
-static HRESULT WINAPI file_scheme_handler_CancelObjectCreation(IMFSchemeHandler *iface, IUnknown *cancel_cookie) | |
+static HRESULT WINAPI scheme_handler_CancelObjectCreation(IMFSchemeHandler *iface, IUnknown *cancel_cookie) | |
{ | |
- struct file_scheme_handler *handler = impl_from_IMFSchemeHandler(iface); | |
- struct file_scheme_handler_result *found = NULL, *cur; | |
+ struct scheme_handler *handler = impl_from_IMFSchemeHandler(iface); | |
+ struct scheme_handler_result *found = NULL, *cur; | |
TRACE("%p, %p.\n", iface, cancel_cookie); | |
EnterCriticalSection(&handler->cs); | |
- LIST_FOR_EACH_ENTRY(cur, &handler->results, struct file_scheme_handler_result, entry) | |
+ LIST_FOR_EACH_ENTRY(cur, &handler->results, struct scheme_handler_result, entry) | |
{ | |
if (cancel_cookie == (IUnknown *)cur->result) | |
{ | |
@@ -824,17 +827,17 @@ static HRESULT WINAPI file_scheme_handler_CancelObjectCreation(IMFSchemeHandler | |
return found ? S_OK : MF_E_UNEXPECTED; | |
} | |
-static const IMFSchemeHandlerVtbl file_scheme_handler_vtbl = | |
+static const IMFSchemeHandlerVtbl scheme_handler_vtbl = | |
{ | |
- file_scheme_handler_QueryInterface, | |
- file_scheme_handler_AddRef, | |
- file_scheme_handler_Release, | |
- file_scheme_handler_BeginCreateObject, | |
- file_scheme_handler_EndCreateObject, | |
- file_scheme_handler_CancelObjectCreation, | |
+ scheme_handler_QueryIntace, | |
+ scheme_handler_AddRef, | |
+ scheme_handler_Release, | |
+ scheme_handler_BeginCreateObject, | |
+ scheme_handler_EndCreateObject, | |
+ scheme_handler_CancelObjectCreation, | |
}; | |
-static HRESULT WINAPI file_scheme_handler_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) | |
+static HRESULT WINAPI scheme_handler_callback_QueryIntace(IMFAsyncCallback *iface, REFIID riid, void **obj) | |
{ | |
if (IsEqualIID(riid, &IID_IMFAsyncCallback) || | |
IsEqualIID(riid, &IID_IUnknown)) | |
@@ -849,24 +852,24 @@ static HRESULT WINAPI file_scheme_handler_callback_QueryInterface(IMFAsyncCallba | |
return E_NOINTERFACE; | |
} | |
-static ULONG WINAPI file_scheme_handler_callback_AddRef(IMFAsyncCallback *iface) | |
+static ULONG WINAPI scheme_handler_callback_AddRef(IMFAsyncCallback *iface) | |
{ | |
- struct file_scheme_handler *handler = impl_from_IMFAsyncCallback(iface); | |
+ struct scheme_handler *handler = impl_from_IMFAsyncCallback(iface); | |
return IMFSchemeHandler_AddRef(&handler->IMFSchemeHandler_iface); | |
} | |
-static ULONG WINAPI file_scheme_handler_callback_Release(IMFAsyncCallback *iface) | |
+static ULONG WINAPI scheme_handler_callback_Release(IMFAsyncCallback *iface) | |
{ | |
- struct file_scheme_handler *handler = impl_from_IMFAsyncCallback(iface); | |
+ struct scheme_handler *handler = impl_from_IMFAsyncCallback(iface); | |
return IMFSchemeHandler_Release(&handler->IMFSchemeHandler_iface); | |
} | |
-static HRESULT WINAPI file_scheme_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) | |
+static HRESULT WINAPI scheme_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) | |
{ | |
return E_NOTIMPL; | |
} | |
-static HRESULT file_scheme_handler_get_resolver(struct file_scheme_handler *handler, IMFSourceResolver **resolver) | |
+static HRESULT file_scheme_handler_get_resolver(struct scheme_handler *handler, IMFSourceResolver **resolver) | |
{ | |
HRESULT hr; | |
@@ -890,8 +893,8 @@ static HRESULT file_scheme_handler_get_resolver(struct file_scheme_handler *hand | |
static HRESULT WINAPI file_scheme_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) | |
{ | |
static const WCHAR schemeW[] = {'f','i','l','e',':','/','/'}; | |
- struct file_scheme_handler *handler = impl_from_IMFAsyncCallback(iface); | |
- struct file_scheme_handler_result *handler_result; | |
+ struct scheme_handler *handler = impl_from_IMFAsyncCallback(iface); | |
+ struct scheme_handler_result *handler_result; | |
MF_OBJECT_TYPE obj_type = MF_OBJECT_INVALID; | |
IUnknown *object = NULL, *context_object; | |
struct create_object_context *context; | |
@@ -964,18 +967,75 @@ static HRESULT WINAPI file_scheme_handler_callback_Invoke(IMFAsyncCallback *ifac | |
return S_OK; | |
} | |
+static HRESULT WINAPI gstreamer_scheme_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) | |
+{ | |
+ IMFAsyncResult *caller; | |
+ struct scheme_handler *handler = impl_from_IMFAsyncCallback(iface); | |
+ struct scheme_handler_result *handler_result; | |
+ IUnknown *object = NULL, *context_object; | |
+ struct create_object_context *context; | |
+ HRESULT hr; | |
+ | |
+ caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result); | |
+ | |
+ if (FAILED(hr = IMFAsyncResult_GetObject(result, &context_object))) | |
+ { | |
+ WARN("Expected context set for callee result.\n"); | |
+ return hr; | |
+ } | |
+ | |
+ context = impl_from_IUnknown(context_object); | |
+ | |
+ hr = winegstreamer_create_media_source_from_uri(context->url, &object); | |
+ | |
+ handler_result = malloc(sizeof(*handler_result)); | |
+ if (handler_result) | |
+ { | |
+ handler_result->result = caller; | |
+ IMFAsyncResult_AddRef(handler_result->result); | |
+ | |
+ // We only know how to create media source | |
+ handler_result->obj_type = MF_OBJECT_MEDIASOURCE; | |
+ handler_result->object = object; | |
+ | |
+ EnterCriticalSection(&handler->cs); | |
+ list_add_tail(&handler->results, &handler_result->entry); | |
+ LeaveCriticalSection(&handler->cs); | |
+ } | |
+ else | |
+ { | |
+ if (object) | |
+ IUnknown_Release(object); | |
+ hr = E_OUTOFMEMORY; | |
+ } | |
+ | |
+ IMFAsyncResult_SetStatus(caller, hr); | |
+ MFInvokeCallback(caller); | |
+ | |
+ return S_OK; | |
+} | |
+ | |
static const IMFAsyncCallbackVtbl file_scheme_handler_callback_vtbl = | |
{ | |
- file_scheme_handler_callback_QueryInterface, | |
- file_scheme_handler_callback_AddRef, | |
- file_scheme_handler_callback_Release, | |
- file_scheme_handler_callback_GetParameters, | |
+ scheme_handler_callback_QueryIntace, | |
+ scheme_handler_callback_AddRef, | |
+ scheme_handler_callback_Release, | |
+ scheme_handler_callback_GetParameters, | |
file_scheme_handler_callback_Invoke, | |
}; | |
+static const IMFAsyncCallbackVtbl gstreamer_scheme_handler_callback_vtbl = | |
+{ | |
+ scheme_handler_callback_QueryIntace, | |
+ scheme_handler_callback_AddRef, | |
+ scheme_handler_callback_Release, | |
+ scheme_handler_callback_GetParameters, | |
+ gstreamer_scheme_handler_callback_Invoke, | |
+}; | |
+ | |
static HRESULT file_scheme_handler_construct(REFIID riid, void **obj) | |
{ | |
- struct file_scheme_handler *handler; | |
+ struct scheme_handler *handler; | |
HRESULT hr; | |
TRACE("%s, %p.\n", debugstr_guid(riid), obj); | |
@@ -983,7 +1043,7 @@ static HRESULT file_scheme_handler_construct(REFIID riid, void **obj) | |
if (!(handler = calloc(1, sizeof(*handler)))) | |
return E_OUTOFMEMORY; | |
- handler->IMFSchemeHandler_iface.lpVtbl = &file_scheme_handler_vtbl; | |
+ handler->IMFSchemeHandler_iface.lpVtbl = &scheme_handler_vtbl; | |
handler->IMFAsyncCallback_iface.lpVtbl = &file_scheme_handler_callback_vtbl; | |
handler->refcount = 1; | |
list_init(&handler->results); | |
@@ -997,6 +1057,30 @@ static HRESULT file_scheme_handler_construct(REFIID riid, void **obj) | |
static struct class_factory file_scheme_handler_factory = { { &class_factory_vtbl }, file_scheme_handler_construct }; | |
+static HRESULT gstreamer_scheme_handler_construct(REFIID riid, void **obj) | |
+{ | |
+ struct scheme_handler *handler; | |
+ HRESULT hr; | |
+ | |
+ TRACE("%s, %p.\n", debugstr_guid(riid), obj); | |
+ | |
+ if (!(handler = calloc(1, sizeof(*handler)))) | |
+ return E_OUTOFMEMORY; | |
+ | |
+ handler->IMFSchemeHandler_iface.lpVtbl = &scheme_handler_vtbl; | |
+ handler->IMFAsyncCallback_iface.lpVtbl = &gstreamer_scheme_handler_callback_vtbl; | |
+ handler->refcount = 1; | |
+ list_init(&handler->results); | |
+ InitializeCriticalSection(&handler->cs); | |
+ | |
+ hr = IMFSchemeHandler_QueryInterface(&handler->IMFSchemeHandler_iface, riid, obj); | |
+ IMFSchemeHandler_Release(&handler->IMFSchemeHandler_iface); | |
+ | |
+ return hr; | |
+} | |
+ | |
+static struct class_factory gstreamer_scheme_handler_factory = { { &class_factory_vtbl }, gstreamer_scheme_handler_construct }; | |
+ | |
static const struct class_object | |
{ | |
const GUID *clsid; | |
@@ -1005,6 +1089,7 @@ static const struct class_object | |
class_objects[] = | |
{ | |
{ &CLSID_FileSchemePlugin, &file_scheme_handler_factory.IClassFactory_iface }, | |
+ { &CLSID_GStreamerSchemePlugin, &gstreamer_scheme_handler_factory.IClassFactory_iface }, | |
}; | |
/******************************************************************************* | |
diff --git a/dlls/mf/mf.idl b/dlls/mf/mf.idl | |
index 289a521b4f2..3c0d2513e9d 100644 | |
--- a/dlls/mf/mf.idl | |
+++ b/dlls/mf/mf.idl | |
@@ -24,3 +24,10 @@ | |
uuid(477ec299-1421-4bdd-971f-7ccb933f21ad) | |
] | |
coclass FileSchemePlugin { } | |
+ | |
+[ | |
+ helpstring("GStreamer scheme handler"), | |
+ threading(both), | |
+ uuid(587eeb6a-7336-4ebd-a4f2-91c948de622c) | |
+] | |
+coclass GStreamerSchemePlugin { } | |
diff --git a/dlls/mf/mf.rgs b/dlls/mf/mf.rgs | |
index f127df76321..53d26cf7a79 100644 | |
--- a/dlls/mf/mf.rgs | |
+++ b/dlls/mf/mf.rgs | |
@@ -12,6 +12,18 @@ HKLM | |
{ | |
val '{477ec299-1421-4bdd-971f-7ccb933f21ad}' = s 'File Scheme Handler' | |
} | |
+ 'http:' | |
+ { | |
+ val '{587eeb6a-7336-4ebd-a4f2-91c948de622c}' = s 'GStreamer Scheme Handler' | |
+ } | |
+ 'https:' | |
+ { | |
+ val '{587eeb6a-7336-4ebd-a4f2-91c948de622c}' = s 'GStreamer Scheme Handler' | |
+ } | |
+ 'rtsp:' | |
+ { | |
+ val '{587eeb6a-7336-4ebd-a4f2-91c948de622c}' = s 'GStreamer Scheme Handler' | |
+ } | |
} | |
} | |
} | |
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c | |
index 21eab6d1172..243bf670815 100644 | |
--- a/dlls/mfplat/tests/mfplat.c | |
+++ b/dlls/mfplat/tests/mfplat.c | |
@@ -520,7 +520,11 @@ static HRESULT WINAPI test_create_from_url_callback_Invoke(IMFAsyncCallback *ifa | |
ok(object2 == object, "Unexpected object.\n"); | |
if (object) | |
+ { | |
+ if (obj_type == MF_OBJECT_MEDIASOURCE) | |
+ IMFMediaSource_Shutdown(object); | |
IUnknown_Release(object); | |
+ } | |
IUnknown_Release(object2); | |
SetEvent(callback->event); | |
@@ -557,6 +561,8 @@ static HRESULT WINAPI test_create_from_file_handler_callback_Invoke(IMFAsyncCall | |
hr = IMFAsyncResult_GetObject(result, &object2); | |
ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); | |
+ if (obj_type == MF_OBJECT_MEDIASOURCE) | |
+ IMFMediaSource_Shutdown((IMFMediaSource *)object); | |
IUnknown_Release(object); | |
} | |
diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in | |
index 9234188619a..07ae6e3b6c3 100644 | |
--- a/dlls/winegstreamer/Makefile.in | |
+++ b/dlls/winegstreamer/Makefile.in | |
@@ -1,5 +1,6 @@ | |
MODULE = winegstreamer.dll | |
IMPORTS = strmbase strmiids uuid ole32 mfuuid | |
+IMPORTLIB = winegstreamer | |
DELAYIMPORTS = mfplat | |
EXTRAINCL = $(GSTREAMER_CFLAGS) | |
EXTRALIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) | |
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h | |
index bf712663d9c..ccba61538b2 100644 | |
--- a/dlls/winegstreamer/gst_private.h | |
+++ b/dlls/winegstreamer/gst_private.h | |
@@ -193,13 +193,14 @@ enum wg_read_result | |
struct unix_funcs | |
{ | |
struct wg_parser *(CDECL *wg_decodebin_parser_create)(void); | |
+ struct wg_parser *(CDECL *wg_uridecodebin_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_raw_media_converter_create)(void); | |
void (CDECL *wg_parser_destroy)(struct wg_parser *parser); | |
- HRESULT (CDECL *wg_parser_connect)(struct wg_parser *parser, uint64_t file_size); | |
+ HRESULT (CDECL *wg_parser_connect)(struct wg_parser *parser, uint64_t file_size, const char *uri); | |
HRESULT (CDECL *wg_parser_connect_unseekable)(struct wg_parser *parser, | |
const struct wg_format *in_format, uint32_t stream_count, const struct wg_format *out_formats, const struct wg_rect *apertures); | |
void (CDECL *wg_parser_disconnect)(struct wg_parser *parser); | |
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c | |
index 7925a5ed856..ea4acf91e0b 100644 | |
--- a/dlls/winegstreamer/media_source.c | |
+++ b/dlls/winegstreamer/media_source.c | |
@@ -1364,63 +1364,42 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl = | |
media_source_Shutdown, | |
}; | |
-static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_source **out_media_source) | |
+static HRESULT media_source_init_from_parser(struct wg_parser *parser, uint64_t file_size, const WCHAR *uri, struct media_source *object) | |
{ | |
BOOL video_selected = FALSE, audio_selected = FALSE; | |
IMFStreamDescriptor **descriptors = NULL; | |
- struct media_source *object; | |
UINT64 total_pres_time = 0; | |
- struct wg_parser *parser; | |
- DWORD bytestream_caps; | |
- uint64_t file_size; | |
unsigned int i; | |
HRESULT hr; | |
+ char *uri_unix = NULL; | |
- if (FAILED(hr = IMFByteStream_GetCapabilities(bytestream, &bytestream_caps))) | |
- return hr; | |
- | |
- if (!(bytestream_caps & MFBYTESTREAM_IS_SEEKABLE)) | |
+ if (uri) | |
{ | |
- FIXME("Non-seekable bytestreams not supported.\n"); | |
- return MF_E_BYTESTREAM_NOT_SEEKABLE; | |
- } | |
+ uri_unix = malloc(wcslen(uri) * 3 + 1); | |
+ if (!uri_unix) { | |
+ hr = E_OUTOFMEMORY; | |
+ goto fail; | |
+ } | |
- if (FAILED(hr = IMFByteStream_GetLength(bytestream, &file_size))) | |
- { | |
- FIXME("Failed to get byte stream length, hr %#x.\n", hr); | |
- return hr; | |
+ WideCharToMultiByte(CP_UNIXCP, 0, uri, -1, uri_unix, wcslen(uri) * 3 + 1, NULL, NULL); | |
} | |
- if (!(object = calloc(1, sizeof(*object)))) | |
- return E_OUTOFMEMORY; | |
- | |
object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl; | |
object->IMFGetService_iface.lpVtbl = &media_source_get_service_vtbl; | |
object->IMFRateSupport_iface.lpVtbl = &media_source_rate_support_vtbl; | |
object->IMFRateControl_iface.lpVtbl = &media_source_rate_control_vtbl; | |
object->async_commands_callback.lpVtbl = &source_async_commands_callback_vtbl; | |
object->ref = 1; | |
- object->byte_stream = bytestream; | |
- IMFByteStream_AddRef(bytestream); | |
if (FAILED(hr = MFCreateEventQueue(&object->event_queue))) | |
goto fail; | |
if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue))) | |
goto fail; | |
- | |
- if (!(parser = unix_funcs->wg_decodebin_parser_create())) | |
- { | |
- hr = E_OUTOFMEMORY; | |
- goto fail; | |
- } | |
object->wg_parser = parser; | |
- | |
- object->read_thread = CreateThread(NULL, 0, read_thread, object, 0, NULL); | |
- | |
object->state = SOURCE_OPENING; | |
- if (FAILED(hr = unix_funcs->wg_parser_connect(parser, file_size))) | |
+ if (FAILED(hr = unix_funcs->wg_parser_connect(parser, file_size, uri_unix))) | |
goto fail; | |
/* In Media Foundation, sources may read from any media source stream | |
@@ -1517,13 +1496,87 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ | |
object->state = SOURCE_STOPPED; | |
- *out_media_source = object; | |
return S_OK; | |
fail: | |
- WARN("Failed to construct MFMediaSource, hr %#x.\n", hr); | |
+ WARN("Failed to setup MFMediaSource, hr %#x.\n", hr); | |
+ free(uri_unix); | |
free(descriptors); | |
+ return hr; | |
+} | |
+ | |
+static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_source **out_media_source) | |
+{ | |
+ struct wg_parser *parser; | |
+ struct media_source *object; | |
+ DWORD bytestream_caps; | |
+ uint64_t file_size; | |
+ HRESULT hr; | |
+ | |
+ if (!(object = calloc(1, sizeof(*object)))) | |
+ return E_OUTOFMEMORY; | |
+ | |
+ if (FAILED(hr = IMFByteStream_GetCapabilities(bytestream, &bytestream_caps))) | |
+ return hr; | |
+ | |
+ if (!(bytestream_caps & MFBYTESTREAM_IS_SEEKABLE)) | |
+ { | |
+ FIXME("Non-seekable bytestreams not supported.\n"); | |
+ return MF_E_BYTESTREAM_NOT_SEEKABLE; | |
+ } | |
+ | |
+ if (FAILED(hr = IMFByteStream_GetLength(bytestream, &file_size))) | |
+ { | |
+ FIXME("Failed to get byte stream length, hr %#lx.\n", hr); | |
+ return hr; | |
+ } | |
+ | |
+ if (!(parser = unix_funcs->wg_decodebin_parser_create())) | |
+ { | |
+ hr = E_OUTOFMEMORY; | |
+ goto fail; | |
+ } | |
+ | |
+ object->byte_stream = bytestream; | |
+ IMFByteStream_AddRef(bytestream); | |
+ | |
+ object->read_thread = CreateThread(NULL, 0, read_thread, object, 0, NULL); | |
+ | |
+ if (FAILED(hr = media_source_init_from_parser(parser, file_size, NULL, object))) | |
+ goto fail; | |
+ | |
+ *out_media_source = object; | |
+ | |
+ return S_OK; | |
+ fail: | |
+ WARN("Failed to construct MFMediaSource, hr %#x.\n", hr); | |
+ IMFMediaSource_Release(&object->IMFMediaSource_iface); | |
+ return hr; | |
+} | |
+ | |
+HRESULT WINAPI winegstreamer_create_media_source_from_uri(const WCHAR *uri, IUnknown **out_media_source) | |
+{ | |
+ struct media_source *object; | |
+ struct wg_parser *parser; | |
+ HRESULT hr; | |
+ | |
+ if (!(object = calloc(1, sizeof(*object)))) | |
+ return E_OUTOFMEMORY; | |
+ | |
+ if (!(parser = unix_funcs->wg_uridecodebin_parser_create())) | |
+ { | |
+ hr = E_OUTOFMEMORY; | |
+ goto fail; | |
+ } | |
+ | |
+ if (FAILED(hr = media_source_init_from_parser(parser, 0, uri, object))) | |
+ goto fail; | |
+ | |
+ *out_media_source = (IUnknown *)&object->IMFMediaSource_iface; | |
+ return S_OK; | |
+ fail: | |
+ WARN("Failed to construct MFMediaSource, hr %#x.\n", hr); | |
IMFMediaSource_Release(&object->IMFMediaSource_iface); | |
return hr; | |
} | |
diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c | |
index 85ba612a077..fc2cc0bf58a 100644 | |
--- a/dlls/winegstreamer/quartz_parser.c | |
+++ b/dlls/winegstreamer/quartz_parser.c | |
@@ -960,7 +960,7 @@ static HRESULT parser_sink_connect(struct strmbase_sink *iface, IPin *peer, cons | |
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))) | |
+ if (FAILED(hr = unix_funcs->wg_parser_connect(filter->wg_parser, file_size, NULL))) | |
goto err; | |
if (!filter->init_gst(filter)) | |
diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c | |
index 255c7bc09c8..129fef306d6 100644 | |
--- a/dlls/winegstreamer/wg_parser.c | |
+++ b/dlls/winegstreamer/wg_parser.c | |
@@ -29,6 +29,7 @@ | |
#define WIN32_NO_STATUS | |
#include "gst_private.h" | |
#include "winternl.h" | |
+#include "wine/unixlib.h" | |
#include <gst/gst.h> | |
#include <gst/video/video.h> | |
@@ -52,6 +53,7 @@ GST_DEBUG_CATEGORY_STATIC(wine); | |
struct wg_parser | |
{ | |
BOOL (*init_gst)(struct wg_parser *parser); | |
+ void (*set_unlimited_buffering)(struct wg_parser *parser); | |
struct wg_parser_stream **streams; | |
unsigned int stream_count, expected_stream_count; | |
@@ -62,6 +64,7 @@ struct wg_parser | |
guint64 file_size, start_offset, next_offset, stop_offset; | |
guint64 next_pull_offset; | |
+ gchar *uri; | |
pthread_t push_thread; | |
@@ -715,11 +718,22 @@ static void CDECL wg_parser_complete_read_request(struct wg_parser *parser, enum | |
} | |
static void CDECL wg_parser_set_unlimited_buffering(struct wg_parser *parser) | |
+{ | |
+ if (parser->set_unlimited_buffering) | |
+ parser->set_unlimited_buffering(parser); | |
+} | |
+ | |
+static void wg_parser_decodebin_set_unlimited_buffering(struct wg_parser *parser) | |
{ | |
g_object_set(parser->decodebin, "max-size-buffers", G_MAXUINT, NULL); | |
g_object_set(parser->decodebin, "max-size-time", G_MAXUINT64, NULL); | |
g_object_set(parser->decodebin, "max-size-bytes", G_MAXUINT, NULL); | |
} | |
+static void wg_parser_uridecodebin_set_unlimited_buffering(struct wg_parser *parser) | |
+{ | |
+ g_object_set(parser->decodebin, "buffer-duration", G_MAXINT64, NULL); | |
+ g_object_set(parser->decodebin, "buffer-size", G_MAXINT, NULL); | |
+} | |
static void CDECL wg_parser_stream_get_preferred_format(struct wg_parser_stream *stream, struct wg_format *format) | |
{ | |
@@ -1970,11 +1984,22 @@ static gchar *query_language(GstPad *pad) | |
return ret; | |
} | |
-static HRESULT wg_parser_connect_inner(struct wg_parser *parser) | |
+static void wg_parser_create_my_src(struct wg_parser *parser) | |
{ | |
GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("wine_src", | |
GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); | |
+ parser->my_src = gst_pad_new_from_static_template(&src_template, "wine-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); | |
+} | |
+ | |
+static HRESULT wg_parser_connect_inner(struct wg_parser *parser) | |
+{ | |
+ | |
parser->sink_connected = true; | |
if (!parser->bus) | |
@@ -1986,26 +2011,21 @@ static HRESULT wg_parser_connect_inner(struct wg_parser *parser) | |
parser->container = gst_bin_new(NULL); | |
gst_element_set_bus(parser->container, parser->bus); | |
- parser->my_src = gst_pad_new_from_static_template(&src_template, "wine-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); | |
- | |
parser->start_offset = parser->next_offset = parser->stop_offset = 0; | |
parser->next_pull_offset = 0; | |
return S_OK; | |
} | |
-static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_size) | |
+static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_size, const char *uri) | |
{ | |
unsigned int i; | |
HRESULT hr; | |
parser->seekable = true; | |
parser->file_size = file_size; | |
+ if (uri) | |
+ parser->uri = strdup(uri); | |
if ((hr = wg_parser_connect_inner(parser))) | |
return hr; | |
@@ -2170,11 +2190,18 @@ static void CDECL wg_parser_disconnect(struct wg_parser *parser) | |
pthread_mutex_unlock(&parser->mutex); | |
gst_element_set_state(parser->container, GST_STATE_NULL); | |
- if (!parser->pull_mode) | |
- gst_pad_set_active(parser->my_src, 0); | |
- gst_pad_unlink(parser->my_src, parser->their_sink); | |
- gst_object_unref(parser->my_src); | |
- gst_object_unref(parser->their_sink); | |
+ if (parser->my_src) | |
+ { | |
+ if (!parser->pull_mode) | |
+ gst_pad_set_active(parser->my_src, 0); | |
+ gst_object_unref(parser->my_src); | |
+ if (parser->their_sink) | |
+ gst_pad_unlink(parser->my_src, parser->their_sink); | |
+ } | |
+ | |
+ if (parser->their_sink) | |
+ gst_object_unref(parser->their_sink); | |
+ | |
parser->my_src = parser->their_sink = NULL; | |
pthread_mutex_lock(&parser->mutex); | |
@@ -2219,6 +2246,8 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) | |
parser->no_more_pads = parser->error = false; | |
pthread_mutex_unlock(&parser->mutex); | |
+ wg_parser_create_my_src(parser); | |
+ | |
if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0) | |
{ | |
GST_ERROR("Failed to link pads, error %d.\n", ret); | |
@@ -2248,6 +2277,48 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) | |
return TRUE; | |
} | |
+static BOOL uridecodebin_parser_init_gst(struct wg_parser *parser) | |
+{ | |
+ GstElement *element; | |
+ int ret; | |
+ | |
+ if (!(element = create_element("uridecodebin", "base"))) | |
+ return FALSE; | |
+ | |
+ gst_bin_add(GST_BIN(parser->container), element); | |
+ parser->decodebin = element; | |
+ | |
+ g_object_set(parser->decodebin, "uri", parser->uri, NULL); | |
+ | |
+ parser->no_more_pads = false; | |
+ | |
+ g_signal_connect(element, "pad-added", G_CALLBACK(pad_added_cb), parser); | |
+ g_signal_connect(element, "pad-removed", G_CALLBACK(pad_removed_cb), 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); | |
+ | |
+ 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; | |
+} | |
+ | |
static BOOL avi_parser_init_gst(struct wg_parser *parser) | |
{ | |
GstElement *element; | |
@@ -2268,6 +2339,8 @@ static BOOL avi_parser_init_gst(struct wg_parser *parser) | |
parser->no_more_pads = parser->error = false; | |
pthread_mutex_unlock(&parser->mutex); | |
+ wg_parser_create_my_src(parser); | |
+ | |
if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0) | |
{ | |
GST_ERROR("Failed to link pads, error %d.\n", ret); | |
@@ -2308,6 +2381,8 @@ static BOOL mpeg_audio_parser_init_gst(struct wg_parser *parser) | |
gst_bin_add(GST_BIN(parser->container), element); | |
+ wg_parser_create_my_src(parser); | |
+ | |
parser->their_sink = gst_element_get_static_pad(element, "sink"); | |
if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0) | |
{ | |
@@ -2350,6 +2425,8 @@ static BOOL wave_parser_init_gst(struct wg_parser *parser) | |
gst_bin_add(GST_BIN(parser->container), element); | |
+ wg_parser_create_my_src(parser); | |
+ | |
parser->their_sink = gst_element_get_static_pad(element, "sink"); | |
if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0) | |
{ | |
@@ -2435,6 +2512,8 @@ static BOOL raw_media_converter_init_gst(struct wg_parser *parser) | |
their_src = gst_element_get_static_pad(resampler, "src"); | |
} | |
+ wg_parser_create_my_src(parser); | |
+ | |
if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0) | |
{ | |
GST_ERROR("Failed to link sink pads, error %d.\n", ret); | |
@@ -2487,7 +2566,22 @@ static struct wg_parser * CDECL wg_decodebin_parser_create(void) | |
struct wg_parser *parser; | |
if ((parser = wg_parser_create())) | |
+ { | |
parser->init_gst = decodebin_parser_init_gst; | |
+ parser->set_unlimited_buffering = wg_parser_decodebin_set_unlimited_buffering; | |
+ } | |
+ return parser; | |
+} | |
+ | |
+static struct wg_parser * CDECL wg_uridecodebin_parser_create(void) | |
+{ | |
+ struct wg_parser *parser; | |
+ | |
+ if ((parser = wg_parser_create())) | |
+ { | |
+ parser->init_gst = uridecodebin_parser_init_gst; | |
+ parser->set_unlimited_buffering = wg_parser_uridecodebin_set_unlimited_buffering; | |
+ } | |
return parser; | |
} | |
@@ -2496,7 +2590,10 @@ static struct wg_parser * CDECL wg_avi_parser_create(void) | |
struct wg_parser *parser; | |
if ((parser = wg_parser_create())) | |
+ { | |
parser->init_gst = avi_parser_init_gst; | |
+ parser->set_unlimited_buffering = wg_parser_decodebin_set_unlimited_buffering; | |
+ } | |
return parser; | |
} | |
@@ -2505,7 +2602,10 @@ static struct wg_parser * CDECL wg_mpeg_audio_parser_create(void) | |
struct wg_parser *parser; | |
if ((parser = wg_parser_create())) | |
+ { | |
parser->init_gst = mpeg_audio_parser_init_gst; | |
+ parser->set_unlimited_buffering = wg_parser_decodebin_set_unlimited_buffering; | |
+ } | |
return parser; | |
} | |
@@ -2514,7 +2614,10 @@ static struct wg_parser * CDECL wg_wave_parser_create(void) | |
struct wg_parser *parser; | |
if ((parser = wg_parser_create())) | |
+ { | |
parser->init_gst = wave_parser_init_gst; | |
+ parser->set_unlimited_buffering = wg_parser_decodebin_set_unlimited_buffering; | |
+ } | |
return parser; | |
} | |
@@ -2523,7 +2626,10 @@ static struct wg_parser * CDECL wg_raw_media_converter_create(void) | |
struct wg_parser *parser; | |
if ((parser = wg_parser_create())) | |
+ { | |
parser->init_gst = raw_media_converter_init_gst; | |
+ parser->set_unlimited_buffering = wg_parser_decodebin_set_unlimited_buffering; | |
+ } | |
return parser; | |
} | |
@@ -2540,12 +2646,14 @@ static void CDECL wg_parser_destroy(struct wg_parser *parser) | |
pthread_cond_destroy(&parser->read_cond); | |
pthread_cond_destroy(&parser->read_done_cond); | |
+ free(parser->uri); | |
free(parser); | |
} | |
static const struct unix_funcs funcs = | |
{ | |
wg_decodebin_parser_create, | |
+ wg_uridecodebin_parser_create, | |
wg_avi_parser_create, | |
wg_mpeg_audio_parser_create, | |
wg_wave_parser_create, | |
diff --git a/dlls/winegstreamer/winegstreamer.spec b/dlls/winegstreamer/winegstreamer.spec | |
index b16365d0c9f..8e19857032a 100644 | |
--- a/dlls/winegstreamer/winegstreamer.spec | |
+++ b/dlls/winegstreamer/winegstreamer.spec | |
@@ -2,3 +2,4 @@ | |
@ stdcall -private DllGetClassObject(ptr ptr ptr) | |
@ stdcall -private DllRegisterServer() | |
@ stdcall -private DllUnregisterServer() | |
+@ stdcall winegstreamer_create_media_source_from_uri(ptr ptr) | |
diff --git a/libs/mfuuid/mfuuid.c b/libs/mfuuid/mfuuid.c | |
index 537eaef6427..76c19089007 100644 | |
--- a/libs/mfuuid/mfuuid.c | |
+++ b/libs/mfuuid/mfuuid.c | |
@@ -35,3 +35,4 @@ | |
DEFINE_GUID(MF_SCRUBBING_SERVICE, 0xdd0ac3d8,0x40e3,0x4128,0xac,0x48,0xc0,0xad,0xd0,0x67,0xb7,0x14); | |
DEFINE_GUID(CLSID_FileSchemePlugin, 0x477ec299,0x1421,0x4bdd,0x97,0x1f,0x7c,0xcb,0x93,0x3f,0x21,0xad); | |
+DEFINE_GUID(CLSID_GStreamerSchemePlugin, 0x587eeb6a,0x7336,0x4ebd,0xa4,0xf2,0x91,0xc9,0x48,0xde,0x62,0x2c); | |
-- | |
2.35.1 |
I'm having trouble setting this up using wine-tkg. I am patching under proton-tkg but still am placing the files under the wine-tkg directory. I placed them in wine-tkg-userpatches but it didn't use them at all, so I instead renamed their extension to ".mypatch" and it seemed to work. In the end I get an error:
==> ERROR: Patch application has failed. The error was logged to /home/shadd/.wine-tkg/wine-tkg-git/wine-tkg-git/prepare.log for your convenience.
-> Removed BIG_UGLY_FROGMINER - Ribbit
-> Removed Proton-tkg token - Valve Ribbit
-> exit cleanup done
And looking at the end of the log file:
Applying your own patch 0001-mfplat-Correctly-calculate-url-scheme-length.mypatch
patching file dlls/mfplat/main.c
Reversed (or previously applied) patch detected! Skipping patch.
1 out of 1 hunk ignored -- saving rejects to file dlls/mfplat/main.c.rej
I also received a warning at the beginning that looks like it would affect these patches:
==> WARNING: ! Staging has disabled mfplat support on this revision, so video playback will not work in games using mfplat unless a hotfix is available !
I'm not sure if I'm applying this patch correctly. I'm also unsure where to post this other than here. Thanks.