From 73fae7aa5b579ae82071509a182628bf6901b096 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Fri, 17 May 2019 15:35:23 +0300 Subject: [PATCH] mf: Slightly improve topoloader Load(). Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- dlls/mf/tests/Makefile.in | 4 +- dlls/mf/tests/mf.c | 269 ++++++++++++++++++++++++++++++++++++++ dlls/mf/tests/resource.rc | 22 ++++ dlls/mf/tests/test.wav | Bin 0 -> 4488 bytes dlls/mf/topology.c | 44 ++++++- include/mfidl.idl | 7 + 6 files changed, 344 insertions(+), 2 deletions(-) create mode 100644 dlls/mf/tests/resource.rc create mode 100644 dlls/mf/tests/test.wav diff --git a/dlls/mf/tests/Makefile.in b/dlls/mf/tests/Makefile.in index bdb493cc605..b26c8630063 100644 --- a/dlls/mf/tests/Makefile.in +++ b/dlls/mf/tests/Makefile.in @@ -1,5 +1,7 @@ TESTDLL = mf.dll -IMPORTS = mf mfplat mfuuid +IMPORTS = mf mfplat mfuuid ole32 C_SRCS = \ mf.c + +RC_SRCS = resource.rc diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 18aa10df96f..37bcb8d0292 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -49,6 +49,34 @@ static void _expect_ref(IUnknown* obj, ULONG expected_refcount, int line) expected_refcount); } +static WCHAR *load_resource(const WCHAR *name) +{ + static WCHAR pathW[MAX_PATH]; + DWORD written; + HANDLE file; + HRSRC res; + void *ptr; + + GetTempPathW(ARRAY_SIZE(pathW), pathW); + lstrcatW(pathW, name); + + file = CreateFileW(pathW, GENERIC_READ|GENERIC_WRITE, 0, + NULL, CREATE_ALWAYS, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %d\n", + wine_dbgstr_w(pathW), GetLastError()); + + res = FindResourceW(NULL, name, (LPCWSTR)RT_RCDATA); + ok(res != 0, "couldn't find resource\n"); + ptr = LockResource(LoadResource(GetModuleHandleA(NULL), res)); + WriteFile(file, ptr, SizeofResource(GetModuleHandleA(NULL), res), + &written, NULL); + ok(written == SizeofResource(GetModuleHandleA(NULL), res), + "couldn't write resource\n" ); + CloseHandle(file); + + return pathW; +} + static HRESULT WINAPI test_unk_QueryInterface(IUnknown *iface, REFIID riid, void **obj) { if (IsEqualIID(riid, &IID_IUnknown)) @@ -998,10 +1026,116 @@ static void test_media_session(void) ok(hr == S_OK, "Shutdown failure, hr %#x.\n", 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)) + { + *obj = iface; + IMFSampleGrabberSinkCallback_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_grabber_callback_AddRef(IMFSampleGrabberSinkCallback *iface) +{ + return 2; +} + +static ULONG WINAPI test_grabber_callback_Release(IMFSampleGrabberSinkCallback *iface) +{ + return 1; +} + +static HRESULT WINAPI test_grabber_callback_OnClockStart(IMFSampleGrabberSinkCallback *iface, MFTIME systime, + LONGLONG offset) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_grabber_callback_OnClockStop(IMFSampleGrabberSinkCallback *iface, MFTIME systime) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_grabber_callback_OnClockPause(IMFSampleGrabberSinkCallback *iface, MFTIME systime) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_grabber_callback_OnClockRestart(IMFSampleGrabberSinkCallback *iface, MFTIME systime) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_grabber_callback_OnClockSetRate(IMFSampleGrabberSinkCallback *iface, MFTIME systime, float rate) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_grabber_callback_OnSetPresentationClock(IMFSampleGrabberSinkCallback *iface, + IMFPresentationClock *clock) +{ + return E_NOTIMPL; +} + +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) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_grabber_callback_OnShutdown(IMFSampleGrabberSinkCallback *iface) +{ + return E_NOTIMPL; +} + +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 void test_topology_loader(void) { + IMFSampleGrabberSinkCallback test_grabber_callback = { &test_grabber_callback_vtbl }; + static const WCHAR wavW[] = {'a','u','d','i','o','/','w','a','v',0}; + static const WCHAR nameW[] = {'t','e','s','t','.','w','a','v',0}; + IMFTopology *topology, *topology2, *full_topology; + IMFTopologyNode *src_node, *sink_node; + IMFPresentationDescriptor *pd; + IMFSourceResolver *resolver; + IMFActivate *sink_activate; + unsigned int count, value; + IMFMediaType *media_type; + IMFStreamDescriptor *sd; + MF_OBJECT_TYPE obj_type; + IMFMediaSource *source; IMFTopoLoader *loader; + IMFByteStream *stream; + IMFAttributes *attr; + IMFMediaSink *sink; + WCHAR *filename; + BOOL selected; HRESULT hr; + GUID guid; + + hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); + ok(hr == S_OK, "Startup failure, hr %#x.\n", hr); hr = MFCreateTopoLoader(NULL); ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); @@ -1009,7 +1143,142 @@ static void test_topology_loader(void) hr = MFCreateTopoLoader(&loader); ok(hr == S_OK, "Failed to create topology loader, hr %#x.\n", hr); + hr = MFCreateTopology(&topology); + ok(hr == S_OK, "Failed to create topology, hr %#x.\n", hr); + + /* Empty topology */ + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); +todo_wine + ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#x.\n", hr); + + hr = MFCreateSourceResolver(&resolver); + ok(hr == S_OK, "Failed to create source resolver, hr %#x.\n", hr); + + filename = load_resource(nameW); + + hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, filename, &stream); + ok(hr == S_OK, "Failed to create file stream, hr %#x.\n", hr); + + IMFByteStream_QueryInterface(stream, &IID_IMFAttributes, (void **)&attr); + IMFAttributes_SetString(attr, &MF_BYTESTREAM_CONTENT_TYPE, wavW); + IMFAttributes_Release(attr); + + hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, NULL, MF_RESOLUTION_MEDIASOURCE, NULL, + &obj_type, (IUnknown **)&source); + ok(hr == S_OK || broken(FAILED(hr)) /* Vista */, "Failed to create source, hr %#x.\n", hr); + if (FAILED(hr)) + return; + + hr = IMFMediaSource_CreatePresentationDescriptor(source, &pd); + ok(hr == S_OK, "Failed to create descriptor, hr %#x.\n", hr); + + hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(pd, 0, &selected, &sd); + ok(hr == S_OK, "Failed to get stream descriptor, hr %#x.\n", hr); + + /* Add source node. */ + hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &src_node); + ok(hr == S_OK, "Failed to create topology node, hr %#x.\n", hr); + + hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_SOURCE, (IUnknown *)source); + ok(hr == S_OK, "Failed to set node source, hr %#x.\n", hr); + + hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_PRESENTATION_DESCRIPTOR, (IUnknown *)pd); + ok(hr == S_OK, "Failed to set node pd, hr %#x.\n", hr); + + hr = IMFTopologyNode_SetUnknown(src_node, &MF_TOPONODE_STREAM_DESCRIPTOR, (IUnknown *)sd); + ok(hr == S_OK, "Failed to set node sd, hr %#x.\n", hr); + + hr = IMFTopology_AddNode(topology, src_node); + ok(hr == S_OK, "Failed to add a node, hr %#x.\n", hr); + + /* Source node only. */ + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); +todo_wine + ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#x.\n", hr); + + /* Add grabber sink. */ + hr = MFCreateMediaType(&media_type); + ok(hr == S_OK, "Failed to create media type, hr %#x.\n", hr); + + hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM); + ok(hr == S_OK, "Failed to set attribute, hr %#x.\n", hr); + + hr = MFCreateSampleGrabberSinkActivate(media_type, &test_grabber_callback, &sink_activate); + ok(hr == S_OK, "Failed to create grabber sink, hr %#x.\n", hr); + + IMFMediaType_Release(media_type); + + hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &sink_node); + ok(hr == S_OK, "Failed to create output node, hr %#x.\n", hr); + + hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)sink_activate); + ok(hr == S_OK, "Failed to set object, hr %#x.\n", hr); + hr = IMFTopology_AddNode(topology, sink_node); + ok(hr == S_OK, "Failed to add sink node, hr %#x.\n", hr); + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); +todo_wine + ok(hr == MF_E_TOPO_UNSUPPORTED, "Unexpected hr %#x.\n", hr); + + hr = IMFTopologyNode_ConnectOutput(src_node, 0, sink_node, 0); + ok(hr == S_OK, "Failed to connect nodes, hr %#x.\n", hr); + + /* Sink was not resolved. */ + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); + ok(hr == MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED, "Unexpected hr %#x.\n", hr); + + hr = IMFActivate_ActivateObject(sink_activate, &IID_IMFMediaSink, (void **)&sink); +todo_wine + ok(hr == S_OK, "Failed to activate, hr %#x.\n", hr); + + hr = IMFTopologyNode_SetObject(sink_node, (IUnknown *)sink); + ok(hr == S_OK, "Failed to set object, hr %#x.\n", hr); + + hr = IMFTopology_GetCount(topology, &count); + ok(hr == S_OK, "Failed to get attribute count, hr %#x.\n", hr); + ok(count == 0, "Unexpected count %u.\n", count); + + hr = IMFTopoLoader_Load(loader, topology, &full_topology, NULL); +todo_wine + ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr); + ok(full_topology != topology, "Unexpected instance.\n"); + + hr = IMFTopology_GetCount(topology, &count); + ok(hr == S_OK, "Failed to get attribute count, hr %#x.\n", hr); + ok(count == 0, "Unexpected count %u.\n", count); + + hr = IMFTopology_GetCount(full_topology, &count); + ok(hr == S_OK, "Failed to get attribute count, hr %#x.\n", hr); +todo_wine + ok(count == 1, "Unexpected count %u.\n", count); + + hr = IMFTopology_GetItemByIndex(full_topology, 0, &guid, NULL); +todo_wine { + ok(hr == S_OK, "Failed to get attribute key, hr %#x.\n", hr); + ok(IsEqualGUID(&guid, &MF_TOPOLOGY_RESOLUTION_STATUS), "Unexpected key %s.\n", wine_dbgstr_guid(&guid)); +} + hr = IMFTopology_GetUINT32(full_topology, &MF_TOPOLOGY_RESOLUTION_STATUS, &value); +todo_wine { + ok(hr == S_OK, "Failed to get attribute, hr %#x.\n", hr); + ok(value == MF_TOPOLOGY_RESOLUTION_SUCCEEDED, "Unexpected value %#x.\n", value); +} + hr = IMFTopoLoader_Load(loader, full_topology, &topology2, NULL); +todo_wine + ok(hr == S_OK, "Failed to resolve topology, hr %#x.\n", hr); + ok(full_topology != topology2, "Unexpected instance.\n"); + + IMFTopology_Release(topology2); + IMFTopology_Release(full_topology); + + IMFMediaSource_Release(source); + IMFSourceResolver_Release(resolver); + IMFByteStream_Release(stream); IMFTopoLoader_Release(loader); + + hr = MFShutdown(); + ok(hr == S_OK, "Shutdown failure, hr %#x.\n", hr); } static HRESULT WINAPI testshutdown_QueryInterface(IMFShutdown *iface, REFIID riid, void **obj) diff --git a/dlls/mf/tests/resource.rc b/dlls/mf/tests/resource.rc new file mode 100644 index 00000000000..f54212a8c8f --- /dev/null +++ b/dlls/mf/tests/resource.rc @@ -0,0 +1,22 @@ +/* + * Copyright 2019 Nikolay Sivov for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "windef.h" + +/* @makedep: test.wav */ +test.wav RCDATA test.wav diff --git a/dlls/mf/tests/test.wav b/dlls/mf/tests/test.wav new file mode 100644 index 0000000000000000000000000000000000000000..51d23936196da1a0452c78713c8af819259d225e GIT binary patch literal 4488 zcmWIYbaQJEWMBw)40BD(Em06)U|?VbLYFlRV9dzC!QkT=93ll2_w;k~_Y8Im;RCXL z63fy|&GbwR^b8FQ8B!8U60LxyG&DA~w6?W(c6Imk^!D}jLqT6(Z%=nuXGeQmYjaa$ zeO*m;Rb_cuX-RQWQDFfL6c!d0mz0*3S5#Kl)YdmNHMg|2cYsVnGN`|=7h+OdYfE!u zLtSl6Rb>Ulq(Zn!AcH_ARa910*VfgKI%zbNM$^)0jvFnPMvKbP3T3p~9c`R|TVA8> dC3y36v{gCU_8#q_jCPtvyOyIJ@PQhp007ieqznK6 literal 0 HcmV?d00001 diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index 1d72d8bb683..81fd17589db 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -791,6 +791,13 @@ static const IMFTopologyVtbl topologyvtbl = topology_GetOutputNodeCollection, }; +static struct topology *unsafe_impl_from_IMFTopology(IMFTopology *iface) +{ + if (!iface || iface->lpVtbl != &topologyvtbl) + return NULL; + return impl_from_IMFTopology(iface); +} + static TOPOID topology_generate_id(void) { TOPOID old; @@ -1720,9 +1727,44 @@ static ULONG WINAPI topology_loader_Release(IMFTopoLoader *iface) static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *input_topology, IMFTopology **output_topology, IMFTopology *current_topology) { + struct topology *topology = unsafe_impl_from_IMFTopology(input_topology); + IMFMediaSink *sink; + HRESULT hr; + size_t i; + FIXME("%p, %p, %p, %p.\n", iface, input_topology, output_topology, current_topology); - return E_NOTIMPL; + if (current_topology) + FIXME("Current topology instance is ignored.\n"); + + for (i = 0; i < topology->nodes.count; ++i) + { + struct topology_node *node = topology->nodes.nodes[i]; + + switch (node->node_type) + { + case MF_TOPOLOGY_OUTPUT_NODE: + if (node->object) + { + /* Sinks must be bound beforehand. */ + if (FAILED(IUnknown_QueryInterface(node->object, &IID_IMFMediaSink, (void **)&sink))) + return MF_E_TOPO_SINK_ACTIVATES_UNSUPPORTED; + IMFMediaSink_Release(sink); + } + break; + case MF_TOPOLOGY_SOURCESTREAM_NODE: + if (FAILED(hr = IMFAttributes_GetItem(node->attributes, &MF_TOPONODE_STREAM_DESCRIPTOR, NULL))) + return hr; + break; + default: + ; + } + } + + if (FAILED(hr = MFCreateTopology(output_topology))) + return hr; + + return IMFTopology_CloneFrom(*output_topology, input_topology); } static const IMFTopoLoaderVtbl topologyloadervtbl = diff --git a/include/mfidl.idl b/include/mfidl.idl index fac3bcf5b66..c024e67378b 100644 --- a/include/mfidl.idl +++ b/include/mfidl.idl @@ -76,6 +76,13 @@ typedef enum MFSESSION_GETFULLTOPOLOGY_FLAGS MFSESSION_GETFULLTOPOLOGY_CURRENT = 0x00000001, } MFSESSION_GETFULLTOPOLOGY_FLAGS; +typedef enum _MF_TOPOLOGY_RESOLUTION_STATUS_FLAGS +{ + MF_TOPOLOGY_RESOLUTION_SUCCEEDED = 0x00000000, + MF_OPTIONAL_NODE_REJECTED_MEDIA_TYPE = 0x00000001, + MF_OPTIONAL_NODE_REJECTED_PROTECTED_PROCESS = 0x00000002, +} MF_TOPOLOGY_RESOLUTION_STATUS_FLAGS; + [ object, uuid(2eb1e945-18b8-4139-9b1a-d5d584818530),