qasf/dmowrapper: Implement source connection.

Signed-off-by: Zebediah Figura <zfigura@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2020-02-18 23:19:09 -06:00 committed by Alexandre Julliard
parent 6fa6ef90a4
commit c1b7a334f5
4 changed files with 285 additions and 6 deletions

View File

@ -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; 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 = static const struct strmbase_source_ops source_ops =
{ {
.base.pin_query_accept = dmo_wrapper_source_query_accept, .base.pin_query_accept = dmo_wrapper_source_query_accept,
.base.pin_get_media_type = dmo_wrapper_source_get_media_type, .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) static inline struct dmo_wrapper *impl_from_IDMOWrapperFilter(IDMOWrapperFilter *iface)

View File

@ -61,10 +61,13 @@ static const IMediaObjectVtbl dmo_vtbl;
static IMediaObject testdmo = {&dmo_vtbl}; static IMediaObject testdmo = {&dmo_vtbl};
static IUnknown *testdmo_outer_unk; static IUnknown *testdmo_outer_unk;
static LONG testdmo_refcount = 1; static LONG testdmo_refcount = 1;
static AM_MEDIA_TYPE testdmo_input_mt; static AM_MEDIA_TYPE testdmo_input_mt, testdmo_output_mt;
static BOOL testdmo_input_mt_set; static BOOL testdmo_input_mt_set, testdmo_output_mt_set;
static HRESULT testdmo_GetInputSizeInfo_hr = E_NOTIMPL; 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) 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); strmbase_dump_media_type((AM_MEDIA_TYPE *)type);
if (flags & DMO_SET_TYPEF_TEST_ONLY) if (flags & DMO_SET_TYPEF_TEST_ONLY)
return type->lSampleSize == 321 ? S_OK : S_FALSE; 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; 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) static HRESULT WINAPI dmo_GetOutputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, DWORD *alignment)
{ {
ok(0, "Unexpected call.\n"); if (winetest_debug > 1) trace("GetOutputSizeInfo(%u)\n", index);
return E_NOTIMPL; *size = testdmo_output_size;
*alignment = testdmo_output_alignment;
return testdmo_GetOutputSizeInfo_hr;
} }
static HRESULT WINAPI dmo_GetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME *latency) 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); 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) static void test_connect_pin(void)
{ {
AM_MEDIA_TYPE req_mt = AM_MEDIA_TYPE req_mt =
@ -1146,20 +1223,23 @@ static void test_connect_pin(void)
.formattype = FORMAT_None, .formattype = FORMAT_None,
}; };
IBaseFilter *filter = create_dmo_wrapper(); IBaseFilter *filter = create_dmo_wrapper();
struct testfilter testsource; struct testfilter testsource, testsink;
IPin *sink, *source, *peer;
IMemInputPin *meminput; IMemInputPin *meminput;
IFilterGraph2 *graph; IFilterGraph2 *graph;
IPin *sink, *peer;
AM_MEDIA_TYPE mt; AM_MEDIA_TYPE mt;
HRESULT hr; HRESULT hr;
ULONG ref; ULONG ref;
testfilter_init(&testsource); testfilter_init(&testsource);
testfilter_init(&testsink);
CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
&IID_IFilterGraph2, (void **)&graph); &IID_IFilterGraph2, (void **)&graph);
IFilterGraph2_AddFilter(graph, &testsource.filter.IBaseFilter_iface, L"source"); 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"); IFilterGraph2_AddFilter(graph, filter, L"DMO wrapper");
IBaseFilter_FindPin(filter, L"in0", &sink); IBaseFilter_FindPin(filter, L"in0", &sink);
IBaseFilter_FindPin(filter, L"out0", &source);
IPin_QueryInterface(sink, &IID_IMemInputPin, (void **)&meminput); IPin_QueryInterface(sink, &IID_IMemInputPin, (void **)&meminput);
/* Test sink connection. */ /* Test sink connection. */
@ -1194,6 +1274,149 @@ static void test_connect_pin(void)
test_sink_allocator(meminput); 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); hr = IFilterGraph2_Disconnect(graph, sink);
ok(hr == S_OK, "Got hr %#x.\n", hr); ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IFilterGraph2_Disconnect(graph, sink); 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"); ok(!testdmo_input_mt_set, "Input type should not be set.\n");
test_source_allocator(graph, source, &testsink);
IPin_Release(sink); IPin_Release(sink);
IPin_Release(source);
IMemInputPin_Release(meminput); IMemInputPin_Release(meminput);
ref = IFilterGraph2_Release(graph); ref = IFilterGraph2_Release(graph);
ok(!ref, "Got outstanding refcount %d.\n", ref); 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); ok(!ref, "Got outstanding refcount %d.\n", ref);
ref = IBaseFilter_Release(&testsource.filter.IBaseFilter_iface); ref = IBaseFilter_Release(&testsource.filter.IBaseFilter_iface);
ok(!ref, "Got outstanding refcount %d.\n", ref); 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) START_TEST(dmowrapper)

View File

@ -552,6 +552,9 @@ static HRESULT WINAPI source_Disconnect(IPin *iface)
return VFW_E_NOT_STOPPED; return VFW_E_NOT_STOPPED;
} }
if (This->pFuncsTable->source_disconnect)
This->pFuncsTable->source_disconnect(This);
if (This->pMemInputPin) if (This->pMemInputPin)
{ {
IMemInputPin_Release(This->pMemInputPin); IMemInputPin_Release(This->pMemInputPin);

View File

@ -74,6 +74,8 @@ struct strmbase_source_ops
BaseOutputPin_DecideBufferSize pfnDecideBufferSize; BaseOutputPin_DecideBufferSize pfnDecideBufferSize;
/* Required for BaseOutputPinImpl_AttemptConnection */ /* Required for BaseOutputPinImpl_AttemptConnection */
BaseOutputPin_DecideAllocator pfnDecideAllocator; BaseOutputPin_DecideAllocator pfnDecideAllocator;
void (*source_disconnect)(struct strmbase_source *pin);
}; };
struct strmbase_sink struct strmbase_sink