Wine incorrectly inserts a sample copier. D3D awareness is handled per node, and each node will have their own sample allocator created from the D3D device manager provided by the session.
-- v6: mf/tests: Test device manager handling in the topology loader. mf/tests: Test D3D awareness handling in the topology loader. mf/tests: Split topology loader tests to a new file. mf/tests: Fix printf format warning. include: Add MFTOPOLOGY_DXVA_MODE enum definition.
From: Rémi Bernon rbernon@codeweavers.com
--- include/mfidl.idl | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/include/mfidl.idl b/include/mfidl.idl index b3201b12d84..666af53c6e3 100644 --- a/include/mfidl.idl +++ b/include/mfidl.idl @@ -131,6 +131,13 @@ typedef enum _MF_VIDEO_PROCESSOR_ALGORITHM_TYPE MF_VIDEO_PROCESSOR_ALGORITHM_MRF_CRF_444 = 1, } MF_VIDEO_PROCESSOR_ALGORITHM_TYPE;
+typedef enum MFTOPOLOGY_DXVA_MODE +{ + MFTOPOLOGY_DXVA_DEFAULT = 0, + MFTOPOLOGY_DXVA_NONE = 1, + MFTOPOLOGY_DXVA_FULL = 2, +} MFTOPOLOGY_DXVA_MODE; + [ object, uuid(2eb1e945-18b8-4139-9b1a-d5d584818530),
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/tests/mf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index fece60d37a7..b3cd355f49d 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -4179,7 +4179,7 @@ static void test_topology_loader(void) { IMFTopology_GetTopologyID(topology, &oldtopoid); IMFTopology_GetTopologyID(full_topology, &newtopoid); - ok(oldtopoid == newtopoid, "Expected the same topology id. %llu == %llu\n", oldtopoid, newtopoid); + ok(oldtopoid == newtopoid, "Expected the same topology id. %I64u == %I64u\n", oldtopoid, newtopoid); ok(topology != full_topology, "Expected a different object for the resolved topology.\n");
hr = IMFTopology_GetCount(full_topology, &count); @@ -4331,7 +4331,7 @@ todo_wine { ok(full_topology != topology2, "Unexpected instance.\n"); IMFTopology_GetTopologyID(topology2, &oldtopoid); IMFTopology_GetTopologyID(full_topology, &newtopoid); - ok(oldtopoid == newtopoid, "Expected the same topology id. %llu == %llu\n", oldtopoid, newtopoid); + ok(oldtopoid == newtopoid, "Expected the same topology id. %I64u == %I64u\n", oldtopoid, newtopoid); hr = IMFTopology_GetUINT32(topology2, &IID_IMFTopology, &value); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/tests/Makefile.in | 1 + dlls/mf/tests/mf.c | 5369 ++++++++++++------------------------- dlls/mf/tests/topology.c | 2688 +++++++++++++++++++ 3 files changed, 4462 insertions(+), 3596 deletions(-) create mode 100644 dlls/mf/tests/topology.c
diff --git a/dlls/mf/tests/Makefile.in b/dlls/mf/tests/Makefile.in index 3bb0c66de0a..598a002260b 100644 --- a/dlls/mf/tests/Makefile.in +++ b/dlls/mf/tests/Makefile.in @@ -4,4 +4,5 @@ IMPORTS = mf mfplat dmoguids mfuuid strmiids uuid wmcodecdspuuid ole32 user32 SOURCES = \ mf.c \ resource.rc \ + topology.c \ transform.c diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index b3cd355f49d..3f75ca943c8 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -419,12 +419,11 @@ static IMFMediaSource *create_test_source(IMFPresentationDescriptor *pd) return &source->IMFMediaSource_iface; }
-static HRESULT WINAPI test_unk_QueryInterface(IUnknown *iface, REFIID riid, void **obj) +static HRESULT WINAPI test_getservice_QI(IMFGetService *iface, REFIID riid, void **obj) { - if (IsEqualIID(riid, &IID_IUnknown)) + if (IsEqualIID(riid, &IID_IMFGetService) || IsEqualIID(riid, &IID_IUnknown)) { *obj = iface; - IUnknown_AddRef(iface); return S_OK; }
@@ -432,1207 +431,1343 @@ static HRESULT WINAPI test_unk_QueryInterface(IUnknown *iface, REFIID riid, void return E_NOINTERFACE; }
-static ULONG WINAPI test_unk_AddRef(IUnknown *iface) +static ULONG WINAPI test_getservice_AddRef(IMFGetService *iface) { return 2; }
-static ULONG WINAPI test_unk_Release(IUnknown *iface) +static ULONG WINAPI test_getservice_Release(IMFGetService *iface) { return 1; }
-static const IUnknownVtbl test_unk_vtbl = +static HRESULT WINAPI test_getservice_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj) { - test_unk_QueryInterface, - test_unk_AddRef, - test_unk_Release, -}; + *obj = (void *)0xdeadbeef; + return 0x83eddead; +}
-static void test_topology(void) +static const IMFGetServiceVtbl testmfgetservicevtbl = { - IMFMediaType *mediatype, *mediatype2, *mediatype3; - IMFCollection *collection, *collection2; - IUnknown test_unk2 = { &test_unk_vtbl }; - IUnknown test_unk = { &test_unk_vtbl }; - IMFTopologyNode *node, *node2, *node3; - IMFTopology *topology, *topology2; - DWORD size, io_count, index; - MF_TOPOLOGY_TYPE node_type; - IUnknown *object; - WORD node_count; - UINT32 count; - HRESULT hr; - TOPOID id; - LONG ref; - - hr = MFCreateTopology(NULL); - ok(hr == E_POINTER, "got %#lx\n", hr); + test_getservice_QI, + test_getservice_AddRef, + test_getservice_Release, + test_getservice_GetService, +};
- hr = MFCreateTopology(&topology); - ok(hr == S_OK, "Failed to create topology, hr %#lx.\n", hr); - hr = IMFTopology_GetTopologyID(topology, &id); - ok(hr == S_OK, "Failed to get id, hr %#lx.\n", hr); - ok(id == 1, "Unexpected id.\n"); +static IMFGetService test_getservice = { &testmfgetservicevtbl };
- hr = MFCreateTopology(&topology2); - ok(hr == S_OK, "Failed to create topology, hr %#lx.\n", hr); - hr = IMFTopology_GetTopologyID(topology2, &id); - ok(hr == S_OK, "Failed to get id, hr %#lx.\n", hr); - ok(id == 2, "Unexpected id.\n"); +static HRESULT WINAPI testservice_QI(IUnknown *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + return S_OK; + }
- ref = IMFTopology_Release(topology); - ok(ref == 0, "Release returned %ld\n", ref); + *obj = NULL;
- hr = MFCreateTopology(&topology); - ok(hr == S_OK, "Failed to create topology, hr %#lx.\n", hr); - hr = IMFTopology_GetTopologyID(topology, &id); - ok(hr == S_OK, "Failed to get id, hr %#lx.\n", hr); - ok(id == 3, "Unexpected id.\n"); + if (IsEqualIID(riid, &IID_IMFGetService)) + return 0x82eddead;
- ref = IMFTopology_Release(topology2); - ok(ref == 0, "Release returned %ld\n", ref); + return E_NOINTERFACE; +}
- /* No attributes by default. */ - for (node_type = MF_TOPOLOGY_OUTPUT_NODE; node_type < MF_TOPOLOGY_TEE_NODE; ++node_type) +static HRESULT WINAPI testservice2_QI(IUnknown *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IUnknown)) { - hr = MFCreateTopologyNode(node_type, &node); - ok(hr == S_OK, "Failed to create a node for type %d, hr %#lx.\n", node_type, hr); - hr = IMFTopologyNode_GetCount(node, &count); - ok(hr == S_OK, "Failed to get attribute count, hr %#lx.\n", hr); - ok(!count, "Unexpected attribute count %u.\n", count); - ref = IMFTopologyNode_Release(node); - ok(ref == 0, "Release returned %ld\n", ref); + *obj = iface; + return S_OK; }
- hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, NULL); - ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + if (IsEqualIID(riid, &IID_IMFGetService)) + { + *obj = &test_getservice; + return S_OK; + }
- hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + *obj = NULL; + return E_NOINTERFACE; +}
- hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &node2); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); +static ULONG WINAPI testservice_AddRef(IUnknown *iface) +{ + return 2; +}
- hr = IMFTopologyNode_GetTopoNodeID(node, &id); - ok(hr == S_OK, "Failed to get node id, hr %#lx.\n", hr); - ok(((id >> 32) == GetCurrentProcessId()) && !!(id & 0xffff), "Unexpected node id %s.\n", wine_dbgstr_longlong(id)); +static ULONG WINAPI testservice_Release(IUnknown *iface) +{ + return 1; +}
- hr = IMFTopologyNode_SetTopoNodeID(node2, id); - ok(hr == S_OK, "Failed to set node id, hr %#lx.\n", hr); +static const IUnknownVtbl testservicevtbl = +{ + testservice_QI, + testservice_AddRef, + testservice_Release, +};
- hr = IMFTopology_GetNodeCount(topology, NULL); - ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); +static const IUnknownVtbl testservice2vtbl = +{ + testservice2_QI, + testservice_AddRef, + testservice_Release, +};
- hr = IMFTopology_AddNode(topology, NULL); - ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); +static IUnknown testservice = { &testservicevtbl }; +static IUnknown testservice2 = { &testservice2vtbl };
- node_count = 1; - hr = IMFTopology_GetNodeCount(topology, &node_count); - ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); - ok(node_count == 0, "Unexpected node count %u.\n", node_count); +static void test_MFGetService(void) +{ + IUnknown *unk; + HRESULT hr;
- /* Same id, different nodes. */ - hr = IMFTopology_AddNode(topology, node); - ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + hr = MFGetService(NULL, NULL, NULL, NULL); + ok(hr == E_POINTER, "Unexpected return value %#lx.\n", hr);
- node_count = 0; - hr = IMFTopology_GetNodeCount(topology, &node_count); - ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); - ok(node_count == 1, "Unexpected node count %u.\n", node_count); + unk = (void *)0xdeadbeef; + hr = MFGetService(NULL, NULL, NULL, (void **)&unk); + ok(hr == E_POINTER, "Unexpected return value %#lx.\n", hr); + ok(unk == (void *)0xdeadbeef, "Unexpected out object.\n");
- hr = IMFTopology_AddNode(topology, node2); - ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); - ref = IMFTopologyNode_Release(node2); - ok(ref == 0, "Release returned %ld\n", ref); + hr = MFGetService(&testservice, NULL, NULL, NULL); + ok(hr == 0x82eddead, "Unexpected return value %#lx.\n", hr);
- hr = IMFTopology_GetNodeByID(topology, id, &node2); - ok(hr == S_OK, "Failed to get a node, hr %#lx.\n", hr); - ok(node2 == node, "Unexpected node.\n"); - IMFTopologyNode_Release(node2); + unk = (void *)0xdeadbeef; + hr = MFGetService(&testservice, NULL, NULL, (void **)&unk); + ok(hr == 0x82eddead, "Unexpected return value %#lx.\n", hr); + ok(unk == (void *)0xdeadbeef, "Unexpected out object.\n");
- /* Change node id, add it again. */ - hr = IMFTopologyNode_SetTopoNodeID(node, ++id); - ok(hr == S_OK, "Failed to set node id, hr %#lx.\n", hr); + unk = NULL; + hr = MFGetService(&testservice2, NULL, NULL, (void **)&unk); + ok(hr == 0x83eddead, "Unexpected return value %#lx.\n", hr); + ok(unk == (void *)0xdeadbeef, "Unexpected out object.\n"); +}
- hr = IMFTopology_GetNodeByID(topology, id, &node2); - ok(hr == S_OK, "Failed to get a node, hr %#lx.\n", hr); - ok(node2 == node, "Unexpected node.\n"); - IMFTopologyNode_Release(node2); +static void test_sequencer_source(void) +{ + IMFSequencerSource *seq_source; + HRESULT hr; + LONG ref;
- hr = IMFTopology_GetNodeByID(topology, id + 1, &node2); - ok(hr == MF_E_NOT_FOUND, "Unexpected hr %#lx.\n", hr); + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Startup failure, hr %#lx.\n", hr);
- hr = IMFTopology_AddNode(topology, node); - ok(hr == E_INVALIDARG, "Failed to add a node, hr %#lx.\n", hr); + hr = MFCreateSequencerSource(NULL, &seq_source); + ok(hr == S_OK, "Failed to create sequencer source, hr %#lx.\n", hr);
- hr = IMFTopology_GetNode(topology, 0, &node2); - ok(hr == S_OK, "Failed to get a node, hr %#lx.\n", hr); - ok(node2 == node, "Unexpected node.\n"); - IMFTopologyNode_Release(node2); + check_interface(seq_source, &IID_IMFMediaSourceTopologyProvider, TRUE);
- hr = IMFTopology_GetNode(topology, 1, NULL); - ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + ref = IMFSequencerSource_Release(seq_source); + ok(ref == 0, "Release returned %ld\n", ref);
- hr = IMFTopology_GetNode(topology, 1, &node2); - ok(hr == MF_E_INVALIDINDEX, "Failed to get a node, hr %#lx.\n", hr); + hr = MFShutdown(); + ok(hr == S_OK, "Shutdown failure, hr %#lx.\n", hr); +}
- hr = IMFTopology_GetNode(topology, -2, &node2); - ok(hr == MF_E_INVALIDINDEX, "Failed to get a node, hr %#lx.\n", hr); +struct test_handler +{ + IMFMediaTypeHandler IMFMediaTypeHandler_iface;
- hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &node2); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); - hr = IMFTopology_AddNode(topology, node2); - ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); - ref = IMFTopologyNode_Release(node2); - ok(ref == 1, "Release returned %ld\n", ref); + ULONG set_current_count; + IMFMediaType *current_type; + IMFMediaType *invalid_type;
- node_count = 0; - hr = IMFTopology_GetNodeCount(topology, &node_count); - ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); - ok(node_count == 2, "Unexpected node count %u.\n", node_count); - - /* Remove with detached node, existing id. */ - hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &node2); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); - hr = IMFTopologyNode_SetTopoNodeID(node2, id); - ok(hr == S_OK, "Failed to set node id, hr %#lx.\n", hr); - hr = IMFTopology_RemoveNode(topology, node2); - ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); - ref = IMFTopologyNode_Release(node2); - ok(ref == 0, "Release returned %ld\n", ref); + ULONG enum_count; + ULONG media_types_count; + IMFMediaType **media_types; +};
- hr = IMFTopology_RemoveNode(topology, node); - ok(hr == S_OK, "Failed to remove a node, hr %#lx.\n", hr); +static struct test_handler *impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler *iface) +{ + return CONTAINING_RECORD(iface, struct test_handler, IMFMediaTypeHandler_iface); +}
- node_count = 0; - hr = IMFTopology_GetNodeCount(topology, &node_count); - ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); - ok(node_count == 1, "Unexpected node count %u.\n", node_count); +static HRESULT WINAPI test_handler_QueryInterface(IMFMediaTypeHandler *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IMFMediaTypeHandler) + || IsEqualIID(riid, &IID_IUnknown)) + { + IMFMediaTypeHandler_AddRef((*obj = iface)); + return S_OK; + }
- hr = IMFTopology_Clear(topology); - ok(hr == S_OK, "Failed to clear topology, hr %#lx.\n", hr); + *obj = NULL; + return E_NOINTERFACE; +}
- node_count = 1; - hr = IMFTopology_GetNodeCount(topology, &node_count); - ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); - ok(node_count == 0, "Unexpected node count %u.\n", node_count); +static ULONG WINAPI test_handler_AddRef(IMFMediaTypeHandler *iface) +{ + return 2; +}
- hr = IMFTopology_Clear(topology); - ok(hr == S_OK, "Failed to clear topology, hr %#lx.\n", hr); +static ULONG WINAPI test_handler_Release(IMFMediaTypeHandler *iface) +{ + return 1; +}
- hr = IMFTopologyNode_SetTopoNodeID(node, 123); - ok(hr == S_OK, "Failed to set node id, hr %#lx.\n", hr); +static HRESULT WINAPI test_handler_IsMediaTypeSupported(IMFMediaTypeHandler *iface, IMFMediaType *in_type, + IMFMediaType **out_type) +{ + struct test_handler *impl = impl_from_IMFMediaTypeHandler(iface); + BOOL result;
- ref = IMFTopologyNode_Release(node); - ok(ref == 0, "Release returned %ld\n", ref); + if (out_type) + *out_type = NULL;
- /* Change id for attached node. */ - hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + if (impl->invalid_type && IMFMediaType_Compare(impl->invalid_type, (IMFAttributes *)in_type, + MF_ATTRIBUTES_MATCH_OUR_ITEMS, &result) == S_OK && result) + return MF_E_INVALIDMEDIATYPE;
- hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &node2); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + if (!impl->current_type) + return S_OK;
- hr = IMFTopology_AddNode(topology, node); - ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + if (IMFMediaType_Compare(impl->current_type, (IMFAttributes *)in_type, + MF_ATTRIBUTES_MATCH_OUR_ITEMS, &result) == S_OK && result) + return S_OK;
- hr = IMFTopology_AddNode(topology, node2); - ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + return MF_E_INVALIDMEDIATYPE; +}
- hr = IMFTopologyNode_GetTopoNodeID(node, &id); - ok(hr == S_OK, "Failed to get node id, hr %#lx.\n", hr); +static HRESULT WINAPI test_handler_GetMediaTypeCount(IMFMediaTypeHandler *iface, DWORD *count) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +}
- hr = IMFTopologyNode_SetTopoNodeID(node2, id); - ok(hr == S_OK, "Failed to get node id, hr %#lx.\n", hr); +static HRESULT WINAPI test_handler_GetMediaTypeByIndex(IMFMediaTypeHandler *iface, DWORD index, + IMFMediaType **type) +{ + struct test_handler *impl = impl_from_IMFMediaTypeHandler(iface);
- hr = IMFTopology_GetNodeByID(topology, id, &node3); - ok(hr == S_OK, "Failed to get a node, hr %#lx.\n", hr); - ok(node3 == node, "Unexpected node.\n"); - IMFTopologyNode_Release(node3); + if (impl->media_types) + { + impl->enum_count++;
- /* Source/output collections. */ - hr = IMFTopology_Clear(topology); - ok(hr == S_OK, "Failed to clear topology, hr %#lx.\n", hr); + if (index >= impl->media_types_count) + return MF_E_NO_MORE_TYPES;
- ref = IMFTopologyNode_Release(node); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFTopologyNode_Release(node2); - ok(ref == 0, "Release returned %ld\n", ref); + IMFMediaType_AddRef((*type = impl->media_types[index])); + return S_OK; + }
- hr = IMFTopology_GetSourceNodeCollection(topology, NULL); - ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +}
- hr = IMFTopology_GetSourceNodeCollection(topology, &collection); - ok(hr == S_OK, "Failed to get source node collection, hr %#lx.\n", hr); - ok(!!collection, "Unexpected object pointer.\n"); +static HRESULT WINAPI test_handler_SetCurrentMediaType(IMFMediaTypeHandler *iface, IMFMediaType *media_type) +{ + struct test_handler *impl = impl_from_IMFMediaTypeHandler(iface);
- hr = IMFTopology_GetSourceNodeCollection(topology, &collection2); - ok(hr == S_OK, "Failed to get source node collection, hr %#lx.\n", hr); - ok(!!collection2, "Unexpected object pointer.\n"); - ok(collection2 != collection, "Expected cloned collection.\n"); + if (impl->current_type) + IMFMediaType_Release(impl->current_type); + IMFMediaType_AddRef((impl->current_type = media_type)); + impl->set_current_count++;
- hr = IMFCollection_GetElementCount(collection, &size); - ok(hr == S_OK, "Failed to get item count, hr %#lx.\n", hr); - ok(!size, "Unexpected item count.\n"); + return S_OK; +}
- EXPECT_REF(collection, 1); - hr = IMFCollection_AddElement(collection, (IUnknown *)collection); - ok(hr == S_OK, "Failed to add element, hr %#lx.\n", hr); - EXPECT_REF(collection, 2); +static HRESULT WINAPI test_handler_GetCurrentMediaType(IMFMediaTypeHandler *iface, IMFMediaType **media_type) +{ + struct test_handler *impl = impl_from_IMFMediaTypeHandler(iface); + HRESULT hr;
- hr = IMFCollection_GetElementCount(collection, &size); - ok(hr == S_OK, "Failed to get item count, hr %#lx.\n", hr); - ok(size == 1, "Unexpected item count.\n"); + if (!impl->current_type) + { + if (!impl->media_types) + return E_FAIL; + if (!impl->media_types_count) + return MF_E_TRANSFORM_TYPE_NOT_SET; + return MF_E_NOT_INITIALIZED; + }
- /* Empty collection to stop referencing itself */ - hr = IMFCollection_RemoveAllElements(collection); - ok(hr == S_OK, "Failed to get item count, hr %#lx.\n", hr); + if (FAILED(hr = MFCreateMediaType(media_type))) + return hr;
- hr = IMFCollection_GetElementCount(collection2, &size); - ok(hr == S_OK, "Failed to get item count, hr %#lx.\n", hr); - ok(!size, "Unexpected item count.\n"); + hr = IMFMediaType_CopyAllItems(impl->current_type, (IMFAttributes *)*media_type); + if (FAILED(hr)) + IMFMediaType_Release(*media_type);
- ref = IMFCollection_Release(collection2); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFCollection_Release(collection); - ok(ref == 0, "Release returned %ld\n", ref); + return hr; +}
- /* Add some nodes. */ - hr = IMFTopology_GetSourceNodeCollection(topology, NULL); - ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); +static HRESULT WINAPI test_handler_GetMajorType(IMFMediaTypeHandler *iface, GUID *type) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +}
- hr = IMFTopology_GetOutputNodeCollection(topology, NULL); - ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); +static const IMFMediaTypeHandlerVtbl test_handler_vtbl = +{ + test_handler_QueryInterface, + test_handler_AddRef, + test_handler_Release, + test_handler_IsMediaTypeSupported, + test_handler_GetMediaTypeCount, + test_handler_GetMediaTypeByIndex, + test_handler_SetCurrentMediaType, + test_handler_GetCurrentMediaType, + test_handler_GetMajorType, +};
- hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node); - ok(hr == S_OK, "Failed to create a node, hr %#lx.\n", hr); - hr = IMFTopology_AddNode(topology, node); - ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); - IMFTopologyNode_Release(node); - - hr = IMFTopology_GetSourceNodeCollection(topology, &collection); - ok(hr == S_OK, "Failed to get source node collection, hr %#lx.\n", hr); - ok(!!collection, "Unexpected object pointer.\n"); - hr = IMFCollection_GetElementCount(collection, &size); - ok(hr == S_OK, "Failed to get item count, hr %#lx.\n", hr); - ok(size == 1, "Unexpected item count.\n"); - ref = IMFCollection_Release(collection); - ok(ref == 0, "Release returned %ld\n", ref); +static const struct test_handler test_handler = {.IMFMediaTypeHandler_iface.lpVtbl = &test_handler_vtbl};
- hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &node); - ok(hr == S_OK, "Failed to create a node, hr %#lx.\n", hr); - hr = IMFTopology_AddNode(topology, node); - ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); - IMFTopologyNode_Release(node); - - hr = IMFTopology_GetSourceNodeCollection(topology, &collection); - ok(hr == S_OK, "Failed to get source node collection, hr %#lx.\n", hr); - ok(!!collection, "Unexpected object pointer.\n"); - hr = IMFCollection_GetElementCount(collection, &size); - ok(hr == S_OK, "Failed to get item count, hr %#lx.\n", hr); - ok(size == 1, "Unexpected item count.\n"); - ref = IMFCollection_Release(collection); - ok(ref == 0, "Release returned %ld\n", ref); +struct test_media_sink +{ + IMFMediaSink IMFMediaSink_iface; + BOOL shutdown; +};
- hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node); - ok(hr == S_OK, "Failed to create a node, hr %#lx.\n", hr); - hr = IMFTopology_AddNode(topology, node); - ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); - IMFTopologyNode_Release(node); - - hr = IMFTopology_GetSourceNodeCollection(topology, &collection); - ok(hr == S_OK, "Failed to get source node collection, hr %#lx.\n", hr); - ok(!!collection, "Unexpected object pointer.\n"); - hr = IMFCollection_GetElementCount(collection, &size); - ok(hr == S_OK, "Failed to get item count, hr %#lx.\n", hr); - ok(size == 1, "Unexpected item count.\n"); - ref = IMFCollection_Release(collection); - ok(ref == 0, "Release returned %ld\n", ref); +static struct test_media_sink *impl_from_IMFMediaSink(IMFMediaSink *iface) +{ + return CONTAINING_RECORD(iface, struct test_media_sink, IMFMediaSink_iface); +}
- hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node); - ok(hr == S_OK, "Failed to create a node, hr %#lx.\n", hr); - hr = IMFTopology_AddNode(topology, node); - ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); +static HRESULT WINAPI test_media_sink_QueryInterface(IMFMediaSink *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IMFMediaSink) + || IsEqualIID(riid, &IID_IUnknown)) + { + IMFMediaSink_AddRef((*obj = iface)); + return S_OK; + }
- /* Associated object. */ - hr = IMFTopologyNode_SetObject(node, NULL); - ok(hr == S_OK, "Failed to set object, hr %#lx.\n", hr); + *obj = NULL; + return E_NOINTERFACE; +}
- hr = IMFTopologyNode_GetObject(node, NULL); - ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); +static ULONG WINAPI test_media_sink_AddRef(IMFMediaSink *iface) +{ + return 2; +}
- object = (void *)0xdeadbeef; - hr = IMFTopologyNode_GetObject(node, &object); - ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); - ok(!object, "Unexpected object %p.\n", object); +static ULONG WINAPI test_media_sink_Release(IMFMediaSink *iface) +{ + return 1; +}
- hr = IMFTopologyNode_SetObject(node, &test_unk); - ok(hr == S_OK, "Failed to set object, hr %#lx.\n", hr); +static HRESULT WINAPI test_media_sink_GetCharacteristics(IMFMediaSink *iface, DWORD *characteristics) +{ + *characteristics = 0; + return S_OK; +}
- hr = IMFTopologyNode_GetObject(node, &object); - ok(hr == S_OK, "Failed to get object, hr %#lx.\n", hr); - ok(object == &test_unk, "Unexpected object %p.\n", object); - IUnknown_Release(object); +static HRESULT WINAPI test_media_sink_AddStreamSink(IMFMediaSink *iface, + DWORD stream_sink_id, IMFMediaType *media_type, IMFStreamSink **stream_sink) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +}
- hr = IMFTopologyNode_SetObject(node, &test_unk2); - ok(hr == S_OK, "Failed to set object, hr %#lx.\n", hr); +static HRESULT WINAPI test_media_sink_RemoveStreamSink(IMFMediaSink *iface, DWORD stream_sink_id) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +}
- hr = IMFTopologyNode_GetCount(node, &count); - ok(hr == S_OK, "Failed to get attribute count, hr %#lx.\n", hr); - ok(count == 0, "Unexpected attribute count %u.\n", count); +static HRESULT WINAPI test_media_sink_GetStreamSinkCount(IMFMediaSink *iface, DWORD *count) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +}
- hr = IMFTopologyNode_SetGUID(node, &MF_TOPONODE_TRANSFORM_OBJECTID, &MF_TOPONODE_TRANSFORM_OBJECTID); - ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); +static HRESULT WINAPI test_media_sink_GetStreamSinkByIndex(IMFMediaSink *iface, DWORD index, IMFStreamSink **sink) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +}
- hr = IMFTopologyNode_SetObject(node, NULL); - ok(hr == S_OK, "Failed to set object, hr %#lx.\n", hr); +static HRESULT WINAPI test_media_sink_GetStreamSinkById(IMFMediaSink *iface, DWORD stream_sink_id, IMFStreamSink **sink) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +}
- object = (void *)0xdeadbeef; - hr = IMFTopologyNode_GetObject(node, &object); - ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); - ok(!object, "Unexpected object %p.\n", object); +static HRESULT WINAPI test_media_sink_SetPresentationClock(IMFMediaSink *iface, IMFPresentationClock *clock) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +}
- hr = IMFTopologyNode_GetCount(node, &count); - ok(hr == S_OK, "Failed to get attribute count, hr %#lx.\n", hr); - ok(count == 1, "Unexpected attribute count %u.\n", count); +static HRESULT WINAPI test_media_sink_GetPresentationClock(IMFMediaSink *iface, IMFPresentationClock **clock) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +}
- /* Preferred stream types. */ - hr = IMFTopologyNode_GetInputCount(node, &io_count); - ok(hr == S_OK, "Failed to get input count, hr %#lx.\n", hr); - ok(io_count == 0, "Unexpected count %lu.\n", io_count); +static HRESULT WINAPI test_media_sink_Shutdown(IMFMediaSink *iface) +{ + struct test_media_sink *sink = impl_from_IMFMediaSink(iface); + ok(!sink->shutdown, "Unexpected call.\n"); + sink->shutdown = TRUE; + return S_OK; +}
- hr = IMFTopologyNode_GetInputPrefType(node, 0, &mediatype); - ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); +static const IMFMediaSinkVtbl test_media_sink_vtbl = +{ + test_media_sink_QueryInterface, + test_media_sink_AddRef, + test_media_sink_Release, + test_media_sink_GetCharacteristics, + test_media_sink_AddStreamSink, + test_media_sink_RemoveStreamSink, + test_media_sink_GetStreamSinkCount, + test_media_sink_GetStreamSinkByIndex, + test_media_sink_GetStreamSinkById, + test_media_sink_SetPresentationClock, + test_media_sink_GetPresentationClock, + test_media_sink_Shutdown, +};
- hr = MFCreateMediaType(&mediatype); - ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); +static const struct test_media_sink test_media_sink = {.IMFMediaSink_iface.lpVtbl = &test_media_sink_vtbl};
- hr = IMFTopologyNode_SetInputPrefType(node, 0, mediatype); - ok(hr == S_OK, "Failed to set preferred type, hr %#lx.\n", hr); +struct test_stream_sink +{ + IMFStreamSink IMFStreamSink_iface; + IMFGetService IMFGetService_iface; + IMFMediaTypeHandler *handler; + IMFMediaSink *media_sink;
- hr = IMFTopologyNode_GetInputPrefType(node, 0, &mediatype2); - ok(hr == S_OK, "Failed to get preferred type, hr %#lx.\n", hr); - ok(mediatype2 == mediatype, "Unexpected mediatype instance.\n"); - IMFMediaType_Release(mediatype2); + IMFAttributes *attributes; + IUnknown *device_manager; +};
- hr = IMFTopologyNode_SetInputPrefType(node, 0, NULL); - ok(hr == S_OK, "Failed to set preferred type, hr %#lx.\n", hr); +static struct test_stream_sink *impl_from_IMFStreamSink(IMFStreamSink *iface) +{ + return CONTAINING_RECORD(iface, struct test_stream_sink, IMFStreamSink_iface); +}
- hr = IMFTopologyNode_GetInputPrefType(node, 0, &mediatype2); - ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); - ok(!mediatype2, "Unexpected mediatype instance.\n"); +static HRESULT WINAPI test_stream_sink_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj) +{ + struct test_stream_sink *impl = impl_from_IMFStreamSink(iface);
- hr = IMFTopologyNode_SetInputPrefType(node, 1, mediatype); - ok(hr == S_OK, "Failed to set preferred type, hr %#lx.\n", hr); + if (IsEqualIID(riid, &IID_IMFStreamSink) + || IsEqualIID(riid, &IID_IMFMediaEventGenerator) + || IsEqualIID(riid, &IID_IUnknown)) + { + IMFStreamSink_AddRef((*obj = iface)); + return S_OK; + }
- hr = IMFTopologyNode_SetInputPrefType(node, 1, mediatype); - ok(hr == S_OK, "Failed to set preferred type, hr %#lx.\n", hr); + if (IsEqualIID(riid, &IID_IMFAttributes) && impl->attributes) + { + IMFAttributes_AddRef((*obj = impl->attributes)); + return S_OK; + }
- hr = IMFTopologyNode_GetInputCount(node, &io_count); - ok(hr == S_OK, "Failed to get input count, hr %#lx.\n", hr); - ok(io_count == 2, "Unexpected count %lu.\n", io_count); + if (IsEqualIID(riid, &IID_IMFGetService)) + { + *obj = &impl->IMFGetService_iface; + IMFGetService_AddRef(&impl->IMFGetService_iface); + return S_OK; + }
- hr = IMFTopologyNode_GetOutputCount(node, &io_count); - ok(hr == S_OK, "Failed to get input count, hr %#lx.\n", hr); - ok(io_count == 0, "Unexpected count %lu.\n", io_count); + *obj = NULL; + return E_NOINTERFACE; +}
- hr = IMFTopologyNode_SetOutputPrefType(node, 0, mediatype); - ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr); +static ULONG WINAPI test_stream_sink_AddRef(IMFStreamSink *iface) +{ + return 2; +}
- ref = IMFTopologyNode_Release(node); - ok(ref == 1, "Release returned %ld\n", ref); +static ULONG WINAPI test_stream_sink_Release(IMFStreamSink *iface) +{ + return 1; +}
- /* Source node. */ - hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node); - ok(hr == S_OK, "Failed to create a node, hr %#lx.\n", hr); +static HRESULT WINAPI test_stream_sink_GetEvent(IMFStreamSink *iface, DWORD flags, IMFMediaEvent **event) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +}
- hr = IMFTopologyNode_SetInputPrefType(node, 0, mediatype); - ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr); +static HRESULT WINAPI test_stream_sink_BeginGetEvent(IMFStreamSink *iface, IMFAsyncCallback *callback, IUnknown *state) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +}
- hr = IMFTopologyNode_SetOutputPrefType(node, 2, mediatype); - ok(hr == S_OK, "Failed to set preferred type, hr %#lx.\n", hr); +static HRESULT WINAPI test_stream_sink_EndGetEvent(IMFStreamSink *iface, IMFAsyncResult *result, + IMFMediaEvent **event) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +}
- hr = IMFTopologyNode_GetOutputPrefType(node, 0, &mediatype2); - ok(hr == E_FAIL, "Failed to get preferred type, hr %#lx.\n", hr); - ok(!mediatype2, "Unexpected mediatype instance.\n"); +static HRESULT WINAPI test_stream_sink_QueueEvent(IMFStreamSink *iface, MediaEventType event_type, + REFGUID ext_type, HRESULT hr, const PROPVARIANT *value) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +}
- hr = IMFTopologyNode_GetOutputCount(node, &io_count); - ok(hr == S_OK, "Failed to get output count, hr %#lx.\n", hr); - ok(io_count == 3, "Unexpected count %lu.\n", io_count); +static HRESULT WINAPI test_stream_sink_GetMediaSink(IMFStreamSink *iface, IMFMediaSink **sink) +{ + struct test_stream_sink *impl = impl_from_IMFStreamSink(iface);
- ref = IMFTopologyNode_Release(node); - ok(ref == 0, "Release returned %ld\n", ref); + if (impl->media_sink) + { + IMFMediaSink_AddRef((*sink = impl->media_sink)); + return S_OK; + }
- /* Tee node. */ - hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &node); - ok(hr == S_OK, "Failed to create a node, hr %#lx.\n", hr); + todo_wine + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +}
- hr = IMFTopologyNode_SetInputPrefType(node, 0, mediatype); - ok(hr == S_OK, "Failed to set preferred type, hr %#lx.\n", hr); +static HRESULT WINAPI test_stream_sink_GetIdentifier(IMFStreamSink *iface, DWORD *id) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +}
- hr = IMFTopologyNode_GetInputPrefType(node, 0, &mediatype2); - ok(hr == S_OK, "Failed to get preferred type, hr %#lx.\n", hr); - ok(mediatype2 == mediatype, "Unexpected mediatype instance.\n"); - IMFMediaType_Release(mediatype2); +static HRESULT WINAPI test_stream_sink_GetMediaTypeHandler(IMFStreamSink *iface, IMFMediaTypeHandler **handler) +{ + struct test_stream_sink *impl = impl_from_IMFStreamSink(iface);
- hr = IMFTopologyNode_GetOutputPrefType(node, 0, &mediatype2); - ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + if (impl->handler) + { + IMFMediaTypeHandler_AddRef((*handler = impl->handler)); + return S_OK; + }
- hr = IMFTopologyNode_GetInputCount(node, &io_count); - ok(hr == S_OK, "Failed to get output count, hr %#lx.\n", hr); - ok(io_count == 0, "Unexpected count %lu.\n", io_count); + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +}
- hr = IMFTopologyNode_SetInputPrefType(node, 1, mediatype); - ok(hr == MF_E_INVALIDTYPE, "Unexpected hr %#lx.\n", hr); +static HRESULT WINAPI test_stream_sink_ProcessSample(IMFStreamSink *iface, IMFSample *sample) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +}
- hr = IMFTopologyNode_SetInputPrefType(node, 3, mediatype); - ok(hr == MF_E_INVALIDTYPE, "Unexpected hr %#lx.\n", hr); +static HRESULT WINAPI test_stream_sink_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type, + const PROPVARIANT *marker_value, const PROPVARIANT *context) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +}
- hr = IMFTopologyNode_SetOutputPrefType(node, 4, mediatype); - ok(hr == S_OK, "Failed to set preferred type, hr %#lx.\n", hr); +static HRESULT WINAPI test_stream_sink_Flush(IMFStreamSink *iface) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +}
- hr = IMFTopologyNode_GetOutputPrefType(node, 0, &mediatype2); - ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); +static const IMFStreamSinkVtbl test_stream_sink_vtbl = +{ + test_stream_sink_QueryInterface, + test_stream_sink_AddRef, + test_stream_sink_Release, + test_stream_sink_GetEvent, + test_stream_sink_BeginGetEvent, + test_stream_sink_EndGetEvent, + test_stream_sink_QueueEvent, + test_stream_sink_GetMediaSink, + test_stream_sink_GetIdentifier, + test_stream_sink_GetMediaTypeHandler, + test_stream_sink_ProcessSample, + test_stream_sink_PlaceMarker, + test_stream_sink_Flush, +};
- hr = MFCreateMediaType(&mediatype2); - ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); +static struct test_stream_sink *impl_from_IMFGetService(IMFGetService *iface) +{ + return CONTAINING_RECORD(iface, struct test_stream_sink, IMFGetService_iface); +}
- /* Changing output type does not change input type. */ - hr = IMFTopologyNode_SetOutputPrefType(node, 4, mediatype2); - ok(hr == S_OK, "Failed to set preferred type, hr %#lx.\n", hr); +static HRESULT WINAPI test_stream_sink_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj) +{ + struct test_stream_sink *stream = impl_from_IMFGetService(iface); + return IMFStreamSink_QueryInterface(&stream->IMFStreamSink_iface, riid, obj); +}
- hr = IMFTopologyNode_GetInputPrefType(node, 0, &mediatype3); - ok(hr == S_OK, "Failed to get preferred type, hr %#lx.\n", hr); - ok(mediatype3 == mediatype, "Unexpected mediatype instance.\n"); - IMFMediaType_Release(mediatype3); - - IMFMediaType_Release(mediatype2); - - hr = IMFTopologyNode_GetInputCount(node, &io_count); - ok(hr == S_OK, "Failed to get output count, hr %#lx.\n", hr); - ok(io_count == 0, "Unexpected count %lu.\n", io_count); - - hr = IMFTopologyNode_GetOutputCount(node, &io_count); - ok(hr == S_OK, "Failed to get output count, hr %#lx.\n", hr); - ok(io_count == 5, "Unexpected count %lu.\n", io_count); +static ULONG WINAPI test_stream_sink_get_service_AddRef(IMFGetService *iface) +{ + struct test_stream_sink *stream = impl_from_IMFGetService(iface); + return IMFStreamSink_AddRef(&stream->IMFStreamSink_iface); +}
- ref = IMFTopologyNode_Release(node); - ok(ref == 0, "Release returned %ld\n", ref); +static ULONG WINAPI test_stream_sink_get_service_Release(IMFGetService *iface) +{ + struct test_stream_sink *stream = impl_from_IMFGetService(iface); + return IMFStreamSink_Release(&stream->IMFStreamSink_iface); +}
- /* Transform node. */ - hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node); - ok(hr == S_OK, "Failed to create a node, hr %#lx.\n", hr); +static HRESULT WINAPI test_stream_sink_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj) +{ + struct test_stream_sink *stream = impl_from_IMFGetService(iface);
- hr = IMFTopologyNode_SetInputPrefType(node, 3, mediatype); - ok(hr == S_OK, "Failed to set preferred type, hr %#lx.\n", hr); + if (IsEqualGUID(service, &MR_VIDEO_ACCELERATION_SERVICE) && stream->device_manager) + return IUnknown_QueryInterface(stream->device_manager, riid, obj);
- hr = IMFTopologyNode_GetInputCount(node, &io_count); - ok(hr == S_OK, "Failed to get input count, hr %#lx.\n", hr); - ok(io_count == 4, "Unexpected count %lu.\n", io_count); + return E_NOINTERFACE; +}
- hr = IMFTopologyNode_SetOutputPrefType(node, 4, mediatype); - ok(hr == S_OK, "Failed to set preferred type, hr %#lx.\n", hr); +static const IMFGetServiceVtbl test_stream_sink_get_service_vtbl = +{ + test_stream_sink_get_service_QueryInterface, + test_stream_sink_get_service_AddRef, + test_stream_sink_get_service_Release, + test_stream_sink_get_service_GetService, +};
- hr = IMFTopologyNode_GetInputCount(node, &io_count); - ok(hr == S_OK, "Failed to get output count, hr %#lx.\n", hr); - ok(io_count == 4, "Unexpected count %lu.\n", io_count); +static const struct test_stream_sink test_stream_sink = +{ + .IMFStreamSink_iface.lpVtbl = &test_stream_sink_vtbl, + .IMFGetService_iface.lpVtbl = &test_stream_sink_get_service_vtbl, +};
- hr = IMFTopologyNode_GetOutputCount(node, &io_count); - ok(hr == S_OK, "Failed to get output count, hr %#lx.\n", hr); - ok(io_count == 5, "Unexpected count %lu.\n", io_count); +struct test_callback +{ + IMFAsyncCallback IMFAsyncCallback_iface; + LONG refcount;
- ref = IMFTopologyNode_Release(node); - ok(ref == 0, "Release returned %ld\n", ref); + HANDLE event; + IMFMediaEvent *media_event; + BOOL check_media_event; +};
- IMFMediaType_Release(mediatype); +static struct test_callback *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct test_callback, IMFAsyncCallback_iface); +}
- hr = IMFTopology_GetOutputNodeCollection(topology, &collection); - ok(hr == S_OK || broken(hr == E_FAIL) /* before Win8 */, "Failed to get output node collection, hr %#lx.\n", hr); - if (SUCCEEDED(hr)) +static HRESULT WINAPI testcallback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IMFAsyncCallback) || + IsEqualIID(riid, &IID_IUnknown)) { - ok(!!collection, "Unexpected object pointer.\n"); - hr = IMFCollection_GetElementCount(collection, &size); - ok(hr == S_OK, "Failed to get item count, hr %#lx.\n", hr); - ok(size == 1, "Unexpected item count.\n"); - ref = IMFCollection_Release(collection); - ok(ref == 0, "Release returned %ld\n", ref); + *obj = iface; + IMFAsyncCallback_AddRef(iface); + return S_OK; }
- ref = IMFTopology_Release(topology); - ok(ref == 0, "Release returned %ld\n", ref); - - /* Connect nodes. */ - hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + *obj = NULL; + return E_NOINTERFACE; +}
- hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node2); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); +static ULONG WINAPI testcallback_AddRef(IMFAsyncCallback *iface) +{ + struct test_callback *callback = impl_from_IMFAsyncCallback(iface); + return InterlockedIncrement(&callback->refcount); +}
- EXPECT_REF(node, 1); - EXPECT_REF(node2, 1); +static ULONG WINAPI testcallback_Release(IMFAsyncCallback *iface) +{ + struct test_callback *callback = impl_from_IMFAsyncCallback(iface); + ULONG refcount = InterlockedDecrement(&callback->refcount);
- hr = IMFTopologyNode_ConnectOutput(node, 0, node2, 1); - ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + if (!refcount) + { + if (callback->media_event) + IMFMediaEvent_Release(callback->media_event); + CloseHandle(callback->event); + free(callback); + }
- EXPECT_REF(node, 2); - EXPECT_REF(node2, 2); + return refcount; +}
- IMFTopologyNode_Release(node); +static HRESULT WINAPI testcallback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) +{ + ok(flags != NULL && queue != NULL, "Unexpected arguments.\n"); + return E_NOTIMPL; +}
- EXPECT_REF(node, 1); - EXPECT_REF(node2, 2); +static HRESULT WINAPI testcallback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + struct test_callback *callback = CONTAINING_RECORD(iface, struct test_callback, IMFAsyncCallback_iface); + IUnknown *object; + HRESULT hr;
- IMFTopologyNode_Release(node2); + ok(result != NULL, "Unexpected result object.\n");
- EXPECT_REF(node, 1); - EXPECT_REF(node2, 1); + if (callback->media_event) + IMFMediaEvent_Release(callback->media_event);
- hr = IMFTopologyNode_GetNodeType(node2, &node_type); - ok(hr == S_OK, "Failed to get node type, hr %#lx.\n", hr); + if (callback->check_media_event) + { + hr = IMFAsyncResult_GetObject(result, &object); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
- IMFTopologyNode_Release(node); + hr = IMFAsyncResult_GetState(result, &object); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaEventGenerator_EndGetEvent((IMFMediaEventGenerator *)object, + result, &callback->media_event); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IUnknown_Release(object); + }
- /* Connect within topology. */ - hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + SetEvent(callback->event);
- hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node2); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + return S_OK; +}
- hr = MFCreateTopology(&topology); - ok(hr == S_OK, "Failed to create topology, hr %#lx.\n", hr); +static const IMFAsyncCallbackVtbl testcallbackvtbl = +{ + testcallback_QueryInterface, + testcallback_AddRef, + testcallback_Release, + testcallback_GetParameters, + testcallback_Invoke, +};
- hr = IMFTopology_AddNode(topology, node); - ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); +static IMFAsyncCallback *create_test_callback(BOOL check_media_event) +{ + struct test_callback *callback;
- hr = IMFTopology_AddNode(topology, node2); - ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + if (!(callback = calloc(1, sizeof(*callback)))) + return NULL;
- EXPECT_REF(node, 2); - EXPECT_REF(node2, 2); + callback->refcount = 1; + callback->check_media_event = check_media_event; + callback->IMFAsyncCallback_iface.lpVtbl = &testcallbackvtbl; + callback->event = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(!!callback->event, "CreateEventW failed, error %lu\n", GetLastError());
- hr = IMFTopologyNode_ConnectOutput(node, 0, node2, 1); - ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + return &callback->IMFAsyncCallback_iface; +}
- EXPECT_REF(node, 3); - EXPECT_REF(node2, 3); +#define wait_media_event(a, b, c, d, e) wait_media_event_(__LINE__, a, b, c, d, e) +static HRESULT wait_media_event_(int line, IMFMediaSession *session, IMFAsyncCallback *callback, + MediaEventType expect_type, DWORD timeout, PROPVARIANT *value) +{ + struct test_callback *impl = impl_from_IMFAsyncCallback(callback); + MediaEventType type; + HRESULT hr, status; + DWORD ret; + GUID guid;
- hr = IMFTopology_Clear(topology); - ok(hr == S_OK, "Failed to clear topology, hr %#lx.\n", hr); + do + { + hr = IMFMediaSession_BeginGetEvent(session, &impl->IMFAsyncCallback_iface, (IUnknown *)session); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ret = WaitForSingleObject(impl->event, timeout); + ok_(__FILE__, line)(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", ret); + hr = IMFMediaEvent_GetType(impl->media_event, &type); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } while (type != expect_type);
- EXPECT_REF(node, 1); - EXPECT_REF(node2, 1); + ok_(__FILE__, line)(type == expect_type, "got type %lu\n", type);
- /* Removing connected node breaks connection. */ - hr = IMFTopology_AddNode(topology, node); - ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + hr = IMFMediaEvent_GetExtendedType(impl->media_event, &guid); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok_(__FILE__, line)(IsEqualGUID(&guid, &GUID_NULL), "got extended type %s\n", debugstr_guid(&guid));
- hr = IMFTopology_AddNode(topology, node2); - ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + hr = IMFMediaEvent_GetValue(impl->media_event, value); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- hr = IMFTopologyNode_ConnectOutput(node, 0, node2, 1); - ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + hr = IMFMediaEvent_GetStatus(impl->media_event, &status); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- hr = IMFTopology_RemoveNode(topology, node); - ok(hr == S_OK, "Failed to remove a node, hr %#lx.\n", hr); + return status; +}
- EXPECT_REF(node, 1); - EXPECT_REF(node2, 2); +#define wait_media_event_until_blocking(a, b, c, d, e) wait_media_event_until_blocking_(__LINE__, a, b, c, d, e) +static HRESULT wait_media_event_until_blocking_(int line, IMFMediaSession *session, IMFAsyncCallback *callback, + MediaEventType expect_type, DWORD timeout, PROPVARIANT *value) +{ + struct test_callback *impl = impl_from_IMFAsyncCallback(callback); + MediaEventType type; + HRESULT hr, status; + DWORD ret; + GUID guid;
- hr = IMFTopologyNode_GetOutput(node, 0, &node3, &index); - ok(hr == MF_E_NOT_FOUND, "Unexpected hr %#lx.\n", hr); + do + { + hr = IMFMediaSession_BeginGetEvent(session, &impl->IMFAsyncCallback_iface, (IUnknown *)session); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ret = WaitForSingleObject(impl->event, timeout); + if (ret == WAIT_TIMEOUT) return WAIT_TIMEOUT; + hr = IMFMediaEvent_GetType(impl->media_event, &type); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } while (type != expect_type);
- hr = IMFTopology_AddNode(topology, node); - ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + ok_(__FILE__, line)(type == expect_type, "got type %lu\n", type);
- hr = IMFTopologyNode_ConnectOutput(node, 0, node2, 1); - ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + hr = IMFMediaEvent_GetExtendedType(impl->media_event, &guid); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok_(__FILE__, line)(IsEqualGUID(&guid, &GUID_NULL), "got extended type %s\n", debugstr_guid(&guid));
- hr = IMFTopology_RemoveNode(topology, node2); - ok(hr == S_OK, "Failed to remove a node, hr %#lx.\n", hr); + hr = IMFMediaEvent_GetValue(impl->media_event, value); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- EXPECT_REF(node, 2); - EXPECT_REF(node2, 1); + hr = IMFMediaEvent_GetStatus(impl->media_event, &status); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- IMFTopologyNode_Release(node); - IMFTopologyNode_Release(node2); + return status; +}
- /* Cloning nodes of different types. */ - hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); +static IMFMediaSource *create_media_source(const WCHAR *name, const WCHAR *mime) +{ + IMFSourceResolver *resolver; + IMFAttributes *attributes; + const BYTE *resource_data; + MF_OBJECT_TYPE obj_type; + IMFMediaSource *source; + IMFByteStream *stream; + ULONG resource_len; + HRSRC resource; + HRESULT hr;
- hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node2); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + resource = FindResourceW(NULL, name, (const WCHAR *)RT_RCDATA); + ok(resource != 0, "FindResourceW %s failed, error %lu\n", debugstr_w(name), GetLastError()); + resource_data = LockResource(LoadResource(GetModuleHandleW(NULL), resource)); + resource_len = SizeofResource(GetModuleHandleW(NULL), resource);
- hr = IMFTopologyNode_CloneFrom(node, node2); - ok(hr == MF_E_INVALIDREQUEST, "Unexpected hr %#lx.\n", hr); + hr = MFCreateTempFile(MF_ACCESSMODE_READWRITE, MF_OPENMODE_DELETE_IF_EXIST, MF_FILEFLAGS_NONE, &stream); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFByteStream_Write(stream, resource_data, resource_len, &resource_len); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFByteStream_SetCurrentPosition(stream, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ref = IMFTopologyNode_Release(node2); - ok(ref == 0, "Release returned %ld\n", ref); + hr = IMFByteStream_QueryInterface(stream, &IID_IMFAttributes, (void **)&attributes); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_SetString(attributes, &MF_BYTESTREAM_CONTENT_TYPE, mime); + ok(hr == S_OK, "Failed to set string value, hr %#lx.\n", hr); + IMFAttributes_Release(attributes);
- /* Cloning preferred types. */ - hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node2); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + hr = MFCreateSourceResolver(&resolver); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL, + &obj_type, (IUnknown **)&source); + todo_wine_if(hr == MF_E_UNEXPECTED) /* Gitlab CI Debian runner */ + ok(hr == S_OK || broken(hr == MF_E_UNSUPPORTED_BYTESTREAM_TYPE), "Unexpected hr %#lx.\n", hr); + IMFSourceResolver_Release(resolver); + IMFByteStream_Release(stream);
- hr = MFCreateMediaType(&mediatype); - ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); + if (FAILED(hr)) + return NULL;
- hr = IMFTopologyNode_SetOutputPrefType(node2, 0, mediatype); - ok(hr == S_OK, "Failed to set preferred type, hr %#lx.\n", hr); + ok(obj_type == MF_OBJECT_MEDIASOURCE, "got %d\n", obj_type); + return source; +}
- /* Vista checks for additional attributes. */ - hr = IMFTopologyNode_CloneFrom(node, node2); - ok(hr == S_OK || broken(hr == MF_E_ATTRIBUTENOTFOUND) /* Vista */, "Failed to clone a node, hr %#lx.\n", hr); +enum object_state +{ + SOURCE_START, + SOURCE_PAUSE, + SOURCE_STOP, + SOURCE_SHUTDOWN, + SINK_ON_CLOCK_START, + SINK_ON_CLOCK_PAUSE, + SINK_ON_CLOCK_STOP, + SINK_ON_CLOCK_RESTART, + SINK_ON_CLOCK_SETRATE, +};
- hr = IMFTopologyNode_GetOutputPrefType(node, 0, &mediatype2); - ok(hr == S_OK, "Failed to get preferred type, hr %#lx.\n", hr); - ok(mediatype == mediatype2, "Unexpected media type.\n"); +#define MAX_OBJECT_STATE 1024
- IMFMediaType_Release(mediatype2); +struct object_state_record +{ + enum object_state states[MAX_OBJECT_STATE]; + unsigned int state_count; +}; +static struct object_state_record actual_object_state_record;
- ref = IMFTopologyNode_Release(node2); - ok(ref == 0, "Release returned %ld\n", ref); +#define add_object_state(a, b) _add_object_state(__LINE__, a, b) +static void _add_object_state(int line, struct object_state_record *record, enum object_state state) +{ + ok_(__FILE__, line)(record->state_count < MAX_OBJECT_STATE, "exceeded state_count maximum %d.\n", MAX_OBJECT_STATE); + if (record->state_count < MAX_OBJECT_STATE) + record->states[record->state_count++] = state; +}
- IMFMediaType_Release(mediatype); +#define compare_object_states(a, b) _compare_object_states(__LINE__, a, b) +static void _compare_object_states(int line, const struct object_state_record *r1, + const struct object_state_record *r2) +{ + ok_(__FILE__, line)(r1->state_count == r2->state_count, "State count not equal.\n"); + if (r1->state_count == r2->state_count) + ok_(__FILE__, line)(!memcmp(r1->states, r2->states, sizeof(enum object_state) * r1->state_count), "Got different states.\n"); +}
- /* Existing preferred types are not cleared. */ - hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node2); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); - - hr = IMFTopologyNode_GetOutputCount(node, &io_count); - ok(hr == S_OK, "Failed to get output count, hr %#lx.\n", hr); - ok(io_count == 1, "Unexpected output count.\n"); - - hr = IMFTopologyNode_CloneFrom(node, node2); - ok(hr == S_OK || broken(hr == MF_E_ATTRIBUTENOTFOUND) /* Vista */, "Failed to clone a node, hr %#lx.\n", hr); - - hr = IMFTopologyNode_GetOutputCount(node, &io_count); - ok(hr == S_OK, "Failed to get output count, hr %#lx.\n", hr); - ok(io_count == 1, "Unexpected output count.\n"); - - hr = IMFTopologyNode_GetOutputPrefType(node, 0, &mediatype2); - ok(hr == S_OK, "Failed to get preferred type, hr %#lx.\n", hr); - ok(!!mediatype2, "Unexpected media type.\n"); - IMFMediaType_Release(mediatype2); - - hr = IMFTopologyNode_CloneFrom(node2, node); - ok(hr == S_OK || broken(hr == MF_E_ATTRIBUTENOTFOUND) /* Vista */, "Failed to clone a node, hr %#lx.\n", hr); - - hr = IMFTopologyNode_GetOutputCount(node2, &io_count); - ok(hr == S_OK, "Failed to get output count, hr %#lx.\n", hr); - ok(io_count == 1, "Unexpected output count.\n"); - - ref = IMFTopologyNode_Release(node2); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFTopologyNode_Release(node); - ok(ref == 0, "Release returned %ld\n", ref); - - /* Add one node, connect to another that hasn't been added. */ - hr = IMFTopology_Clear(topology); - ok(hr == S_OK, "Failed to clear topology, hr %#lx.\n", hr); - - hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); - - hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node2); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); - - hr = IMFTopology_AddNode(topology, node); - ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); - - hr = IMFTopology_GetNodeCount(topology, &node_count); - ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); - ok(node_count == 1, "Unexpected node count.\n"); - - hr = IMFTopologyNode_ConnectOutput(node, 0, node2, 0); - ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); - - hr = IMFTopology_GetNodeCount(topology, &node_count); - ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); - ok(node_count == 1, "Unexpected node count.\n"); - - /* Add same node to different topologies. */ - hr = IMFTopology_Clear(topology); - ok(hr == S_OK, "Failed to clear topology, hr %#lx.\n", hr); - - hr = MFCreateTopology(&topology2); - ok(hr == S_OK, "Failed to create topology, hr %#lx.\n", hr); - - hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); - - hr = IMFTopology_AddNode(topology, node); - ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); - EXPECT_REF(node, 2); - - hr = IMFTopology_GetNodeCount(topology, &node_count); - ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); - ok(node_count == 1, "Unexpected node count.\n"); - - hr = IMFTopology_GetNodeCount(topology2, &node_count); - ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); - ok(node_count == 0, "Unexpected node count.\n"); - - hr = IMFTopology_AddNode(topology2, node); - ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); - EXPECT_REF(node, 3); +enum source_state +{ + SOURCE_STOPPED, + SOURCE_RUNNING, + SOURCE_PAUSED, +};
- hr = IMFTopology_GetNodeCount(topology, &node_count); - ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); - ok(node_count == 1, "Unexpected node count.\n"); +struct test_media_stream +{ + IMFMediaStream IMFMediaStream_iface; + IMFMediaEventQueue *event_queue; + IMFStreamDescriptor *sd; + IMFMediaSource *source; + LONGLONG sample_duration; + LONGLONG sample_time; + BOOL is_new; + LONG refcount; +};
- hr = IMFTopology_GetNodeCount(topology2, &node_count); - ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); - ok(node_count == 1, "Unexpected node count.\n"); +static struct test_media_stream *impl_from_IMFMediaStream(IMFMediaStream *iface) +{ + return CONTAINING_RECORD(iface, struct test_media_stream, IMFMediaStream_iface); +}
- ref = IMFTopology_Release(topology2); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFTopology_Release(topology); - ok(ref == 0, "Release returned %ld\n", ref); +static HRESULT WINAPI test_media_stream_QueryInterface(IMFMediaStream *iface, REFIID riid, void **out) +{ + if (IsEqualIID(riid, &IID_IMFMediaStream) + || IsEqualIID(riid, &IID_IMFMediaEventGenerator) + || IsEqualIID(riid, &IID_IUnknown)) + { + *out = iface; + } + else + { + *out = NULL; + return E_NOINTERFACE; + }
- ref = IMFTopologyNode_Release(node); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFTopologyNode_Release(node2); - ok(ref == 0, "Release returned %ld\n", ref); + IMFMediaStream_AddRef(iface); + return S_OK; +}
- /* Try cloning a topology without all outputs connected */ - hr = MFCreateTopology(&topology); - ok(hr == S_OK, "Failed to create topology, hr %#lx.\n", hr); +static ULONG WINAPI test_media_stream_AddRef(IMFMediaStream *iface) +{ + struct test_media_stream *stream = impl_from_IMFMediaStream(iface); + return InterlockedIncrement(&stream->refcount); +}
- hr = MFCreateTopology(&topology2); - ok(hr == S_OK, "Failed to create topology, hr %#lx.\n", hr); +static ULONG WINAPI test_media_stream_Release(IMFMediaStream *iface) +{ + struct test_media_stream *stream = impl_from_IMFMediaStream(iface); + ULONG refcount = InterlockedDecrement(&stream->refcount);
- hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + if (!refcount) + { + IMFMediaEventQueue_Release(stream->event_queue); + free(stream); + }
- hr = IMFTopology_AddNode(topology, node); - ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); - EXPECT_REF(node, 2); + return refcount; +}
- hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node2); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); +static HRESULT WINAPI test_media_stream_GetEvent(IMFMediaStream *iface, DWORD flags, IMFMediaEvent **event) +{ + struct test_media_stream *stream = impl_from_IMFMediaStream(iface); + return IMFMediaEventQueue_GetEvent(stream->event_queue, flags, event); +}
- hr = IMFTopology_AddNode(topology, node2); - ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); - EXPECT_REF(node, 2); +static HRESULT WINAPI test_media_stream_BeginGetEvent(IMFMediaStream *iface, IMFAsyncCallback *callback, IUnknown *state) +{ + struct test_media_stream *stream = impl_from_IMFMediaStream(iface); + return IMFMediaEventQueue_BeginGetEvent(stream->event_queue, callback, state); +}
- hr = IMFTopologyNode_ConnectOutput(node, 1, node2, 0); - ok(hr == S_OK, "Failed to connect output, hr %#lx.\n", hr); +static HRESULT WINAPI test_media_stream_EndGetEvent(IMFMediaStream *iface, IMFAsyncResult *result, IMFMediaEvent **event) +{ + struct test_media_stream *stream = impl_from_IMFMediaStream(iface); + return IMFMediaEventQueue_EndGetEvent(stream->event_queue, result, event); +}
- hr = IMFTopology_CloneFrom(topology2, topology); - ok(hr == S_OK, "Failed to clone from topology, hr %#lx.\n", hr); +static HRESULT WINAPI test_media_stream_QueueEvent(IMFMediaStream *iface, MediaEventType event_type, REFGUID ext_type, + HRESULT hr, const PROPVARIANT *value) +{ + struct test_media_stream *stream = impl_from_IMFMediaStream(iface); + return IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, event_type, ext_type, hr, value); +}
- hr = IMFTopology_GetNodeCount(topology2, &node_count); - ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); - ok(node_count == 2, "Unexpected node count %u.\n", node_count); +static HRESULT WINAPI test_media_stream_GetMediaSource(IMFMediaStream *iface, IMFMediaSource **source) +{ + struct test_media_stream *stream = impl_from_IMFMediaStream(iface);
- hr = IMFTopology_GetNode(topology2, 0, &node3); - ok(hr == S_OK, "Failed to get node, hr %#lx.\n", hr); + *source = stream->source; + IMFMediaSource_AddRef(*source);
- hr = IMFTopologyNode_GetOutputCount(node3, &size); - ok(hr == S_OK, "Failed to get output count, hr %#lx.\n", hr); - ok(size == 2, "Unexpected output count %lu.\n", size); + return S_OK; +}
- IMFTopologyNode_Release(node3); +static HRESULT WINAPI test_media_stream_GetStreamDescriptor(IMFMediaStream *iface, IMFStreamDescriptor **sd) +{ + struct test_media_stream *stream = impl_from_IMFMediaStream(iface);
- ref = IMFTopology_Release(topology2); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFTopology_Release(topology); - ok(ref == 0, "Release returned %ld\n", ref); + *sd = stream->sd; + IMFStreamDescriptor_AddRef(*sd);
- ref = IMFTopologyNode_Release(node2); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFTopologyNode_Release(node); - ok(ref == 0, "Release returned %ld\n", ref); + return S_OK; }
-static void test_topology_tee_node(void) +static HRESULT WINAPI test_media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token) { - IMFTopologyNode *src_node, *tee_node; - IMFMediaType *mediatype, *mediatype2; - IMFTopology *topology; - DWORD count; + struct test_media_stream *stream = impl_from_IMFMediaStream(iface); + IMFMediaBuffer *buffer; + IMFSample *sample; HRESULT hr; - LONG ref; - - hr = MFCreateTopology(&topology); - ok(hr == S_OK, "Failed to create topology, hr %#lx.\n", hr); - - hr = MFCreateMediaType(&mediatype); - ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); - - hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &tee_node); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); - - hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &src_node); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); - - hr = IMFTopologyNode_SetInputPrefType(tee_node, 0, mediatype); - ok(hr == S_OK, "Failed to set type, hr %#lx.\n", hr);
- /* Even though tee node has only one input and source has only one output, - it's possible to connect to higher inputs/outputs. */ + hr = MFCreateSample(&sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (stream->sample_duration) + { + hr = IMFSample_SetSampleDuration(sample, stream->sample_duration); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- /* SRC(0) -> TEE(0) */ - hr = IMFTopologyNode_ConnectOutput(src_node, 0, tee_node, 0); - ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + hr = IMFSample_SetSampleTime(sample, stream->sample_time); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- hr = IMFTopologyNode_GetInputCount(tee_node, &count); - ok(hr == S_OK, "Failed to get count, hr %#lx.\n", hr); - ok(count == 1, "Unexpected count %lu.\n", count); + stream->sample_time += stream->sample_duration; + } + else + { + hr = IMFSample_SetSampleTime(sample, 123); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- hr = IMFTopologyNode_GetInputPrefType(tee_node, 0, &mediatype2); - ok(hr == S_OK, "Failed to get type, hr %#lx.\n", hr); - ok(mediatype2 == mediatype, "Unexpected type.\n"); - IMFMediaType_Release(mediatype2); + hr = IMFSample_SetSampleDuration(sample, 1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + }
- /* SRC(0) -> TEE(1) */ - hr = IMFTopologyNode_ConnectOutput(src_node, 0, tee_node, 1); - ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + if (token) + IMFSample_SetUnknown(sample, &MFSampleExtension_Token, token);
- hr = IMFTopologyNode_GetInputCount(tee_node, &count); - ok(hr == S_OK, "Failed to get count, hr %#lx.\n", hr); - ok(count == 2, "Unexpected count %lu.\n", count); + /* Reader expects buffers, empty samples are considered an error. */ + hr = MFCreateMemoryBuffer(8, &buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFSample_AddBuffer(sample, buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaBuffer_Release(buffer);
- hr = IMFTopologyNode_SetInputPrefType(tee_node, 1, mediatype); - ok(hr == MF_E_INVALIDTYPE, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaEventQueue_QueueEventParamUnk(stream->event_queue, MEMediaSample, &GUID_NULL, S_OK, + (IUnknown *)sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFSample_Release(sample);
- /* SRC(1) -> TEE(1) */ - hr = IMFTopologyNode_ConnectOutput(src_node, 1, tee_node, 1); - ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + return S_OK; +}
- hr = IMFTopologyNode_GetOutputCount(src_node, &count); - ok(hr == S_OK, "Failed to get count, hr %#lx.\n", hr); - ok(count == 2, "Unexpected count %lu.\n", count); +static const IMFMediaStreamVtbl test_media_stream_vtbl = +{ + test_media_stream_QueryInterface, + test_media_stream_AddRef, + test_media_stream_Release, + test_media_stream_GetEvent, + test_media_stream_BeginGetEvent, + test_media_stream_EndGetEvent, + test_media_stream_QueueEvent, + test_media_stream_GetMediaSource, + test_media_stream_GetStreamDescriptor, + test_media_stream_RequestSample, +};
- EXPECT_REF(src_node, 2); - EXPECT_REF(tee_node, 2); - hr = IMFTopologyNode_DisconnectOutput(src_node, 1); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); +#define TEST_SOURCE_NUM_STREAMS 3
- ref = IMFTopologyNode_Release(src_node); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFTopologyNode_Release(tee_node); - ok(ref == 0, "Release returned %ld\n", ref); +struct test_seek_source +{ + IMFMediaSource IMFMediaSource_iface; + IMFMediaEventQueue *event_queue; + IMFPresentationDescriptor *pd; + struct test_media_stream *streams[TEST_SOURCE_NUM_STREAMS]; + enum source_state state; + unsigned stream_count; + CRITICAL_SECTION cs; + BOOL seekable; + LONG refcount; +};
- ref = IMFMediaType_Release(mediatype); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFTopology_Release(topology); - ok(ref == 0, "Release returned %ld\n", ref); +static struct test_seek_source *impl_test_seek_source_from_IMFMediaSource(IMFMediaSource *iface) +{ + return CONTAINING_RECORD(iface, struct test_seek_source, IMFMediaSource_iface); }
-static HRESULT WINAPI test_getservice_QI(IMFGetService *iface, REFIID riid, void **obj) +static HRESULT WINAPI test_seek_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out) { - if (IsEqualIID(riid, &IID_IMFGetService) || IsEqualIID(riid, &IID_IUnknown)) + if (IsEqualIID(riid, &IID_IMFMediaSource) + || IsEqualIID(riid, &IID_IMFMediaEventGenerator) + || IsEqualIID(riid, &IID_IUnknown)) { - *obj = iface; - return S_OK; + *out = iface; + } + else + { + *out = NULL; + return E_NOINTERFACE; }
- *obj = NULL; - return E_NOINTERFACE; + IMFMediaSource_AddRef(iface); + return S_OK; }
-static ULONG WINAPI test_getservice_AddRef(IMFGetService *iface) +static ULONG WINAPI test_seek_source_AddRef(IMFMediaSource *iface) { - return 2; + struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); + return InterlockedIncrement(&source->refcount); }
-static ULONG WINAPI test_getservice_Release(IMFGetService *iface) +static ULONG WINAPI test_seek_source_Release(IMFMediaSource *iface) { - return 1; + struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); + ULONG refcount = InterlockedDecrement(&source->refcount); + + if (!refcount) + { + IMFMediaEventQueue_Release(source->event_queue); + free(source); + } + + return refcount; }
-static HRESULT WINAPI test_getservice_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj) +static HRESULT WINAPI test_seek_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event) { - *obj = (void *)0xdeadbeef; - return 0x83eddead; + struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); + return IMFMediaEventQueue_GetEvent(source->event_queue, flags, event); }
-static const IMFGetServiceVtbl testmfgetservicevtbl = +static HRESULT WINAPI test_seek_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state) { - test_getservice_QI, - test_getservice_AddRef, - test_getservice_Release, - test_getservice_GetService, -}; - -static IMFGetService test_getservice = { &testmfgetservicevtbl }; + struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); + return IMFMediaEventQueue_BeginGetEvent(source->event_queue, callback, state); +}
-static HRESULT WINAPI testservice_QI(IUnknown *iface, REFIID riid, void **obj) +static HRESULT WINAPI test_seek_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event) { - if (IsEqualIID(riid, &IID_IUnknown)) - { - *obj = iface; - return S_OK; - } + struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); + return IMFMediaEventQueue_EndGetEvent(source->event_queue, result, event); +}
- *obj = NULL; +static HRESULT WINAPI test_seek_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type, + HRESULT hr, const PROPVARIANT *value) +{ + struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); + return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, ext_type, hr, value); +}
- if (IsEqualIID(riid, &IID_IMFGetService)) - return 0x82eddead; +static HRESULT WINAPI test_seek_source_GetCharacteristics(IMFMediaSource *iface, DWORD *flags) +{ + struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface);
- return E_NOINTERFACE; + if (source->seekable) + *flags = MFMEDIASOURCE_CAN_PAUSE | MFMEDIASOURCE_CAN_SEEK; + else + *flags = MFMEDIASOURCE_CAN_PAUSE; + return S_OK; }
-static HRESULT WINAPI testservice2_QI(IUnknown *iface, REFIID riid, void **obj) +static HRESULT WINAPI test_seek_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **pd) { - if (IsEqualIID(riid, &IID_IUnknown)) - { - *obj = iface; - return S_OK; - } + struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); + IMFStreamDescriptor *sds[ARRAY_SIZE(source->streams)]; + IMFMediaType *media_type; + HRESULT hr = S_OK; + int i;
- if (IsEqualIID(riid, &IID_IMFGetService)) + EnterCriticalSection(&source->cs); + + if (source->pd) { - *obj = &test_getservice; - return S_OK; + *pd = source->pd; + IMFPresentationDescriptor_AddRef(*pd); } + else + { + for (i = 0; i < source->stream_count; ++i) + { + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- *obj = NULL; - return E_NOINTERFACE; -} + hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_RGB32); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, (UINT64)640 << 32 | 480); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-static ULONG WINAPI testservice_AddRef(IUnknown *iface) -{ - return 2; -} + hr = MFCreateStreamDescriptor(i, 1, &media_type, &sds[i]); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-static ULONG WINAPI testservice_Release(IUnknown *iface) -{ - return 1; + IMFMediaType_Release(media_type); + } + + hr = MFCreatePresentationDescriptor(source->stream_count, sds, &source->pd); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFPresentationDescriptor_SetUINT64(source->pd, &MF_PD_DURATION, 10 * 10000000); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFPresentationDescriptor_SelectStream(source->pd, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < source->stream_count; ++i) + IMFStreamDescriptor_Release(sds[i]); + + *pd = source->pd; + IMFPresentationDescriptor_AddRef(*pd); + } + + LeaveCriticalSection(&source->cs); + + return hr; }
-static const IUnknownVtbl testservicevtbl = +static BOOL is_stream_selected(IMFPresentationDescriptor *pd, DWORD index) { - testservice_QI, - testservice_AddRef, - testservice_Release, -}; + IMFStreamDescriptor *sd; + BOOL selected = FALSE;
-static const IUnknownVtbl testservice2vtbl = -{ - testservice2_QI, - testservice_AddRef, - testservice_Release, -}; + if (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, index, &selected, &sd))) + IMFStreamDescriptor_Release(sd);
-static IUnknown testservice = { &testservicevtbl }; -static IUnknown testservice2 = { &testservice2vtbl }; + return selected; +}
-static void test_MFGetService(void) +static HRESULT WINAPI test_seek_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *pd, const GUID *time_format, + const PROPVARIANT *start_position) { - IUnknown *unk; + struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); + MediaEventType event_type; + PROPVARIANT var; HRESULT hr; + int i;
- hr = MFGetService(NULL, NULL, NULL, NULL); - ok(hr == E_POINTER, "Unexpected return value %#lx.\n", hr); + add_object_state(&actual_object_state_record, SOURCE_START);
- unk = (void *)0xdeadbeef; - hr = MFGetService(NULL, NULL, NULL, (void **)&unk); - ok(hr == E_POINTER, "Unexpected return value %#lx.\n", hr); - ok(unk == (void *)0xdeadbeef, "Unexpected out object.\n"); + ok(time_format && IsEqualGUID(time_format, &GUID_NULL), "Unexpected time format %s.\n", + wine_dbgstr_guid(time_format)); + ok(start_position && (start_position->vt == VT_I8 || start_position->vt == VT_EMPTY), + "Unexpected position type.\n");
- hr = MFGetService(&testservice, NULL, NULL, NULL); - ok(hr == 0x82eddead, "Unexpected return value %#lx.\n", hr); + /* This is what makes IMFMediaSession::Start() seeking fail, not the lacking of MFMEDIASOURCE_CAN_SEEK. + * Without this, IMFMediaSession::Start() seeking succeeds even with the missing MFMEDIASOURCE_CAN_SEEK. + * If this is check is not here, the first IMFMediaSession::Start() call to a non-zero position + * succeeds somehow on Windows 10, then all following seeks fails and no MESessionStarted events */ + if (!source->seekable && start_position && start_position->vt == VT_I8 && start_position->hVal.QuadPart) + return E_FAIL;
- unk = (void *)0xdeadbeef; - hr = MFGetService(&testservice, NULL, NULL, (void **)&unk); - ok(hr == 0x82eddead, "Unexpected return value %#lx.\n", hr); - ok(unk == (void *)0xdeadbeef, "Unexpected out object.\n"); + EnterCriticalSection(&source->cs);
- unk = NULL; - hr = MFGetService(&testservice2, NULL, NULL, (void **)&unk); - ok(hr == 0x83eddead, "Unexpected return value %#lx.\n", hr); - ok(unk == (void *)0xdeadbeef, "Unexpected out object.\n"); -} + event_type = source->state != SOURCE_STOPPED ? MESourceSeeked : MESourceStarted; + hr = IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, &GUID_NULL, S_OK, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-static void test_sequencer_source(void) -{ - IMFSequencerSource *seq_source; - HRESULT hr; - LONG ref; + for (i = 0; i < source->stream_count; ++i) + { + if (!is_stream_selected(pd, i)) + continue;
- hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); - ok(hr == S_OK, "Startup failure, hr %#lx.\n", hr); + var.vt = VT_UNKNOWN; + var.punkVal = (IUnknown *)&source->streams[i]->IMFMediaStream_iface; + event_type = source->streams[i]->is_new ? MENewStream : MEUpdatedStream; + source->streams[i]->is_new = FALSE; + hr = IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, &GUID_NULL, S_OK, &var); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- hr = MFCreateSequencerSource(NULL, &seq_source); - ok(hr == S_OK, "Failed to create sequencer source, hr %#lx.\n", hr); + event_type = source->state != SOURCE_STOPPED ? MEStreamSeeked : MEStreamStarted; + hr = IMFMediaEventQueue_QueueEventParamVar(source->streams[i]->event_queue, event_type, &GUID_NULL, + S_OK, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + }
- check_interface(seq_source, &IID_IMFMediaSourceTopologyProvider, TRUE); + source->state = SOURCE_RUNNING;
- ref = IMFSequencerSource_Release(seq_source); - ok(ref == 0, "Release returned %ld\n", ref); + LeaveCriticalSection(&source->cs);
- hr = MFShutdown(); - ok(hr == S_OK, "Shutdown failure, hr %#lx.\n", hr); + return S_OK; }
-struct test_handler +static HRESULT WINAPI test_seek_source_Stop(IMFMediaSource *iface) { - IMFMediaTypeHandler IMFMediaTypeHandler_iface; + struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); + MediaEventType event_type; + HRESULT hr; + int i;
- ULONG set_current_count; - IMFMediaType *current_type; - IMFMediaType *invalid_type; + add_object_state(&actual_object_state_record, SOURCE_STOP);
- ULONG enum_count; - ULONG media_types_count; - IMFMediaType **media_types; -}; + EnterCriticalSection(&source->cs);
-static struct test_handler *impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler *iface) -{ - return CONTAINING_RECORD(iface, struct test_handler, IMFMediaTypeHandler_iface); -} + event_type = MESourceStopped; + hr = IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, &GUID_NULL, S_OK, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-static HRESULT WINAPI test_handler_QueryInterface(IMFMediaTypeHandler *iface, REFIID riid, void **obj) -{ - if (IsEqualIID(riid, &IID_IMFMediaTypeHandler) - || IsEqualIID(riid, &IID_IUnknown)) + for (i = 0; i < source->stream_count; ++i) { - IMFMediaTypeHandler_AddRef((*obj = iface)); - return S_OK; + if (!is_stream_selected(source->pd, i)) + continue; + + event_type = MEStreamStopped; + hr = IMFMediaEventQueue_QueueEventParamVar(source->streams[i]->event_queue, event_type, &GUID_NULL, + S_OK, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); }
- *obj = NULL; - return E_NOINTERFACE; -} + source->state = SOURCE_STOPPED;
-static ULONG WINAPI test_handler_AddRef(IMFMediaTypeHandler *iface) -{ - return 2; -} + LeaveCriticalSection(&source->cs);
-static ULONG WINAPI test_handler_Release(IMFMediaTypeHandler *iface) -{ - return 1; + return S_OK; }
-static HRESULT WINAPI test_handler_IsMediaTypeSupported(IMFMediaTypeHandler *iface, IMFMediaType *in_type, - IMFMediaType **out_type) +static HRESULT WINAPI test_seek_source_Pause(IMFMediaSource *iface) { - struct test_handler *impl = impl_from_IMFMediaTypeHandler(iface); - BOOL result; - - if (out_type) - *out_type = NULL; - - if (impl->invalid_type && IMFMediaType_Compare(impl->invalid_type, (IMFAttributes *)in_type, - MF_ATTRIBUTES_MATCH_OUR_ITEMS, &result) == S_OK && result) - return MF_E_INVALIDMEDIATYPE; - - if (!impl->current_type) - return S_OK; - - if (IMFMediaType_Compare(impl->current_type, (IMFAttributes *)in_type, - MF_ATTRIBUTES_MATCH_OUR_ITEMS, &result) == S_OK && result) - return S_OK; + struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); + MediaEventType event_type; + HRESULT hr; + int i;
- return MF_E_INVALIDMEDIATYPE; -} + add_object_state(&actual_object_state_record, SOURCE_PAUSE);
-static HRESULT WINAPI test_handler_GetMediaTypeCount(IMFMediaTypeHandler *iface, DWORD *count) -{ - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; -} + EnterCriticalSection(&source->cs);
-static HRESULT WINAPI test_handler_GetMediaTypeByIndex(IMFMediaTypeHandler *iface, DWORD index, - IMFMediaType **type) -{ - struct test_handler *impl = impl_from_IMFMediaTypeHandler(iface); + event_type = MESourcePaused; + hr = IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, &GUID_NULL, S_OK, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- if (impl->media_types) + for (i = 0; i < source->stream_count; ++i) { - impl->enum_count++; - - if (index >= impl->media_types_count) - return MF_E_NO_MORE_TYPES; + if (!is_stream_selected(source->pd, i)) + continue;
- IMFMediaType_AddRef((*type = impl->media_types[index])); - return S_OK; + event_type = MEStreamPaused; + hr = IMFMediaEventQueue_QueueEventParamVar(source->streams[i]->event_queue, event_type, &GUID_NULL, + S_OK, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); }
- ok(0, "Unexpected call.\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI test_handler_SetCurrentMediaType(IMFMediaTypeHandler *iface, IMFMediaType *media_type) -{ - struct test_handler *impl = impl_from_IMFMediaTypeHandler(iface); - - if (impl->current_type) - IMFMediaType_Release(impl->current_type); - IMFMediaType_AddRef((impl->current_type = media_type)); - impl->set_current_count++; + source->state = SOURCE_PAUSED; + LeaveCriticalSection(&source->cs);
return S_OK; }
-static HRESULT WINAPI test_handler_GetCurrentMediaType(IMFMediaTypeHandler *iface, IMFMediaType **media_type) +static HRESULT WINAPI test_seek_source_Shutdown(IMFMediaSource *iface) { - struct test_handler *impl = impl_from_IMFMediaTypeHandler(iface); + struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); HRESULT hr;
- if (!impl->current_type) - { - if (!impl->media_types) - return E_FAIL; - if (!impl->media_types_count) - return MF_E_TRANSFORM_TYPE_NOT_SET; - return MF_E_NOT_INITIALIZED; - } - - if (FAILED(hr = MFCreateMediaType(media_type))) - return hr; - - hr = IMFMediaType_CopyAllItems(impl->current_type, (IMFAttributes *)*media_type); - if (FAILED(hr)) - IMFMediaType_Release(*media_type); + add_object_state(&actual_object_state_record, SOURCE_SHUTDOWN);
- return hr; -} + hr = IMFMediaEventQueue_Shutdown(source->event_queue); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-static HRESULT WINAPI test_handler_GetMajorType(IMFMediaTypeHandler *iface, GUID *type) -{ - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + return S_OK; }
-static const IMFMediaTypeHandlerVtbl test_handler_vtbl = -{ - test_handler_QueryInterface, - test_handler_AddRef, - test_handler_Release, - test_handler_IsMediaTypeSupported, - test_handler_GetMediaTypeCount, - test_handler_GetMediaTypeByIndex, - test_handler_SetCurrentMediaType, - test_handler_GetCurrentMediaType, - test_handler_GetMajorType, -}; - -static const struct test_handler test_handler = {.IMFMediaTypeHandler_iface.lpVtbl = &test_handler_vtbl}; - -struct test_media_sink +static const IMFMediaSourceVtbl test_seek_source_vtbl = { - IMFMediaSink IMFMediaSink_iface; - BOOL shutdown; + test_seek_source_QueryInterface, + test_seek_source_AddRef, + test_seek_source_Release, + test_seek_source_GetEvent, + test_seek_source_BeginGetEvent, + test_seek_source_EndGetEvent, + test_seek_source_QueueEvent, + test_seek_source_GetCharacteristics, + test_seek_source_CreatePresentationDescriptor, + test_seek_source_Start, + test_seek_source_Stop, + test_seek_source_Pause, + test_seek_source_Shutdown, };
-static struct test_media_sink *impl_from_IMFMediaSink(IMFMediaSink *iface) -{ - return CONTAINING_RECORD(iface, struct test_media_sink, IMFMediaSink_iface); -} - -static HRESULT WINAPI test_media_sink_QueryInterface(IMFMediaSink *iface, REFIID riid, void **obj) +static HRESULT WINAPI test_seek_clock_sink_QueryInterface(IMFClockStateSink *iface, REFIID riid, void **obj) { - if (IsEqualIID(riid, &IID_IMFMediaSink) - || IsEqualIID(riid, &IID_IUnknown)) + if (IsEqualIID(riid, &IID_IMFClockStateSink) || + IsEqualIID(riid, &IID_IUnknown)) { - IMFMediaSink_AddRef((*obj = iface)); + *obj = iface; + IMFClockStateSink_AddRef(iface); return S_OK; }
@@ -1640,2946 +1775,992 @@ static HRESULT WINAPI test_media_sink_QueryInterface(IMFMediaSink *iface, REFIID return E_NOINTERFACE; }
-static ULONG WINAPI test_media_sink_AddRef(IMFMediaSink *iface) +static ULONG WINAPI test_seek_clock_sink_AddRef(IMFClockStateSink *iface) { - return 2; + return 2; }
-static ULONG WINAPI test_media_sink_Release(IMFMediaSink *iface) +static ULONG WINAPI test_seek_clock_sink_Release(IMFClockStateSink *iface) { - return 1; + return 1; }
-static HRESULT WINAPI test_media_sink_GetCharacteristics(IMFMediaSink *iface, DWORD *characteristics) +static HRESULT WINAPI test_seek_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME system_time, LONGLONG offset) { - *characteristics = 0; - return S_OK; + add_object_state(&actual_object_state_record, SINK_ON_CLOCK_START); + return S_OK; }
-static HRESULT WINAPI test_media_sink_AddStreamSink(IMFMediaSink *iface, - DWORD stream_sink_id, IMFMediaType *media_type, IMFStreamSink **stream_sink) +static HRESULT WINAPI test_seek_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME system_time) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + add_object_state(&actual_object_state_record, SINK_ON_CLOCK_STOP); + return S_OK; }
-static HRESULT WINAPI test_media_sink_RemoveStreamSink(IMFMediaSink *iface, DWORD stream_sink_id) +static HRESULT WINAPI test_seek_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME system_time) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + add_object_state(&actual_object_state_record, SINK_ON_CLOCK_PAUSE); + return S_OK; }
-static HRESULT WINAPI test_media_sink_GetStreamSinkCount(IMFMediaSink *iface, DWORD *count) +static HRESULT WINAPI test_seek_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME system_time) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + add_object_state(&actual_object_state_record, SINK_ON_CLOCK_RESTART); + return S_OK; }
-static HRESULT WINAPI test_media_sink_GetStreamSinkByIndex(IMFMediaSink *iface, DWORD index, IMFStreamSink **sink) +static HRESULT WINAPI test_seek_clock_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME system_time, float rate) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + add_object_state(&actual_object_state_record, SINK_ON_CLOCK_SETRATE); + return S_OK; }
-static HRESULT WINAPI test_media_sink_GetStreamSinkById(IMFMediaSink *iface, DWORD stream_sink_id, IMFStreamSink **sink) +static const IMFClockStateSinkVtbl test_seek_clock_sink_vtbl = { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; -} + test_seek_clock_sink_QueryInterface, + test_seek_clock_sink_AddRef, + test_seek_clock_sink_Release, + test_seek_clock_sink_OnClockStart, + test_seek_clock_sink_OnClockStop, + test_seek_clock_sink_OnClockPause, + test_seek_clock_sink_OnClockRestart, + test_seek_clock_sink_OnClockSetRate, +};
-static HRESULT WINAPI test_media_sink_SetPresentationClock(IMFMediaSink *iface, IMFPresentationClock *clock) +static struct test_media_stream *create_test_stream(DWORD stream_index, IMFMediaSource *source) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; -} + struct test_media_stream *stream; + IMFPresentationDescriptor *pd; + BOOL selected; + HRESULT hr;
-static HRESULT WINAPI test_media_sink_GetPresentationClock(IMFMediaSink *iface, IMFPresentationClock **clock) -{ - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; -} + stream = calloc(1, sizeof(*stream)); + stream->IMFMediaStream_iface.lpVtbl = &test_media_stream_vtbl; + stream->refcount = 1; + hr = MFCreateEventQueue(&stream->event_queue); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + stream->source = source; + IMFMediaSource_AddRef(stream->source); + stream->is_new = TRUE;
-static HRESULT WINAPI test_media_sink_Shutdown(IMFMediaSink *iface) -{ - struct test_media_sink *sink = impl_from_IMFMediaSink(iface); - ok(!sink->shutdown, "Unexpected call.\n"); - sink->shutdown = TRUE; - return S_OK; + IMFMediaSource_CreatePresentationDescriptor(source, &pd); + IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, stream_index, &selected, &stream->sd); + IMFPresentationDescriptor_Release(pd); + + return stream; }
-static const IMFMediaSinkVtbl test_media_sink_vtbl = +static IMFMediaSource *create_test_seek_source(BOOL seekable) { - test_media_sink_QueryInterface, - test_media_sink_AddRef, - test_media_sink_Release, - test_media_sink_GetCharacteristics, - test_media_sink_AddStreamSink, - test_media_sink_RemoveStreamSink, - test_media_sink_GetStreamSinkCount, - test_media_sink_GetStreamSinkByIndex, - test_media_sink_GetStreamSinkById, - test_media_sink_SetPresentationClock, - test_media_sink_GetPresentationClock, - test_media_sink_Shutdown, -}; + struct test_seek_source *source; + int i;
-static const struct test_media_sink test_media_sink = {.IMFMediaSink_iface.lpVtbl = &test_media_sink_vtbl}; + source = calloc(1, sizeof(*source)); + source->IMFMediaSource_iface.lpVtbl = &test_seek_source_vtbl; + source->refcount = 1; + source->stream_count = 1; + source->seekable = seekable; + MFCreateEventQueue(&source->event_queue); + InitializeCriticalSection(&source->cs); + for (i = 0; i < source->stream_count; ++i) + source->streams[i] = create_test_stream(i, &source->IMFMediaSource_iface);
-struct test_stream_sink -{ - IMFStreamSink IMFStreamSink_iface; - IMFMediaTypeHandler *handler; - IMFMediaSink *media_sink; -}; + return &source->IMFMediaSource_iface; +}
-static struct test_stream_sink *impl_from_IMFStreamSink(IMFStreamSink *iface) -{ - return CONTAINING_RECORD(iface, struct test_stream_sink, IMFStreamSink_iface); -} - -static HRESULT WINAPI test_stream_sink_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj) +static void test_media_session_events(void) { - if (IsEqualIID(riid, &IID_IMFStreamSink) - || IsEqualIID(riid, &IID_IMFMediaEventGenerator) - || IsEqualIID(riid, &IID_IUnknown)) + static const media_type_desc audio_float_44100 = { - IMFStreamSink_AddRef((*obj = iface)); - return S_OK; - } + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float), + ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1), + ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 4), + ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100), + ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 4 * 44100), + ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 4 * 8), + }; + static const media_type_desc audio_pcm_48000 = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM), + ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1), + ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 2), + ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 48000), + ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 2 * 48000), + ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 2 * 8), + };
- *obj = NULL; - return E_NOINTERFACE; -} + struct test_stream_sink stream_sink = test_stream_sink; + struct test_media_sink media_sink = test_media_sink; + struct test_handler handler = test_handler; + struct test_source *source_impl; + IMFAsyncCallback *callback, *callback2; + IMFMediaType *input_type, *output_type; + IMFTopologyNode *src_node, *sink_node; + IMFPresentationDescriptor *pd; + IMFMediaSession *session; + IMFStreamDescriptor *sd; + IMFAsyncResult *result; + IMFMediaSource *source; + IMFTopology *topology; + IMFMediaEvent *event; + PROPVARIANT propvar; + HRESULT hr; + ULONG ref;
-static ULONG WINAPI test_stream_sink_AddRef(IMFStreamSink *iface) -{ - return 2; -} + stream_sink.handler = &handler.IMFMediaTypeHandler_iface; + stream_sink.media_sink = &media_sink.IMFMediaSink_iface;
-static ULONG WINAPI test_stream_sink_Release(IMFStreamSink *iface) -{ - return 1; -} + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Startup failure, hr %#lx.\n", hr);
-static HRESULT WINAPI test_stream_sink_GetEvent(IMFStreamSink *iface, DWORD flags, IMFMediaEvent **event) -{ - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; -} + callback = create_test_callback(TRUE); + callback2 = create_test_callback(TRUE);
-static HRESULT WINAPI test_stream_sink_BeginGetEvent(IMFStreamSink *iface, IMFAsyncCallback *callback, IUnknown *state) -{ - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; -} + hr = MFCreateMediaSession(NULL, &session); + ok(hr == S_OK, "Failed to create media session, hr %#lx.\n", hr);
-static HRESULT WINAPI test_stream_sink_EndGetEvent(IMFStreamSink *iface, IMFAsyncResult *result, - IMFMediaEvent **event) -{ - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; -} + hr = IMFMediaSession_GetEvent(session, MF_EVENT_FLAG_NO_WAIT, &event); + ok(hr == MF_E_NO_EVENTS_AVAILABLE, "Unexpected hr %#lx.\n", hr);
-static HRESULT WINAPI test_stream_sink_QueueEvent(IMFStreamSink *iface, MediaEventType event_type, - REFGUID ext_type, HRESULT hr, const PROPVARIANT *value) -{ - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; -} + /* Async case. */ + hr = IMFMediaSession_BeginGetEvent(session, NULL, NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
-static HRESULT WINAPI test_stream_sink_GetMediaSink(IMFStreamSink *iface, IMFMediaSink **sink) -{ - struct test_stream_sink *impl = impl_from_IMFStreamSink(iface); + hr = IMFMediaSession_BeginGetEvent(session, callback, (IUnknown *)session); + ok(hr == S_OK, "Failed to Begin*, hr %#lx.\n", hr); + EXPECT_REF(callback, 2);
- if (impl->media_sink) - { - IMFMediaSink_AddRef((*sink = impl->media_sink)); - return S_OK; - } + /* Same callback, same state. */ + hr = IMFMediaSession_BeginGetEvent(session, callback, (IUnknown *)session); + ok(hr == MF_S_MULTIPLE_BEGIN, "Unexpected hr %#lx.\n", hr); + EXPECT_REF(callback, 2);
- todo_wine - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; -} + /* Same callback, different state. */ + hr = IMFMediaSession_BeginGetEvent(session, callback, (IUnknown *)callback); + ok(hr == MF_E_MULTIPLE_BEGIN, "Unexpected hr %#lx.\n", hr); + EXPECT_REF(callback, 2);
-static HRESULT WINAPI test_stream_sink_GetIdentifier(IMFStreamSink *iface, DWORD *id) -{ - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; -} + /* Different callback, same state. */ + hr = IMFMediaSession_BeginGetEvent(session, callback2, (IUnknown *)session); + ok(hr == MF_E_MULTIPLE_SUBSCRIBERS, "Unexpected hr %#lx.\n", hr); + EXPECT_REF(callback2, 1);
-static HRESULT WINAPI test_stream_sink_GetMediaTypeHandler(IMFStreamSink *iface, IMFMediaTypeHandler **handler) -{ - struct test_stream_sink *impl = impl_from_IMFStreamSink(iface); + /* Different callback, different state. */ + hr = IMFMediaSession_BeginGetEvent(session, callback2, (IUnknown *)callback); + ok(hr == MF_E_MULTIPLE_SUBSCRIBERS, "Unexpected hr %#lx.\n", hr); + EXPECT_REF(callback, 2);
- if (impl->handler) - { - IMFMediaTypeHandler_AddRef((*handler = impl->handler)); - return S_OK; - } + hr = MFCreateAsyncResult(NULL, callback, NULL, &result); + ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr);
- ok(0, "Unexpected call.\n"); - return E_NOTIMPL; -} + hr = IMFMediaSession_EndGetEvent(session, result, &event); + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
-static HRESULT WINAPI test_stream_sink_ProcessSample(IMFStreamSink *iface, IMFSample *sample) -{ - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; -} + /* Shutdown behavior. */ + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + IMFMediaSession_Release(session);
-static HRESULT WINAPI test_stream_sink_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type, - const PROPVARIANT *marker_value, const PROPVARIANT *context) -{ - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; -} + /* Shutdown leaks callback */ + EXPECT_REF(callback, 2); + EXPECT_REF(callback2, 1);
-static HRESULT WINAPI test_stream_sink_Flush(IMFStreamSink *iface) -{ - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; -} + IMFAsyncCallback_Release(callback); + IMFAsyncCallback_Release(callback2);
-static const IMFStreamSinkVtbl test_stream_sink_vtbl = -{ - test_stream_sink_QueryInterface, - test_stream_sink_AddRef, - test_stream_sink_Release, - test_stream_sink_GetEvent, - test_stream_sink_BeginGetEvent, - test_stream_sink_EndGetEvent, - test_stream_sink_QueueEvent, - test_stream_sink_GetMediaSink, - test_stream_sink_GetIdentifier, - test_stream_sink_GetMediaTypeHandler, - test_stream_sink_ProcessSample, - test_stream_sink_PlaceMarker, - test_stream_sink_Flush, -};
-static const struct test_stream_sink test_stream_sink = {.IMFStreamSink_iface.lpVtbl = &test_stream_sink_vtbl}; + callback = create_test_callback(TRUE);
-struct test_callback -{ - IMFAsyncCallback IMFAsyncCallback_iface; - LONG refcount; + hr = MFCreateMediaSession(NULL, &session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- HANDLE event; - IMFMediaEvent *media_event; - BOOL check_media_event; -}; + propvar.vt = VT_EMPTY; + hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionStarted, 1000, &propvar); + ok(hr == MF_E_INVALIDREQUEST, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt);
-static struct test_callback *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) -{ - return CONTAINING_RECORD(iface, struct test_callback, IMFAsyncCallback_iface); -} + hr = IMFMediaSession_Stop(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionStopped, 1000, &propvar); + todo_wine + ok(hr == MF_E_INVALIDREQUEST, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt);
-static HRESULT WINAPI testcallback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) -{ - if (IsEqualIID(riid, &IID_IMFAsyncCallback) || - IsEqualIID(riid, &IID_IUnknown)) - { - *obj = iface; - IMFAsyncCallback_AddRef(iface); - return S_OK; - } + hr = IMFMediaSession_Pause(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionPaused, 1000, &propvar); + todo_wine + ok(hr == MF_E_INVALIDREQUEST, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt);
- *obj = NULL; - return E_NOINTERFACE; -} + hr = IMFMediaSession_ClearTopologies(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionTopologiesCleared, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt);
-static ULONG WINAPI testcallback_AddRef(IMFAsyncCallback *iface) -{ - struct test_callback *callback = impl_from_IMFAsyncCallback(iface); - return InterlockedIncrement(&callback->refcount); -} + hr = IMFMediaSession_ClearTopologies(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionTopologiesCleared, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt);
-static ULONG WINAPI testcallback_Release(IMFAsyncCallback *iface) -{ - struct test_callback *callback = impl_from_IMFAsyncCallback(iface); - ULONG refcount = InterlockedDecrement(&callback->refcount); + hr = IMFMediaSession_Close(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionClosed, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt);
- if (!refcount) - { - if (callback->media_event) - IMFMediaEvent_Release(callback->media_event); - CloseHandle(callback->event); - free(callback); - } - - return refcount; -} - -static HRESULT WINAPI testcallback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) -{ - ok(flags != NULL && queue != NULL, "Unexpected arguments.\n"); - return E_NOTIMPL; -} + hr = IMFMediaSession_ClearTopologies(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionTopologiesCleared, 1000, &propvar); + ok(hr == MF_E_INVALIDREQUEST, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt);
-static HRESULT WINAPI testcallback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) -{ - struct test_callback *callback = CONTAINING_RECORD(iface, struct test_callback, IMFAsyncCallback_iface); - IUnknown *object; - HRESULT hr; + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ok(result != NULL, "Unexpected result object.\n"); + /* sometimes briefly leaking */ + IMFMediaSession_Release(session);
- if (callback->media_event) - IMFMediaEvent_Release(callback->media_event);
- if (callback->check_media_event) - { - hr = IMFAsyncResult_GetObject(result, &object); - ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + hr = MFCreateMediaSession(NULL, &session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- hr = IMFAsyncResult_GetState(result, &object); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFMediaEventGenerator_EndGetEvent((IMFMediaEventGenerator *)object, - result, &callback->media_event); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - IUnknown_Release(object); - } + hr = MFCreateMediaType(&input_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_media_type(input_type, audio_float_44100, -1); + create_descriptors(1, &input_type, NULL, &pd, &sd);
- SetEvent(callback->event); + hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &sink_node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_sink_node(&stream_sink.IMFStreamSink_iface, -1, sink_node);
- return S_OK; -} + hr = MFCreateMediaType(&output_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_media_type(output_type, audio_pcm_48000, -1); + handler.media_types_count = 1; + handler.media_types = &output_type;
-static const IMFAsyncCallbackVtbl testcallbackvtbl = -{ - testcallback_QueryInterface, - testcallback_AddRef, - testcallback_Release, - testcallback_GetParameters, - testcallback_Invoke, -}; + hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &src_node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_source_node(NULL, -1, src_node, pd, sd);
-static IMFAsyncCallback *create_test_callback(BOOL check_media_event) -{ - struct test_callback *callback; + hr = MFCreateTopology(&topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopology_AddNode(topology, sink_node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopology_AddNode(topology, src_node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- if (!(callback = calloc(1, sizeof(*callback)))) - return NULL; + hr = IMFMediaSession_SetTopology(session, 0, topology); + ok(hr == MF_E_TOPO_MISSING_SOURCE, "Unexpected hr %#lx.\n", hr);
- callback->refcount = 1; - callback->check_media_event = check_media_event; - callback->IMFAsyncCallback_iface.lpVtbl = &testcallbackvtbl; - callback->event = CreateEventW(NULL, FALSE, FALSE, NULL); - ok(!!callback->event, "CreateEventW failed, error %lu\n", GetLastError()); + source = create_test_source(pd); + init_source_node(source, -1, src_node, pd, sd);
- return &callback->IMFAsyncCallback_iface; -} + hr = IMFMediaSession_SetTopology(session, 0, topology); + ok(hr == MF_E_TOPO_STREAM_DESCRIPTOR_NOT_SELECTED, "Unexpected hr %#lx.\n", hr);
-#define wait_media_event(a, b, c, d, e) wait_media_event_(__LINE__, a, b, c, d, e) -static HRESULT wait_media_event_(int line, IMFMediaSession *session, IMFAsyncCallback *callback, - MediaEventType expect_type, DWORD timeout, PROPVARIANT *value) -{ - struct test_callback *impl = impl_from_IMFAsyncCallback(callback); - MediaEventType type; - HRESULT hr, status; - DWORD ret; - GUID guid; + hr = IMFMediaSession_ClearTopologies(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionTopologiesCleared, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt);
- do - { - hr = IMFMediaSession_BeginGetEvent(session, &impl->IMFAsyncCallback_iface, (IUnknown *)session); - ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ret = WaitForSingleObject(impl->event, timeout); - ok_(__FILE__, line)(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", ret); - hr = IMFMediaEvent_GetType(impl->media_event, &type); - ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); - } while (type != expect_type); + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!media_sink.shutdown, "media sink is shutdown.\n"); + media_sink.shutdown = FALSE;
- ok_(__FILE__, line)(type == expect_type, "got type %lu\n", type); + /* sometimes briefly leaking */ + IMFMediaSession_Release(session);
- hr = IMFMediaEvent_GetExtendedType(impl->media_event, &guid); - ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok_(__FILE__, line)(IsEqualGUID(&guid, &GUID_NULL), "got extended type %s\n", debugstr_guid(&guid)); + if (handler.current_type) + IMFMediaType_Release(handler.current_type); + handler.current_type = NULL;
- hr = IMFMediaEvent_GetValue(impl->media_event, value); - ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- hr = IMFMediaEvent_GetStatus(impl->media_event, &status); - ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + /* SetTopology without a current output type */
- return status; -} + hr = MFCreateMediaSession(NULL, &session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-#define wait_media_event_until_blocking(a, b, c, d, e) wait_media_event_until_blocking_(__LINE__, a, b, c, d, e) -static HRESULT wait_media_event_until_blocking_(int line, IMFMediaSession *session, IMFAsyncCallback *callback, - MediaEventType expect_type, DWORD timeout, PROPVARIANT *value) -{ - struct test_callback *impl = impl_from_IMFAsyncCallback(callback); - MediaEventType type; - HRESULT hr, status; - DWORD ret; - GUID guid; + IMFPresentationDescriptor_SelectStream(pd, 0);
- do - { - hr = IMFMediaSession_BeginGetEvent(session, &impl->IMFAsyncCallback_iface, (IUnknown *)session); - ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ret = WaitForSingleObject(impl->event, timeout); - if (ret == WAIT_TIMEOUT) return WAIT_TIMEOUT; - hr = IMFMediaEvent_GetType(impl->media_event, &type); - ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); - } while (type != expect_type); + hr = IMFMediaSession_SetTopology(session, MFSESSION_SETTOPOLOGY_NORESOLUTION, topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionTopologySet, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_UNKNOWN, "got vt %u\n", propvar.vt); + ok(propvar.punkVal == (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); + PropVariantClear(&propvar);
- ok_(__FILE__, line)(type == expect_type, "got type %lu\n", type); + ok(!handler.enum_count, "got %lu GetMediaTypeByIndex\n", handler.enum_count); + ok(!handler.set_current_count, "got %lu SetCurrentMediaType\n", handler.set_current_count); + handler.enum_count = handler.set_current_count = 0;
- hr = IMFMediaEvent_GetExtendedType(impl->media_event, &guid); - ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok_(__FILE__, line)(IsEqualGUID(&guid, &GUID_NULL), "got extended type %s\n", debugstr_guid(&guid)); + hr = IMFMediaSession_ClearTopologies(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionTopologiesCleared, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt);
- hr = IMFMediaEvent_GetValue(impl->media_event, value); - ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(media_sink.shutdown, "media sink didn't shutdown.\n"); + media_sink.shutdown = FALSE;
- hr = IMFMediaEvent_GetStatus(impl->media_event, &status); - ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + /* sometimes briefly leaking */ + IMFMediaSession_Release(session);
- return status; -} + if (handler.current_type) + IMFMediaType_Release(handler.current_type); + handler.current_type = NULL;
-static IMFMediaSource *create_media_source(const WCHAR *name, const WCHAR *mime) -{ - IMFSourceResolver *resolver; - IMFAttributes *attributes; - const BYTE *resource_data; - MF_OBJECT_TYPE obj_type; - IMFMediaSource *source; - IMFByteStream *stream; - ULONG resource_len; - HRSRC resource; - HRESULT hr;
- resource = FindResourceW(NULL, name, (const WCHAR *)RT_RCDATA); - ok(resource != 0, "FindResourceW %s failed, error %lu\n", debugstr_w(name), GetLastError()); - resource_data = LockResource(LoadResource(GetModuleHandleW(NULL), resource)); - resource_len = SizeofResource(GetModuleHandleW(NULL), resource); + /* SetTopology without a current output type */
- hr = MFCreateTempFile(MF_ACCESSMODE_READWRITE, MF_OPENMODE_DELETE_IF_EXIST, MF_FILEFLAGS_NONE, &stream); + hr = MFCreateMediaSession(NULL, &session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFByteStream_Write(stream, resource_data, resource_len, &resource_len); + + hr = IMFMediaSession_SetTopology(session, 0, topology); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFByteStream_SetCurrentPosition(stream, 0); + hr = wait_media_event(session, callback, MESessionTopologySet, 1000, &propvar); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_UNKNOWN, "got vt %u\n", propvar.vt); + ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); + PropVariantClear(&propvar);
- hr = IMFByteStream_QueryInterface(stream, &IID_IMFAttributes, (void **)&attributes); + todo_wine + ok(!handler.enum_count, "got %lu GetMediaTypeByIndex\n", handler.enum_count); + ok(handler.set_current_count, "got %lu SetCurrentMediaType\n", handler.set_current_count); + handler.enum_count = handler.set_current_count = 0; + + hr = IMFMediaSession_ClearTopologies(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFAttributes_SetString(attributes, &MF_BYTESTREAM_CONTENT_TYPE, mime); - ok(hr == S_OK, "Failed to set string value, hr %#lx.\n", hr); - IMFAttributes_Release(attributes); + hr = wait_media_event(session, callback, MESessionTopologiesCleared, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt);
- hr = MFCreateSourceResolver(&resolver); + hr = IMFMediaSession_Shutdown(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL, - &obj_type, (IUnknown **)&source); - todo_wine_if(hr == MF_E_UNEXPECTED) /* Gitlab CI Debian runner */ - ok(hr == S_OK || broken(hr == MF_E_UNSUPPORTED_BYTESTREAM_TYPE), "Unexpected hr %#lx.\n", hr); - IMFSourceResolver_Release(resolver); - IMFByteStream_Release(stream); + ok(media_sink.shutdown, "media sink didn't shutdown.\n"); + media_sink.shutdown = FALSE;
- if (FAILED(hr)) - return NULL; + /* sometimes briefly leaking */ + IMFMediaSession_Release(session);
- ok(obj_type == MF_OBJECT_MEDIASOURCE, "got %d\n", obj_type); - return source; -} + if (handler.current_type) + IMFMediaType_Release(handler.current_type); + handler.current_type = NULL;
-enum object_state -{ - SOURCE_START, - SOURCE_PAUSE, - SOURCE_STOP, - SOURCE_SHUTDOWN, - SINK_ON_CLOCK_START, - SINK_ON_CLOCK_PAUSE, - SINK_ON_CLOCK_STOP, - SINK_ON_CLOCK_RESTART, - SINK_ON_CLOCK_SETRATE, -};
-#define MAX_OBJECT_STATE 1024 + /* SetTopology without a current output type, refusing input type */
-struct object_state_record -{ - enum object_state states[MAX_OBJECT_STATE]; - unsigned int state_count; -}; -static struct object_state_record actual_object_state_record; + handler.invalid_type = input_type;
-#define add_object_state(a, b) _add_object_state(__LINE__, a, b) -static void _add_object_state(int line, struct object_state_record *record, enum object_state state) -{ - ok_(__FILE__, line)(record->state_count < MAX_OBJECT_STATE, "exceeded state_count maximum %d.\n", MAX_OBJECT_STATE); - if (record->state_count < MAX_OBJECT_STATE) - record->states[record->state_count++] = state; -} + hr = MFCreateMediaSession(NULL, &session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-#define compare_object_states(a, b) _compare_object_states(__LINE__, a, b) -static void _compare_object_states(int line, const struct object_state_record *r1, - const struct object_state_record *r2) -{ - ok_(__FILE__, line)(r1->state_count == r2->state_count, "State count not equal.\n"); - if (r1->state_count == r2->state_count) - ok_(__FILE__, line)(!memcmp(r1->states, r2->states, sizeof(enum object_state) * r1->state_count), "Got different states.\n"); -} + hr = IMFMediaSession_SetTopology(session, 0, topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionTopologySet, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_UNKNOWN, "got vt %u\n", propvar.vt); + ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); + PropVariantClear(&propvar);
-enum source_state -{ - SOURCE_STOPPED, - SOURCE_RUNNING, - SOURCE_PAUSED, -}; + ok(handler.enum_count, "got %lu GetMediaTypeByIndex\n", handler.enum_count); + ok(handler.set_current_count, "got %lu SetCurrentMediaType\n", handler.set_current_count); + handler.enum_count = handler.set_current_count = 0;
-struct test_media_stream -{ - IMFMediaStream IMFMediaStream_iface; - IMFMediaEventQueue *event_queue; - IMFStreamDescriptor *sd; - IMFMediaSource *source; - LONGLONG sample_duration; - LONGLONG sample_time; - BOOL is_new; - LONG refcount; -}; + hr = IMFMediaSession_ClearTopologies(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionTopologiesCleared, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt);
-static struct test_media_stream *impl_from_IMFMediaStream(IMFMediaStream *iface) -{ - return CONTAINING_RECORD(iface, struct test_media_stream, IMFMediaStream_iface); -} + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(media_sink.shutdown, "media sink didn't shutdown.\n"); + media_sink.shutdown = FALSE;
-static HRESULT WINAPI test_media_stream_QueryInterface(IMFMediaStream *iface, REFIID riid, void **out) -{ - if (IsEqualIID(riid, &IID_IMFMediaStream) - || IsEqualIID(riid, &IID_IMFMediaEventGenerator) - || IsEqualIID(riid, &IID_IUnknown)) - { - *out = iface; - } - else - { - *out = NULL; - return E_NOINTERFACE; - } + /* sometimes briefly leaking */ + IMFMediaSession_Release(session);
- IMFMediaStream_AddRef(iface); - return S_OK; -} + if (handler.current_type) + IMFMediaType_Release(handler.current_type); + handler.current_type = NULL;
-static ULONG WINAPI test_media_stream_AddRef(IMFMediaStream *iface) -{ - struct test_media_stream *stream = impl_from_IMFMediaStream(iface); - return InterlockedIncrement(&stream->refcount); -}
-static ULONG WINAPI test_media_stream_Release(IMFMediaStream *iface) -{ - struct test_media_stream *stream = impl_from_IMFMediaStream(iface); - ULONG refcount = InterlockedDecrement(&stream->refcount); + /* SetTopology without a current output type, refusing input type, requiring a converter */
- if (!refcount) - { - IMFMediaEventQueue_Release(stream->event_queue); - free(stream); - } + handler.media_types_count = 0; + handler.invalid_type = input_type;
- return refcount; -} + hr = MFCreateMediaSession(NULL, &session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-static HRESULT WINAPI test_media_stream_GetEvent(IMFMediaStream *iface, DWORD flags, IMFMediaEvent **event) -{ - struct test_media_stream *stream = impl_from_IMFMediaStream(iface); - return IMFMediaEventQueue_GetEvent(stream->event_queue, flags, event); -} + hr = IMFMediaSession_SetTopology(session, 0, topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionTopologySet, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_UNKNOWN, "got vt %u\n", propvar.vt); + ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); + PropVariantClear(&propvar);
-static HRESULT WINAPI test_media_stream_BeginGetEvent(IMFMediaStream *iface, IMFAsyncCallback *callback, IUnknown *state) -{ - struct test_media_stream *stream = impl_from_IMFMediaStream(iface); - return IMFMediaEventQueue_BeginGetEvent(stream->event_queue, callback, state); -} + ok(!handler.enum_count, "got %lu GetMediaTypeByIndex\n", handler.enum_count); + ok(handler.set_current_count, "got %lu SetCurrentMediaType\n", handler.set_current_count); + handler.enum_count = handler.set_current_count = 0;
-static HRESULT WINAPI test_media_stream_EndGetEvent(IMFMediaStream *iface, IMFAsyncResult *result, IMFMediaEvent **event) -{ - struct test_media_stream *stream = impl_from_IMFMediaStream(iface); - return IMFMediaEventQueue_EndGetEvent(stream->event_queue, result, event); -} + hr = IMFMediaSession_ClearTopologies(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionTopologiesCleared, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt);
-static HRESULT WINAPI test_media_stream_QueueEvent(IMFMediaStream *iface, MediaEventType event_type, REFGUID ext_type, - HRESULT hr, const PROPVARIANT *value) -{ - struct test_media_stream *stream = impl_from_IMFMediaStream(iface); - return IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, event_type, ext_type, hr, value); -} + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(media_sink.shutdown, "media sink didn't shutdown.\n"); + media_sink.shutdown = FALSE;
-static HRESULT WINAPI test_media_stream_GetMediaSource(IMFMediaStream *iface, IMFMediaSource **source) -{ - struct test_media_stream *stream = impl_from_IMFMediaStream(iface); + /* sometimes briefly leaking */ + IMFMediaSession_Release(session);
- *source = stream->source; - IMFMediaSource_AddRef(*source); + if (handler.current_type) + IMFMediaType_Release(handler.current_type); + handler.current_type = NULL;
- return S_OK; -}
-static HRESULT WINAPI test_media_stream_GetStreamDescriptor(IMFMediaStream *iface, IMFStreamDescriptor **sd) -{ - struct test_media_stream *stream = impl_from_IMFMediaStream(iface); + /* SetTopology with a current output type */
- *sd = stream->sd; - IMFStreamDescriptor_AddRef(*sd); + handler.media_types_count = 1; + IMFMediaType_AddRef((handler.current_type = output_type));
- return S_OK; -} + hr = MFCreateMediaSession(NULL, &session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-static HRESULT WINAPI test_media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token) -{ - struct test_media_stream *stream = impl_from_IMFMediaStream(iface); - IMFMediaBuffer *buffer; - IMFSample *sample; - HRESULT hr; + hr = IMFMediaSession_SetTopology(session, 0, topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionTopologySet, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_UNKNOWN, "got vt %u\n", propvar.vt); + ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); + PropVariantClear(&propvar);
- hr = MFCreateSample(&sample); + ok(!handler.enum_count, "got %lu GetMediaTypeByIndex\n", handler.enum_count); + ok(handler.set_current_count, "got %lu SetCurrentMediaType\n", handler.set_current_count); + handler.enum_count = handler.set_current_count = 0; + + hr = IMFMediaSession_ClearTopologies(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (stream->sample_duration) - { - hr = IMFSample_SetSampleDuration(sample, stream->sample_duration); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionTopologiesCleared, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt);
- hr = IMFSample_SetSampleTime(sample, stream->sample_time); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(media_sink.shutdown, "media sink didn't shutdown.\n"); + media_sink.shutdown = FALSE;
- stream->sample_time += stream->sample_duration; - } - else - { - hr = IMFSample_SetSampleTime(sample, 123); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + /* sometimes briefly leaking */ + IMFMediaSession_Release(session);
- hr = IMFSample_SetSampleDuration(sample, 1); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - }
- if (token) - IMFSample_SetUnknown(sample, &MFSampleExtension_Token, token); + /* test IMFMediaSession_Start with source returning an error in BeginGetEvent */ + source_impl = impl_from_IMFMediaSource(source);
- /* Reader expects buffers, empty samples are considered an error. */ - hr = MFCreateMemoryBuffer(8, &buffer); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFSample_AddBuffer(sample, buffer); + hr = MFCreateMediaSession(NULL, &session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - IMFMediaBuffer_Release(buffer);
- hr = IMFMediaEventQueue_QueueEventParamUnk(stream->event_queue, MEMediaSample, &GUID_NULL, S_OK, - (IUnknown *)sample); + hr = IMFMediaSession_SetTopology(session, 0, topology); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - IMFSample_Release(sample); + hr = wait_media_event(session, callback, MESessionTopologySet, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_UNKNOWN, "got vt %u\n", propvar.vt); + ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); + PropVariantClear(&propvar);
- return S_OK; -} + source_impl->begin_get_event_res = 0x80001234;
-static const IMFMediaStreamVtbl test_media_stream_vtbl = -{ - test_media_stream_QueryInterface, - test_media_stream_AddRef, - test_media_stream_Release, - test_media_stream_GetEvent, - test_media_stream_BeginGetEvent, - test_media_stream_EndGetEvent, - test_media_stream_QueueEvent, - test_media_stream_GetMediaSource, - test_media_stream_GetStreamDescriptor, - test_media_stream_RequestSample, -}; - -#define TEST_SOURCE_NUM_STREAMS 3 - -struct test_seek_source -{ - IMFMediaSource IMFMediaSource_iface; - IMFMediaEventQueue *event_queue; - IMFPresentationDescriptor *pd; - struct test_media_stream *streams[TEST_SOURCE_NUM_STREAMS]; - enum source_state state; - unsigned stream_count; - CRITICAL_SECTION cs; - BOOL seekable; - LONG refcount; -}; - -static struct test_seek_source *impl_test_seek_source_from_IMFMediaSource(IMFMediaSource *iface) -{ - return CONTAINING_RECORD(iface, struct test_seek_source, IMFMediaSource_iface); -} - -static HRESULT WINAPI test_seek_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out) -{ - if (IsEqualIID(riid, &IID_IMFMediaSource) - || IsEqualIID(riid, &IID_IMFMediaEventGenerator) - || IsEqualIID(riid, &IID_IUnknown)) - { - *out = iface; - } - else - { - *out = NULL; - return E_NOINTERFACE; - } - - IMFMediaSource_AddRef(iface); - return S_OK; -} - -static ULONG WINAPI test_seek_source_AddRef(IMFMediaSource *iface) -{ - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); - return InterlockedIncrement(&source->refcount); -} - -static ULONG WINAPI test_seek_source_Release(IMFMediaSource *iface) -{ - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); - ULONG refcount = InterlockedDecrement(&source->refcount); - - if (!refcount) - { - IMFMediaEventQueue_Release(source->event_queue); - free(source); - } - - return refcount; -} - -static HRESULT WINAPI test_seek_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event) -{ - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); - return IMFMediaEventQueue_GetEvent(source->event_queue, flags, event); -} - -static HRESULT WINAPI test_seek_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state) -{ - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); - return IMFMediaEventQueue_BeginGetEvent(source->event_queue, callback, state); -} - -static HRESULT WINAPI test_seek_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event) -{ - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); - return IMFMediaEventQueue_EndGetEvent(source->event_queue, result, event); -} - -static HRESULT WINAPI test_seek_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type, - HRESULT hr, const PROPVARIANT *value) -{ - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); - return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, ext_type, hr, value); -} - -static HRESULT WINAPI test_seek_source_GetCharacteristics(IMFMediaSource *iface, DWORD *flags) -{ - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); - - if (source->seekable) - *flags = MFMEDIASOURCE_CAN_PAUSE | MFMEDIASOURCE_CAN_SEEK; - else - *flags = MFMEDIASOURCE_CAN_PAUSE; - return S_OK; -} - -static HRESULT WINAPI test_seek_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **pd) -{ - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); - IMFStreamDescriptor *sds[ARRAY_SIZE(source->streams)]; - IMFMediaType *media_type; - HRESULT hr = S_OK; - int i; - - EnterCriticalSection(&source->cs); - - if (source->pd) - { - *pd = source->pd; - IMFPresentationDescriptor_AddRef(*pd); - } - else - { - for (i = 0; i < source->stream_count; ++i) - { - hr = MFCreateMediaType(&media_type); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFVideoFormat_RGB32); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, (UINT64)640 << 32 | 480); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - hr = MFCreateStreamDescriptor(i, 1, &media_type, &sds[i]); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - IMFMediaType_Release(media_type); - } - - hr = MFCreatePresentationDescriptor(source->stream_count, sds, &source->pd); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFPresentationDescriptor_SetUINT64(source->pd, &MF_PD_DURATION, 10 * 10000000); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFPresentationDescriptor_SelectStream(source->pd, 0); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - for (i = 0; i < source->stream_count; ++i) - IMFStreamDescriptor_Release(sds[i]); - - *pd = source->pd; - IMFPresentationDescriptor_AddRef(*pd); - } - - LeaveCriticalSection(&source->cs); - - return hr; -} - -static BOOL is_stream_selected(IMFPresentationDescriptor *pd, DWORD index) -{ - IMFStreamDescriptor *sd; - BOOL selected = FALSE; - - if (SUCCEEDED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, index, &selected, &sd))) - IMFStreamDescriptor_Release(sd); - - return selected; -} - -static HRESULT WINAPI test_seek_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *pd, const GUID *time_format, - const PROPVARIANT *start_position) -{ - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); - MediaEventType event_type; - PROPVARIANT var; - HRESULT hr; - int i; - - add_object_state(&actual_object_state_record, SOURCE_START); - - ok(time_format && IsEqualGUID(time_format, &GUID_NULL), "Unexpected time format %s.\n", - wine_dbgstr_guid(time_format)); - ok(start_position && (start_position->vt == VT_I8 || start_position->vt == VT_EMPTY), - "Unexpected position type.\n"); - - /* This is what makes IMFMediaSession::Start() seeking fail, not the lacking of MFMEDIASOURCE_CAN_SEEK. - * Without this, IMFMediaSession::Start() seeking succeeds even with the missing MFMEDIASOURCE_CAN_SEEK. - * If this is check is not here, the first IMFMediaSession::Start() call to a non-zero position - * succeeds somehow on Windows 10, then all following seeks fails and no MESessionStarted events */ - if (!source->seekable && start_position && start_position->vt == VT_I8 && start_position->hVal.QuadPart) - return E_FAIL; - - EnterCriticalSection(&source->cs); - - event_type = source->state != SOURCE_STOPPED ? MESourceSeeked : MESourceStarted; - hr = IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, &GUID_NULL, S_OK, NULL); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - for (i = 0; i < source->stream_count; ++i) - { - if (!is_stream_selected(pd, i)) - continue; - - var.vt = VT_UNKNOWN; - var.punkVal = (IUnknown *)&source->streams[i]->IMFMediaStream_iface; - event_type = source->streams[i]->is_new ? MENewStream : MEUpdatedStream; - source->streams[i]->is_new = FALSE; - hr = IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, &GUID_NULL, S_OK, &var); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - event_type = source->state != SOURCE_STOPPED ? MEStreamSeeked : MEStreamStarted; - hr = IMFMediaEventQueue_QueueEventParamVar(source->streams[i]->event_queue, event_type, &GUID_NULL, - S_OK, NULL); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - } - - source->state = SOURCE_RUNNING; - - LeaveCriticalSection(&source->cs); - - return S_OK; -} - -static HRESULT WINAPI test_seek_source_Stop(IMFMediaSource *iface) -{ - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); - MediaEventType event_type; - HRESULT hr; - int i; - - add_object_state(&actual_object_state_record, SOURCE_STOP); - - EnterCriticalSection(&source->cs); - - event_type = MESourceStopped; - hr = IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, &GUID_NULL, S_OK, NULL); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - for (i = 0; i < source->stream_count; ++i) - { - if (!is_stream_selected(source->pd, i)) - continue; - - event_type = MEStreamStopped; - hr = IMFMediaEventQueue_QueueEventParamVar(source->streams[i]->event_queue, event_type, &GUID_NULL, - S_OK, NULL); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - } - - source->state = SOURCE_STOPPED; - - LeaveCriticalSection(&source->cs); - - return S_OK; -} - -static HRESULT WINAPI test_seek_source_Pause(IMFMediaSource *iface) -{ - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); - MediaEventType event_type; - HRESULT hr; - int i; - - add_object_state(&actual_object_state_record, SOURCE_PAUSE); - - EnterCriticalSection(&source->cs); - - event_type = MESourcePaused; - hr = IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, &GUID_NULL, S_OK, NULL); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - for (i = 0; i < source->stream_count; ++i) - { - if (!is_stream_selected(source->pd, i)) - continue; - - event_type = MEStreamPaused; - hr = IMFMediaEventQueue_QueueEventParamVar(source->streams[i]->event_queue, event_type, &GUID_NULL, - S_OK, NULL); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - } - - source->state = SOURCE_PAUSED; - LeaveCriticalSection(&source->cs); - - return S_OK; -} - -static HRESULT WINAPI test_seek_source_Shutdown(IMFMediaSource *iface) -{ - struct test_seek_source *source = impl_test_seek_source_from_IMFMediaSource(iface); - HRESULT hr; - - add_object_state(&actual_object_state_record, SOURCE_SHUTDOWN); - - hr = IMFMediaEventQueue_Shutdown(source->event_queue); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - return S_OK; -} - -static const IMFMediaSourceVtbl test_seek_source_vtbl = -{ - test_seek_source_QueryInterface, - test_seek_source_AddRef, - test_seek_source_Release, - test_seek_source_GetEvent, - test_seek_source_BeginGetEvent, - test_seek_source_EndGetEvent, - test_seek_source_QueueEvent, - test_seek_source_GetCharacteristics, - test_seek_source_CreatePresentationDescriptor, - test_seek_source_Start, - test_seek_source_Stop, - test_seek_source_Pause, - test_seek_source_Shutdown, -}; - -static HRESULT WINAPI test_seek_clock_sink_QueryInterface(IMFClockStateSink *iface, REFIID riid, void **obj) -{ - if (IsEqualIID(riid, &IID_IMFClockStateSink) || - IsEqualIID(riid, &IID_IUnknown)) - { - *obj = iface; - IMFClockStateSink_AddRef(iface); - return S_OK; - } - - *obj = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI test_seek_clock_sink_AddRef(IMFClockStateSink *iface) -{ - return 2; -} - -static ULONG WINAPI test_seek_clock_sink_Release(IMFClockStateSink *iface) -{ - return 1; -} - -static HRESULT WINAPI test_seek_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME system_time, LONGLONG offset) -{ - add_object_state(&actual_object_state_record, SINK_ON_CLOCK_START); - return S_OK; -} - -static HRESULT WINAPI test_seek_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME system_time) -{ - add_object_state(&actual_object_state_record, SINK_ON_CLOCK_STOP); - return S_OK; -} - -static HRESULT WINAPI test_seek_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME system_time) -{ - add_object_state(&actual_object_state_record, SINK_ON_CLOCK_PAUSE); - return S_OK; -} - -static HRESULT WINAPI test_seek_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME system_time) -{ - add_object_state(&actual_object_state_record, SINK_ON_CLOCK_RESTART); - return S_OK; -} - -static HRESULT WINAPI test_seek_clock_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME system_time, float rate) -{ - add_object_state(&actual_object_state_record, SINK_ON_CLOCK_SETRATE); - return S_OK; -} - -static const IMFClockStateSinkVtbl test_seek_clock_sink_vtbl = -{ - test_seek_clock_sink_QueryInterface, - test_seek_clock_sink_AddRef, - test_seek_clock_sink_Release, - test_seek_clock_sink_OnClockStart, - test_seek_clock_sink_OnClockStop, - test_seek_clock_sink_OnClockPause, - test_seek_clock_sink_OnClockRestart, - test_seek_clock_sink_OnClockSetRate, -}; - -static struct test_media_stream *create_test_stream(DWORD stream_index, IMFMediaSource *source) -{ - struct test_media_stream *stream; - IMFPresentationDescriptor *pd; - BOOL selected; - HRESULT hr; - - stream = calloc(1, sizeof(*stream)); - stream->IMFMediaStream_iface.lpVtbl = &test_media_stream_vtbl; - stream->refcount = 1; - hr = MFCreateEventQueue(&stream->event_queue); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - stream->source = source; - IMFMediaSource_AddRef(stream->source); - stream->is_new = TRUE; - - IMFMediaSource_CreatePresentationDescriptor(source, &pd); - IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, stream_index, &selected, &stream->sd); - IMFPresentationDescriptor_Release(pd); - - return stream; -} - -static IMFMediaSource *create_test_seek_source(BOOL seekable) -{ - struct test_seek_source *source; - int i; - - source = calloc(1, sizeof(*source)); - source->IMFMediaSource_iface.lpVtbl = &test_seek_source_vtbl; - source->refcount = 1; - source->stream_count = 1; - source->seekable = seekable; - MFCreateEventQueue(&source->event_queue); - InitializeCriticalSection(&source->cs); - for (i = 0; i < source->stream_count; ++i) - source->streams[i] = create_test_stream(i, &source->IMFMediaSource_iface); - - return &source->IMFMediaSource_iface; -} - -static void test_media_session_events(void) -{ - static const media_type_desc audio_float_44100 = - { - ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), - ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float), - ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1), - ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 4), - ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100), - ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 4 * 44100), - ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 4 * 8), - }; - static const media_type_desc audio_pcm_48000 = - { - ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), - ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM), - ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1), - ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 2), - ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 48000), - ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 2 * 48000), - ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 2 * 8), - }; - - struct test_stream_sink stream_sink = test_stream_sink; - struct test_media_sink media_sink = test_media_sink; - struct test_handler handler = test_handler; - struct test_source *source_impl; - IMFAsyncCallback *callback, *callback2; - IMFMediaType *input_type, *output_type; - IMFTopologyNode *src_node, *sink_node; - IMFPresentationDescriptor *pd; - IMFMediaSession *session; - IMFStreamDescriptor *sd; - IMFAsyncResult *result; - IMFMediaSource *source; - IMFTopology *topology; - IMFMediaEvent *event; - PROPVARIANT propvar; - HRESULT hr; - ULONG ref; - - stream_sink.handler = &handler.IMFMediaTypeHandler_iface; - stream_sink.media_sink = &media_sink.IMFMediaSink_iface; - - hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); - ok(hr == S_OK, "Startup failure, hr %#lx.\n", hr); - - callback = create_test_callback(TRUE); - callback2 = create_test_callback(TRUE); - - hr = MFCreateMediaSession(NULL, &session); - ok(hr == S_OK, "Failed to create media session, hr %#lx.\n", hr); - - hr = IMFMediaSession_GetEvent(session, MF_EVENT_FLAG_NO_WAIT, &event); - ok(hr == MF_E_NO_EVENTS_AVAILABLE, "Unexpected hr %#lx.\n", hr); - - /* Async case. */ - hr = IMFMediaSession_BeginGetEvent(session, NULL, NULL); - ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); - - hr = IMFMediaSession_BeginGetEvent(session, callback, (IUnknown *)session); - ok(hr == S_OK, "Failed to Begin*, hr %#lx.\n", hr); - EXPECT_REF(callback, 2); - - /* Same callback, same state. */ - hr = IMFMediaSession_BeginGetEvent(session, callback, (IUnknown *)session); - ok(hr == MF_S_MULTIPLE_BEGIN, "Unexpected hr %#lx.\n", hr); - EXPECT_REF(callback, 2); - - /* Same callback, different state. */ - hr = IMFMediaSession_BeginGetEvent(session, callback, (IUnknown *)callback); - ok(hr == MF_E_MULTIPLE_BEGIN, "Unexpected hr %#lx.\n", hr); - EXPECT_REF(callback, 2); - - /* Different callback, same state. */ - hr = IMFMediaSession_BeginGetEvent(session, callback2, (IUnknown *)session); - ok(hr == MF_E_MULTIPLE_SUBSCRIBERS, "Unexpected hr %#lx.\n", hr); - EXPECT_REF(callback2, 1); - - /* Different callback, different state. */ - hr = IMFMediaSession_BeginGetEvent(session, callback2, (IUnknown *)callback); - ok(hr == MF_E_MULTIPLE_SUBSCRIBERS, "Unexpected hr %#lx.\n", hr); - EXPECT_REF(callback, 2); - - hr = MFCreateAsyncResult(NULL, callback, NULL, &result); - ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); - - hr = IMFMediaSession_EndGetEvent(session, result, &event); - ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); - - /* Shutdown behavior. */ - hr = IMFMediaSession_Shutdown(session); - ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); - IMFMediaSession_Release(session); - - /* Shutdown leaks callback */ - EXPECT_REF(callback, 2); - EXPECT_REF(callback2, 1); - - IMFAsyncCallback_Release(callback); - IMFAsyncCallback_Release(callback2); - - - callback = create_test_callback(TRUE); - - hr = MFCreateMediaSession(NULL, &session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - propvar.vt = VT_EMPTY; - hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = wait_media_event(session, callback, MESessionStarted, 1000, &propvar); - ok(hr == MF_E_INVALIDREQUEST, "Unexpected hr %#lx.\n", hr); - ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); - - hr = IMFMediaSession_Stop(session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = wait_media_event(session, callback, MESessionStopped, 1000, &propvar); - todo_wine - ok(hr == MF_E_INVALIDREQUEST, "Unexpected hr %#lx.\n", hr); - ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); - - hr = IMFMediaSession_Pause(session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = wait_media_event(session, callback, MESessionPaused, 1000, &propvar); - todo_wine - ok(hr == MF_E_INVALIDREQUEST, "Unexpected hr %#lx.\n", hr); - ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); - - hr = IMFMediaSession_ClearTopologies(session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = wait_media_event(session, callback, MESessionTopologiesCleared, 1000, &propvar); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); - - hr = IMFMediaSession_ClearTopologies(session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = wait_media_event(session, callback, MESessionTopologiesCleared, 1000, &propvar); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); - - hr = IMFMediaSession_Close(session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = wait_media_event(session, callback, MESessionClosed, 1000, &propvar); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); - - hr = IMFMediaSession_ClearTopologies(session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = wait_media_event(session, callback, MESessionTopologiesCleared, 1000, &propvar); - ok(hr == MF_E_INVALIDREQUEST, "Unexpected hr %#lx.\n", hr); - ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); - - hr = IMFMediaSession_Shutdown(session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - /* sometimes briefly leaking */ - IMFMediaSession_Release(session); - - - hr = MFCreateMediaSession(NULL, &session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - hr = MFCreateMediaType(&input_type); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - init_media_type(input_type, audio_float_44100, -1); - create_descriptors(1, &input_type, NULL, &pd, &sd); - - hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &sink_node); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - init_sink_node(&stream_sink.IMFStreamSink_iface, -1, sink_node); - - hr = MFCreateMediaType(&output_type); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - init_media_type(output_type, audio_pcm_48000, -1); - handler.media_types_count = 1; - handler.media_types = &output_type; - - hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &src_node); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - init_source_node(NULL, -1, src_node, pd, sd); - - hr = MFCreateTopology(&topology); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFTopology_AddNode(topology, sink_node); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFTopology_AddNode(topology, src_node); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - hr = IMFMediaSession_SetTopology(session, 0, topology); - ok(hr == MF_E_TOPO_MISSING_SOURCE, "Unexpected hr %#lx.\n", hr); - - source = create_test_source(pd); - init_source_node(source, -1, src_node, pd, sd); - - hr = IMFMediaSession_SetTopology(session, 0, topology); - ok(hr == MF_E_TOPO_STREAM_DESCRIPTOR_NOT_SELECTED, "Unexpected hr %#lx.\n", hr); - - hr = IMFMediaSession_ClearTopologies(session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = wait_media_event(session, callback, MESessionTopologiesCleared, 1000, &propvar); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); - - hr = IMFMediaSession_Shutdown(session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(!media_sink.shutdown, "media sink is shutdown.\n"); - media_sink.shutdown = FALSE; - - /* sometimes briefly leaking */ - IMFMediaSession_Release(session); - - if (handler.current_type) - IMFMediaType_Release(handler.current_type); - handler.current_type = NULL; - - - /* SetTopology without a current output type */ - - hr = MFCreateMediaSession(NULL, &session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - IMFPresentationDescriptor_SelectStream(pd, 0); - - hr = IMFMediaSession_SetTopology(session, MFSESSION_SETTOPOLOGY_NORESOLUTION, topology); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = wait_media_event(session, callback, MESessionTopologySet, 1000, &propvar); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(propvar.vt == VT_UNKNOWN, "got vt %u\n", propvar.vt); - ok(propvar.punkVal == (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); - PropVariantClear(&propvar); - - ok(!handler.enum_count, "got %lu GetMediaTypeByIndex\n", handler.enum_count); - ok(!handler.set_current_count, "got %lu SetCurrentMediaType\n", handler.set_current_count); - handler.enum_count = handler.set_current_count = 0; - - hr = IMFMediaSession_ClearTopologies(session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = wait_media_event(session, callback, MESessionTopologiesCleared, 1000, &propvar); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); - - hr = IMFMediaSession_Shutdown(session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(media_sink.shutdown, "media sink didn't shutdown.\n"); - media_sink.shutdown = FALSE; - - /* sometimes briefly leaking */ - IMFMediaSession_Release(session); - - if (handler.current_type) - IMFMediaType_Release(handler.current_type); - handler.current_type = NULL; - - - /* SetTopology without a current output type */ - - hr = MFCreateMediaSession(NULL, &session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - hr = IMFMediaSession_SetTopology(session, 0, topology); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = wait_media_event(session, callback, MESessionTopologySet, 1000, &propvar); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(propvar.vt == VT_UNKNOWN, "got vt %u\n", propvar.vt); - ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); - PropVariantClear(&propvar); - - todo_wine - ok(!handler.enum_count, "got %lu GetMediaTypeByIndex\n", handler.enum_count); - ok(handler.set_current_count, "got %lu SetCurrentMediaType\n", handler.set_current_count); - handler.enum_count = handler.set_current_count = 0; - - hr = IMFMediaSession_ClearTopologies(session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = wait_media_event(session, callback, MESessionTopologiesCleared, 1000, &propvar); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); - - hr = IMFMediaSession_Shutdown(session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(media_sink.shutdown, "media sink didn't shutdown.\n"); - media_sink.shutdown = FALSE; - - /* sometimes briefly leaking */ - IMFMediaSession_Release(session); - - if (handler.current_type) - IMFMediaType_Release(handler.current_type); - handler.current_type = NULL; - - - /* SetTopology without a current output type, refusing input type */ - - handler.invalid_type = input_type; - - hr = MFCreateMediaSession(NULL, &session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - hr = IMFMediaSession_SetTopology(session, 0, topology); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = wait_media_event(session, callback, MESessionTopologySet, 1000, &propvar); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(propvar.vt == VT_UNKNOWN, "got vt %u\n", propvar.vt); - ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); - PropVariantClear(&propvar); - - ok(handler.enum_count, "got %lu GetMediaTypeByIndex\n", handler.enum_count); - ok(handler.set_current_count, "got %lu SetCurrentMediaType\n", handler.set_current_count); - handler.enum_count = handler.set_current_count = 0; - - hr = IMFMediaSession_ClearTopologies(session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = wait_media_event(session, callback, MESessionTopologiesCleared, 1000, &propvar); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); - - hr = IMFMediaSession_Shutdown(session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(media_sink.shutdown, "media sink didn't shutdown.\n"); - media_sink.shutdown = FALSE; - - /* sometimes briefly leaking */ - IMFMediaSession_Release(session); - - if (handler.current_type) - IMFMediaType_Release(handler.current_type); - handler.current_type = NULL; - - - /* SetTopology without a current output type, refusing input type, requiring a converter */ - - handler.media_types_count = 0; - handler.invalid_type = input_type; - - hr = MFCreateMediaSession(NULL, &session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - hr = IMFMediaSession_SetTopology(session, 0, topology); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = wait_media_event(session, callback, MESessionTopologySet, 1000, &propvar); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(propvar.vt == VT_UNKNOWN, "got vt %u\n", propvar.vt); - ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); - PropVariantClear(&propvar); - - ok(!handler.enum_count, "got %lu GetMediaTypeByIndex\n", handler.enum_count); - ok(handler.set_current_count, "got %lu SetCurrentMediaType\n", handler.set_current_count); - handler.enum_count = handler.set_current_count = 0; - - hr = IMFMediaSession_ClearTopologies(session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = wait_media_event(session, callback, MESessionTopologiesCleared, 1000, &propvar); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); - - hr = IMFMediaSession_Shutdown(session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(media_sink.shutdown, "media sink didn't shutdown.\n"); - media_sink.shutdown = FALSE; - - /* sometimes briefly leaking */ - IMFMediaSession_Release(session); - - if (handler.current_type) - IMFMediaType_Release(handler.current_type); - handler.current_type = NULL; - - - /* SetTopology with a current output type */ - - handler.media_types_count = 1; - IMFMediaType_AddRef((handler.current_type = output_type)); - - hr = MFCreateMediaSession(NULL, &session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - hr = IMFMediaSession_SetTopology(session, 0, topology); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = wait_media_event(session, callback, MESessionTopologySet, 1000, &propvar); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(propvar.vt == VT_UNKNOWN, "got vt %u\n", propvar.vt); - ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); - PropVariantClear(&propvar); - - ok(!handler.enum_count, "got %lu GetMediaTypeByIndex\n", handler.enum_count); - ok(handler.set_current_count, "got %lu SetCurrentMediaType\n", handler.set_current_count); - handler.enum_count = handler.set_current_count = 0; - - hr = IMFMediaSession_ClearTopologies(session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = wait_media_event(session, callback, MESessionTopologiesCleared, 1000, &propvar); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); - - hr = IMFMediaSession_Shutdown(session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(media_sink.shutdown, "media sink didn't shutdown.\n"); - media_sink.shutdown = FALSE; - - /* sometimes briefly leaking */ - IMFMediaSession_Release(session); - - - /* test IMFMediaSession_Start with source returning an error in BeginGetEvent */ - source_impl = impl_from_IMFMediaSource(source); - - hr = MFCreateMediaSession(NULL, &session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - hr = IMFMediaSession_SetTopology(session, 0, topology); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = wait_media_event(session, callback, MESessionTopologySet, 1000, &propvar); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(propvar.vt == VT_UNKNOWN, "got vt %u\n", propvar.vt); - ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); - PropVariantClear(&propvar); - - source_impl->begin_get_event_res = 0x80001234; - - SET_EXPECT(test_source_BeginGetEvent); - SET_EXPECT(test_source_QueueEvent); - SET_EXPECT(test_source_Start); - - propvar.vt = VT_EMPTY; - hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = wait_media_event_until_blocking(session, callback, MESessionStarted, 1000, &propvar); - ok(hr == 0x80001234, "Unexpected hr %#lx.\n", hr); - ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); - ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); - PropVariantClear(&propvar); - - CHECK_CALLED(test_source_BeginGetEvent); - CHECK_NOT_CALLED(test_source_Start); - - hr = IMFMediaSession_ClearTopologies(session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - hr = IMFMediaSession_Shutdown(session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(media_sink.shutdown, "media sink didn't shutdown.\n"); - media_sink.shutdown = FALSE; - - source_impl->begin_get_event_res = E_NOTIMPL; - - CLEAR_CALLED(test_source_BeginGetEvent); - CLEAR_CALLED(test_source_QueueEvent); - CLEAR_CALLED(test_source_Start); - - /* sometimes briefly leaking */ - IMFMediaSession_Release(session); - - - /* test IMFMediaSession_Start when test source BeginGetEvent returns S_OK */ - hr = MFCreateMediaSession(NULL, &session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - hr = IMFMediaSession_SetTopology(session, 0, topology); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = wait_media_event(session, callback, MESessionTopologySet, 1000, &propvar); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(propvar.vt == VT_UNKNOWN, "got vt %u\n", propvar.vt); - ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); - PropVariantClear(&propvar); - - source_impl = impl_from_IMFMediaSource(source); - source_impl->begin_get_event_res = S_OK; - - SET_EXPECT(test_source_BeginGetEvent); - SET_EXPECT(test_source_QueueEvent); - SET_EXPECT(test_source_Start); - - propvar.vt = VT_EMPTY; - hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = wait_media_event_until_blocking(session, callback, MESessionStarted, 1000, &propvar); - ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr); - ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); - ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); - PropVariantClear(&propvar); - - CHECK_CALLED(test_source_BeginGetEvent); - CHECK_CALLED(test_source_Start); - - hr = IMFMediaSession_ClearTopologies(session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - hr = IMFMediaSession_Shutdown(session); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(media_sink.shutdown, "media sink didn't shutdown.\n"); - media_sink.shutdown = FALSE; - - source_impl->begin_get_event_res = E_NOTIMPL; - - CLEAR_CALLED(test_source_BeginGetEvent); - CLEAR_CALLED(test_source_QueueEvent); - CLEAR_CALLED(test_source_Start); - - /* sometimes briefly leaking */ - IMFMediaSession_Release(session); - - IMFAsyncCallback_Release(callback); - - if (handler.current_type) - IMFMediaType_Release(handler.current_type); - handler.current_type = NULL; - - hr = IMFTopology_Clear(topology); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ref = IMFTopologyNode_Release(src_node); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFTopologyNode_Release(sink_node); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFTopology_Release(topology); - ok(ref == 0, "Release returned %ld\n", ref); - - ref = IMFMediaSource_Release(source); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFPresentationDescriptor_Release(pd); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFStreamDescriptor_Release(sd); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFMediaType_Release(input_type); - ok(ref == 0, "Release returned %ld\n", ref); - - - hr = MFShutdown(); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -} - -static void test_media_session(void) -{ - IMFRateSupport *rate_support; - IMFAttributes *attributes; - IMFMediaSession *session; - MFSHUTDOWN_STATUS status; - IMFTopology *topology; - IMFShutdown *shutdown; - PROPVARIANT propvar; - IMFGetService *gs; - IMFClock *clock; - HRESULT hr; - DWORD caps; - - hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); - ok(hr == S_OK, "Startup failure, hr %#lx.\n", hr); - - hr = MFCreateMediaSession(NULL, &session); - ok(hr == S_OK, "Failed to create media session, hr %#lx.\n", hr); - - check_interface(session, &IID_IMFGetService, TRUE); - check_interface(session, &IID_IMFRateSupport, TRUE); - check_interface(session, &IID_IMFRateControl, TRUE); - check_interface(session, &IID_IMFAttributes, FALSE); - check_interface(session, &IID_IMFTopologyNodeAttributeEditor, FALSE); - check_interface(session, &IID_IMFLocalMFTRegistration, FALSE); - check_service_interface(session, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, TRUE); - check_service_interface(session, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateControl, TRUE); - check_service_interface(session, &MF_TOPONODE_ATTRIBUTE_EDITOR_SERVICE, &IID_IMFTopologyNodeAttributeEditor, TRUE); - check_service_interface(session, &MF_LOCAL_MFT_REGISTRATION_SERVICE, &IID_IMFLocalMFTRegistration, TRUE); - - hr = IMFMediaSession_GetClock(session, &clock); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - hr = IMFClock_QueryInterface(clock, &IID_IMFShutdown, (void **)&shutdown); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - hr = IMFShutdown_GetShutdownStatus(shutdown, &status); - ok(hr == MF_E_INVALIDREQUEST, "Unexpected hr %#lx.\n", hr); - - hr = IMFMediaSession_Shutdown(session); - ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); - - check_interface(session, &IID_IMFGetService, TRUE); - - hr = IMFMediaSession_QueryInterface(session, &IID_IMFGetService, (void **)&gs); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - hr = IMFGetService_GetService(gs, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support); - ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); - - IMFGetService_Release(gs); - - hr = IMFShutdown_GetShutdownStatus(shutdown, &status); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(status == MFSHUTDOWN_COMPLETED, "Unexpected shutdown status %u.\n", status); - - IMFShutdown_Release(shutdown); - - hr = IMFMediaSession_ClearTopologies(session); - ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); - - hr = IMFMediaSession_Start(session, &GUID_NULL, NULL); - ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); - - propvar.vt = VT_EMPTY; - hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); - ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); - - hr = IMFMediaSession_Pause(session); - ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); - - hr = IMFMediaSession_Stop(session); - ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); - - hr = IMFMediaSession_Close(session); - ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); - - hr = IMFMediaSession_GetClock(session, &clock); - ok(hr == MF_E_SHUTDOWN || broken(hr == E_UNEXPECTED) /* Win7 */, "Unexpected hr %#lx.\n", hr); - - hr = IMFMediaSession_GetSessionCapabilities(session, &caps); - ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); - - hr = IMFMediaSession_GetSessionCapabilities(session, NULL); - ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); - - hr = IMFMediaSession_GetFullTopology(session, MFSESSION_GETFULLTOPOLOGY_CURRENT, 0, &topology); - ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); - - hr = IMFMediaSession_Shutdown(session); - ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr); - - IMFMediaSession_Release(session); - - /* Custom topology loader, GUID is not registered. */ - hr = MFCreateAttributes(&attributes, 1); - ok(hr == S_OK, "Failed to create attributes, hr %#lx.\n", hr); - - hr = IMFAttributes_SetGUID(attributes, &MF_SESSION_TOPOLOADER, &MF_SESSION_TOPOLOADER); - ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); - - hr = MFCreateMediaSession(attributes, &session); - ok(hr == S_OK, "Failed to create media session, hr %#lx.\n", hr); - IMFMediaSession_Release(session); - - /* Disabled quality manager. */ - hr = IMFAttributes_SetGUID(attributes, &MF_SESSION_QUALITY_MANAGER, &GUID_NULL); - ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); - - hr = MFCreateMediaSession(attributes, &session); - ok(hr == S_OK, "Failed to create media session, hr %#lx.\n", hr); - IMFMediaSession_Release(session); - - IMFAttributes_Release(attributes); -} - -static void test_media_session_rate_control(void) -{ - IMFRateControl *rate_control, *clock_rate_control; - IMFPresentationClock *presentation_clock; - IMFPresentationTimeSource *time_source; - MFCLOCK_PROPERTIES clock_props; - IMFRateSupport *rate_support; - IMFMediaSession *session; - IMFClock *clock; - HRESULT hr; - float rate; - BOOL thin; - - hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); - ok(hr == S_OK, "Startup failure, hr %#lx.\n", hr); - - hr = MFCreateMediaSession(NULL, &session); - ok(hr == S_OK, "Failed to create media session, hr %#lx.\n", hr); - - hr = MFGetService((IUnknown *)session, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support); - ok(hr == S_OK, "Failed to get rate support interface, hr %#lx.\n", hr); - - hr = MFGetService((IUnknown *)session, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateControl, (void **)&rate_control); - ok(hr == S_OK, "Failed to get rate control interface, hr %#lx.\n", hr); - - hr = IMFRateControl_GetRate(rate_control, NULL, NULL); - ok(FAILED(hr), "Unexpected hr %#lx.\n", hr); - - rate = 0.0f; - hr = IMFRateControl_GetRate(rate_control, NULL, &rate); - ok(hr == S_OK, "Failed to get playback rate, hr %#lx.\n", hr); - ok(rate == 1.0f, "Unexpected rate %f.\n", rate); - - hr = IMFRateControl_GetRate(rate_control, &thin, NULL); - ok(FAILED(hr), "Unexpected hr %#lx.\n", hr); - - thin = TRUE; - rate = 0.0f; - hr = IMFRateControl_GetRate(rate_control, &thin, &rate); - ok(hr == S_OK, "Failed to get playback rate, hr %#lx.\n", hr); - ok(!thin, "Unexpected thinning.\n"); - ok(rate == 1.0f, "Unexpected rate %f.\n", rate); - - hr = IMFMediaSession_GetClock(session, &clock); - ok(hr == S_OK, "Failed to get clock, hr %#lx.\n", hr); - - hr = IMFClock_QueryInterface(clock, &IID_IMFPresentationClock, (void **)&presentation_clock); - ok(hr == S_OK, "Failed to get rate control, hr %#lx.\n", hr); - - hr = IMFClock_QueryInterface(clock, &IID_IMFRateControl, (void **)&clock_rate_control); - ok(hr == S_OK, "Failed to get rate control, hr %#lx.\n", hr); - - rate = 0.0f; - hr = IMFRateControl_GetRate(clock_rate_control, NULL, &rate); - ok(hr == S_OK, "Failed to get clock rate, hr %#lx.\n", hr); - ok(rate == 1.0f, "Unexpected rate %f.\n", rate); - - hr = IMFRateControl_SetRate(clock_rate_control, FALSE, 1.5f); - ok(hr == MF_E_CLOCK_NO_TIME_SOURCE, "Unexpected hr %#lx.\n", hr); - - hr = IMFRateControl_SetRate(rate_control, FALSE, 1.5f); - ok(hr == S_OK, "Failed to set rate, hr %#lx.\n", hr); - - hr = IMFClock_GetProperties(clock, &clock_props); - ok(hr == MF_E_CLOCK_NO_TIME_SOURCE, "Unexpected hr %#lx.\n", hr); - - hr = MFCreateSystemTimeSource(&time_source); - ok(hr == S_OK, "Failed to create time source, hr %#lx.\n", hr); - - hr = IMFPresentationClock_SetTimeSource(presentation_clock, time_source); - ok(hr == S_OK, "Failed to set time source, hr %#lx.\n", hr); - - hr = IMFRateControl_SetRate(rate_control, FALSE, 1.5f); - ok(hr == S_OK, "Failed to set rate, hr %#lx.\n", hr); - - rate = 0.0f; - hr = IMFRateControl_GetRate(clock_rate_control, NULL, &rate); - ok(hr == S_OK, "Failed to get clock rate, hr %#lx.\n", hr); - ok(rate == 1.0f, "Unexpected rate %f.\n", rate); - - IMFPresentationTimeSource_Release(time_source); - - IMFRateControl_Release(clock_rate_control); - IMFPresentationClock_Release(presentation_clock); - IMFClock_Release(clock); - - IMFRateControl_Release(rate_control); - IMFRateSupport_Release(rate_support); - - IMFMediaSession_Release(session); - - hr = MFShutdown(); - ok(hr == S_OK, "Shutdown failure, hr %#lx.\n", hr); -} - -struct test_grabber_callback -{ - IMFSampleGrabberSinkCallback IMFSampleGrabberSinkCallback_iface; - LONG refcount; - - IMFCollection *samples; - HANDLE ready_event; - HANDLE done_event; -}; - -static struct test_grabber_callback *impl_from_IMFSampleGrabberSinkCallback(IMFSampleGrabberSinkCallback *iface) -{ - return CONTAINING_RECORD(iface, struct test_grabber_callback, IMFSampleGrabberSinkCallback_iface); -} - -static HRESULT WINAPI test_grabber_callback_QueryInterface(IMFSampleGrabberSinkCallback *iface, REFIID riid, void **obj) -{ - if (IsEqualIID(riid, &IID_IMFSampleGrabberSinkCallback) || - IsEqualIID(riid, &IID_IMFClockStateSink) || - IsEqualIID(riid, &IID_IUnknown)) - { - *obj = iface; - IMFSampleGrabberSinkCallback_AddRef(iface); - return S_OK; - } - - *obj = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI test_grabber_callback_AddRef(IMFSampleGrabberSinkCallback *iface) -{ - struct test_grabber_callback *grabber = impl_from_IMFSampleGrabberSinkCallback(iface); - return InterlockedIncrement(&grabber->refcount); -} - -static ULONG WINAPI test_grabber_callback_Release(IMFSampleGrabberSinkCallback *iface) -{ - struct test_grabber_callback *grabber = impl_from_IMFSampleGrabberSinkCallback(iface); - ULONG refcount = InterlockedDecrement(&grabber->refcount); - - if (!refcount) - { - IMFCollection_Release(grabber->samples); - if (grabber->ready_event) - CloseHandle(grabber->ready_event); - if (grabber->done_event) - CloseHandle(grabber->done_event); - free(grabber); - } - - return refcount; -} + SET_EXPECT(test_source_BeginGetEvent); + SET_EXPECT(test_source_QueueEvent); + SET_EXPECT(test_source_Start);
-static HRESULT WINAPI test_grabber_callback_OnClockStart(IMFSampleGrabberSinkCallback *iface, MFTIME time, LONGLONG offset) -{ - return S_OK; -} + propvar.vt = VT_EMPTY; + hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event_until_blocking(session, callback, MESessionStarted, 1000, &propvar); + ok(hr == 0x80001234, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); + PropVariantClear(&propvar);
-static HRESULT WINAPI test_grabber_callback_OnClockStop(IMFSampleGrabberSinkCallback *iface, MFTIME time) -{ - return S_OK; -} + CHECK_CALLED(test_source_BeginGetEvent); + CHECK_NOT_CALLED(test_source_Start);
-static HRESULT WINAPI test_grabber_callback_OnClockPause(IMFSampleGrabberSinkCallback *iface, MFTIME time) -{ - return S_OK; -} + hr = IMFMediaSession_ClearTopologies(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-static HRESULT WINAPI test_grabber_callback_OnClockRestart(IMFSampleGrabberSinkCallback *iface, MFTIME time) -{ - return S_OK; -} + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(media_sink.shutdown, "media sink didn't shutdown.\n"); + media_sink.shutdown = FALSE;
-static HRESULT WINAPI test_grabber_callback_OnClockSetRate(IMFSampleGrabberSinkCallback *iface, MFTIME time, float rate) -{ - return S_OK; -} + source_impl->begin_get_event_res = E_NOTIMPL;
-static HRESULT WINAPI test_grabber_callback_OnSetPresentationClock(IMFSampleGrabberSinkCallback *iface, - IMFPresentationClock *clock) -{ - return S_OK; -} + CLEAR_CALLED(test_source_BeginGetEvent); + CLEAR_CALLED(test_source_QueueEvent); + CLEAR_CALLED(test_source_Start);
-static HRESULT WINAPI test_grabber_callback_OnProcessSample(IMFSampleGrabberSinkCallback *iface, REFGUID major_type, - DWORD sample_flags, LONGLONG sample_time, LONGLONG sample_duration, const BYTE *buffer, DWORD sample_size) -{ - struct test_grabber_callback *grabber = CONTAINING_RECORD(iface, struct test_grabber_callback, IMFSampleGrabberSinkCallback_iface); - IMFSample *sample; - HRESULT hr; - DWORD res; + /* sometimes briefly leaking */ + IMFMediaSession_Release(session);
- if (!grabber->ready_event) - return E_NOTIMPL;
- sample = create_sample(buffer, sample_size); - hr = IMFSample_SetSampleFlags(sample, sample_flags); + /* test IMFMediaSession_Start when test source BeginGetEvent returns S_OK */ + hr = MFCreateMediaSession(NULL, &session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - /* FIXME: sample time is inconsistent across windows versions, ignore it */ - hr = IMFSample_SetSampleTime(sample, 0); + + hr = IMFMediaSession_SetTopology(session, 0, topology); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFSample_SetSampleDuration(sample, sample_duration); + hr = wait_media_event(session, callback, MESessionTopologySet, 1000, &propvar); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - IMFCollection_AddElement(grabber->samples, (IUnknown *)sample); - IMFSample_Release(sample); - - SetEvent(grabber->ready_event); - res = WaitForSingleObject(grabber->done_event, 1000); - ok(!res, "WaitForSingleObject returned %#lx\n", res); - - return S_OK; -} + ok(propvar.vt == VT_UNKNOWN, "got vt %u\n", propvar.vt); + ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); + PropVariantClear(&propvar);
-static HRESULT WINAPI test_grabber_callback_OnShutdown(IMFSampleGrabberSinkCallback *iface) -{ - return S_OK; -} + source_impl = impl_from_IMFMediaSource(source); + source_impl->begin_get_event_res = S_OK;
-static const IMFSampleGrabberSinkCallbackVtbl test_grabber_callback_vtbl = -{ - test_grabber_callback_QueryInterface, - test_grabber_callback_AddRef, - test_grabber_callback_Release, - test_grabber_callback_OnClockStart, - test_grabber_callback_OnClockStop, - test_grabber_callback_OnClockPause, - test_grabber_callback_OnClockRestart, - test_grabber_callback_OnClockSetRate, - test_grabber_callback_OnSetPresentationClock, - test_grabber_callback_OnProcessSample, - test_grabber_callback_OnShutdown, -}; + SET_EXPECT(test_source_BeginGetEvent); + SET_EXPECT(test_source_QueueEvent); + SET_EXPECT(test_source_Start);
-static IMFSampleGrabberSinkCallback *create_test_grabber_callback(void) -{ - struct test_grabber_callback *grabber; - HRESULT hr; + propvar.vt = VT_EMPTY; + hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event_until_blocking(session, callback, MESessionStarted, 1000, &propvar); + ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); + PropVariantClear(&propvar);
- if (!(grabber = calloc(1, sizeof(*grabber)))) - return NULL; + CHECK_CALLED(test_source_BeginGetEvent); + CHECK_CALLED(test_source_Start);
- grabber->IMFSampleGrabberSinkCallback_iface.lpVtbl = &test_grabber_callback_vtbl; - grabber->refcount = 1; - hr = MFCreateCollection(&grabber->samples); + hr = IMFMediaSession_ClearTopologies(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- return &grabber->IMFSampleGrabberSinkCallback_iface; -} - -enum loader_test_flags -{ - LOADER_TODO = 0x4, - LOADER_NEEDS_VIDEO_PROCESSOR = 0x8, - LOADER_SET_ENUMERATE_SOURCE_TYPES = 0x10, - LOADER_NO_CURRENT_OUTPUT = 0x20, - LOADER_SET_INVALID_INPUT = 0x40, - LOADER_SET_MEDIA_TYPES = 0x80, - LOADER_ADD_RESAMPLER_MFT = 0x100, -}; + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(media_sink.shutdown, "media sink didn't shutdown.\n"); + media_sink.shutdown = FALSE;
-static void test_topology_loader(void) -{ - static const media_type_desc audio_float_44100 = - { - ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), - ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float), - ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1), - ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 4), - ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100), - ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 4 * 44100), - ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 4 * 8), - }; - static const media_type_desc audio_pcm_44100 = - { - ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), - ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM), - ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1), - ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100), - ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 44100), - ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 1), - ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 8), - }; - static const media_type_desc audio_pcm_48000 = - { - ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), - ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM), - ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1), - ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 48000), - ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 48000), - ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 1), - ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 8), - }; - static const media_type_desc audio_pcm_48000_resampler = - { - ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), - ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM), - ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16), - ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2), - ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 48000), - ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 192000), - ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 4), - ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), - ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1), - }; - static const media_type_desc audio_float_48000 = - { - ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), - ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float), - ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2), - ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 48000), - ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 8 * 48000), - ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 8), - ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 32), - }; - static const media_type_desc audio_mp3_44100 = - { - ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), - ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_MP3), - ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2), - ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100), - ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 16000), - ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 1), - }; - static const media_type_desc audio_pcm_44100_incomplete = - { - ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), - ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM), - ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1), - ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100), - ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 1), - ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 8), - }; - static const media_type_desc audio_float_44100_stereo = - { - ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), - ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float), - ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2), - ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 2 * 4), - ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100), - ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 2 * 4 * 44100), - ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 4 * 8), - ATTR_UINT32(MF_MT_AUDIO_CHANNEL_MASK, 3), - ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), - }; - static const media_type_desc video_i420_1280 = - { - ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), - ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_I420), - ATTR_RATIO(MF_MT_FRAME_SIZE, 1280, 720), - }; - static const media_type_desc video_color_convert_1280_rgb32 = - { - ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), - ATTR_GUID(MF_MT_SUBTYPE, DMOVideoFormat_RGB32), - ATTR_RATIO(MF_MT_FRAME_SIZE, 1280, 720), - }; - static const media_type_desc video_video_processor_1280_rgb32 = - { - ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), - ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), - ATTR_RATIO(MF_MT_FRAME_SIZE, 1280, 720), - }; - static const media_type_desc video_video_processor_rgb32 = - { - ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), - ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), - }; - static const media_type_desc video_h264_1280 = - { - ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), - ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_H264), - ATTR_RATIO(MF_MT_FRAME_SIZE, 1280, 720), - }; - static const media_type_desc video_nv12_1280 = - { - ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), - ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12), - ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001), - ATTR_RATIO(MF_MT_FRAME_SIZE, 1280, 720), - ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), - ATTR_UINT32(MF_MT_SAMPLE_SIZE, 1280 * 720 * 3 / 2), - ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), - ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 1280), - ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), - ATTR_UINT32(MF_MT_INTERLACE_MODE, 7), - }; - static const media_type_desc video_dummy = - { - ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), - }; + source_impl->begin_get_event_res = E_NOTIMPL;
- const struct loader_test - { - const media_type_desc *input_type; - const media_type_desc *output_type; - const media_type_desc *current_input; - const media_type_desc *decoded_type; - MF_CONNECT_METHOD source_method; - MF_CONNECT_METHOD sink_method; - HRESULT expected_result; - unsigned int flags; - GUID decoder_class; - GUID converter_class; - } - loader_tests[] = - { - { - /* PCM -> PCM, same enumerated type, no current type */ - .input_type = &audio_pcm_44100, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, - .expected_result = S_OK, - }, - { - /* PCM -> PCM, same enumerated type, incomplete current type */ - .input_type = &audio_pcm_44100, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, - .current_input = &audio_pcm_44100_incomplete, - .expected_result = MF_E_INVALIDMEDIATYPE, - .flags = LOADER_TODO, - }, - { - /* PCM -> PCM, same enumerated bps, different current bps */ - .input_type = &audio_pcm_48000, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, - .current_input = &audio_pcm_44100, - .expected_result = MF_E_INVALIDMEDIATYPE, - }, - { - /* PCM -> PCM, same enumerated bps, different current bps, force enumerate */ - .input_type = &audio_pcm_48000, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, - .current_input = &audio_pcm_44100, - .expected_result = S_OK, - .flags = LOADER_SET_ENUMERATE_SOURCE_TYPES, - }, + CLEAR_CALLED(test_source_BeginGetEvent); + CLEAR_CALLED(test_source_QueueEvent); + CLEAR_CALLED(test_source_Start);
- { - /* PCM -> PCM, incomplete enumerated type, same current type */ - .input_type = &audio_pcm_44100_incomplete, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, - .current_input = &audio_pcm_44100, - .expected_result = S_OK, - }, - { - /* PCM -> PCM, incomplete enumerated type, same current type, force enumerate */ - .input_type = &audio_pcm_44100_incomplete, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, - .current_input = &audio_pcm_44100, - .expected_result = MF_E_NO_MORE_TYPES, - .flags = LOADER_SET_ENUMERATE_SOURCE_TYPES | LOADER_TODO, - }, + /* sometimes briefly leaking */ + IMFMediaSession_Release(session);
- { - /* PCM -> PCM, different enumerated bps, no current type */ - .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, - .expected_result = MF_E_INVALIDMEDIATYPE, - }, - { - /* PCM -> PCM, different enumerated bps, same current bps */ - .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, - .current_input = &audio_pcm_48000, - .expected_result = S_OK, - }, - { - /* PCM -> PCM, different enumerated bps, same current bps, force enumerate */ - .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, - .current_input = &audio_pcm_48000, - .expected_result = MF_E_NO_MORE_TYPES, - .flags = LOADER_SET_ENUMERATE_SOURCE_TYPES, - }, - { - /* PCM -> PCM, different enumerated bps, no current type, sink allow converter */ - .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_ALLOW_CONVERTER, .source_method = MF_CONNECT_DIRECT, - .expected_result = S_OK, .converter_class = CLSID_CResamplerMediaObject, - }, - { - /* PCM -> PCM, different enumerated bps, same current type, sink allow converter, force enumerate */ - .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_ALLOW_CONVERTER, .source_method = -1, - .current_input = &audio_pcm_48000, - .expected_result = S_OK, .converter_class = CLSID_CResamplerMediaObject, - .flags = LOADER_SET_ENUMERATE_SOURCE_TYPES, - }, - { - /* PCM -> PCM, different enumerated bps, no current type, sink allow decoder */ - .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_ALLOW_DECODER, .source_method = MF_CONNECT_DIRECT, - .expected_result = S_OK, .converter_class = CLSID_CResamplerMediaObject, - }, - { - /* PCM -> PCM, different enumerated bps, no current type, default methods */ - .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = -1, .source_method = -1, - .expected_result = S_OK, .converter_class = CLSID_CResamplerMediaObject, - }, - { - /* PCM -> PCM, different enumerated bps, no current type, source allow converter */ - .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_DIRECT, .source_method = MF_CONNECT_ALLOW_CONVERTER, - .expected_result = MF_E_INVALIDMEDIATYPE, - }, + IMFAsyncCallback_Release(callback);
- { - /* Float -> PCM, refuse input type, add converter */ - .input_type = &audio_float_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, - .expected_result = MF_E_NO_MORE_TYPES, .converter_class = CLSID_CResamplerMediaObject, - .flags = LOADER_SET_INVALID_INPUT | LOADER_ADD_RESAMPLER_MFT, - }, - { - /* Float -> PCM, refuse input type, add converter, allow resampler output type */ - .input_type = &audio_float_44100, .output_type = &audio_pcm_48000_resampler, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, - .expected_result = S_OK, .converter_class = CLSID_CResamplerMediaObject, - .flags = LOADER_SET_INVALID_INPUT | LOADER_ADD_RESAMPLER_MFT, - }, + if (handler.current_type) + IMFMediaType_Release(handler.current_type); + handler.current_type = NULL;
- { - /* MP3 -> PCM */ - .input_type = &audio_mp3_44100, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, - .current_input = &audio_mp3_44100, - .expected_result = MF_E_INVALIDMEDIATYPE, - }, - { - /* MP3 -> PCM, force enumerate */ - .input_type = &audio_mp3_44100, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, - .current_input = &audio_mp3_44100, - .expected_result = MF_E_NO_MORE_TYPES, - .flags = LOADER_SET_ENUMERATE_SOURCE_TYPES, - }, - { - /* MP3 -> PCM */ - .input_type = &audio_mp3_44100, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_ALLOW_CONVERTER, .source_method = -1, - .current_input = &audio_mp3_44100, - .expected_result = MF_E_TRANSFORM_NOT_POSSIBLE_FOR_CURRENT_MEDIATYPE_COMBINATION, - .flags = LOADER_TODO, - }, - { - /* MP3 -> PCM */ - .input_type = &audio_mp3_44100, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_ALLOW_DECODER, .source_method = -1, - .current_input = &audio_mp3_44100, - .expected_result = S_OK, .decoder_class = CLSID_CMP3DecMediaObject, - .flags = LOADER_TODO, - }, - { - /* MP3 -> PCM, need both decoder and converter */ - .input_type = &audio_mp3_44100, .output_type = &audio_float_48000, .sink_method = MF_CONNECT_ALLOW_DECODER, .source_method = -1, - .current_input = &audio_mp3_44100, .decoded_type = &audio_float_44100_stereo, - .expected_result = S_OK, .decoder_class = CLSID_CMP3DecMediaObject, .converter_class = CLSID_CResamplerMediaObject, - .flags = LOADER_TODO, - }, + hr = IMFTopology_Clear(topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ref = IMFTopologyNode_Release(src_node); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopologyNode_Release(sink_node); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopology_Release(topology); + ok(ref == 0, "Release returned %ld\n", ref);
- { - /* I420 -> RGB32, Color Convert media type */ - .input_type = &video_i420_1280, .output_type = &video_color_convert_1280_rgb32, .sink_method = -1, .source_method = -1, - .expected_result = MF_E_TOPO_CODEC_NOT_FOUND, .converter_class = CLSID_CColorConvertDMO, - .flags = LOADER_NEEDS_VIDEO_PROCESSOR, - }, - { - /* I420 -> RGB32, Video Processor media type */ - .input_type = &video_i420_1280, .output_type = &video_video_processor_1280_rgb32, .sink_method = -1, .source_method = -1, - .expected_result = S_OK, .converter_class = CLSID_CColorConvertDMO, - }, - { - /* I420 -> RGB32, Video Processor media type without frame size */ - .input_type = &video_i420_1280, .output_type = &video_video_processor_rgb32, .sink_method = -1, .source_method = -1, - .expected_result = S_OK, .converter_class = CLSID_CColorConvertDMO, - }, - { - /* H264 -> RGB32, Video Processor media type */ - .input_type = &video_h264_1280, .output_type = &video_video_processor_1280_rgb32, .sink_method = -1, .source_method = -1, - .decoded_type = &video_nv12_1280, - .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, .converter_class = CLSID_CColorConvertDMO, - }, - { - /* RGB32 -> Any Video, no current output type */ - .input_type = &video_i420_1280, .output_type = &video_dummy, .sink_method = -1, .source_method = -1, - .expected_result = S_OK, - .flags = LOADER_NO_CURRENT_OUTPUT, - }, - { - /* RGB32 -> Any Video, no current output type, refuse input type */ - .input_type = &video_i420_1280, .output_type = &video_dummy, .sink_method = -1, .source_method = -1, - .expected_result = S_OK, .converter_class = CLSID_CColorConvertDMO, - .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_INVALID_INPUT, - }, - { - /* RGB32 -> Any Video, no current output type, refuse input type */ - .input_type = &video_i420_1280, .output_type = &video_video_processor_rgb32, .sink_method = -1, .source_method = -1, - .expected_result = S_OK, .converter_class = CLSID_CColorConvertDMO, - .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_INVALID_INPUT | LOADER_SET_MEDIA_TYPES, - }, - }; + ref = IMFMediaSource_Release(source); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFPresentationDescriptor_Release(pd); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFStreamDescriptor_Release(sd); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFMediaType_Release(input_type); + ok(ref == 0, "Release returned %ld\n", ref);
- IMFTopologyNode *src_node, *sink_node, *src_node2, *sink_node2, *mft_node; - IMFSampleGrabberSinkCallback *grabber_callback = create_test_grabber_callback(); - struct test_stream_sink stream_sink = test_stream_sink; - IMFMediaType *media_type, *input_type, *output_type; - IMFTopology *topology, *topology2, *full_topology; - struct test_handler handler = test_handler; - IMFPresentationDescriptor *pd; - unsigned int i, count, value; - IMFActivate *sink_activate; - MF_TOPOLOGY_TYPE node_type; - IMFStreamDescriptor *sd; - IMFTransform *transform; - IMFMediaSource *source; - IMFTopoLoader *loader; - IUnknown *node_object; - WORD node_count; - TOPOID node_id, oldtopoid, newtopoid; - DWORD index; - HRESULT hr; - BOOL ret; - LONG ref;
- stream_sink.handler = &handler.IMFMediaTypeHandler_iface; + hr = MFShutdown(); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); +} + +static void test_media_session(void) +{ + IMFRateSupport *rate_support; + IMFAttributes *attributes; + IMFMediaSession *session; + MFSHUTDOWN_STATUS status; + IMFTopology *topology; + IMFShutdown *shutdown; + PROPVARIANT propvar; + IMFGetService *gs; + IMFClock *clock; + HRESULT hr; + DWORD caps;
hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); ok(hr == S_OK, "Startup failure, hr %#lx.\n", hr);
- hr = MFCreateTopoLoader(NULL); - ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + hr = MFCreateMediaSession(NULL, &session); + ok(hr == S_OK, "Failed to create media session, hr %#lx.\n", hr);
- hr = MFCreateTopoLoader(&loader); - ok(hr == S_OK, "Failed to create topology loader, hr %#lx.\n", hr); + check_interface(session, &IID_IMFGetService, TRUE); + check_interface(session, &IID_IMFRateSupport, TRUE); + check_interface(session, &IID_IMFRateControl, TRUE); + check_interface(session, &IID_IMFAttributes, FALSE); + check_interface(session, &IID_IMFTopologyNodeAttributeEditor, FALSE); + check_interface(session, &IID_IMFLocalMFTRegistration, FALSE); + check_service_interface(session, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, TRUE); + check_service_interface(session, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateControl, TRUE); + check_service_interface(session, &MF_TOPONODE_ATTRIBUTE_EDITOR_SERVICE, &IID_IMFTopologyNodeAttributeEditor, TRUE); + check_service_interface(session, &MF_LOCAL_MFT_REGISTRATION_SERVICE, &IID_IMFLocalMFTRegistration, TRUE);
- hr = MFCreateTopology(&topology); - ok(hr == S_OK, "Failed to create topology, hr %#lx.\n", hr); + hr = IMFMediaSession_GetClock(session, &clock); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- /* Empty topology */ - hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); - todo_wine_if(hr == S_OK) - ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#lx.\n", hr); - if (hr == S_OK) IMFTopology_Release(full_topology); + hr = IMFClock_QueryInterface(clock, &IID_IMFShutdown, (void **)&shutdown); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- /* Add source node. */ - hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &src_node); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + hr = IMFShutdown_GetShutdownStatus(shutdown, &status); + ok(hr == MF_E_INVALIDREQUEST, "Unexpected hr %#lx.\n", hr);
- hr = MFCreateMediaType(&media_type); - ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); - hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio); - ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); - hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM); - ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr);
- /* When a decoder is involved, windows requires this attribute to be present */ - create_descriptors(1, &media_type, NULL, &pd, &sd); - IMFMediaType_Release(media_type); + check_interface(session, &IID_IMFGetService, TRUE);
- source = create_test_source(pd); + hr = IMFMediaSession_QueryInterface(session, &IID_IMFGetService, (void **)&gs); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_SOURCE, (IUnknown *)source); - ok(hr == S_OK, "Failed to set node source, hr %#lx.\n", hr); + hr = IMFGetService_GetService(gs, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
- hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_STREAM_DESCRIPTOR, (IUnknown *)sd); - ok(hr == S_OK, "Failed to set node sd, hr %#lx.\n", hr); + IMFGetService_Release(gs);
- hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, (IUnknown *)pd); - ok(hr == S_OK, "Failed to set node pd, hr %#lx.\n", hr); + hr = IMFShutdown_GetShutdownStatus(shutdown, &status); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(status == MFSHUTDOWN_COMPLETED, "Unexpected shutdown status %u.\n", status);
- hr = IMFTopology_AddNode(topology, src_node); - ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + IMFShutdown_Release(shutdown);
- /* Source node only. */ - hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); - ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSession_ClearTopologies(session); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
- hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &sink_node); - ok(hr == S_OK, "Failed to create output node, hr %#lx.\n", hr); + hr = IMFMediaSession_Start(session, &GUID_NULL, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
- hr = MFCreateMediaType(&media_type); - ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); + propvar.vt = VT_EMPTY; + hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
- hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio); - ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); - hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM); - ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); + hr = IMFMediaSession_Pause(session); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
- hr = MFCreateSampleGrabberSinkActivate(media_type, grabber_callback, &sink_activate); - ok(hr == S_OK, "Failed to create grabber sink, hr %#lx.\n", hr); + hr = IMFMediaSession_Stop(session); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
- hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)sink_activate); - ok(hr == S_OK, "Failed to set object, hr %#lx.\n", hr); + hr = IMFMediaSession_Close(session); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
- IMFMediaType_Release(media_type); + hr = IMFMediaSession_GetClock(session, &clock); + ok(hr == MF_E_SHUTDOWN || broken(hr == E_UNEXPECTED) /* Win7 */, "Unexpected hr %#lx.\n", hr);
- hr = IMFTopology_AddNode(topology, sink_node); - ok(hr == S_OK, "Failed to add sink node, hr %#lx.\n", hr); + hr = IMFMediaSession_GetSessionCapabilities(session, &caps); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
- hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); - todo_wine_if(hr == MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED) - ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSession_GetSessionCapabilities(session, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
- hr = IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0); - ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + hr = IMFMediaSession_GetFullTopology(session, MFSESSION_GETFULLTOPOLOGY_CURRENT, 0, &topology); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
- /* Sink was not resolved. */ - hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); - ok(hr == MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaSession_Shutdown(session); + ok(hr == MF_E_SHUTDOWN, "Unexpected hr %#lx.\n", hr);
- hr = IMFTopologyNode_SetObject(sink_node, NULL); - ok(hr == S_OK, "Failed to set object, hr %#lx.\n", hr); + IMFMediaSession_Release(session);
- hr = IMFActivate_ShutdownObject(sink_activate); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ref = IMFActivate_Release(sink_activate); - ok(ref == 0, "Release returned %ld\n", ref); + /* Custom topology loader, GUID is not registered. */ + hr = MFCreateAttributes(&attributes, 1); + ok(hr == S_OK, "Failed to create attributes, hr %#lx.\n", hr);
- hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_SOURCE, NULL); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, NULL); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ref = IMFMediaSource_Release(source); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFPresentationDescriptor_Release(pd); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFStreamDescriptor_Release(sd); - ok(ref == 0, "Release returned %ld\n", ref); + hr = IMFAttributes_SetGUID(attributes, &MF_SESSION_TOPOLOADER, &MF_SESSION_TOPOLOADER); + ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr);
+ hr = MFCreateMediaSession(attributes, &session); + ok(hr == S_OK, "Failed to create media session, hr %#lx.\n", hr); + IMFMediaSession_Release(session);
- hr = MFCreateMediaType(&input_type); - ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); + /* Disabled quality manager. */ + hr = IMFAttributes_SetGUID(attributes, &MF_SESSION_QUALITY_MANAGER, &GUID_NULL); + ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr);
- hr = MFCreateMediaType(&output_type); - ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); + hr = MFCreateMediaSession(attributes, &session); + ok(hr == S_OK, "Failed to create media session, hr %#lx.\n", hr); + IMFMediaSession_Release(session);
- for (i = 0; i < ARRAY_SIZE(loader_tests); ++i) - { - const struct loader_test *test = &loader_tests[i]; + IMFAttributes_Release(attributes); +}
- winetest_push_context("%u", i); +static void test_media_session_rate_control(void) +{ + IMFRateControl *rate_control, *clock_rate_control; + IMFPresentationClock *presentation_clock; + IMFPresentationTimeSource *time_source; + MFCLOCK_PROPERTIES clock_props; + IMFRateSupport *rate_support; + IMFMediaSession *session; + IMFClock *clock; + HRESULT hr; + float rate; + BOOL thin;
- init_media_type(input_type, *test->input_type, -1); - init_media_type(output_type, *test->output_type, -1); + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Startup failure, hr %#lx.\n", hr);
- handler.set_current_count = 0; - if (test->flags & LOADER_NO_CURRENT_OUTPUT) - handler.current_type = NULL; - else - IMFMediaType_AddRef((handler.current_type = output_type)); + hr = MFCreateMediaSession(NULL, &session); + ok(hr == S_OK, "Failed to create media session, hr %#lx.\n", hr);
- if (test->flags & LOADER_SET_INVALID_INPUT) - handler.invalid_type = input_type; - else - handler.invalid_type = NULL; + hr = MFGetService((IUnknown *)session, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support); + ok(hr == S_OK, "Failed to get rate support interface, hr %#lx.\n", hr);
- handler.enum_count = 0; - if (test->flags & LOADER_SET_MEDIA_TYPES) - { - handler.media_types_count = 1; - handler.media_types = &output_type; - } - else - { - handler.media_types_count = 0; - handler.media_types = NULL; - } + hr = MFGetService((IUnknown *)session, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateControl, (void **)&rate_control); + ok(hr == S_OK, "Failed to get rate control interface, hr %#lx.\n", hr);
- if (test->flags & LOADER_ADD_RESAMPLER_MFT) - { - hr = IMFTopology_Clear(topology); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFTopology_AddNode(topology, src_node); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFTopology_AddNode(topology, sink_node); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFRateControl_GetRate(rate_control, NULL, NULL); + ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
- hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &mft_node); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + rate = 0.0f; + hr = IMFRateControl_GetRate(rate_control, NULL, &rate); + ok(hr == S_OK, "Failed to get playback rate, hr %#lx.\n", hr); + ok(rate == 1.0f, "Unexpected rate %f.\n", rate);
- hr = CoCreateInstance(&CLSID_CResamplerMediaObject, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFTopologyNode_SetGUID(mft_node, &MF_TOPONODE_TRANSFORM_OBJECTID, &CLSID_CResamplerMediaObject); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFTopologyNode_SetObject(mft_node, (IUnknown *)transform); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - IMFTransform_Release(transform); + hr = IMFRateControl_GetRate(rate_control, &thin, NULL); + ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
- hr = IMFTopology_AddNode(topology, mft_node); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFTopologyNode_ConnectOutput(src_node, 0, mft_node, 0); - ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); - hr = IMFTopologyNode_ConnectOutput(mft_node, 0, sink_node, 0); - ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); - IMFTopologyNode_Release(mft_node); - } - else - { - hr = IMFTopology_Clear(topology); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFTopology_AddNode(topology, src_node); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFTopology_AddNode(topology, sink_node); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - } + thin = TRUE; + rate = 0.0f; + hr = IMFRateControl_GetRate(rate_control, &thin, &rate); + ok(hr == S_OK, "Failed to get playback rate, hr %#lx.\n", hr); + ok(!thin, "Unexpected thinning.\n"); + ok(rate == 1.0f, "Unexpected rate %f.\n", rate);
- create_descriptors(1, &input_type, test->current_input, &pd, &sd); + hr = IMFMediaSession_GetClock(session, &clock); + ok(hr == S_OK, "Failed to get clock, hr %#lx.\n", hr);
- source = create_test_source(pd); + hr = IMFClock_QueryInterface(clock, &IID_IMFPresentationClock, (void **)&presentation_clock); + ok(hr == S_OK, "Failed to get rate control, hr %#lx.\n", hr);
- init_source_node(source, test->source_method, src_node, pd, sd); - init_sink_node(&stream_sink.IMFStreamSink_iface, test->sink_method, sink_node); + hr = IMFClock_QueryInterface(clock, &IID_IMFRateControl, (void **)&clock_rate_control); + ok(hr == S_OK, "Failed to get rate control, hr %#lx.\n", hr);
- hr = IMFTopology_GetCount(topology, &count); - ok(hr == S_OK, "Failed to get attribute count, hr %#lx.\n", hr); - ok(!count, "Unexpected count %u.\n", count); + rate = 0.0f; + hr = IMFRateControl_GetRate(clock_rate_control, NULL, &rate); + ok(hr == S_OK, "Failed to get clock rate, hr %#lx.\n", hr); + ok(rate == 1.0f, "Unexpected rate %f.\n", rate);
- if (test->flags & LOADER_SET_ENUMERATE_SOURCE_TYPES) - IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, 1); - hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); - IMFTopology_DeleteItem(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES); + hr = IMFRateControl_SetRate(clock_rate_control, FALSE, 1.5f); + ok(hr == MF_E_CLOCK_NO_TIME_SOURCE, "Unexpected hr %#lx.\n", hr);
- if (test->flags & LOADER_NEEDS_VIDEO_PROCESSOR && !has_video_processor) - ok(hr == MF_E_INVALIDMEDIATYPE || hr == MF_E_TOPO_CODEC_NOT_FOUND, - "Unexpected hr %#lx\n", hr); - else - { - todo_wine_if(test->flags & LOADER_TODO) - ok(hr == test->expected_result, "Unexpected hr %#lx\n", hr); - ok(full_topology != topology, "Unexpected instance.\n"); - } + hr = IMFRateControl_SetRate(rate_control, FALSE, 1.5f); + ok(hr == S_OK, "Failed to set rate, hr %#lx.\n", hr);
- if (test->expected_result != hr) - { - if (hr != S_OK) ref = 0; - else ref = IMFTopology_Release(full_topology); - ok(ref == 0, "Release returned %ld\n", ref); - } - else if (test->expected_result == S_OK) - { - IMFTopology_GetTopologyID(topology, &oldtopoid); - IMFTopology_GetTopologyID(full_topology, &newtopoid); - ok(oldtopoid == newtopoid, "Expected the same topology id. %I64u == %I64u\n", oldtopoid, newtopoid); - ok(topology != full_topology, "Expected a different object for the resolved topology.\n"); - - hr = IMFTopology_GetCount(full_topology, &count); - ok(hr == S_OK, "Failed to get attribute count, hr %#lx.\n", hr); - todo_wine - ok(count == (test->flags & LOADER_SET_ENUMERATE_SOURCE_TYPES ? 2 : 1), - "Unexpected count %u.\n", count); - - value = 0xdeadbeef; - hr = IMFTopology_GetUINT32(full_topology, &MF_TOPOLOGY_RESOLUTION_STATUS, &value); -todo_wine { - ok(hr == S_OK, "Failed to get attribute, hr %#lx.\n", hr); - ok(value == MF_TOPOLOGY_RESOLUTION_SUCCEEDED, "Unexpected value %#x.\n", value); -} - count = 2; - if (!IsEqualGUID(&test->decoder_class, &GUID_NULL)) - count++; - if (!IsEqualGUID(&test->converter_class, &GUID_NULL)) - count++; - - hr = IMFTopology_GetNodeCount(full_topology, &node_count); - ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); - todo_wine_if(IsEqualGUID(&test->decoder_class, &CLSID_CMP3DecMediaObject)) - ok(node_count == count, "Unexpected node count %u.\n", node_count); - - hr = IMFTopologyNode_GetTopoNodeID(src_node, &node_id); - ok(hr == S_OK, "Failed to get source node id, hr %#lx.\n", hr); - - hr = IMFTopology_GetNodeByID(full_topology, node_id, &src_node2); - ok(hr == S_OK, "Failed to get source in resolved topology, hr %#lx.\n", hr); - - hr = IMFTopologyNode_GetTopoNodeID(sink_node, &node_id); - ok(hr == S_OK, "Failed to get sink node id, hr %#lx.\n", hr); - - hr = IMFTopology_GetNodeByID(full_topology, node_id, &sink_node2); - ok(hr == S_OK, "Failed to get sink in resolved topology, hr %#lx.\n", hr); - - if (!IsEqualGUID(&test->decoder_class, &GUID_NULL)) - { - GUID class_id; - - hr = IMFTopologyNode_GetOutput(src_node2, 0, &mft_node, &index); - ok(hr == S_OK, "Failed to get decoder in resolved topology, hr %#lx.\n", hr); - ok(!index, "Unexpected stream index %lu.\n", index); - - hr = IMFTopologyNode_GetNodeType(mft_node, &node_type); - ok(hr == S_OK, "Failed to get transform node type in resolved topology, hr %#lx.\n", hr); - ok(node_type == MF_TOPOLOGY_TRANSFORM_NODE, "Unexpected node type %u.\n", node_type); - - value = 0; - hr = IMFTopologyNode_GetUINT32(mft_node, &MF_TOPONODE_DECODER, &value); - ok(hr == S_OK, "Failed to get attribute, hr %#lx.\n", hr); - ok(value == 1, "Unexpected value.\n"); - - class_id = GUID_NULL; - hr = IMFTopologyNode_GetGUID(mft_node, &MF_TOPONODE_TRANSFORM_OBJECTID, &class_id); - ok(hr == S_OK, "Failed to get attribute, hr %#lx.\n", hr); - ok(IsEqualGUID(&class_id, &test->decoder_class), "got MF_TOPONODE_TRANSFORM_OBJECTID %s.\n", debugstr_guid(&class_id)); - - hr = IMFTopologyNode_GetObject(mft_node, &node_object); - ok(hr == S_OK, "Failed to get object of transform node, hr %#lx.\n", hr); - IMFTopologyNode_Release(mft_node); - - hr = IUnknown_QueryInterface(node_object, &IID_IMFTransform, (void **)&transform); - ok(hr == S_OK, "Failed to get IMFTransform from transform node's object, hr %#lx.\n", hr); - IUnknown_Release(node_object); - - hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type); - ok(hr == S_OK, "Failed to get transform input type, hr %#lx.\n", hr); - hr = IMFMediaType_Compare(input_type, (IMFAttributes *)media_type, MF_ATTRIBUTES_MATCH_OUR_ITEMS, &ret); - ok(hr == S_OK, "Failed to compare media types, hr %#lx.\n", hr); - ok(ret, "Input type of first transform doesn't match source node type.\n"); - IMFMediaType_Release(media_type); - - hr = IMFTransform_GetOutputCurrentType(transform, 0, &media_type); - ok(hr == S_OK, "Failed to get transform input type, hr %#lx.\n", hr); - if (IsEqualGUID(&test->converter_class, &GUID_NULL)) - { - hr = IMFMediaType_Compare(output_type, (IMFAttributes *)media_type, MF_ATTRIBUTES_MATCH_OUR_ITEMS, &ret); - ok(hr == S_OK, "Failed to compare media types, hr %#lx.\n", hr); - ok(ret, "Output type of first transform doesn't match sink node type.\n"); - } - else if (test->decoded_type) - { - check_media_type(media_type, *test->decoded_type, -1); - } - IMFMediaType_Release(media_type); - - IMFTransform_Release(transform); - } - - if (!IsEqualGUID(&test->converter_class, &GUID_NULL)) - { - GUID class_id; - - hr = IMFTopologyNode_GetInput(sink_node2, 0, &mft_node, &index); - ok(hr == S_OK, "Failed to get decoder in resolved topology, hr %#lx.\n", hr); - ok(!index, "Unexpected stream index %lu.\n", index); - - hr = IMFTopologyNode_GetNodeType(mft_node, &node_type); - ok(hr == S_OK, "Failed to get transform node type in resolved topology, hr %#lx.\n", hr); - ok(node_type == MF_TOPOLOGY_TRANSFORM_NODE, "Unexpected node type %u.\n", node_type); - - class_id = GUID_NULL; - hr = IMFTopologyNode_GetGUID(mft_node, &MF_TOPONODE_TRANSFORM_OBJECTID, &class_id); - ok(hr == S_OK, "Failed to get attribute, hr %#lx.\n", hr); - todo_wine_if(IsEqualGUID(&test->converter_class, &CLSID_CColorConvertDMO)) - ok(IsEqualGUID(&class_id, &test->converter_class), "got MF_TOPONODE_TRANSFORM_OBJECTID %s.\n", debugstr_guid(&class_id)); - - hr = IMFTopologyNode_GetObject(mft_node, &node_object); - ok(hr == S_OK, "Failed to get object of transform node, hr %#lx.\n", hr); - IMFTopologyNode_Release(mft_node); - - hr = IUnknown_QueryInterface(node_object, &IID_IMFTransform, (void **)&transform); - ok(hr == S_OK, "Failed to get IMFTransform from transform node's object, hr %#lx.\n", hr); - IUnknown_Release(node_object); - - hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type); - ok(hr == S_OK, "Failed to get transform input type, hr %#lx.\n", hr); - if (IsEqualGUID(&test->decoder_class, &GUID_NULL)) - { - hr = IMFMediaType_Compare(input_type, (IMFAttributes *)media_type, MF_ATTRIBUTES_MATCH_OUR_ITEMS, &ret); - ok(hr == S_OK, "Failed to compare media types, hr %#lx.\n", hr); - ok(ret, "Input type of last transform doesn't match source node type.\n"); - } - else if (test->decoded_type) - { - check_media_type(media_type, *test->decoded_type, -1); - } - IMFMediaType_Release(media_type); - - hr = IMFTransform_GetOutputCurrentType(transform, 0, &media_type); - ok(hr == S_OK, "Failed to get transform input type, hr %#lx.\n", hr); - hr = IMFMediaType_Compare(output_type, (IMFAttributes *)media_type, MF_ATTRIBUTES_MATCH_OUR_ITEMS, &ret); - ok(hr == S_OK, "Failed to compare media types, hr %#lx.\n", hr); - ok(ret, "Output type of last transform doesn't match sink node type.\n"); - IMFMediaType_Release(media_type); - - IMFTransform_Release(transform); - } - - IMFTopologyNode_Release(src_node2); - IMFTopologyNode_Release(sink_node2); - - hr = IMFTopology_SetUINT32(full_topology, &IID_IMFTopology, 123); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFTopoLoader_Load(loader, full_topology, &topology2, NULL); - ok(hr == S_OK, "Failed to resolve topology, hr %#lx.\n", hr); - ok(full_topology != topology2, "Unexpected instance.\n"); - IMFTopology_GetTopologyID(topology2, &oldtopoid); - IMFTopology_GetTopologyID(full_topology, &newtopoid); - ok(oldtopoid == newtopoid, "Expected the same topology id. %I64u == %I64u\n", oldtopoid, newtopoid); - hr = IMFTopology_GetUINT32(topology2, &IID_IMFTopology, &value); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFClock_GetProperties(clock, &clock_props); + ok(hr == MF_E_CLOCK_NO_TIME_SOURCE, "Unexpected hr %#lx.\n", hr);
- ref = IMFTopology_Release(topology2); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFTopology_Release(full_topology); - ok(ref == 0, "Release returned %ld\n", ref); - } + hr = MFCreateSystemTimeSource(&time_source); + ok(hr == S_OK, "Failed to create time source, hr %#lx.\n", hr);
- hr = IMFTopology_GetCount(topology, &count); - ok(hr == S_OK, "Failed to get attribute count, hr %#lx.\n", hr); - ok(!count, "Unexpected count %u.\n", count); + hr = IMFPresentationClock_SetTimeSource(presentation_clock, time_source); + ok(hr == S_OK, "Failed to set time source, hr %#lx.\n", hr);
- if (test->flags & LOADER_SET_MEDIA_TYPES) - ok(handler.enum_count, "got %lu GetMediaTypeByIndex\n", handler.enum_count); - else - ok(!handler.enum_count, "got %lu GetMediaTypeByIndex\n", handler.enum_count); - ok(!handler.set_current_count, "got %lu SetCurrentMediaType\n", handler.set_current_count); + hr = IMFRateControl_SetRate(rate_control, FALSE, 1.5f); + ok(hr == S_OK, "Failed to set rate, hr %#lx.\n", hr);
- if (handler.current_type) - IMFMediaType_Release(handler.current_type); - handler.current_type = NULL; + rate = 0.0f; + hr = IMFRateControl_GetRate(clock_rate_control, NULL, &rate); + ok(hr == S_OK, "Failed to get clock rate, hr %#lx.\n", hr); + ok(rate == 1.0f, "Unexpected rate %f.\n", rate);
- hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_SOURCE, NULL); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, NULL); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ref = IMFMediaSource_Release(source); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFPresentationDescriptor_Release(pd); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFStreamDescriptor_Release(sd); - ok(ref == 0, "Release returned %ld\n", ref); + IMFPresentationTimeSource_Release(time_source);
- winetest_pop_context(); - } + IMFRateControl_Release(clock_rate_control); + IMFPresentationClock_Release(presentation_clock); + IMFClock_Release(clock);
- ref = IMFTopology_Release(topology); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFTopoLoader_Release(loader); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFTopologyNode_Release(src_node); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFTopologyNode_Release(sink_node); - ok(ref == 0, "Release returned %ld\n", ref); + IMFRateControl_Release(rate_control); + IMFRateSupport_Release(rate_support);
- ref = IMFMediaType_Release(input_type); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFMediaType_Release(output_type); - ok(ref == 0, "Release returned %ld\n", ref); + IMFMediaSession_Release(session);
hr = MFShutdown(); ok(hr == S_OK, "Shutdown failure, hr %#lx.\n", hr); - - IMFSampleGrabberSinkCallback_Release(grabber_callback); }
-static void test_topology_loader_evr(void) +struct test_grabber_callback { - static const media_type_desc media_type_desc = - { - ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), - ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), - ATTR_RATIO(MF_MT_FRAME_SIZE, 640, 480), - ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE), - {0}, - }; - IMFTopologyNode *node, *source_node, *evr_node; - IMFTopology *topology, *full_topology; - IMFPresentationDescriptor *pd; - IMFMediaTypeHandler *handler; - unsigned int i, count, value; - IMFStreamSink *stream_sink; - IMFMediaType *media_type; - IMFStreamDescriptor *sd; - IMFActivate *activate; - IMFTopoLoader *loader; - IMFMediaSink *sink; - WORD node_count; - UINT64 value64; - HWND window; - HRESULT hr; - LONG ref; - - hr = CoInitialize(NULL); - ok(hr == S_OK, "Failed to initialize, hr %#lx.\n", hr); + IMFSampleGrabberSinkCallback IMFSampleGrabberSinkCallback_iface; + LONG refcount;
- /* EVR sink node. */ - window = create_window(); + IMFCollection *samples; + HANDLE ready_event; + HANDLE done_event; +};
- hr = MFCreateVideoRendererActivate(window, &activate); - ok(hr == S_OK, "Failed to create activate object, hr %#lx.\n", hr); +static struct test_grabber_callback *impl_from_IMFSampleGrabberSinkCallback(IMFSampleGrabberSinkCallback *iface) +{ + return CONTAINING_RECORD(iface, struct test_grabber_callback, IMFSampleGrabberSinkCallback_iface); +}
- hr = IMFActivate_ActivateObject(activate, &IID_IMFMediaSink, (void **)&sink); - if (FAILED(hr)) +static HRESULT WINAPI test_grabber_callback_QueryInterface(IMFSampleGrabberSinkCallback *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IMFSampleGrabberSinkCallback) || + IsEqualIID(riid, &IID_IMFClockStateSink) || + IsEqualIID(riid, &IID_IUnknown)) { - skip("Failed to create an EVR sink, skipping tests.\n"); - DestroyWindow(window); - IMFActivate_Release(activate); - CoUninitialize(); - return; + *obj = iface; + IMFSampleGrabberSinkCallback_AddRef(iface); + return S_OK; } - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- hr = MFCreateTopoLoader(&loader); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + *obj = NULL; + return E_NOINTERFACE; +}
- /* Source node. */ - hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &source_node); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); +static ULONG WINAPI test_grabber_callback_AddRef(IMFSampleGrabberSinkCallback *iface) +{ + struct test_grabber_callback *grabber = impl_from_IMFSampleGrabberSinkCallback(iface); + return InterlockedIncrement(&grabber->refcount); +}
- hr = MFCreateMediaType(&media_type); - ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); - init_media_type(media_type, media_type_desc, -1); +static ULONG WINAPI test_grabber_callback_Release(IMFSampleGrabberSinkCallback *iface) +{ + struct test_grabber_callback *grabber = impl_from_IMFSampleGrabberSinkCallback(iface); + ULONG refcount = InterlockedDecrement(&grabber->refcount);
- create_descriptors(1, &media_type, &media_type_desc, &pd, &sd); - init_source_node(NULL, -1, source_node, pd, sd); - IMFPresentationDescriptor_Release(pd); - IMFStreamDescriptor_Release(sd); + if (!refcount) + { + IMFCollection_Release(grabber->samples); + if (grabber->ready_event) + CloseHandle(grabber->ready_event); + if (grabber->done_event) + CloseHandle(grabber->done_event); + free(grabber); + }
+ return refcount; +}
- hr = IMFMediaSink_GetStreamSinkById(sink, 0, &stream_sink); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); +static HRESULT WINAPI test_grabber_callback_OnClockStart(IMFSampleGrabberSinkCallback *iface, MFTIME time, LONGLONG offset) +{ + return S_OK; +}
- hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &evr_node); - ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); +static HRESULT WINAPI test_grabber_callback_OnClockStop(IMFSampleGrabberSinkCallback *iface, MFTIME time) +{ + return S_OK; +}
- hr = IMFTopologyNode_SetObject(evr_node, (IUnknown *)stream_sink); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); +static HRESULT WINAPI test_grabber_callback_OnClockPause(IMFSampleGrabberSinkCallback *iface, MFTIME time) +{ + return S_OK; +}
- hr = IMFStreamSink_GetMediaTypeHandler(stream_sink, &handler); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, media_type); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - IMFMediaTypeHandler_Release(handler); +static HRESULT WINAPI test_grabber_callback_OnClockRestart(IMFSampleGrabberSinkCallback *iface, MFTIME time) +{ + return S_OK; +}
- IMFStreamSink_Release(stream_sink); +static HRESULT WINAPI test_grabber_callback_OnClockSetRate(IMFSampleGrabberSinkCallback *iface, MFTIME time, float rate) +{ + return S_OK; +}
- hr = MFCreateTopology(&topology); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); +static HRESULT WINAPI test_grabber_callback_OnSetPresentationClock(IMFSampleGrabberSinkCallback *iface, + IMFPresentationClock *clock) +{ + return S_OK; +}
- hr = IMFTopology_AddNode(topology, source_node); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFTopology_AddNode(topology, evr_node); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IMFTopologyNode_ConnectOutput(source_node, 0, evr_node, 0); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); +static HRESULT WINAPI test_grabber_callback_OnProcessSample(IMFSampleGrabberSinkCallback *iface, REFGUID major_type, + DWORD sample_flags, LONGLONG sample_time, LONGLONG sample_duration, const BYTE *buffer, DWORD sample_size) +{ + struct test_grabber_callback *grabber = CONTAINING_RECORD(iface, struct test_grabber_callback, IMFSampleGrabberSinkCallback_iface); + IMFSample *sample; + HRESULT hr; + DWORD res;
- hr = IMFTopologyNode_SetUINT32(evr_node, &MF_TOPONODE_CONNECT_METHOD, MF_CONNECT_DIRECT); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (!grabber->ready_event) + return E_NOTIMPL;
- hr = IMFTopologyNode_GetCount(evr_node, &count); + sample = create_sample(buffer, sample_size); + hr = IMFSample_SetSampleFlags(sample, sample_flags); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(count == 1, "Unexpected attribute count %u.\n", count); - - hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + /* FIXME: sample time is inconsistent across windows versions, ignore it */ + hr = IMFSample_SetSampleTime(sample, 0); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - hr = IMFTopology_GetNodeCount(full_topology, &node_count); + hr = IMFSample_SetSampleDuration(sample, sample_duration); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(node_count == 3, "Unexpected node count %u.\n", node_count); - - for (i = 0; i < node_count; ++i) - { - MF_TOPOLOGY_TYPE node_type; - - hr = IMFTopology_GetNode(full_topology, i, &node); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - hr = IMFTopologyNode_GetNodeType(node, &node_type); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - switch (node_type) - { - case MF_TOPOLOGY_OUTPUT_NODE: - { - value = 1; - hr = IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_STREAMID, &value); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(!value, "Unexpected stream id %u.\n", value); - break; - } - case MF_TOPOLOGY_TRANSFORM_NODE: - { - IMFAttributes *attrs; - IMFTransform *copier; - IUnknown *obj; - - hr = IMFTopologyNode_GetObject(node, (IUnknown **)&obj); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - hr = IUnknown_QueryInterface(obj, &IID_IMFTransform, (void **)&copier); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - - hr = IMFTransform_GetAttributes(copier, &attrs); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFCollection_AddElement(grabber->samples, (IUnknown *)sample); + IMFSample_Release(sample);
- value = 0xdeadbeef; - hr = IMFAttributes_GetUINT32(attrs, &MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, &value); - ok(value == 1, "Unexpected dynamic state support state %u.\n", value); + SetEvent(grabber->ready_event); + res = WaitForSingleObject(grabber->done_event, 1000); + ok(!res, "WaitForSingleObject returned %#lx\n", res);
- IMFAttributes_Release(attrs); - IMFTransform_Release(copier); - IUnknown_Release(obj); - break; - } - case MF_TOPOLOGY_SOURCESTREAM_NODE: - { - value64 = 1; - hr = IMFTopologyNode_GetUINT64(node, &MF_TOPONODE_MEDIASTART, &value64); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(!value64, "Unexpected value.\n"); - break; - } - default: - ok(0, "Got unexpected node type %u.\n", node_type); - break; - } + return S_OK; +}
- IMFTopologyNode_Release(node); - } +static HRESULT WINAPI test_grabber_callback_OnShutdown(IMFSampleGrabberSinkCallback *iface) +{ + return S_OK; +}
- ref = IMFTopology_Release(full_topology); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFTopoLoader_Release(loader); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFTopology_Release(topology); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFTopologyNode_Release(source_node); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFTopologyNode_Release(evr_node); - ok(ref == 0, "Release returned %ld\n", ref); +static const IMFSampleGrabberSinkCallbackVtbl test_grabber_callback_vtbl = +{ + test_grabber_callback_QueryInterface, + test_grabber_callback_AddRef, + test_grabber_callback_Release, + test_grabber_callback_OnClockStart, + test_grabber_callback_OnClockStop, + test_grabber_callback_OnClockPause, + test_grabber_callback_OnClockRestart, + test_grabber_callback_OnClockSetRate, + test_grabber_callback_OnSetPresentationClock, + test_grabber_callback_OnProcessSample, + test_grabber_callback_OnShutdown, +};
- hr = IMFActivate_ShutdownObject(activate); - ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); - ref = IMFActivate_Release(activate); - ok(ref == 0, "Release returned %ld\n", ref); - ref = IMFMediaSink_Release(sink); - ok(ref == 0, "Release returned %ld\n", ref); +static IMFSampleGrabberSinkCallback *create_test_grabber_callback(void) +{ + struct test_grabber_callback *grabber; + HRESULT hr;
- ref = IMFMediaType_Release(media_type); - ok(ref == 0, "Release returned %ld\n", ref); + if (!(grabber = calloc(1, sizeof(*grabber)))) + return NULL;
- DestroyWindow(window); + grabber->IMFSampleGrabberSinkCallback_iface.lpVtbl = &test_grabber_callback_vtbl; + grabber->refcount = 1; + hr = MFCreateCollection(&grabber->samples); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- CoUninitialize(); + return &grabber->IMFSampleGrabberSinkCallback_iface; }
static HRESULT WINAPI testshutdown_QueryInterface(IMFShutdown *iface, REFIID riid, void **obj) @@ -8250,10 +6431,6 @@ START_TEST(mf) return; }
- test_topology(); - test_topology_tee_node(); - test_topology_loader(); - test_topology_loader_evr(); test_MFGetService(); test_sequencer_source(); test_media_session(); diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c new file mode 100644 index 00000000000..ef4dc86d21e --- /dev/null +++ b/dlls/mf/tests/topology.c @@ -0,0 +1,2688 @@ +/* + * Copyright 2017 Nikolay Sivov + * + * 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 + */ + +#include <stdarg.h> +#include <string.h> +#include <float.h> + +#define COBJMACROS +#include "windef.h" +#include "winbase.h" + +#include "uuids.h" +#include "wmcodecdsp.h" + +#include "mferror.h" + +#include "mf_test.h" + +#include "wine/test.h" + +#define DEFINE_EXPECT(func) \ + static BOOL expect_ ## func = FALSE, called_ ## func = FALSE + +#define SET_EXPECT(func) \ + expect_ ## func = TRUE + +#define CHECK_EXPECT2(func) \ + do { \ + ok(expect_ ##func, "unexpected call " #func "\n"); \ + called_ ## func = TRUE; \ + }while(0) + +#define CHECK_EXPECT(func) \ + do { \ + CHECK_EXPECT2(func); \ + expect_ ## func = FALSE; \ + }while(0) + +#define CHECK_CALLED(func) \ + do { \ + ok(called_ ## func, "expected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + +#define CHECK_NOT_CALLED(func) \ + do { \ + ok(!called_ ## func, "unexpected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + +#define CLEAR_CALLED(func) \ + expect_ ## func = called_ ## func = FALSE + +extern GUID DMOVideoFormat_RGB32; + +#define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__) +static void _expect_ref(IUnknown* obj, ULONG expected_refcount, int line) +{ + ULONG refcount; + IUnknown_AddRef(obj); + refcount = IUnknown_Release(obj); + ok_(__FILE__, line)(refcount == expected_refcount, "Unexpected refcount %ld, expected %ld.\n", refcount, + expected_refcount); +} + +static HWND create_window(void) +{ + RECT r = {0, 0, 640, 480}; + + AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW | WS_VISIBLE, FALSE); + + return CreateWindowA("static", "mf_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 0, 0, r.right - r.left, r.bottom - r.top, NULL, NULL, NULL, NULL); +} + +static IMFSample *create_sample(const BYTE *data, ULONG size) +{ + IMFMediaBuffer *media_buffer; + IMFSample *sample; + DWORD length; + BYTE *buffer; + HRESULT hr; + ULONG ret; + + hr = MFCreateSample(&sample); + ok(hr == S_OK, "MFCreateSample returned %#lx\n", hr); + hr = MFCreateMemoryBuffer(size, &media_buffer); + ok(hr == S_OK, "MFCreateMemoryBuffer returned %#lx\n", hr); + hr = IMFMediaBuffer_Lock(media_buffer, &buffer, NULL, &length); + ok(hr == S_OK, "Lock returned %#lx\n", hr); + ok(length == 0, "got length %lu\n", length); + if (!data) memset(buffer, 0xcd, size); + else memcpy(buffer, data, size); + hr = IMFMediaBuffer_Unlock(media_buffer); + ok(hr == S_OK, "Unlock returned %#lx\n", hr); + hr = IMFMediaBuffer_SetCurrentLength(media_buffer, data ? size : 0); + ok(hr == S_OK, "SetCurrentLength returned %#lx\n", hr); + hr = IMFSample_AddBuffer(sample, media_buffer); + ok(hr == S_OK, "AddBuffer returned %#lx\n", hr); + ret = IMFMediaBuffer_Release(media_buffer); + ok(ret == 1, "Release returned %lu\n", ret); + + return sample; +} + +static void create_descriptors(UINT enum_types_count, IMFMediaType **enum_types, const media_type_desc *current_desc, + IMFPresentationDescriptor **pd, IMFStreamDescriptor **sd) +{ + HRESULT hr; + + hr = MFCreateStreamDescriptor(0, enum_types_count, enum_types, sd); + ok(hr == S_OK, "Failed to create stream descriptor, hr %#lx.\n", hr); + + hr = MFCreatePresentationDescriptor(1, sd, pd); + ok(hr == S_OK, "Failed to create presentation descriptor, hr %#lx.\n", hr); + + if (current_desc) + { + IMFMediaTypeHandler *handler; + IMFMediaType *type; + + hr = MFCreateMediaType(&type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + init_media_type(type, *current_desc, -1); + + hr = IMFStreamDescriptor_GetMediaTypeHandler(*sd, &handler); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + IMFMediaTypeHandler_Release(handler); + IMFMediaType_Release(type); + } +} + +static void init_source_node(IMFMediaSource *source, MF_CONNECT_METHOD method, IMFTopologyNode *node, + IMFPresentationDescriptor *pd, IMFStreamDescriptor *sd) +{ + HRESULT hr; + + hr = IMFTopologyNode_DeleteAllItems(node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFTopologyNode_SetUnknown(node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, (IUnknown *)pd); + ok(hr == S_OK, "Failed to set node pd, hr %#lx.\n", hr); + hr = IMFTopologyNode_SetUnknown(node, &MF_TOPONODE_STREAM_DESCRIPTOR, (IUnknown *)sd); + ok(hr == S_OK, "Failed to set node sd, hr %#lx.\n", hr); + + if (method != -1) + { + hr = IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_CONNECT_METHOD, method); + ok(hr == S_OK, "Failed to set connect method, hr %#lx.\n", hr); + } + + if (source) + { + hr = IMFTopologyNode_SetUnknown(node, &MF_TOPONODE_SOURCE, (IUnknown *)source); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } +} + +static void init_sink_node(IMFStreamSink *stream_sink, MF_CONNECT_METHOD method, IMFTopologyNode *node) +{ + HRESULT hr; + + hr = IMFTopologyNode_DeleteAllItems(node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFTopologyNode_SetObject(node, (IUnknown *)stream_sink); + ok(hr == S_OK, "Failed to set object, hr %#lx.\n", hr); + + if (method != -1) + { + hr = IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_CONNECT_METHOD, method); + ok(hr == S_OK, "Failed to set connect method, hr %#lx.\n", hr); + } +} + +DEFINE_EXPECT(test_source_BeginGetEvent); +DEFINE_EXPECT(test_source_QueueEvent); +DEFINE_EXPECT(test_source_Start); + +struct test_source +{ + IMFMediaSource IMFMediaSource_iface; + LONG refcount; + HRESULT begin_get_event_res; + IMFPresentationDescriptor *pd; +}; + +static struct test_source *impl_from_IMFMediaSource(IMFMediaSource *iface) +{ + return CONTAINING_RECORD(iface, struct test_source, IMFMediaSource_iface); +} + +static HRESULT WINAPI test_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out) +{ + if (IsEqualIID(riid, &IID_IMFMediaSource) + || IsEqualIID(riid, &IID_IMFMediaEventGenerator) + || IsEqualIID(riid, &IID_IUnknown)) + { + *out = iface; + } + else + { + *out = NULL; + return E_NOINTERFACE; + } + + IMFMediaSource_AddRef(iface); + return S_OK; +} + +static ULONG WINAPI test_source_AddRef(IMFMediaSource *iface) +{ + struct test_source *source = impl_from_IMFMediaSource(iface); + return InterlockedIncrement(&source->refcount); +} + +static ULONG WINAPI test_source_Release(IMFMediaSource *iface) +{ + struct test_source *source = impl_from_IMFMediaSource(iface); + ULONG refcount = InterlockedDecrement(&source->refcount); + + if (!refcount) + { + IMFPresentationDescriptor_Release(source->pd); + free(source); + } + + return refcount; +} + +static HRESULT WINAPI test_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state) +{ + struct test_source *source = impl_from_IMFMediaSource(iface); + CHECK_EXPECT(test_source_BeginGetEvent); + return source->begin_get_event_res; +} + +static HRESULT WINAPI test_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type, + HRESULT hr, const PROPVARIANT *value) +{ + CHECK_EXPECT(test_source_QueueEvent); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_source_GetCharacteristics(IMFMediaSource *iface, DWORD *flags) +{ + *flags = 0; + return S_OK; +} + +static HRESULT WINAPI test_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **pd) +{ + struct test_source *source = impl_from_IMFMediaSource(iface); + return IMFPresentationDescriptor_Clone(source->pd, pd); +} + +static HRESULT WINAPI test_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *pd, const GUID *time_format, + const PROPVARIANT *start_position) +{ + CHECK_EXPECT(test_source_Start); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_source_Stop(IMFMediaSource *iface) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_source_Pause(IMFMediaSource *iface) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_source_Shutdown(IMFMediaSource *iface) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static const IMFMediaSourceVtbl test_source_vtbl = +{ + test_source_QueryInterface, + test_source_AddRef, + test_source_Release, + test_source_GetEvent, + test_source_BeginGetEvent, + test_source_EndGetEvent, + test_source_QueueEvent, + test_source_GetCharacteristics, + test_source_CreatePresentationDescriptor, + test_source_Start, + test_source_Stop, + test_source_Pause, + test_source_Shutdown, +}; + +static IMFMediaSource *create_test_source(IMFPresentationDescriptor *pd) +{ + struct test_source *source; + + source = calloc(1, sizeof(*source)); + source->IMFMediaSource_iface.lpVtbl = &test_source_vtbl; + source->refcount = 1; + source->begin_get_event_res = E_NOTIMPL; + IMFPresentationDescriptor_AddRef((source->pd = pd)); + + return &source->IMFMediaSource_iface; +} + +static HRESULT WINAPI test_unk_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 test_unk_AddRef(IUnknown *iface) +{ + return 2; +} + +static ULONG WINAPI test_unk_Release(IUnknown *iface) +{ + return 1; +} + +static const IUnknownVtbl test_unk_vtbl = +{ + test_unk_QueryInterface, + test_unk_AddRef, + test_unk_Release, +}; + +static void test_topology(void) +{ + IMFMediaType *mediatype, *mediatype2, *mediatype3; + IMFCollection *collection, *collection2; + IUnknown test_unk2 = { &test_unk_vtbl }; + IUnknown test_unk = { &test_unk_vtbl }; + IMFTopologyNode *node, *node2, *node3; + IMFTopology *topology, *topology2; + DWORD size, io_count, index; + MF_TOPOLOGY_TYPE node_type; + IUnknown *object; + WORD node_count; + UINT32 count; + HRESULT hr; + TOPOID id; + LONG ref; + + hr = MFCreateTopology(NULL); + ok(hr == E_POINTER, "got %#lx\n", hr); + + hr = MFCreateTopology(&topology); + ok(hr == S_OK, "Failed to create topology, hr %#lx.\n", hr); + hr = IMFTopology_GetTopologyID(topology, &id); + ok(hr == S_OK, "Failed to get id, hr %#lx.\n", hr); + ok(id == 1, "Unexpected id.\n"); + + hr = MFCreateTopology(&topology2); + ok(hr == S_OK, "Failed to create topology, hr %#lx.\n", hr); + hr = IMFTopology_GetTopologyID(topology2, &id); + ok(hr == S_OK, "Failed to get id, hr %#lx.\n", hr); + ok(id == 2, "Unexpected id.\n"); + + ref = IMFTopology_Release(topology); + ok(ref == 0, "Release returned %ld\n", ref); + + hr = MFCreateTopology(&topology); + ok(hr == S_OK, "Failed to create topology, hr %#lx.\n", hr); + hr = IMFTopology_GetTopologyID(topology, &id); + ok(hr == S_OK, "Failed to get id, hr %#lx.\n", hr); + ok(id == 3, "Unexpected id.\n"); + + ref = IMFTopology_Release(topology2); + ok(ref == 0, "Release returned %ld\n", ref); + + /* No attributes by default. */ + for (node_type = MF_TOPOLOGY_OUTPUT_NODE; node_type < MF_TOPOLOGY_TEE_NODE; ++node_type) + { + hr = MFCreateTopologyNode(node_type, &node); + ok(hr == S_OK, "Failed to create a node for type %d, hr %#lx.\n", node_type, hr); + hr = IMFTopologyNode_GetCount(node, &count); + ok(hr == S_OK, "Failed to get attribute count, hr %#lx.\n", hr); + ok(!count, "Unexpected attribute count %u.\n", count); + ref = IMFTopologyNode_Release(node); + ok(ref == 0, "Release returned %ld\n", ref); + } + + hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &node2); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetTopoNodeID(node, &id); + ok(hr == S_OK, "Failed to get node id, hr %#lx.\n", hr); + ok(((id >> 32) == GetCurrentProcessId()) && !!(id & 0xffff), "Unexpected node id %s.\n", wine_dbgstr_longlong(id)); + + hr = IMFTopologyNode_SetTopoNodeID(node2, id); + ok(hr == S_OK, "Failed to set node id, hr %#lx.\n", hr); + + hr = IMFTopology_GetNodeCount(topology, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + hr = IMFTopology_AddNode(topology, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + node_count = 1; + hr = IMFTopology_GetNodeCount(topology, &node_count); + ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); + ok(node_count == 0, "Unexpected node count %u.\n", node_count); + + /* Same id, different nodes. */ + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + + node_count = 0; + hr = IMFTopology_GetNodeCount(topology, &node_count); + ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); + ok(node_count == 1, "Unexpected node count %u.\n", node_count); + + hr = IMFTopology_AddNode(topology, node2); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + ref = IMFTopologyNode_Release(node2); + ok(ref == 0, "Release returned %ld\n", ref); + + hr = IMFTopology_GetNodeByID(topology, id, &node2); + ok(hr == S_OK, "Failed to get a node, hr %#lx.\n", hr); + ok(node2 == node, "Unexpected node.\n"); + IMFTopologyNode_Release(node2); + + /* Change node id, add it again. */ + hr = IMFTopologyNode_SetTopoNodeID(node, ++id); + ok(hr == S_OK, "Failed to set node id, hr %#lx.\n", hr); + + hr = IMFTopology_GetNodeByID(topology, id, &node2); + ok(hr == S_OK, "Failed to get a node, hr %#lx.\n", hr); + ok(node2 == node, "Unexpected node.\n"); + IMFTopologyNode_Release(node2); + + hr = IMFTopology_GetNodeByID(topology, id + 1, &node2); + ok(hr == MF_E_NOT_FOUND, "Unexpected hr %#lx.\n", hr); + + hr = IMFTopology_AddNode(topology, node); + ok(hr == E_INVALIDARG, "Failed to add a node, hr %#lx.\n", hr); + + hr = IMFTopology_GetNode(topology, 0, &node2); + ok(hr == S_OK, "Failed to get a node, hr %#lx.\n", hr); + ok(node2 == node, "Unexpected node.\n"); + IMFTopologyNode_Release(node2); + + hr = IMFTopology_GetNode(topology, 1, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + hr = IMFTopology_GetNode(topology, 1, &node2); + ok(hr == MF_E_INVALIDINDEX, "Failed to get a node, hr %#lx.\n", hr); + + hr = IMFTopology_GetNode(topology, -2, &node2); + ok(hr == MF_E_INVALIDINDEX, "Failed to get a node, hr %#lx.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &node2); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + hr = IMFTopology_AddNode(topology, node2); + ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + ref = IMFTopologyNode_Release(node2); + ok(ref == 1, "Release returned %ld\n", ref); + + node_count = 0; + hr = IMFTopology_GetNodeCount(topology, &node_count); + ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); + ok(node_count == 2, "Unexpected node count %u.\n", node_count); + + /* Remove with detached node, existing id. */ + hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &node2); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + hr = IMFTopologyNode_SetTopoNodeID(node2, id); + ok(hr == S_OK, "Failed to set node id, hr %#lx.\n", hr); + hr = IMFTopology_RemoveNode(topology, node2); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + ref = IMFTopologyNode_Release(node2); + ok(ref == 0, "Release returned %ld\n", ref); + + hr = IMFTopology_RemoveNode(topology, node); + ok(hr == S_OK, "Failed to remove a node, hr %#lx.\n", hr); + + node_count = 0; + hr = IMFTopology_GetNodeCount(topology, &node_count); + ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); + ok(node_count == 1, "Unexpected node count %u.\n", node_count); + + hr = IMFTopology_Clear(topology); + ok(hr == S_OK, "Failed to clear topology, hr %#lx.\n", hr); + + node_count = 1; + hr = IMFTopology_GetNodeCount(topology, &node_count); + ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); + ok(node_count == 0, "Unexpected node count %u.\n", node_count); + + hr = IMFTopology_Clear(topology); + ok(hr == S_OK, "Failed to clear topology, hr %#lx.\n", hr); + + hr = IMFTopologyNode_SetTopoNodeID(node, 123); + ok(hr == S_OK, "Failed to set node id, hr %#lx.\n", hr); + + ref = IMFTopologyNode_Release(node); + ok(ref == 0, "Release returned %ld\n", ref); + + /* Change id for attached node. */ + hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &node2); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + + hr = IMFTopology_AddNode(topology, node2); + ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetTopoNodeID(node, &id); + ok(hr == S_OK, "Failed to get node id, hr %#lx.\n", hr); + + hr = IMFTopologyNode_SetTopoNodeID(node2, id); + ok(hr == S_OK, "Failed to get node id, hr %#lx.\n", hr); + + hr = IMFTopology_GetNodeByID(topology, id, &node3); + ok(hr == S_OK, "Failed to get a node, hr %#lx.\n", hr); + ok(node3 == node, "Unexpected node.\n"); + IMFTopologyNode_Release(node3); + + /* Source/output collections. */ + hr = IMFTopology_Clear(topology); + ok(hr == S_OK, "Failed to clear topology, hr %#lx.\n", hr); + + ref = IMFTopologyNode_Release(node); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopologyNode_Release(node2); + ok(ref == 0, "Release returned %ld\n", ref); + + hr = IMFTopology_GetSourceNodeCollection(topology, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + hr = IMFTopology_GetSourceNodeCollection(topology, &collection); + ok(hr == S_OK, "Failed to get source node collection, hr %#lx.\n", hr); + ok(!!collection, "Unexpected object pointer.\n"); + + hr = IMFTopology_GetSourceNodeCollection(topology, &collection2); + ok(hr == S_OK, "Failed to get source node collection, hr %#lx.\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 %#lx.\n", hr); + ok(!size, "Unexpected item count.\n"); + + EXPECT_REF(collection, 1); + hr = IMFCollection_AddElement(collection, (IUnknown *)collection); + ok(hr == S_OK, "Failed to add element, hr %#lx.\n", hr); + EXPECT_REF(collection, 2); + + hr = IMFCollection_GetElementCount(collection, &size); + ok(hr == S_OK, "Failed to get item count, hr %#lx.\n", hr); + ok(size == 1, "Unexpected item count.\n"); + + /* Empty collection to stop referencing itself */ + hr = IMFCollection_RemoveAllElements(collection); + ok(hr == S_OK, "Failed to get item count, hr %#lx.\n", hr); + + hr = IMFCollection_GetElementCount(collection2, &size); + ok(hr == S_OK, "Failed to get item count, hr %#lx.\n", hr); + ok(!size, "Unexpected item count.\n"); + + ref = IMFCollection_Release(collection2); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFCollection_Release(collection); + ok(ref == 0, "Release returned %ld\n", ref); + + /* Add some nodes. */ + hr = IMFTopology_GetSourceNodeCollection(topology, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + hr = IMFTopology_GetOutputNodeCollection(topology, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node); + ok(hr == S_OK, "Failed to create a node, hr %#lx.\n", hr); + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + IMFTopologyNode_Release(node); + + hr = IMFTopology_GetSourceNodeCollection(topology, &collection); + ok(hr == S_OK, "Failed to get source node collection, hr %#lx.\n", hr); + ok(!!collection, "Unexpected object pointer.\n"); + hr = IMFCollection_GetElementCount(collection, &size); + ok(hr == S_OK, "Failed to get item count, hr %#lx.\n", hr); + ok(size == 1, "Unexpected item count.\n"); + ref = IMFCollection_Release(collection); + ok(ref == 0, "Release returned %ld\n", ref); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &node); + ok(hr == S_OK, "Failed to create a node, hr %#lx.\n", hr); + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + IMFTopologyNode_Release(node); + + hr = IMFTopology_GetSourceNodeCollection(topology, &collection); + ok(hr == S_OK, "Failed to get source node collection, hr %#lx.\n", hr); + ok(!!collection, "Unexpected object pointer.\n"); + hr = IMFCollection_GetElementCount(collection, &size); + ok(hr == S_OK, "Failed to get item count, hr %#lx.\n", hr); + ok(size == 1, "Unexpected item count.\n"); + ref = IMFCollection_Release(collection); + ok(ref == 0, "Release returned %ld\n", ref); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node); + ok(hr == S_OK, "Failed to create a node, hr %#lx.\n", hr); + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + IMFTopologyNode_Release(node); + + hr = IMFTopology_GetSourceNodeCollection(topology, &collection); + ok(hr == S_OK, "Failed to get source node collection, hr %#lx.\n", hr); + ok(!!collection, "Unexpected object pointer.\n"); + hr = IMFCollection_GetElementCount(collection, &size); + ok(hr == S_OK, "Failed to get item count, hr %#lx.\n", hr); + ok(size == 1, "Unexpected item count.\n"); + ref = IMFCollection_Release(collection); + ok(ref == 0, "Release returned %ld\n", ref); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node); + ok(hr == S_OK, "Failed to create a node, hr %#lx.\n", hr); + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + + /* Associated object. */ + hr = IMFTopologyNode_SetObject(node, NULL); + ok(hr == S_OK, "Failed to set object, hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetObject(node, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + object = (void *)0xdeadbeef; + hr = IMFTopologyNode_GetObject(node, &object); + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + ok(!object, "Unexpected object %p.\n", object); + + hr = IMFTopologyNode_SetObject(node, &test_unk); + ok(hr == S_OK, "Failed to set object, hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetObject(node, &object); + ok(hr == S_OK, "Failed to get object, hr %#lx.\n", hr); + ok(object == &test_unk, "Unexpected object %p.\n", object); + IUnknown_Release(object); + + hr = IMFTopologyNode_SetObject(node, &test_unk2); + ok(hr == S_OK, "Failed to set object, hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetCount(node, &count); + ok(hr == S_OK, "Failed to get attribute count, hr %#lx.\n", hr); + ok(count == 0, "Unexpected attribute count %u.\n", count); + + hr = IMFTopologyNode_SetGUID(node, &MF_TOPONODE_TRANSFORM_OBJECTID, &MF_TOPONODE_TRANSFORM_OBJECTID); + ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); + + hr = IMFTopologyNode_SetObject(node, NULL); + ok(hr == S_OK, "Failed to set object, hr %#lx.\n", hr); + + object = (void *)0xdeadbeef; + hr = IMFTopologyNode_GetObject(node, &object); + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + ok(!object, "Unexpected object %p.\n", object); + + hr = IMFTopologyNode_GetCount(node, &count); + ok(hr == S_OK, "Failed to get attribute count, hr %#lx.\n", hr); + ok(count == 1, "Unexpected attribute count %u.\n", count); + + /* Preferred stream types. */ + hr = IMFTopologyNode_GetInputCount(node, &io_count); + ok(hr == S_OK, "Failed to get input count, hr %#lx.\n", hr); + ok(io_count == 0, "Unexpected count %lu.\n", io_count); + + hr = IMFTopologyNode_GetInputPrefType(node, 0, &mediatype); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateMediaType(&mediatype); + ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); + + hr = IMFTopologyNode_SetInputPrefType(node, 0, mediatype); + ok(hr == S_OK, "Failed to set preferred type, hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetInputPrefType(node, 0, &mediatype2); + ok(hr == S_OK, "Failed to get preferred type, hr %#lx.\n", hr); + ok(mediatype2 == mediatype, "Unexpected mediatype instance.\n"); + IMFMediaType_Release(mediatype2); + + hr = IMFTopologyNode_SetInputPrefType(node, 0, NULL); + ok(hr == S_OK, "Failed to set preferred type, hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetInputPrefType(node, 0, &mediatype2); + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + ok(!mediatype2, "Unexpected mediatype instance.\n"); + + hr = IMFTopologyNode_SetInputPrefType(node, 1, mediatype); + ok(hr == S_OK, "Failed to set preferred type, hr %#lx.\n", hr); + + hr = IMFTopologyNode_SetInputPrefType(node, 1, mediatype); + ok(hr == S_OK, "Failed to set preferred type, hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetInputCount(node, &io_count); + ok(hr == S_OK, "Failed to get input count, hr %#lx.\n", hr); + ok(io_count == 2, "Unexpected count %lu.\n", io_count); + + hr = IMFTopologyNode_GetOutputCount(node, &io_count); + ok(hr == S_OK, "Failed to get input count, hr %#lx.\n", hr); + ok(io_count == 0, "Unexpected count %lu.\n", io_count); + + hr = IMFTopologyNode_SetOutputPrefType(node, 0, mediatype); + ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr); + + ref = IMFTopologyNode_Release(node); + ok(ref == 1, "Release returned %ld\n", ref); + + /* Source node. */ + hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node); + ok(hr == S_OK, "Failed to create a node, hr %#lx.\n", hr); + + hr = IMFTopologyNode_SetInputPrefType(node, 0, mediatype); + ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr); + + hr = IMFTopologyNode_SetOutputPrefType(node, 2, mediatype); + ok(hr == S_OK, "Failed to set preferred type, hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetOutputPrefType(node, 0, &mediatype2); + ok(hr == E_FAIL, "Failed to get preferred type, hr %#lx.\n", hr); + ok(!mediatype2, "Unexpected mediatype instance.\n"); + + hr = IMFTopologyNode_GetOutputCount(node, &io_count); + ok(hr == S_OK, "Failed to get output count, hr %#lx.\n", hr); + ok(io_count == 3, "Unexpected count %lu.\n", io_count); + + ref = IMFTopologyNode_Release(node); + ok(ref == 0, "Release returned %ld\n", ref); + + /* Tee node. */ + hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &node); + ok(hr == S_OK, "Failed to create a node, hr %#lx.\n", hr); + + hr = IMFTopologyNode_SetInputPrefType(node, 0, mediatype); + ok(hr == S_OK, "Failed to set preferred type, hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetInputPrefType(node, 0, &mediatype2); + ok(hr == S_OK, "Failed to get preferred type, hr %#lx.\n", hr); + ok(mediatype2 == mediatype, "Unexpected mediatype instance.\n"); + IMFMediaType_Release(mediatype2); + + hr = IMFTopologyNode_GetOutputPrefType(node, 0, &mediatype2); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetInputCount(node, &io_count); + ok(hr == S_OK, "Failed to get output count, hr %#lx.\n", hr); + ok(io_count == 0, "Unexpected count %lu.\n", io_count); + + hr = IMFTopologyNode_SetInputPrefType(node, 1, mediatype); + ok(hr == MF_E_INVALIDTYPE, "Unexpected hr %#lx.\n", hr); + + hr = IMFTopologyNode_SetInputPrefType(node, 3, mediatype); + ok(hr == MF_E_INVALIDTYPE, "Unexpected hr %#lx.\n", hr); + + hr = IMFTopologyNode_SetOutputPrefType(node, 4, mediatype); + ok(hr == S_OK, "Failed to set preferred type, hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetOutputPrefType(node, 0, &mediatype2); + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateMediaType(&mediatype2); + ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); + + /* Changing output type does not change input type. */ + hr = IMFTopologyNode_SetOutputPrefType(node, 4, mediatype2); + ok(hr == S_OK, "Failed to set preferred type, hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetInputPrefType(node, 0, &mediatype3); + ok(hr == S_OK, "Failed to get preferred type, hr %#lx.\n", hr); + ok(mediatype3 == mediatype, "Unexpected mediatype instance.\n"); + IMFMediaType_Release(mediatype3); + + IMFMediaType_Release(mediatype2); + + hr = IMFTopologyNode_GetInputCount(node, &io_count); + ok(hr == S_OK, "Failed to get output count, hr %#lx.\n", hr); + ok(io_count == 0, "Unexpected count %lu.\n", io_count); + + hr = IMFTopologyNode_GetOutputCount(node, &io_count); + ok(hr == S_OK, "Failed to get output count, hr %#lx.\n", hr); + ok(io_count == 5, "Unexpected count %lu.\n", io_count); + + ref = IMFTopologyNode_Release(node); + ok(ref == 0, "Release returned %ld\n", ref); + + /* Transform node. */ + hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node); + ok(hr == S_OK, "Failed to create a node, hr %#lx.\n", hr); + + hr = IMFTopologyNode_SetInputPrefType(node, 3, mediatype); + ok(hr == S_OK, "Failed to set preferred type, hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetInputCount(node, &io_count); + ok(hr == S_OK, "Failed to get input count, hr %#lx.\n", hr); + ok(io_count == 4, "Unexpected count %lu.\n", io_count); + + hr = IMFTopologyNode_SetOutputPrefType(node, 4, mediatype); + ok(hr == S_OK, "Failed to set preferred type, hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetInputCount(node, &io_count); + ok(hr == S_OK, "Failed to get output count, hr %#lx.\n", hr); + ok(io_count == 4, "Unexpected count %lu.\n", io_count); + + hr = IMFTopologyNode_GetOutputCount(node, &io_count); + ok(hr == S_OK, "Failed to get output count, hr %#lx.\n", hr); + ok(io_count == 5, "Unexpected count %lu.\n", io_count); + + ref = IMFTopologyNode_Release(node); + ok(ref == 0, "Release returned %ld\n", ref); + + IMFMediaType_Release(mediatype); + + hr = IMFTopology_GetOutputNodeCollection(topology, &collection); + ok(hr == S_OK || broken(hr == E_FAIL) /* before Win8 */, "Failed to get output node collection, hr %#lx.\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 %#lx.\n", hr); + ok(size == 1, "Unexpected item count.\n"); + ref = IMFCollection_Release(collection); + ok(ref == 0, "Release returned %ld\n", ref); + } + + ref = IMFTopology_Release(topology); + ok(ref == 0, "Release returned %ld\n", ref); + + /* Connect nodes. */ + hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node2); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + + EXPECT_REF(node, 1); + EXPECT_REF(node2, 1); + + hr = IMFTopologyNode_ConnectOutput(node, 0, node2, 1); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + + EXPECT_REF(node, 2); + EXPECT_REF(node2, 2); + + IMFTopologyNode_Release(node); + + EXPECT_REF(node, 1); + EXPECT_REF(node2, 2); + + IMFTopologyNode_Release(node2); + + EXPECT_REF(node, 1); + EXPECT_REF(node2, 1); + + hr = IMFTopologyNode_GetNodeType(node2, &node_type); + ok(hr == S_OK, "Failed to get node type, hr %#lx.\n", hr); + + IMFTopologyNode_Release(node); + + /* Connect within topology. */ + hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node2); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + + hr = MFCreateTopology(&topology); + ok(hr == S_OK, "Failed to create topology, hr %#lx.\n", hr); + + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + + hr = IMFTopology_AddNode(topology, node2); + ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + + EXPECT_REF(node, 2); + EXPECT_REF(node2, 2); + + hr = IMFTopologyNode_ConnectOutput(node, 0, node2, 1); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + + EXPECT_REF(node, 3); + EXPECT_REF(node2, 3); + + hr = IMFTopology_Clear(topology); + ok(hr == S_OK, "Failed to clear topology, hr %#lx.\n", hr); + + EXPECT_REF(node, 1); + EXPECT_REF(node2, 1); + + /* Removing connected node breaks connection. */ + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + + hr = IMFTopology_AddNode(topology, node2); + ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + + hr = IMFTopologyNode_ConnectOutput(node, 0, node2, 1); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + + hr = IMFTopology_RemoveNode(topology, node); + ok(hr == S_OK, "Failed to remove a node, hr %#lx.\n", hr); + + EXPECT_REF(node, 1); + EXPECT_REF(node2, 2); + + hr = IMFTopologyNode_GetOutput(node, 0, &node3, &index); + ok(hr == MF_E_NOT_FOUND, "Unexpected hr %#lx.\n", hr); + + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + + hr = IMFTopologyNode_ConnectOutput(node, 0, node2, 1); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + + hr = IMFTopology_RemoveNode(topology, node2); + ok(hr == S_OK, "Failed to remove a node, hr %#lx.\n", hr); + + EXPECT_REF(node, 2); + EXPECT_REF(node2, 1); + + IMFTopologyNode_Release(node); + IMFTopologyNode_Release(node2); + + /* Cloning nodes of different types. */ + hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node2); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + + hr = IMFTopologyNode_CloneFrom(node, node2); + ok(hr == MF_E_INVALIDREQUEST, "Unexpected hr %#lx.\n", hr); + + ref = IMFTopologyNode_Release(node2); + ok(ref == 0, "Release returned %ld\n", ref); + + /* Cloning preferred types. */ + hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node2); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + + hr = MFCreateMediaType(&mediatype); + ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); + + hr = IMFTopologyNode_SetOutputPrefType(node2, 0, mediatype); + ok(hr == S_OK, "Failed to set preferred type, hr %#lx.\n", hr); + + /* Vista checks for additional attributes. */ + hr = IMFTopologyNode_CloneFrom(node, node2); + ok(hr == S_OK || broken(hr == MF_E_ATTRIBUTENOTFOUND) /* Vista */, "Failed to clone a node, hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetOutputPrefType(node, 0, &mediatype2); + ok(hr == S_OK, "Failed to get preferred type, hr %#lx.\n", hr); + ok(mediatype == mediatype2, "Unexpected media type.\n"); + + IMFMediaType_Release(mediatype2); + + ref = IMFTopologyNode_Release(node2); + ok(ref == 0, "Release returned %ld\n", ref); + + IMFMediaType_Release(mediatype); + + /* Existing preferred types are not cleared. */ + hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node2); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetOutputCount(node, &io_count); + ok(hr == S_OK, "Failed to get output count, hr %#lx.\n", hr); + ok(io_count == 1, "Unexpected output count.\n"); + + hr = IMFTopologyNode_CloneFrom(node, node2); + ok(hr == S_OK || broken(hr == MF_E_ATTRIBUTENOTFOUND) /* Vista */, "Failed to clone a node, hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetOutputCount(node, &io_count); + ok(hr == S_OK, "Failed to get output count, hr %#lx.\n", hr); + ok(io_count == 1, "Unexpected output count.\n"); + + hr = IMFTopologyNode_GetOutputPrefType(node, 0, &mediatype2); + ok(hr == S_OK, "Failed to get preferred type, hr %#lx.\n", hr); + ok(!!mediatype2, "Unexpected media type.\n"); + IMFMediaType_Release(mediatype2); + + hr = IMFTopologyNode_CloneFrom(node2, node); + ok(hr == S_OK || broken(hr == MF_E_ATTRIBUTENOTFOUND) /* Vista */, "Failed to clone a node, hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetOutputCount(node2, &io_count); + ok(hr == S_OK, "Failed to get output count, hr %#lx.\n", hr); + ok(io_count == 1, "Unexpected output count.\n"); + + ref = IMFTopologyNode_Release(node2); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopologyNode_Release(node); + ok(ref == 0, "Release returned %ld\n", ref); + + /* Add one node, connect to another that hasn't been added. */ + hr = IMFTopology_Clear(topology); + ok(hr == S_OK, "Failed to clear topology, hr %#lx.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node2); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + + hr = IMFTopology_GetNodeCount(topology, &node_count); + ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); + ok(node_count == 1, "Unexpected node count.\n"); + + hr = IMFTopologyNode_ConnectOutput(node, 0, node2, 0); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + + hr = IMFTopology_GetNodeCount(topology, &node_count); + ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); + ok(node_count == 1, "Unexpected node count.\n"); + + /* Add same node to different topologies. */ + hr = IMFTopology_Clear(topology); + ok(hr == S_OK, "Failed to clear topology, hr %#lx.\n", hr); + + hr = MFCreateTopology(&topology2); + ok(hr == S_OK, "Failed to create topology, hr %#lx.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + EXPECT_REF(node, 2); + + hr = IMFTopology_GetNodeCount(topology, &node_count); + ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); + ok(node_count == 1, "Unexpected node count.\n"); + + hr = IMFTopology_GetNodeCount(topology2, &node_count); + ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); + ok(node_count == 0, "Unexpected node count.\n"); + + hr = IMFTopology_AddNode(topology2, node); + ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + EXPECT_REF(node, 3); + + hr = IMFTopology_GetNodeCount(topology, &node_count); + ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); + ok(node_count == 1, "Unexpected node count.\n"); + + hr = IMFTopology_GetNodeCount(topology2, &node_count); + ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); + ok(node_count == 1, "Unexpected node count.\n"); + + ref = IMFTopology_Release(topology2); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopology_Release(topology); + ok(ref == 0, "Release returned %ld\n", ref); + + ref = IMFTopologyNode_Release(node); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopologyNode_Release(node2); + ok(ref == 0, "Release returned %ld\n", ref); + + /* Try cloning a topology without all outputs connected */ + hr = MFCreateTopology(&topology); + ok(hr == S_OK, "Failed to create topology, hr %#lx.\n", hr); + + hr = MFCreateTopology(&topology2); + ok(hr == S_OK, "Failed to create topology, hr %#lx.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + EXPECT_REF(node, 2); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node2); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + + hr = IMFTopology_AddNode(topology, node2); + ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + EXPECT_REF(node, 2); + + hr = IMFTopologyNode_ConnectOutput(node, 1, node2, 0); + ok(hr == S_OK, "Failed to connect output, hr %#lx.\n", hr); + + hr = IMFTopology_CloneFrom(topology2, topology); + ok(hr == S_OK, "Failed to clone from topology, hr %#lx.\n", hr); + + hr = IMFTopology_GetNodeCount(topology2, &node_count); + ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); + ok(node_count == 2, "Unexpected node count %u.\n", node_count); + + hr = IMFTopology_GetNode(topology2, 0, &node3); + ok(hr == S_OK, "Failed to get node, hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetOutputCount(node3, &size); + ok(hr == S_OK, "Failed to get output count, hr %#lx.\n", hr); + ok(size == 2, "Unexpected output count %lu.\n", size); + + IMFTopologyNode_Release(node3); + + ref = IMFTopology_Release(topology2); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopology_Release(topology); + ok(ref == 0, "Release returned %ld\n", ref); + + ref = IMFTopologyNode_Release(node2); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopologyNode_Release(node); + ok(ref == 0, "Release returned %ld\n", ref); +} + +static void test_topology_tee_node(void) +{ + IMFTopologyNode *src_node, *tee_node; + IMFMediaType *mediatype, *mediatype2; + IMFTopology *topology; + DWORD count; + HRESULT hr; + LONG ref; + + hr = MFCreateTopology(&topology); + ok(hr == S_OK, "Failed to create topology, hr %#lx.\n", hr); + + hr = MFCreateMediaType(&mediatype); + ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &tee_node); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &src_node); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + + hr = IMFTopologyNode_SetInputPrefType(tee_node, 0, mediatype); + ok(hr == S_OK, "Failed to set type, hr %#lx.\n", hr); + + /* Even though tee node has only one input and source has only one output, + it's possible to connect to higher inputs/outputs. */ + + /* SRC(0) -> TEE(0) */ + hr = IMFTopologyNode_ConnectOutput(src_node, 0, tee_node, 0); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetInputCount(tee_node, &count); + ok(hr == S_OK, "Failed to get count, hr %#lx.\n", hr); + ok(count == 1, "Unexpected count %lu.\n", count); + + hr = IMFTopologyNode_GetInputPrefType(tee_node, 0, &mediatype2); + ok(hr == S_OK, "Failed to get type, hr %#lx.\n", hr); + ok(mediatype2 == mediatype, "Unexpected type.\n"); + IMFMediaType_Release(mediatype2); + + /* SRC(0) -> TEE(1) */ + hr = IMFTopologyNode_ConnectOutput(src_node, 0, tee_node, 1); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetInputCount(tee_node, &count); + ok(hr == S_OK, "Failed to get count, hr %#lx.\n", hr); + ok(count == 2, "Unexpected count %lu.\n", count); + + hr = IMFTopologyNode_SetInputPrefType(tee_node, 1, mediatype); + ok(hr == MF_E_INVALIDTYPE, "Unexpected hr %#lx.\n", hr); + + /* SRC(1) -> TEE(1) */ + hr = IMFTopologyNode_ConnectOutput(src_node, 1, tee_node, 1); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetOutputCount(src_node, &count); + ok(hr == S_OK, "Failed to get count, hr %#lx.\n", hr); + ok(count == 2, "Unexpected count %lu.\n", count); + + EXPECT_REF(src_node, 2); + EXPECT_REF(tee_node, 2); + hr = IMFTopologyNode_DisconnectOutput(src_node, 1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + ref = IMFTopologyNode_Release(src_node); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopologyNode_Release(tee_node); + ok(ref == 0, "Release returned %ld\n", ref); + + ref = IMFMediaType_Release(mediatype); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopology_Release(topology); + ok(ref == 0, "Release returned %ld\n", ref); +} + +struct test_handler +{ + IMFMediaTypeHandler IMFMediaTypeHandler_iface; + + ULONG set_current_count; + IMFMediaType *current_type; + IMFMediaType *invalid_type; + + ULONG enum_count; + ULONG media_types_count; + IMFMediaType **media_types; +}; + +static struct test_handler *impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler *iface) +{ + return CONTAINING_RECORD(iface, struct test_handler, IMFMediaTypeHandler_iface); +} + +static HRESULT WINAPI test_handler_QueryInterface(IMFMediaTypeHandler *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IMFMediaTypeHandler) + || IsEqualIID(riid, &IID_IUnknown)) + { + IMFMediaTypeHandler_AddRef((*obj = iface)); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_handler_AddRef(IMFMediaTypeHandler *iface) +{ + return 2; +} + +static ULONG WINAPI test_handler_Release(IMFMediaTypeHandler *iface) +{ + return 1; +} + +static HRESULT WINAPI test_handler_IsMediaTypeSupported(IMFMediaTypeHandler *iface, IMFMediaType *in_type, + IMFMediaType **out_type) +{ + struct test_handler *impl = impl_from_IMFMediaTypeHandler(iface); + BOOL result; + + if (out_type) + *out_type = NULL; + + if (impl->invalid_type && IMFMediaType_Compare(impl->invalid_type, (IMFAttributes *)in_type, + MF_ATTRIBUTES_MATCH_OUR_ITEMS, &result) == S_OK && result) + return MF_E_INVALIDMEDIATYPE; + + if (!impl->current_type) + return S_OK; + + if (IMFMediaType_Compare(impl->current_type, (IMFAttributes *)in_type, + MF_ATTRIBUTES_MATCH_OUR_ITEMS, &result) == S_OK && result) + return S_OK; + + return MF_E_INVALIDMEDIATYPE; +} + +static HRESULT WINAPI test_handler_GetMediaTypeCount(IMFMediaTypeHandler *iface, DWORD *count) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_handler_GetMediaTypeByIndex(IMFMediaTypeHandler *iface, DWORD index, + IMFMediaType **type) +{ + struct test_handler *impl = impl_from_IMFMediaTypeHandler(iface); + + if (impl->media_types) + { + impl->enum_count++; + + if (index >= impl->media_types_count) + return MF_E_NO_MORE_TYPES; + + IMFMediaType_AddRef((*type = impl->media_types[index])); + return S_OK; + } + + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_handler_SetCurrentMediaType(IMFMediaTypeHandler *iface, IMFMediaType *media_type) +{ + struct test_handler *impl = impl_from_IMFMediaTypeHandler(iface); + + if (impl->current_type) + IMFMediaType_Release(impl->current_type); + IMFMediaType_AddRef((impl->current_type = media_type)); + impl->set_current_count++; + + return S_OK; +} + +static HRESULT WINAPI test_handler_GetCurrentMediaType(IMFMediaTypeHandler *iface, IMFMediaType **media_type) +{ + struct test_handler *impl = impl_from_IMFMediaTypeHandler(iface); + HRESULT hr; + + if (!impl->current_type) + { + if (!impl->media_types) + return E_FAIL; + if (!impl->media_types_count) + return MF_E_TRANSFORM_TYPE_NOT_SET; + return MF_E_NOT_INITIALIZED; + } + + if (FAILED(hr = MFCreateMediaType(media_type))) + return hr; + + hr = IMFMediaType_CopyAllItems(impl->current_type, (IMFAttributes *)*media_type); + if (FAILED(hr)) + IMFMediaType_Release(*media_type); + + return hr; +} + +static HRESULT WINAPI test_handler_GetMajorType(IMFMediaTypeHandler *iface, GUID *type) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static const IMFMediaTypeHandlerVtbl test_handler_vtbl = +{ + test_handler_QueryInterface, + test_handler_AddRef, + test_handler_Release, + test_handler_IsMediaTypeSupported, + test_handler_GetMediaTypeCount, + test_handler_GetMediaTypeByIndex, + test_handler_SetCurrentMediaType, + test_handler_GetCurrentMediaType, + test_handler_GetMajorType, +}; + +static const struct test_handler test_handler = {.IMFMediaTypeHandler_iface.lpVtbl = &test_handler_vtbl}; + +struct test_stream_sink +{ + IMFStreamSink IMFStreamSink_iface; + IMFMediaTypeHandler *handler; + IMFMediaSink *media_sink; + + IMFAttributes *attributes; +}; + +static struct test_stream_sink *impl_from_IMFStreamSink(IMFStreamSink *iface) +{ + return CONTAINING_RECORD(iface, struct test_stream_sink, IMFStreamSink_iface); +} + +static HRESULT WINAPI test_stream_sink_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj) +{ + struct test_stream_sink *impl = impl_from_IMFStreamSink(iface); + + if (IsEqualIID(riid, &IID_IMFStreamSink) + || IsEqualIID(riid, &IID_IMFMediaEventGenerator) + || IsEqualIID(riid, &IID_IUnknown)) + { + IMFStreamSink_AddRef((*obj = iface)); + return S_OK; + } + + if (IsEqualIID(riid, &IID_IMFAttributes) && impl->attributes) + { + IMFAttributes_AddRef((*obj = impl->attributes)); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_stream_sink_AddRef(IMFStreamSink *iface) +{ + return 2; +} + +static ULONG WINAPI test_stream_sink_Release(IMFStreamSink *iface) +{ + return 1; +} + +static HRESULT WINAPI test_stream_sink_GetEvent(IMFStreamSink *iface, DWORD flags, IMFMediaEvent **event) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_stream_sink_BeginGetEvent(IMFStreamSink *iface, IMFAsyncCallback *callback, IUnknown *state) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_stream_sink_EndGetEvent(IMFStreamSink *iface, IMFAsyncResult *result, + IMFMediaEvent **event) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_stream_sink_QueueEvent(IMFStreamSink *iface, MediaEventType event_type, + REFGUID ext_type, HRESULT hr, const PROPVARIANT *value) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_stream_sink_GetMediaSink(IMFStreamSink *iface, IMFMediaSink **sink) +{ + struct test_stream_sink *impl = impl_from_IMFStreamSink(iface); + + if (impl->media_sink) + { + IMFMediaSink_AddRef((*sink = impl->media_sink)); + return S_OK; + } + + todo_wine + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_stream_sink_GetIdentifier(IMFStreamSink *iface, DWORD *id) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_stream_sink_GetMediaTypeHandler(IMFStreamSink *iface, IMFMediaTypeHandler **handler) +{ + struct test_stream_sink *impl = impl_from_IMFStreamSink(iface); + + if (impl->handler) + { + IMFMediaTypeHandler_AddRef((*handler = impl->handler)); + return S_OK; + } + + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_stream_sink_ProcessSample(IMFStreamSink *iface, IMFSample *sample) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_stream_sink_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type, + const PROPVARIANT *marker_value, const PROPVARIANT *context) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_stream_sink_Flush(IMFStreamSink *iface) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static const IMFStreamSinkVtbl test_stream_sink_vtbl = +{ + test_stream_sink_QueryInterface, + test_stream_sink_AddRef, + test_stream_sink_Release, + test_stream_sink_GetEvent, + test_stream_sink_BeginGetEvent, + test_stream_sink_EndGetEvent, + test_stream_sink_QueueEvent, + test_stream_sink_GetMediaSink, + test_stream_sink_GetIdentifier, + test_stream_sink_GetMediaTypeHandler, + test_stream_sink_ProcessSample, + test_stream_sink_PlaceMarker, + test_stream_sink_Flush, +}; + +static const struct test_stream_sink test_stream_sink = {.IMFStreamSink_iface.lpVtbl = &test_stream_sink_vtbl}; + +enum object_state +{ + SOURCE_START, + SOURCE_PAUSE, + SOURCE_STOP, + SOURCE_SHUTDOWN, + SINK_ON_CLOCK_START, + SINK_ON_CLOCK_PAUSE, + SINK_ON_CLOCK_STOP, + SINK_ON_CLOCK_RESTART, + SINK_ON_CLOCK_SETRATE, +}; + +struct test_grabber_callback +{ + IMFSampleGrabberSinkCallback IMFSampleGrabberSinkCallback_iface; + LONG refcount; + + IMFCollection *samples; + HANDLE ready_event; + HANDLE done_event; +}; + +static struct test_grabber_callback *impl_from_IMFSampleGrabberSinkCallback(IMFSampleGrabberSinkCallback *iface) +{ + return CONTAINING_RECORD(iface, struct test_grabber_callback, IMFSampleGrabberSinkCallback_iface); +} + +static HRESULT WINAPI test_grabber_callback_QueryInterface(IMFSampleGrabberSinkCallback *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IMFSampleGrabberSinkCallback) || + IsEqualIID(riid, &IID_IMFClockStateSink) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFSampleGrabberSinkCallback_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_grabber_callback_AddRef(IMFSampleGrabberSinkCallback *iface) +{ + struct test_grabber_callback *grabber = impl_from_IMFSampleGrabberSinkCallback(iface); + return InterlockedIncrement(&grabber->refcount); +} + +static ULONG WINAPI test_grabber_callback_Release(IMFSampleGrabberSinkCallback *iface) +{ + struct test_grabber_callback *grabber = impl_from_IMFSampleGrabberSinkCallback(iface); + ULONG refcount = InterlockedDecrement(&grabber->refcount); + + if (!refcount) + { + IMFCollection_Release(grabber->samples); + if (grabber->ready_event) + CloseHandle(grabber->ready_event); + if (grabber->done_event) + CloseHandle(grabber->done_event); + free(grabber); + } + + return refcount; +} + +static HRESULT WINAPI test_grabber_callback_OnClockStart(IMFSampleGrabberSinkCallback *iface, MFTIME time, LONGLONG offset) +{ + return S_OK; +} + +static HRESULT WINAPI test_grabber_callback_OnClockStop(IMFSampleGrabberSinkCallback *iface, MFTIME time) +{ + return S_OK; +} + +static HRESULT WINAPI test_grabber_callback_OnClockPause(IMFSampleGrabberSinkCallback *iface, MFTIME time) +{ + return S_OK; +} + +static HRESULT WINAPI test_grabber_callback_OnClockRestart(IMFSampleGrabberSinkCallback *iface, MFTIME time) +{ + return S_OK; +} + +static HRESULT WINAPI test_grabber_callback_OnClockSetRate(IMFSampleGrabberSinkCallback *iface, MFTIME time, float rate) +{ + return S_OK; +} + +static HRESULT WINAPI test_grabber_callback_OnSetPresentationClock(IMFSampleGrabberSinkCallback *iface, + IMFPresentationClock *clock) +{ + return S_OK; +} + +static HRESULT WINAPI test_grabber_callback_OnProcessSample(IMFSampleGrabberSinkCallback *iface, REFGUID major_type, + DWORD sample_flags, LONGLONG sample_time, LONGLONG sample_duration, const BYTE *buffer, DWORD sample_size) +{ + struct test_grabber_callback *grabber = CONTAINING_RECORD(iface, struct test_grabber_callback, IMFSampleGrabberSinkCallback_iface); + IMFSample *sample; + HRESULT hr; + DWORD res; + + if (!grabber->ready_event) + return E_NOTIMPL; + + sample = create_sample(buffer, sample_size); + hr = IMFSample_SetSampleFlags(sample, sample_flags); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + /* FIXME: sample time is inconsistent across windows versions, ignore it */ + hr = IMFSample_SetSampleTime(sample, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFSample_SetSampleDuration(sample, sample_duration); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFCollection_AddElement(grabber->samples, (IUnknown *)sample); + IMFSample_Release(sample); + + SetEvent(grabber->ready_event); + res = WaitForSingleObject(grabber->done_event, 1000); + ok(!res, "WaitForSingleObject returned %#lx\n", res); + + return S_OK; +} + +static HRESULT WINAPI test_grabber_callback_OnShutdown(IMFSampleGrabberSinkCallback *iface) +{ + return S_OK; +} + +static const IMFSampleGrabberSinkCallbackVtbl test_grabber_callback_vtbl = +{ + test_grabber_callback_QueryInterface, + test_grabber_callback_AddRef, + test_grabber_callback_Release, + test_grabber_callback_OnClockStart, + test_grabber_callback_OnClockStop, + test_grabber_callback_OnClockPause, + test_grabber_callback_OnClockRestart, + test_grabber_callback_OnClockSetRate, + test_grabber_callback_OnSetPresentationClock, + test_grabber_callback_OnProcessSample, + test_grabber_callback_OnShutdown, +}; + +static IMFSampleGrabberSinkCallback *create_test_grabber_callback(void) +{ + struct test_grabber_callback *grabber; + HRESULT hr; + + if (!(grabber = calloc(1, sizeof(*grabber)))) + return NULL; + + grabber->IMFSampleGrabberSinkCallback_iface.lpVtbl = &test_grabber_callback_vtbl; + grabber->refcount = 1; + hr = MFCreateCollection(&grabber->samples); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + return &grabber->IMFSampleGrabberSinkCallback_iface; +} + +enum loader_test_flags +{ + LOADER_TODO = 0x4, + LOADER_NEEDS_VIDEO_PROCESSOR = 0x8, + LOADER_SET_ENUMERATE_SOURCE_TYPES = 0x10, + LOADER_NO_CURRENT_OUTPUT = 0x20, + LOADER_SET_INVALID_INPUT = 0x40, + LOADER_SET_MEDIA_TYPES = 0x80, + LOADER_ADD_RESAMPLER_MFT = 0x100, +}; + +static void test_topology_loader(void) +{ + static const media_type_desc audio_float_44100 = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float), + ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1), + ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 4), + ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100), + ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 4 * 44100), + ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 4 * 8), + }; + static const media_type_desc audio_pcm_44100 = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM), + ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1), + ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100), + ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 44100), + ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 1), + ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 8), + }; + static const media_type_desc audio_pcm_48000 = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM), + ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1), + ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 48000), + ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 48000), + ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 1), + ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 8), + }; + static const media_type_desc audio_pcm_48000_resampler = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM), + ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16), + ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2), + ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 48000), + ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 192000), + ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 4), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1), + }; + static const media_type_desc audio_float_48000 = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float), + ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2), + ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 48000), + ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 8 * 48000), + ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 8), + ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 32), + }; + static const media_type_desc audio_mp3_44100 = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_MP3), + ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2), + ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100), + ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 16000), + ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 1), + }; + static const media_type_desc audio_pcm_44100_incomplete = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM), + ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1), + ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100), + ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 1), + ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 8), + }; + static const media_type_desc audio_float_44100_stereo = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float), + ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 2), + ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 2 * 4), + ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100), + ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 2 * 4 * 44100), + ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 4 * 8), + ATTR_UINT32(MF_MT_AUDIO_CHANNEL_MASK, 3), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + }; + static const media_type_desc video_i420_1280 = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_I420), + ATTR_RATIO(MF_MT_FRAME_SIZE, 1280, 720), + }; + static const media_type_desc video_color_convert_1280_rgb32 = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, DMOVideoFormat_RGB32), + ATTR_RATIO(MF_MT_FRAME_SIZE, 1280, 720), + }; + static const media_type_desc video_video_processor_1280_rgb32 = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + ATTR_RATIO(MF_MT_FRAME_SIZE, 1280, 720), + }; + static const media_type_desc video_video_processor_rgb32 = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + }; + static const media_type_desc video_h264_1280 = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_H264), + ATTR_RATIO(MF_MT_FRAME_SIZE, 1280, 720), + }; + static const media_type_desc video_nv12_1280 = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_NV12), + ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001), + ATTR_RATIO(MF_MT_FRAME_SIZE, 1280, 720), + ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), + ATTR_UINT32(MF_MT_SAMPLE_SIZE, 1280 * 720 * 3 / 2), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + ATTR_UINT32(MF_MT_DEFAULT_STRIDE, 1280), + ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), + ATTR_UINT32(MF_MT_INTERLACE_MODE, 7), + }; + static const media_type_desc video_dummy = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + }; + + const struct loader_test + { + const media_type_desc *input_type; + const media_type_desc *output_type; + const media_type_desc *current_input; + const media_type_desc *decoded_type; + MF_CONNECT_METHOD source_method; + MF_CONNECT_METHOD sink_method; + HRESULT expected_result; + unsigned int flags; + GUID decoder_class; + GUID converter_class; + } + loader_tests[] = + { + { + /* PCM -> PCM, same enumerated type, no current type */ + .input_type = &audio_pcm_44100, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .expected_result = S_OK, + }, + { + /* PCM -> PCM, same enumerated type, incomplete current type */ + .input_type = &audio_pcm_44100, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .current_input = &audio_pcm_44100_incomplete, + .expected_result = MF_E_INVALIDMEDIATYPE, + .flags = LOADER_TODO, + }, + { + /* PCM -> PCM, same enumerated bps, different current bps */ + .input_type = &audio_pcm_48000, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .current_input = &audio_pcm_44100, + .expected_result = MF_E_INVALIDMEDIATYPE, + }, + { + /* PCM -> PCM, same enumerated bps, different current bps, force enumerate */ + .input_type = &audio_pcm_48000, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .current_input = &audio_pcm_44100, + .expected_result = S_OK, + .flags = LOADER_SET_ENUMERATE_SOURCE_TYPES, + }, + + { + /* PCM -> PCM, incomplete enumerated type, same current type */ + .input_type = &audio_pcm_44100_incomplete, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .current_input = &audio_pcm_44100, + .expected_result = S_OK, + }, + { + /* PCM -> PCM, incomplete enumerated type, same current type, force enumerate */ + .input_type = &audio_pcm_44100_incomplete, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .current_input = &audio_pcm_44100, + .expected_result = MF_E_NO_MORE_TYPES, + .flags = LOADER_SET_ENUMERATE_SOURCE_TYPES | LOADER_TODO, + }, + + { + /* PCM -> PCM, different enumerated bps, no current type */ + .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .expected_result = MF_E_INVALIDMEDIATYPE, + }, + { + /* PCM -> PCM, different enumerated bps, same current bps */ + .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .current_input = &audio_pcm_48000, + .expected_result = S_OK, + }, + { + /* PCM -> PCM, different enumerated bps, same current bps, force enumerate */ + .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .current_input = &audio_pcm_48000, + .expected_result = MF_E_NO_MORE_TYPES, + .flags = LOADER_SET_ENUMERATE_SOURCE_TYPES, + }, + { + /* PCM -> PCM, different enumerated bps, no current type, sink allow converter */ + .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_ALLOW_CONVERTER, .source_method = MF_CONNECT_DIRECT, + .expected_result = S_OK, .converter_class = CLSID_CResamplerMediaObject, + }, + { + /* PCM -> PCM, different enumerated bps, same current type, sink allow converter, force enumerate */ + .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_ALLOW_CONVERTER, .source_method = -1, + .current_input = &audio_pcm_48000, + .expected_result = S_OK, .converter_class = CLSID_CResamplerMediaObject, + .flags = LOADER_SET_ENUMERATE_SOURCE_TYPES, + }, + { + /* PCM -> PCM, different enumerated bps, no current type, sink allow decoder */ + .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_ALLOW_DECODER, .source_method = MF_CONNECT_DIRECT, + .expected_result = S_OK, .converter_class = CLSID_CResamplerMediaObject, + }, + { + /* PCM -> PCM, different enumerated bps, no current type, default methods */ + .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = -1, .source_method = -1, + .expected_result = S_OK, .converter_class = CLSID_CResamplerMediaObject, + }, + { + /* PCM -> PCM, different enumerated bps, no current type, source allow converter */ + .input_type = &audio_pcm_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_DIRECT, .source_method = MF_CONNECT_ALLOW_CONVERTER, + .expected_result = MF_E_INVALIDMEDIATYPE, + }, + + { + /* Float -> PCM, refuse input type, add converter */ + .input_type = &audio_float_44100, .output_type = &audio_pcm_48000, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .expected_result = MF_E_NO_MORE_TYPES, .converter_class = CLSID_CResamplerMediaObject, + .flags = LOADER_SET_INVALID_INPUT | LOADER_ADD_RESAMPLER_MFT, + }, + { + /* Float -> PCM, refuse input type, add converter, allow resampler output type */ + .input_type = &audio_float_44100, .output_type = &audio_pcm_48000_resampler, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .expected_result = S_OK, .converter_class = CLSID_CResamplerMediaObject, + .flags = LOADER_SET_INVALID_INPUT | LOADER_ADD_RESAMPLER_MFT, + }, + + { + /* MP3 -> PCM */ + .input_type = &audio_mp3_44100, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .current_input = &audio_mp3_44100, + .expected_result = MF_E_INVALIDMEDIATYPE, + }, + { + /* MP3 -> PCM, force enumerate */ + .input_type = &audio_mp3_44100, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_DIRECT, .source_method = -1, + .current_input = &audio_mp3_44100, + .expected_result = MF_E_NO_MORE_TYPES, + .flags = LOADER_SET_ENUMERATE_SOURCE_TYPES, + }, + { + /* MP3 -> PCM */ + .input_type = &audio_mp3_44100, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_ALLOW_CONVERTER, .source_method = -1, + .current_input = &audio_mp3_44100, + .expected_result = MF_E_TRANSFORM_NOT_POSSIBLE_FOR_CURRENT_MEDIATYPE_COMBINATION, + .flags = LOADER_TODO, + }, + { + /* MP3 -> PCM */ + .input_type = &audio_mp3_44100, .output_type = &audio_pcm_44100, .sink_method = MF_CONNECT_ALLOW_DECODER, .source_method = -1, + .current_input = &audio_mp3_44100, + .expected_result = S_OK, .decoder_class = CLSID_CMP3DecMediaObject, + .flags = LOADER_TODO, + }, + { + /* MP3 -> PCM, need both decoder and converter */ + .input_type = &audio_mp3_44100, .output_type = &audio_float_48000, .sink_method = MF_CONNECT_ALLOW_DECODER, .source_method = -1, + .current_input = &audio_mp3_44100, .decoded_type = &audio_float_44100_stereo, + .expected_result = S_OK, .decoder_class = CLSID_CMP3DecMediaObject, .converter_class = CLSID_CResamplerMediaObject, + .flags = LOADER_TODO, + }, + + { + /* I420 -> RGB32, Color Convert media type */ + .input_type = &video_i420_1280, .output_type = &video_color_convert_1280_rgb32, .sink_method = -1, .source_method = -1, + .expected_result = MF_E_TOPO_CODEC_NOT_FOUND, .converter_class = CLSID_CColorConvertDMO, + .flags = LOADER_NEEDS_VIDEO_PROCESSOR, + }, + { + /* I420 -> RGB32, Video Processor media type */ + .input_type = &video_i420_1280, .output_type = &video_video_processor_1280_rgb32, .sink_method = -1, .source_method = -1, + .expected_result = S_OK, .converter_class = CLSID_CColorConvertDMO, + }, + { + /* I420 -> RGB32, Video Processor media type without frame size */ + .input_type = &video_i420_1280, .output_type = &video_video_processor_rgb32, .sink_method = -1, .source_method = -1, + .expected_result = S_OK, .converter_class = CLSID_CColorConvertDMO, + }, + { + /* H264 -> RGB32, Video Processor media type */ + .input_type = &video_h264_1280, .output_type = &video_video_processor_1280_rgb32, .sink_method = -1, .source_method = -1, + .decoded_type = &video_nv12_1280, + .expected_result = S_OK, .decoder_class = CLSID_CMSH264DecoderMFT, .converter_class = CLSID_CColorConvertDMO, + }, + { + /* RGB32 -> Any Video, no current output type */ + .input_type = &video_i420_1280, .output_type = &video_dummy, .sink_method = -1, .source_method = -1, + .expected_result = S_OK, + .flags = LOADER_NO_CURRENT_OUTPUT, + }, + { + /* RGB32 -> Any Video, no current output type, refuse input type */ + .input_type = &video_i420_1280, .output_type = &video_dummy, .sink_method = -1, .source_method = -1, + .expected_result = S_OK, .converter_class = CLSID_CColorConvertDMO, + .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_INVALID_INPUT, + }, + { + /* RGB32 -> Any Video, no current output type, refuse input type */ + .input_type = &video_i420_1280, .output_type = &video_video_processor_rgb32, .sink_method = -1, .source_method = -1, + .expected_result = S_OK, .converter_class = CLSID_CColorConvertDMO, + .flags = LOADER_NO_CURRENT_OUTPUT | LOADER_SET_INVALID_INPUT | LOADER_SET_MEDIA_TYPES, + }, + }; + + IMFTopologyNode *src_node, *sink_node, *src_node2, *sink_node2, *mft_node; + IMFSampleGrabberSinkCallback *grabber_callback = create_test_grabber_callback(); + struct test_stream_sink stream_sink = test_stream_sink; + IMFMediaType *media_type, *input_type, *output_type; + IMFTopology *topology, *topology2, *full_topology; + struct test_handler handler = test_handler; + IMFPresentationDescriptor *pd; + unsigned int i, count, value; + IMFActivate *sink_activate; + MF_TOPOLOGY_TYPE node_type; + IMFStreamDescriptor *sd; + IMFTransform *transform; + IMFMediaSource *source; + IMFTopoLoader *loader; + IUnknown *node_object; + WORD node_count; + TOPOID node_id, oldtopoid, newtopoid; + DWORD index; + HRESULT hr; + BOOL ret; + LONG ref; + + stream_sink.handler = &handler.IMFMediaTypeHandler_iface; + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Startup failure, hr %#lx.\n", hr); + + hr = MFCreateTopoLoader(NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateTopoLoader(&loader); + ok(hr == S_OK, "Failed to create topology loader, hr %#lx.\n", hr); + + hr = MFCreateTopology(&topology); + ok(hr == S_OK, "Failed to create topology, hr %#lx.\n", hr); + + /* Empty topology */ + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + todo_wine_if(hr == S_OK) + ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) IMFTopology_Release(full_topology); + + /* Add source node. */ + hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &src_node); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio); + ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM); + ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); + + /* When a decoder is involved, windows requires this attribute to be present */ + create_descriptors(1, &media_type, NULL, &pd, &sd); + IMFMediaType_Release(media_type); + + source = create_test_source(pd); + + hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_SOURCE, (IUnknown *)source); + ok(hr == S_OK, "Failed to set node source, hr %#lx.\n", hr); + + hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_STREAM_DESCRIPTOR, (IUnknown *)sd); + ok(hr == S_OK, "Failed to set node sd, hr %#lx.\n", hr); + + hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, (IUnknown *)pd); + ok(hr == S_OK, "Failed to set node pd, hr %#lx.\n", hr); + + hr = IMFTopology_AddNode(topology, src_node); + ok(hr == S_OK, "Failed to add a node, hr %#lx.\n", hr); + + /* Source node only. */ + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &sink_node); + ok(hr == S_OK, "Failed to create output node, hr %#lx.\n", hr); + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); + + hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio); + ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM); + ok(hr == S_OK, "Failed to set attribute, hr %#lx.\n", hr); + + hr = MFCreateSampleGrabberSinkActivate(media_type, grabber_callback, &sink_activate); + ok(hr == S_OK, "Failed to create grabber sink, hr %#lx.\n", hr); + + hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)sink_activate); + ok(hr == S_OK, "Failed to set object, hr %#lx.\n", hr); + + IMFMediaType_Release(media_type); + + hr = IMFTopology_AddNode(topology, sink_node); + ok(hr == S_OK, "Failed to add sink node, hr %#lx.\n", hr); + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + todo_wine_if(hr == MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED) + ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#lx.\n", hr); + + hr = IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + + /* Sink was not resolved. */ + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED, "Unexpected hr %#lx.\n", hr); + + hr = IMFTopologyNode_SetObject(sink_node, NULL); + ok(hr == S_OK, "Failed to set object, hr %#lx.\n", hr); + + hr = IMFActivate_ShutdownObject(sink_activate); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ref = IMFActivate_Release(sink_activate); + ok(ref == 0, "Release returned %ld\n", ref); + + hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_SOURCE, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ref = IMFMediaSource_Release(source); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFPresentationDescriptor_Release(pd); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFStreamDescriptor_Release(sd); + ok(ref == 0, "Release returned %ld\n", ref); + + + hr = MFCreateMediaType(&input_type); + ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); + + hr = MFCreateMediaType(&output_type); + ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); + + for (i = 0; i < ARRAY_SIZE(loader_tests); ++i) + { + const struct loader_test *test = &loader_tests[i]; + + winetest_push_context("%u", i); + + init_media_type(input_type, *test->input_type, -1); + init_media_type(output_type, *test->output_type, -1); + + handler.set_current_count = 0; + if (test->flags & LOADER_NO_CURRENT_OUTPUT) + handler.current_type = NULL; + else + IMFMediaType_AddRef((handler.current_type = output_type)); + + if (test->flags & LOADER_SET_INVALID_INPUT) + handler.invalid_type = input_type; + else + handler.invalid_type = NULL; + + handler.enum_count = 0; + if (test->flags & LOADER_SET_MEDIA_TYPES) + { + handler.media_types_count = 1; + handler.media_types = &output_type; + } + else + { + handler.media_types_count = 0; + handler.media_types = NULL; + } + + if (test->flags & LOADER_ADD_RESAMPLER_MFT) + { + hr = IMFTopology_Clear(topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopology_AddNode(topology, src_node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopology_AddNode(topology, sink_node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &mft_node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = CoCreateInstance(&CLSID_CResamplerMediaObject, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyNode_SetGUID(mft_node, &MF_TOPONODE_TRANSFORM_OBJECTID, &CLSID_CResamplerMediaObject); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyNode_SetObject(mft_node, (IUnknown *)transform); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFTransform_Release(transform); + + hr = IMFTopology_AddNode(topology, mft_node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyNode_ConnectOutput(src_node, 0, mft_node, 0); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + hr = IMFTopologyNode_ConnectOutput(mft_node, 0, sink_node, 0); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + IMFTopologyNode_Release(mft_node); + } + else + { + hr = IMFTopology_Clear(topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopology_AddNode(topology, src_node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopology_AddNode(topology, sink_node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } + + create_descriptors(1, &input_type, test->current_input, &pd, &sd); + + source = create_test_source(pd); + + init_source_node(source, test->source_method, src_node, pd, sd); + init_sink_node(&stream_sink.IMFStreamSink_iface, test->sink_method, sink_node); + + hr = IMFTopology_GetCount(topology, &count); + ok(hr == S_OK, "Failed to get attribute count, hr %#lx.\n", hr); + ok(!count, "Unexpected count %u.\n", count); + + if (test->flags & LOADER_SET_ENUMERATE_SOURCE_TYPES) + IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, 1); + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + IMFTopology_DeleteItem(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES); + + if (test->flags & LOADER_NEEDS_VIDEO_PROCESSOR && !has_video_processor) + ok(hr == MF_E_INVALIDMEDIATYPE || hr == MF_E_TOPO_CODEC_NOT_FOUND, + "Unexpected hr %#lx\n", hr); + else + { + todo_wine_if(test->flags & LOADER_TODO) + ok(hr == test->expected_result, "Unexpected hr %#lx\n", hr); + ok(full_topology != topology, "Unexpected instance.\n"); + } + + if (test->expected_result != hr) + { + if (hr != S_OK) ref = 0; + else ref = IMFTopology_Release(full_topology); + ok(ref == 0, "Release returned %ld\n", ref); + } + else if (test->expected_result == S_OK) + { + IMFTopology_GetTopologyID(topology, &oldtopoid); + IMFTopology_GetTopologyID(full_topology, &newtopoid); + ok(oldtopoid == newtopoid, "Expected the same topology id. %I64u == %I64u\n", oldtopoid, newtopoid); + ok(topology != full_topology, "Expected a different object for the resolved topology.\n"); + + hr = IMFTopology_GetCount(full_topology, &count); + ok(hr == S_OK, "Failed to get attribute count, hr %#lx.\n", hr); + todo_wine + ok(count == (test->flags & LOADER_SET_ENUMERATE_SOURCE_TYPES ? 2 : 1), + "Unexpected count %u.\n", count); + + value = 0xdeadbeef; + hr = IMFTopology_GetUINT32(full_topology, &MF_TOPOLOGY_RESOLUTION_STATUS, &value); +todo_wine { + ok(hr == S_OK, "Failed to get attribute, hr %#lx.\n", hr); + ok(value == MF_TOPOLOGY_RESOLUTION_SUCCEEDED, "Unexpected value %#x.\n", value); +} + count = 2; + if (!IsEqualGUID(&test->decoder_class, &GUID_NULL)) + count++; + if (!IsEqualGUID(&test->converter_class, &GUID_NULL)) + count++; + + hr = IMFTopology_GetNodeCount(full_topology, &node_count); + ok(hr == S_OK, "Failed to get node count, hr %#lx.\n", hr); + todo_wine_if(IsEqualGUID(&test->decoder_class, &CLSID_CMP3DecMediaObject)) + ok(node_count == count, "Unexpected node count %u.\n", node_count); + + hr = IMFTopologyNode_GetTopoNodeID(src_node, &node_id); + ok(hr == S_OK, "Failed to get source node id, hr %#lx.\n", hr); + + hr = IMFTopology_GetNodeByID(full_topology, node_id, &src_node2); + ok(hr == S_OK, "Failed to get source in resolved topology, hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetTopoNodeID(sink_node, &node_id); + ok(hr == S_OK, "Failed to get sink node id, hr %#lx.\n", hr); + + hr = IMFTopology_GetNodeByID(full_topology, node_id, &sink_node2); + ok(hr == S_OK, "Failed to get sink in resolved topology, hr %#lx.\n", hr); + + if (!IsEqualGUID(&test->decoder_class, &GUID_NULL)) + { + GUID class_id; + + hr = IMFTopologyNode_GetOutput(src_node2, 0, &mft_node, &index); + ok(hr == S_OK, "Failed to get decoder in resolved topology, hr %#lx.\n", hr); + ok(!index, "Unexpected stream index %lu.\n", index); + + hr = IMFTopologyNode_GetNodeType(mft_node, &node_type); + ok(hr == S_OK, "Failed to get transform node type in resolved topology, hr %#lx.\n", hr); + ok(node_type == MF_TOPOLOGY_TRANSFORM_NODE, "Unexpected node type %u.\n", node_type); + + value = 0; + hr = IMFTopologyNode_GetUINT32(mft_node, &MF_TOPONODE_DECODER, &value); + ok(hr == S_OK, "Failed to get attribute, hr %#lx.\n", hr); + ok(value == 1, "Unexpected value.\n"); + + class_id = GUID_NULL; + hr = IMFTopologyNode_GetGUID(mft_node, &MF_TOPONODE_TRANSFORM_OBJECTID, &class_id); + ok(hr == S_OK, "Failed to get attribute, hr %#lx.\n", hr); + ok(IsEqualGUID(&class_id, &test->decoder_class), "got MF_TOPONODE_TRANSFORM_OBJECTID %s.\n", debugstr_guid(&class_id)); + + hr = IMFTopologyNode_GetObject(mft_node, &node_object); + ok(hr == S_OK, "Failed to get object of transform node, hr %#lx.\n", hr); + IMFTopologyNode_Release(mft_node); + + hr = IUnknown_QueryInterface(node_object, &IID_IMFTransform, (void **)&transform); + ok(hr == S_OK, "Failed to get IMFTransform from transform node's object, hr %#lx.\n", hr); + IUnknown_Release(node_object); + + hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type); + ok(hr == S_OK, "Failed to get transform input type, hr %#lx.\n", hr); + hr = IMFMediaType_Compare(input_type, (IMFAttributes *)media_type, MF_ATTRIBUTES_MATCH_OUR_ITEMS, &ret); + ok(hr == S_OK, "Failed to compare media types, hr %#lx.\n", hr); + ok(ret, "Input type of first transform doesn't match source node type.\n"); + IMFMediaType_Release(media_type); + + hr = IMFTransform_GetOutputCurrentType(transform, 0, &media_type); + ok(hr == S_OK, "Failed to get transform input type, hr %#lx.\n", hr); + if (IsEqualGUID(&test->converter_class, &GUID_NULL)) + { + hr = IMFMediaType_Compare(output_type, (IMFAttributes *)media_type, MF_ATTRIBUTES_MATCH_OUR_ITEMS, &ret); + ok(hr == S_OK, "Failed to compare media types, hr %#lx.\n", hr); + ok(ret, "Output type of first transform doesn't match sink node type.\n"); + } + else if (test->decoded_type) + { + check_media_type(media_type, *test->decoded_type, -1); + } + IMFMediaType_Release(media_type); + + IMFTransform_Release(transform); + } + + if (!IsEqualGUID(&test->converter_class, &GUID_NULL)) + { + GUID class_id; + + hr = IMFTopologyNode_GetInput(sink_node2, 0, &mft_node, &index); + ok(hr == S_OK, "Failed to get decoder in resolved topology, hr %#lx.\n", hr); + ok(!index, "Unexpected stream index %lu.\n", index); + + hr = IMFTopologyNode_GetNodeType(mft_node, &node_type); + ok(hr == S_OK, "Failed to get transform node type in resolved topology, hr %#lx.\n", hr); + ok(node_type == MF_TOPOLOGY_TRANSFORM_NODE, "Unexpected node type %u.\n", node_type); + + class_id = GUID_NULL; + hr = IMFTopologyNode_GetGUID(mft_node, &MF_TOPONODE_TRANSFORM_OBJECTID, &class_id); + ok(hr == S_OK, "Failed to get attribute, hr %#lx.\n", hr); + todo_wine_if(IsEqualGUID(&test->converter_class, &CLSID_CColorConvertDMO)) + ok(IsEqualGUID(&class_id, &test->converter_class), "got MF_TOPONODE_TRANSFORM_OBJECTID %s.\n", debugstr_guid(&class_id)); + + hr = IMFTopologyNode_GetObject(mft_node, &node_object); + ok(hr == S_OK, "Failed to get object of transform node, hr %#lx.\n", hr); + IMFTopologyNode_Release(mft_node); + + hr = IUnknown_QueryInterface(node_object, &IID_IMFTransform, (void **)&transform); + ok(hr == S_OK, "Failed to get IMFTransform from transform node's object, hr %#lx.\n", hr); + IUnknown_Release(node_object); + + hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type); + ok(hr == S_OK, "Failed to get transform input type, hr %#lx.\n", hr); + if (IsEqualGUID(&test->decoder_class, &GUID_NULL)) + { + hr = IMFMediaType_Compare(input_type, (IMFAttributes *)media_type, MF_ATTRIBUTES_MATCH_OUR_ITEMS, &ret); + ok(hr == S_OK, "Failed to compare media types, hr %#lx.\n", hr); + ok(ret, "Input type of last transform doesn't match source node type.\n"); + } + else if (test->decoded_type) + { + check_media_type(media_type, *test->decoded_type, -1); + } + IMFMediaType_Release(media_type); + + hr = IMFTransform_GetOutputCurrentType(transform, 0, &media_type); + ok(hr == S_OK, "Failed to get transform input type, hr %#lx.\n", hr); + hr = IMFMediaType_Compare(output_type, (IMFAttributes *)media_type, MF_ATTRIBUTES_MATCH_OUR_ITEMS, &ret); + ok(hr == S_OK, "Failed to compare media types, hr %#lx.\n", hr); + ok(ret, "Output type of last transform doesn't match sink node type.\n"); + IMFMediaType_Release(media_type); + + IMFTransform_Release(transform); + } + + IMFTopologyNode_Release(src_node2); + IMFTopologyNode_Release(sink_node2); + + hr = IMFTopology_SetUINT32(full_topology, &IID_IMFTopology, 123); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopoLoader_Load(loader, full_topology, &topology2, NULL); + ok(hr == S_OK, "Failed to resolve topology, hr %#lx.\n", hr); + ok(full_topology != topology2, "Unexpected instance.\n"); + IMFTopology_GetTopologyID(topology2, &oldtopoid); + IMFTopology_GetTopologyID(full_topology, &newtopoid); + ok(oldtopoid == newtopoid, "Expected the same topology id. %I64u == %I64u\n", oldtopoid, newtopoid); + hr = IMFTopology_GetUINT32(topology2, &IID_IMFTopology, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + ref = IMFTopology_Release(topology2); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopology_Release(full_topology); + ok(ref == 0, "Release returned %ld\n", ref); + } + + hr = IMFTopology_GetCount(topology, &count); + ok(hr == S_OK, "Failed to get attribute count, hr %#lx.\n", hr); + ok(!count, "Unexpected count %u.\n", count); + + if (test->flags & LOADER_SET_MEDIA_TYPES) + ok(handler.enum_count, "got %lu GetMediaTypeByIndex\n", handler.enum_count); + else + ok(!handler.enum_count, "got %lu GetMediaTypeByIndex\n", handler.enum_count); + ok(!handler.set_current_count, "got %lu SetCurrentMediaType\n", handler.set_current_count); + + if (handler.current_type) + IMFMediaType_Release(handler.current_type); + handler.current_type = NULL; + + hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_SOURCE, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ref = IMFMediaSource_Release(source); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFPresentationDescriptor_Release(pd); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFStreamDescriptor_Release(sd); + ok(ref == 0, "Release returned %ld\n", ref); + + winetest_pop_context(); + } + + ref = IMFTopology_Release(topology); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopoLoader_Release(loader); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopologyNode_Release(src_node); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopologyNode_Release(sink_node); + ok(ref == 0, "Release returned %ld\n", ref); + + ref = IMFMediaType_Release(input_type); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFMediaType_Release(output_type); + ok(ref == 0, "Release returned %ld\n", ref); + + hr = MFShutdown(); + ok(hr == S_OK, "Shutdown failure, hr %#lx.\n", hr); + + IMFSampleGrabberSinkCallback_Release(grabber_callback); +} + +static void test_topology_loader_evr(void) +{ + static const media_type_desc media_type_desc = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + ATTR_RATIO(MF_MT_FRAME_SIZE, 640, 480), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE), + {0}, + }; + IMFTopologyNode *node, *source_node, *evr_node; + IMFTopology *topology, *full_topology; + IMFPresentationDescriptor *pd; + IMFMediaTypeHandler *handler; + unsigned int i, count, value; + IMFStreamSink *stream_sink; + IMFMediaType *media_type; + IMFStreamDescriptor *sd; + IMFActivate *activate; + IMFTopoLoader *loader; + IMFMediaSink *sink; + WORD node_count; + UINT64 value64; + HWND window; + HRESULT hr; + LONG ref; + + hr = CoInitialize(NULL); + ok(hr == S_OK, "Failed to initialize, hr %#lx.\n", hr); + + /* EVR sink node. */ + window = create_window(); + + hr = MFCreateVideoRendererActivate(window, &activate); + ok(hr == S_OK, "Failed to create activate object, hr %#lx.\n", hr); + + hr = IMFActivate_ActivateObject(activate, &IID_IMFMediaSink, (void **)&sink); + if (FAILED(hr)) + { + skip("Failed to create an EVR sink, skipping tests.\n"); + DestroyWindow(window); + IMFActivate_Release(activate); + CoUninitialize(); + return; + } + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateTopoLoader(&loader); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Source node. */ + hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &source_node); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Failed to create media type, hr %#lx.\n", hr); + init_media_type(media_type, media_type_desc, -1); + + create_descriptors(1, &media_type, &media_type_desc, &pd, &sd); + init_source_node(NULL, -1, source_node, pd, sd); + IMFPresentationDescriptor_Release(pd); + IMFStreamDescriptor_Release(sd); + + + hr = IMFMediaSink_GetStreamSinkById(sink, 0, &stream_sink); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &evr_node); + ok(hr == S_OK, "Failed to create topology node, hr %#lx.\n", hr); + + hr = IMFTopologyNode_SetObject(evr_node, (IUnknown *)stream_sink); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFStreamSink_GetMediaTypeHandler(stream_sink, &handler); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaTypeHandler_Release(handler); + + IMFStreamSink_Release(stream_sink); + + hr = MFCreateTopology(&topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFTopology_AddNode(topology, source_node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopology_AddNode(topology, evr_node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyNode_ConnectOutput(source_node, 0, evr_node, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFTopologyNode_SetUINT32(evr_node, &MF_TOPONODE_CONNECT_METHOD, MF_CONNECT_DIRECT); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetCount(evr_node, &count); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(count == 1, "Unexpected attribute count %u.\n", count); + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFTopology_GetNodeCount(full_topology, &node_count); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(node_count == 3, "Unexpected node count %u.\n", node_count); + + for (i = 0; i < node_count; ++i) + { + MF_TOPOLOGY_TYPE node_type; + + hr = IMFTopology_GetNode(full_topology, i, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFTopologyNode_GetNodeType(node, &node_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + switch (node_type) + { + case MF_TOPOLOGY_OUTPUT_NODE: + { + value = 1; + hr = IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_STREAMID, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!value, "Unexpected stream id %u.\n", value); + break; + } + case MF_TOPOLOGY_TRANSFORM_NODE: + { + IMFAttributes *attrs; + IMFTransform *copier; + IUnknown *obj; + + hr = IMFTopologyNode_GetObject(node, (IUnknown **)&obj); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IUnknown_QueryInterface(obj, &IID_IMFTransform, (void **)&copier); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFTransform_GetAttributes(copier, &attrs); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + value = 0xdeadbeef; + hr = IMFAttributes_GetUINT32(attrs, &MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, &value); + ok(value == 1, "Unexpected dynamic state support state %u.\n", value); + + IMFAttributes_Release(attrs); + IMFTransform_Release(copier); + IUnknown_Release(obj); + break; + } + case MF_TOPOLOGY_SOURCESTREAM_NODE: + { + value64 = 1; + hr = IMFTopologyNode_GetUINT64(node, &MF_TOPONODE_MEDIASTART, &value64); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!value64, "Unexpected value.\n"); + break; + } + default: + ok(0, "Got unexpected node type %u.\n", node_type); + break; + } + + IMFTopologyNode_Release(node); + } + + ref = IMFTopology_Release(full_topology); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopoLoader_Release(loader); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopology_Release(topology); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopologyNode_Release(source_node); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopologyNode_Release(evr_node); + ok(ref == 0, "Release returned %ld\n", ref); + + hr = IMFActivate_ShutdownObject(activate); + ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); + ref = IMFActivate_Release(activate); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFMediaSink_Release(sink); + ok(ref == 0, "Release returned %ld\n", ref); + + ref = IMFMediaType_Release(media_type); + ok(ref == 0, "Release returned %ld\n", ref); + + DestroyWindow(window); + + CoUninitialize(); +} + +START_TEST(topology) +{ + init_functions(); + + test_topology(); + test_topology_tee_node(); + test_topology_loader(); + test_topology_loader_evr(); +}
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/tests/topology.c | 485 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 485 insertions(+)
diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c index ef4dc86d21e..c717b170c71 100644 --- a/dlls/mf/tests/topology.c +++ b/dlls/mf/tests/topology.c @@ -191,6 +191,309 @@ static void init_sink_node(IMFStreamSink *stream_sink, MF_CONNECT_METHOD method, } }
+struct test_transform +{ + IMFTransform IMFTransform_iface; + LONG refcount; + + IMFAttributes *attributes; + + UINT input_count; + IMFMediaType **input_types; + IMFMediaType *input_type; + + UINT output_count; + IMFMediaType **output_types; + IMFMediaType *output_type; +}; + +static struct test_transform *test_transform_from_IMFTransform(IMFTransform *iface) +{ + return CONTAINING_RECORD(iface, struct test_transform, IMFTransform_iface); +} + +static HRESULT WINAPI test_transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + + if (IsEqualGUID(iid, &IID_IUnknown) + || IsEqualGUID(iid, &IID_IMFTransform)) + { + IMFTransform_AddRef(&transform->IMFTransform_iface); + *out = &transform->IMFTransform_iface; + return S_OK; + } + + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_transform_AddRef(IMFTransform *iface) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + ULONG refcount = InterlockedIncrement(&transform->refcount); + return refcount; +} + +static ULONG WINAPI test_transform_Release(IMFTransform *iface) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + ULONG refcount = InterlockedDecrement(&transform->refcount); + + if (!refcount) + { + if (transform->input_type) + IMFMediaType_Release(transform->input_type); + if (transform->output_type) + IMFMediaType_Release(transform->output_type); + if (transform->attributes) + IMFAttributes_Release(transform->attributes); + free(transform); + } + + return refcount; +} + +static HRESULT WINAPI test_transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, + DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) +{ + *inputs = *outputs = 1; + return S_OK; +} + +static HRESULT WINAPI test_transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, + DWORD output_size, DWORD *outputs) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) +{ + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) +{ + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + if (!(*attributes = transform->attributes)) + return E_NOTIMPL; + IMFAttributes_AddRef(*attributes); + return S_OK; +} + +static HRESULT WINAPI test_transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_DeleteInputStream(IMFTransform *iface, DWORD id) +{ + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) +{ + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, + IMFMediaType **type) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + + if (index >= transform->input_count) + { + *type = NULL; + return MF_E_NO_MORE_TYPES; + } + + *type = transform->input_types[index]; + IMFMediaType_AddRef(*type); + return S_OK; +} + +static HRESULT WINAPI test_transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, + DWORD index, IMFMediaType **type) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + + if (index >= transform->output_count) + { + *type = NULL; + return MF_E_NO_MORE_TYPES; + } + + *type = transform->output_types[index]; + IMFMediaType_AddRef(*type); + return S_OK; +} + +static HRESULT WINAPI test_transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + if (flags & MFT_SET_TYPE_TEST_ONLY) + return S_OK; + if (transform->input_type) + IMFMediaType_Release(transform->input_type); + if ((transform->input_type = type)) + IMFMediaType_AddRef(transform->input_type); + return S_OK; +} + +static HRESULT WINAPI test_transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + if (flags & MFT_SET_TYPE_TEST_ONLY) + return S_OK; + if (transform->output_type) + IMFMediaType_Release(transform->output_type); + if ((transform->output_type = type)) + IMFMediaType_AddRef(transform->output_type); + return S_OK; +} + +static HRESULT WINAPI test_transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + if (!(*type = transform->input_type)) + return MF_E_TRANSFORM_TYPE_NOT_SET; + IMFMediaType_AddRef(*type); + return S_OK; +} + +static HRESULT WINAPI test_transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + if (!(*type = transform->output_type)) + return MF_E_TRANSFORM_TYPE_NOT_SET; + IMFMediaType_AddRef(*type); + return S_OK; +} + +static HRESULT WINAPI test_transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) +{ + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_GetOutputStatus(IMFTransform *iface, DWORD *flags) +{ + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) +{ + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) +{ + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) +{ + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) +{ + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, + MFT_OUTPUT_DATA_BUFFER *data, DWORD *status) +{ + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; +} + +static const IMFTransformVtbl test_transform_vtbl = +{ + test_transform_QueryInterface, + test_transform_AddRef, + test_transform_Release, + test_transform_GetStreamLimits, + test_transform_GetStreamCount, + test_transform_GetStreamIDs, + test_transform_GetInputStreamInfo, + test_transform_GetOutputStreamInfo, + test_transform_GetAttributes, + test_transform_GetInputStreamAttributes, + test_transform_GetOutputStreamAttributes, + test_transform_DeleteInputStream, + test_transform_AddInputStreams, + test_transform_GetInputAvailableType, + test_transform_GetOutputAvailableType, + test_transform_SetInputType, + test_transform_SetOutputType, + test_transform_GetInputCurrentType, + test_transform_GetOutputCurrentType, + test_transform_GetInputStatus, + test_transform_GetOutputStatus, + test_transform_SetOutputBounds, + test_transform_ProcessEvent, + test_transform_ProcessMessage, + test_transform_ProcessInput, + test_transform_ProcessOutput, +}; + +static HRESULT WINAPI test_transform_create(UINT input_count, IMFMediaType **input_types, + UINT output_count, IMFMediaType **output_types, BOOL d3d_aware, IMFTransform **out) +{ + struct test_transform *transform; + HRESULT hr; + + if (!(transform = calloc(1, sizeof(*transform)))) + return E_OUTOFMEMORY; + transform->IMFTransform_iface.lpVtbl = &test_transform_vtbl; + transform->refcount = 1; + + transform->input_count = input_count; + transform->input_types = input_types; + transform->input_type = input_types[0]; + IMFMediaType_AddRef(transform->input_type); + transform->output_count = output_count; + transform->output_types = output_types; + transform->output_type = output_types[0]; + IMFMediaType_AddRef(transform->output_type); + + hr = MFCreateAttributes(&transform->attributes, 1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_SetUINT32(transform->attributes, &MF_SA_D3D_AWARE, d3d_aware); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFAttributes_SetUINT32(transform->attributes, &MF_SA_D3D11_AWARE, d3d_aware); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + *out = &transform->IMFTransform_iface; + return S_OK; +} + DEFINE_EXPECT(test_source_BeginGetEvent); DEFINE_EXPECT(test_source_QueueEvent); DEFINE_EXPECT(test_source_Start); @@ -2677,6 +2980,187 @@ static void test_topology_loader_evr(void) CoUninitialize(); }
+static void test_topology_loader_d3d_init(IMFTopology *topology, IMFMediaSource *source, IMFPresentationDescriptor *pd, IMFStreamDescriptor *sd, + UINT transform_count, IMFTransform **transforms, IMFStreamSink *sink) +{ + IMFTopologyNode *prev_node, *node; + HRESULT hr; + UINT i; + + hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node); + ok(hr == S_OK, "got hr %#lx.\n", hr); + init_source_node(source, MF_CONNECT_DIRECT, node, pd, sd); + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "got hr %#lx.\n", hr); + prev_node = node; + + for (i = 0; i < transform_count; i++) + { + hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyNode_SetObject(node, (IUnknown *)transforms[i]); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyNode_ConnectOutput(prev_node, 0, node, 0); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + IMFTopologyNode_Release(prev_node); + prev_node = node; + } + + hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node); + ok(hr == S_OK, "got hr %#lx.\n", hr); + init_sink_node(sink, MF_CONNECT_DIRECT, node); + hr = IMFTopology_AddNode(topology, node); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = IMFTopologyNode_ConnectOutput(prev_node, 0, node, 0); + ok(hr == S_OK, "Failed to connect nodes, hr %#lx.\n", hr); + IMFTopologyNode_Release(prev_node); + IMFTopologyNode_Release(node); +} + +static void test_topology_loader_d3d(void) +{ + static const media_type_desc video_media_type_desc = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + ATTR_RATIO(MF_MT_FRAME_SIZE, 1280, 720), + }; + + struct test_stream_sink stream_sink = test_stream_sink; + struct test_handler handler = test_handler; + IMFTopology *topology, *full_topology; + IMFPresentationDescriptor *pd; + IMFTransform *transforms[4]; + IMFMediaType *media_type; + IMFStreamDescriptor *sd; + IMFMediaSource *source; + IMFTopoLoader *loader; + HRESULT hr; + WORD count; + LONG ref; + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "got hr %#lx.\n", hr); + init_media_type(media_type, video_media_type_desc, -1); + + stream_sink.handler = &handler.IMFMediaTypeHandler_iface; + hr = MFCreateAttributes(&stream_sink.attributes, 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + handler.media_types_count = 1; + handler.media_types = &media_type; + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + hr = MFCreateTopoLoader(&loader); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = MFCreateTopology(&topology); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + create_descriptors(1, &media_type, &video_media_type_desc, &pd, &sd); + source = create_test_source(pd); + + test_topology_loader_d3d_init(topology, source, pd, sd, 0, NULL, &stream_sink.IMFStreamSink_iface); + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ref = IMFTopology_GetNodeCount(full_topology, &count); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ok(count == 2, "got count %u.\n", count); + ref = IMFTopology_Release(full_topology); + ok(ref == 0, "Release returned %ld\n", ref); + + + /* sink D3D aware attribute doesn't change the resolved topology */ + + hr = IMFAttributes_SetUINT32(stream_sink.attributes, &MF_SA_D3D11_AWARE, 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = IMFAttributes_SetUINT32(stream_sink.attributes, &MF_SA_D3D_AWARE, 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ref = IMFTopology_GetNodeCount(full_topology, &count); + ok(hr == S_OK, "got hr %#lx.\n", hr); + todo_wine ok(count == 2, "got count %u.\n", count); + ref = IMFTopology_Release(full_topology); + ok(ref == 0, "Release returned %ld\n", ref); + + + /* source D3D aware attribute doesn't change the resolved topology */ + + hr = IMFStreamDescriptor_SetUINT32(sd, &MF_SA_D3D11_AWARE, 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = IMFStreamDescriptor_SetUINT32(sd, &MF_SA_D3D_AWARE, 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ref = IMFTopology_GetNodeCount(full_topology, &count); + ok(hr == S_OK, "got hr %#lx.\n", hr); + todo_wine ok(count == 2, "got count %u.\n", count); + ref = IMFTopology_Release(full_topology); + ok(ref == 0, "Release returned %ld\n", ref); + + ref = IMFTopology_Release(topology); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopoLoader_Release(loader); + ok(ref == 0, "Release returned %ld\n", ref); + + + /* transform D3D aware attribute doesn't change the resolved topology */ + + hr = MFCreateTopoLoader(&loader); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = MFCreateTopology(&topology); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + test_transform_create(1, &media_type, 1, &media_type, FALSE, &transforms[0]); + test_transform_create(1, &media_type, 1, &media_type, TRUE, &transforms[1]); + test_transform_create(1, &media_type, 1, &media_type, FALSE, &transforms[2]); + test_transform_create(1, &media_type, 1, &media_type, TRUE, &transforms[3]); + + test_topology_loader_d3d_init(topology, source, pd, sd, 4, transforms, &stream_sink.IMFStreamSink_iface); + + IMFTransform_Release(transforms[0]); + IMFTransform_Release(transforms[1]); + IMFTransform_Release(transforms[2]); + IMFTransform_Release(transforms[3]); + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ref = IMFTopology_GetNodeCount(full_topology, &count); + ok(hr == S_OK, "got hr %#lx.\n", hr); + todo_wine ok(count == 6, "got count %u.\n", count); + ref = IMFTopology_Release(full_topology); + ok(ref == 0, "Release returned %ld\n", ref); + + ref = IMFTopology_Release(topology); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopoLoader_Release(loader); + ok(ref == 0, "Release returned %ld\n", ref); + + + ref = IMFMediaSource_Release(source); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFPresentationDescriptor_Release(pd); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFStreamDescriptor_Release(sd); + ok(ref == 0, "Release returned %ld\n", ref); + + hr = MFShutdown(); + ok(hr == S_OK, "Shutdown failure, hr %#lx.\n", hr); + + + IMFAttributes_Release(stream_sink.attributes); + IMFMediaType_Release(media_type); + + winetest_pop_context(); +} + START_TEST(topology) { init_functions(); @@ -2685,4 +3169,5 @@ START_TEST(topology) test_topology_tee_node(); test_topology_loader(); test_topology_loader_evr(); + test_topology_loader_d3d(); }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/mf/tests/Makefile.in | 2 +- dlls/mf/tests/topology.c | 619 +++++++++++++++++++++++++++++++++++++- 2 files changed, 615 insertions(+), 6 deletions(-)
diff --git a/dlls/mf/tests/Makefile.in b/dlls/mf/tests/Makefile.in index 598a002260b..432400d4efc 100644 --- a/dlls/mf/tests/Makefile.in +++ b/dlls/mf/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = mf.dll -IMPORTS = mf mfplat dmoguids mfuuid strmiids uuid wmcodecdspuuid ole32 user32 propsys msdmo d3d11 msvfw32 +IMPORTS = mf mfplat dmoguids mfuuid strmiids uuid wmcodecdspuuid ole32 user32 propsys msdmo d3d9 d3d11 dxva2 msvfw32
SOURCES = \ mf.c \ diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c index c717b170c71..7b820c8abfa 100644 --- a/dlls/mf/tests/topology.c +++ b/dlls/mf/tests/topology.c @@ -26,6 +26,9 @@
#include "uuids.h" #include "wmcodecdsp.h" +#include "d3d9.h" +#include "evr9.h" +#include "d3d11_4.h"
#include "mferror.h"
@@ -78,6 +81,21 @@ static void _expect_ref(IUnknown* obj, ULONG expected_refcount, int line) expected_refcount); }
+#define check_interface(a, b, c) check_interface_(__LINE__, a, b, c) +static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported) +{ + IUnknown *iface = iface_ptr; + HRESULT hr, expected_hr; + IUnknown *unk; + + expected_hr = supported ? S_OK : E_NOINTERFACE; + + hr = IUnknown_QueryInterface(iface, iid, (void **)&unk); + ok_(__FILE__, line)(hr == expected_hr, "Got hr %#lx, expected %#lx.\n", hr, expected_hr); + if (SUCCEEDED(hr)) + IUnknown_Release(unk); +} + static HWND create_window(void) { RECT r = {0, 0, 640, 480}; @@ -88,6 +106,27 @@ static HWND create_window(void) 0, 0, r.right - r.left, r.bottom - r.top, NULL, NULL, NULL, NULL); }
+static IDirect3DDevice9 *create_d3d9_device(IDirect3D9 *d3d9, HWND focus_window) +{ + D3DPRESENT_PARAMETERS present_parameters = {0}; + IDirect3DDevice9 *device = NULL; + + present_parameters.BackBufferWidth = 640; + present_parameters.BackBufferHeight = 480; + present_parameters.BackBufferFormat = D3DFMT_X8R8G8B8; + present_parameters.SwapEffect = D3DSWAPEFFECT_DISCARD; + present_parameters.hDeviceWindow = focus_window; + present_parameters.Windowed = TRUE; + present_parameters.EnableAutoDepthStencil = TRUE; + present_parameters.AutoDepthStencilFormat = D3DFMT_D24S8; + present_parameters.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; + + IDirect3D9_CreateDevice(d3d9, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, focus_window, + D3DCREATE_HARDWARE_VERTEXPROCESSING, &present_parameters, &device); + + return device; +} + static IMFSample *create_sample(const BYTE *data, ULONG size) { IMFMediaBuffer *media_buffer; @@ -197,6 +236,7 @@ struct test_transform LONG refcount;
IMFAttributes *attributes; + const MFT_OUTPUT_STREAM_INFO *output_stream_info;
UINT input_count; IMFMediaType **input_types; @@ -205,6 +245,11 @@ struct test_transform UINT output_count; IMFMediaType **output_types; IMFMediaType *output_type; + + IDirect3DDeviceManager9 *expect_d3d9_device_manager; + BOOL got_d3d9_device_manager; + IMFDXGIDeviceManager *expect_dxgi_device_manager; + BOOL got_dxgi_device_manager; };
static struct test_transform *test_transform_from_IMFTransform(IMFTransform *iface) @@ -279,10 +324,22 @@ static HRESULT WINAPI test_transform_GetInputStreamInfo(IMFTransform *iface, DWO return E_NOTIMPL; }
+static void test_transform_set_output_stream_info(IMFTransform *iface, const MFT_OUTPUT_STREAM_INFO *info) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + transform->output_stream_info = info; +} + static HRESULT WINAPI test_transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) { - ok(0, "Unexpected %s call.\n", __func__); - return E_NOTIMPL; + struct test_transform *transform = test_transform_from_IMFTransform(iface); + + ok(!!transform->output_stream_info, "Unexpected %s iface %p call.\n", __func__, iface); + if (!transform->output_stream_info) + return E_NOTIMPL; + + *info = *transform->output_stream_info; + return S_OK; }
static HRESULT WINAPI test_transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) @@ -414,10 +471,75 @@ static HRESULT WINAPI test_transform_ProcessEvent(IMFTransform *iface, DWORD id, return E_NOTIMPL; }
+static void test_transform_set_expect_d3d9_device_manager(IMFTransform *iface, IDirect3DDeviceManager9 *manager) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + transform->expect_d3d9_device_manager = manager; +} + +static void test_transform_set_expect_dxgi_device_manager(IMFTransform *iface, IMFDXGIDeviceManager *manager) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + transform->expect_dxgi_device_manager = manager; +} + static HRESULT WINAPI test_transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { - ok(0, "Unexpected %s call.\n", __func__); - return E_NOTIMPL; + struct test_transform *transform = test_transform_from_IMFTransform(iface); + switch (message) + { + case MFT_MESSAGE_SET_D3D_MANAGER: + ok(!!param, "Unexpected param.\n"); + ok(transform->expect_d3d9_device_manager || transform->expect_dxgi_device_manager, "Unexpected %s call.\n", __func__); + + if (transform->expect_d3d9_device_manager) + { + IDirect3DDeviceManager9 *manager; + HRESULT hr; + + check_interface((IUnknown *)param, &IID_IMFDXGIDeviceManager, FALSE); + hr = IUnknown_QueryInterface((IUnknown *)param, &IID_IDirect3DDeviceManager9, (void **)&manager); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(manager == transform->expect_d3d9_device_manager, "got manager %p\n", manager); + IDirect3DDeviceManager9_Release(manager); + + transform->got_d3d9_device_manager = TRUE; + } + if (transform->expect_dxgi_device_manager) + { + IMFDXGIDeviceManager *manager; + HRESULT hr; + + check_interface((IUnknown *)param, &IID_IDirect3DDeviceManager9, FALSE); + hr = IUnknown_QueryInterface((IUnknown *)param, &IID_IMFDXGIDeviceManager, (void **)&manager); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(manager == transform->expect_dxgi_device_manager, "got manager %p\n", manager); + if (manager) IMFDXGIDeviceManager_Release(manager); + + transform->got_dxgi_device_manager = TRUE; + } + return S_OK; + + default: + ok(0, "Unexpected %s call.\n", __func__); + return E_NOTIMPL; + } +} + +static BOOL test_transform_got_d3d9_device_manager(IMFTransform *iface) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + BOOL ret = transform->got_d3d9_device_manager; + transform->got_d3d9_device_manager = FALSE; + return ret; +} + +static BOOL test_transform_got_dxgi_device_manager(IMFTransform *iface) +{ + struct test_transform *transform = test_transform_from_IMFTransform(iface); + BOOL ret = transform->got_dxgi_device_manager; + transform->got_dxgi_device_manager = FALSE; + return ret; }
static HRESULT WINAPI test_transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) @@ -1695,10 +1817,12 @@ static const struct test_handler test_handler = {.IMFMediaTypeHandler_iface.lpVt struct test_stream_sink { IMFStreamSink IMFStreamSink_iface; + IMFGetService IMFGetService_iface; IMFMediaTypeHandler *handler; IMFMediaSink *media_sink;
IMFAttributes *attributes; + IUnknown *device_manager; };
static struct test_stream_sink *impl_from_IMFStreamSink(IMFStreamSink *iface) @@ -1724,6 +1848,13 @@ static HRESULT WINAPI test_stream_sink_QueryInterface(IMFStreamSink *iface, REFI return S_OK; }
+ if (IsEqualIID(riid, &IID_IMFGetService)) + { + *obj = &impl->IMFGetService_iface; + IMFGetService_AddRef(&impl->IMFGetService_iface); + return S_OK; + } + *obj = NULL; return E_NOINTERFACE; } @@ -1835,7 +1966,52 @@ static const IMFStreamSinkVtbl test_stream_sink_vtbl = test_stream_sink_Flush, };
-static const struct test_stream_sink test_stream_sink = {.IMFStreamSink_iface.lpVtbl = &test_stream_sink_vtbl}; +static struct test_stream_sink *impl_from_IMFGetService(IMFGetService *iface) +{ + return CONTAINING_RECORD(iface, struct test_stream_sink, IMFGetService_iface); +} + +static HRESULT WINAPI test_stream_sink_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj) +{ + struct test_stream_sink *stream = impl_from_IMFGetService(iface); + return IMFStreamSink_QueryInterface(&stream->IMFStreamSink_iface, riid, obj); +} + +static ULONG WINAPI test_stream_sink_get_service_AddRef(IMFGetService *iface) +{ + struct test_stream_sink *stream = impl_from_IMFGetService(iface); + return IMFStreamSink_AddRef(&stream->IMFStreamSink_iface); +} + +static ULONG WINAPI test_stream_sink_get_service_Release(IMFGetService *iface) +{ + struct test_stream_sink *stream = impl_from_IMFGetService(iface); + return IMFStreamSink_Release(&stream->IMFStreamSink_iface); +} + +static HRESULT WINAPI test_stream_sink_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj) +{ + struct test_stream_sink *stream = impl_from_IMFGetService(iface); + + if (IsEqualGUID(service, &MR_VIDEO_ACCELERATION_SERVICE) && stream->device_manager) + return IUnknown_QueryInterface(stream->device_manager, riid, obj); + + return E_NOINTERFACE; +} + +static const IMFGetServiceVtbl test_stream_sink_get_service_vtbl = +{ + test_stream_sink_get_service_QueryInterface, + test_stream_sink_get_service_AddRef, + test_stream_sink_get_service_Release, + test_stream_sink_get_service_GetService, +}; + +static const struct test_stream_sink test_stream_sink = +{ + .IMFStreamSink_iface.lpVtbl = &test_stream_sink_vtbl, + .IMFGetService_iface.lpVtbl = &test_stream_sink_get_service_vtbl, +};
enum object_state { @@ -3161,6 +3337,433 @@ static void test_topology_loader_d3d(void) winetest_pop_context(); }
+static void test_topology_loader_d3d9(MFTOPOLOGY_DXVA_MODE mode) +{ + static const media_type_desc video_media_type_desc = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + ATTR_RATIO(MF_MT_FRAME_SIZE, 1280, 720), + }; + + struct test_stream_sink stream_sink = test_stream_sink; + MFT_OUTPUT_STREAM_INFO output_stream_info = {0}; + struct test_handler handler = test_handler; + IMFTopology *topology, *full_topology; + IDirect3DDeviceManager9 *d3d9_manager; + IMFPresentationDescriptor *pd; + IDirect3DDevice9 *d3d9_device; + IMFTransform *transforms[4]; + IMFMediaType *media_type; + IMFStreamDescriptor *sd; + IMFMediaSource *source; + IMFTopoLoader *loader; + IDirect3D9 *d3d9; + UINT token; + HRESULT hr; + WORD count; + HWND hwnd; + BOOL ret; + LONG ref; + + winetest_push_context("d3d9 mode %d", mode); + + hwnd = create_window(); + + if (!(d3d9 = Direct3DCreate9(D3D_SDK_VERSION))) + { + skip("Failed to create a D3D9 object, skipping tests.\n"); + goto skip_d3d9; + } + if (!(d3d9_device = create_d3d9_device(d3d9, hwnd))) + { + skip("Failed to create a D3D9 device, skipping tests.\n"); + IDirect3D9_Release(d3d9); + goto skip_d3d9; + } + IDirect3D9_Release(d3d9); + + hr = DXVA2CreateDirect3DDeviceManager9(&token, &d3d9_manager); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IDirect3DDeviceManager9_ResetDevice(d3d9_manager, d3d9_device, token); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IDirect3DDevice9_Release(d3d9_device); + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "got hr %#lx.\n", hr); + init_media_type(media_type, video_media_type_desc, -1); + + stream_sink.handler = &handler.IMFMediaTypeHandler_iface; + hr = MFCreateAttributes(&stream_sink.attributes, 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = IMFAttributes_SetUINT32(stream_sink.attributes, &MF_SA_D3D_AWARE, 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + stream_sink.device_manager = (IUnknown *)d3d9_manager; + + handler.media_types_count = 1; + handler.media_types = &media_type; + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + + hr = MFCreateTopoLoader(&loader); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = MFCreateTopology(&topology); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_DXVA_MODE, mode); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + create_descriptors(1, &media_type, &video_media_type_desc, &pd, &sd); + hr = IMFStreamDescriptor_SetUINT32(sd, &MF_SA_D3D_AWARE, 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + source = create_test_source(pd); + + + /* D3D aware transforms connected to downstream non-D3D-aware transforms don't receive a device manager */ + + test_transform_create(1, &media_type, 1, &media_type, FALSE, &transforms[0]); + test_transform_create(1, &media_type, 1, &media_type, TRUE, &transforms[1]); + test_transform_create(1, &media_type, 1, &media_type, FALSE, &transforms[2]); + test_transform_create(1, &media_type, 1, &media_type, TRUE, &transforms[3]); + + test_topology_loader_d3d_init(topology, source, pd, sd, 4, transforms, &stream_sink.IMFStreamSink_iface); + + IMFMediaSource_Release(source); + IMFPresentationDescriptor_Release(pd); + IMFStreamDescriptor_Release(sd); + + test_transform_set_output_stream_info(transforms[3], &output_stream_info); + + if (mode == MFTOPOLOGY_DXVA_FULL) + { + test_transform_set_expect_d3d9_device_manager(transforms[1], d3d9_manager); + test_transform_set_expect_d3d9_device_manager(transforms[3], d3d9_manager); + } + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ref = IMFTopology_GetNodeCount(full_topology, &count); + ok(hr == S_OK, "got hr %#lx.\n", hr); + todo_wine ok(count == 6, "got count %u.\n", count); + ref = IMFTopology_Release(full_topology); + ok(ref == 0, "Release returned %ld\n", ref); + + if (mode == MFTOPOLOGY_DXVA_FULL) + { + ret = test_transform_got_d3d9_device_manager(transforms[0]); + ok(!ret, "got d3d9 device manager\n"); + ret = test_transform_got_d3d9_device_manager(transforms[1]); + ok(!ret, "got d3d9 device manager\n"); + ret = test_transform_got_d3d9_device_manager(transforms[2]); + ok(!ret, "got d3d9 device manager\n"); + ret = test_transform_got_d3d9_device_manager(transforms[3]); + todo_wine ok(!!ret, "got d3d9 device manager\n"); + } + + /* copier is inserted before the sink if preceding node may allocate samples without a device manager */ + + output_stream_info.dwFlags = MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES; + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ref = IMFTopology_GetNodeCount(full_topology, &count); + ok(hr == S_OK, "got hr %#lx.\n", hr); + if (mode == MFTOPOLOGY_DXVA_NONE || mode == MFTOPOLOGY_DXVA_FULL) + todo_wine ok(count == 6, "got count %u.\n", count); + else + ok(count == 7, "got count %u.\n", count); + ref = IMFTopology_Release(full_topology); + ok(ref == 0, "Release returned %ld\n", ref); + + if (mode == MFTOPOLOGY_DXVA_FULL) + { + ret = test_transform_got_d3d9_device_manager(transforms[0]); + ok(!ret, "got d3d9 device manager\n"); + ret = test_transform_got_d3d9_device_manager(transforms[1]); + ok(!ret, "got d3d9 device manager\n"); + ret = test_transform_got_d3d9_device_manager(transforms[2]); + ok(!ret, "got d3d9 device manager\n"); + ret = test_transform_got_d3d9_device_manager(transforms[3]); + todo_wine ok(!!ret, "got d3d9 device manager\n"); + } + + output_stream_info.dwFlags = MFT_OUTPUT_STREAM_PROVIDES_SAMPLES; + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ref = IMFTopology_GetNodeCount(full_topology, &count); + ok(hr == S_OK, "got hr %#lx.\n", hr); + if (mode == MFTOPOLOGY_DXVA_NONE || mode == MFTOPOLOGY_DXVA_FULL) + todo_wine ok(count == 6, "got count %u.\n", count); + else + ok(count == 7, "got count %u.\n", count); + ref = IMFTopology_Release(full_topology); + ok(ref == 0, "Release returned %ld\n", ref); + + if (mode == MFTOPOLOGY_DXVA_FULL) + { + ret = test_transform_got_d3d9_device_manager(transforms[0]); + ok(!ret, "got d3d9 device manager\n"); + ret = test_transform_got_d3d9_device_manager(transforms[1]); + ok(!ret, "got d3d9 device manager\n"); + ret = test_transform_got_d3d9_device_manager(transforms[2]); + ok(!ret, "got d3d9 device manager\n"); + ret = test_transform_got_d3d9_device_manager(transforms[3]); + todo_wine ok(!!ret, "got d3d9 device manager\n"); + } + + ref = IMFTopology_Release(topology); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopoLoader_Release(loader); + ok(ref == 0, "Release returned %ld\n", ref); + + IMFTransform_Release(transforms[0]); + IMFTransform_Release(transforms[1]); + IMFTransform_Release(transforms[2]); + IMFTransform_Release(transforms[3]); + + + IMFAttributes_Release(stream_sink.attributes); + IMFMediaType_Release(media_type); + + hr = MFShutdown(); + ok(hr == S_OK, "Shutdown failure, hr %#lx.\n", hr); + + IDirect3DDeviceManager9_Release(d3d9_manager); + +skip_d3d9: + DestroyWindow(hwnd); + + winetest_pop_context(); +} + +static void test_topology_loader_d3d11(MFTOPOLOGY_DXVA_MODE mode) +{ + static const media_type_desc video_media_type_desc = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + ATTR_RATIO(MF_MT_FRAME_SIZE, 1280, 720), + }; + + struct test_stream_sink stream_sink = test_stream_sink; + MFT_OUTPUT_STREAM_INFO output_stream_info = {0}; + struct test_handler handler = test_handler; + IMFTopology *topology, *full_topology; + IMFDXGIDeviceManager *dxgi_manager; + ID3D11Multithread *multithread; + IMFPresentationDescriptor *pd; + IMFTransform *transforms[4]; + IMFMediaType *media_type; + IMFStreamDescriptor *sd; + IMFMediaSource *source; + IMFTopoLoader *loader; + ID3D11Device *d3d11; + UINT token; + HRESULT hr; + WORD count; + BOOL ret; + LONG ref; + + winetest_push_context("d3d11 mode %d", mode); + + hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_VIDEO_SUPPORT, NULL, 0, + D3D11_SDK_VERSION, &d3d11, NULL, NULL); + if (FAILED(hr)) + { + skip("D3D11 device creation failed, skipping tests.\n"); + goto skip_d3d11; + } + + hr = ID3D11Device_QueryInterface(d3d11, &IID_ID3D11Multithread, (void **)&multithread); + ok(hr == S_OK, "got %#lx\n", hr); + ID3D11Multithread_SetMultithreadProtected(multithread, TRUE); + ID3D11Multithread_Release(multithread); + + hr = pMFCreateDXGIDeviceManager(&token, &dxgi_manager); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IMFDXGIDeviceManager_ResetDevice(dxgi_manager, (IUnknown *)d3d11, token); + ok(hr == S_OK, "got %#lx\n", hr); + ID3D11Device_Release(d3d11); + + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "got hr %#lx.\n", hr); + init_media_type(media_type, video_media_type_desc, -1); + + stream_sink.handler = &handler.IMFMediaTypeHandler_iface; + hr = MFCreateAttributes(&stream_sink.attributes, 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = IMFAttributes_SetUINT32(stream_sink.attributes, &MF_SA_D3D11_AWARE, 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + stream_sink.device_manager = (IUnknown *)dxgi_manager; + + handler.media_types_count = 1; + handler.media_types = &media_type; + + create_descriptors(1, &media_type, &video_media_type_desc, &pd, &sd); + hr = IMFStreamDescriptor_SetUINT32(sd, &MF_SA_D3D11_AWARE, 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + source = create_test_source(pd); + + + /* D3D aware transforms connected to downstream non-D3D-aware transforms don't receive a device manager */ + + hr = MFCreateTopoLoader(&loader); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = MFCreateTopology(&topology); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_DXVA_MODE, mode); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + test_transform_create(1, &media_type, 1, &media_type, TRUE, &transforms[0]); + test_transform_create(1, &media_type, 1, &media_type, TRUE, &transforms[1]); + test_transform_create(1, &media_type, 1, &media_type, FALSE, &transforms[2]); + test_transform_create(1, &media_type, 1, &media_type, FALSE, &transforms[3]); + + test_topology_loader_d3d_init(topology, source, pd, sd, 4, transforms, &stream_sink.IMFStreamSink_iface); + + test_transform_set_output_stream_info(transforms[3], &output_stream_info); + + if (mode == MFTOPOLOGY_DXVA_FULL) + { + test_transform_set_expect_dxgi_device_manager(transforms[2], dxgi_manager); + test_transform_set_expect_dxgi_device_manager(transforms[3], dxgi_manager); + } + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ref = IMFTopology_GetNodeCount(full_topology, &count); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ok(count == 6, "got count %u.\n", count); + ref = IMFTopology_Release(full_topology); + ok(ref == 0, "Release returned %ld\n", ref); + + if (mode == MFTOPOLOGY_DXVA_FULL) + { + ret = test_transform_got_dxgi_device_manager(transforms[0]); + ok(!ret, "got dxgi device manager\n"); + ret = test_transform_got_dxgi_device_manager(transforms[1]); + ok(!ret, "got dxgi device manager\n"); + ret = test_transform_got_dxgi_device_manager(transforms[2]); + ok(!ret, "got dxgi device manager\n"); + ret = test_transform_got_dxgi_device_manager(transforms[3]); + ok(!ret, "got dxgi device manager\n"); + } + + /* copier is never needed in MFTOPOLOGY_DXVA_NONE mode */ + + output_stream_info.dwFlags = MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES; + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ref = IMFTopology_GetNodeCount(full_topology, &count); + ok(hr == S_OK, "got hr %#lx.\n", hr); + if (mode == MFTOPOLOGY_DXVA_NONE) + ok(count == 6, "got count %u.\n", count); + else + todo_wine ok(count == 7, "got count %u.\n", count); + ref = IMFTopology_Release(full_topology); + ok(ref == 0, "Release returned %ld\n", ref); + + if (mode == MFTOPOLOGY_DXVA_FULL) + { + ret = test_transform_got_dxgi_device_manager(transforms[0]); + ok(!ret, "got dxgi device manager\n"); + ret = test_transform_got_dxgi_device_manager(transforms[1]); + ok(!ret, "got dxgi device manager\n"); + ret = test_transform_got_dxgi_device_manager(transforms[2]); + ok(!ret, "got dxgi device manager\n"); + ret = test_transform_got_dxgi_device_manager(transforms[3]); + ok(!ret, "got dxgi device manager\n"); + } + + output_stream_info.dwFlags = 0; + + ref = IMFTopology_Release(topology); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopoLoader_Release(loader); + ok(ref == 0, "Release returned %ld\n", ref); + + IMFTransform_Release(transforms[0]); + IMFTransform_Release(transforms[1]); + IMFTransform_Release(transforms[2]); + IMFTransform_Release(transforms[3]); + + + /* D3D aware transforms connected together to downstream D3D-aware sink receive a device manager */ + + hr = MFCreateTopoLoader(&loader); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = MFCreateTopology(&topology); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_DXVA_MODE, mode); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + test_transform_create(1, &media_type, 1, &media_type, FALSE, &transforms[0]); + test_transform_create(1, &media_type, 1, &media_type, FALSE, &transforms[1]); + test_transform_create(1, &media_type, 1, &media_type, TRUE, &transforms[2]); + test_transform_create(1, &media_type, 1, &media_type, TRUE, &transforms[3]); + + test_topology_loader_d3d_init(topology, source, pd, sd, 4, transforms, &stream_sink.IMFStreamSink_iface); + + test_transform_set_output_stream_info(transforms[3], &output_stream_info); + + if (mode == MFTOPOLOGY_DXVA_FULL) + { + test_transform_set_expect_dxgi_device_manager(transforms[2], dxgi_manager); + test_transform_set_expect_dxgi_device_manager(transforms[3], dxgi_manager); + } + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ref = IMFTopology_GetNodeCount(full_topology, &count); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ok(count == 6, "got count %u.\n", count); + ref = IMFTopology_Release(full_topology); + ok(ref == 0, "Release returned %ld\n", ref); + + if (mode == MFTOPOLOGY_DXVA_FULL) + { + ret = test_transform_got_dxgi_device_manager(transforms[0]); + ok(!ret, "got dxgi device manager\n"); + ret = test_transform_got_dxgi_device_manager(transforms[1]); + ok(!ret, "got dxgi device manager\n"); + ret = test_transform_got_dxgi_device_manager(transforms[2]); + todo_wine ok(!!ret, "got dxgi device manager\n"); + ret = test_transform_got_dxgi_device_manager(transforms[3]); + todo_wine ok(!!ret, "got dxgi device manager\n"); + } + + ref = IMFTopology_Release(topology); + ok(ref == 0, "Release returned %ld\n", ref); + ref = IMFTopoLoader_Release(loader); + ok(ref == 0, "Release returned %ld\n", ref); + + IMFTransform_Release(transforms[0]); + IMFTransform_Release(transforms[1]); + IMFTransform_Release(transforms[2]); + IMFTransform_Release(transforms[3]); + + + IMFMediaSource_Release(source); + IMFPresentationDescriptor_Release(pd); + IMFStreamDescriptor_Release(sd); + + IMFAttributes_Release(stream_sink.attributes); + IMFMediaType_Release(media_type); + + hr = MFShutdown(); + ok(hr == S_OK, "Shutdown failure, hr %#lx.\n", hr); + + IMFDXGIDeviceManager_Release(dxgi_manager); + +skip_d3d11: + winetest_pop_context(); +} + START_TEST(topology) { init_functions(); @@ -3170,4 +3773,10 @@ START_TEST(topology) test_topology_loader(); test_topology_loader_evr(); test_topology_loader_d3d(); + test_topology_loader_d3d9(MFTOPOLOGY_DXVA_DEFAULT); + test_topology_loader_d3d9(MFTOPOLOGY_DXVA_NONE); + test_topology_loader_d3d9(MFTOPOLOGY_DXVA_FULL); + test_topology_loader_d3d11(MFTOPOLOGY_DXVA_DEFAULT); + test_topology_loader_d3d11(MFTOPOLOGY_DXVA_NONE); + test_topology_loader_d3d11(MFTOPOLOGY_DXVA_FULL); }
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=144852
Your paranoid android.
=== w11pro64_amd (64 bit report) ===
mf: mf.c:2725: Test failed: WaitForSingleObject returned 0x102
On Tue Apr 9 09:22:24 2024 +0000, Rémi Bernon wrote:
changed this line in version 6 of the diff
Changed to always return S_OK.
On Tue Apr 9 09:22:25 2024 +0000, Rémi Bernon wrote:
changed this line in version 6 of the diff
No indeed, it's a leftover from some local refactor.
Split the topology tests to a separate source.
This merge request was approved by Nikolay Sivov.