[PATCH v2 3/5] qasf/dmowrapper: Implement source connection.

Zebediah Figura z.figura12 at gmail.com
Tue Feb 18 23:19:09 CST 2020


Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
 dlls/qasf/dmowrapper.c       |  46 +++++++
 dlls/qasf/tests/dmowrapper.c | 240 ++++++++++++++++++++++++++++++++++-
 dlls/strmbase/pin.c          |   3 +
 include/wine/strmbase.h      |   2 +
 4 files changed, 285 insertions(+), 6 deletions(-)

diff --git a/dlls/qasf/dmowrapper.c b/dlls/qasf/dmowrapper.c
index 28d8e82175c..7a18d0ba079 100644
--- a/dlls/qasf/dmowrapper.c
+++ b/dlls/qasf/dmowrapper.c
@@ -166,10 +166,56 @@ static HRESULT dmo_wrapper_source_get_media_type(struct strmbase_pin *iface, uns
     return hr == S_OK ? S_OK : VFW_S_NO_MORE_ITEMS;
 }
 
+static HRESULT WINAPI dmo_wrapper_source_DecideBufferSize(struct strmbase_source *iface,
+        IMemAllocator *allocator, ALLOCATOR_PROPERTIES *props)
+{
+    struct dmo_wrapper *filter = impl_from_strmbase_filter(iface->pin.filter);
+    DWORD index = impl_source_from_strmbase_pin(&iface->pin) - filter->sources;
+    ALLOCATOR_PROPERTIES ret_props;
+    DWORD size = 0, alignment = 0;
+    IMediaObject *dmo;
+    HRESULT hr;
+
+    IUnknown_QueryInterface(filter->dmo, &IID_IMediaObject, (void **)&dmo);
+
+    if (SUCCEEDED(hr = IMediaObject_SetOutputType(dmo, index,
+            (const DMO_MEDIA_TYPE *)&iface->pin.mt, 0)))
+        hr = IMediaObject_GetOutputSizeInfo(dmo, index, &size, &alignment);
+
+    if (SUCCEEDED(hr))
+    {
+        props->cBuffers = max(props->cBuffers, 1);
+        props->cbBuffer = max(max(props->cbBuffer, size), 16384);
+        props->cbAlign = max(props->cbAlign, alignment);
+        hr = IMemAllocator_SetProperties(allocator, props, &ret_props);
+    }
+
+    IMediaObject_Release(dmo);
+
+    return hr;
+}
+
+static void dmo_wrapper_source_disconnect(struct strmbase_source *iface)
+{
+    struct dmo_wrapper *filter = impl_from_strmbase_filter(iface->pin.filter);
+    IMediaObject *dmo;
+
+    IUnknown_QueryInterface(filter->dmo, &IID_IMediaObject, (void **)&dmo);
+
+    IMediaObject_SetOutputType(dmo, impl_source_from_strmbase_pin(&iface->pin) - filter->sources,
+            NULL, DMO_SET_TYPEF_CLEAR);
+
+    IMediaObject_Release(dmo);
+}
+
 static const struct strmbase_source_ops source_ops =
 {
     .base.pin_query_accept = dmo_wrapper_source_query_accept,
     .base.pin_get_media_type = dmo_wrapper_source_get_media_type,
+    .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
+    .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator,
+    .pfnDecideBufferSize = dmo_wrapper_source_DecideBufferSize,
+    .source_disconnect = dmo_wrapper_source_disconnect,
 };
 
 static inline struct dmo_wrapper *impl_from_IDMOWrapperFilter(IDMOWrapperFilter *iface)
diff --git a/dlls/qasf/tests/dmowrapper.c b/dlls/qasf/tests/dmowrapper.c
index 641fa689042..dbb9d9d17f3 100644
--- a/dlls/qasf/tests/dmowrapper.c
+++ b/dlls/qasf/tests/dmowrapper.c
@@ -61,10 +61,13 @@ static const IMediaObjectVtbl dmo_vtbl;
 static IMediaObject testdmo = {&dmo_vtbl};
 static IUnknown *testdmo_outer_unk;
 static LONG testdmo_refcount = 1;
-static AM_MEDIA_TYPE testdmo_input_mt;
-static BOOL testdmo_input_mt_set;
+static AM_MEDIA_TYPE testdmo_input_mt, testdmo_output_mt;
+static BOOL testdmo_input_mt_set, testdmo_output_mt_set;
 
 static HRESULT testdmo_GetInputSizeInfo_hr = E_NOTIMPL;
