strmbase: Move OutputPin implementation to strmbase.
diff --git a/dlls/qcap/Makefile.in b/dlls/qcap/Makefile.in
index 81e3dc2..d4762bd 100644
--- a/dlls/qcap/Makefile.in
+++ b/dlls/qcap/Makefile.in
@@ -5,7 +5,6 @@
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 b291a9e..45552e1 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 52fb311..0000000
--- 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 <stdarg.h>
-
-#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 <assert.h>
-#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 ef129cc..0000000
--- 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 75d8467..8f85501 100644
--- a/dlls/qcap/qcap_main.h
+++ b/dlls/qcap/qcap_main.h
@@ -37,7 +37,6 @@
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 3180804..fadcd49 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 <stdio.h>
#include <fcntl.h>
@@ -619,7 +618,7 @@
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 @@
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 @@
{
IMemAllocator * pAlloc = NULL;
ALLOCATOR_PROPERTIES ap, actual;
- OutputPin *out;
+ BaseOutputPin *out;
ap.cBuffers = 3;
if (!capBox->swresize)
@@ -697,7 +696,7 @@
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 cf8f8c4..fd94ceb 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 @@
/* VfwPin implementation */
typedef struct VfwPinImpl
{
- OutputPin pin;
+ BaseOutputPin pin;
Capture *driver_info;
VfwCapture *parent;
const IKsPropertySetVtbl * KSP_VT;
@@ -786,13 +785,10 @@
{
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 @@
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 @@
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 05863b3..506e654 100644
--- a/dlls/quartz/acmwrapper.c
+++ b/dlls/quartz/acmwrapper.c
@@ -120,7 +120,7 @@
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 @@
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 @@
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 605bc5c..d09b97e 100644
--- a/dlls/quartz/avidec.c
+++ b/dlls/quartz/avidec.c
@@ -112,7 +112,7 @@
/* 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 @@
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 @@
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 a895ae5..109de20 100644
--- a/dlls/quartz/avisplit.c
+++ b/dlls/quartz/avisplit.c
@@ -311,7 +311,7 @@
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 8c564b6..b3acc5d 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 1cbc0cc..c7529e7 100644
--- a/dlls/quartz/filesource.c
+++ b/dlls/quartz/filesource.c
@@ -773,7 +773,7 @@
typedef struct FileAsyncReader
{
- OutputPin pin;
+ BaseOutputPin pin;
const struct IAsyncReaderVtbl * lpVtblAR;
HANDLE hFile;
@@ -886,8 +886,8 @@
FileAsyncReaderPin_QueryInterface,
BasePinImpl_AddRef,
FileAsyncReaderPin_Release,
- OutputPin_Connect,
- OutputPin_ReceiveConnection,
+ BaseOutputPinImpl_Connect,
+ BaseOutputPinImpl_ReceiveConnection,
BasePinImpl_Disconnect,
BasePinImpl_ConnectedTo,
BasePinImpl_ConnectionMediaType,
@@ -897,19 +897,19 @@
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 @@
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 @@
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 7eb2d2c..e7ff496 100644
--- a/dlls/quartz/mpegsplit.c
+++ b/dlls/quartz/mpegsplit.c
@@ -226,7 +226,7 @@
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 0c93cca..22a2c8b 100644
--- a/dlls/quartz/parser.c
+++ b/dlls/quartz/parser.c
@@ -234,7 +234,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 b542388..afbd68d 100644
--- a/dlls/quartz/parser.h
+++ b/dlls/quartz/parser.h
@@ -49,7 +49,7 @@
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 1862292..e45c0c0 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 @@
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 @@
/*** 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 @@
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 @@
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 3e61a9f..db7cd1a 100644
--- a/dlls/quartz/pin.h
+++ b/dlls/quartz/pin.h
@@ -84,19 +84,6 @@
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 @@
/*** 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_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 fd97f52..29b8c78 100644
--- a/dlls/quartz/transform.c
+++ b/dlls/quartz/transform.c
@@ -117,7 +117,7 @@
((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 @@
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 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 @@
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 cbdfceb..2dc85fd 100644
--- a/dlls/quartz/waveparser.c
+++ b/dlls/quartz/waveparser.c
@@ -132,7 +132,7 @@
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 ef5aba5..1e52314 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 @@
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 @@
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 a9aa167..217827b 100644
--- a/include/wine/strmbase.h
+++ b/include/wine/strmbase.h
@@ -26,6 +26,7 @@
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 @@
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_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);