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.