+static HRESULT testdmo_GetOutputSizeInfo_hr = S_OK;
+static DWORD testdmo_output_size = 123;
+static DWORD testdmo_output_alignment = 1;
 
 static HRESULT WINAPI dmo_inner_QueryInterface(IUnknown *iface, REFIID iid, void **out)
 {
@@ -183,6 +186,13 @@ static HRESULT WINAPI dmo_SetOutputType(IMediaObject *iface, DWORD index, const
     strmbase_dump_media_type((AM_MEDIA_TYPE *)type);
     if (flags & DMO_SET_TYPEF_TEST_ONLY)
         return type->lSampleSize == 321 ? S_OK : S_FALSE;
+    if (flags & DMO_SET_TYPEF_CLEAR)
+    {
+        testdmo_output_mt_set = FALSE;
+        return S_OK;
+    }
+    MoCopyMediaType((DMO_MEDIA_TYPE *)&testdmo_output_mt, type);
+    testdmo_output_mt_set = TRUE;
     return S_OK;
 }
 
@@ -210,8 +220,10 @@ static HRESULT WINAPI dmo_GetInputSizeInfo(IMediaObject *iface, DWORD index,
 
 static HRESULT WINAPI dmo_GetOutputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, DWORD *alignment)
 {
-    ok(0, "Unexpected call.\n");
-    return E_NOTIMPL;
+    if (winetest_debug > 1) trace("GetOutputSizeInfo(%u)\n", index);
+    *size = testdmo_output_size;
+    *alignment = testdmo_output_alignment;
+    return testdmo_GetOutputSizeInfo_hr;
 }
 
 static HRESULT WINAPI dmo_GetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME *latency)
@@ -1137,6 +1149,71 @@ static void test_sink_allocator(IMemInputPin *input)
     IMemAllocator_Release(ret_allocator);
 }
 
+static void test_source_allocator(IFilterGraph2 *graph, IPin *source, struct testfilter *testsink)
+{
+    ALLOCATOR_PROPERTIES props, req_props = {2, 30000, 32, 0};
+    IMemAllocator *allocator;
+    HRESULT hr;
+
+    hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &mt2);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    ok(!!testsink->sink.pAllocator, "Expected an allocator.\n");
+    hr = IMemAllocator_GetProperties(testsink->sink.pAllocator, &props);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(props.cBuffers == 1, "Got %d buffers.\n", props.cBuffers);
+    ok(props.cbBuffer == 16384, "Got size %d.\n", props.cbBuffer);
+    ok(props.cbAlign == 1, "Got alignment %d.\n", props.cbAlign);
+    ok(!props.cbPrefix, "Got prefix %d.\n", props.cbPrefix);
+
+    IFilterGraph2_Disconnect(graph, source);
+    IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface);
+
+    testdmo_output_alignment = 16;
+    testdmo_output_size = 20000;
+
+    hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &mt2);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    ok(!!testsink->sink.pAllocator, "Expected an allocator.\n");
+    hr = IMemAllocator_GetProperties(testsink->sink.pAllocator, &props);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(props.cBuffers == 1, "Got %d buffers.\n", props.cBuffers);
+    ok(props.cbBuffer == 20000, "Got size %d.\n", props.cbBuffer);
+    ok(props.cbAlign == 16, "Got alignment %d.\n", props.cbAlign);
+    ok(!props.cbPrefix, "Got prefix %d.\n", props.cbPrefix);
+
+    IFilterGraph2_Disconnect(graph, source);
+    IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface);
+
+    testdmo_GetOutputSizeInfo_hr = E_NOTIMPL;
+    hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &mt2);
+    ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr);
+    testdmo_GetOutputSizeInfo_hr = S_OK;
+
+    CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
+            &IID_IMemAllocator, (void **)&allocator);
+    testsink->sink.pAllocator = allocator;
+
+    hr = IMemAllocator_SetProperties(allocator, &req_props, &props);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    hr = IFilterGraph2_ConnectDirect(graph, source, &testsink->sink.pin.IPin_iface, &mt2);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    ok(testsink->sink.pAllocator == allocator, "Expected an allocator.\n");
+    hr = IMemAllocator_GetProperties(testsink->sink.pAllocator, &props);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(props.cBuffers == 1, "Got %d buffers.\n", props.cBuffers);
+    ok(props.cbBuffer == 20000, "Got size %d.\n", props.cbBuffer);
+    ok(props.cbAlign == 16, "Got alignment %d.\n", props.cbAlign);
+    ok(!props.cbPrefix, "Got prefix %d.\n", props.cbPrefix);
+
+    IFilterGraph2_Disconnect(graph, source);
+    IFilterGraph2_Disconnect(graph, &testsink->sink.pin.IPin_iface);
+
+}
+
 static void test_connect_pin(void)
 {
     AM_MEDIA_TYPE req_mt =
@@ -1146,20 +1223,23 @@ static void test_connect_pin(void)
         .formattype = FORMAT_None,
     };
     IBaseFilter *filter = create_dmo_wrapper();
