Signed-off-by: Nikolay Sivov nsivov@codeweavers.com ---
v2: fixes test crashes on older versions
dlls/mf/tests/mf.c | 110 +++++++++++++++++++++++++++++++++++++++++++++ dlls/mf/topology.c | 55 +++++++++++++++++++++-- 2 files changed, 161 insertions(+), 4 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 2b3fdcd798..21d8be80c8 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -35,8 +35,10 @@
static void test_topology(void) { + IMFCollection *collection, *collection2; IMFTopologyNode *node, *node2, *node3; IMFTopology *topology; + DWORD size; WORD count; HRESULT hr; TOPOID id; @@ -192,6 +194,114 @@ static void test_topology(void) IMFTopologyNode_Release(node); IMFTopologyNode_Release(node2);
+ /* Source/output collections. */ + hr = IMFTopology_Clear(topology); + ok(hr == S_OK, "Failed to clear topology, hr %#x.\n", hr); + + hr = IMFTopology_GetSourceNodeCollection(topology, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + hr = IMFTopology_GetSourceNodeCollection(topology, &collection); + ok(hr == S_OK, "Failed to get source node collection, hr %#x.\n", hr); + ok(!!collection, "Unexpected object pointer.\n"); + + hr = IMFTopology_GetSourceNodeCollection(topology, &collection2); + ok(hr == S_OK, "Failed to get source node collection, hr %#x.\n", hr); + ok(!!collection2, "Unexpected object pointer.\n"); + ok(collection2 != collection, "Expected cloned collection.\n"); + + hr = IMFCollection_GetElementCount(collection, &size); + ok(hr == S_OK, "Failed to get item count, hr %#x.\n", hr); + ok(!size, "Unexpected item count.\n"); + + hr = IMFCollection_AddElement(collection, (IUnknown *)collection); + ok(hr == S_OK, "Failed to add element, hr %#x.\n", hr); + + hr = IMFCollection_GetElementCount(collection, &size); + ok(hr == S_OK, "Failed to get item count, hr %#x.\n", hr); + ok(size == 1, "Unexpected item count.\n"); + + hr = IMFCollection_GetElementCount(collection2, &size); + ok(hr == S_OK, "Failed to get item count, hr %#x.\n", hr); + ok(!size, "Unexpected item count.\n"); + + IMFCollection_Release(collection2); + IMFCollection_Release(collection); + + /* Add some nodes. */ + hr = IMFTopology_GetSourceNodeCollection(topology, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + hr = IMFTopology_GetOutputNodeCollection(topology, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node); + ok(hr == S_OK, "Failed to create a node, hr %#x.\n", hr); + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr); + IMFTopologyNode_Release(node); + + hr = IMFTopology_GetSourceNodeCollection(topology, &collection); + ok(hr == S_OK, "Failed to get source node collection, hr %#x.\n", hr); + ok(!!collection, "Unexpected object pointer.\n"); + hr = IMFCollection_GetElementCount(collection, &size); + ok(hr == S_OK, "Failed to get item count, hr %#x.\n", hr); + ok(size == 1, "Unexpected item count.\n"); + IMFCollection_Release(collection); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &node); + ok(hr == S_OK, "Failed to create a node, hr %#x.\n", hr); + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr); + IMFTopologyNode_Release(node); + + hr = IMFTopology_GetSourceNodeCollection(topology, &collection); + ok(hr == S_OK, "Failed to get source node collection, hr %#x.\n", hr); + ok(!!collection, "Unexpected object pointer.\n"); + hr = IMFCollection_GetElementCount(collection, &size); + ok(hr == S_OK, "Failed to get item count, hr %#x.\n", hr); + ok(size == 1, "Unexpected item count.\n"); + IMFCollection_Release(collection); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node); + ok(hr == S_OK, "Failed to create a node, hr %#x.\n", hr); + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr); + IMFTopologyNode_Release(node); + + hr = IMFTopology_GetSourceNodeCollection(topology, &collection); + ok(hr == S_OK, "Failed to get source node collection, hr %#x.\n", hr); + ok(!!collection, "Unexpected object pointer.\n"); + hr = IMFCollection_GetElementCount(collection, &size); + ok(hr == S_OK, "Failed to get item count, hr %#x.\n", hr); + ok(size == 1, "Unexpected item count.\n"); + IMFCollection_Release(collection); + + hr = IMFTopology_GetOutputNodeCollection(topology, &collection); + ok(hr == S_OK || broken(hr == E_FAIL) /* before Win8 */, "Failed to get source node collection, hr %#x.\n", hr); + if (SUCCEEDED(hr)) + { + ok(!!collection, "Unexpected object pointer.\n"); + hr = IMFCollection_GetElementCount(collection, &size); + ok(hr == S_OK, "Failed to get item count, hr %#x.\n", hr); + ok(!size, "Unexpected item count.\n"); + IMFCollection_Release(collection); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node); + ok(hr == S_OK, "Failed to create a node, hr %#x.\n", hr); + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr); + IMFTopologyNode_Release(node); + + hr = IMFTopology_GetOutputNodeCollection(topology, &collection); + ok(hr == S_OK, "Failed to get source node collection, hr %#x.\n", hr); + ok(!!collection, "Unexpected object pointer.\n"); + hr = IMFCollection_GetElementCount(collection, &size); + ok(hr == S_OK, "Failed to get item count, hr %#x.\n", hr); + ok(size == 1, "Unexpected item count.\n"); + IMFCollection_Release(collection); + } + IMFTopology_Release(topology); }
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index d8012226f4..3b4a2e1a58 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -535,18 +535,65 @@ static HRESULT WINAPI topology_GetNodeByID(IMFTopology *iface, TOPOID id, IMFTop return topology_get_node_by_id(topology, id, node); }
+static HRESULT topology_add_node_of_type(const struct topology *topology, IMFTopologyNode *node, + MF_TOPOLOGY_TYPE filter, IMFCollection *collection) +{ + MF_TOPOLOGY_TYPE node_type; + HRESULT hr; + + if (FAILED(hr = IMFTopologyNode_GetNodeType(node, &node_type))) + return hr; + + if (node_type != filter) + return S_OK; + + return IMFCollection_AddElement(collection, (IUnknown *)node); +} + +static HRESULT topology_get_node_collection(const struct topology *topology, MF_TOPOLOGY_TYPE node_type, + IMFCollection **collection) +{ + IMFTopologyNode *node; + unsigned int i = 0; + HRESULT hr; + + if (!collection) + return E_POINTER; + + if (FAILED(hr = MFCreateCollection(collection))) + return hr; + + while (IMFCollection_GetElement(topology->nodes, i++, (IUnknown **)&node) == S_OK) + { + hr = topology_add_node_of_type(topology, node, node_type, *collection); + IMFTopologyNode_Release(node); + if (FAILED(hr)) + { + IMFCollection_Release(*collection); + *collection = NULL; + break; + } + } + + return hr; +} + static HRESULT WINAPI topology_GetSourceNodeCollection(IMFTopology *iface, IMFCollection **collection) { - FIXME("(%p)->(%p)\n", iface, collection); + struct topology *topology = impl_from_IMFTopology(iface);
- return E_NOTIMPL; + TRACE("(%p)->(%p)\n", iface, collection); + + return topology_get_node_collection(topology, MF_TOPOLOGY_SOURCESTREAM_NODE, collection); }
static HRESULT WINAPI topology_GetOutputNodeCollection(IMFTopology *iface, IMFCollection **collection) { - FIXME("(%p)->(%p)\n", iface, collection); + struct topology *topology = impl_from_IMFTopology(iface);
- return E_NOTIMPL; + TRACE("(%p)->(%p)\n", iface, collection); + + return topology_get_node_collection(topology, MF_TOPOLOGY_OUTPUT_NODE, collection); }
static const IMFTopologyVtbl topologyvtbl =
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/tests/mf.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 21d8be80c8..150314933d 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -448,9 +448,31 @@ static void test_MFCreateSequencerSource(void) ok(hr == S_OK, "Shutdown failure, hr %#x.\n", hr); }
+static void test_media_session(void) +{ + IMFMediaSession *session; + IUnknown *unk; + HRESULT hr; + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Startup failure, hr %#x.\n", hr); + + hr = MFCreateMediaSession(NULL, &session); + ok(hr == S_OK, "Failed to create media session, hr %#x.\n", hr); + + hr = IMFMediaSession_QueryInterface(session, &IID_IMFAttributes, (void **)&unk); + ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr); + + IMFMediaSession_Release(session); + + hr = MFShutdown(); + ok(hr == S_OK, "Shutdown failure, hr %#x.\n", hr); +} + START_TEST(mf) { test_topology(); test_MFGetService(); test_MFCreateSequencerSource(); + test_media_session(); }
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/session.c | 135 +++++++++++++++++++++------------------------- 1 file changed, 60 insertions(+), 75 deletions(-)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 5913af39b9..fda3ec7455 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -24,193 +24,175 @@ #include "windef.h" #include "winbase.h" #include "mfidl.h" +#include "mfapi.h"
#include "wine/debug.h" +#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
-typedef struct mfsession +struct media_session { IMFMediaSession IMFMediaSession_iface; - LONG ref; -} mfsession; + LONG refcount; + IMFMediaEventQueue *event_queue; +};
-static inline mfsession *impl_from_IMFMediaSession(IMFMediaSession *iface) +static inline struct media_session *impl_from_IMFMediaSession(IMFMediaSession *iface) { - return CONTAINING_RECORD(iface, mfsession, IMFMediaSession_iface); + return CONTAINING_RECORD(iface, struct media_session, IMFMediaSession_iface); }
static HRESULT WINAPI mfsession_QueryInterface(IMFMediaSession *iface, REFIID riid, void **out) { - mfsession *This = impl_from_IMFMediaSession(iface); + struct media_session *session = impl_from_IMFMediaSession(iface);
- TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), out); + TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), out);
if (IsEqualIID(riid, &IID_IMFMediaSession) || IsEqualIID(riid, &IID_IMFMediaEventGenerator) || IsEqualIID(riid, &IID_IUnknown)) { - *out = &This->IMFMediaSession_iface; - } - else - { - FIXME("(%s, %p)\n", debugstr_guid(riid), out); - *out = NULL; - return E_NOINTERFACE; + *out = &session->IMFMediaSession_iface; + IMFMediaSession_AddRef(iface); + return S_OK; }
- IUnknown_AddRef((IUnknown*)*out); - return S_OK; + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *out = NULL; + return E_NOINTERFACE; }
static ULONG WINAPI mfsession_AddRef(IMFMediaSession *iface) { - mfsession *This = impl_from_IMFMediaSession(iface); - ULONG ref = InterlockedIncrement(&This->ref); + struct media_session *session = impl_from_IMFMediaSession(iface); + ULONG refcount = InterlockedIncrement(&session->refcount);
- TRACE("(%p) ref=%u\n", This, ref); + TRACE("(%p) refcount=%u\n", iface, refcount);
- return ref; + return refcount; }
static ULONG WINAPI mfsession_Release(IMFMediaSession *iface) { - mfsession *This = impl_from_IMFMediaSession(iface); - ULONG ref = InterlockedDecrement(&This->ref); + struct media_session *session = impl_from_IMFMediaSession(iface); + ULONG refcount = InterlockedDecrement(&session->refcount);
- TRACE("(%p) ref=%u\n", This, ref); + TRACE("(%p) refcount=%u\n", iface, refcount);
- if (!ref) + if (!refcount) { - HeapFree(GetProcessHeap(), 0, This); + if (session->event_queue) + IMFMediaEventQueue_Release(session->event_queue); + heap_free(session); }
- return ref; + return refcount; }
static HRESULT WINAPI mfsession_GetEvent(IMFMediaSession *iface, DWORD flags, IMFMediaEvent **event) { - mfsession *This = impl_from_IMFMediaSession(iface); + struct media_session *session = impl_from_IMFMediaSession(iface);
- FIXME("(%p)->(%#x, %p)\n", This, flags, event); + TRACE("(%p)->(%#x, %p)\n", iface, flags, event);
- return E_NOTIMPL; + return IMFMediaEventQueue_GetEvent(session->event_queue, flags, event); }
static HRESULT WINAPI mfsession_BeginGetEvent(IMFMediaSession *iface, IMFAsyncCallback *callback, IUnknown *state) { - mfsession *This = impl_from_IMFMediaSession(iface); + struct media_session *session = impl_from_IMFMediaSession(iface);
- FIXME("(%p)->(%p, %p)\n", This, callback, state); + TRACE("(%p)->(%p, %p)\n", iface, callback, state);
- return E_NOTIMPL; + return IMFMediaEventQueue_BeginGetEvent(session->event_queue, callback, state); }
static HRESULT WINAPI mfsession_EndGetEvent(IMFMediaSession *iface, IMFAsyncResult *result, IMFMediaEvent **event) { - mfsession *This = impl_from_IMFMediaSession(iface); + struct media_session *session = impl_from_IMFMediaSession(iface);
- FIXME("(%p)->(%p, %p)\n", This, result, event); + TRACE("(%p)->(%p, %p)\n", iface, result, event);
- return E_NOTIMPL; + return IMFMediaEventQueue_EndGetEvent(session->event_queue, result, event); }
static HRESULT WINAPI mfsession_QueueEvent(IMFMediaSession *iface, MediaEventType event_type, REFGUID ext_type, HRESULT hr, const PROPVARIANT *value) { - mfsession *This = impl_from_IMFMediaSession(iface); + struct media_session *session = impl_from_IMFMediaSession(iface);
- FIXME("(%p)->(%d, %s, %#x, %p)\n", This, event_type, debugstr_guid(ext_type), hr, value); + TRACE("(%p)->(%d, %s, %#x, %p)\n", iface, event_type, debugstr_guid(ext_type), hr, value);
- return E_NOTIMPL; + return IMFMediaEventQueue_QueueEventParamVar(session->event_queue, event_type, ext_type, hr, value); }
static HRESULT WINAPI mfsession_SetTopology(IMFMediaSession *iface, DWORD flags, IMFTopology *topology) { - mfsession *This = impl_from_IMFMediaSession(iface); - - FIXME("(%p)->(%#x, %p)\n", This, flags, topology); + FIXME("(%p)->(%#x, %p)\n", iface, flags, topology);
return E_NOTIMPL; }
static HRESULT WINAPI mfsession_ClearTopologies(IMFMediaSession *iface) { - mfsession *This = impl_from_IMFMediaSession(iface); - - FIXME("(%p)\n", This); + FIXME("(%p)\n", iface);
return E_NOTIMPL; }
static HRESULT WINAPI mfsession_Start(IMFMediaSession *iface, const GUID *format, const PROPVARIANT *start) { - mfsession *This = impl_from_IMFMediaSession(iface); - - FIXME("(%p)->(%s, %p)\n", This, debugstr_guid(format), start); + FIXME("(%p)->(%s, %p)\n", iface, debugstr_guid(format), start);
return E_NOTIMPL; }
static HRESULT WINAPI mfsession_Pause(IMFMediaSession *iface) { - mfsession *This = impl_from_IMFMediaSession(iface); - - FIXME("(%p)\n", This); + FIXME("(%p)\n", iface);
return E_NOTIMPL; }
static HRESULT WINAPI mfsession_Stop(IMFMediaSession *iface) { - mfsession *This = impl_from_IMFMediaSession(iface); - - FIXME("(%p)\n", This); + FIXME("(%p)\n", iface);
return E_NOTIMPL; }
static HRESULT WINAPI mfsession_Close(IMFMediaSession *iface) { - mfsession *This = impl_from_IMFMediaSession(iface); - - FIXME("(%p)\n", This); + FIXME("(%p)\n", iface);
return S_OK; }
static HRESULT WINAPI mfsession_Shutdown(IMFMediaSession *iface) { - mfsession *This = impl_from_IMFMediaSession(iface); - - FIXME("(%p)\n", This); + FIXME("(%p)\n", iface);
return E_NOTIMPL; }
static HRESULT WINAPI mfsession_GetClock(IMFMediaSession *iface, IMFClock **clock) { - mfsession *This = impl_from_IMFMediaSession(iface); - - FIXME("(%p)->(%p)\n", This, clock); + FIXME("(%p)->(%p)\n", iface, clock);
return E_NOTIMPL; }
static HRESULT WINAPI mfsession_GetSessionCapabilities(IMFMediaSession *iface, DWORD *caps) { - mfsession *This = impl_from_IMFMediaSession(iface); - - FIXME("(%p)->(%p)\n", This, caps); + FIXME("(%p)->(%p)\n", iface, caps);
return E_NOTIMPL; }
static HRESULT WINAPI mfsession_GetFullTopology(IMFMediaSession *iface, DWORD flags, TOPOID id, IMFTopology **topology) { - mfsession *This = impl_from_IMFMediaSession(iface); - - FIXME("(%p)->(%#x, %s, %p)\n", This, flags, wine_dbgstr_longlong(id), topology); + FIXME("(%p)->(%#x, %s, %p)\n", iface, flags, wine_dbgstr_longlong(id), topology);
return E_NOTIMPL; } @@ -237,26 +219,29 @@ static const IMFMediaSessionVtbl mfmediasessionvtbl = };
/*********************************************************************** - * MFCreateTopology (mf.@) + * MFCreateMediaSession (mf.@) */ HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **session) { - mfsession *object; + struct media_session *object; + HRESULT hr;
TRACE("(%p, %p)\n", config, session);
- if (!session) - return E_POINTER; - if (config) FIXME("session configuration ignored\n");
- object = HeapAlloc(GetProcessHeap(), 0, sizeof(*object)); + object = heap_alloc_zero(sizeof(*object)); if (!object) return E_OUTOFMEMORY;
object->IMFMediaSession_iface.lpVtbl = &mfmediasessionvtbl; - object->ref = 1; + object->refcount = 1; + if (FAILED(hr = MFCreateEventQueue(&object->event_queue))) + { + IMFMediaSession_Release(&object->IMFMediaSession_iface); + return hr; + }
*session = &object->IMFMediaSession_iface;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/mf.spec | 2 +- dlls/mf/tests/mf.c | 15 ++++++++ dlls/mf/topology.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++ include/mfidl.idl | 12 ++++++ 4 files changed, 121 insertions(+), 1 deletion(-)
diff --git a/dlls/mf/mf.spec b/dlls/mf/mf.spec index b2e0b9bea6..64f0b1db83 100644 --- a/dlls/mf/mf.spec +++ b/dlls/mf/mf.spec @@ -59,7 +59,7 @@ @ stub MFCreateSimpleTypeHandler @ stdcall MFCreateSourceResolver(ptr) mfplat.MFCreateSourceResolver @ stub MFCreateStandardQualityManager -@ stub MFCreateTopoLoader +@ stdcall MFCreateTopoLoader(ptr) @ stdcall MFCreateTopology(ptr) @ stdcall MFCreateTopologyNode(long ptr) @ stub MFCreateTranscodeProfile diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 150314933d..91ddd60842 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -469,9 +469,24 @@ static void test_media_session(void) ok(hr == S_OK, "Shutdown failure, hr %#x.\n", hr); }
+static void test_topology_loader(void) +{ + IMFTopoLoader *loader; + HRESULT hr; + + hr = MFCreateTopoLoader(NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + hr = MFCreateTopoLoader(&loader); + ok(hr == S_OK, "Failed to create topology loader, hr %#x.\n", hr); + + IMFTopoLoader_Release(loader); +} + START_TEST(mf) { test_topology(); + test_topology_loader(); test_MFGetService(); test_MFCreateSequencerSource(); test_media_session(); diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index 3b4a2e1a58..84387ae0cc 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -52,6 +52,12 @@ struct topology_node TOPOID id; };
+struct topology_loader +{ + IMFTopoLoader IMFTopoLoader_iface; + LONG refcount; +}; + struct seq_source { IMFSequencerSource IMFSequencerSource_iface; @@ -68,6 +74,11 @@ static struct topology_node *impl_from_IMFTopologyNode(IMFTopologyNode *iface) return CONTAINING_RECORD(iface, struct topology_node, IMFTopologyNode_iface); }
+static struct topology_loader *impl_from_IMFTopoLoader(IMFTopoLoader *iface) +{ + return CONTAINING_RECORD(iface, struct topology_loader, IMFTopoLoader_iface); +} + static struct seq_source *impl_from_IMFSequencerSource(IMFSequencerSource *iface) { return CONTAINING_RECORD(iface, struct seq_source, IMFSequencerSource_iface); @@ -1212,6 +1223,88 @@ HRESULT WINAPI MFCreateTopologyNode(MF_TOPOLOGY_TYPE node_type, IMFTopologyNode return S_OK; }
+static HRESULT WINAPI topology_loader_QueryInterface(IMFTopoLoader *iface, REFIID riid, void **out) +{ + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out); + + if (IsEqualIID(riid, &IID_IMFTopoLoader) || + IsEqualIID(riid, &IID_IUnknown)) + { + *out = iface; + IMFTopoLoader_AddRef(iface); + return S_OK; + } + + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI topology_loader_AddRef(IMFTopoLoader *iface) +{ + struct topology_loader *loader = impl_from_IMFTopoLoader(iface); + ULONG refcount = InterlockedIncrement(&loader->refcount); + + TRACE("(%p) refcount=%u\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI topology_loader_Release(IMFTopoLoader *iface) +{ + struct topology_loader *loader = impl_from_IMFTopoLoader(iface); + ULONG refcount = InterlockedDecrement(&loader->refcount); + + TRACE("(%p) refcount=%u\n", iface, refcount); + + if (!refcount) + { + heap_free(loader); + } + + return refcount; +} + +static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology, + IMFTopology **output_topology, IMFTopology *current_topology) +{ + FIXME("%p, %p, %p, %p.\n", iface, input_topology, output_topology, current_topology); + + return E_NOTIMPL; +} + +static const IMFTopoLoaderVtbl topologyloadervtbl = +{ + topology_loader_QueryInterface, + topology_loader_AddRef, + topology_loader_Release, + topology_loader_Load, +}; + +/*********************************************************************** + * MFCreateTopoLoader (mf.@) + */ +HRESULT WINAPI MFCreateTopoLoader(IMFTopoLoader **loader) +{ + struct topology_loader *object; + + TRACE("%p.\n", loader); + + if (!loader) + return E_POINTER; + + object = heap_alloc(sizeof(*object)); + if (!object) + return E_OUTOFMEMORY; + + object->IMFTopoLoader_iface.lpVtbl = &topologyloadervtbl; + object->refcount = 1; + + *loader = &object->IMFTopoLoader_iface; + + return S_OK; +} + static HRESULT WINAPI seq_source_QueryInterface(IMFSequencerSource *iface, REFIID riid, void **out) { struct seq_source *seq_source = impl_from_IMFSequencerSource(iface); diff --git a/include/mfidl.idl b/include/mfidl.idl index 82a87bab36..831bc357df 100644 --- a/include/mfidl.idl +++ b/include/mfidl.idl @@ -116,6 +116,17 @@ interface IMFTopology : IMFAttributes HRESULT GetOutputNodeCollection([out] IMFCollection **collection); }
+[ + object, + uuid(de9a6157-f660-4643-b56a-df9f7998c7cd), + local, +] +interface IMFTopoLoader : IUnknown +{ + HRESULT Load([in] IMFTopology *input_topology, [out] IMFTopology **output_topology, + [in] IMFTopology *current_topology); +} + [ object, uuid(90377834-21d0-4dee-8214-ba2e3e6c1127), @@ -313,6 +324,7 @@ cpp_quote("HRESULT WINAPI MFCreateStreamDescriptor(DWORD identifier, DWORD cMedi cpp_quote(" IMFMediaType **types, IMFStreamDescriptor **descriptor);") cpp_quote("HRESULT WINAPI MFCreateTopology(IMFTopology **topology);") cpp_quote("HRESULT WINAPI MFCreateTopologyNode(MF_TOPOLOGY_TYPE node_type, IMFTopologyNode **node);") +cpp_quote("HRESULT WINAPI MFCreateTopoLoader(IMFTopoLoader **loader);") cpp_quote("HRESULT WINAPI MFGetSupportedMimeTypes(PROPVARIANT *array);") cpp_quote("HRESULT WINAPI MFGetService(IUnknown *object, REFGUID service, REFIID iid, void **obj);") cpp_quote("MFTIME WINAPI MFGetSystemTime(void);")
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/tests/mf.c | 23 +++++++++++++++++++++-- dlls/mf/topology.c | 30 ++++++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 4 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 91ddd60842..c56428d27e 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -37,7 +37,7 @@ static void test_topology(void) { IMFCollection *collection, *collection2; IMFTopologyNode *node, *node2, *node3; - IMFTopology *topology; + IMFTopology *topology, *topology2; DWORD size; WORD count; HRESULT hr; @@ -47,7 +47,26 @@ static void test_topology(void) ok(hr == E_POINTER, "got %#x\n", hr);
hr = MFCreateTopology(&topology); - ok(hr == S_OK, "got %#x\n", hr); + ok(hr == S_OK, "Failed to create topology, hr %#x.\n", hr); + hr = IMFTopology_GetTopologyID(topology, &id); + ok(hr == S_OK, "Failed to get id, hr %#x.\n", hr); + ok(id == 1, "Unexpected id.\n"); + + hr = MFCreateTopology(&topology2); + ok(hr == S_OK, "Failed to create topology, hr %#x.\n", hr); + hr = IMFTopology_GetTopologyID(topology2, &id); + ok(hr == S_OK, "Failed to get id, hr %#x.\n", hr); + ok(id == 2, "Unexpected id.\n"); + + IMFTopology_Release(topology); + + hr = MFCreateTopology(&topology); + ok(hr == S_OK, "Failed to create topology, hr %#x.\n", hr); + hr = IMFTopology_GetTopologyID(topology, &id); + ok(hr == S_OK, "Failed to get id, hr %#x.\n", hr); + ok(id == 3, "Unexpected id.\n"); + + IMFTopology_Release(topology2);
hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, NULL); ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index 84387ae0cc..543e08fb24 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -15,7 +15,9 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ + #include "config.h" +#include "wine/port.h"
#include <stdarg.h>
@@ -34,6 +36,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
static LONG next_node_id; +static TOPOID next_topology_id;
struct topology { @@ -41,6 +44,7 @@ struct topology LONG refcount; IMFAttributes *attributes; IMFCollection *nodes; + TOPOID id; };
struct topology_node @@ -412,9 +416,16 @@ static HRESULT WINAPI topology_CopyAllItems(IMFTopology *iface, IMFAttributes *d
static HRESULT WINAPI topology_GetTopologyID(IMFTopology *iface, TOPOID *id) { - FIXME("(%p)->(%p)\n", iface, id); + struct topology *topology = impl_from_IMFTopology(iface);
- return E_NOTIMPL; + TRACE("(%p)->(%p)\n", iface, id); + + if (!id) + return E_POINTER; + + *id = topology->id; + + return S_OK; }
static HRESULT topology_get_node_by_id(const struct topology *topology, TOPOID id, IMFTopologyNode **node) @@ -654,6 +665,19 @@ static const IMFTopologyVtbl topologyvtbl = topology_GetOutputNodeCollection, };
+static TOPOID topology_generate_id(void) +{ + TOPOID old; + + do + { + old = next_topology_id; + } + while (interlocked_cmpxchg64((LONG64 *)&next_topology_id, old + 1, old) != old); + + return next_topology_id; +} + /*********************************************************************** * MFCreateTopology (mf.@) */ @@ -684,6 +708,8 @@ HRESULT WINAPI MFCreateTopology(IMFTopology **topology) return hr; }
+ object->id = topology_generate_id(); + *topology = &object->IMFTopology_iface;
return S_OK;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfreadwrite/main.c | 219 +++++++++++++++++++++++++++++- dlls/mfreadwrite/mfreadwrite.spec | 2 +- include/mfidl.idl | 23 ++++ include/mfreadwrite.idl | 2 + 4 files changed, 241 insertions(+), 5 deletions(-)
diff --git a/dlls/mfreadwrite/main.c b/dlls/mfreadwrite/main.c index dcacd9a751..a83ece0359 100644 --- a/dlls/mfreadwrite/main.c +++ b/dlls/mfreadwrite/main.c @@ -27,8 +27,8 @@ #include "initguid.h" #include "ole2.h" #include "rpcproxy.h" -#include "mfreadwrite.h" #include "mfidl.h" +#include "mfreadwrite.h"
#include "wine/debug.h" #include "wine/heap.h" @@ -77,11 +77,22 @@ typedef struct _srcreader LONG ref; } srcreader;
+struct sink_writer +{ + IMFSinkWriter IMFSinkWriter_iface; + LONG refcount; +}; + static inline srcreader *impl_from_IMFSourceReader(IMFSourceReader *iface) { return CONTAINING_RECORD(iface, srcreader, IMFSourceReader_iface); }
+static inline struct sink_writer *impl_from_IMFSinkWriter(IMFSinkWriter *iface) +{ + return CONTAINING_RECORD(iface, struct sink_writer, IMFSinkWriter_iface); +} + static HRESULT WINAPI src_reader_QueryInterface(IMFSourceReader *iface, REFIID riid, void **out) { srcreader *This = impl_from_IMFSourceReader(iface); @@ -249,6 +260,191 @@ static HRESULT create_source_reader_from_stream(IMFByteStream *stream, IMFAttrib return create_source_reader_from_source(NULL, attributes, riid, out); }
+static HRESULT WINAPI sink_writer_QueryInterface(IMFSinkWriter *iface, REFIID riid, void **out) +{ + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out); + + if (IsEqualIID(riid, &IID_IMFSinkWriter) || + IsEqualIID(riid, &IID_IUnknown)) + { + *out = iface; + IMFSinkWriter_AddRef(iface); + return S_OK; + } + + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI sink_writer_AddRef(IMFSinkWriter *iface) +{ + struct sink_writer *writer = impl_from_IMFSinkWriter(iface); + ULONG refcount = InterlockedIncrement(&writer->refcount); + + TRACE("%p, %u.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI sink_writer_Release(IMFSinkWriter *iface) +{ + struct sink_writer *writer = impl_from_IMFSinkWriter(iface); + ULONG refcount = InterlockedDecrement(&writer->refcount); + + TRACE("%p, %u.\n", iface, refcount); + + if (!refcount) + { + heap_free(writer); + } + + return refcount; +} + +static HRESULT WINAPI sink_writer_AddStream(IMFSinkWriter *iface, IMFMediaType *type, DWORD *index) +{ + FIXME("%p, %p, %p.\n", iface, type, index); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sink_writer_SetInputMediaType(IMFSinkWriter *iface, DWORD index, IMFMediaType *type, + IMFAttributes *parameters) +{ + FIXME("%p, %u, %p, %p.\n", iface, index, type, parameters); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sink_writer_BeginWriting(IMFSinkWriter *iface) +{ + FIXME("%p.\n", iface); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sink_writer_WriteSample(IMFSinkWriter *iface, DWORD index, IMFSample *sample) +{ + FIXME("%p, %u, %p.\n", iface, index, sample); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sink_writer_SendStreamTick(IMFSinkWriter *iface, DWORD index, LONGLONG timestamp) +{ + FIXME("%p, %u, %s.\n", iface, index, wine_dbgstr_longlong(timestamp)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sink_writer_PlaceMarker(IMFSinkWriter *iface, DWORD index, void *context) +{ + FIXME("%p, %u, %p.\n", iface, index, context); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sink_writer_NotifyEndOfSegment(IMFSinkWriter *iface, DWORD index) +{ + FIXME("%p, %u.\n", iface, index); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sink_writer_Flush(IMFSinkWriter *iface, DWORD index) +{ + FIXME("%p, %u.\n", iface, index); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sink_writer_Finalize(IMFSinkWriter *iface) +{ + FIXME("%p.\n", iface); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sink_writer_GetServiceForStream(IMFSinkWriter *iface, DWORD index, REFGUID service, + REFIID riid, void **object) +{ + FIXME("%p, %u, %s, %s, %p.\n", iface, index, debugstr_guid(service), debugstr_guid(riid), object); + + return E_NOTIMPL; +} + +static HRESULT WINAPI sink_writer_GetStatistics(IMFSinkWriter *iface, DWORD index, MF_SINK_WRITER_STATISTICS *stats) +{ + FIXME("%p, %u, %p.\n", iface, index, stats); + + return E_NOTIMPL; +} + +static const IMFSinkWriterVtbl sink_writer_vtbl = +{ + sink_writer_QueryInterface, + sink_writer_AddRef, + sink_writer_Release, + sink_writer_AddStream, + sink_writer_SetInputMediaType, + sink_writer_BeginWriting, + sink_writer_WriteSample, + sink_writer_SendStreamTick, + sink_writer_PlaceMarker, + sink_writer_NotifyEndOfSegment, + sink_writer_Flush, + sink_writer_Finalize, + sink_writer_GetServiceForStream, + sink_writer_GetStatistics, +}; + +static HRESULT create_sink_writer_from_sink(IMFMediaSink *sink, IMFAttributes *attributes, + REFIID riid, void **out) +{ + struct sink_writer *object; + HRESULT hr; + + object = heap_alloc(sizeof(*object)); + if (!object) + return E_OUTOFMEMORY; + + object->IMFSinkWriter_iface.lpVtbl = &sink_writer_vtbl; + object->refcount = 1; + + hr = IMFSinkWriter_QueryInterface(&object->IMFSinkWriter_iface, riid, out); + IMFSinkWriter_Release(&object->IMFSinkWriter_iface); + return hr; +} + +static HRESULT create_sink_writer_from_stream(IMFByteStream *stream, IMFAttributes *attributes, + REFIID riid, void **out) +{ + struct sink_writer *object; + HRESULT hr; + + object = heap_alloc(sizeof(*object)); + if (!object) + return E_OUTOFMEMORY; + + object->IMFSinkWriter_iface.lpVtbl = &sink_writer_vtbl; + object->refcount = 1; + + hr = IMFSinkWriter_QueryInterface(&object->IMFSinkWriter_iface, riid, out); + IMFSinkWriter_Release(&object->IMFSinkWriter_iface); + return hr; +} + +/*********************************************************************** + * MFCreateSinkWriterFromMediaSink (mfreadwrite.@) + */ +HRESULT WINAPI MFCreateSinkWriterFromMediaSink(IMFMediaSink *sink, IMFAttributes *attributes, IMFSinkWriter **writer) +{ + TRACE("%p, %p, %p.\n", sink, attributes, writer); + + return create_sink_writer_from_sink(sink, attributes, &IID_IMFSinkWriter, (void **)writer); +} + /*********************************************************************** * MFCreateSourceReaderFromByteStream (mfreadwrite.@) */ @@ -334,9 +530,24 @@ static HRESULT WINAPI readwrite_factory_CreateInstanceFromObject(IMFReadWriteCla } else if (IsEqualGUID(clsid, &CLSID_MFSinkWriter)) { - FIXME("MFSinkWriter is not supported.\n"); - *out = NULL; - return E_NOTIMPL; + IMFByteStream *stream = NULL; + IMFMediaSink *sink = NULL; + + hr = IUnknown_QueryInterface(unk, &IID_IMFByteStream, (void **)&stream); + if (FAILED(hr)) + hr = IUnknown_QueryInterface(unk, &IID_IMFMediaSink, (void **)&sink); + + if (stream) + hr = create_sink_writer_from_stream(stream, attributes, riid, out); + else if (sink) + hr = create_sink_writer_from_sink(sink, attributes, riid, out); + + if (sink) + IMFMediaSink_Release(sink); + if (stream) + IMFByteStream_Release(stream); + + return hr; } else { diff --git a/dlls/mfreadwrite/mfreadwrite.spec b/dlls/mfreadwrite/mfreadwrite.spec index ad61646718..d8ed6942eb 100644 --- a/dlls/mfreadwrite/mfreadwrite.spec +++ b/dlls/mfreadwrite/mfreadwrite.spec @@ -2,7 +2,7 @@ @ stdcall -private DllGetClassObject(ptr ptr ptr) @ stdcall -private DllRegisterServer() @ stdcall -private DllUnregisterServer() -@ stub MFCreateSinkWriterFromMediaSink +@ stdcall MFCreateSinkWriterFromMediaSink(ptr ptr ptr) @ stub MFCreateSinkWriterFromURL @ stdcall MFCreateSourceReaderFromByteStream(ptr ptr ptr) @ stdcall MFCreateSourceReaderFromMediaSource(ptr ptr ptr) diff --git a/include/mfidl.idl b/include/mfidl.idl index 831bc357df..c8f011bb77 100644 --- a/include/mfidl.idl +++ b/include/mfidl.idl @@ -357,6 +357,29 @@ interface IMFMediaSource : IMFMediaEventGenerator HRESULT Shutdown(); }
+interface IMFStreamSink; +interface IMFPresentationClock; + +[ + object, + uuid(6ef2a660-47c0-4666-b13d-cbb717f2fa2c) +] +interface IMFMediaSink : IUnknown +{ + HRESULT GetCharacteristics([out] DWORD *characteristics); + HRESULT AddStreamSink( + [in] DWORD stream_sink_id, + [in] IMFMediaType *media_type, + [out] IMFStreamSink **stream_sink); + HRESULT RemoveStreamSink([in] DWORD stream_sink_id); + HRESULT GetStreamSinkCount([out] DWORD *count); + HRESULT GetStreamSinkByIndex([in] DWORD index, [out] IMFStreamSink **sink); + HRESULT GetStreamSinkById([in] DWORD stream_sink_id, [out] IMFStreamSink **sink); + HRESULT SetPresentationClock([in] IMFPresentationClock *clock); + HRESULT GetPresentationClock([out] IMFPresentationClock **clock); + HRESULT Shutdown(); +} + cpp_quote("#define MF_RESOLUTION_MEDIASOURCE 0x00000001") cpp_quote("#define MF_RESOLUTION_BYTESTREAM 0x00000002") cpp_quote("#define MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE 0x00000010") diff --git a/include/mfreadwrite.idl b/include/mfreadwrite.idl index 8547b80e02..82f67d499c 100644 --- a/include/mfreadwrite.idl +++ b/include/mfreadwrite.idl @@ -145,6 +145,8 @@ interface IMFReadWriteClassFactory : IUnknown [in] REFIID riid, [out, iid_is(riid)] void **object ); }
+cpp_quote( "HRESULT WINAPI MFCreateSinkWriterFromMediaSink(IMFMediaSink *sink, IMFAttributes *attributes," ) +cpp_quote( " IMFSinkWriter **writer);" ) cpp_quote( "HRESULT WINAPI MFCreateSourceReaderFromByteStream(IMFByteStream *stream, IMFAttributes *attributes," ) cpp_quote( " IMFSourceReader **reader);" ) cpp_quote( "HRESULT WINAPI MFCreateSourceReaderFromMediaSource(IMFMediaSource *source, IMFAttributes *attributes," )