[PATCH 2/2] mf: Slightly improve topoloader Load().

Nikolay Sivov nsivov at codeweavers.com
Fri May 17 07:35:23 CDT 2019


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 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 bdb493cc60..b26c863006 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 18aa10df96..37bcb8d029 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 0000000000..f54212a8c8
--- /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 at PQhp007ieqznK6

literal 0
HcmV?d00001

diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c
index 1d72d8bb68..81fd17589d 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 fac3bcf5b6..c024e67378 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),
-- 
2.20.1




More information about the wine-devel mailing list