From 6dce36357aa26d7d012776d52646c96b5ac9314c Mon Sep 17 00:00:00 2001 From: Piotr Caban Date: Tue, 26 Nov 2013 14:36:19 +0100 Subject: [PATCH] qcap: Fix Avi Mux output pin Connect implementation. --- dlls/qcap/avimux.c | 75 ++++++++++++++---- dlls/qcap/tests/qcap.c | 167 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 218 insertions(+), 24 deletions(-) diff --git a/dlls/qcap/avimux.c b/dlls/qcap/avimux.c index 37849f67664..cfd0fd6ab6d 100644 --- a/dlls/qcap/avimux.c +++ b/dlls/qcap/avimux.c @@ -141,10 +141,6 @@ static ULONG WINAPI AviMux_Release(IBaseFilter *iface) if(!ref) { int i; - if(This->out->pin.pin.pConnectedTo) { - IPin_Disconnect(This->out->pin.pin.pConnectedTo); - IPin_Disconnect(&This->out->pin.pin.IPin_iface); - } BaseOutputPinImpl_Release(&This->out->pin.pin.IPin_iface); for(i=0; iinput_pin_no; i++) @@ -661,8 +657,16 @@ static const ISpecifyPropertyPagesVtbl SpecifyPropertyPagesVtbl = { static HRESULT WINAPI AviMuxOut_AttemptConnection(BasePin *base, IPin *pReceivePin, const AM_MEDIA_TYPE *pmt) { + PIN_DIRECTION dir; + HRESULT hr; + TRACE("(%p)->(%p AM_MEDIA_TYPE(%p))\n", base, pReceivePin, pmt); dump_AM_MEDIA_TYPE(pmt); + + hr = IPin_QueryDirection(pReceivePin, &dir); + if(hr==S_OK && dir!=PINDIR_INPUT) + return VFW_E_INVALID_DIRECTION; + return BaseOutputPinImpl_AttemptConnection(base, pReceivePin, pmt); } @@ -699,18 +703,30 @@ static const BasePinFuncTable AviMuxOut_BaseFuncTable = { AviMuxOut_GetMediaType }; -static HRESULT WINAPI AviMuxOut_DecideBufferSize(BaseOutputPin *base, - IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest) -{ - FIXME("(%p)->(%p %p)\n", base, pAlloc, ppropInputRequest); - return E_NOTIMPL; -} - static HRESULT WINAPI AviMuxOut_DecideAllocator(BaseOutputPin *base, IMemInputPin *pPin, IMemAllocator **pAlloc) { - FIXME("(%p)->(%p %p)\n", base, pPin, pAlloc); - return E_NOTIMPL; + ALLOCATOR_PROPERTIES req, actual; + HRESULT hr; + + TRACE("(%p)->(%p %p)\n", base, pPin, pAlloc); + + hr = BaseOutputPinImpl_InitAllocator(base, pAlloc); + if(FAILED(hr)) + return hr; + + hr = IMemInputPin_GetAllocatorRequirements(pPin, &req); + if(FAILED(hr)) + req.cbAlign = 1; + req.cBuffers = 32; + req.cbBuffer = 0; + req.cbPrefix = 0; + + hr = IMemAllocator_SetProperties(*pAlloc, &req, &actual); + if(FAILED(hr)) + return hr; + + return IMemInputPin_NotifyAllocator(pPin, *pAlloc, TRUE); } static HRESULT WINAPI AviMuxOut_BreakConnect(BaseOutputPin *base) @@ -720,7 +736,7 @@ static HRESULT WINAPI AviMuxOut_BreakConnect(BaseOutputPin *base) } static const BaseOutputPinFuncTable AviMuxOut_BaseOutputFuncTable = { - AviMuxOut_DecideBufferSize, + NULL, AviMuxOut_DecideAllocator, AviMuxOut_BreakConnect }; @@ -769,9 +785,30 @@ static HRESULT WINAPI AviMuxOut_Connect(IPin *iface, IPin *pReceivePin, const AM_MEDIA_TYPE *pmt) { AviMux *This = impl_from_out_IPin(iface); + HRESULT hr; + int i; + TRACE("(%p)->(%p AM_MEDIA_TYPE(%p))\n", This, pReceivePin, pmt); dump_AM_MEDIA_TYPE(pmt); - return BaseOutputPinImpl_Connect(iface, pReceivePin, pmt); + + hr = BaseOutputPinImpl_Connect(iface, pReceivePin, pmt); + if(FAILED(hr)) + return hr; + + for(i=0; iinput_pin_no; i++) { + if(!This->in[i]->pin.pin.pConnectedTo) + continue; + + hr = IFilterGraph_Reconnect(This->filter.filterInfo.pGraph, &This->in[i]->pin.pin.IPin_iface); + if(FAILED(hr)) { + BaseOutputPinImpl_Disconnect(iface); + break; + } + } + + if(hr == S_OK) + IBaseFilter_AddRef(&This->filter.IBaseFilter_iface); + return hr; } static HRESULT WINAPI AviMuxOut_ReceiveConnection(IPin *iface, @@ -786,8 +823,14 @@ static HRESULT WINAPI AviMuxOut_ReceiveConnection(IPin *iface, static HRESULT WINAPI AviMuxOut_Disconnect(IPin *iface) { AviMux *This = impl_from_out_IPin(iface); + HRESULT hr; + TRACE("(%p)\n", This); - return BaseOutputPinImpl_Disconnect(iface); + + hr = BaseOutputPinImpl_Disconnect(iface); + if(hr == S_OK) + IBaseFilter_Release(&This->filter.IBaseFilter_iface); + return hr; } static HRESULT WINAPI AviMuxOut_ConnectedTo(IPin *iface, IPin **pPin) diff --git a/dlls/qcap/tests/qcap.c b/dlls/qcap/tests/qcap.c index 80c2b336da6..86beda7ae3c 100644 --- a/dlls/qcap/tests/qcap.c +++ b/dlls/qcap/tests/qcap.c @@ -31,6 +31,35 @@ #include "wine/strmbase.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_EXPECT(ReceiveConnection); +DEFINE_EXPECT(GetAllocatorRequirements); +DEFINE_EXPECT(NotifyAllocator); +DEFINE_EXPECT(Reconnect); + static const char *debugstr_guid(REFIID riid) { static char buf[50]; @@ -342,7 +371,8 @@ static HRESULT WINAPI GraphBuilder_QueryInterface( return S_OK; } - ok(IsEqualIID(riid, &IID_IMediaEvent), "QueryInterface(%s)\n", debugstr_guid(riid)); + ok(IsEqualIID(riid, &IID_IMediaEvent) || IsEqualIID(riid, &IID_IMediaEventSink), + "QueryInterface(%s)\n", debugstr_guid(riid)); *ppv = NULL; return E_NOINTERFACE; } @@ -394,8 +424,8 @@ static HRESULT WINAPI GraphBuilder_ConnectDirect(IGraphBuilder *iface, static HRESULT WINAPI GraphBuilder_Reconnect(IGraphBuilder *iface, IPin *ppin) { - ok(0, "unexpected call\n"); - return E_NOTIMPL; + CHECK_EXPECT(Reconnect); + return S_OK; } static HRESULT WINAPI GraphBuilder_Disconnect(IGraphBuilder *iface, IPin *ppin) @@ -482,6 +512,7 @@ typedef struct { IEnumPins IEnumPins_iface; IPin IPin_iface; IKsPropertySet IKsPropertySet_iface; + IMemInputPin IMemInputPin_iface; IEnumMediaTypes IEnumMediaTypes_iface; PIN_DIRECTION dir; @@ -709,7 +740,12 @@ static HRESULT WINAPI Pin_QueryInterface(IPin *iface, REFIID riid, void **ppv) return S_OK; } - ok(0, "unexpected call\n"); + if(IsEqualIID(riid, &IID_IMemInputPin)) { + *ppv = &This->IMemInputPin_iface; + return S_OK; + } + + ok(0, "unexpected call: %s\n", debugstr_guid(riid)); *ppv = NULL; return E_NOINTERFACE; } @@ -733,8 +769,21 @@ static HRESULT WINAPI Pin_Connect(IPin *iface, IPin *pReceivePin, const AM_MEDIA static HRESULT WINAPI Pin_ReceiveConnection(IPin *iface, IPin *pConnector, const AM_MEDIA_TYPE *pmt) { - ok(0, "unexpected call\n"); - return E_NOTIMPL; + CHECK_EXPECT(ReceiveConnection); + + ok(IsEqualIID(&pmt->majortype, &MEDIATYPE_Stream), "majortype = %s\n", + debugstr_guid(&pmt->majortype)); + ok(IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_Avi), "subtype = %s\n", + debugstr_guid(&pmt->subtype)); + ok(pmt->bFixedSizeSamples, "bFixedSizeSamples = %x\n", pmt->bFixedSizeSamples); + ok(!pmt->bTemporalCompression, "bTemporalCompression = %x\n", pmt->bTemporalCompression); + ok(pmt->lSampleSize == 1, "lSampleSize = %d\n", pmt->lSampleSize); + ok(IsEqualIID(&pmt->formattype, &GUID_NULL), "formattype = %s\n", + debugstr_guid(&pmt->formattype)); + ok(!pmt->pUnk, "pUnk = %p\n", pmt->pUnk); + ok(!pmt->cbFormat, "cbFormat = %d\n", pmt->cbFormat); + ok(!pmt->pbFormat, "pbFormat = %p\n", pmt->pbFormat); + return S_OK; } static HRESULT WINAPI Pin_Disconnect(IPin *iface) @@ -910,6 +959,86 @@ static const IKsPropertySetVtbl KsPropertySetVtbl = { KsPropertySet_QuerySupported }; +static HRESULT WINAPI MemInputPin_QueryInterface(IMemInputPin *iface, REFIID riid, void **ppv) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static ULONG WINAPI MemInputPin_AddRef(IMemInputPin *iface) +{ + return 2; +} + +static ULONG WINAPI MemInputPin_Release(IMemInputPin *iface) +{ + return 1; +} + +static HRESULT WINAPI MemInputPin_GetAllocator(IMemInputPin *iface, IMemAllocator **ppAllocator) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI MemInputPin_NotifyAllocator(IMemInputPin *iface, + IMemAllocator *pAllocator, BOOL bReadOnly) +{ + ALLOCATOR_PROPERTIES ap; + HRESULT hr; + + CHECK_EXPECT(NotifyAllocator); + + ok(pAllocator != NULL, "pAllocator = %p\n", pAllocator); + ok(bReadOnly, "bReadOnly = %x\n", bReadOnly); + + hr = IMemAllocator_GetProperties(pAllocator, &ap); + ok(hr == S_OK, "GetProperties returned %x\n", hr); + ok(ap.cBuffers == 32, "cBuffers = %d\n", ap.cBuffers); + ok(ap.cbBuffer == 0, "cbBuffer = %d\n", ap.cbBuffer); + ok(ap.cbAlign == 1, "cbAlign = %d\n", ap.cbAlign); + ok(ap.cbPrefix == 0, "cbPrefix = %d\n", ap.cbPrefix); + return S_OK; +} + +static HRESULT WINAPI MemInputPin_GetAllocatorRequirements( + IMemInputPin *iface, ALLOCATOR_PROPERTIES *pProps) +{ + CHECK_EXPECT(GetAllocatorRequirements); + return E_NOTIMPL; +} + +static HRESULT WINAPI MemInputPin_Receive(IMemInputPin *iface, IMediaSample *pSample) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin *iface, + IMediaSample **pSamples, LONG nSamples, LONG *nSamplesProcessed) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI MemInputPin_ReceiveCanBlock(IMemInputPin *iface) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static const IMemInputPinVtbl MemInputPinVtbl = { + MemInputPin_QueryInterface, + MemInputPin_AddRef, + MemInputPin_Release, + MemInputPin_GetAllocator, + MemInputPin_NotifyAllocator, + MemInputPin_GetAllocatorRequirements, + MemInputPin_Receive, + MemInputPin_ReceiveMultiple, + MemInputPin_ReceiveCanBlock +}; + static test_filter* impl_from_IEnumMediaTypes(IEnumMediaTypes *iface) { return CONTAINING_RECORD(iface, test_filter, IEnumMediaTypes_iface); @@ -965,7 +1094,7 @@ static HRESULT WINAPI EnumMediaTypes_Reset(IEnumMediaTypes *iface) check_calls_list("EnumMediaTypes_Reset", ENUMMEDIATYPES_RESET, This->filter_type); This->enum_media_types_pos = 0; - return E_FAIL; + return S_OK; } static HRESULT WINAPI EnumMediaTypes_Clone(IEnumMediaTypes *iface, IEnumMediaTypes **ppEnum) @@ -991,6 +1120,7 @@ static void init_test_filter(test_filter *This, PIN_DIRECTION dir, filter_type t This->IEnumPins_iface.lpVtbl = &EnumPinsVtbl; This->IPin_iface.lpVtbl = &PinVtbl; This->IKsPropertySet_iface.lpVtbl = &KsPropertySetVtbl; + This->IMemInputPin_iface.lpVtbl = &MemInputPinVtbl; This->IEnumMediaTypes_iface.lpVtbl = &EnumMediaTypesVtbl; This->dir = dir; @@ -1082,7 +1212,7 @@ static void test_AviMux_QueryInterface(void) static void test_AviMux(void) { - test_filter source_filter; + test_filter source_filter, sink_filter; VIDEOINFOHEADER videoinfoheader; IPin *avimux_in, *avimux_out, *pin; AM_MEDIA_TYPE source_media_type; @@ -1094,6 +1224,7 @@ static void test_AviMux(void) HRESULT hr; init_test_filter(&source_filter, PINDIR_OUTPUT, SOURCE_FILTER); + init_test_filter(&sink_filter, PINDIR_INPUT, SINK_FILTER); hr = CoCreateInstance(&CLSID_AviDest, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (void**)&avimux); ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG), @@ -1177,6 +1308,26 @@ static void test_AviMux(void) ok(pin == &source_filter.IPin_iface, "incorrect pin: %p, expected %p\n", pin, &source_filter.IPin_iface); + hr = IPin_Connect(avimux_out, &source_filter.IPin_iface, NULL); + todo_wine ok(hr == VFW_E_INVALID_DIRECTION, "Connect returned %x\n", hr); + + hr = IBaseFilter_JoinFilterGraph(avimux, (IFilterGraph*)&GraphBuilder, NULL); + ok(hr == S_OK, "JoinFilterGraph returned %x\n", hr); + + SET_EXPECT(ReceiveConnection); + SET_EXPECT(GetAllocatorRequirements); + SET_EXPECT(NotifyAllocator); + SET_EXPECT(Reconnect); + hr = IPin_Connect(avimux_out, &sink_filter.IPin_iface, NULL); + ok(hr == S_OK, "Connect returned %x\n", hr); + CHECK_CALLED(ReceiveConnection); + CHECK_CALLED(GetAllocatorRequirements); + CHECK_CALLED(NotifyAllocator); + CHECK_CALLED(Reconnect); + + hr = IPin_Disconnect(avimux_out); + ok(hr == S_OK, "Disconnect returned %x\n", hr); + IPin_Release(avimux_in); IPin_Release(avimux_out); IBaseFilter_Release(avimux);