Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/Makefile.in | 1 + dlls/mf/main.c | 2 +- dlls/mf/mf.spec | 4 +-- dlls/mf/mf_private.h | 2 +- dlls/mf/samplegrabber.c | 4 +-- dlls/mf/sar.c | 76 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 dlls/mf/sar.c
diff --git a/dlls/mf/Makefile.in b/dlls/mf/Makefile.in index 2eb9b346d9..ecedea65c1 100644 --- a/dlls/mf/Makefile.in +++ b/dlls/mf/Makefile.in @@ -5,6 +5,7 @@ IMPORTS = mfplat mfuuid C_SRCS = \ main.c \ samplegrabber.c \ + sar.c \ session.c \ topology.c
diff --git a/dlls/mf/main.c b/dlls/mf/main.c index c2e5eb45d2..b5b4b0e7c8 100644 --- a/dlls/mf/main.c +++ b/dlls/mf/main.c @@ -392,7 +392,7 @@ static HRESULT WINAPI activate_object_ActivateObject(IMFActivate *iface, REFIID
if (!activate->object) { - if (FAILED(hr = activate->funcs->create_object(activate->context, &object))) + if (FAILED(hr = activate->funcs->create_object((IMFAttributes *)iface, activate->context, &object))) return hr;
if (!InterlockedCompareExchangePointer((void **)&activate->object, object, NULL)) diff --git a/dlls/mf/mf.spec b/dlls/mf/mf.spec index 6131495225..6e64404ba6 100644 --- a/dlls/mf/mf.spec +++ b/dlls/mf/mf.spec @@ -23,8 +23,8 @@ @ stub MFCreateASFStreamingMediaSinkActivate @ stub MFCreateAggregateSource @ stub MFCreateAppSourceProxy -@ stub MFCreateAudioRenderer -@ stub MFCreateAudioRendererActivate +@ stdcall MFCreateAudioRenderer(ptr ptr) +@ stdcall MFCreateAudioRendererActivate(ptr) @ stub MFCreateByteCacheFile @ stub MFCreateCacheManager @ stub MFCreateCredentialCache diff --git a/dlls/mf/mf_private.h b/dlls/mf/mf_private.h index 45a3834eec..0b7d1c65fa 100644 --- a/dlls/mf/mf_private.h +++ b/dlls/mf/mf_private.h @@ -49,7 +49,7 @@ static inline BOOL mf_array_reserve(void **elements, size_t *capacity, size_t co
struct activate_funcs { - HRESULT (*create_object)(void *context, IUnknown **object); + HRESULT (*create_object)(IMFAttributes *attributes, void *context, IUnknown **object); void (*free_private)(void *context); };
diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c index 1ffa3ba0b0..7b3536467c 100644 --- a/dlls/mf/samplegrabber.c +++ b/dlls/mf/samplegrabber.c @@ -40,9 +40,9 @@ static void sample_grabber_free_private(void *user_context) heap_free(context); }
-static HRESULT sample_grabber_create_object(void *user_context, IUnknown **obj) +static HRESULT sample_grabber_create_object(IMFAttributes *attributes, void *user_context, IUnknown **obj) { - FIXME("%p, %p.\n", user_context, obj); + FIXME("%p, %p, %p.\n", attributes, user_context, obj);
return E_NOTIMPL; } diff --git a/dlls/mf/sar.c b/dlls/mf/sar.c new file mode 100644 index 0000000000..c0c1803df1 --- /dev/null +++ b/dlls/mf/sar.c @@ -0,0 +1,76 @@ +/* + * Copyright 2019 Nikolay Sivov for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS + +#include "mfidl.h" +#include "mf_private.h" + +#include "wine/debug.h" +#include "wine/heap.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + +static HRESULT sar_create_object(IMFAttributes *attributes, void *user_context, IUnknown **obj) +{ + FIXME("%p, %p, %p.\n", attributes, user_context, obj); + + return E_NOTIMPL; +} + +static void sar_free_private(void *user_context) +{ +} + +static const struct activate_funcs sar_activate_funcs = +{ + sar_create_object, + sar_free_private, +}; + +/*********************************************************************** + * MFCreateAudioRendererActivate (mf.@) + */ +HRESULT WINAPI MFCreateAudioRendererActivate(IMFActivate **activate) +{ + TRACE("%p.\n", activate); + + if (!activate) + return E_POINTER; + + return create_activation_object(NULL, &sar_activate_funcs, activate); +} + +/*********************************************************************** + * MFCreateAudioRenderer (mf.@) + */ +HRESULT WINAPI MFCreateAudioRenderer(IMFAttributes *attributes, IMFMediaSink **sink) +{ + IUnknown *object; + HRESULT hr; + + TRACE("%p, %p.\n", attributes, sink); + + if (SUCCEEDED(hr = sar_create_object(attributes, NULL, &object))) + { + hr = IUnknown_QueryInterface(object, &IID_IMFMediaSink, (void **)sink); + IUnknown_Release(object); + } + + return hr; +}
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/Makefile.in | 2 +- dlls/mf/session.c | 208 +++++++++++++++++++++++++++++++++++++++++++- dlls/mf/topology.c | 4 - include/mfidl.idl | 12 +++ 4 files changed, 217 insertions(+), 9 deletions(-)
diff --git a/dlls/mf/Makefile.in b/dlls/mf/Makefile.in index ecedea65c1..d9c85c435f 100644 --- a/dlls/mf/Makefile.in +++ b/dlls/mf/Makefile.in @@ -1,6 +1,6 @@ MODULE = mf.dll IMPORTLIB = mf -IMPORTS = mfplat mfuuid +IMPORTS = mfplat uuid mfuuid
C_SRCS = \ main.c \ diff --git a/dlls/mf/session.c b/dlls/mf/session.c index a433a300ee..7923581f13 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -33,12 +33,33 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+enum session_command +{ + SESSION_CLEAR_TOPOLOGIES, +}; + +struct session_op +{ + IUnknown IUnknown_iface; + LONG refcount; + enum session_command command; +}; + +struct queued_topology +{ + struct list entry; + IMFTopology *topology; +}; + struct media_session { IMFMediaSession IMFMediaSession_iface; IMFGetService IMFGetService_iface; + IMFAsyncCallback commands_callback; LONG refcount; IMFMediaEventQueue *event_queue; + struct list topologies; + CRITICAL_SECTION cs; };
struct clock_sink @@ -93,11 +114,21 @@ static inline struct media_session *impl_from_IMFMediaSession(IMFMediaSession *i return CONTAINING_RECORD(iface, struct media_session, IMFMediaSession_iface); }
+static struct media_session *impl_from_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct media_session, commands_callback); +} + static struct media_session *impl_from_IMFGetService(IMFGetService *iface) { return CONTAINING_RECORD(iface, struct media_session, IMFGetService_iface); }
+static struct session_op *impl_op_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct session_op, IUnknown_iface); +} + static struct presentation_clock *impl_from_IMFPresentationClock(IMFPresentationClock *iface) { return CONTAINING_RECORD(iface, struct presentation_clock, IMFPresentationClock_iface); @@ -128,6 +159,79 @@ static struct sink_notification *impl_from_IUnknown(IUnknown *iface) return CONTAINING_RECORD(iface, struct sink_notification, IUnknown_iface); }
+static HRESULT WINAPI session_op_QueryInterface(IUnknown *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IUnknown_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI session_op_AddRef(IUnknown *iface) +{ + struct session_op *op = impl_op_from_IUnknown(iface); + ULONG refcount = InterlockedIncrement(&op->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI session_op_Release(IUnknown *iface) +{ + struct session_op *op = impl_op_from_IUnknown(iface); + ULONG refcount = InterlockedDecrement(&op->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + if (!refcount) + { + heap_free(op); + } + + return refcount; +} + +static IUnknownVtbl session_op_vtbl = +{ + session_op_QueryInterface, + session_op_AddRef, + session_op_Release, +}; + +static HRESULT create_session_op(enum session_command command, IUnknown **ret) +{ + struct session_op *op; + + if (!(op = heap_alloc(sizeof(*op)))) + return E_OUTOFMEMORY; + + op->IUnknown_iface.lpVtbl = &session_op_vtbl; + op->refcount = 1; + op->command = command; + + *ret = &op->IUnknown_iface; + + return S_OK; +} + +static void session_clear_topologies(struct media_session *session) +{ + struct queued_topology *ptr, *next; + + LIST_FOR_EACH_ENTRY_SAFE(ptr, next, &session->topologies, struct queued_topology, entry) + { + list_remove(&ptr->entry); + IMFTopology_Release(ptr->topology); + heap_free(ptr); + } +} + static HRESULT WINAPI mfsession_QueryInterface(IMFMediaSession *iface, REFIID riid, void **out) { struct media_session *session = impl_from_IMFMediaSession(iface); @@ -173,8 +277,10 @@ static ULONG WINAPI mfsession_Release(IMFMediaSession *iface)
if (!refcount) { + session_clear_topologies(session); if (session->event_queue) IMFMediaEventQueue_Release(session->event_queue); + DeleteCriticalSection(&session->cs); heap_free(session); }
@@ -220,16 +326,44 @@ static HRESULT WINAPI mfsession_QueueEvent(IMFMediaSession *iface, MediaEventTyp
static HRESULT WINAPI mfsession_SetTopology(IMFMediaSession *iface, DWORD flags, IMFTopology *topology) { - FIXME("(%p)->(%#x, %p)\n", iface, flags, topology); + struct media_session *session = impl_from_IMFMediaSession(iface); + struct queued_topology *queued_topology;
- return E_NOTIMPL; + FIXME("%p, %#x, %p.\n", iface, flags, topology); + + if (!(queued_topology = heap_alloc(sizeof(*queued_topology)))) + return E_OUTOFMEMORY; + + queued_topology->topology = topology; + IMFTopology_AddRef(queued_topology->topology); + + EnterCriticalSection(&session->cs); + list_add_tail(&session->topologies, &queued_topology->entry); + LeaveCriticalSection(&session->cs); + + return S_OK; +} + +static HRESULT session_submit_command(struct media_session *session, IUnknown *op) +{ + return MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &session->commands_callback, op); }
static HRESULT WINAPI mfsession_ClearTopologies(IMFMediaSession *iface) { - FIXME("(%p)\n", iface); + struct media_session *session = impl_from_IMFMediaSession(iface); + IUnknown *op; + HRESULT hr;
- return E_NOTIMPL; + TRACE("%p.\n", iface); + + if (FAILED(hr = create_session_op(SESSION_CLEAR_TOPOLOGIES, &op))) + return hr; + + hr = session_submit_command(session, op); + IUnknown_Release(op); + + return hr; }
static HRESULT WINAPI mfsession_Start(IMFMediaSession *iface, const GUID *format, const PROPVARIANT *start) @@ -346,6 +480,69 @@ static const IMFGetServiceVtbl session_get_service_vtbl = session_get_service_GetService, };
+static HRESULT WINAPI session_commands_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 session_commands_callback_AddRef(IMFAsyncCallback *iface) +{ + struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface); + return IMFMediaSession_AddRef(&session->IMFMediaSession_iface); +} + +static ULONG WINAPI session_commands_callback_Release(IMFAsyncCallback *iface) +{ + struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface); + return IMFMediaSession_Release(&session->IMFMediaSession_iface); +} + +static HRESULT WINAPI session_commands_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + struct session_op *op = impl_op_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result)); + struct media_session *session = impl_from_commands_callback_IMFAsyncCallback(iface); + + switch (op->command) + { + case SESSION_CLEAR_TOPOLOGIES: + EnterCriticalSection(&session->cs); + session_clear_topologies(session); + LeaveCriticalSection(&session->cs); + + IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MESessionTopologiesCleared, &GUID_NULL, + S_OK, NULL); + break; + default: + ; + } + + return S_OK; +} + +static const IMFAsyncCallbackVtbl session_commands_callback_vtbl = +{ + session_commands_callback_QueryInterface, + session_commands_callback_AddRef, + session_commands_callback_Release, + session_commands_callback_GetParameters, + session_commands_callback_Invoke, +}; + /*********************************************************************** * MFCreateMediaSession (mf.@) */ @@ -365,12 +562,15 @@ HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **ses
object->IMFMediaSession_iface.lpVtbl = &mfmediasessionvtbl; object->IMFGetService_iface.lpVtbl = &session_get_service_vtbl; + object->commands_callback.lpVtbl = &session_commands_callback_vtbl; object->refcount = 1; if (FAILED(hr = MFCreateEventQueue(&object->event_queue))) { IMFMediaSession_Release(&object->IMFMediaSession_iface); return hr; } + list_init(&object->topologies); + InitializeCriticalSection(&object->cs);
*session = &object->IMFMediaSession_iface;
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index e10bc8b07d..1d72d8bb68 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -26,10 +26,6 @@ #include "windef.h" #include "winbase.h"
-#include "initguid.h" -#include "ole2.h" -#include "ocidl.h" - #undef INITGUID #include <guiddef.h> #include "mfapi.h" diff --git a/include/mfidl.idl b/include/mfidl.idl index 702434aa2d..5db737e68d 100644 --- a/include/mfidl.idl +++ b/include/mfidl.idl @@ -64,6 +64,18 @@ typedef enum _MFCLOCK_CHARACTERISTICS_FLAGS MFCLOCK_CHARACTERISTICS_FLAG_IS_SYSTEM_CLOCK = 0x00000008, } MFCLOCK_CHARACTERISTICS_FLAGS;
+typedef enum MFSESSION_SETTOPOLOGY_FLAGS +{ + MFSESSION_SETTOPOLOGY_IMMEDIATE = 0x00000001, + MFSESSION_SETTOPOLOGY_NORESOLUTION = 0x00000002, + MFSESSION_SETTOPOLOGY_CLEAR_CURRENT = 0x00000004, +} MFSESSION_SETTOPOLOGY_FLAGS; + +typedef enum MFSESSION_GETFULLTOPOLOGY_FLAGS +{ + MFSESSION_GETFULLTOPOLOGY_CURRENT = 0x00000001, +} MFSESSION_GETFULLTOPOLOGY_FLAGS; + [ object, uuid(2eb1e945-18b8-4139-9b1a-d5d584818530),