-    struct testfilter testsource;
+    struct testfilter testsource, testsink;
+    IPin *sink, *source, *peer;
     IMemInputPin *meminput;
     IFilterGraph2 *graph;
-    IPin *sink, *peer;
     AM_MEDIA_TYPE mt;
     HRESULT hr;
     ULONG ref;
 
     testfilter_init(&testsource);
+    testfilter_init(&testsink);
     CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
             &IID_IFilterGraph2, (void **)&graph);
     IFilterGraph2_AddFilter(graph, &testsource.filter.IBaseFilter_iface, L"source");
+    IFilterGraph2_AddFilter(graph, &testsink.filter.IBaseFilter_iface, L"sink");
     IFilterGraph2_AddFilter(graph, filter, L"DMO wrapper");
     IBaseFilter_FindPin(filter, L"in0", &sink);
+    IBaseFilter_FindPin(filter, L"out0", &source);
     IPin_QueryInterface(sink, &IID_IMemInputPin, (void **)&meminput);
 
     /* Test sink connection. */
@@ -1194,6 +1274,149 @@ static void test_connect_pin(void)
 
     test_sink_allocator(meminput);
 
+    /* Test source connection. */
+    peer = (IPin *)0xdeadbeef;
+    hr = IPin_ConnectedTo(source, &peer);
+    ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
+    ok(!peer, "Got peer %p.\n", peer);
+
+    hr = IPin_ConnectionMediaType(source, &mt);
+    ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
+
+    ok(!testdmo_output_mt_set, "Output type should not be set.\n");
+
+    /* Exact connection. */
+
+    req_mt = mt2;
+    hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+    hr = IPin_ConnectedTo(source, &peer);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(peer == &testsink.sink.pin.IPin_iface, "Got peer %p.\n", peer);
+    IPin_Release(peer);
+
+    hr = IPin_ConnectionMediaType(source, &mt);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(compare_media_types(&mt, &req_mt), "Media types didn't match.\n");
+
+    ok(testdmo_output_mt_set, "Ouput type should be set.\n");
+    ok(compare_media_types(&testdmo_output_mt, &req_mt), "Media types didn't match.\n");
+
+    hr = IFilterGraph2_Disconnect(graph, source);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    hr = IFilterGraph2_Disconnect(graph, source);
+    ok(hr == S_FALSE, "Got hr %#x.\n", hr);
+    ok(testsink.sink.pin.peer == source, "Got peer %p.\n", testsink.sink.pin.peer);
+    IFilterGraph2_Disconnect(graph, &testsink.sink.pin.IPin_iface);
+
+    peer = (IPin *)0xdeadbeef;
+    hr = IPin_ConnectedTo(source, &peer);
+    ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
+    ok(!peer, "Got peer %p.\n", peer);
+
+    hr = IPin_ConnectionMediaType(source, &mt);
+    ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#x.\n", hr);
+
+    ok(!testdmo_output_mt_set, "Output type should not be set.\n");
+
+    req_mt.lSampleSize = 0;
+    hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt);
+    ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr);
+
+    /* Connection with wildcards. */
+
+    hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, NULL);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(compare_media_types(&testsink.sink.pin.mt, &mt2), "Media types didn't match.\n");
+    ok(testdmo_output_mt_set, "Ouput type should be set.\n");
+    ok(compare_media_types(&testdmo_output_mt, &mt2), "Media types didn't match.\n");
+    IFilterGraph2_Disconnect(graph, source);
+    IFilterGraph2_Disconnect(graph, &testsink.sink.pin.IPin_iface);
+
+    req_mt.majortype = GUID_NULL;
+    hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(compare_media_types(&testsink.sink.pin.mt, &mt2), "Media types didn't match.\n");
+    IFilterGraph2_Disconnect(graph, source);
+    IFilterGraph2_Disconnect(graph, &testsink.sink.pin.IPin_iface);
+
+    req_mt.subtype = MEDIASUBTYPE_RGB32;
+    hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt);
+    ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr);
+
+    req_mt.subtype = GUID_NULL;
+    hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(compare_media_types(&testsink.sink.pin.mt, &mt2), "Media types didn't match.\n");
+    IFilterGraph2_Disconnect(graph, source);
+    IFilterGraph2_Disconnect(graph, &testsink.sink.pin.IPin_iface);
+
+    req_mt.formattype = FORMAT_WaveFormatEx;
+    hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt);
+    ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr);
+
+    req_mt = mt2;
+    req_mt.formattype = GUID_NULL;
+    hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(compare_media_types(&testsink.sink.pin.mt, &mt2), "Media types didn't match.\n");
+    IFilterGraph2_Disconnect(graph, source);
+    IFilterGraph2_Disconnect(graph, &testsink.sink.pin.IPin_iface);
+
+    req_mt.subtype = MEDIASUBTYPE_RGB32;
+    hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt);
+    ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr);
+
+    req_mt.subtype = GUID_NULL;
+    hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(compare_media_types(&testsink.sink.pin.mt, &mt2), "Media types didn't match.\n");
+    IFilterGraph2_Disconnect(graph, source);
+    IFilterGraph2_Disconnect(graph, &testsink.sink.pin.IPin_iface);
+
+    req_mt.majortype = MEDIATYPE_Audio;
+    hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt);
+    ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr);
+
+    mt = req_mt;
+    testsink.sink_mt = &mt;
+    hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, NULL);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(compare_media_types(&testsink.sink.pin.mt, &mt), "Media types didn't match.\n");
+    IFilterGraph2_Disconnect(graph, source);
+    IFilterGraph2_Disconnect(graph, &testsink.sink.pin.IPin_iface);
+
+    mt.lSampleSize = 1;
+    hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt);
+    ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr);
+    mt.lSampleSize = 321;
+
+    mt.majortype = mt.subtype = mt.formattype = GUID_NULL;
+    req_mt = mt;
+    hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt);
+    ok(hr == S_OK, "Got hr %#x.\n", hr);
+    ok(compare_media_types(&testsink.sink.pin.mt, &mt), "Media types didn't match.\n");
+    IFilterGraph2_Disconnect(graph, source);
+    IFilterGraph2_Disconnect(graph, &testsink.sink.pin.IPin_iface);
+
+    req_mt.majortype = mt2.majortype;
+    hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt);
+    ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr);
+    req_mt.majortype = GUID_NULL;
+
+    req_mt.subtype = mt2.subtype;
+    hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt);
+    ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr);
+    req_mt.subtype = GUID_NULL;
+
+    req_mt.formattype = mt2.formattype;
+    hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt);
+    ok(hr == VFW_E_NO_ACCEPTABLE_TYPES, "Got hr %#x.\n", hr);
+    req_mt.formattype = GUID_NULL;
+
+    testsink.sink_mt = NULL;
+
     hr = IFilterGraph2_Disconnect(graph, sink);
     ok(hr == S_OK, "Got hr %#x.\n", hr);
     hr = IFilterGraph2_Disconnect(graph, sink);
