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 --- v5: Explicitely use gstreamer media source as a fallback. --- dlls/mfplat/main.c | 6 + dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/gst_private.h | 2 + dlls/winegstreamer/media_source.c | 455 +++++++++++++++++++ dlls/winegstreamer/mfplat.c | 3 + dlls/winegstreamer/winegstreamer.rgs | 20 + dlls/winegstreamer/winegstreamer_classes.idl | 7 + 7 files changed, 494 insertions(+) create mode 100644 dlls/winegstreamer/media_source.c
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index ea1b1770e15..a6ff97ae04a 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -6057,6 +6057,12 @@ static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHA break; }
+ if (FAILED(hr)) + { + static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}}; + hr = CoCreateInstance(&CLSID_GStreamerByteStreamHandler, NULL, CLSCTX_INPROC_SERVER, &IID_IMFByteStreamHandler, (void **)handler); + } + CoTaskMemFree(mimeW); return hr; } 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..c996f06211e 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -398,6 +398,8 @@ failed: return hr; }
+static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}}; + static const struct class_object { const GUID *clsid; @@ -406,6 +408,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 {}
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- v6: I forgot to remove the winegstreamer.rgs change, whoops. 😅 --- dlls/mfplat/main.c | 6 + dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/gst_private.h | 2 + dlls/winegstreamer/media_source.c | 455 +++++++++++++++++++ dlls/winegstreamer/mfplat.c | 3 + dlls/winegstreamer/winegstreamer_classes.idl | 7 + 6 files changed, 474 insertions(+) create mode 100644 dlls/winegstreamer/media_source.c
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index ea1b1770e15..a6ff97ae04a 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -6057,6 +6057,12 @@ static HRESULT resolver_get_bytestream_handler(IMFByteStream *stream, const WCHA break; }
+ if (FAILED(hr)) + { + static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}}; + hr = CoCreateInstance(&CLSID_GStreamerByteStreamHandler, NULL, CLSCTX_INPROC_SERVER, &IID_IMFByteStreamHandler, (void **)handler); + } + CoTaskMemFree(mimeW); return hr; } 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..c996f06211e 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -398,6 +398,8 @@ failed: return hr; }
+static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}}; + static const struct class_object { const GUID *clsid; @@ -406,6 +408,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_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 {}
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
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: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- v5: Use IMFMediaSource::Release on failed construction. --- dlls/winegstreamer/media_source.c | 36 ++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 8 deletions(-)
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index c8f21cd6143..b98949459ce 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) @@ -68,6 +69,7 @@ static ULONG WINAPI media_source_Release(IMFMediaSource *iface)
if (!ref) { + IMFMediaEventQueue_Release(source->event_queue); heap_free(source); }
@@ -76,31 +78,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 +188,25 @@ 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); + + IMFMediaSource_Release(&object->IMFMediaSource_iface); + return hr; }
struct winegstreamer_stream_handler_result
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- v5: - Allow the event queue to handle the shutdown state. - Shutdown the media source on release. --- dlls/mfplat/tests/mfplat.c | 4 ++-- dlls/winegstreamer/media_source.c | 36 +++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 4 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 b98949459ce..d8536bba00a 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) @@ -69,6 +75,7 @@ static ULONG WINAPI media_source_Release(IMFMediaSource *iface)
if (!ref) { + IMFMediaSource_Shutdown(&source->IMFMediaSource_iface); IMFMediaEventQueue_Release(source->event_queue); heap_free(source); } @@ -119,6 +126,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; }
@@ -128,6 +138,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; }
@@ -138,6 +151,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; }
@@ -147,6 +163,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; }
@@ -156,6 +175,9 @@ 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; }
@@ -163,9 +185,17 @@ 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; + if (source->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + + source->state = SOURCE_SHUTDOWN; + + if (source->event_queue) + IMFMediaEventQueue_Shutdown(source->event_queue); + + return S_OK; }
static const IMFMediaSourceVtbl IMFMediaSource_vtbl = @@ -196,6 +226,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;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=77976
Your paranoid android.
=== w1064v1809 (32 bit report) ===
mfplat: mfplat.c:523: Test failed: Unexpected hr 0xc00d36c3. mfplat.c:527: Test failed: Failed to resolve url, hr 0xc00d36c3. 0664:mfplat: unhandled exception c0000005 at 00000001