I'm submitting these patches as RFCs as I'm new to this API, and I'm not sure about the best way to abstract functionality in COM classes when using C.
Derek Lesho (2): mf: Move generic handler to code to helper functions. mf: Implement stub MPEG4 ByteStream handler.
dlls/mf/Makefile.in | 2 + dlls/mf/handler.c | 360 +++++++++++++++++++++++++++++++++++++++++ dlls/mf/main.c | 371 +++++-------------------------------------- dlls/mf/mf.idl | 7 + dlls/mf/mf.rgs | 7 + dlls/mf/mf_private.h | 26 +++ dlls/mf/mpeg4.c | 149 +++++++++++++++++ 7 files changed, 593 insertions(+), 329 deletions(-) create mode 100644 dlls/mf/handler.c create mode 100644 dlls/mf/mpeg4.c
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/mf/Makefile.in | 1 + dlls/mf/handler.c | 360 +++++++++++++++++++++++++++++++++++++++++ dlls/mf/main.c | 369 +++++-------------------------------------- dlls/mf/mf_private.h | 24 +++ 4 files changed, 425 insertions(+), 329 deletions(-) create mode 100644 dlls/mf/handler.c
diff --git a/dlls/mf/Makefile.in b/dlls/mf/Makefile.in index d23349c9cf..81872b17a5 100644 --- a/dlls/mf/Makefile.in +++ b/dlls/mf/Makefile.in @@ -5,6 +5,7 @@ IMPORTS = mfplat ole32 uuid mfuuid EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \ + handler.c \ main.c \ samplegrabber.c \ sar.c \ diff --git a/dlls/mf/handler.c b/dlls/mf/handler.c new file mode 100644 index 0000000000..aac4b0fb72 --- /dev/null +++ b/dlls/mf/handler.c @@ -0,0 +1,360 @@ +#include <stdarg.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "mfidl.h" +#include "rpcproxy.h" + +#include "mf.h" + +#include "mfapi.h" +#include "mferror.h" + +#include "mf_private.h" + +#include "wine/debug.h" +#include "wine/heap.h" +#include "wine/list.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + +struct create_object_context +{ + IUnknown IUnknown_iface; + LONG refcount; + + IPropertyStore *props; + IMFByteStream *stream; + WCHAR *url; + DWORD flags; +}; + +struct handler_result +{ + struct list entry; + IMFAsyncResult *result; + MF_OBJECT_TYPE obj_type; + IUnknown *object; +}; + +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, +}; + +/* Start async methods */ +static struct handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct handler, IMFAsyncCallback_iface); +} + +static HRESULT WINAPI 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; +} + +/* lifetime not managed with COM */ +static ULONG WINAPI handler_callback_AddRef(IMFAsyncCallback *iface) +{ + return 2; +} + +static ULONG WINAPI handler_callback_Release(IMFAsyncCallback *iface) +{ + return 1; +} + +static HRESULT WINAPI handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + struct handler *handler = impl_from_IMFAsyncCallback(iface); + struct 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 = 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 handler_callback_vtbl = +{ + handler_callback_QueryInterface, + handler_callback_AddRef, + handler_callback_Release, + handler_callback_GetParameters, + handler_callback_Invoke, +}; + +/* Start handler helpers */ + +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; +} + +HRESULT handler_begin_create_object(struct handler *handler, IMFByteStream *stream, + const WCHAR *url, DWORD flags, IPropertyStore *props, IUnknown **cancel_cookie, + IMFAsyncCallback *callback, IUnknown *state) +{ + struct create_object_context *context; + IMFAsyncResult *caller, *item; + HRESULT hr; + + 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->url && !context->stream) + { + IMFAsyncResult_Release(caller); + IUnknown_Release(&context->IUnknown_iface); + return E_OUTOFMEMORY; + } + + hr = MFCreateAsyncResult(&context->IUnknown_iface, &handler->IMFAsyncCallback_iface, (IUnknown *)caller, &item); + IUnknown_Release(&context->IUnknown_iface); + IMFAsyncResult_Release(caller); + if (SUCCEEDED(hr)) + { + if (SUCCEEDED(hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO, item))) + { + if (cancel_cookie) + IMFAsyncResult_GetState(item, cancel_cookie); + } + + IMFAsyncResult_Release(item); + } + + return hr; +} + +HRESULT handler_end_create_object(struct handler *handler, IMFAsyncResult *result, + MF_OBJECT_TYPE *obj_type, IUnknown **object) +{ + struct handler_result *found = NULL, *cur; + HRESULT hr; + + EnterCriticalSection(&handler->cs); + + LIST_FOR_EACH_ENTRY(cur, &handler->results, struct handler_result, entry) + { + if (result == cur->result) + { + list_remove(&cur->entry); + found = cur; + break; + } + } + + LeaveCriticalSection(&handler->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; +} + +HRESULT handler_cancel_object_creation(struct handler *handler, IUnknown *cancel_cookie) +{ + struct handler_result *found = NULL, *cur; + + EnterCriticalSection(&handler->cs); + + LIST_FOR_EACH_ENTRY(cur, &handler->results, struct handler_result, entry) + { + if (cancel_cookie == (IUnknown *)cur->result) + { + list_remove(&cur->entry); + found = cur; + break; + } + } + + LeaveCriticalSection(&handler->cs); + + if (found) + { + IMFAsyncResult_Release(found->result); + if (found->object) + IUnknown_Release(found->object); + heap_free(found); + } + + return found ? S_OK : MF_E_UNEXPECTED; +} + +void handler_construct(struct handler *handler, p_create_object_callback create_object_callback) +{ + handler->IMFAsyncCallback_iface.lpVtbl = &handler_callback_vtbl; + handler->create_object = create_object_callback; + + list_init(&handler->results); + InitializeCriticalSection(&handler->cs); +} + +void handler_destruct(struct handler *handler) +{ + struct handler_result *result, *next; + + LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct handler_result, entry) + { + list_remove(&result->entry); + IMFAsyncResult_Release(result->result); + if (result->object) + IUnknown_Release(result->object); + heap_free(result); + } + DeleteCriticalSection(&handler->cs); +} \ No newline at end of file diff --git a/dlls/mf/main.c b/dlls/mf/main.c index 251d59e1c0..8cff665c1c 100644 --- a/dlls/mf/main.c +++ b/dlls/mf/main.c @@ -547,22 +547,12 @@ static const IClassFactoryVtbl class_factory_vtbl = class_factory_LockServer, };
-struct file_scheme_handler_result -{ - struct list entry; - IMFAsyncResult *result; - MF_OBJECT_TYPE obj_type; - IUnknown *object; -}; - struct file_scheme_handler { IMFSchemeHandler IMFSchemeHandler_iface; - IMFAsyncCallback IMFAsyncCallback_iface; LONG refcount; + struct handler handler; IMFSourceResolver *resolver; - struct list results; - CRITICAL_SECTION cs; };
static struct file_scheme_handler *impl_from_IMFSchemeHandler(IMFSchemeHandler *iface) @@ -570,11 +560,6 @@ static struct file_scheme_handler *impl_from_IMFSchemeHandler(IMFSchemeHandler * return CONTAINING_RECORD(iface, struct file_scheme_handler, IMFSchemeHandler_iface); }
-static struct file_scheme_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) -{ - return CONTAINING_RECORD(iface, struct file_scheme_handler, IMFAsyncCallback_iface); -} - static HRESULT WINAPI file_scheme_handler_QueryInterface(IMFSchemeHandler *iface, REFIID riid, void **obj) { TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); @@ -604,239 +589,45 @@ static ULONG WINAPI file_scheme_handler_AddRef(IMFSchemeHandler *iface)
static ULONG WINAPI file_scheme_handler_Release(IMFSchemeHandler *iface) { - struct file_scheme_handler *handler = impl_from_IMFSchemeHandler(iface); - ULONG refcount = InterlockedDecrement(&handler->refcount); - struct file_scheme_handler_result *result, *next; - - TRACE("%p, refcount %u.\n", iface, refcount); - - if (!refcount) - { - LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct file_scheme_handler_result, entry) - { - list_remove(&result->entry); - IMFAsyncResult_Release(result->result); - if (result->object) - IUnknown_Release(result->object); - heap_free(result); - } - DeleteCriticalSection(&handler->cs); - if (handler->resolver) - IMFSourceResolver_Release(handler->resolver); - heap_free(handler); - } - - return refcount; -} - -struct create_object_context -{ - IUnknown IUnknown_iface; - LONG refcount; - - IPropertyStore *props; - 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); + struct file_scheme_handler *this = impl_from_IMFSchemeHandler(iface); + ULONG refcount = InterlockedDecrement(&this->refcount);
TRACE("%p, refcount %u.\n", iface, refcount);
if (!refcount) { - if (context->props) - IPropertyStore_Release(context->props); - heap_free(context->url); - heap_free(context); + if (this->resolver) + IMFSourceResolver_Release(this->resolver); + handler_destruct(&this->handler); }
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 file_scheme_handler_BeginCreateObject(IMFSchemeHandler *iface, const WCHAR *url, DWORD flags, IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state) { - struct file_scheme_handler *handler = impl_from_IMFSchemeHandler(iface); - struct create_object_context *context; - IMFAsyncResult *caller, *item; - HRESULT hr; + struct file_scheme_handler *this = impl_from_IMFSchemeHandler(iface);
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->url = heap_strdupW(url); - if (!context->url) - { - IMFAsyncResult_Release(caller); - IUnknown_Release(&context->IUnknown_iface); - return E_OUTOFMEMORY; - } - - hr = MFCreateAsyncResult(&context->IUnknown_iface, &handler->IMFAsyncCallback_iface, (IUnknown *)caller, &item); - IUnknown_Release(&context->IUnknown_iface); - IMFAsyncResult_Release(caller); - if (SUCCEEDED(hr)) - { - if (SUCCEEDED(hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO, item))) - { - if (cancel_cookie) - IMFAsyncResult_GetState(item, cancel_cookie); - } - - IMFAsyncResult_Release(item); - } - - return hr; + return handler_begin_create_object(&this->handler, NULL, url, flags, props, cancel_cookie, callback, state); }
static HRESULT WINAPI file_scheme_handler_EndCreateObject(IMFSchemeHandler *iface, IMFAsyncResult *result, MF_OBJECT_TYPE *obj_type, IUnknown **object) { - struct file_scheme_handler *handler = impl_from_IMFSchemeHandler(iface); - struct file_scheme_handler_result *found = NULL, *cur; - HRESULT hr; + struct file_scheme_handler *this = impl_from_IMFSchemeHandler(iface);
TRACE("%p, %p, %p, %p.\n", iface, result, obj_type, object); - - EnterCriticalSection(&handler->cs); - - LIST_FOR_EACH_ENTRY(cur, &handler->results, struct file_scheme_handler_result, entry) - { - if (result == cur->result) - { - list_remove(&cur->entry); - found = cur; - break; - } - } - - LeaveCriticalSection(&handler->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; + return handler_end_create_object(&this->handler, result, obj_type, object); }
static HRESULT WINAPI file_scheme_handler_CancelObjectCreation(IMFSchemeHandler *iface, IUnknown *cancel_cookie) { - struct file_scheme_handler *handler = impl_from_IMFSchemeHandler(iface); - struct file_scheme_handler_result *found = NULL, *cur; + struct file_scheme_handler *this = impl_from_IMFSchemeHandler(iface);
TRACE("%p, %p.\n", iface, cancel_cookie); - - EnterCriticalSection(&handler->cs); - - LIST_FOR_EACH_ENTRY(cur, &handler->results, struct file_scheme_handler_result, entry) - { - if (cancel_cookie == (IUnknown *)cur->result) - { - list_remove(&cur->entry); - found = cur; - break; - } - } - - LeaveCriticalSection(&handler->cs); - - if (found) - { - IMFAsyncResult_Release(found->result); - if (found->object) - IUnknown_Release(found->object); - heap_free(found); - } - - return found ? S_OK : MF_E_UNEXPECTED; + return handler_cancel_object_creation(&this->handler, cancel_cookie); }
static const IMFSchemeHandlerVtbl file_scheme_handler_vtbl = @@ -849,38 +640,6 @@ static const IMFSchemeHandlerVtbl file_scheme_handler_vtbl = file_scheme_handler_CancelObjectCreation, };
-static HRESULT WINAPI file_scheme_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 file_scheme_handler_callback_AddRef(IMFAsyncCallback *iface) -{ - struct file_scheme_handler *handler = impl_from_IMFAsyncCallback(iface); - return IMFSchemeHandler_AddRef(&handler->IMFSchemeHandler_iface); -} - -static ULONG WINAPI file_scheme_handler_callback_Release(IMFAsyncCallback *iface) -{ - struct file_scheme_handler *handler = impl_from_IMFAsyncCallback(iface); - return IMFSchemeHandler_Release(&handler->IMFSchemeHandler_iface); -} - -static HRESULT WINAPI file_scheme_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) -{ - return E_NOTIMPL; -} - static HRESULT file_scheme_handler_get_resolver(struct file_scheme_handler *handler, IMFSourceResolver **resolver) { HRESULT hr; @@ -902,111 +661,63 @@ static HRESULT file_scheme_handler_get_resolver(struct file_scheme_handler *hand return S_OK; }
-static HRESULT WINAPI file_scheme_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +static HRESULT file_scheme_handler_create_object(struct handler *handler, WCHAR *url, IMFByteStream *stream, DWORD flags, + IPropertyStore *props, IUnknown **out_object, MF_OBJECT_TYPE *out_obj_type) { static const WCHAR schemeW[] = {'f','i','l','e',':','/','/'}; - struct file_scheme_handler *handler = impl_from_IMFAsyncCallback(iface); - struct file_scheme_handler_result *handler_result; - MF_OBJECT_TYPE obj_type = MF_OBJECT_INVALID; - IUnknown *object = NULL, *context_object; - struct create_object_context *context; + HRESULT hr = S_OK; + WCHAR *path; + IMFByteStream *file_byte_stream; + struct file_scheme_handler *this = CONTAINING_RECORD(handler, struct file_scheme_handler, handler); IMFSourceResolver *resolver; - IMFAsyncResult *caller; - IMFByteStream *stream; - const WCHAR *url; - 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);
/* Strip from scheme, MFCreateFile() won't be expecting it. */ - url = context->url; - if (!wcsnicmp(context->url, schemeW, ARRAY_SIZE(schemeW))) - url += ARRAY_SIZE(schemeW); + path = url; + if (!wcsnicmp(url, schemeW, ARRAY_SIZE(schemeW))) + path += ARRAY_SIZE(schemeW);
- hr = MFCreateFile(context->flags & MF_RESOLUTION_WRITE ? MF_ACCESSMODE_READWRITE : MF_ACCESSMODE_READ, - MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, url, &stream); + hr = MFCreateFile(flags & MF_RESOLUTION_WRITE ? MF_ACCESSMODE_READWRITE : MF_ACCESSMODE_READ, + MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, path, &file_byte_stream); if (SUCCEEDED(hr)) { - if (context->flags & MF_RESOLUTION_MEDIASOURCE) + if (flags & MF_RESOLUTION_MEDIASOURCE) { - if (SUCCEEDED(hr = file_scheme_handler_get_resolver(handler, &resolver))) + if (SUCCEEDED(hr = file_scheme_handler_get_resolver(this, &resolver))) { - hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, context->url, context->flags, - context->props, &obj_type, &object); + hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, file_byte_stream, url, flags, + props, out_obj_type, out_object); IMFSourceResolver_Release(resolver); - IMFByteStream_Release(stream); + IMFByteStream_Release(file_byte_stream); } } else { - object = (IUnknown *)stream; - obj_type = MF_OBJECT_BYTESTREAM; + *out_object = (IUnknown *)file_byte_stream; + *out_obj_type = MF_OBJECT_BYTESTREAM; } }
- 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; + return hr; }
-static const IMFAsyncCallbackVtbl file_scheme_handler_callback_vtbl = -{ - file_scheme_handler_callback_QueryInterface, - file_scheme_handler_callback_AddRef, - file_scheme_handler_callback_Release, - file_scheme_handler_callback_GetParameters, - file_scheme_handler_callback_Invoke, -}; - static HRESULT file_scheme_handler_construct(REFIID riid, void **obj) { - struct file_scheme_handler *handler; + struct file_scheme_handler *this; HRESULT hr;
TRACE("%s, %p.\n", debugstr_guid(riid), obj);
- handler = heap_alloc_zero(sizeof(*handler)); - if (!handler) + this = heap_alloc_zero(sizeof(*this)); + if (!this) return E_OUTOFMEMORY;
- handler->IMFSchemeHandler_iface.lpVtbl = &file_scheme_handler_vtbl; - handler->IMFAsyncCallback_iface.lpVtbl = &file_scheme_handler_callback_vtbl; - handler->refcount = 1; - list_init(&handler->results); - InitializeCriticalSection(&handler->cs); + handler_construct(&this->handler, file_scheme_handler_create_object); + + this->IMFSchemeHandler_iface.lpVtbl = &file_scheme_handler_vtbl; + this->refcount = 1;
- hr = IMFSchemeHandler_QueryInterface(&handler->IMFSchemeHandler_iface, riid, obj); - IMFSchemeHandler_Release(&handler->IMFSchemeHandler_iface); + hr = IMFSchemeHandler_QueryInterface(&this->IMFSchemeHandler_iface, riid, obj); + IMFSchemeHandler_Release(&this->IMFSchemeHandler_iface);
return hr; } diff --git a/dlls/mf/mf_private.h b/dlls/mf/mf_private.h index 0b7d1c65fa..a06962ba79 100644 --- a/dlls/mf/mf_private.h +++ b/dlls/mf/mf_private.h @@ -19,6 +19,7 @@ #include "mfidl.h"
#include "wine/heap.h" +#include "wine/list.h"
static inline BOOL mf_array_reserve(void **elements, size_t *capacity, size_t count, size_t size) { @@ -54,3 +55,26 @@ struct activate_funcs };
HRESULT create_activation_object(void *context, const struct activate_funcs *funcs, IMFActivate **ret) DECLSPEC_HIDDEN; + +/* helper sub-object that handles ansyncronous nature of handlers */ + +struct handler; +typedef HRESULT (*p_create_object_callback)(struct handler *handler, WCHAR *url, IMFByteStream *stream, DWORD flags, IPropertyStore *props, + IUnknown **out_object, MF_OBJECT_TYPE *out_obj_type); + +struct handler +{ + IMFAsyncCallback IMFAsyncCallback_iface; + struct list results; + CRITICAL_SECTION cs; + p_create_object_callback create_object; +}; + +void handler_construct(struct handler *handler, p_create_object_callback create_object_callback); +void handler_destruct(struct handler *handler); +HRESULT handler_begin_create_object(struct handler *handler, IMFByteStream *stream, + const WCHAR *url, DWORD flags, IPropertyStore *props, IUnknown **cancel_cookie, + IMFAsyncCallback *callback, IUnknown *state); +HRESULT handler_end_create_object(struct handler *handler, IMFAsyncResult *result, + MF_OBJECT_TYPE *obj_type, IUnknown **object); +HRESULT handler_cancel_object_creation(struct handler *handler, IUnknown *cancel_cookie); \ No newline at end of file
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/mf/Makefile.in | 1 + dlls/mf/main.c | 2 + dlls/mf/mf.idl | 7 ++ dlls/mf/mf.rgs | 7 ++ dlls/mf/mf_private.h | 4 +- dlls/mf/mpeg4.c | 149 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 dlls/mf/mpeg4.c
diff --git a/dlls/mf/Makefile.in b/dlls/mf/Makefile.in index 81872b17a5..2412cbaf31 100644 --- a/dlls/mf/Makefile.in +++ b/dlls/mf/Makefile.in @@ -7,6 +7,7 @@ EXTRADLLFLAGS = -mno-cygwin C_SRCS = \ handler.c \ main.c \ + mpeg4.c \ samplegrabber.c \ sar.c \ session.c \ diff --git a/dlls/mf/main.c b/dlls/mf/main.c index 8cff665c1c..36c74559af 100644 --- a/dlls/mf/main.c +++ b/dlls/mf/main.c @@ -723,6 +723,7 @@ static HRESULT file_scheme_handler_construct(REFIID riid, void **obj) }
static struct class_factory file_scheme_handler_factory = { { &class_factory_vtbl }, file_scheme_handler_construct }; +static struct class_factory mpeg4_byte_stream_handler_factory = { { &class_factory_vtbl }, mpeg4_stream_handler_construct };
static const struct class_object { @@ -732,6 +733,7 @@ static const struct class_object class_objects[] = { { &CLSID_FileSchemeHandler, &file_scheme_handler_factory.IClassFactory_iface }, + { &CLSID_MPEG4ByteStreamHandler, &mpeg4_byte_stream_handler_factory.IClassFactory_iface }, };
/******************************************************************************* diff --git a/dlls/mf/mf.idl b/dlls/mf/mf.idl index 824c246d30..c673106343 100644 --- a/dlls/mf/mf.idl +++ b/dlls/mf/mf.idl @@ -24,3 +24,10 @@ uuid(477ec299-1421-4bdd-971f-7ccb933f21ad) ] coclass FileSchemeHandler { } + +[ + helpstring("MPEG4 Byte Stream Handler"), + threading(both), + uuid(271c3902-6095-4c45-a22f-20091816ee9e) +] +coclass MPEG4ByteStreamHandler { } \ No newline at end of file diff --git a/dlls/mf/mf.rgs b/dlls/mf/mf.rgs index f127df7632..749f8eef88 100644 --- a/dlls/mf/mf.rgs +++ b/dlls/mf/mf.rgs @@ -13,6 +13,13 @@ HKLM val '{477ec299-1421-4bdd-971f-7ccb933f21ad}' = s 'File Scheme Handler' } } + NoRemove 'ByteStreamHandlers' + { + '.mp4' + { + val '{271C3902-6095-4c45-A22F-20091816EE9E}' = s 'MPEG4 Byte Stream Handler' + } + } } } } diff --git a/dlls/mf/mf_private.h b/dlls/mf/mf_private.h index a06962ba79..fbf7113ce9 100644 --- a/dlls/mf/mf_private.h +++ b/dlls/mf/mf_private.h @@ -77,4 +77,6 @@ HRESULT handler_begin_create_object(struct handler *handler, IMFByteStream *stre IMFAsyncCallback *callback, IUnknown *state); HRESULT handler_end_create_object(struct handler *handler, IMFAsyncResult *result, MF_OBJECT_TYPE *obj_type, IUnknown **object); -HRESULT handler_cancel_object_creation(struct handler *handler, IUnknown *cancel_cookie); \ No newline at end of file +HRESULT handler_cancel_object_creation(struct handler *handler, IUnknown *cancel_cookie); + +HRESULT mpeg4_stream_handler_construct(REFIID riid, void **obj); \ No newline at end of file diff --git a/dlls/mf/mpeg4.c b/dlls/mf/mpeg4.c new file mode 100644 index 0000000000..aa422afd44 --- /dev/null +++ b/dlls/mf/mpeg4.c @@ -0,0 +1,149 @@ +#include <stdarg.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "mfidl.h" +#include "rpcproxy.h" + +#include "mf.h" + +#include "mfapi.h" +#include "mferror.h" + +#include "mf_private.h" + +#include "wine/debug.h" +#include "wine/heap.h" +#include "wine/list.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + +/* IMFByteStreamHandler */ + +struct mpeg4_stream_handler +{ + IMFByteStreamHandler IMFByteStreamHandler_iface; + LONG refcount; + struct handler handler; +}; + +static struct mpeg4_stream_handler *impl_from_IMFByteStreamHandler(IMFByteStreamHandler *iface) +{ + return CONTAINING_RECORD(iface, struct mpeg4_stream_handler, IMFByteStreamHandler_iface); +} + +static HRESULT WINAPI mpeg_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 mpeg_stream_handler_AddRef(IMFByteStreamHandler *iface) +{ + struct mpeg4_stream_handler *handler = impl_from_IMFByteStreamHandler(iface); + ULONG refcount = InterlockedIncrement(&handler->refcount); + + TRACE("%p, refcount %u.\n", handler, refcount); + + return refcount; +} + +static ULONG WINAPI mpeg_stream_handler_Release(IMFByteStreamHandler *iface) +{ + struct mpeg4_stream_handler *this = impl_from_IMFByteStreamHandler(iface); + ULONG refcount = InterlockedDecrement(&this->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + if (!refcount) + { + handler_destruct(&this->handler); + } + + return refcount; +} + +static HRESULT WINAPI mpeg_stream_handler_BeginCreateObject(IMFByteStreamHandler *iface, IMFByteStream *stream, const WCHAR *url, DWORD flags, + IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state) +{ + struct mpeg4_stream_handler *this = impl_from_IMFByteStreamHandler(iface); + + TRACE("%p, %s, %#x, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state); + return handler_begin_create_object(&this->handler, stream, url, flags, props, cancel_cookie, callback, state); +} + +static HRESULT WINAPI mpeg_stream_handler_EndCreateObject(IMFByteStreamHandler *iface, IMFAsyncResult *result, + MF_OBJECT_TYPE *obj_type, IUnknown **object) +{ + struct mpeg4_stream_handler *this = impl_from_IMFByteStreamHandler(iface); + + TRACE("%p, %p, %p, %p.\n", iface, result, obj_type, object); + return handler_end_create_object(&this->handler, result, obj_type, object); +} + +static HRESULT WINAPI mpeg_stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cancel_cookie) +{ + struct mpeg4_stream_handler *this = impl_from_IMFByteStreamHandler(iface); + + TRACE("%p, %p.\n", iface, cancel_cookie); + return handler_cancel_object_creation(&this->handler, cancel_cookie); +} + +static HRESULT mpeg_stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler *iface, QWORD *bytes) +{ + FIXME("stub (%p)\n", bytes); + return E_NOTIMPL; +} + +static const IMFByteStreamHandlerVtbl mpeg4_stream_handler_vtbl = +{ + mpeg_stream_handler_QueryInterface, + mpeg_stream_handler_AddRef, + mpeg_stream_handler_Release, + mpeg_stream_handler_BeginCreateObject, + mpeg_stream_handler_EndCreateObject, + mpeg_stream_handler_CancelObjectCreation, + mpeg_stream_handler_GetMaxNumberOfBytesRequiredForResolution, +}; + +static HRESULT mpeg4_stream_handler_create_object(struct handler *handler, WCHAR *url, IMFByteStream *stream, DWORD flags, + IPropertyStore *props, IUnknown **out_object, MF_OBJECT_TYPE *out_obj_type) +{ + FIXME("stub! (%p %s %p %u %p %p %p)\n", handler, url, stream, flags, props, out_object, out_obj_type); + return E_NOTIMPL; +} + +HRESULT mpeg4_stream_handler_construct(REFIID riid, void **obj) +{ + struct mpeg4_stream_handler *this; + HRESULT hr; + + TRACE("%s, %p.\n", debugstr_guid(riid), obj); + + this = heap_alloc_zero(sizeof(*this)); + if (!this) + return E_OUTOFMEMORY; + + handler_construct(&this->handler, mpeg4_stream_handler_create_object); + + this->IMFByteStreamHandler_iface.lpVtbl = &mpeg4_stream_handler_vtbl; + this->refcount = 1; + + hr = IMFByteStreamHandler_QueryInterface(&this->IMFByteStreamHandler_iface, riid, obj); + IMFByteStreamHandler_Release(&this->IMFByteStreamHandler_iface); + + return hr; +} \ No newline at end of file