From 5c1409b55fed15a44accaceb223eaebc1f3c88d0 Mon Sep 17 00:00:00 2001 From: Aric Stewart Date: Tue, 5 Oct 2010 14:37:56 -0500 Subject: [PATCH] strmbase: Move OutputPin implementation to strmbase. --- dlls/qcap/Makefile.in | 1 - dlls/qcap/enummedia.c | 15 -- dlls/qcap/pin.c | 314 --------------------------- dlls/qcap/pin.h | 58 ----- dlls/qcap/qcap_main.h | 1 - dlls/qcap/v4l.c | 9 +- dlls/qcap/vfwcapture.c | 24 +- dlls/quartz/acmwrapper.c | 6 +- dlls/quartz/avidec.c | 6 +- dlls/quartz/avisplit.c | 2 +- dlls/quartz/enummedia.c | 10 - dlls/quartz/filesource.c | 23 +- dlls/quartz/mpegsplit.c | 2 +- dlls/quartz/parser.c | 22 +- dlls/quartz/parser.h | 2 +- dlls/quartz/pin.c | 526 -------------------------------------------- dlls/quartz/pin.h | 31 --- dlls/quartz/transform.c | 22 +- dlls/quartz/waveparser.c | 2 +- dlls/strmbase/pin.c | 553 +++++++++++++++++++++++++++++++++++++++++++++++ include/wine/strmbase.h | 32 +++ 21 files changed, 641 insertions(+), 1020 deletions(-) delete mode 100644 dlls/qcap/pin.c delete mode 100644 dlls/qcap/pin.h diff --git a/dlls/qcap/Makefile.in b/dlls/qcap/Makefile.in index 81e3dc2d923..d4762bdebd2 100644 --- a/dlls/qcap/Makefile.in +++ b/dlls/qcap/Makefile.in @@ -5,7 +5,6 @@ C_SRCS = \ capturegraph.c \ dllsetup.c \ enummedia.c \ - pin.c \ qcap_main.c \ v4l.c \ vfwcapture.c \ diff --git a/dlls/qcap/enummedia.c b/dlls/qcap/enummedia.c index b291a9e4e45..45552e16a46 100644 --- a/dlls/qcap/enummedia.c +++ b/dlls/qcap/enummedia.c @@ -35,21 +35,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(qcap); -BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, - BOOL bWildcards) -{ - TRACE("pmt1: "); - dump_AM_MEDIA_TYPE(pmt1); - TRACE("pmt2: "); - dump_AM_MEDIA_TYPE(pmt2); - return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || - IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || - IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) && - ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || - IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || - IsEqualGUID(&pmt1->subtype, &pmt2->subtype))); -} - void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt) { if (!pmt) diff --git a/dlls/qcap/pin.c b/dlls/qcap/pin.c deleted file mode 100644 index 52fb311f49c..00000000000 --- a/dlls/qcap/pin.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Generic Implementation of IPin Interface - * - * Copyright 2003 Robert Shearman - * - * 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 - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "wtypes.h" -#include "wingdi.h" -#include "winuser.h" -#include "dshow.h" - -#include "qcap_main.h" - -#include "wine/debug.h" -#include "wine/unicode.h" -#include "uuids.h" -#include "vfwmsgs.h" -#include -#include "pin.h" - -WINE_DEFAULT_DEBUG_CHANNEL(qcap); - -#define ALIGNDOWN(value,boundary) ((value) & ~(boundary-1)) -#define ALIGNUP(value,boundary) (ALIGNDOWN(value - 1, boundary) + boundary) - -static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc) -{ - /* Tempting to just do a memcpy, but the name field is - 128 characters long! We will probably never exceed 10 - most of the time, so we are better off copying - each field manually */ - strcpyW(pDest->achName, pSrc->achName); - pDest->dir = pSrc->dir; - pDest->pFilter = pSrc->pFilter; -} - -/* Function called as a helper to IPin_Connect */ -/* specific AM_MEDIA_TYPE - it cannot be NULL */ -/* NOTE: not part of standard interface */ -static HRESULT OutputPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) -{ - OutputPin *This = (OutputPin *)iface; - HRESULT hr; - IMemAllocator * pMemAlloc = NULL; - ALLOCATOR_PROPERTIES actual; /* FIXME: should we put the actual props back in to This? */ - - TRACE("(%p, %p)\n", pReceivePin, pmt); - dump_AM_MEDIA_TYPE(pmt); - - /* FIXME: call queryacceptproc */ - - This->pin.pConnectedTo = pReceivePin; - IPin_AddRef(pReceivePin); - CopyMediaType(&This->pin.mtCurrent, pmt); - - hr = IPin_ReceiveConnection(pReceivePin, iface, pmt); - - /* get the IMemInputPin interface we will use to deliver samples to the - * connected pin */ - if (SUCCEEDED(hr)) - { - hr = IPin_QueryInterface(pReceivePin, &IID_IMemInputPin, (LPVOID)&This->pMemInputPin); - - if (SUCCEEDED(hr)) - hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pMemAlloc); - - if (hr == VFW_E_NO_ALLOCATOR) - { - /* Input pin provides no allocator, use standard memory allocator */ - hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (LPVOID*)&pMemAlloc); - - if (SUCCEEDED(hr)) - { - hr = IMemInputPin_NotifyAllocator(This->pMemInputPin, pMemAlloc, FALSE); - } - } - - if (SUCCEEDED(hr)) - hr = IMemAllocator_SetProperties(pMemAlloc, &This->allocProps, &actual); - - if (pMemAlloc) - IMemAllocator_Release(pMemAlloc); - - /* break connection if we couldn't get the allocator */ - if (FAILED(hr)) - IPin_Disconnect(pReceivePin); - } - - if (FAILED(hr)) - { - IPin_Release(This->pin.pConnectedTo); - This->pin.pConnectedTo = NULL; - DeleteMediaType(&This->pin.mtCurrent); - } - - TRACE(" -- %x\n", hr); - return hr; -} - -HRESULT OutputPin_Init(const PIN_INFO * pPinInfo, const ALLOCATOR_PROPERTIES * props, - LPCRITICAL_SECTION pCritSec, OutputPin * pPinImpl) -{ - TRACE("\n"); - - /* Common attributes */ - pPinImpl->pin.refCount = 1; - pPinImpl->pin.pConnectedTo = NULL; - pPinImpl->pin.pCritSec = pCritSec; - Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo); - - /* Output pin attributes */ - pPinImpl->pMemInputPin = NULL; - pPinImpl->pConnectSpecific = OutputPin_ConnectSpecific; - if (props) - { - pPinImpl->allocProps = *props; - if (pPinImpl->allocProps.cbAlign == 0) - pPinImpl->allocProps.cbAlign = 1; - } - else - ZeroMemory(&pPinImpl->allocProps, sizeof(pPinImpl->allocProps)); - - return S_OK; -} - -HRESULT WINAPI OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) -{ - HRESULT hr; - OutputPin *This = (OutputPin *)iface; - - TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt); - dump_AM_MEDIA_TYPE(pmt); - - /* If we try to connect to ourself, we will definitely deadlock. - * There are other cases where we could deadlock too, but this - * catches the obvious case */ - assert(pReceivePin != iface); - - EnterCriticalSection(This->pin.pCritSec); - { - /* if we have been a specific type to connect with, then we can either connect - * with that or fail. We cannot choose different AM_MEDIA_TYPE */ - if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL)) - hr = This->pConnectSpecific(iface, pReceivePin, pmt); - else - { - /* negotiate media type */ - - IEnumMediaTypes * pEnumCandidates; - AM_MEDIA_TYPE * pmtCandidate; /* Candidate media type */ - - if (SUCCEEDED(hr = IPin_EnumMediaTypes(iface, &pEnumCandidates))) - { - hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */ - - /* try this filter's media types first */ - while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL)) - { - if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && - (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK)) - { - hr = S_OK; - TRACE("o_o\n"); - DeleteMediaType(pmtCandidate); - break; - } - DeleteMediaType(pmtCandidate); - } - IEnumMediaTypes_Release(pEnumCandidates); - } - - /* then try receiver filter's media types */ - if (hr != S_OK && SUCCEEDED(hr = IPin_EnumMediaTypes(pReceivePin, &pEnumCandidates))) /* if we haven't already connected successfully */ - { - hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */ - - while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL)) - { - if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && - (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK)) - { - hr = S_OK; - DeleteMediaType(pmtCandidate); - break; - } - DeleteMediaType(pmtCandidate); - } /* while */ - IEnumMediaTypes_Release(pEnumCandidates); - } /* if not found */ - } /* if negotiate media type */ - } /* if succeeded */ - LeaveCriticalSection(This->pin.pCritSec); - - TRACE(" -- %x\n", hr); - return hr; -} - -HRESULT WINAPI OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) -{ - ERR("Incoming connection on an output pin! (%p, %p)\n", pReceivePin, pmt); - - return E_UNEXPECTED; -} - -HRESULT WINAPI OutputPin_Disconnect(IPin * iface) -{ - HRESULT hr; - OutputPin *This = (OutputPin *)iface; - - TRACE("()\n"); - - EnterCriticalSection(This->pin.pCritSec); - { - if (This->pMemInputPin) - { - IMemInputPin_Release(This->pMemInputPin); - This->pMemInputPin = NULL; - } - if (This->pin.pConnectedTo) - { - IPin_Release(This->pin.pConnectedTo); - This->pin.pConnectedTo = NULL; - hr = S_OK; - } - else - hr = S_FALSE; - } - LeaveCriticalSection(This->pin.pCritSec); - - return hr; -} - -HRESULT OutputPin_GetDeliveryBuffer(OutputPin * This, IMediaSample ** ppSample, REFERENCE_TIME * tStart, REFERENCE_TIME * tStop, DWORD dwFlags) -{ - HRESULT hr; - - TRACE("(%p, %p, %p, %x)\n", ppSample, tStart, tStop, dwFlags); - - EnterCriticalSection(This->pin.pCritSec); - { - if (!This->pin.pConnectedTo) - hr = VFW_E_NOT_CONNECTED; - else - { - IMemAllocator * pAlloc = NULL; - - hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc); - - if (SUCCEEDED(hr)) - hr = IMemAllocator_GetBuffer(pAlloc, ppSample, tStart, tStop, dwFlags); - - if (SUCCEEDED(hr)) - hr = IMediaSample_SetTime(*ppSample, tStart, tStop); - - if (pAlloc) - IMemAllocator_Release(pAlloc); - } - } - LeaveCriticalSection(This->pin.pCritSec); - - return hr; -} - -HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample) -{ - HRESULT hr = S_OK; - IMemInputPin * pMemConnected = NULL; - - EnterCriticalSection(This->pin.pCritSec); - { - if (!This->pin.pConnectedTo || !This->pMemInputPin) - hr = VFW_E_NOT_CONNECTED; - else - { - /* we don't have the lock held when using This->pMemInputPin, - * so we need to AddRef it to stop it being deleted while we are - * using it. */ - pMemConnected = This->pMemInputPin; - IMemInputPin_AddRef(pMemConnected); - } - } - LeaveCriticalSection(This->pin.pCritSec); - - if (SUCCEEDED(hr)) - { - /* NOTE: if we are in a critical section when Receive is called - * then it causes some problems (most notably with the native Video - * Renderer) if we are re-entered for whatever reason */ - hr = IMemInputPin_Receive(pMemConnected, pSample); - IMemInputPin_Release(pMemConnected); - } - - return hr; -} diff --git a/dlls/qcap/pin.h b/dlls/qcap/pin.h deleted file mode 100644 index ef129cca38a..00000000000 --- a/dlls/qcap/pin.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * IPin function declarations to allow inheritance - * - * Copyright 2003 Robert Shearman - * - * 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 - */ - -/* This function will process incoming samples to the pin. - * Any return value valid in IMemInputPin::Receive is allowed here - */ -typedef HRESULT (* SAMPLEPROC)(LPVOID userdata, IMediaSample * pSample); - -/* This function will determine whether a type is supported or not. - * It is allowed to return any error value (within reason), as opposed - * to IPin::QueryAccept which is only allowed to return S_OK or S_FALSE. - */ -typedef HRESULT (* QUERYACCEPTPROC)(LPVOID userdata, const AM_MEDIA_TYPE * pmt); - -/* This function is called prior to finalizing a connection with - * another pin and can be used to get things from the other pin - * like IMemInput interfaces. - */ -typedef HRESULT (* PRECONNECTPROC)(IPin * iface, IPin * pConnectPin); - -typedef struct OutputPin -{ - /* inheritance C style! */ - BasePin pin; - - IMemInputPin * pMemInputPin; - HRESULT (* pConnectSpecific)(IPin * iface, IPin * pReceiver, const AM_MEDIA_TYPE * pmt); - ALLOCATOR_PROPERTIES allocProps; -} OutputPin; - -/*** Initializers ***/ -HRESULT OutputPin_Init(const PIN_INFO * pPinInfo, const ALLOCATOR_PROPERTIES *props, - LPCRITICAL_SECTION pCritSec, OutputPin * pPinImpl); - -/* Output Pin */ -HRESULT WINAPI OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt); -HRESULT WINAPI OutputPin_Disconnect(IPin * iface); -HRESULT WINAPI OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt); - -HRESULT OutputPin_GetDeliveryBuffer(OutputPin * This, IMediaSample ** ppSample, REFERENCE_TIME * tStart, REFERENCE_TIME * tStop, DWORD dwFlags); -HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample); diff --git a/dlls/qcap/qcap_main.h b/dlls/qcap/qcap_main.h index 75d84678ebd..8f855012d68 100644 --- a/dlls/qcap/qcap_main.h +++ b/dlls/qcap/qcap_main.h @@ -37,7 +37,6 @@ extern IUnknown * WINAPI QCAP_createInfinitePinTeeFilter(IUnknown *pUnkOuter, HR extern IUnknown * WINAPI QCAP_createSmartTeeFilter(IUnknown *pUnkOuter, HRESULT *phr); extern IUnknown * WINAPI QCAP_createAudioInputMixerPropertyPage(IUnknown *pUnkOuter, HRESULT *phr); -BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards); void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt); enum YUV_Format { diff --git a/dlls/qcap/v4l.c b/dlls/qcap/v4l.c index 31808040a20..fadcd49bd1a 100644 --- a/dlls/qcap/v4l.c +++ b/dlls/qcap/v4l.c @@ -43,7 +43,6 @@ #include "capture.h" #include "qcap_main.h" -#include "pin.h" #include #include @@ -619,7 +618,7 @@ static DWORD WINAPI ReadThread(LPVOID lParam) EnterCriticalSection(&capBox->CritSect); if (capBox->stopped) break; - hr = OutputPin_GetDeliveryBuffer((OutputPin *)capBox->pOut, &pSample, NULL, NULL, 0); + hr = BaseOutputPinImpl_GetDeliveryBuffer((BaseOutputPin *)capBox->pOut, &pSample, NULL, NULL, 0); if (SUCCEEDED(hr)) { int len; @@ -638,7 +637,7 @@ static DWORD WINAPI ReadThread(LPVOID lParam) V4l_GetFrame(capBox, &pInput); capBox->renderer(capBox, pOutput, pInput); Resize(capBox, pTarget, pOutput); - hr = OutputPin_SendSample((OutputPin *)capBox->pOut, pSample); + hr = BaseOutputPinImpl_Deliver((BaseOutputPin *)capBox->pOut, pSample); TRACE("%p -> Frame %u: %x\n", capBox, ++framecount, hr); IMediaSample_Release(pSample); V4l_FreeFrame(capBox); @@ -686,7 +685,7 @@ HRESULT qcap_driver_run(Capture *capBox, FILTER_STATE *state) { IMemAllocator * pAlloc = NULL; ALLOCATOR_PROPERTIES ap, actual; - OutputPin *out; + BaseOutputPin *out; ap.cBuffers = 3; if (!capBox->swresize) @@ -697,7 +696,7 @@ HRESULT qcap_driver_run(Capture *capBox, FILTER_STATE *state) ap.cbAlign = 1; ap.cbPrefix = 0; - out = (OutputPin *)capBox->pOut; + out = (BaseOutputPin *)capBox->pOut; hr = IMemInputPin_GetAllocator(out->pMemInputPin, &pAlloc); if (SUCCEEDED(hr)) diff --git a/dlls/qcap/vfwcapture.c b/dlls/qcap/vfwcapture.c index cf8f8c4ff4a..fd94ceba27c 100644 --- a/dlls/qcap/vfwcapture.c +++ b/dlls/qcap/vfwcapture.c @@ -35,7 +35,6 @@ #include "qcap_main.h" #include "wine/debug.h" -#include "pin.h" #include "capture.h" #include "uuids.h" #include "vfwmsgs.h" @@ -78,7 +77,7 @@ typedef struct VfwCapture /* VfwPin implementation */ typedef struct VfwPinImpl { - OutputPin pin; + BaseOutputPin pin; Capture *driver_info; VfwCapture *parent; const IKsPropertySetVtbl * KSP_VT; @@ -786,13 +785,10 @@ VfwPin_Construct( IBaseFilter * pBaseFilter, LPCRITICAL_SECTION pCritSec, { static const WCHAR wszOutputPinName[] = { 'O','u','t','p','u','t',0 }; ALLOCATOR_PROPERTIES ap; - VfwPinImpl * pPinImpl; PIN_INFO piOutput; HRESULT hr; - pPinImpl = CoTaskMemAlloc( sizeof(*pPinImpl) ); - if (!pPinImpl) - return E_OUTOFMEMORY; + ppPin = NULL; /* What we put here doesn't matter, the driver function should override it then commit */ @@ -806,17 +802,15 @@ VfwPin_Construct( IBaseFilter * pBaseFilter, LPCRITICAL_SECTION pCritSec, lstrcpyW(piOutput.achName, wszOutputPinName); ObjectRefCount(TRUE); - hr = OutputPin_Init(&piOutput, &ap, pCritSec, &pPinImpl->pin); + hr = BaseOutputPin_Construct(&VfwPin_Vtbl, sizeof(VfwPinImpl), &piOutput, &ap, NULL, pCritSec, ppPin); + if (SUCCEEDED(hr)) { + VfwPinImpl *pPinImpl = (VfwPinImpl*)*ppPin; pPinImpl->KSP_VT = &KSP_VTable; - pPinImpl->pin.pin.lpVtbl = &VfwPin_Vtbl; - *ppPin = (IPin *)(&pPinImpl->pin.pin.lpVtbl); - return S_OK; } - CoTaskMemFree(pPinImpl); - return E_FAIL; + return hr; } static HRESULT WINAPI VfwPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) @@ -924,9 +918,9 @@ static const IPinVtbl VfwPin_Vtbl = VfwPin_QueryInterface, VfwPin_AddRef, VfwPin_Release, - OutputPin_Connect, - OutputPin_ReceiveConnection, - OutputPin_Disconnect, + BaseOutputPinImpl_Connect, + BaseOutputPinImpl_ReceiveConnection, + BaseOutputPinImpl_Disconnect, BasePinImpl_ConnectedTo, BasePinImpl_ConnectionMediaType, BasePinImpl_QueryPinInfo, diff --git a/dlls/quartz/acmwrapper.c b/dlls/quartz/acmwrapper.c index 05863b304ba..506e6547356 100644 --- a/dlls/quartz/acmwrapper.c +++ b/dlls/quartz/acmwrapper.c @@ -120,7 +120,7 @@ static HRESULT ACMWrapper_ProcessSampleData(InputPin *pin, IMediaSample *pSample while(hr == S_OK && ash.cbSrcLength) { - hr = OutputPin_GetDeliveryBuffer((OutputPin*)This->tf.ppPins[1], &pOutSample, NULL, NULL, 0); + hr = BaseOutputPinImpl_GetDeliveryBuffer((BaseOutputPin*)This->tf.ppPins[1], &pOutSample, NULL, NULL, 0); if (FAILED(hr)) { ERR("Unable to get delivery buffer (%x)\n", hr); @@ -205,7 +205,7 @@ static HRESULT ACMWrapper_ProcessSampleData(InputPin *pin, IMediaSample *pSample TRACE("Sample stop time: %u.%03u\n", (DWORD)(tStart/10000000), (DWORD)((tStart/10000)%1000)); LeaveCriticalSection(&This->tf.csFilter); - hr = OutputPin_SendSample((OutputPin*)This->tf.ppPins[1], pOutSample); + hr = BaseOutputPinImpl_Deliver((BaseOutputPin*)This->tf.ppPins[1], pOutSample); EnterCriticalSection(&This->tf.csFilter); if (hr != S_OK && hr != VFW_E_NOT_CONNECTED) { @@ -272,7 +272,7 @@ static HRESULT ACMWrapper_ConnectInput(InputPin *pin, const AM_MEDIA_TYPE * pmt) This->has = drv; /* Update buffer size of media samples in output */ - ((OutputPin*)This->tf.ppPins[1])->allocProps.cbBuffer = This->pWfOut->nAvgBytesPerSec / 2; + ((BaseOutputPin*)This->tf.ppPins[1])->allocProps.cbBuffer = This->pWfOut->nAvgBytesPerSec / 2; TRACE("Connection accepted\n"); return S_OK; } diff --git a/dlls/quartz/avidec.c b/dlls/quartz/avidec.c index 605bc5c7005..d09b97eca1e 100644 --- a/dlls/quartz/avidec.c +++ b/dlls/quartz/avidec.c @@ -112,7 +112,7 @@ static HRESULT AVIDec_ProcessSampleData(InputPin *pin, IMediaSample *pSample) /* Update input size to match sample size */ This->pBihIn->biSizeImage = cbSrcStream; - hr = OutputPin_GetDeliveryBuffer((OutputPin*)This->tf.ppPins[1], &pOutSample, NULL, NULL, 0); + hr = BaseOutputPinImpl_GetDeliveryBuffer((BaseOutputPin*)This->tf.ppPins[1], &pOutSample, NULL, NULL, 0); if (FAILED(hr)) { ERR("Unable to get delivery buffer (%x)\n", hr); goto error; @@ -149,7 +149,7 @@ static HRESULT AVIDec_ProcessSampleData(InputPin *pin, IMediaSample *pSample) IMediaSample_SetTime(pOutSample, NULL, NULL); LeaveCriticalSection(&This->tf.csFilter); - hr = OutputPin_SendSample((OutputPin*)This->tf.ppPins[1], pOutSample); + hr = BaseOutputPinImpl_Deliver((BaseOutputPin*)This->tf.ppPins[1], pOutSample); if (hr != S_OK && hr != VFW_E_NOT_CONNECTED) ERR("Error sending sample (%x)\n", hr); IMediaSample_Release(pOutSample); @@ -269,7 +269,7 @@ static HRESULT AVIDec_ConnectInput(InputPin *pin, const AM_MEDIA_TYPE * pmt) assert(0); /* Update buffer size of media samples in output */ - ((OutputPin*)This->tf.ppPins[1])->allocProps.cbBuffer = This->pBihOut->biSizeImage; + ((BaseOutputPin*)This->tf.ppPins[1])->allocProps.cbBuffer = This->pBihOut->biSizeImage; TRACE("Connection accepted\n"); return S_OK; diff --git a/dlls/quartz/avisplit.c b/dlls/quartz/avisplit.c index a895ae5ab8a..109de201bbc 100644 --- a/dlls/quartz/avisplit.c +++ b/dlls/quartz/avisplit.c @@ -311,7 +311,7 @@ static HRESULT AVISplitter_Receive(AVISplitterImpl *This, IMediaSample *sample, IMediaSample_SetTime(sample, &start, &stop); - hr = OutputPin_SendSample(&pin->pin, sample); + hr = BaseOutputPinImpl_Deliver((BaseOutputPin*)&pin->pin, sample); /* Uncomment this if you want to debug the time differences between the * different streams, it is useful for that diff --git a/dlls/quartz/enummedia.c b/dlls/quartz/enummedia.c index 8c564b699fe..b3acc5d4e25 100644 --- a/dlls/quartz/enummedia.c +++ b/dlls/quartz/enummedia.c @@ -24,16 +24,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(quartz); -BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards) -{ - TRACE("pmt1: "); - dump_AM_MEDIA_TYPE(pmt1); - TRACE("pmt2: "); - dump_AM_MEDIA_TYPE(pmt2); - return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) && - ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype))); -} - void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt) { if (!pmt) diff --git a/dlls/quartz/filesource.c b/dlls/quartz/filesource.c index 1cbc0ccf2a3..c7529e72bc7 100644 --- a/dlls/quartz/filesource.c +++ b/dlls/quartz/filesource.c @@ -773,7 +773,7 @@ typedef struct DATAREQUEST typedef struct FileAsyncReader { - OutputPin pin; + BaseOutputPin pin; const struct IAsyncReaderVtbl * lpVtblAR; HANDLE hFile; @@ -886,8 +886,8 @@ static const IPinVtbl FileAsyncReaderPin_Vtbl = FileAsyncReaderPin_QueryInterface, BasePinImpl_AddRef, FileAsyncReaderPin_Release, - OutputPin_Connect, - OutputPin_ReceiveConnection, + BaseOutputPinImpl_Connect, + BaseOutputPinImpl_ReceiveConnection, BasePinImpl_Disconnect, BasePinImpl_ConnectedTo, BasePinImpl_ConnectionMediaType, @@ -897,19 +897,19 @@ static const IPinVtbl FileAsyncReaderPin_Vtbl = FileAsyncReaderPin_QueryAccept, FileAsyncReaderPin_EnumMediaTypes, BasePinImpl_QueryInternalConnections, - OutputPin_EndOfStream, - OutputPin_BeginFlush, - OutputPin_EndFlush, - OutputPin_NewSegment + BaseOutputPinImpl_EndOfStream, + BaseOutputPinImpl_BeginFlush, + BaseOutputPinImpl_EndFlush, + BaseOutputPinImpl_NewSegment }; /* Function called as a helper to IPin_Connect */ /* specific AM_MEDIA_TYPE - it cannot be NULL */ -/* this differs from standard OutputPin_ConnectSpecific only in that it +/* this differs from standard OutputPin_AttemptConnection only in that it * doesn't need the IMemInputPin interface on the receiving pin */ -static HRESULT FileAsyncReaderPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) +static HRESULT WINAPI FileAsyncReaderPin_AttemptConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) { - OutputPin *This = (OutputPin *)iface; + BaseOutputPin *This = (BaseOutputPin *)iface; HRESULT hr; TRACE("(%p, %p)\n", pReceivePin, pmt); @@ -943,7 +943,7 @@ static HRESULT FileAsyncReader_Construct(HANDLE hFile, IBaseFilter * pBaseFilter piOutput.dir = PINDIR_OUTPUT; piOutput.pFilter = pBaseFilter; strcpyW(piOutput.achName, wszOutputPinName); - hr = OutputPin_Construct(&FileAsyncReaderPin_Vtbl, sizeof(FileAsyncReader), &piOutput, NULL, pCritSec, ppPin); + hr = BaseOutputPin_Construct(&FileAsyncReaderPin_Vtbl, sizeof(FileAsyncReader), &piOutput, NULL, FileAsyncReaderPin_AttemptConnection, pCritSec, ppPin); if (SUCCEEDED(hr)) { @@ -954,7 +954,6 @@ static HRESULT FileAsyncReader_Construct(HANDLE hFile, IBaseFilter * pBaseFilter pPinImpl->sample_list = NULL; pPinImpl->handle_list = NULL; pPinImpl->queued_number = 0; - pPinImpl->pin.pConnectSpecific = FileAsyncReaderPin_ConnectSpecific; InitializeCriticalSection(&pPinImpl->csList); pPinImpl->csList.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FileAsyncReader.csList"); } diff --git a/dlls/quartz/mpegsplit.c b/dlls/quartz/mpegsplit.c index 7eb2d2c213f..e7ff4963f32 100644 --- a/dlls/quartz/mpegsplit.c +++ b/dlls/quartz/mpegsplit.c @@ -226,7 +226,7 @@ static HRESULT FillBuffer(MPEGSplitterImpl *This, IMediaSample *pCurrentSample) IMediaSample_SetTime(pCurrentSample, &time, &This->position); - hr = OutputPin_SendSample(&pOutputPin->pin, pCurrentSample); + hr = BaseOutputPinImpl_Deliver((BaseOutputPin*)&pOutputPin->pin, pCurrentSample); if (hr != S_OK) { diff --git a/dlls/quartz/parser.c b/dlls/quartz/parser.c index 0c93cca23fa..22a2c8be594 100644 --- a/dlls/quartz/parser.c +++ b/dlls/quartz/parser.c @@ -234,7 +234,7 @@ HRESULT WINAPI Parser_Stop(IBaseFilter * iface) for (i = 1; i < (This->cStreams + 1); i++) { - OutputPin_DecommitAllocator((OutputPin *)This->ppPins[i]); + BaseOutputPinImpl_Inactive((BaseOutputPin *)This->ppPins[i]); } LeaveCriticalSection(&This->csFilter); @@ -308,7 +308,7 @@ HRESULT WINAPI Parser_Run(IBaseFilter * iface, REFERENCE_TIME tStart) for (i = 1; i < (This->cStreams + 1); i++) { - hr = OutputPin_CommitAllocator((OutputPin *)This->ppPins[i]); + hr = BaseOutputPinImpl_Active((BaseOutputPin *)This->ppPins[i]); if (SUCCEEDED(hr)) hr_any = hr; } @@ -491,7 +491,7 @@ HRESULT Parser_AddPin(ParserImpl * This, const PIN_INFO * piOutput, ALLOCATOR_PR This->ppPins = CoTaskMemAlloc((This->cStreams + 2) * sizeof(IPin *)); memcpy(This->ppPins, ppOldPins, (This->cStreams + 1) * sizeof(IPin *)); - hr = OutputPin_Construct(&Parser_OutputPin_Vtbl, sizeof(Parser_OutputPin), piOutput, props, &This->csFilter, This->ppPins + (This->cStreams + 1)); + hr = BaseOutputPin_Construct(&Parser_OutputPin_Vtbl, sizeof(Parser_OutputPin), piOutput, props, NULL, &This->csFilter, This->ppPins + (This->cStreams + 1)); if (SUCCEEDED(hr)) { @@ -532,7 +532,7 @@ static HRESULT Parser_RemoveOutputPins(ParserImpl * This) for (i = 0; i < This->cStreams; i++) { - hr = OutputPin_DeliverDisconnect((OutputPin *)ppOldPins[i + 1]); + hr = BaseOutputPinImpl_BreakConnect((BaseOutputPin *)ppOldPins[i + 1]); TRACE("Disconnect: %08x\n", hr); IPin_Release(ppOldPins[i + 1]); } @@ -684,7 +684,7 @@ static HRESULT WINAPI Parser_OutputPin_Connect(IPin * iface, IPin * pReceivePin, This->pin.alloc = parser->pInputPin->pAlloc; LeaveCriticalSection(This->pin.pin.pCritSec); - return OutputPin_Connect(iface, pReceivePin, pmt); + return BaseOutputPinImpl_Connect(iface, pReceivePin, pmt); } static HRESULT WINAPI Parser_OutputPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE * pmt) @@ -703,8 +703,8 @@ static const IPinVtbl Parser_OutputPin_Vtbl = BasePinImpl_AddRef, Parser_OutputPin_Release, Parser_OutputPin_Connect, - OutputPin_ReceiveConnection, - OutputPin_Disconnect, + BaseOutputPinImpl_ReceiveConnection, + BaseOutputPinImpl_Disconnect, BasePinImpl_ConnectedTo, BasePinImpl_ConnectionMediaType, BasePinImpl_QueryPinInfo, @@ -713,10 +713,10 @@ static const IPinVtbl Parser_OutputPin_Vtbl = Parser_OutputPin_QueryAccept, Parser_OutputPin_EnumMediaTypes, BasePinImpl_QueryInternalConnections, - OutputPin_EndOfStream, - OutputPin_BeginFlush, - OutputPin_EndFlush, - OutputPin_NewSegment + BaseOutputPinImpl_EndOfStream, + BaseOutputPinImpl_BeginFlush, + BaseOutputPinImpl_EndFlush, + BaseOutputPinImpl_NewSegment }; static HRESULT WINAPI Parser_PullPin_Disconnect(IPin * iface) diff --git a/dlls/quartz/parser.h b/dlls/quartz/parser.h index b5423885400..afbd68d4fe1 100644 --- a/dlls/quartz/parser.h +++ b/dlls/quartz/parser.h @@ -49,7 +49,7 @@ struct ParserImpl typedef struct Parser_OutputPin { - OutputPin pin; + BaseOutputPin pin; AM_MEDIA_TYPE * pmt; LONGLONG dwSamplesProcessed; diff --git a/dlls/quartz/pin.c b/dlls/quartz/pin.c index 186229226c7..e45c0c01994 100644 --- a/dlls/quartz/pin.c +++ b/dlls/quartz/pin.c @@ -30,7 +30,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(quartz); static const IPinVtbl InputPin_Vtbl; -static const IPinVtbl OutputPin_Vtbl; static const IMemInputPinVtbl MemInputPin_Vtbl; static const IPinVtbl PullPin_Vtbl; @@ -510,391 +509,6 @@ static const IMemInputPinVtbl MemInputPin_Vtbl = MemInputPin_ReceiveCanBlock }; -/*** OutputPin implementation ***/ - -HRESULT WINAPI OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) -{ - OutputPin *This = (OutputPin *)iface; - - TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv); - - *ppv = NULL; - - if (IsEqualIID(riid, &IID_IUnknown)) - *ppv = iface; - else if (IsEqualIID(riid, &IID_IPin)) - *ppv = iface; - else if (IsEqualIID(riid, &IID_IMediaSeeking)) - { - return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv); - } - - if (*ppv) - { - IUnknown_AddRef((IUnknown *)(*ppv)); - return S_OK; - } - - FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); - - return E_NOINTERFACE; -} - -ULONG WINAPI OutputPin_Release(IPin * iface) -{ - OutputPin *This = (OutputPin *)iface; - ULONG refCount = InterlockedDecrement(&This->pin.refCount); - - TRACE("(%p)->() Release from %d\n", iface, refCount + 1); - - if (!refCount) - { - FreeMediaType(&This->pin.mtCurrent); - CoTaskMemFree(This); - return 0; - } - return refCount; -} - -HRESULT WINAPI OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) -{ - HRESULT hr; - OutputPin *This = (OutputPin *)iface; - - TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt); - dump_AM_MEDIA_TYPE(pmt); - - /* If we try to connect to ourself, we will definitely deadlock. - * There are other cases where we could deadlock too, but this - * catches the obvious case */ - assert(pReceivePin != iface); - - EnterCriticalSection(This->pin.pCritSec); - { - /* if we have been a specific type to connect with, then we can either connect - * with that or fail. We cannot choose different AM_MEDIA_TYPE */ - if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL)) - hr = This->pConnectSpecific(iface, pReceivePin, pmt); - else - { - /* negotiate media type */ - - IEnumMediaTypes * pEnumCandidates; - AM_MEDIA_TYPE * pmtCandidate = NULL; /* Candidate media type */ - - if (SUCCEEDED(hr = IPin_EnumMediaTypes(iface, &pEnumCandidates))) - { - hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */ - - /* try this filter's media types first */ - while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL)) - { - assert(pmtCandidate); - dump_AM_MEDIA_TYPE(pmtCandidate); - if (!IsEqualGUID(&FORMAT_None, &pmtCandidate->formattype) - && !IsEqualGUID(&GUID_NULL, &pmtCandidate->formattype)) - assert(pmtCandidate->pbFormat); - if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && - (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK)) - { - hr = S_OK; - DeleteMediaType(pmtCandidate); - break; - } - DeleteMediaType(pmtCandidate); - pmtCandidate = NULL; - } - IEnumMediaTypes_Release(pEnumCandidates); - } - - /* then try receiver filter's media types */ - if (hr != S_OK && SUCCEEDED(hr = IPin_EnumMediaTypes(pReceivePin, &pEnumCandidates))) /* if we haven't already connected successfully */ - { - hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */ - - while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL)) - { - assert(pmtCandidate); - dump_AM_MEDIA_TYPE(pmtCandidate); - if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && - (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK)) - { - hr = S_OK; - DeleteMediaType(pmtCandidate); - break; - } - DeleteMediaType(pmtCandidate); - pmtCandidate = NULL; - } /* while */ - IEnumMediaTypes_Release(pEnumCandidates); - } /* if not found */ - } /* if negotiate media type */ - } /* if succeeded */ - LeaveCriticalSection(This->pin.pCritSec); - - TRACE(" -- %x\n", hr); - return hr; -} - -HRESULT WINAPI OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) -{ - ERR("Incoming connection on an output pin! (%p, %p)\n", pReceivePin, pmt); - - return E_UNEXPECTED; -} - -HRESULT WINAPI OutputPin_Disconnect(IPin * iface) -{ - HRESULT hr; - OutputPin *This = (OutputPin *)iface; - - TRACE("()\n"); - - EnterCriticalSection(This->pin.pCritSec); - { - if (This->pMemInputPin) - { - IMemInputPin_Release(This->pMemInputPin); - This->pMemInputPin = NULL; - } - if (This->pin.pConnectedTo) - { - IPin_Release(This->pin.pConnectedTo); - This->pin.pConnectedTo = NULL; - FreeMediaType(&This->pin.mtCurrent); - ZeroMemory(&This->pin.mtCurrent, sizeof(This->pin.mtCurrent)); - hr = S_OK; - } - else - hr = S_FALSE; - } - LeaveCriticalSection(This->pin.pCritSec); - - return hr; -} - -HRESULT WINAPI OutputPin_EndOfStream(IPin * iface) -{ - TRACE("()\n"); - - /* not supposed to do anything in an output pin */ - - return E_UNEXPECTED; -} - -HRESULT WINAPI OutputPin_BeginFlush(IPin * iface) -{ - TRACE("(%p)->()\n", iface); - - /* not supposed to do anything in an output pin */ - - return E_UNEXPECTED; -} - -HRESULT WINAPI OutputPin_EndFlush(IPin * iface) -{ - TRACE("(%p)->()\n", iface); - - /* not supposed to do anything in an output pin */ - - return E_UNEXPECTED; -} - -HRESULT WINAPI OutputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - TRACE("(%p)->(%x%08x, %x%08x, %e)\n", iface, (ULONG)(tStart >> 32), (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)tStop, dRate); - - /* not supposed to do anything in an output pin */ - - return E_UNEXPECTED; -} - -static const IPinVtbl OutputPin_Vtbl = -{ - OutputPin_QueryInterface, - BasePinImpl_AddRef, - OutputPin_Release, - OutputPin_Connect, - OutputPin_ReceiveConnection, - OutputPin_Disconnect, - BasePinImpl_ConnectedTo, - BasePinImpl_ConnectionMediaType, - BasePinImpl_QueryPinInfo, - BasePinImpl_QueryDirection, - BasePinImpl_QueryId, - BasePinImpl_QueryAccept, - BasePinImpl_EnumMediaTypes, - BasePinImpl_QueryInternalConnections, - OutputPin_EndOfStream, - OutputPin_BeginFlush, - OutputPin_EndFlush, - OutputPin_NewSegment -}; - -HRESULT OutputPin_GetDeliveryBuffer(OutputPin * This, IMediaSample ** ppSample, REFERENCE_TIME * tStart, REFERENCE_TIME * tStop, DWORD dwFlags) -{ - HRESULT hr; - - TRACE("(%p, %p, %p, %x)\n", ppSample, tStart, tStop, dwFlags); - - EnterCriticalSection(This->pin.pCritSec); - { - if (!This->pin.pConnectedTo) - hr = VFW_E_NOT_CONNECTED; - else - { - IMemAllocator * pAlloc = NULL; - - hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc); - - if (SUCCEEDED(hr)) - hr = IMemAllocator_GetBuffer(pAlloc, ppSample, tStart, tStop, dwFlags); - - if (SUCCEEDED(hr)) - hr = IMediaSample_SetTime(*ppSample, tStart, tStop); - - if (pAlloc) - IMemAllocator_Release(pAlloc); - } - } - LeaveCriticalSection(This->pin.pCritSec); - - return hr; -} - -HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample) -{ - HRESULT hr = S_OK; - IMemInputPin * pMemConnected = NULL; - PIN_INFO pinInfo; - - EnterCriticalSection(This->pin.pCritSec); - { - if (!This->pin.pConnectedTo || !This->pMemInputPin) - hr = VFW_E_NOT_CONNECTED; - else - { - /* we don't have the lock held when using This->pMemInputPin, - * so we need to AddRef it to stop it being deleted while we are - * using it. Same with its filter. */ - pMemConnected = This->pMemInputPin; - IMemInputPin_AddRef(pMemConnected); - hr = IPin_QueryPinInfo(This->pin.pConnectedTo, &pinInfo); - } - } - LeaveCriticalSection(This->pin.pCritSec); - - if (SUCCEEDED(hr)) - { - /* NOTE: if we are in a critical section when Receive is called - * then it causes some problems (most notably with the native Video - * Renderer) if we are re-entered for whatever reason */ - hr = IMemInputPin_Receive(pMemConnected, pSample); - - /* If the filter's destroyed, tell upstream to stop sending data */ - if(IBaseFilter_Release(pinInfo.pFilter) == 0 && SUCCEEDED(hr)) - hr = S_FALSE; - } - if (pMemConnected) - IMemInputPin_Release(pMemConnected); - - return hr; -} - -HRESULT OutputPin_CommitAllocator(OutputPin * This) -{ - HRESULT hr = S_OK; - - TRACE("(%p)->()\n", This); - - EnterCriticalSection(This->pin.pCritSec); - { - if (!This->pin.pConnectedTo || !This->pMemInputPin) - hr = VFW_E_NOT_CONNECTED; - else - { - IMemAllocator * pAlloc = NULL; - - hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc); - - if (SUCCEEDED(hr)) - hr = IMemAllocator_Commit(pAlloc); - - if (pAlloc) - IMemAllocator_Release(pAlloc); - } - } - LeaveCriticalSection(This->pin.pCritSec); - - TRACE("--> %08x\n", hr); - return hr; -} - -HRESULT OutputPin_DecommitAllocator(OutputPin * This) -{ - HRESULT hr = S_OK; - - TRACE("(%p)->()\n", This); - - EnterCriticalSection(This->pin.pCritSec); - { - if (!This->pin.pConnectedTo || !This->pMemInputPin) - hr = VFW_E_NOT_CONNECTED; - else - { - IMemAllocator * pAlloc = NULL; - - hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc); - - if (SUCCEEDED(hr)) - hr = IMemAllocator_Decommit(pAlloc); - - if (pAlloc) - IMemAllocator_Release(pAlloc); - } - } - LeaveCriticalSection(This->pin.pCritSec); - - TRACE("--> %08x\n", hr); - return hr; -} - -HRESULT OutputPin_DeliverDisconnect(OutputPin * This) -{ - HRESULT hr; - - TRACE("(%p)->()\n", This); - - EnterCriticalSection(This->pin.pCritSec); - { - if (!This->pin.pConnectedTo || !This->pMemInputPin) - hr = VFW_E_NOT_CONNECTED; - else if (!This->custom_allocator) - { - IMemAllocator * pAlloc = NULL; - - hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc); - - if (SUCCEEDED(hr)) - hr = IMemAllocator_Decommit(pAlloc); - - if (pAlloc) - IMemAllocator_Release(pAlloc); - - if (SUCCEEDED(hr)) - hr = IPin_Disconnect(This->pin.pConnectedTo); - } - else /* Kill the allocator! */ - { - hr = IPin_Disconnect(This->pin.pConnectedTo); - } - IPin_Disconnect((IPin *)This); - } - LeaveCriticalSection(This->pin.pCritSec); - - return hr; -} - /*** PullPin implementation ***/ static HRESULT PullPin_Init(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PULL pSampleProc, LPVOID pUserData, @@ -1524,83 +1138,6 @@ static const IPinVtbl PullPin_Vtbl = /*** The Construct functions ***/ -/* Function called as a helper to IPin_Connect */ -/* specific AM_MEDIA_TYPE - it cannot be NULL */ -/* NOTE: not part of standard interface */ -static HRESULT OutputPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) -{ - OutputPin *This = (OutputPin *)iface; - HRESULT hr; - IMemAllocator * pMemAlloc = NULL; - ALLOCATOR_PROPERTIES actual; /* FIXME: should we put the actual props back in to This? */ - - TRACE("(%p, %p)\n", pReceivePin, pmt); - dump_AM_MEDIA_TYPE(pmt); - - /* FIXME: call queryacceptproc */ - - This->pin.pConnectedTo = pReceivePin; - IPin_AddRef(pReceivePin); - CopyMediaType(&This->pin.mtCurrent, pmt); - - hr = IPin_ReceiveConnection(pReceivePin, iface, pmt); - - /* get the IMemInputPin interface we will use to deliver samples to the - * connected pin */ - if (SUCCEEDED(hr)) - { - This->pMemInputPin = NULL; - hr = IPin_QueryInterface(pReceivePin, &IID_IMemInputPin, (LPVOID)&This->pMemInputPin); - - if (SUCCEEDED(hr) && !This->custom_allocator) - { - hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pMemAlloc); - - if (hr == VFW_E_NO_ALLOCATOR) - /* Input pin provides no allocator, use standard memory allocator */ - hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (LPVOID*)&pMemAlloc); - - if (SUCCEEDED(hr)) - hr = IMemAllocator_SetProperties(pMemAlloc, &This->allocProps, &actual); - - if (SUCCEEDED(hr)) - hr = IMemInputPin_NotifyAllocator(This->pMemInputPin, pMemAlloc, This->readonly); - - if (pMemAlloc) - IMemAllocator_Release(pMemAlloc); - } - else if (SUCCEEDED(hr)) - { - if (This->alloc) - { - hr = IMemInputPin_NotifyAllocator(This->pMemInputPin, This->alloc, This->readonly); - } - else - hr = VFW_E_NO_ALLOCATOR; - } - - /* break connection if we couldn't get the allocator */ - if (FAILED(hr)) - { - if (This->pMemInputPin) - IMemInputPin_Release(This->pMemInputPin); - This->pMemInputPin = NULL; - - IPin_Disconnect(pReceivePin); - } - } - - if (FAILED(hr)) - { - IPin_Release(This->pin.pConnectedTo); - This->pin.pConnectedTo = NULL; - FreeMediaType(&This->pin.mtCurrent); - } - - TRACE(" -- %x\n", hr); - return hr; -} - static HRESULT InputPin_Init(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PUSH pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, LPCRITICAL_SECTION pCritSec, IMemAllocator *allocator, InputPin * pPinImpl) { @@ -1631,40 +1168,6 @@ static HRESULT InputPin_Init(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPi return S_OK; } -static HRESULT OutputPin_Init(const IPinVtbl *OutputPin_Vtbl, const PIN_INFO * pPinInfo, const ALLOCATOR_PROPERTIES * props, - LPCRITICAL_SECTION pCritSec, OutputPin * pPinImpl) -{ - TRACE("\n"); - - /* Common attributes */ - pPinImpl->pin.lpVtbl = OutputPin_Vtbl; - pPinImpl->pin.refCount = 1; - pPinImpl->pin.pConnectedTo = NULL; - pPinImpl->pin.pCritSec = pCritSec; - Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo); - ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE)); - - /* Output pin attributes */ - pPinImpl->pMemInputPin = NULL; - pPinImpl->pConnectSpecific = OutputPin_ConnectSpecific; - /* If custom_allocator is set, you will need to specify an allocator - * in the alloc member of the struct before an output pin can connect - */ - pPinImpl->custom_allocator = 0; - pPinImpl->alloc = NULL; - pPinImpl->readonly = FALSE; - if (props) - { - pPinImpl->allocProps = *props; - if (pPinImpl->allocProps.cbAlign == 0) - pPinImpl->allocProps.cbAlign = 1; - } - else - ZeroMemory(&pPinImpl->allocProps, sizeof(pPinImpl->allocProps)); - - return S_OK; -} - HRESULT InputPin_Construct(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PUSH pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, LPCRITICAL_SECTION pCritSec, IMemAllocator *allocator, IPin ** ppPin) { InputPin * pPinImpl; @@ -1691,32 +1194,3 @@ HRESULT InputPin_Construct(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPinI CoTaskMemFree(pPinImpl); return E_FAIL; } - -HRESULT OutputPin_Construct(const IPinVtbl *OutputPin_Vtbl, LONG outputpin_size, const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, LPCRITICAL_SECTION pCritSec, IPin ** ppPin) -{ - OutputPin * pPinImpl; - - *ppPin = NULL; - - if (pPinInfo->dir != PINDIR_OUTPUT) - { - ERR("Pin direction(%x) != PINDIR_OUTPUT\n", pPinInfo->dir); - return E_INVALIDARG; - } - - assert(outputpin_size >= sizeof(OutputPin)); - - pPinImpl = CoTaskMemAlloc(outputpin_size); - - if (!pPinImpl) - return E_OUTOFMEMORY; - - if (SUCCEEDED(OutputPin_Init(OutputPin_Vtbl, pPinInfo, props, pCritSec, pPinImpl))) - { - *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl); - return S_OK; - } - - CoTaskMemFree(pPinImpl); - return E_FAIL; -} diff --git a/dlls/quartz/pin.h b/dlls/quartz/pin.h index 3e61a9fa58c..db7cd1a9183 100644 --- a/dlls/quartz/pin.h +++ b/dlls/quartz/pin.h @@ -84,19 +84,6 @@ typedef struct InputPin IMemAllocator *preferred_allocator; } InputPin; -typedef struct OutputPin -{ - /* inheritance C style! */ - BasePin pin; - - IMemInputPin * pMemInputPin; - HRESULT (* pConnectSpecific)(IPin * iface, IPin * pReceiver, const AM_MEDIA_TYPE * pmt); - BOOL custom_allocator; - IMemAllocator *alloc; - BOOL readonly; - ALLOCATOR_PROPERTIES allocProps; -} OutputPin; - typedef struct PullPin { /* inheritance C style! */ @@ -134,7 +121,6 @@ typedef struct PullPin /*** Constructors ***/ HRESULT InputPin_Construct(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PUSH pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, LPCRITICAL_SECTION pCritSec, IMemAllocator *, IPin ** ppPin); -HRESULT OutputPin_Construct(const IPinVtbl *OutputPin_Vtbl, LONG outputpin_size, const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, LPCRITICAL_SECTION pCritSec, IPin ** ppPin); HRESULT PullPin_Construct(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PULL pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, STOPPROCESSPROC, REQUESTPROC pCustomRequest, LPCRITICAL_SECTION pCritSec, IPin ** ppPin); /**************************/ @@ -151,23 +137,6 @@ HRESULT WINAPI InputPin_BeginFlush(IPin * iface); HRESULT WINAPI InputPin_EndFlush(IPin * iface); HRESULT WINAPI InputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); -/* Output Pin */ -HRESULT WINAPI OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv); -ULONG WINAPI OutputPin_Release(IPin * iface); -HRESULT WINAPI OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt); -HRESULT WINAPI OutputPin_Disconnect(IPin * iface); -HRESULT WINAPI OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt); -HRESULT WINAPI OutputPin_EndOfStream(IPin * iface); -HRESULT WINAPI OutputPin_BeginFlush(IPin * iface); -HRESULT WINAPI OutputPin_EndFlush(IPin * iface); -HRESULT WINAPI OutputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - -HRESULT OutputPin_CommitAllocator(OutputPin * This); -HRESULT OutputPin_DecommitAllocator(OutputPin * This); -HRESULT OutputPin_GetDeliveryBuffer(OutputPin * This, IMediaSample ** ppSample, REFERENCE_TIME * tStart, REFERENCE_TIME * tStop, DWORD dwFlags); -HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample); -HRESULT OutputPin_DeliverDisconnect(OutputPin * This); - /* Pull Pin */ HRESULT WINAPI PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt); HRESULT WINAPI PullPin_Disconnect(IPin * iface); diff --git a/dlls/quartz/transform.c b/dlls/quartz/transform.c index fd97f522707..29b8c786c25 100644 --- a/dlls/quartz/transform.c +++ b/dlls/quartz/transform.c @@ -117,7 +117,7 @@ HRESULT TransformFilter_Create(TransformFilterImpl* pTransformFilter, const CLSI ((InputPin *)pTransformFilter->ppPins[0])->pUserData = pTransformFilter->ppPins[0]; - hr = OutputPin_Construct(&TransformFilter_OutputPin_Vtbl, sizeof(OutputPin), &piOutput, &props, &pTransformFilter->csFilter, &pTransformFilter->ppPins[1]); + hr = BaseOutputPin_Construct(&TransformFilter_OutputPin_Vtbl, sizeof(BaseOutputPin), &piOutput, &props, NULL, &pTransformFilter->csFilter, &pTransformFilter->ppPins[1]); if (FAILED(hr)) ERR("Cannot create output pin (%x)\n", hr); @@ -295,7 +295,7 @@ static HRESULT WINAPI TransformFilter_Run(IBaseFilter * iface, REFERENCE_TIME tS if (This->pFuncsTable->pfnProcessBegin) hr = This->pFuncsTable->pfnProcessBegin(This); if (SUCCEEDED(hr)) - hr = OutputPin_CommitAllocator((OutputPin *)This->ppPins[1]); + hr = BaseOutputPinImpl_Active((BaseOutputPin *)This->ppPins[1]); } if (SUCCEEDED(hr)) @@ -624,12 +624,12 @@ static HRESULT WINAPI TransformFilter_Output_EnumMediaTypes(IPin * iface, IEnumM static const IPinVtbl TransformFilter_OutputPin_Vtbl = { - OutputPin_QueryInterface, + BaseOutputPinImpl_QueryInterface, BasePinImpl_AddRef, - OutputPin_Release, - OutputPin_Connect, - OutputPin_ReceiveConnection, - OutputPin_Disconnect, + BaseOutputPinImpl_Release, + BaseOutputPinImpl_Connect, + BaseOutputPinImpl_ReceiveConnection, + BaseOutputPinImpl_Disconnect, BasePinImpl_ConnectedTo, BasePinImpl_ConnectionMediaType, BasePinImpl_QueryPinInfo, @@ -638,8 +638,8 @@ static const IPinVtbl TransformFilter_OutputPin_Vtbl = TransformFilter_Output_QueryAccept, TransformFilter_Output_EnumMediaTypes, BasePinImpl_QueryInternalConnections, - OutputPin_EndOfStream, - OutputPin_BeginFlush, - OutputPin_EndFlush, - OutputPin_NewSegment + BaseOutputPinImpl_EndOfStream, + BaseOutputPinImpl_BeginFlush, + BaseOutputPinImpl_EndFlush, + BaseOutputPinImpl_NewSegment }; diff --git a/dlls/quartz/waveparser.c b/dlls/quartz/waveparser.c index cbdfcebc3b8..2dc85fd155e 100644 --- a/dlls/quartz/waveparser.c +++ b/dlls/quartz/waveparser.c @@ -132,7 +132,7 @@ static HRESULT WAVEParser_Sample(LPVOID iface, IMediaSample * pSample, DWORD_PTR IMediaSample_SetTime(pSample, &tAviStart, &tAviStop); - hr = OutputPin_SendSample(&pOutputPin->pin, pSample); + hr = BaseOutputPinImpl_Deliver(&pOutputPin->pin, pSample); if (hr != S_OK && hr != S_FALSE && hr != VFW_E_WRONG_STATE) ERR("Error sending sample (%x)\n", hr); else if (hr != S_OK) diff --git a/dlls/strmbase/pin.c b/dlls/strmbase/pin.c index ef5aba5a4d0..1e52314d335 100644 --- a/dlls/strmbase/pin.c +++ b/dlls/strmbase/pin.c @@ -31,6 +31,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(strmbase); +static const IPinVtbl OutputPin_Vtbl; + static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc) { /* Tempting to just do a memcpy, but the name field is @@ -42,6 +44,23 @@ static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc) pDest->pFilter = pSrc->pFilter; } +static void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt) +{ + if (!pmt) + return; + TRACE("\t%s\n\t%s\n\t...\n\t%s\n", debugstr_guid(&pmt->majortype), debugstr_guid(&pmt->subtype), debugstr_guid(&pmt->formattype)); +} + +static BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards) +{ + TRACE("pmt1: "); + dump_AM_MEDIA_TYPE(pmt1); + TRACE("pmt2: "); + dump_AM_MEDIA_TYPE(pmt2); + return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) && + ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype))); +} + /*** Common Base Pin function */ HRESULT WINAPI BasePinImpl_GetMediaType(IPin *iface, int iPosition, AM_MEDIA_TYPE *pmt) { @@ -205,3 +224,537 @@ HRESULT WINAPI BasePinImpl_QueryInternalConnections(IPin * iface, IPin ** apPin, return E_NOTIMPL; /* to tell caller that all input pins connected to all output pins */ } + +/*** OutputPin implementation ***/ + +HRESULT WINAPI BaseOutputPinImpl_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) +{ + BaseOutputPin *This = (BaseOutputPin *)iface; + + TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppv); + + *ppv = NULL; + + if (IsEqualIID(riid, &IID_IUnknown)) + *ppv = iface; + else if (IsEqualIID(riid, &IID_IPin)) + *ppv = iface; + else if (IsEqualIID(riid, &IID_IMediaSeeking)) + { + return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv); + } + + if (*ppv) + { + IUnknown_AddRef((IUnknown *)(*ppv)); + return S_OK; + } + + FIXME("No interface for %s!\n", debugstr_guid(riid)); + + return E_NOINTERFACE; +} + +ULONG WINAPI BaseOutputPinImpl_Release(IPin * iface) +{ + BaseOutputPin *This = (BaseOutputPin *)iface; + ULONG refCount = InterlockedDecrement(&This->pin.refCount); + + TRACE("(%p)->() Release from %d\n", iface, refCount + 1); + + if (!refCount) + { + FreeMediaType(&This->pin.mtCurrent); + CoTaskMemFree(This); + return 0; + } + return refCount; +} + +HRESULT WINAPI BaseOutputPinImpl_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) +{ + HRESULT hr; + BaseOutputPin *This = (BaseOutputPin *)iface; + + TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt); + dump_AM_MEDIA_TYPE(pmt); + + /* If we try to connect to ourself, we will definitely deadlock. + * There are other cases where we could deadlock too, but this + * catches the obvious case */ + assert(pReceivePin != iface); + + EnterCriticalSection(This->pin.pCritSec); + { + /* if we have been a specific type to connect with, then we can either connect + * with that or fail. We cannot choose different AM_MEDIA_TYPE */ + if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL)) + hr = This->pAttemptConnection(iface, pReceivePin, pmt); + else + { + /* negotiate media type */ + + IEnumMediaTypes * pEnumCandidates; + AM_MEDIA_TYPE * pmtCandidate = NULL; /* Candidate media type */ + + if (SUCCEEDED(hr = IPin_EnumMediaTypes(iface, &pEnumCandidates))) + { + hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */ + + /* try this filter's media types first */ + while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL)) + { + assert(pmtCandidate); + dump_AM_MEDIA_TYPE(pmtCandidate); + if (!IsEqualGUID(&FORMAT_None, &pmtCandidate->formattype) + && !IsEqualGUID(&GUID_NULL, &pmtCandidate->formattype)) + assert(pmtCandidate->pbFormat); + if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && + (This->pAttemptConnection(iface, pReceivePin, pmtCandidate) == S_OK)) + { + hr = S_OK; + DeleteMediaType(pmtCandidate); + break; + } + DeleteMediaType(pmtCandidate); + pmtCandidate = NULL; + } + IEnumMediaTypes_Release(pEnumCandidates); + } + + /* then try receiver filter's media types */ + if (hr != S_OK && SUCCEEDED(hr = IPin_EnumMediaTypes(pReceivePin, &pEnumCandidates))) /* if we haven't already connected successfully */ + { + hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */ + + while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL)) + { + assert(pmtCandidate); + dump_AM_MEDIA_TYPE(pmtCandidate); + if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && + (This->pAttemptConnection(iface, pReceivePin, pmtCandidate) == S_OK)) + { + hr = S_OK; + DeleteMediaType(pmtCandidate); + break; + } + DeleteMediaType(pmtCandidate); + pmtCandidate = NULL; + } /* while */ + IEnumMediaTypes_Release(pEnumCandidates); + } /* if not found */ + } /* if negotiate media type */ + } /* if succeeded */ + LeaveCriticalSection(This->pin.pCritSec); + + TRACE(" -- %x\n", hr); + return hr; +} + +HRESULT WINAPI BaseOutputPinImpl_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) +{ + ERR("Incoming connection on an output pin! (%p, %p)\n", pReceivePin, pmt); + + return E_UNEXPECTED; +} + +HRESULT WINAPI BaseOutputPinImpl_Disconnect(IPin * iface) +{ + HRESULT hr; + BaseOutputPin *This = (BaseOutputPin *)iface; + + TRACE("()\n"); + + EnterCriticalSection(This->pin.pCritSec); + { + if (This->pMemInputPin) + { + IMemInputPin_Release(This->pMemInputPin); + This->pMemInputPin = NULL; + } + if (This->pin.pConnectedTo) + { + IPin_Release(This->pin.pConnectedTo); + This->pin.pConnectedTo = NULL; + FreeMediaType(&This->pin.mtCurrent); + ZeroMemory(&This->pin.mtCurrent, sizeof(This->pin.mtCurrent)); + hr = S_OK; + } + else + hr = S_FALSE; + } + LeaveCriticalSection(This->pin.pCritSec); + + return hr; +} + +HRESULT WINAPI BaseOutputPinImpl_EndOfStream(IPin * iface) +{ + TRACE("()\n"); + + /* not supposed to do anything in an output pin */ + + return E_UNEXPECTED; +} + +HRESULT WINAPI BaseOutputPinImpl_BeginFlush(IPin * iface) +{ + TRACE("(%p)->()\n", iface); + + /* not supposed to do anything in an output pin */ + + return E_UNEXPECTED; +} + +HRESULT WINAPI BaseOutputPinImpl_EndFlush(IPin * iface) +{ + TRACE("(%p)->()\n", iface); + + /* not supposed to do anything in an output pin */ + + return E_UNEXPECTED; +} + +HRESULT WINAPI BaseOutputPinImpl_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + TRACE("(%p)->(%x%08x, %x%08x, %e)\n", iface, (ULONG)(tStart >> 32), (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)tStop, dRate); + + /* not supposed to do anything in an output pin */ + + return E_UNEXPECTED; +} + +static const IPinVtbl OutputPin_Vtbl = +{ + BaseOutputPinImpl_QueryInterface, + BasePinImpl_AddRef, + BaseOutputPinImpl_Release, + BaseOutputPinImpl_Connect, + BaseOutputPinImpl_ReceiveConnection, + BaseOutputPinImpl_Disconnect, + BasePinImpl_ConnectedTo, + BasePinImpl_ConnectionMediaType, + BasePinImpl_QueryPinInfo, + BasePinImpl_QueryDirection, + BasePinImpl_QueryId, + BasePinImpl_QueryAccept, + BasePinImpl_EnumMediaTypes, + BasePinImpl_QueryInternalConnections, + BaseOutputPinImpl_EndOfStream, + BaseOutputPinImpl_BeginFlush, + BaseOutputPinImpl_EndFlush, + BaseOutputPinImpl_NewSegment +}; + +HRESULT WINAPI BaseOutputPinImpl_GetDeliveryBuffer(BaseOutputPin *This, IMediaSample ** ppSample, REFERENCE_TIME * tStart, REFERENCE_TIME * tStop, DWORD dwFlags) +{ + HRESULT hr; + + TRACE("(%p, %p, %p, %x)\n", ppSample, tStart, tStop, dwFlags); + + EnterCriticalSection(This->pin.pCritSec); + { + if (!This->pin.pConnectedTo) + hr = VFW_E_NOT_CONNECTED; + else + { + IMemAllocator * pAlloc = NULL; + + hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc); + + if (SUCCEEDED(hr)) + hr = IMemAllocator_GetBuffer(pAlloc, ppSample, tStart, tStop, dwFlags); + + if (SUCCEEDED(hr)) + hr = IMediaSample_SetTime(*ppSample, tStart, tStop); + + if (pAlloc) + IMemAllocator_Release(pAlloc); + } + } + LeaveCriticalSection(This->pin.pCritSec); + + return hr; +} + +/* replaces OutputPin_SendSample */ +HRESULT WINAPI BaseOutputPinImpl_Deliver(BaseOutputPin *This, IMediaSample * pSample) +{ + HRESULT hr = S_OK; + IMemInputPin * pMemConnected = NULL; + PIN_INFO pinInfo; + + EnterCriticalSection(This->pin.pCritSec); + { + if (!This->pin.pConnectedTo || !This->pMemInputPin) + hr = VFW_E_NOT_CONNECTED; + else + { + /* we don't have the lock held when using This->pMemInputPin, + * so we need to AddRef it to stop it being deleted while we are + * using it. Same with its filter. */ + pMemConnected = This->pMemInputPin; + IMemInputPin_AddRef(pMemConnected); + hr = IPin_QueryPinInfo(This->pin.pConnectedTo, &pinInfo); + } + } + LeaveCriticalSection(This->pin.pCritSec); + + if (SUCCEEDED(hr)) + { + /* NOTE: if we are in a critical section when Receive is called + * then it causes some problems (most notably with the native Video + * Renderer) if we are re-entered for whatever reason */ + hr = IMemInputPin_Receive(pMemConnected, pSample); + + /* If the filter's destroyed, tell upstream to stop sending data */ + if(IBaseFilter_Release(pinInfo.pFilter) == 0 && SUCCEEDED(hr)) + hr = S_FALSE; + } + if (pMemConnected) + IMemInputPin_Release(pMemConnected); + + return hr; +} + +/* replaces OutputPin_CommitAllocator */ +HRESULT WINAPI BaseOutputPinImpl_Active(BaseOutputPin *This) +{ + HRESULT hr = S_OK; + + TRACE("(%p)->()\n", This); + + EnterCriticalSection(This->pin.pCritSec); + { + if (!This->pin.pConnectedTo || !This->pMemInputPin) + hr = VFW_E_NOT_CONNECTED; + else + { + IMemAllocator * pAlloc = NULL; + + hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc); + + if (SUCCEEDED(hr)) + hr = IMemAllocator_Commit(pAlloc); + + if (pAlloc) + IMemAllocator_Release(pAlloc); + } + } + LeaveCriticalSection(This->pin.pCritSec); + + TRACE("--> %08x\n", hr); + return hr; +} + +/* replaces OutputPin_DecommitAllocator */ +HRESULT WINAPI BaseOutputPinImpl_Inactive(BaseOutputPin *This) +{ + HRESULT hr = S_OK; + + TRACE("(%p)->()\n", This); + + EnterCriticalSection(This->pin.pCritSec); + { + if (!This->pin.pConnectedTo || !This->pMemInputPin) + hr = VFW_E_NOT_CONNECTED; + else + { + IMemAllocator * pAlloc = NULL; + + hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc); + + if (SUCCEEDED(hr)) + hr = IMemAllocator_Decommit(pAlloc); + + if (pAlloc) + IMemAllocator_Release(pAlloc); + } + } + LeaveCriticalSection(This->pin.pCritSec); + + TRACE("--> %08x\n", hr); + return hr; +} + +/* replaces OutputPin_DeliverDisconnect */ +HRESULT WINAPI BaseOutputPinImpl_BreakConnect(BaseOutputPin *This) +{ + HRESULT hr; + + TRACE("(%p)->()\n", This); + + EnterCriticalSection(This->pin.pCritSec); + { + if (!This->pin.pConnectedTo || !This->pMemInputPin) + hr = VFW_E_NOT_CONNECTED; + else if (!This->custom_allocator) + { + IMemAllocator * pAlloc = NULL; + + hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc); + + if (SUCCEEDED(hr)) + hr = IMemAllocator_Decommit(pAlloc); + + if (pAlloc) + IMemAllocator_Release(pAlloc); + + if (SUCCEEDED(hr)) + hr = IPin_Disconnect(This->pin.pConnectedTo); + } + else /* Kill the allocator! */ + { + hr = IPin_Disconnect(This->pin.pConnectedTo); + } + IPin_Disconnect((IPin *)This); + } + LeaveCriticalSection(This->pin.pCritSec); + + return hr; +} + +/*** The Construct functions ***/ + +/* Function called as a helper to IPin_Connect */ +/* specific AM_MEDIA_TYPE - it cannot be NULL */ +static HRESULT WINAPI OutputPin_AttemptConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) +{ + BaseOutputPin *This = (BaseOutputPin *)iface; + HRESULT hr; + IMemAllocator * pMemAlloc = NULL; + ALLOCATOR_PROPERTIES actual; /* FIXME: should we put the actual props back in to This? */ + + TRACE("(%p, %p)\n", pReceivePin, pmt); + dump_AM_MEDIA_TYPE(pmt); + + /* FIXME: call queryacceptproc */ + + This->pin.pConnectedTo = pReceivePin; + IPin_AddRef(pReceivePin); + CopyMediaType(&This->pin.mtCurrent, pmt); + + hr = IPin_ReceiveConnection(pReceivePin, iface, pmt); + + /* get the IMemInputPin interface we will use to deliver samples to the + * connected pin */ + if (SUCCEEDED(hr)) + { + This->pMemInputPin = NULL; + hr = IPin_QueryInterface(pReceivePin, &IID_IMemInputPin, (LPVOID)&This->pMemInputPin); + + if (SUCCEEDED(hr) && !This->custom_allocator) + { + hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pMemAlloc); + + if (hr == VFW_E_NO_ALLOCATOR) + /* Input pin provides no allocator, use standard memory allocator */ + hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (LPVOID*)&pMemAlloc); + + if (SUCCEEDED(hr)) + hr = IMemAllocator_SetProperties(pMemAlloc, &This->allocProps, &actual); + + if (SUCCEEDED(hr)) + hr = IMemInputPin_NotifyAllocator(This->pMemInputPin, pMemAlloc, This->readonly); + + if (pMemAlloc) + IMemAllocator_Release(pMemAlloc); + } + else if (SUCCEEDED(hr)) + { + if (This->alloc) + { + hr = IMemInputPin_NotifyAllocator(This->pMemInputPin, This->alloc, This->readonly); + } + else + hr = VFW_E_NO_ALLOCATOR; + } + + /* break connection if we couldn't get the allocator */ + if (FAILED(hr)) + { + if (This->pMemInputPin) + IMemInputPin_Release(This->pMemInputPin); + This->pMemInputPin = NULL; + + IPin_Disconnect(pReceivePin); + } + } + + if (FAILED(hr)) + { + IPin_Release(This->pin.pConnectedTo); + This->pin.pConnectedTo = NULL; + FreeMediaType(&This->pin.mtCurrent); + } + + TRACE(" -- %x\n", hr); + return hr; +} + +static HRESULT OutputPin_Init(const IPinVtbl *OutputPin_Vtbl, const PIN_INFO * +pPinInfo, const ALLOCATOR_PROPERTIES * props, BasePin_AttemptConnection pConnectProc, LPCRITICAL_SECTION pCritSec, +BaseOutputPin * pPinImpl) +{ + TRACE("\n"); + + /* Common attributes */ + pPinImpl->pin.lpVtbl = OutputPin_Vtbl; + pPinImpl->pin.refCount = 1; + pPinImpl->pin.pConnectedTo = NULL; + pPinImpl->pin.pCritSec = pCritSec; + Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo); + ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE)); + + /* Output pin attributes */ + pPinImpl->pMemInputPin = NULL; + if(pConnectProc) + pPinImpl->pAttemptConnection = pConnectProc; + else + pPinImpl->pAttemptConnection = OutputPin_AttemptConnection; + /* If custom_allocator is set, you will need to specify an allocator + * in the alloc member of the struct before an output pin can connect + */ + pPinImpl->custom_allocator = 0; + pPinImpl->alloc = NULL; + pPinImpl->readonly = FALSE; + if (props) + { + pPinImpl->allocProps = *props; + if (pPinImpl->allocProps.cbAlign == 0) + pPinImpl->allocProps.cbAlign = 1; + } + else + ZeroMemory(&pPinImpl->allocProps, sizeof(pPinImpl->allocProps)); + + return S_OK; +} + +HRESULT WINAPI BaseOutputPin_Construct(const IPinVtbl *OutputPin_Vtbl, LONG outputpin_size, const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, BasePin_AttemptConnection pConnectProc, LPCRITICAL_SECTION pCritSec, IPin ** ppPin) +{ + BaseOutputPin * pPinImpl; + + *ppPin = NULL; + + if (pPinInfo->dir != PINDIR_OUTPUT) + { + ERR("Pin direction(%x) != PINDIR_OUTPUT\n", pPinInfo->dir); + return E_INVALIDARG; + } + + assert(outputpin_size >= sizeof(BaseOutputPin)); + + pPinImpl = CoTaskMemAlloc(outputpin_size); + + if (!pPinImpl) + return E_OUTOFMEMORY; + + if (SUCCEEDED(OutputPin_Init(OutputPin_Vtbl, pPinInfo, props, pConnectProc, pCritSec, pPinImpl))) + { + *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl); + return S_OK; + } + + CoTaskMemFree(pPinImpl); + return E_FAIL; +} diff --git a/include/wine/strmbase.h b/include/wine/strmbase.h index a9aa167c06b..217827b3781 100644 --- a/include/wine/strmbase.h +++ b/include/wine/strmbase.h @@ -26,6 +26,7 @@ void WINAPI DeleteMediaType(AM_MEDIA_TYPE * pMediaType); typedef HRESULT (WINAPI *BasePin_GetMediaType)(IPin* iface, int iPosition, AM_MEDIA_TYPE *amt); typedef LONG (WINAPI *BasePin_GetMediaTypeVersion)(IPin* iface); +typedef HRESULT (WINAPI *BasePin_AttemptConnection)(IPin *iface, IPin *pReceivePin, const AM_MEDIA_TYPE *pmt); typedef IPin* (WINAPI *BaseFilter_GetPin)(IBaseFilter* iface, int iPosition); typedef LONG (WINAPI *BaseFilter_GetPinCount)(IBaseFilter* iface); @@ -47,6 +48,19 @@ typedef struct BasePin AM_MEDIA_TYPE mtCurrent; } BasePin; +typedef struct BaseOutputPin +{ + /* inheritance C style! */ + BasePin pin; + + IMemInputPin * pMemInputPin; + BasePin_AttemptConnection pAttemptConnection; + BOOL custom_allocator; + IMemAllocator *alloc; + BOOL readonly; + ALLOCATOR_PROPERTIES allocProps; +} BaseOutputPin; + /* Base Pin */ HRESULT WINAPI BasePinImpl_GetMediaType(IPin *iface, int iPosition, AM_MEDIA_TYPE *pmt); LONG WINAPI BasePinImpl_GetMediaTypeVersion(IPin *iface); @@ -60,3 +74,21 @@ HRESULT WINAPI BasePinImpl_QueryId(IPin * iface, LPWSTR * Id); HRESULT WINAPI BasePinImpl_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt); HRESULT WINAPI BasePinImpl_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum); HRESULT WINAPI BasePinImpl_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin); + +/* Base Output Pin */ +HRESULT WINAPI BaseOutputPinImpl_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv); +ULONG WINAPI BaseOutputPinImpl_Release(IPin * iface); +HRESULT WINAPI BaseOutputPinImpl_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt); +HRESULT WINAPI BaseOutputPinImpl_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt); +HRESULT WINAPI BaseOutputPinImpl_Disconnect(IPin * iface); +HRESULT WINAPI BaseOutputPinImpl_EndOfStream(IPin * iface); +HRESULT WINAPI BaseOutputPinImpl_BeginFlush(IPin * iface); +HRESULT WINAPI BaseOutputPinImpl_EndFlush(IPin * iface); +HRESULT WINAPI BaseOutputPinImpl_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + +HRESULT WINAPI BaseOutputPinImpl_GetDeliveryBuffer(BaseOutputPin * This, IMediaSample ** ppSample, REFERENCE_TIME * tStart, REFERENCE_TIME * tStop, DWORD dwFlags); +HRESULT WINAPI BaseOutputPinImpl_Deliver(BaseOutputPin * This, IMediaSample * pSample); +HRESULT WINAPI BaseOutputPinImpl_BreakConnect(BaseOutputPin * This); +HRESULT WINAPI BaseOutputPinImpl_Active(BaseOutputPin * This); +HRESULT WINAPI BaseOutputPinImpl_Inactive(BaseOutputPin * This); +HRESULT WINAPI BaseOutputPin_Construct(const IPinVtbl *OutputPin_Vtbl, LONG outputpin_size, const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, BasePin_AttemptConnection pConnectProc, LPCRITICAL_SECTION pCritSec, IPin ** ppPin); -- 2.11.4.GIT