Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/mfplat/main.c | 207 +------------------------------------ dlls/mfplat/tests/mfplat.c | 106 +++++++++++-------- 2 files changed, 64 insertions(+), 249 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 6cd409d63b7..ea1b1770e15 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -5679,188 +5679,6 @@ HRESULT WINAPI MFGetPluginControl(IMFPluginControl **ret) return S_OK; }
-typedef struct _mfsource -{ - IMFMediaSource IMFMediaSource_iface; - LONG ref; -} mfsource; - -static inline mfsource *impl_from_IMFMediaSource(IMFMediaSource *iface) -{ - return CONTAINING_RECORD(iface, mfsource, IMFMediaSource_iface); -} - -static HRESULT WINAPI mfsource_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out) -{ - mfsource *This = impl_from_IMFMediaSource(iface); - - TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), out); - - if (IsEqualIID(riid, &IID_IMFMediaSource) || - IsEqualIID(riid, &IID_IMFMediaEventGenerator) || - IsEqualIID(riid, &IID_IUnknown)) - { - *out = &This->IMFMediaSource_iface; - } - else - { - FIXME("(%s, %p)\n", debugstr_guid(riid), out); - *out = NULL; - return E_NOINTERFACE; - } - - IUnknown_AddRef((IUnknown*)*out); - return S_OK; -} - -static ULONG WINAPI mfsource_AddRef(IMFMediaSource *iface) -{ - mfsource *This = impl_from_IMFMediaSource(iface); - ULONG ref = InterlockedIncrement(&This->ref); - - TRACE("(%p) ref=%u\n", This, ref); - - return ref; -} - -static ULONG WINAPI mfsource_Release(IMFMediaSource *iface) -{ - mfsource *This = impl_from_IMFMediaSource(iface); - ULONG ref = InterlockedDecrement(&This->ref); - - TRACE("(%p) ref=%u\n", This, ref); - - if (!ref) - { - HeapFree(GetProcessHeap(), 0, This); - } - - return ref; -} - -static HRESULT WINAPI mfsource_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event) -{ - mfsource *This = impl_from_IMFMediaSource(iface); - - FIXME("(%p)->(%#x, %p)\n", This, flags, event); - - return E_NOTIMPL; -} - -static HRESULT WINAPI mfsource_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state) -{ - mfsource *This = impl_from_IMFMediaSource(iface); - - FIXME("(%p)->(%p, %p)\n", This, callback, state); - - return E_NOTIMPL; -} - -static HRESULT WINAPI mfsource_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event) -{ - mfsource *This = impl_from_IMFMediaSource(iface); - - FIXME("(%p)->(%p, %p)\n", This, result, event); - - return E_NOTIMPL; -} - -static HRESULT WINAPI mfsource_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type, - HRESULT hr, const PROPVARIANT *value) -{ - mfsource *This = impl_from_IMFMediaSource(iface); - - FIXME("(%p)->(%d, %s, %#x, %p)\n", This, event_type, debugstr_guid(ext_type), hr, value); - - return E_NOTIMPL; -} - -static HRESULT WINAPI mfsource_GetCharacteristics(IMFMediaSource *iface, DWORD *characteristics) -{ - mfsource *This = impl_from_IMFMediaSource(iface); - - FIXME("(%p)->(%p): stub\n", This, characteristics); - - return E_NOTIMPL; -} - -static HRESULT WINAPI mfsource_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor) -{ - mfsource *This = impl_from_IMFMediaSource(iface); - IMFStreamDescriptor *sd; - IMFMediaType *mediatype; - HRESULT hr; - - FIXME("(%p)->(%p): stub\n", This, descriptor); - - if (FAILED(hr = MFCreateMediaType(&mediatype))) - return hr; - - hr = MFCreateStreamDescriptor(0, 1, &mediatype, &sd); - IMFMediaType_Release(mediatype); - if (FAILED(hr)) - return hr; - - hr = MFCreatePresentationDescriptor(1, &sd, descriptor); - IMFStreamDescriptor_Release(sd); - - return hr; -} - -static HRESULT WINAPI mfsource_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor, - const GUID *time_format, const PROPVARIANT *start_position) -{ - mfsource *This = impl_from_IMFMediaSource(iface); - - FIXME("(%p)->(%p, %p, %p): stub\n", This, descriptor, time_format, start_position); - - return E_NOTIMPL; -} - -static HRESULT WINAPI mfsource_Stop(IMFMediaSource *iface) -{ - mfsource *This = impl_from_IMFMediaSource(iface); - - FIXME("(%p): stub\n", This); - - return E_NOTIMPL; -} - -static HRESULT WINAPI mfsource_Pause(IMFMediaSource *iface) -{ - mfsource *This = impl_from_IMFMediaSource(iface); - - FIXME("(%p): stub\n", This); - - return E_NOTIMPL; -} - -static HRESULT WINAPI mfsource_Shutdown(IMFMediaSource *iface) -{ - mfsource *This = impl_from_IMFMediaSource(iface); - - FIXME("(%p): stub\n", This); - - return S_OK; -} - -static const IMFMediaSourceVtbl mfsourcevtbl = -{ - mfsource_QueryInterface, - mfsource_AddRef, - mfsource_Release, - mfsource_GetEvent, - mfsource_BeginGetEvent, - mfsource_EndGetEvent, - mfsource_QueueEvent, - mfsource_GetCharacteristics, - mfsource_CreatePresentationDescriptor, - mfsource_Start, - mfsource_Stop, - mfsource_Pause, - mfsource_Shutdown, -}; - enum resolved_object_origin { OBJECT_FROM_BYTESTREAM, @@ -6505,7 +6323,7 @@ static HRESULT WINAPI source_resolver_CreateObjectFromByteStream(IMFSourceResolv return E_POINTER;
if (FAILED(hr = resolver_get_bytestream_handler(stream, url, flags, &handler))) - goto fallback; + return MF_E_UNSUPPORTED_BYTESTREAM_TYPE;
hr = RtwqCreateAsyncResult((IUnknown *)handler, NULL, NULL, &result); IMFByteStreamHandler_Release(handler); @@ -6528,28 +6346,7 @@ static HRESULT WINAPI source_resolver_CreateObjectFromByteStream(IMFSourceResolv hr = resolver_end_create_object(resolver, OBJECT_FROM_BYTESTREAM, result, obj_type, object); IRtwqAsyncResult_Release(result);
- /* TODO: following stub is left intentionally until real source plugins are implemented. */ - if (SUCCEEDED(hr)) - return hr; - -fallback: - if (flags & MF_RESOLUTION_MEDIASOURCE) - { - mfsource *new_object; - - new_object = HeapAlloc( GetProcessHeap(), 0, sizeof(*new_object) ); - if (!new_object) - return E_OUTOFMEMORY; - - new_object->IMFMediaSource_iface.lpVtbl = &mfsourcevtbl; - new_object->ref = 1; - - *object = (IUnknown *)&new_object->IMFMediaSource_iface; - *obj_type = MF_OBJECT_MEDIASOURCE; - return S_OK; - } - - return E_NOTIMPL; + return hr; }
static HRESULT WINAPI source_resolver_BeginCreateObjectFromURL(IMFSourceResolver *iface, const WCHAR *url, diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 01749dd9ef8..fa90f1e4bac 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -382,12 +382,16 @@ static HRESULT WINAPI test_create_from_file_handler_callback_Invoke(IMFAsyncCall handler = (IMFSchemeHandler *)IMFAsyncResult_GetStateNoAddRef(result);
hr = IMFSchemeHandler_EndCreateObject(handler, result, &obj_type, &object); +todo_wine ok(hr == S_OK, "Failed to create an object, hr %#x.\n", hr);
- hr = IMFAsyncResult_GetObject(result, &object2); - ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + if (SUCCEEDED(hr)) + { + hr = IMFAsyncResult_GetObject(result, &object2); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
- IUnknown_Release(object); + IUnknown_Release(object); + }
SetEvent(callback->event);
@@ -502,13 +506,43 @@ static void test_source_resolver(void)
hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL, &obj_type, (IUnknown **)&mediasource); - todo_wine ok(hr == MF_E_UNSUPPORTED_BYTESTREAM_TYPE, "got 0x%08x\n", hr); + ok(hr == MF_E_UNSUPPORTED_BYTESTREAM_TYPE, "got 0x%08x\n", hr); if (hr == S_OK) IMFMediaSource_Release(mediasource);
hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, NULL, MF_RESOLUTION_BYTESTREAM, NULL, &obj_type, (IUnknown **)&mediasource); - todo_wine ok(hr == MF_E_UNSUPPORTED_BYTESTREAM_TYPE, "got 0x%08x\n", hr); + ok(hr == MF_E_UNSUPPORTED_BYTESTREAM_TYPE, "got 0x%08x\n", hr); + + IMFByteStream_Release(stream); + + /* Create from URL. */ + callback.event = CreateEventA(NULL, FALSE, FALSE, NULL); + + hr = IMFSourceResolver_CreateObjectFromURL(resolver, L"nonexisting.mp4", MF_RESOLUTION_BYTESTREAM, NULL, &obj_type, + (IUnknown **)&stream); + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "Unexpected hr %#x.\n", hr); + + hr = IMFSourceResolver_CreateObjectFromURL(resolver, filename, MF_RESOLUTION_BYTESTREAM, NULL, &obj_type, + (IUnknown **)&stream); + ok(hr == S_OK, "Failed to resolve url, hr %#x.\n", hr); + IMFByteStream_Release(stream); + + hr = IMFSourceResolver_BeginCreateObjectFromURL(resolver, filename, MF_RESOLUTION_BYTESTREAM, NULL, + &cancel_cookie, &callback.IMFAsyncCallback_iface, (IUnknown *)resolver); + ok(hr == S_OK, "Create request failed, hr %#x.\n", hr); + ok(cancel_cookie != NULL, "Unexpected cancel object.\n"); + IUnknown_Release(cancel_cookie); + + if (SUCCEEDED(hr)) + WaitForSingleObject(callback.event, INFINITE); + + /* With explicit scheme. */ + lstrcpyW(pathW, fileschemeW); + lstrcatW(pathW, filename);
+ hr = IMFSourceResolver_CreateObjectFromURL(resolver, pathW, MF_RESOLUTION_BYTESTREAM, NULL, &obj_type, + (IUnknown **)&stream); + ok(hr == S_OK, "Failed to resolve url, hr %#x.\n", hr); IMFByteStream_Release(stream);
/* We have to create a new bytestream here, because all following @@ -522,14 +556,31 @@ static void test_source_resolver(void) ok(hr == S_OK, "Failed to set string value, hr %#x.\n", hr); IMFAttributes_Release(attributes);
+ /* Start of gstreamer dependent tests */ + hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL, &obj_type, (IUnknown **)&mediasource); - ok(hr == S_OK, "got 0x%08x\n", hr); + if (strcmp(winetest_platform, "wine")) + ok(hr == S_OK, "got 0x%08x\n", hr); + if (FAILED(hr)) + { + IMFByteStream_Release(stream); + IMFSourceResolver_Release(resolver); + + hr = MFShutdown(); + ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr); + + DeleteFileW(filename); + return; + } ok(mediasource != NULL, "got %p\n", mediasource); ok(obj_type == MF_OBJECT_MEDIASOURCE, "got %d\n", obj_type);
hr = IMFMediaSource_CreatePresentationDescriptor(mediasource, &descriptor); +todo_wine ok(hr == S_OK, "Failed to get presentation descriptor, hr %#x.\n", hr); + if (FAILED(hr)) + goto skip_source_tests; ok(descriptor != NULL, "got %p\n", descriptor);
hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor, 0, &selected, &sd); @@ -540,10 +591,7 @@ static void test_source_resolver(void) IMFStreamDescriptor_Release(sd);
hr = IMFMediaTypeHandler_GetMajorType(handler, &guid); -todo_wine ok(hr == S_OK, "Failed to get stream major type, hr %#x.\n", hr); - if (FAILED(hr)) - goto skip_source_tests;
/* Check major/minor type for the test media. */ ok(IsEqualGUID(&guid, &MFMediaType_Video), "Unexpected major type %s.\n", debugstr_guid(&guid)); @@ -624,6 +672,7 @@ todo_wine get_event((IMFMediaEventGenerator *)mediasource, MEEndOfPresentation, NULL);
IMFMediaTypeHandler_Release(handler); + IMFPresentationDescriptor_Release(descriptor);
hr = IMFMediaSource_Shutdown(mediasource); ok(hr == S_OK, "Unexpected hr %#x.\n", hr); @@ -633,42 +682,9 @@ todo_wine
skip_source_tests:
- IMFPresentationDescriptor_Release(descriptor); IMFMediaSource_Release(mediasource); IMFByteStream_Release(stream);
- /* Create from URL. */ - callback.event = CreateEventA(NULL, FALSE, FALSE, NULL); - - hr = IMFSourceResolver_CreateObjectFromURL(resolver, L"nonexisting.mp4", MF_RESOLUTION_BYTESTREAM, NULL, &obj_type, - (IUnknown **)&stream); - ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "Unexpected hr %#x.\n", hr); - - hr = IMFSourceResolver_CreateObjectFromURL(resolver, filename, MF_RESOLUTION_BYTESTREAM, NULL, &obj_type, - (IUnknown **)&stream); - ok(hr == S_OK, "Failed to resolve url, hr %#x.\n", hr); - IMFByteStream_Release(stream); - - hr = IMFSourceResolver_BeginCreateObjectFromURL(resolver, filename, MF_RESOLUTION_BYTESTREAM, NULL, - &cancel_cookie, &callback.IMFAsyncCallback_iface, (IUnknown *)resolver); - ok(hr == S_OK, "Create request failed, hr %#x.\n", hr); - ok(cancel_cookie != NULL, "Unexpected cancel object.\n"); - IUnknown_Release(cancel_cookie); - - if (SUCCEEDED(hr)) - WaitForSingleObject(callback.event, INFINITE); - - /* With explicit scheme. */ - lstrcpyW(pathW, fileschemeW); - lstrcatW(pathW, filename); - - hr = IMFSourceResolver_CreateObjectFromURL(resolver, pathW, MF_RESOLUTION_BYTESTREAM, NULL, &obj_type, - (IUnknown **)&stream); - ok(hr == S_OK, "Failed to resolve url, hr %#x.\n", hr); - IMFByteStream_Release(stream); - - IMFSourceResolver_Release(resolver); - /* Create directly through scheme handler. */ hr = CoInitialize(NULL); ok(SUCCEEDED(hr), "Failed to initialize, hr %#x.\n", hr); @@ -693,12 +709,14 @@ skip_source_tests: if (do_uninit) CoUninitialize();
+ CloseHandle(callback.event); + + IMFSourceResolver_Release(resolver); + hr = MFShutdown(); ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
DeleteFileW(filename); - - CloseHandle(callback.event); }
static void init_functions(void)
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- v4: - Expose generic media source instead of mp4 targetted one. - Defer init_gstreamer to a later patch. - Rename container_stream_handler to winegstreamer_stream_handler. --- dlls/mfplat/main.c | 2 +- dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/gst_private.h | 2 + dlls/winegstreamer/media_source.c | 455 +++++++++++++++++++ dlls/winegstreamer/mfplat.c | 1 + dlls/winegstreamer/winegstreamer.rgs | 20 + dlls/winegstreamer/winegstreamer_classes.idl | 7 + include/mfidl.idl | 1 + 8 files changed, 488 insertions(+), 1 deletion(-) create mode 100644 dlls/winegstreamer/media_source.c
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index ea1b1770e15..6eb755fe954 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -6030,7 +6030,7 @@ static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHA
for (i = 0, hr = E_FAIL; i < ARRAY_SIZE(hkey_roots); ++i) { - const WCHAR *namesW[2] = { mimeW, url_ext }; + const WCHAR *namesW[3] = { mimeW, url_ext, L"wine/all" }; HKEY hkey, hkey_handler;
if (RegOpenKeyA(hkey_roots[i], streamhandlerspath, &hkey)) diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index 337c1086e6b..e578d194f7f 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -10,6 +10,7 @@ C_SRCS = \ gst_cbs.c \ gstdemux.c \ main.c \ + media_source.c \ mediatype.c \ mfplat.c \ pin.c \ diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index e6fb841fc87..ef07d3591e7 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -54,4 +54,6 @@ void start_dispatch_thread(void) DECLSPEC_HIDDEN;
extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) DECLSPEC_HIDDEN;
+HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN; + #endif /* __GST_PRIVATE_INCLUDED__ */ diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c new file mode 100644 index 00000000000..9d051146aef --- /dev/null +++ b/dlls/winegstreamer/media_source.c @@ -0,0 +1,455 @@ +#include "gst_private.h" + +#include <stdarg.h> + +#define COBJMACROS +#define NONAMELESSUNION + +#include "mfapi.h" +#include "mferror.h" +#include "mfidl.h" + +#include "wine/debug.h" +#include "wine/heap.h" +#include "wine/list.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + +struct winegstreamer_stream_handler_result +{ + struct list entry; + IMFAsyncResult *result; + MF_OBJECT_TYPE obj_type; + IUnknown *object; +}; + +struct winegstreamer_stream_handler +{ + IMFByteStreamHandler IMFByteStreamHandler_iface; + IMFAsyncCallback IMFAsyncCallback_iface; + LONG refcount; + struct list results; + CRITICAL_SECTION cs; +}; + +static struct winegstreamer_stream_handler *impl_from_IMFByteStreamHandler(IMFByteStreamHandler *iface) +{ + return CONTAINING_RECORD(iface, struct winegstreamer_stream_handler, IMFByteStreamHandler_iface); +} + +static struct winegstreamer_stream_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct winegstreamer_stream_handler, IMFAsyncCallback_iface); +} + +static HRESULT WINAPI winegstreamer_stream_handler_QueryInterface(IMFByteStreamHandler *iface, REFIID riid, void **obj) +{ + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IMFByteStreamHandler) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFByteStreamHandler_AddRef(iface); + return S_OK; + } + + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI winegstreamer_stream_handler_AddRef(IMFByteStreamHandler *iface) +{ + struct winegstreamer_stream_handler *handler = impl_from_IMFByteStreamHandler(iface); + ULONG refcount = InterlockedIncrement(&handler->refcount); + + TRACE("%p, refcount %u.\n", handler, refcount); + + return refcount; +} + +static ULONG WINAPI winegstreamer_stream_handler_Release(IMFByteStreamHandler *iface) +{ + struct winegstreamer_stream_handler *handler = impl_from_IMFByteStreamHandler(iface); + ULONG refcount = InterlockedDecrement(&handler->refcount); + struct winegstreamer_stream_handler_result *result, *next; + + TRACE("%p, refcount %u.\n", iface, refcount); + + if (!refcount) + { + LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct winegstreamer_stream_handler_result, entry) + { + list_remove(&result->entry); + IMFAsyncResult_Release(result->result); + if (result->object) + IUnknown_Release(result->object); + heap_free(result); + } + DeleteCriticalSection(&handler->cs); + heap_free(handler); + } + + return refcount; +} + +struct create_object_context +{ + IUnknown IUnknown_iface; + LONG refcount; + + IPropertyStore *props; + IMFByteStream *stream; + WCHAR *url; + DWORD flags; +}; + +static struct create_object_context *impl_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct create_object_context, IUnknown_iface); +} + +static HRESULT WINAPI create_object_context_QueryInterface(IUnknown *iface, REFIID riid, void **obj) +{ + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IUnknown_AddRef(iface); + return S_OK; + } + + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI create_object_context_AddRef(IUnknown *iface) +{ + struct create_object_context *context = impl_from_IUnknown(iface); + ULONG refcount = InterlockedIncrement(&context->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI create_object_context_Release(IUnknown *iface) +{ + struct create_object_context *context = impl_from_IUnknown(iface); + ULONG refcount = InterlockedDecrement(&context->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + if (!refcount) + { + if (context->props) + IPropertyStore_Release(context->props); + if (context->stream) + IMFByteStream_Release(context->stream); + if (context->url) + heap_free(context->url); + heap_free(context); + } + + return refcount; +} + +static const IUnknownVtbl create_object_context_vtbl = +{ + create_object_context_QueryInterface, + create_object_context_AddRef, + create_object_context_Release, +}; + +static WCHAR *heap_strdupW(const WCHAR *str) +{ + WCHAR *ret = NULL; + + if (str) + { + unsigned int size; + + size = (lstrlenW(str) + 1) * sizeof(WCHAR); + ret = heap_alloc(size); + if (ret) + memcpy(ret, str, size); + } + + return ret; +} + +static HRESULT WINAPI winegstreamer_stream_handler_BeginCreateObject(IMFByteStreamHandler *iface, IMFByteStream *stream, const WCHAR *url, DWORD flags, + IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state) +{ + struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface); + struct create_object_context *context; + IMFAsyncResult *caller, *item; + HRESULT hr; + + TRACE("%p, %s, %#x, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state); + + if (cancel_cookie) + *cancel_cookie = NULL; + + if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &caller))) + return hr; + + context = heap_alloc(sizeof(*context)); + if (!context) + { + IMFAsyncResult_Release(caller); + return E_OUTOFMEMORY; + } + + context->IUnknown_iface.lpVtbl = &create_object_context_vtbl; + context->refcount = 1; + context->props = props; + if (context->props) + IPropertyStore_AddRef(context->props); + context->flags = flags; + context->stream = stream; + if (context->stream) + IMFByteStream_AddRef(context->stream); + if (url) + context->url = heap_strdupW(url); + if (!context->stream) + { + IMFAsyncResult_Release(caller); + IUnknown_Release(&context->IUnknown_iface); + return E_OUTOFMEMORY; + } + + hr = MFCreateAsyncResult(&context->IUnknown_iface, &this->IMFAsyncCallback_iface, (IUnknown *)caller, &item); + IUnknown_Release(&context->IUnknown_iface); + if (SUCCEEDED(hr)) + { + if (SUCCEEDED(hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO, item))) + { + if (cancel_cookie) + { + *cancel_cookie = (IUnknown *)caller; + IUnknown_AddRef(*cancel_cookie); + } + } + + IMFAsyncResult_Release(item); + } + IMFAsyncResult_Release(caller); + + return hr; +} + +static HRESULT WINAPI winegstreamer_stream_handler_EndCreateObject(IMFByteStreamHandler *iface, IMFAsyncResult *result, + MF_OBJECT_TYPE *obj_type, IUnknown **object) +{ + struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface); + struct winegstreamer_stream_handler_result *found = NULL, *cur; + HRESULT hr; + + TRACE("%p, %p, %p, %p.\n", iface, result, obj_type, object); + + EnterCriticalSection(&this->cs); + + LIST_FOR_EACH_ENTRY(cur, &this->results, struct winegstreamer_stream_handler_result, entry) + { + if (result == cur->result) + { + list_remove(&cur->entry); + found = cur; + break; + } + } + + LeaveCriticalSection(&this->cs); + + if (found) + { + *obj_type = found->obj_type; + *object = found->object; + hr = IMFAsyncResult_GetStatus(found->result); + IMFAsyncResult_Release(found->result); + heap_free(found); + } + else + { + *obj_type = MF_OBJECT_INVALID; + *object = NULL; + hr = MF_E_UNEXPECTED; + } + + return hr; +} + +static HRESULT WINAPI winegstreamer_stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cancel_cookie) +{ + struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface); + struct winegstreamer_stream_handler_result *found = NULL, *cur; + + TRACE("%p, %p.\n", iface, cancel_cookie); + + EnterCriticalSection(&this->cs); + + LIST_FOR_EACH_ENTRY(cur, &this->results, struct winegstreamer_stream_handler_result, entry) + { + if (cancel_cookie == (IUnknown *)cur->result) + { + list_remove(&cur->entry); + found = cur; + break; + } + } + + LeaveCriticalSection(&this->cs); + + if (found) + { + IMFAsyncResult_Release(found->result); + if (found->object) + IUnknown_Release(found->object); + heap_free(found); + } + + return found ? S_OK : MF_E_UNEXPECTED; +} + +static HRESULT WINAPI winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler *iface, QWORD *bytes) +{ + FIXME("stub (%p %p)\n", iface, bytes); + return E_NOTIMPL; +} + +static const IMFByteStreamHandlerVtbl winegstreamer_stream_handler_vtbl = +{ + winegstreamer_stream_handler_QueryInterface, + winegstreamer_stream_handler_AddRef, + winegstreamer_stream_handler_Release, + winegstreamer_stream_handler_BeginCreateObject, + winegstreamer_stream_handler_EndCreateObject, + winegstreamer_stream_handler_CancelObjectCreation, + winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution, +}; + +static HRESULT WINAPI winegstreamer_stream_handler_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IMFAsyncCallback) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFAsyncCallback_AddRef(iface); + return S_OK; + } + + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI winegstreamer_stream_handler_callback_AddRef(IMFAsyncCallback *iface) +{ + struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface); + return IMFByteStreamHandler_AddRef(&handler->IMFByteStreamHandler_iface); +} + +static ULONG WINAPI winegstreamer_stream_handler_callback_Release(IMFAsyncCallback *iface) +{ + struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface); + return IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface); +} + +static HRESULT WINAPI winegstreamer_stream_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) +{ + return E_NOTIMPL; +} + +static HRESULT winegstreamer_stream_handler_create_object(struct winegstreamer_stream_handler *This, WCHAR *url, IMFByteStream *stream, DWORD flags, + IPropertyStore *props, IUnknown **out_object, MF_OBJECT_TYPE *out_obj_type) +{ + FIXME("(%p %s %p %u %p %p %p)\n", This, debugstr_w(url), stream, flags, props, out_object, out_obj_type); + + return E_NOTIMPL; +} + +static HRESULT WINAPI winegstreamer_stream_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface); + struct winegstreamer_stream_handler_result *handler_result; + MF_OBJECT_TYPE obj_type = MF_OBJECT_INVALID; + IUnknown *object = NULL, *context_object; + struct create_object_context *context; + IMFAsyncResult *caller; + 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_stream_handler_create_object(handler, context->url, context->stream, context->flags, context->props, &object, &obj_type); + + handler_result = heap_alloc(sizeof(*handler_result)); + if (handler_result) + { + handler_result->result = caller; + IMFAsyncResult_AddRef(handler_result->result); + handler_result->obj_type = obj_type; + 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; + } + + IUnknown_Release(&context->IUnknown_iface); + + IMFAsyncResult_SetStatus(caller, hr); + MFInvokeCallback(caller); + + return S_OK; +} + +static const IMFAsyncCallbackVtbl winegstreamer_stream_handler_callback_vtbl = +{ + winegstreamer_stream_handler_callback_QueryInterface, + winegstreamer_stream_handler_callback_AddRef, + winegstreamer_stream_handler_callback_Release, + winegstreamer_stream_handler_callback_GetParameters, + winegstreamer_stream_handler_callback_Invoke, +}; + +HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) +{ + struct winegstreamer_stream_handler *this; + HRESULT hr; + + TRACE("%s, %p.\n", debugstr_guid(riid), obj); + + this = heap_alloc_zero(sizeof(*this)); + if (!this) + return E_OUTOFMEMORY; + + list_init(&this->results); + InitializeCriticalSection(&this->cs); + + this->IMFByteStreamHandler_iface.lpVtbl = &winegstreamer_stream_handler_vtbl; + this->IMFAsyncCallback_iface.lpVtbl = &winegstreamer_stream_handler_callback_vtbl; + this->refcount = 1; + + hr = IMFByteStreamHandler_QueryInterface(&this->IMFByteStreamHandler_iface, riid, obj); + IMFByteStreamHandler_Release(&this->IMFByteStreamHandler_iface); + + return hr; +} diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 55b9b088765..0a0f4b68013 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -406,6 +406,7 @@ static const struct class_object class_objects[] = { { &CLSID_VideoProcessorMFT, &video_processor_create }, + { &CLSID_GStreamerByteStreamHandler, &winegstreamer_stream_handler_create }, };
HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) diff --git a/dlls/winegstreamer/winegstreamer.rgs b/dlls/winegstreamer/winegstreamer.rgs index 923ba673f8c..4b902e1cf5a 100644 --- a/dlls/winegstreamer/winegstreamer.rgs +++ b/dlls/winegstreamer/winegstreamer.rgs @@ -12,3 +12,23 @@ HKCR } } } + +HKLM +{ + NoRemove 'Software' + { + NoRemove 'Microsoft' + { + NoRemove 'Windows Media Foundation' + { + NoRemove 'ByteStreamHandlers' + { + 'wine/all' + { + val '{317DF618-5E5A-468A-9F15-D827A9A08162}' = s 'Gstreamer Byte Stream Handler' + } + } + } + } + } +} diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl index fa0e1784057..1dc4ba9a10b 100644 --- a/dlls/winegstreamer/winegstreamer_classes.idl +++ b/dlls/winegstreamer/winegstreamer_classes.idl @@ -54,3 +54,10 @@ coclass Gstreamer_Splitter {} uuid(88753b26-5b24-49bd-b2e7-0c445c78c982) ] coclass VideoProcessorMFT {} + +[ + helpstring("Generic Decodebin Byte Stream Handler"), + threading(both), + uuid(317df618-5e5a-468a-9f15-d827a9a08162) +] +coclass GStreamerByteStreamHandler {} diff --git a/include/mfidl.idl b/include/mfidl.idl index 4ceeb707bd0..2273e84fb70 100644 --- a/include/mfidl.idl +++ b/include/mfidl.idl @@ -1241,3 +1241,4 @@ cpp_quote("EXTERN_GUID(MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_ACTIVATE, 0xba491365, cpp_quote("EXTERN_GUID(MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_FLAGS, 0xba491366, 0xbe50, 0x451e, 0x95, 0xab, 0x6d, 0x4a, 0xcc, 0xc7, 0xda, 0xd8);")
cpp_quote("EXTERN_GUID(CLSID_VideoProcessorMFT, 0x88753b26, 0x5b24, 0x49bd, 0xb2, 0xe7, 0xc, 0x44, 0x5c, 0x78, 0xc9, 0x82);") +cpp_quote("EXTERN_GUID(CLSID_GStreamerByteStreamHandler, 0x317df618, 0x5e5a, 0x468a, 0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62);")
On 8/28/20 11:48 PM, Derek Lesho wrote:
@@ -6030,7 +6030,7 @@ static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHA
for (i = 0, hr = E_FAIL; i < ARRAY_SIZE(hkey_roots); ++i) {
const WCHAR *namesW[2] = { mimeW, url_ext };
const WCHAR *namesW[3] = { mimeW, url_ext, L"wine/all" }; HKEY hkey, hkey_handler; if (RegOpenKeyA(hkey_roots[i], streamhandlerspath, &hkey))
Is it a way to avoid registering specific types/extensions? Could you explain why this is better than regular registration.
On 9/1/20 2:29 AM, Nikolay Sivov wrote:
On 8/28/20 11:48 PM, Derek Lesho wrote:
@@ -6030,7 +6030,7 @@ static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHA
for (i = 0, hr = E_FAIL; i < ARRAY_SIZE(hkey_roots); ++i) {
const WCHAR *namesW[2] = { mimeW, url_ext };
const WCHAR *namesW[3] = { mimeW, url_ext, L"wine/all" }; HKEY hkey, hkey_handler; if (RegOpenKeyA(hkey_roots[i], streamhandlerspath, &hkey))
Is it a way to avoid registering specific types/extensions? Could you explain why this is better than regular registration.
Yes, this is a way to avoid registering specific types. This was zebediah's suggestion, and his reasoning was:
Even if some application creates CLSID_MPEG4ByteStreamHandler manually, and we need to hook up this decoder thereto, I think it makes more sense for the original patch to create it under a generic name (maybe CLSID_GStreamerByteStreamHandler) and custom CLSID. Then, in another patch, we can hook up CLSID_MPEG4ByteStreamHandler to the same object.
Media Foundation doesn't make it as easy as DirectShow to plug in a generic catch-all handler, i.e. we can't just set some registry keys and have done, but regardless I think it's something we want to do, even if that means making the modification in mfreadwrite instead.
On 9/1/20 4:54 PM, Derek Lesho wrote:
On 9/1/20 2:29 AM, Nikolay Sivov wrote:
On 8/28/20 11:48 PM, Derek Lesho wrote:
@@ -6030,7 +6030,7 @@ static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHA for (i = 0, hr = E_FAIL; i < ARRAY_SIZE(hkey_roots); ++i) { - const WCHAR *namesW[2] = { mimeW, url_ext }; + const WCHAR *namesW[3] = { mimeW, url_ext, L"wine/all" }; HKEY hkey, hkey_handler; if (RegOpenKeyA(hkey_roots[i], streamhandlerspath, &hkey))
Is it a way to avoid registering specific types/extensions? Could you explain why this is better than regular registration.
Yes, this is a way to avoid registering specific types. This was zebediah's suggestion, and his reasoning was:
Even if some application creates CLSID_MPEG4ByteStreamHandler manually, and we need to hook up this decoder thereto, I think it makes more sense for the original patch to create it under a generic name (maybe CLSID_GStreamerByteStreamHandler) and custom CLSID. Then, in another patch, we can hook up CLSID_MPEG4ByteStreamHandler to the same object.
Media Foundation doesn't make it as easy as DirectShow to plug in a generic catch-all handler, i.e. we can't just set some registry keys and have done, but regardless I think it's something we want to do, even if that means making the modification in mfreadwrite instead.
I don't know, I don't see a problem in registering whole list of mime types/extensions, which then could be tweaked. Is it the size of this list that makes this undesirable? In practice it will grow to maybe 20 entries I think.
P.S. mfreadwrite was mentioned, should that be mfplat.dll or does mfreadwrite need special handling for some reason?
On 9/1/20 9:13 AM, Nikolay Sivov wrote:
On 9/1/20 4:54 PM, Derek Lesho wrote:
On 9/1/20 2:29 AM, Nikolay Sivov wrote:
On 8/28/20 11:48 PM, Derek Lesho wrote:
@@ -6030,7 +6030,7 @@ static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHA for (i = 0, hr = E_FAIL; i < ARRAY_SIZE(hkey_roots); ++i) { - const WCHAR *namesW[2] = { mimeW, url_ext }; + const WCHAR *namesW[3] = { mimeW, url_ext, L"wine/all" }; HKEY hkey, hkey_handler; if (RegOpenKeyA(hkey_roots[i], streamhandlerspath, &hkey))
Is it a way to avoid registering specific types/extensions? Could you explain why this is better than regular registration.
Yes, this is a way to avoid registering specific types. This was zebediah's suggestion, and his reasoning was:
Even if some application creates CLSID_MPEG4ByteStreamHandler manually, and we need to hook up this decoder thereto, I think it makes more sense for the original patch to create it under a generic name (maybe CLSID_GStreamerByteStreamHandler) and custom CLSID. Then, in another patch, we can hook up CLSID_MPEG4ByteStreamHandler to the same object.
Media Foundation doesn't make it as easy as DirectShow to plug in a generic catch-all handler, i.e. we can't just set some registry keys and have done, but regardless I think it's something we want to do, even if that means making the modification in mfreadwrite instead.
I don't know, I don't see a problem in registering whole list of mime types/extensions, which then could be tweaked. Is it the size of this list that makes this undesirable? In practice it will grow to maybe 20 entries I think.
I agree with you, although it would probably grow to be longer than that, as I think Zebediah wants us to support media types not supported on windows:
The point of doing this is mainly for generic media players (which, as bug reports will tell you, are used quite frequently with Wine, for one reason or another). It also has the benefit of obviating most of the registry entries (like the ones below) and CLSID mappings that we'd otherwise have to add.
P.S. mfreadwrite was mentioned, should that be mfplat.dll or does mfreadwrite need special handling for some reason?
I think Zebediah was just mistaken here.
On 9/1/20 9:13 AM, Nikolay Sivov wrote:
On 9/1/20 4:54 PM, Derek Lesho wrote:
On 9/1/20 2:29 AM, Nikolay Sivov wrote:
On 8/28/20 11:48 PM, Derek Lesho wrote:
@@ -6030,7 +6030,7 @@ static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHA for (i = 0, hr = E_FAIL; i < ARRAY_SIZE(hkey_roots); ++i) { - const WCHAR *namesW[2] = { mimeW, url_ext }; + const WCHAR *namesW[3] = { mimeW, url_ext, L"wine/all" }; HKEY hkey, hkey_handler; if (RegOpenKeyA(hkey_roots[i], streamhandlerspath, &hkey))
Is it a way to avoid registering specific types/extensions? Could you explain why this is better than regular registration.
Yes, this is a way to avoid registering specific types. This was zebediah's suggestion, and his reasoning was:
Even if some application creates CLSID_MPEG4ByteStreamHandler manually, and we need to hook up this decoder thereto, I think it makes more sense for the original patch to create it under a generic name (maybe CLSID_GStreamerByteStreamHandler) and custom CLSID. Then, in another patch, we can hook up CLSID_MPEG4ByteStreamHandler to the same object.
Media Foundation doesn't make it as easy as DirectShow to plug in a generic catch-all handler, i.e. we can't just set some registry keys and have done, but regardless I think it's something we want to do, even if that means making the modification in mfreadwrite instead.
I don't know, I don't see a problem in registering whole list of mime types/extensions, which then could be tweaked. Is it the size of this list that makes this undesirable? In practice it will grow to maybe 20 entries I think.
The suggestion was based on the quartz model, which I think in hindsight works quite well.
Granted, we could certainly try to anticipate every host format and add registry entries for those, or even pick a few common ones and hang the rest, but I don't see why we should, when we can just as easily throw everything into one bucket. It makes our entire job that much easier.
We can also just completely ignore host integration, but I really think that's not a good idea.
P.S. mfreadwrite was mentioned, should that be mfplat.dll or does mfreadwrite need special handling for some reason?
mfreadwrite has some handling for MIME type detection; I only skimmed the code so I don't know if it's what's relevant here.
On 9/1/20 5:58 PM, Zebediah Figura wrote:
On 9/1/20 9:13 AM, Nikolay Sivov wrote:
On 9/1/20 4:54 PM, Derek Lesho wrote:
On 9/1/20 2:29 AM, Nikolay Sivov wrote:
On 8/28/20 11:48 PM, Derek Lesho wrote:
@@ -6030,7 +6030,7 @@ static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHA for (i = 0, hr = E_FAIL; i < ARRAY_SIZE(hkey_roots); ++i) { - const WCHAR *namesW[2] = { mimeW, url_ext }; + const WCHAR *namesW[3] = { mimeW, url_ext, L"wine/all" }; HKEY hkey, hkey_handler; if (RegOpenKeyA(hkey_roots[i], streamhandlerspath, &hkey))
Is it a way to avoid registering specific types/extensions? Could you explain why this is better than regular registration.
Yes, this is a way to avoid registering specific types. This was zebediah's suggestion, and his reasoning was:
Even if some application creates CLSID_MPEG4ByteStreamHandler manually, and we need to hook up this decoder thereto, I think it makes more sense for the original patch to create it under a generic name (maybe CLSID_GStreamerByteStreamHandler) and custom CLSID. Then, in another patch, we can hook up CLSID_MPEG4ByteStreamHandler to the same object.
Media Foundation doesn't make it as easy as DirectShow to plug in a generic catch-all handler, i.e. we can't just set some registry keys and have done, but regardless I think it's something we want to do, even if that means making the modification in mfreadwrite instead.
I don't know, I don't see a problem in registering whole list of mime types/extensions, which then could be tweaked. Is it the size of this list that makes this undesirable? In practice it will grow to maybe 20 entries I think.
The suggestion was based on the quartz model, which I think in hindsight works quite well.
Granted, we could certainly try to anticipate every host format and add registry entries for those, or even pick a few common ones and hang the rest, but I don't see why we should, when we can just as easily throw everything into one bucket. It makes our entire job that much easier.
We can also just completely ignore host integration, but I really think that's not a good idea.
Can we hardcode CLSID as a fallback equivalent of wine/all? Or is it not flexible enough.
P.S. mfreadwrite was mentioned, should that be mfplat.dll or does mfreadwrite need special handling for some reason?
mfreadwrite has some handling for MIME type detection; I only skimmed the code so I don't know if it's what's relevant here.
I don't think it's relevant, it will try to through format magics, but resolver is free to ignore that hint. That part does not have to change.
On 9/2/20 5:02 AM, Nikolay Sivov wrote:
Can we hardcode CLSID as a fallback equivalent of wine/all? Or is it not flexible enough.
I assume you mean falling back to the generic handler if get_bytestream_handler fails, instead of using wine/all? Yeah, we can certainly do that, shall I send v5 w/ that in place along with the other comments addressed?
On 9/2/20 5:10 PM, Derek Lesho wrote:
On 9/2/20 5:02 AM, Nikolay Sivov wrote:
Can we hardcode CLSID as a fallback equivalent of wine/all? Or is it not flexible enough.
I assume you mean falling back to the generic handler if get_bytestream_handler fails, instead of using wine/all? Yeah, we can certainly do that, shall I send v5 w/ that in place along with the other comments addressed?
I'd like to wait on Zeb's opinion on that. If that's worse for whatever reason, let's go with proposed generic mime string.
On 9/2/20 5:02 AM, Nikolay Sivov wrote:
On 9/1/20 5:58 PM, Zebediah Figura wrote:
On 9/1/20 9:13 AM, Nikolay Sivov wrote:
On 9/1/20 4:54 PM, Derek Lesho wrote:
On 9/1/20 2:29 AM, Nikolay Sivov wrote:
On 8/28/20 11:48 PM, Derek Lesho wrote:
@@ -6030,7 +6030,7 @@ static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHA for (i = 0, hr = E_FAIL; i < ARRAY_SIZE(hkey_roots); ++i) { - const WCHAR *namesW[2] = { mimeW, url_ext }; + const WCHAR *namesW[3] = { mimeW, url_ext, L"wine/all" }; HKEY hkey, hkey_handler; if (RegOpenKeyA(hkey_roots[i], streamhandlerspath, &hkey))
Is it a way to avoid registering specific types/extensions? Could you explain why this is better than regular registration.
Yes, this is a way to avoid registering specific types. This was zebediah's suggestion, and his reasoning was:
Even if some application creates CLSID_MPEG4ByteStreamHandler manually, and we need to hook up this decoder thereto, I think it makes more sense for the original patch to create it under a generic name (maybe CLSID_GStreamerByteStreamHandler) and custom CLSID. Then, in another patch, we can hook up CLSID_MPEG4ByteStreamHandler to the same object.
Media Foundation doesn't make it as easy as DirectShow to plug in a generic catch-all handler, i.e. we can't just set some registry keys and have done, but regardless I think it's something we want to do, even if that means making the modification in mfreadwrite instead.
I don't know, I don't see a problem in registering whole list of mime types/extensions, which then could be tweaked. Is it the size of this list that makes this undesirable? In practice it will grow to maybe 20 entries I think.
The suggestion was based on the quartz model, which I think in hindsight works quite well.
Granted, we could certainly try to anticipate every host format and add registry entries for those, or even pick a few common ones and hang the rest, but I don't see why we should, when we can just as easily throw everything into one bucket. It makes our entire job that much easier.
We can also just completely ignore host integration, but I really think that's not a good idea.
Can we hardcode CLSID as a fallback equivalent of wine/all? Or is it not flexible enough.
The thing that potentially bothers me about that is that we might want to leave room for another backend besides GStreamer (in particular, whatever the replacement for QT is.) But it'd also be easy enough to code in two fallback CLSIDs instead of one.
P.S. mfreadwrite was mentioned, should that be mfplat.dll or does mfreadwrite need special handling for some reason?
mfreadwrite has some handling for MIME type detection; I only skimmed the code so I don't know if it's what's relevant here.
I don't think it's relevant, it will try to through format magics, but resolver is free to ignore that hint. That part does not have to change.
On 8/28/20 11:48 PM, Derek Lesho wrote:
@@ -1241,3 +1241,4 @@ cpp_quote("EXTERN_GUID(MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_ACTIVATE, 0xba491365, cpp_quote("EXTERN_GUID(MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_FLAGS, 0xba491366, 0xbe50, 0x451e, 0x95, 0xab, 0x6d, 0x4a, 0xcc, 0xc7, 0xda, 0xd8);")
cpp_quote("EXTERN_GUID(CLSID_VideoProcessorMFT, 0x88753b26, 0x5b24, 0x49bd, 0xb2, 0xe7, 0xc, 0x44, 0x5c, 0x78, 0xc9, 0x82);") +cpp_quote("EXTERN_GUID(CLSID_GStreamerByteStreamHandler, 0x317df618, 0x5e5a, 0x468a, 0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62);")
This one obviously does not belong to public headers. Why does it have to be exported like that at all?
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/mfplat/tests/mfplat.c | 1 - dlls/winegstreamer/media_source.c | 197 +++++++++++++++++++++++++++++- 2 files changed, 195 insertions(+), 3 deletions(-)
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index fa90f1e4bac..94fdf9e6f39 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -382,7 +382,6 @@ static HRESULT WINAPI test_create_from_file_handler_callback_Invoke(IMFAsyncCall handler = (IMFSchemeHandler *)IMFAsyncResult_GetStateNoAddRef(result);
hr = IMFSchemeHandler_EndCreateObject(handler, result, &obj_type, &object); -todo_wine ok(hr == S_OK, "Failed to create an object, hr %#x.\n", hr);
if (SUCCEEDED(hr)) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 9d051146aef..c8f21cd6143 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -15,6 +15,180 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+struct media_source +{ + IMFMediaSource IMFMediaSource_iface; + LONG ref; +}; + +static inline struct media_source *impl_from_IMFMediaSource(IMFMediaSource *iface) +{ + return CONTAINING_RECORD(iface, struct media_source, IMFMediaSource_iface); +} + +static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out) +{ + struct media_source *source = impl_from_IMFMediaSource(iface); + + TRACE("(%p)->(%s %p)\n", source, debugstr_guid(riid), out); + + if (IsEqualIID(riid, &IID_IMFMediaSource) || + IsEqualIID(riid, &IID_IMFMediaEventGenerator) || + IsEqualIID(riid, &IID_IUnknown)) + { + *out = &source->IMFMediaSource_iface; + } + else + { + FIXME("(%s, %p)\n", debugstr_guid(riid), out); + *out = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*out); + return S_OK; +} + +static ULONG WINAPI media_source_AddRef(IMFMediaSource *iface) +{ + struct media_source *source = impl_from_IMFMediaSource(iface); + ULONG ref = InterlockedIncrement(&source->ref); + + TRACE("(%p) ref=%u\n", source, ref); + + return ref; +} + +static ULONG WINAPI media_source_Release(IMFMediaSource *iface) +{ + struct media_source *source = impl_from_IMFMediaSource(iface); + ULONG ref = InterlockedDecrement(&source->ref); + + TRACE("(%p) ref=%u\n", source, ref); + + if (!ref) + { + heap_free(source); + } + + return ref; +} + +static HRESULT WINAPI media_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event) +{ + FIXME("(%p)->(%#x, %p)\n", iface, flags, event); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state) +{ + FIXME("(%p)->(%p, %p)\n", iface, callback, state); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event) +{ + FIXME("(%p)->(%p, %p)\n", iface, result, event); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type, + HRESULT hr, const PROPVARIANT *value) +{ + FIXME("(%p)->(%d, %s, %#x, %p)\n", iface, event_type, debugstr_guid(ext_type), hr, value); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWORD *characteristics) +{ + struct media_source *source = impl_from_IMFMediaSource(iface); + + FIXME("(%p)->(%p): stub\n", source, characteristics); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor) +{ + struct media_source *source = impl_from_IMFMediaSource(iface); + + FIXME("(%p)->(%p): stub\n", source, descriptor); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor, + const GUID *time_format, const PROPVARIANT *start_position) +{ + struct media_source *source = impl_from_IMFMediaSource(iface); + + FIXME("(%p)->(%p, %p, %p): stub\n", source, descriptor, time_format, start_position); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface) +{ + struct media_source *source = impl_from_IMFMediaSource(iface); + + FIXME("(%p): stub\n", source); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface) +{ + struct media_source *source = impl_from_IMFMediaSource(iface); + + FIXME("(%p): stub\n", source); + + return E_NOTIMPL; +} + +static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) +{ + struct media_source *source = impl_from_IMFMediaSource(iface); + + FIXME("(%p): stub\n", source); + + return E_NOTIMPL; +} + +static const IMFMediaSourceVtbl IMFMediaSource_vtbl = +{ + media_source_QueryInterface, + media_source_AddRef, + media_source_Release, + media_source_GetEvent, + media_source_BeginGetEvent, + media_source_EndGetEvent, + media_source_QueueEvent, + media_source_GetCharacteristics, + media_source_CreatePresentationDescriptor, + media_source_Start, + media_source_Stop, + media_source_Pause, + media_source_Shutdown, +}; + +static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_source **out_media_source) +{ + struct media_source *object = heap_alloc_zero(sizeof(*object)); + + if (!object) + return E_OUTOFMEMORY; + + object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl; + object->ref = 1; + + *out_media_source = object; + return S_OK; +} + struct winegstreamer_stream_handler_result { struct list entry; @@ -367,9 +541,28 @@ static HRESULT WINAPI winegstreamer_stream_handler_callback_GetParameters(IMFAsy static HRESULT winegstreamer_stream_handler_create_object(struct winegstreamer_stream_handler *This, WCHAR *url, IMFByteStream *stream, DWORD flags, IPropertyStore *props, IUnknown **out_object, MF_OBJECT_TYPE *out_obj_type) { - FIXME("(%p %s %p %u %p %p %p)\n", This, debugstr_w(url), stream, flags, props, out_object, out_obj_type); + TRACE("(%p %s %p %u %p %p %p)\n", This, debugstr_w(url), stream, flags, props, out_object, out_obj_type);
- return E_NOTIMPL; + if (flags & MF_RESOLUTION_MEDIASOURCE) + { + HRESULT hr; + struct media_source *new_source; + + if (FAILED(hr = media_source_constructor(stream, &new_source))) + return hr; + + TRACE("->(%p)\n", new_source); + + *out_object = (IUnknown*)&new_source->IMFMediaSource_iface; + *out_obj_type = MF_OBJECT_MEDIASOURCE; + + return S_OK; + } + else + { + FIXME("flags = %08x\n", flags); + return E_NOTIMPL; + } }
static HRESULT WINAPI winegstreamer_stream_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/winegstreamer/media_source.c | 37 ++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 8 deletions(-)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index c8f21cd6143..7fd5e6a4d77 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -19,6 +19,7 @@ struct media_source { IMFMediaSource IMFMediaSource_iface; LONG ref; + IMFMediaEventQueue *event_queue; };
static inline struct media_source *impl_from_IMFMediaSource(IMFMediaSource *iface) @@ -76,31 +77,39 @@ static ULONG WINAPI media_source_Release(IMFMediaSource *iface)
static HRESULT WINAPI media_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event) { - FIXME("(%p)->(%#x, %p)\n", iface, flags, event); + struct media_source *source = impl_from_IMFMediaSource(iface);
- return E_NOTIMPL; + TRACE("(%p)->(%#x, %p)\n", source, flags, event); + + return IMFMediaEventQueue_GetEvent(source->event_queue, flags, event); }
static HRESULT WINAPI media_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state) { - FIXME("(%p)->(%p, %p)\n", iface, callback, state); + struct media_source *source = impl_from_IMFMediaSource(iface);
- return E_NOTIMPL; + TRACE("(%p)->(%p, %p)\n", source, callback, state); + + return IMFMediaEventQueue_BeginGetEvent(source->event_queue, callback, state); }
static HRESULT WINAPI media_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event) { - FIXME("(%p)->(%p, %p)\n", iface, result, event); + struct media_source *source = impl_from_IMFMediaSource(iface);
- return E_NOTIMPL; + TRACE("(%p)->(%p, %p)\n", source, result, event); + + return IMFMediaEventQueue_EndGetEvent(source->event_queue, result, event); }
static HRESULT WINAPI media_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type, HRESULT hr, const PROPVARIANT *value) { - FIXME("(%p)->(%d, %s, %#x, %p)\n", iface, event_type, debugstr_guid(ext_type), hr, value); + struct media_source *source = impl_from_IMFMediaSource(iface);
- return E_NOTIMPL; + TRACE("(%p)->(%d, %s, %#x, %p)\n", source, event_type, debugstr_guid(ext_type), hr, value); + + return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, ext_type, hr, value); }
static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWORD *characteristics) @@ -178,15 +187,27 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl = static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_source **out_media_source) { struct media_source *object = heap_alloc_zero(sizeof(*object)); + HRESULT hr;
if (!object) return E_OUTOFMEMORY;
+ if (FAILED(hr = MFCreateEventQueue(&object->event_queue))) + goto fail; + object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl; object->ref = 1;
*out_media_source = object; return S_OK; + + fail: + WARN("Failed to construct MFMediaSource, hr %#x.\n", hr); + + if (object->event_queue) + IMFMediaEventQueue_Release(object->event_queue); + heap_free(object); + return hr; }
struct winegstreamer_stream_handler_result
On 8/28/20 11:48 PM, Derek Lesho wrote:
@@ -178,15 +187,27 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl = static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_source **out_media_source) { struct media_source *object = heap_alloc_zero(sizeof(*object));
HRESULT hr;
if (!object) return E_OUTOFMEMORY;
if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
goto fail;
object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl; object->ref = 1;
*out_media_source = object; return S_OK;
fail:
WARN("Failed to construct MFMediaSource, hr %#x.\n", hr);
if (object->event_queue)
IMFMediaEventQueue_Release(object->event_queue);
heap_free(object);
return hr;
}
Might be easier to do a regular Release() on failure.
On source release you should release the queue, and probably shutdown too just in case.
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/mfplat/tests/mfplat.c | 4 +-- dlls/winegstreamer/media_source.c | 51 ++++++++++++++++++++++++++++--- 2 files changed, 49 insertions(+), 6 deletions(-)
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 94fdf9e6f39..309f7b669a4 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -673,14 +673,14 @@ todo_wine IMFMediaTypeHandler_Release(handler); IMFPresentationDescriptor_Release(descriptor);
+skip_source_tests: + hr = IMFMediaSource_Shutdown(mediasource); ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = IMFMediaSource_CreatePresentationDescriptor(mediasource, NULL); ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#x.\n", hr);
-skip_source_tests: - IMFMediaSource_Release(mediasource); IMFByteStream_Release(stream);
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 7fd5e6a4d77..da0a1be22b6 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -20,6 +20,12 @@ struct media_source IMFMediaSource IMFMediaSource_iface; LONG ref; IMFMediaEventQueue *event_queue; + enum + { + SOURCE_OPENING, + SOURCE_STOPPED, + SOURCE_SHUTDOWN, + } state; };
static inline struct media_source *impl_from_IMFMediaSource(IMFMediaSource *iface) @@ -81,6 +87,9 @@ static HRESULT WINAPI media_source_GetEvent(IMFMediaSource *iface, DWORD flags,
TRACE("(%p)->(%#x, %p)\n", source, flags, event);
+ if (source->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + return IMFMediaEventQueue_GetEvent(source->event_queue, flags, event); }
@@ -90,6 +99,9 @@ static HRESULT WINAPI media_source_BeginGetEvent(IMFMediaSource *iface, IMFAsync
TRACE("(%p)->(%p, %p)\n", source, callback, state);
+ if (source->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + return IMFMediaEventQueue_BeginGetEvent(source->event_queue, callback, state); }
@@ -99,6 +111,9 @@ static HRESULT WINAPI media_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncRe
TRACE("(%p)->(%p, %p)\n", source, result, event);
+ if (source->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + return IMFMediaEventQueue_EndGetEvent(source->event_queue, result, event); }
@@ -109,6 +124,9 @@ static HRESULT WINAPI media_source_QueueEvent(IMFMediaSource *iface, MediaEventT
TRACE("(%p)->(%d, %s, %#x, %p)\n", source, event_type, debugstr_guid(ext_type), hr, value);
+ if (source->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, ext_type, hr, value); }
@@ -118,6 +136,9 @@ static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWO
FIXME("(%p)->(%p): stub\n", source, characteristics);
+ if (source->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + return E_NOTIMPL; }
@@ -127,6 +148,9 @@ static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *
FIXME("(%p)->(%p): stub\n", source, descriptor);
+ if (source->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + return E_NOTIMPL; }
@@ -137,6 +161,9 @@ static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationD
FIXME("(%p)->(%p, %p, %p): stub\n", source, descriptor, time_format, start_position);
+ if (source->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + return E_NOTIMPL; }
@@ -146,6 +173,9 @@ static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface)
FIXME("(%p): stub\n", source);
+ if (source->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + return E_NOTIMPL; }
@@ -155,16 +185,28 @@ static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface)
FIXME("(%p): stub\n", source);
+ if (source->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + return E_NOTIMPL; }
+static HRESULT media_source_teardown(struct media_source *source) +{ + if (source->event_queue) + IMFMediaEventQueue_Release(source->event_queue); + + return S_OK; +} + static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) { struct media_source *source = impl_from_IMFMediaSource(iface);
- FIXME("(%p): stub\n", source); + TRACE("(%p)\n", source);
- return E_NOTIMPL; + source->state = SOURCE_SHUTDOWN; + return media_source_teardown(source); }
static const IMFMediaSourceVtbl IMFMediaSource_vtbl = @@ -195,6 +237,8 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ if (FAILED(hr = MFCreateEventQueue(&object->event_queue))) goto fail;
+ object->state = SOURCE_STOPPED; + object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl; object->ref = 1;
@@ -204,8 +248,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ fail: WARN("Failed to construct MFMediaSource, hr %#x.\n", hr);
- if (object->event_queue) - IMFMediaEventQueue_Release(object->event_queue); + media_source_teardown(object); heap_free(object); return hr; }
On 8/28/20 11:48 PM, Derek Lesho wrote:
@@ -81,6 +87,9 @@ static HRESULT WINAPI media_source_GetEvent(IMFMediaSource *iface, DWORD flags,
TRACE("(%p)->(%#x, %p)\n", source, flags, event);
- if (source->state == SOURCE_SHUTDOWN)
return MF_E_SHUTDOWN;
- return IMFMediaEventQueue_GetEvent(source->event_queue, flags, event);
}
@@ -90,6 +99,9 @@ static HRESULT WINAPI media_source_BeginGetEvent(IMFMediaSource *iface, IMFAsync
TRACE("(%p)->(%p, %p)\n", source, callback, state);
- if (source->state == SOURCE_SHUTDOWN)
return MF_E_SHUTDOWN;
- return IMFMediaEventQueue_BeginGetEvent(source->event_queue, callback, state);
}
This is unnecessary. If the queue is shut down on source->Shutdown(), you'll get same return value from queue methods. Queue tracks its state internally.
static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) { struct media_source *source = impl_from_IMFMediaSource(iface);
- FIXME("(%p): stub\n", source);
- TRACE("(%p)\n", source);
- return E_NOTIMPL;
- source->state = SOURCE_SHUTDOWN;
- return media_source_teardown(source);
}
Related to comment above, it will be shorter to forward to the queue unconditionally, and only shutdown here, without releasing it.
I was thinking we will be keeping this stub until winegstreamer changes are in and got tested enough. Not sure what the current situation is on macos, maybe we'll need this stub until we have a bridge to newer multimedia API, now that quicktime one is deprecated.
On 8/29/20 1:30 AM, Nikolay Sivov wrote:
I was thinking we will be keeping this stub until winegstreamer changes are in and got tested enough. Not sure what the current situation is on macos, maybe we'll need this stub until we have a bridge to newer multimedia API, now that quicktime one is deprecated.
I'm fine with keeping or it or removing it. In my initial patch I preserved it, at the expensive of uglier testing code. However, what's the purpose of the stub in the first place? Do any applications rely on it being present?
On 29-08-2020 18:29, Derek Lesho wrote:
On 8/29/20 1:30 AM, Nikolay Sivov wrote:
I was thinking we will be keeping this stub until winegstreamer changes are in and got tested enough. Not sure what the current situation is on macos, maybe we'll need this stub until we have a bridge to newer multimedia API, now that quicktime one is deprecated.
I'm fine with keeping or it or removing it. In my initial patch I preserved it, at the expensive of uglier testing code. However, what's the purpose of the stub in the first place? Do any applications rely on it being present?
Hey Derek,
I added this stub to make Disgaea 5 work, but IIRC the devs ended up removing their MF code because they couldn't get it to work on Windows either. I guess you could check if the game still launches without the fallback. Not sure about other applications.
Cheers, Sven
On 8/29/20 7:29 PM, Derek Lesho wrote:
On 8/29/20 1:30 AM, Nikolay Sivov wrote:
I was thinking we will be keeping this stub until winegstreamer changes are in and got tested enough. Not sure what the current situation is on macos, maybe we'll need this stub until we have a bridge to newer multimedia API, now that quicktime one is deprecated.
I'm fine with keeping or it or removing it. In my initial patch I preserved it, at the expensive of uglier testing code. However, what's the purpose of the stub in the first place? Do any applications rely on it being present?
We either keep it until we have something better or remove it only to find out what breaks.
On 8/29/20 1:09 PM, Nikolay Sivov wrote:
On 8/29/20 7:29 PM, Derek Lesho wrote:
On 8/29/20 1:30 AM, Nikolay Sivov wrote:
I was thinking we will be keeping this stub until winegstreamer changes are in and got tested enough. Not sure what the current situation is on macos, maybe we'll need this stub until we have a bridge to newer multimedia API, now that quicktime one is deprecated.
I'm fine with keeping or it or removing it. In my initial patch I preserved it, at the expensive of uglier testing code. However, what's the purpose of the stub in the first place? Do any applications rely on it being present?
We either keep it until we have something better or remove it only to find out what breaks.
It seems unlikely that anything will break. I tested Disgaea, which the hack was written for, and it works fine if lookup of the media source fails. I think it would take a very strange application to not handle the failure of creating a media source, yet gracefully handle failure when interacting with the presentation descriptor. If anything, removing the stub might improve compatibility.