@@ -1211,7 +1434,10 @@ static void test_connect_pin(void)
 
     ok(!testdmo_input_mt_set, "Input type should not be set.\n");
 
+    test_source_allocator(graph, source, &testsink);
+
     IPin_Release(sink);
+    IPin_Release(source);
     IMemInputPin_Release(meminput);
     ref = IFilterGraph2_Release(graph);
     ok(!ref, "Got outstanding refcount %d.\n", ref);
@@ -1219,6 +1445,8 @@ static void test_connect_pin(void)
     ok(!ref, "Got outstanding refcount %d.\n", ref);
     ref = IBaseFilter_Release(&testsource.filter.IBaseFilter_iface);
     ok(!ref, "Got outstanding refcount %d.\n", ref);
+    ref = IBaseFilter_Release(&testsink.filter.IBaseFilter_iface);
+    ok(!ref, "Got outstanding refcount %d.\n", ref);
 }
 
 START_TEST(dmowrapper)
diff --git a/dlls/strmbase/pin.c b/dlls/strmbase/pin.c
index 8a565b536e2..4676c9d82b0 100644
--- a/dlls/strmbase/pin.c
+++ b/dlls/strmbase/pin.c
@@ -555,6 +555,9 @@ static HRESULT WINAPI source_Disconnect(IPin *iface)
             return VFW_E_NOT_STOPPED;
         }
 
+        if (This->pFuncsTable->source_disconnect)
+            This->pFuncsTable->source_disconnect(This);
+
         if (This->pMemInputPin)
         {
             IMemInputPin_Release(This->pMemInputPin);
diff --git a/include/wine/strmbase.h b/include/wine/strmbase.h
index 5151e68644b..0e0f73afa3c 100644
--- a/include/wine/strmbase.h
+++ b/include/wine/strmbase.h
@@ -74,6 +74,8 @@ struct strmbase_source_ops
     BaseOutputPin_DecideBufferSize pfnDecideBufferSize;
     /* Required for BaseOutputPinImpl_AttemptConnection */
     BaseOutputPin_DecideAllocator pfnDecideAllocator;
+
+    void (*source_disconnect)(struct strmbase_source *pin);
 };
 
 struct strmbase_sink
-- 
2.25.0




More information about the wine-devel mailing list