Signed-off-by: Derek Lesho dlesho@codeweavers.com --- v3: - Split up stub media source patch. - Add this patch to simply tests. - Add newlines to end of files. --- 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 --- dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/gst_private.h | 2 + dlls/winegstreamer/media_source.c | 457 +++++++++++++++++++ dlls/winegstreamer/mfplat.c | 9 + dlls/winegstreamer/winegstreamer.rgs | 32 ++ dlls/winegstreamer/winegstreamer_classes.idl | 7 + include/mfidl.idl | 1 + 7 files changed, 509 insertions(+) create mode 100644 dlls/winegstreamer/media_source.c
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..b44e75a8a5b 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 container_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..801d058f6b8 --- /dev/null +++ b/dlls/winegstreamer/media_source.c @@ -0,0 +1,457 @@ +#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); + +/* IMFByteStreamHandler */ + +struct container_stream_handler_result +{ + struct list entry; + IMFAsyncResult *result; + MF_OBJECT_TYPE obj_type; + IUnknown *object; +}; + +struct container_stream_handler +{ + IMFByteStreamHandler IMFByteStreamHandler_iface; + IMFAsyncCallback IMFAsyncCallback_iface; + LONG refcount; + struct list results; + CRITICAL_SECTION cs; +}; + +static struct container_stream_handler *impl_from_IMFByteStreamHandler(IMFByteStreamHandler *iface) +{ + return CONTAINING_RECORD(iface, struct container_stream_handler, IMFByteStreamHandler_iface); +} + +static struct container_stream_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct container_stream_handler, IMFAsyncCallback_iface); +} + +static HRESULT WINAPI container_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 container_stream_handler_AddRef(IMFByteStreamHandler *iface) +{ + struct container_stream_handler *handler = impl_from_IMFByteStreamHandler(iface); + ULONG refcount = InterlockedIncrement(&handler->refcount); + + TRACE("%p, refcount %u.\n", handler, refcount); + + return refcount; +} + +static ULONG WINAPI container_stream_handler_Release(IMFByteStreamHandler *iface) +{ + struct container_stream_handler *handler = impl_from_IMFByteStreamHandler(iface); + ULONG refcount = InterlockedDecrement(&handler->refcount); + struct container_stream_handler_result *result, *next; + + TRACE("%p, refcount %u.\n", iface, refcount); + + if (!refcount) + { + LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct container_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 container_stream_handler_BeginCreateObject(IMFByteStreamHandler *iface, IMFByteStream *stream, const WCHAR *url, DWORD flags, + IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state) +{ + struct container_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 container_stream_handler_EndCreateObject(IMFByteStreamHandler *iface, IMFAsyncResult *result, + MF_OBJECT_TYPE *obj_type, IUnknown **object) +{ + struct container_stream_handler *this = impl_from_IMFByteStreamHandler(iface); + struct container_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 container_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 container_stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cancel_cookie) +{ + struct container_stream_handler *this = impl_from_IMFByteStreamHandler(iface); + struct container_stream_handler_result *found = NULL, *cur; + + TRACE("%p, %p.\n", iface, cancel_cookie); + + EnterCriticalSection(&this->cs); + + LIST_FOR_EACH_ENTRY(cur, &this->results, struct container_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 container_stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler *iface, QWORD *bytes) +{ + FIXME("stub (%p %p)\n", iface, bytes); + return E_NOTIMPL; +} + +static const IMFByteStreamHandlerVtbl container_stream_handler_vtbl = +{ + container_stream_handler_QueryInterface, + container_stream_handler_AddRef, + container_stream_handler_Release, + container_stream_handler_BeginCreateObject, + container_stream_handler_EndCreateObject, + container_stream_handler_CancelObjectCreation, + container_stream_handler_GetMaxNumberOfBytesRequiredForResolution, +}; + +static HRESULT WINAPI container_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 container_stream_handler_callback_AddRef(IMFAsyncCallback *iface) +{ + struct container_stream_handler *handler = impl_from_IMFAsyncCallback(iface); + return IMFByteStreamHandler_AddRef(&handler->IMFByteStreamHandler_iface); +} + +static ULONG WINAPI container_stream_handler_callback_Release(IMFAsyncCallback *iface) +{ + struct container_stream_handler *handler = impl_from_IMFAsyncCallback(iface); + return IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface); +} + +static HRESULT WINAPI container_stream_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) +{ + return E_NOTIMPL; +} + +static HRESULT container_stream_handler_create_object(struct container_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 container_stream_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + struct container_stream_handler *handler = impl_from_IMFAsyncCallback(iface); + struct container_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 = container_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 container_stream_handler_callback_vtbl = +{ + container_stream_handler_callback_QueryInterface, + container_stream_handler_callback_AddRef, + container_stream_handler_callback_Release, + container_stream_handler_callback_GetParameters, + container_stream_handler_callback_Invoke, +}; + +HRESULT container_stream_handler_create(REFIID riid, void **obj) +{ + struct container_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 = &container_stream_handler_vtbl; + this->IMFAsyncCallback_iface.lpVtbl = &container_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..3d65fe8dd48 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -398,6 +398,11 @@ failed: return hr; }
+static HRESULT mp4_stream_handler_create(REFIID riid, void **ret) +{ + return container_stream_handler_create(riid, ret); +} + static const struct class_object { const GUID *clsid; @@ -406,6 +411,7 @@ static const struct class_object class_objects[] = { { &CLSID_VideoProcessorMFT, &video_processor_create }, + { &CLSID_MPEG4ByteStreamHandler, &mp4_stream_handler_create }, };
HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) @@ -414,6 +420,9 @@ HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) unsigned int i; HRESULT hr;
+ if (!(init_gstreamer())) + return CLASS_E_CLASSNOTAVAILABLE; + for (i = 0; i < ARRAY_SIZE(class_objects); ++i) { if (IsEqualGUID(class_objects[i].clsid, rclsid)) diff --git a/dlls/winegstreamer/winegstreamer.rgs b/dlls/winegstreamer/winegstreamer.rgs index 923ba673f8c..9323bcc24dd 100644 --- a/dlls/winegstreamer/winegstreamer.rgs +++ b/dlls/winegstreamer/winegstreamer.rgs @@ -12,3 +12,35 @@ HKCR } } } + +HKLM +{ + NoRemove 'Software' + { + NoRemove 'Microsoft' + { + NoRemove 'Windows Media Foundation' + { + NoRemove 'ByteStreamHandlers' + { + '.m4v' + { + val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler' + } + '.mp4' + { + val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler' + } + 'video/m4v' + { + val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler' + } + 'video/mp4' + { + val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler' + } + } + } + } + } +} diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl index fa0e1784057..997a28b052f 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("MP4 Byte Stream Handler"), + threading(both), + uuid(271c3902-6095-4c45-a22f-20091816ee9e) +] +coclass MPEG4ByteStreamHandler {} diff --git a/include/mfidl.idl b/include/mfidl.idl index 4ceeb707bd0..6aefbe76624 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_MPEG4ByteStreamHandler, 0x271c3902, 0x6095, 0x4c45, 0xa2, 0x2f, 0x20, 0x09, 0x18, 0x16, 0xee, 0x9e);")
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=77689
Your paranoid android.
=== debiant (64 bit WoW report) ===
mfplat: mfplat.c:3365: Test failed: Unexpected refcount 1.
On 8/27/20 1:29 PM, Marvin wrote:
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=77689
Your paranoid android.
=== debiant (64 bit WoW report) ===
mfplat: mfplat.c:3365: Test failed: Unexpected refcount 1.
I don't understand how this patch could have caused this failure, and I can't reproduce it on my system.
On 8/27/20 1:22 PM, Derek Lesho wrote:
Signed-off-by: Derek Lesho dlesho@codeweavers.com
dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/gst_private.h | 2 + dlls/winegstreamer/media_source.c | 457 +++++++++++++++++++ dlls/winegstreamer/mfplat.c | 9 + dlls/winegstreamer/winegstreamer.rgs | 32 ++ dlls/winegstreamer/winegstreamer_classes.idl | 7 + include/mfidl.idl | 1 + 7 files changed, 509 insertions(+) create mode 100644 dlls/winegstreamer/media_source.c
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..b44e75a8a5b 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 container_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..801d058f6b8 --- /dev/null +++ b/dlls/winegstreamer/media_source.c @@ -0,0 +1,457 @@ +#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);
+/* IMFByteStreamHandler */
I'm not sure what comments like this are doing. It's already clear that struct container_stream_handler exposes IMFByteStreamHandler.
+struct container_stream_handler_result +{
- struct list entry;
- IMFAsyncResult *result;
- MF_OBJECT_TYPE obj_type;
- IUnknown *object;
+};
+struct container_stream_handler +{
- IMFByteStreamHandler IMFByteStreamHandler_iface;
- IMFAsyncCallback IMFAsyncCallback_iface;
- LONG refcount;
- struct list results;
- CRITICAL_SECTION cs;
+};
Why "container"?
+static struct container_stream_handler *impl_from_IMFByteStreamHandler(IMFByteStreamHandler *iface) +{
- return CONTAINING_RECORD(iface, struct container_stream_handler, IMFByteStreamHandler_iface);
+}
+static struct container_stream_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) +{
- return CONTAINING_RECORD(iface, struct container_stream_handler, IMFAsyncCallback_iface);
+}
+static HRESULT WINAPI container_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 container_stream_handler_AddRef(IMFByteStreamHandler *iface) +{
- struct container_stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
- ULONG refcount = InterlockedIncrement(&handler->refcount);
- TRACE("%p, refcount %u.\n", handler, refcount);
- return refcount;
+}
+static ULONG WINAPI container_stream_handler_Release(IMFByteStreamHandler *iface) +{
- struct container_stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
- ULONG refcount = InterlockedDecrement(&handler->refcount);
- struct container_stream_handler_result *result, *next;
- TRACE("%p, refcount %u.\n", iface, refcount);
- if (!refcount)
- {
LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct container_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 container_stream_handler_BeginCreateObject(IMFByteStreamHandler *iface, IMFByteStream *stream, const WCHAR *url, DWORD flags,
IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state)
+{
- struct container_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 container_stream_handler_EndCreateObject(IMFByteStreamHandler *iface, IMFAsyncResult *result,
MF_OBJECT_TYPE *obj_type, IUnknown **object)
+{
- struct container_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
- struct container_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 container_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 container_stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cancel_cookie) +{
- struct container_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
- struct container_stream_handler_result *found = NULL, *cur;
- TRACE("%p, %p.\n", iface, cancel_cookie);
- EnterCriticalSection(&this->cs);
- LIST_FOR_EACH_ENTRY(cur, &this->results, struct container_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 container_stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler *iface, QWORD *bytes) +{
- FIXME("stub (%p %p)\n", iface, bytes);
- return E_NOTIMPL;
+}
+static const IMFByteStreamHandlerVtbl container_stream_handler_vtbl = +{
- container_stream_handler_QueryInterface,
- container_stream_handler_AddRef,
- container_stream_handler_Release,
- container_stream_handler_BeginCreateObject,
- container_stream_handler_EndCreateObject,
- container_stream_handler_CancelObjectCreation,
- container_stream_handler_GetMaxNumberOfBytesRequiredForResolution,
+};
+static HRESULT WINAPI container_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 container_stream_handler_callback_AddRef(IMFAsyncCallback *iface) +{
- struct container_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
- return IMFByteStreamHandler_AddRef(&handler->IMFByteStreamHandler_iface);
+}
+static ULONG WINAPI container_stream_handler_callback_Release(IMFAsyncCallback *iface) +{
- struct container_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
- return IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface);
+}
+static HRESULT WINAPI container_stream_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) +{
- return E_NOTIMPL;
+}
+static HRESULT container_stream_handler_create_object(struct container_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 container_stream_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{
- struct container_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
- struct container_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);
That doesn't seem safe at all. Surely you should call QueryInterface here?
- 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 = container_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 container_stream_handler_callback_vtbl = +{
- container_stream_handler_callback_QueryInterface,
- container_stream_handler_callback_AddRef,
- container_stream_handler_callback_Release,
- container_stream_handler_callback_GetParameters,
- container_stream_handler_callback_Invoke,
+};
+HRESULT container_stream_handler_create(REFIID riid, void **obj) +{
- struct container_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 = &container_stream_handler_vtbl;
- this->IMFAsyncCallback_iface.lpVtbl = &container_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..3d65fe8dd48 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -398,6 +398,11 @@ failed: return hr; }
+static HRESULT mp4_stream_handler_create(REFIID riid, void **ret) +{
- return container_stream_handler_create(riid, ret);
+}
This function seems redundant.
static const struct class_object { const GUID *clsid; @@ -406,6 +411,7 @@ static const struct class_object class_objects[] = { { &CLSID_VideoProcessorMFT, &video_processor_create },
- { &CLSID_MPEG4ByteStreamHandler, &mp4_stream_handler_create },
};
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.
HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) @@ -414,6 +420,9 @@ HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) unsigned int i; HRESULT hr;
- if (!(init_gstreamer()))
return CLASS_E_CLASSNOTAVAILABLE;
This doesn't exactly make a lot of sense in this patch, since you're not using gstreamer yet. That said, when you do need it, I think it may make more sense just to move the call up to the top-level DllGetClassObject() implementation.
for (i = 0; i < ARRAY_SIZE(class_objects); ++i) { if (IsEqualGUID(class_objects[i].clsid, rclsid))
diff --git a/dlls/winegstreamer/winegstreamer.rgs b/dlls/winegstreamer/winegstreamer.rgs index 923ba673f8c..9323bcc24dd 100644 --- a/dlls/winegstreamer/winegstreamer.rgs +++ b/dlls/winegstreamer/winegstreamer.rgs @@ -12,3 +12,35 @@ HKCR } } }
+HKLM +{
- NoRemove 'Software'
- {
NoRemove 'Microsoft'
{
NoRemove 'Windows Media Foundation'
{
NoRemove 'ByteStreamHandlers'
{
'.m4v'
{
val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler'
Case is not only inconsistent here, but identical to the Windows registry...
}
'.mp4'
{
val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler'
}
'video/m4v'
{
val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler'
}
'video/mp4'
{
val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler'
}
}
}
}
- }
+}
This hunk should probably be a separate patch. Of course, see my comments above...
diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl index fa0e1784057..997a28b052f 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("MP4 Byte Stream Handler"),
- threading(both),
- uuid(271c3902-6095-4c45-a22f-20091816ee9e)
+] +coclass MPEG4ByteStreamHandler {} diff --git a/include/mfidl.idl b/include/mfidl.idl index 4ceeb707bd0..6aefbe76624 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_MPEG4ByteStreamHandler, 0x271c3902, 0x6095, 0x4c45, 0xa2, 0x2f, 0x20, 0x09, 0x18, 0x16, 0xee, 0x9e);")
On 8/28/20 10:19 AM, Zebediah Figura wrote:
On 8/27/20 1:22 PM, Derek Lesho wrote:
Signed-off-by: Derek Lesho dlesho@codeweavers.com
dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/gst_private.h | 2 + dlls/winegstreamer/media_source.c | 457 +++++++++++++++++++ dlls/winegstreamer/mfplat.c | 9 + dlls/winegstreamer/winegstreamer.rgs | 32 ++ dlls/winegstreamer/winegstreamer_classes.idl | 7 + include/mfidl.idl | 1 + 7 files changed, 509 insertions(+) create mode 100644 dlls/winegstreamer/media_source.c
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..b44e75a8a5b 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 container_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..801d058f6b8 --- /dev/null +++ b/dlls/winegstreamer/media_source.c @@ -0,0 +1,457 @@ +#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);
+/* IMFByteStreamHandler */
I'm not sure what comments like this are doing. It's already clear that struct container_stream_handler exposes IMFByteStreamHandler.
👌
+struct container_stream_handler_result +{
- struct list entry;
- IMFAsyncResult *result;
- MF_OBJECT_TYPE obj_type;
- IUnknown *object;
+};
+struct container_stream_handler +{
- IMFByteStreamHandler IMFByteStreamHandler_iface;
- IMFAsyncCallback IMFAsyncCallback_iface;
- LONG refcount;
- struct list results;
- CRITICAL_SECTION cs;
+};
Why "container"?
Because it's a media source which derives streams out of container formats (mp4, wmv).
+static struct container_stream_handler *impl_from_IMFByteStreamHandler(IMFByteStreamHandler *iface) +{
- return CONTAINING_RECORD(iface, struct container_stream_handler, IMFByteStreamHandler_iface);
+}
+static struct container_stream_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) +{
- return CONTAINING_RECORD(iface, struct container_stream_handler, IMFAsyncCallback_iface);
+}
+static HRESULT WINAPI container_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 container_stream_handler_AddRef(IMFByteStreamHandler *iface) +{
- struct container_stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
- ULONG refcount = InterlockedIncrement(&handler->refcount);
- TRACE("%p, refcount %u.\n", handler, refcount);
- return refcount;
+}
+static ULONG WINAPI container_stream_handler_Release(IMFByteStreamHandler *iface) +{
- struct container_stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
- ULONG refcount = InterlockedDecrement(&handler->refcount);
- struct container_stream_handler_result *result, *next;
- TRACE("%p, refcount %u.\n", iface, refcount);
- if (!refcount)
- {
LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct container_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 container_stream_handler_BeginCreateObject(IMFByteStreamHandler *iface, IMFByteStream *stream, const WCHAR *url, DWORD flags,
IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state)
+{
- struct container_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 container_stream_handler_EndCreateObject(IMFByteStreamHandler *iface, IMFAsyncResult *result,
MF_OBJECT_TYPE *obj_type, IUnknown **object)
+{
- struct container_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
- struct container_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 container_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 container_stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cancel_cookie) +{
- struct container_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
- struct container_stream_handler_result *found = NULL, *cur;
- TRACE("%p, %p.\n", iface, cancel_cookie);
- EnterCriticalSection(&this->cs);
- LIST_FOR_EACH_ENTRY(cur, &this->results, struct container_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 container_stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler *iface, QWORD *bytes) +{
- FIXME("stub (%p %p)\n", iface, bytes);
- return E_NOTIMPL;
+}
+static const IMFByteStreamHandlerVtbl container_stream_handler_vtbl = +{
- container_stream_handler_QueryInterface,
- container_stream_handler_AddRef,
- container_stream_handler_Release,
- container_stream_handler_BeginCreateObject,
- container_stream_handler_EndCreateObject,
- container_stream_handler_CancelObjectCreation,
- container_stream_handler_GetMaxNumberOfBytesRequiredForResolution,
+};
+static HRESULT WINAPI container_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 container_stream_handler_callback_AddRef(IMFAsyncCallback *iface) +{
- struct container_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
- return IMFByteStreamHandler_AddRef(&handler->IMFByteStreamHandler_iface);
+}
+static ULONG WINAPI container_stream_handler_callback_Release(IMFAsyncCallback *iface) +{
- struct container_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
- return IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface);
+}
+static HRESULT WINAPI container_stream_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) +{
- return E_NOTIMPL;
+}
+static HRESULT container_stream_handler_create_object(struct container_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 container_stream_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{
- struct container_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
- struct container_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);
That doesn't seem safe at all. Surely you should call QueryInterface here?
I don't think so, in BeginCreateObject we always send in a IMFAsyncResult. FWIW, I copied most of the implementation of this object from the file scheme handler https://source.winehq.org/git/wine.git/blob/7489efa03f09c6c3613668a0169abade... .
- 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 = container_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 container_stream_handler_callback_vtbl = +{
- container_stream_handler_callback_QueryInterface,
- container_stream_handler_callback_AddRef,
- container_stream_handler_callback_Release,
- container_stream_handler_callback_GetParameters,
- container_stream_handler_callback_Invoke,
+};
+HRESULT container_stream_handler_create(REFIID riid, void **obj) +{
- struct container_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 = &container_stream_handler_vtbl;
- this->IMFAsyncCallback_iface.lpVtbl = &container_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..3d65fe8dd48 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -398,6 +398,11 @@ failed: return hr; }
+static HRESULT mp4_stream_handler_create(REFIID riid, void **ret) +{
- return container_stream_handler_create(riid, ret);
+}
This function seems redundant.
👌
static const struct class_object { const GUID *clsid; @@ -406,6 +411,7 @@ static const struct class_object class_objects[] = { { &CLSID_VideoProcessorMFT, &video_processor_create },
- { &CLSID_MPEG4ByteStreamHandler, &mp4_stream_handler_create }, };
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'm not sure why that's necessary, as 99% of games will just be using mp4 or WMV, but I guess it wouldn't hurt to do this. FWIW, the modification would be in source_resolver_CreateObjectFromByteStream, in place of the old fallback code.
HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) @@ -414,6 +420,9 @@ HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) unsigned int i; HRESULT hr;
- if (!(init_gstreamer()))
return CLASS_E_CLASSNOTAVAILABLE;
This doesn't exactly make a lot of sense in this patch, since you're not using gstreamer yet. That said, when you do need it, I think it may make more sense just to move the call up to the top-level DllGetClassObject() implementation.
👌
for (i = 0; i < ARRAY_SIZE(class_objects); ++i) { if (IsEqualGUID(class_objects[i].clsid, rclsid))
diff --git a/dlls/winegstreamer/winegstreamer.rgs b/dlls/winegstreamer/winegstreamer.rgs index 923ba673f8c..9323bcc24dd 100644 --- a/dlls/winegstreamer/winegstreamer.rgs +++ b/dlls/winegstreamer/winegstreamer.rgs @@ -12,3 +12,35 @@ HKCR } } }
+HKLM +{
- NoRemove 'Software'
- {
NoRemove 'Microsoft'
{
NoRemove 'Windows Media Foundation'
{
NoRemove 'ByteStreamHandlers'
{
'.m4v'
{
val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler'
Case is not only inconsistent here, but identical to the Windows registry...
😂👌
}
'.mp4'
{
val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler'
}
'video/m4v'
{
val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler'
}
'video/mp4'
{
val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler'
}
}
}
}
- }
+}
This hunk should probably be a separate patch. Of course, see my comments above...
👌
diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl index fa0e1784057..997a28b052f 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("MP4 Byte Stream Handler"),
- threading(both),
- uuid(271c3902-6095-4c45-a22f-20091816ee9e)
+] +coclass MPEG4ByteStreamHandler {} diff --git a/include/mfidl.idl b/include/mfidl.idl index 4ceeb707bd0..6aefbe76624 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_MPEG4ByteStreamHandler, 0x271c3902, 0x6095, 0x4c45, 0xa2, 0x2f, 0x20, 0x09, 0x18, 0x16, 0xee, 0x9e);")
On 8/28/20 11:00 AM, Derek Lesho wrote:
On 8/28/20 10:19 AM, Zebediah Figura wrote:
On 8/27/20 1:22 PM, Derek Lesho wrote:
Signed-off-by: Derek Lesho dlesho@codeweavers.com
dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/gst_private.h | 2 + dlls/winegstreamer/media_source.c | 457 +++++++++++++++++++ dlls/winegstreamer/mfplat.c | 9 + dlls/winegstreamer/winegstreamer.rgs | 32 ++ dlls/winegstreamer/winegstreamer_classes.idl | 7 + include/mfidl.idl | 1 + 7 files changed, 509 insertions(+) create mode 100644 dlls/winegstreamer/media_source.c
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..b44e75a8a5b 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 container_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..801d058f6b8 --- /dev/null +++ b/dlls/winegstreamer/media_source.c @@ -0,0 +1,457 @@ +#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);
+/* IMFByteStreamHandler */
I'm not sure what comments like this are doing. It's already clear that struct container_stream_handler exposes IMFByteStreamHandler.
👌
+struct container_stream_handler_result +{
- struct list entry;
- IMFAsyncResult *result;
- MF_OBJECT_TYPE obj_type;
- IUnknown *object;
+};
+struct container_stream_handler +{
- IMFByteStreamHandler IMFByteStreamHandler_iface;
- IMFAsyncCallback IMFAsyncCallback_iface;
- LONG refcount;
- struct list results;
- CRITICAL_SECTION cs;
+};
Why "container"?
Because it's a media source which derives streams out of container formats (mp4, wmv).
Surely it also supports non-container formats, such as mp3?
+static struct container_stream_handler *impl_from_IMFByteStreamHandler(IMFByteStreamHandler *iface) +{
- return CONTAINING_RECORD(iface, struct container_stream_handler, IMFByteStreamHandler_iface);
+}
+static struct container_stream_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) +{
- return CONTAINING_RECORD(iface, struct container_stream_handler, IMFAsyncCallback_iface);
+}
+static HRESULT WINAPI container_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 container_stream_handler_AddRef(IMFByteStreamHandler *iface) +{
- struct container_stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
- ULONG refcount = InterlockedIncrement(&handler->refcount);
- TRACE("%p, refcount %u.\n", handler, refcount);
- return refcount;
+}
+static ULONG WINAPI container_stream_handler_Release(IMFByteStreamHandler *iface) +{
- struct container_stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
- ULONG refcount = InterlockedDecrement(&handler->refcount);
- struct container_stream_handler_result *result, *next;
- TRACE("%p, refcount %u.\n", iface, refcount);
- if (!refcount)
- {
LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct container_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 container_stream_handler_BeginCreateObject(IMFByteStreamHandler *iface, IMFByteStream *stream, const WCHAR *url, DWORD flags,
IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state)
+{
- struct container_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 container_stream_handler_EndCreateObject(IMFByteStreamHandler *iface, IMFAsyncResult *result,
MF_OBJECT_TYPE *obj_type, IUnknown **object)
+{
- struct container_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
- struct container_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 container_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 container_stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cancel_cookie) +{
- struct container_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
- struct container_stream_handler_result *found = NULL, *cur;
- TRACE("%p, %p.\n", iface, cancel_cookie);
- EnterCriticalSection(&this->cs);
- LIST_FOR_EACH_ENTRY(cur, &this->results, struct container_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 container_stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler *iface, QWORD *bytes) +{
- FIXME("stub (%p %p)\n", iface, bytes);
- return E_NOTIMPL;
+}
+static const IMFByteStreamHandlerVtbl container_stream_handler_vtbl = +{
- container_stream_handler_QueryInterface,
- container_stream_handler_AddRef,
- container_stream_handler_Release,
- container_stream_handler_BeginCreateObject,
- container_stream_handler_EndCreateObject,
- container_stream_handler_CancelObjectCreation,
- container_stream_handler_GetMaxNumberOfBytesRequiredForResolution,
+};
+static HRESULT WINAPI container_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 container_stream_handler_callback_AddRef(IMFAsyncCallback *iface) +{
- struct container_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
- return IMFByteStreamHandler_AddRef(&handler->IMFByteStreamHandler_iface);
+}
+static ULONG WINAPI container_stream_handler_callback_Release(IMFAsyncCallback *iface) +{
- struct container_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
- return IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface);
+}
+static HRESULT WINAPI container_stream_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) +{
- return E_NOTIMPL;
+}
+static HRESULT container_stream_handler_create_object(struct container_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 container_stream_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{
- struct container_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
- struct container_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);
That doesn't seem safe at all. Surely you should call QueryInterface here?
I don't think so, in BeginCreateObject we always send in a IMFAsyncResult. FWIW, I copied most of the implementation of this object from the file scheme handler https://source.winehq.org/git/wine.git/blob/7489efa03f09c6c3613668a0169abade...
I see; that's still more than a little concerning, but...
.
- 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 = container_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 container_stream_handler_callback_vtbl = +{
- container_stream_handler_callback_QueryInterface,
- container_stream_handler_callback_AddRef,
- container_stream_handler_callback_Release,
- container_stream_handler_callback_GetParameters,
- container_stream_handler_callback_Invoke,
+};
+HRESULT container_stream_handler_create(REFIID riid, void **obj) +{
- struct container_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 = &container_stream_handler_vtbl;
- this->IMFAsyncCallback_iface.lpVtbl = &container_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..3d65fe8dd48 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -398,6 +398,11 @@ failed: return hr; }
+static HRESULT mp4_stream_handler_create(REFIID riid, void **ret) +{
- return container_stream_handler_create(riid, ret);
+}
This function seems redundant.
👌
static const struct class_object { const GUID *clsid; @@ -406,6 +411,7 @@ static const struct class_object class_objects[] = { { &CLSID_VideoProcessorMFT, &video_processor_create },
- { &CLSID_MPEG4ByteStreamHandler, &mp4_stream_handler_create }, };
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'm not sure why that's necessary, as 99% of games will just be using mp4 or WMV, but I guess it wouldn't hurt to do this. FWIW, the modification would be in source_resolver_CreateObjectFromByteStream, in place of the old fallback code.
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.
HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) @@ -414,6 +420,9 @@ HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) unsigned int i; HRESULT hr;
- if (!(init_gstreamer()))
return CLASS_E_CLASSNOTAVAILABLE;
This doesn't exactly make a lot of sense in this patch, since you're not using gstreamer yet. That said, when you do need it, I think it may make more sense just to move the call up to the top-level DllGetClassObject() implementation.
👌
for (i = 0; i < ARRAY_SIZE(class_objects); ++i) { if (IsEqualGUID(class_objects[i].clsid, rclsid))
diff --git a/dlls/winegstreamer/winegstreamer.rgs b/dlls/winegstreamer/winegstreamer.rgs index 923ba673f8c..9323bcc24dd 100644 --- a/dlls/winegstreamer/winegstreamer.rgs +++ b/dlls/winegstreamer/winegstreamer.rgs @@ -12,3 +12,35 @@ HKCR } } }
+HKLM +{
- NoRemove 'Software'
- {
NoRemove 'Microsoft'
{
NoRemove 'Windows Media Foundation'
{
NoRemove 'ByteStreamHandlers'
{
'.m4v'
{
val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler'
Case is not only inconsistent here, but identical to the Windows registry...
😂👌
}
'.mp4'
{
val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler'
}
'video/m4v'
{
val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler'
}
'video/mp4'
{
val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler'
}
}
}
}
- }
+}
This hunk should probably be a separate patch. Of course, see my comments above...
👌
diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl index fa0e1784057..997a28b052f 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("MP4 Byte Stream Handler"),
- threading(both),
- uuid(271c3902-6095-4c45-a22f-20091816ee9e)
+] +coclass MPEG4ByteStreamHandler {} diff --git a/include/mfidl.idl b/include/mfidl.idl index 4ceeb707bd0..6aefbe76624 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_MPEG4ByteStreamHandler, 0x271c3902, 0x6095, 0x4c45, 0xa2, 0x2f, 0x20, 0x09, 0x18, 0x16, 0xee, 0x9e);")
On 8/28/20 11:10 AM, Zebediah Figura wrote:
Surely it also supports non-container formats, such as mp3?
Would you not classify mp3 as a container format? This page from mozilla seems to https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Containers . Either way, I think it's a descriptive name, because it makes clear that it's not a, for instance, screen capture media source, webcam source, microphone source, etc. I'm willing to change it though if you have any better ideas, maybe media_file_stream_handler?
On 8/28/20 11:21 AM, Derek Lesho wrote:
On 8/28/20 11:10 AM, Zebediah Figura wrote:
Surely it also supports non-container formats, such as mp3?
Would you not classify mp3 as a container format? This page from mozilla seems to https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Containers .
Calling mp3 a container format seems more than a little weird to me; it's an audio codec which can itself be embedded into other containers. Granted, I'm not sure there's a clear definition of what is and isn't a container...
Either way, I think it's a descriptive name, because it makes clear that it's not a, for instance, screen capture media source, webcam source, microphone source, etc. I'm willing to change it though if you have any better ideas, maybe media_file_stream_handler?
Perhaps I misunderstand the architecture of mfplat, but I was under the impression that a media source can receive a byte stream from any source, not necessarily a file (and, in particular, does in practice receive byte streams from Internet URLs). E.g. if a webcam was insane enough to output muxed audio and video, a media source could even decode that.
A potential name more specific than "stream_handler" could be "winegstreamer_stream_handler".
On 8/28/20 11:31 AM, Zebediah Figura wrote:
Perhaps I misunderstand the architecture of mfplat, but I was under the impression that a media source can receive a byte stream from any source, not necessarily a file (and, in particular, does in practice receive byte streams from Internet URLs). E.g. if a webcam was insane enough to output muxed audio and video, a media source could even decode that.
True.
A potential name more specific than "stream_handler" could be "winegstreamer_stream_handler".
Can I just reduce the name to stream_handler? We're already in the winegstreamer module so reiterating that seems redundant to me.
On 8/28/20 11:44 AM, Derek Lesho wrote:
On 8/28/20 11:31 AM, Zebediah Figura wrote:
Perhaps I misunderstand the architecture of mfplat, but I was under the impression that a media source can receive a byte stream from any source, not necessarily a file (and, in particular, does in practice receive byte streams from Internet URLs). E.g. if a webcam was insane enough to output muxed audio and video, a media source could even decode that.
True.
A potential name more specific than "stream_handler" could be "winegstreamer_stream_handler".
Can I just reduce the name to stream_handler? We're already in the winegstreamer module so reiterating that seems redundant to me.
The only reason I wouldn't do that is because you're using the generic "mfplat" debug channel name, so it's not particularly obvious from TRACE output where logs are coming from. Using "winegstreamer" alleviates that concern; I'm not immediately sure if there are drawbacks thereto.
On 8/28/20 11:47 AM, Zebediah Figura wrote:
On 8/28/20 11:44 AM, Derek Lesho wrote:
On 8/28/20 11:31 AM, Zebediah Figura wrote:
Perhaps I misunderstand the architecture of mfplat, but I was under the impression that a media source can receive a byte stream from any source, not necessarily a file (and, in particular, does in practice receive byte streams from Internet URLs). E.g. if a webcam was insane enough to output muxed audio and video, a media source could even decode that.
True.
A potential name more specific than "stream_handler" could be "winegstreamer_stream_handler".
Can I just reduce the name to stream_handler? We're already in the winegstreamer module so reiterating that seems redundant to me.
The only reason I wouldn't do that is because you're using the generic "mfplat" debug channel name, so it's not particularly obvious from TRACE output where logs are coming from. Using "winegstreamer" alleviates that concern; I'm not immediately sure if there are drawbacks thereto.
👌
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/mfplat/tests/mfplat.c | 1 - dlls/winegstreamer/media_source.c | 198 +++++++++++++++++++++++++++++- 2 files changed, 196 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 801d058f6b8..32088498465 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -15,6 +15,181 @@
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)); + HRESULT hr; + + if (!object) + return E_OUTOFMEMORY; + + object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl; + object->ref = 1; + + *out_media_source = object; + return S_OK; +} + /* IMFByteStreamHandler */
struct container_stream_handler_result @@ -369,9 +544,28 @@ static HRESULT WINAPI container_stream_handler_callback_GetParameters(IMFAsyncCa static HRESULT container_stream_handler_create_object(struct container_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 container_stream_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- 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 32088498465..d60c9bd34a3 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) @@ -183,11 +192,22 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ 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; }
/* IMFByteStreamHandler */
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 d60c9bd34a3..1038f6914cd 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; }
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=77692
Your paranoid android.
=== debiant (32 bit Japanese:Japan report) ===
mfplat: Unhandled exception: page fault on read access to 0x00000010 in 32-bit code (0x65881e8a).
Report validation errors: mfplat:mfplat crashed (c0000005)