Pin functions patch
Maarten Lankhorst
m.b.lankhorst at gmail.com
Mon May 16 17:11:50 CDT 2005
Copies some pin functions from directshow for internal use, might have
to add more later.
ChangeLog:
Add pin functions from quartz
-------------- next part --------------
Index: Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/qcap/Makefile.in,v
retrieving revision 1.11
diff -u -p -r1.11 Makefile.in
--- Makefile.in 14 May 2005 11:03:44 -0000 1.11
+++ Makefile.in 16 May 2005 22:08:17 -0000
@@ -11,7 +11,8 @@ C_SRCS = \
capturegraph.c \
dllsetup.c \
enummedia.c \
enumpins.c \
+ pin.c \
qcap_main.c
RC_SRCS = version.rc
--- /dev/null 2005-05-14 21:30:08.488754512 +0200
+++ pin.c 2005-05-17 00:07:00.000000000 +0200
@@ -0,0 +1,422 @@
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "pin.h"
+
+#include "wine/debug.h"
+#include "wine/unicode.h"
+#include "uuids.h"
+#include "vfwmsgs.h"
+#include <assert.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;
+}
+
+HRESULT WINAPI IPinImpl_ConnectedTo(IPin * iface, IPin ** ppPin)
+{
+ HRESULT hr;
+ IPinImpl *This = (IPinImpl *)iface;
+
+/* TRACE("(%p)\n", ppPin);*/
+
+ EnterCriticalSection(This->pCritSec);
+ {
+ if (This->pConnectedTo)
+ {
+ *ppPin = This->pConnectedTo;
+ IPin_AddRef(*ppPin);
+ hr = S_OK;
+ }
+ else
+ hr = VFW_E_NOT_CONNECTED;
+ }
+ LeaveCriticalSection(This->pCritSec);
+
+ return hr;
+}
+
+HRESULT WINAPI IPinImpl_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
+{
+ HRESULT hr;
+ IPinImpl *This = (IPinImpl *)iface;
+
+ TRACE("(%p/%p)->(%p)\n", This, iface, pmt);
+
+ EnterCriticalSection(This->pCritSec);
+ {
+ if (This->pConnectedTo)
+ {
+ CopyMediaType(pmt, &This->mtCurrent);
+ hr = S_OK;
+ }
+ else
+ {
+ ZeroMemory(pmt, sizeof(*pmt));
+ hr = VFW_E_NOT_CONNECTED;
+ }
+ }
+ LeaveCriticalSection(This->pCritSec);
+
+ return hr;
+}
+
+HRESULT WINAPI IPinImpl_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
+{
+ IPinImpl *This = (IPinImpl *)iface;
+
+ TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
+
+ Copy_PinInfo(pInfo, &This->pinInfo);
+ IBaseFilter_AddRef(pInfo->pFilter);
+
+ return S_OK;
+}
+
+HRESULT WINAPI IPinImpl_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
+{
+ IPinImpl *This = (IPinImpl *)iface;
+
+ TRACE("(%p/%p)->(%p)\n", This, iface, pPinDir);
+
+ *pPinDir = This->pinInfo.dir;
+
+ return S_OK;
+}
+
+HRESULT WINAPI IPinImpl_QueryId(IPin * iface, LPWSTR * Id)
+{
+ IPinImpl *This = (IPinImpl *)iface;
+
+ TRACE("(%p/%p)->(%p)\n", This, iface, Id);
+
+ *Id = CoTaskMemAlloc((strlenW(This->pinInfo.achName) + 1) * sizeof(WCHAR));
+ if (!Id)
+ return E_OUTOFMEMORY;
+
+ strcpyW(*Id, This->pinInfo.achName);
+
+ return S_OK;
+}
+
+HRESULT WINAPI IPinImpl_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
+{
+ IPinImpl *This = (IPinImpl *)iface;
+
+ TRACE("(%p/%p)->(%p)\n", This, iface, pmt);
+
+ if (!This->fnQueryAccept) return S_OK;
+
+ return (This->fnQueryAccept(This->pUserData, pmt) == S_OK ? S_OK : S_FALSE);
+}
+
+HRESULT WINAPI IPinImpl_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
+{
+ IPinImpl *This = (IPinImpl *)iface;
+
+ TRACE("(%p/%p)->(%p, %p)\n", This, iface, apPin, cPin);
+
+ return E_NOTIMPL; /* to tell caller that all input pins connected to all output pins */
+}
+
+/* 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(" -- %lx\n", hr);
+ return hr;
+}
+
+HRESULT OutputPin_Init(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES * props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, OutputPin * pPinImpl)
+{
+ TRACE("\n");
+
+ /* Common attributes */
+ pPinImpl->pin.refCount = 1;
+ pPinImpl->pin.pConnectedTo = NULL;
+ pPinImpl->pin.fnQueryAccept = pQueryAccept;
+ pPinImpl->pin.pUserData = pUserData;
+ pPinImpl->pin.pCritSec = pCritSec;
+ Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo);
+
+ /* Output pin attributes */
+ pPinImpl->pMemInputPin = NULL;
+ pPinImpl->pConnectSpecific = OutputPin_ConnectSpecific;
+ if (props)
+ {
+ memcpy(&pPinImpl->allocProps, props, sizeof(pPinImpl->allocProps));
+ 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(" -- %lx\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, const REFERENCE_TIME * tStart, const REFERENCE_TIME * tStop, DWORD dwFlags)
+{
+ HRESULT hr;
+
+ TRACE("(%p, %p, %p, %lx)\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, (REFERENCE_TIME *)tStart, (REFERENCE_TIME *)tStop, dwFlags);
+
+ if (SUCCEEDED(hr))
+ hr = IMediaSample_SetTime(*ppSample, (REFERENCE_TIME *)tStart, (REFERENCE_TIME *)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;
+}
+
--- /dev/null 2005-05-14 21:30:08.488754512 +0200
+++ pin.h 2005-05-16 23:53:28.000000000 +0200
@@ -0,0 +1,81 @@
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 IPinImpl
+{
+ const struct IPinVtbl * lpVtbl;
+ ULONG refCount;
+ LPCRITICAL_SECTION pCritSec;
+ PIN_INFO pinInfo;
+ IPin * pConnectedTo;
+ AM_MEDIA_TYPE mtCurrent;
+ ENUMMEDIADETAILS enumMediaDetails;
+ QUERYACCEPTPROC fnQueryAccept;
+ LPVOID pUserData;
+} IPinImpl;
+
+typedef struct OutputPin
+{
+ /* inheritance C style! */
+ IPinImpl 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, ALLOCATOR_PROPERTIES *props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, OutputPin * pPinImpl);
+
+/* Common */
+HRESULT WINAPI IPinImpl_ConnectedTo(IPin * iface, IPin ** ppPin);
+HRESULT WINAPI IPinImpl_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt);
+HRESULT WINAPI IPinImpl_QueryPinInfo(IPin * iface, PIN_INFO * pInfo);
+HRESULT WINAPI IPinImpl_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir);
+HRESULT WINAPI IPinImpl_QueryId(IPin * iface, LPWSTR * Id);
+HRESULT WINAPI IPinImpl_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt);
+HRESULT WINAPI IPinImpl_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum);
+HRESULT WINAPI IPinImpl_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin);
+
+/* 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, const REFERENCE_TIME * tStart, const REFERENCE_TIME * tStop, DWORD dwFlags);
+HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample);
+
More information about the wine-patches
mailing list