[DSHOW-09] Features and bug fixes for Pin interface

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch contains a load of bug fixes for the pin functions (InputPin_* and 
OutputPin_*) and includes the implementation of the third type of pin 
(PullPin). There are also a few helper functions for the OutputPin 
class/structure which aid in delivering messages and data to another filter 
through a connected pin.
This should enable me to submit the AVI splitter filter in a couple of days 
or so.

Rob

Changelog:
- A few cosmetic fixes
- Various bug fixes
- Add some OutputPin helpers
- Add a new type of pin, PullPin
Index: wine/dlls/quartz/filesource.c
===================================================================
RCS file: /home/wine/wine/dlls/quartz/filesource.c,v
retrieving revision 1.2
diff -u -r1.2 filesource.c
--- wine/dlls/quartz/filesource.c	5 Sep 2003 23:08:32 -0000	1.2
+++ wine/dlls/quartz/filesource.c	25 Sep 2003 22:00:26 -0000
@@ -34,9 +34,6 @@
 
 static const WCHAR wszOutputPinName[] = { 'O','u','t','p','u','t',0 };
 
-/* see IAsyncReader::Request on MSDN for the explanation of this */
-#define BYTES_FROM_MEDIATIME(time) ((time) / 10000000)
-
 typedef struct AsyncReader
 {
     const struct IBaseFilterVtbl * lpVtbl;
@@ -877,7 +874,7 @@
     piOutput.pFilter = pBaseFilter;
     strcpyW(piOutput.achName, wszOutputPinName);
 
-    if (SUCCEEDED(OutputPin_Init(&piOutput, pBaseFilter, AcceptProcAFR, pCritSec, &pPinImpl->pin)))
+    if (SUCCEEDED(OutputPin_Init(&piOutput, NULL, pBaseFilter, AcceptProcAFR, pCritSec, &pPinImpl->pin)))
     {
         pPinImpl->pin.pin.lpVtbl = &FileAsyncReaderPin_Vtbl;
         pPinImpl->lpVtblAR = &FileAsyncReader_Vtbl;
Index: wine/dlls/quartz/pin.c
===================================================================
RCS file: /home/wine/wine/dlls/quartz/pin.c,v
retrieving revision 1.1
diff -u -r1.1 pin.c
--- wine/dlls/quartz/pin.c	6 Aug 2003 22:04:45 -0000	1.1
+++ wine/dlls/quartz/pin.c	25 Sep 2003 22:00:27 -0000
@@ -32,6 +32,10 @@
 static const struct IPinVtbl InputPin_Vtbl;
 static const struct IPinVtbl OutputPin_Vtbl;
 static const struct IMemInputPinVtbl MemInputPin_Vtbl;
+static const struct IPinVtbl PullPin_Vtbl;
+
+#define ALIGNDOWN(value,boundary) ((value) & ~(boundary-1))
+#define ALIGNUP(value,boundary) (ALIGNDOWN(value - 1, boundary) + boundary)
 
 #define _IMemInputPin_Offset ((int)(&(((InputPin*)0)->lpVtblMemInput)))
 #define ICOM_THIS_From_IMemInputPin(impl, iface) impl* This = (impl*)(((char*)iface)-_IMemInputPin_Offset);
@@ -53,24 +57,50 @@
 /* NOTE: not part of standard interface */
 static HRESULT OutputPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
 {
-    HRESULT hr;
     ICOM_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->pin.pConnectedTo = pReceivePin;
-        IPin_AddRef(pReceivePin);
-        CopyMediaType(&This->pin.mtCurrent, pmt);
+        hr = IPin_QueryInterface(pReceivePin, &IID_IMemInputPin, (LPVOID)&This->pMemInputPin);
+
+        if (SUCCEEDED(hr))
+            hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pMemAlloc);
+
+        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);
     }
-    else
+
+    if (FAILED(hr))
+    {
+        IPin_Release(This->pin.pConnectedTo);
         This->pin.pConnectedTo = NULL;
+        DeleteMediaType(&This->pin.mtCurrent);
+    }
 
-    TRACE("-- %lx\n", hr);
+    TRACE(" -- %lx\n", hr);
     return hr;
 }
 
@@ -108,14 +138,13 @@
     /* Common attributes */
     pPinImpl->pin.refCount = 1;
     pPinImpl->pin.pConnectedTo = NULL;
-    pPinImpl->pin.pQueryAccept = pQueryAccept;
+    pPinImpl->pin.fnQueryAccept = pQueryAccept;
     pPinImpl->pin.pUserData = pUserData;
     pPinImpl->pin.pCritSec = pCritSec;
-    InitializeCriticalSection(pPinImpl->pin.pCritSec);
     Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo);
 
     /* Input pin attributes */
-    pPinImpl->pSampleProc = pSampleProc;
+    pPinImpl->fnSampleProc = pSampleProc;
     pPinImpl->pAllocator = NULL;
     pPinImpl->tStart = 0;
     pPinImpl->tStop = 0;
@@ -124,26 +153,34 @@
     return S_OK;
 }
 
-HRESULT OutputPin_Init(const PIN_INFO * pPinInfo, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, OutputPin * pPinImpl)
+HRESULT OutputPin_Init(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES * props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, OutputPin * pPinImpl)
 {
     /* Common attributes */
     pPinImpl->pin.lpVtbl = &OutputPin_Vtbl;
     pPinImpl->pin.refCount = 1;
     pPinImpl->pin.pConnectedTo = NULL;
-    pPinImpl->pin.pQueryAccept = pQueryAccept;
+    pPinImpl->pin.fnQueryAccept = pQueryAccept;
     pPinImpl->pin.pUserData = pUserData;
     pPinImpl->pin.pCritSec = pCritSec;
-    InitializeCriticalSection(pPinImpl->pin.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 OutputPin_Construct(const PIN_INFO * pPinInfo, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
+HRESULT OutputPin_Construct(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
 {
     OutputPin * pPinImpl;
 
@@ -160,7 +197,7 @@
     if (!pPinImpl)
         return E_OUTOFMEMORY;
 
-    if (SUCCEEDED(OutputPin_Init(pPinInfo, pUserData, pQueryAccept, pCritSec, pPinImpl)))
+    if (SUCCEEDED(OutputPin_Init(pPinInfo, props, pUserData, pQueryAccept, pCritSec, pPinImpl)))
     {
         pPinImpl->pin.lpVtbl = &OutputPin_Vtbl;
         
@@ -206,27 +243,19 @@
 
 HRESULT WINAPI IPinImpl_ConnectedTo(IPin * iface, IPin ** ppPin)
 {
-    HRESULT hr = S_OK;
     ICOM_THIS(IPinImpl, iface);
 
 /*  TRACE("(%p)\n", ppPin);*/
 
-    EnterCriticalSection(This->pCritSec);
+    *ppPin = This->pConnectedTo;
+
+    if (*ppPin)
     {
-        if (!This->pConnectedTo)
-        {
-            *ppPin = NULL;
-            hr = VFW_E_NOT_CONNECTED;
-        }
-        else
-        {
-            *ppPin = This->pConnectedTo;
-            IPin_AddRef(*ppPin);
-        }
+        IPin_AddRef(*ppPin);
+        return S_OK;
     }
-    LeaveCriticalSection(This->pCritSec);
-
-    return hr;
+    else
+        return VFW_E_NOT_CONNECTED;
 }
 
 HRESULT WINAPI IPinImpl_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
@@ -297,7 +326,7 @@
 
     TRACE("(%p)\n", pmt);
 
-    return (This->pQueryAccept(This->pUserData, pmt) == S_OK ? S_OK : S_FALSE);
+    return (This->fnQueryAccept(This->pUserData, pmt) == S_OK ? S_OK : S_FALSE);
 }
 
 HRESULT WINAPI IPinImpl_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
@@ -356,6 +385,7 @@
     
     if (!InterlockedDecrement(&This->pin.refCount))
     {
+        DeleteMediaType(&This->pin.mtCurrent);
         if (This->pAllocator)
             IMemAllocator_Release(This->pAllocator);
         CoTaskMemFree(This);
@@ -375,8 +405,8 @@
 
 HRESULT WINAPI InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
 {
-    PIN_DIRECTION pindirReceive;
     ICOM_THIS(InputPin, iface);
+    PIN_DIRECTION pindirReceive;
     HRESULT hr = S_OK;
 
     TRACE("(%p, %p)\n", pReceivePin, pmt);
@@ -387,8 +417,8 @@
         if (This->pin.pConnectedTo)
             hr = VFW_E_ALREADY_CONNECTED;
 
-        if (SUCCEEDED(hr) && This->pin.pQueryAccept(This->pin.pUserData, pmt) != S_OK)
-            hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto 
+        if (SUCCEEDED(hr) && This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK)
+            hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto
                                            * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */
 
         if (SUCCEEDED(hr))
@@ -509,7 +539,7 @@
 {
     ICOM_THIS_From_IMemInputPin(InputPin, iface);
 
-    TRACE("MemInputPin_NotifyAllocator()\n");
+    TRACE("()\n");
 
     if (This->pAllocator)
         IMemAllocator_Release(This->pAllocator);
@@ -536,7 +566,7 @@
     /* this trace commented out for performance reasons */
 /*  TRACE("(%p)\n", pSample);*/
 
-    return This->pSampleProc(This->pin.pUserData, pSample);
+    return This->fnSampleProc(This->pin.pUserData, pSample);
 }
 
 HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin * iface, IMediaSample ** pSamples, long nSamples, long *nSamplesProcessed)
@@ -607,6 +637,7 @@
     
     if (!InterlockedDecrement(&This->pin.refCount))
     {
+        DeleteMediaType(&This->pin.mtCurrent);
         CoTaskMemFree(This);
         return 0;
     }
@@ -628,63 +659,57 @@
 
     EnterCriticalSection(This->pin.pCritSec);
     {
-        /* get the IMemInputPin interface we will use to deliver samples to the
-         * connected pin */
-        hr = IPin_QueryInterface(pReceivePin, &IID_IMemInputPin, (LPVOID *)&This->pMemInputPin);
-
         /* 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 (SUCCEEDED(hr))
+        if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
+            hr = This->pConnectSpecific(iface, pReceivePin, pmt);
+        else
         {
-            if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
-                hr = This->pConnectSpecific(iface, pReceivePin, pmt);
-            else
-            {
-                /* negotiate media type */
+            /* negotiate media type */
 
-                IEnumMediaTypes * pEnumCandidates;
-                AM_MEDIA_TYPE * pmtCandidate; /* Candidate 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 */
+            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))
+                /* 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))
                     {
-                        if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && 
-                            (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK))
-                        {
-                            hr = S_OK;
-                            CoTaskMemFree(pmtCandidate);
-                            break;
-                        }
+                        hr = S_OK;
                         CoTaskMemFree(pmtCandidate);
+                        break;
                     }
-                    IEnumMediaTypes_Release(pEnumCandidates);
+                    CoTaskMemFree(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 */
+            /* then try receiver filter's media types */
+            if (hr != S_OK && SUCCEEDED(hr = IPin_EnumMediaTypes(pReceivePin, &pEnumCandidates))) /* if we haven't already connected successfully */
+            {
+                while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL))
                 {
-                    while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL))
+                    if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && 
+                        (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK))
                     {
-                        if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && 
-                            (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK))
-                        {
-                            hr = S_OK;
-                            CoTaskMemFree(pmtCandidate);
-                            break;
-                        }
+                        hr = S_OK;
                         CoTaskMemFree(pmtCandidate);
-                    } /* while */
-                    IEnumMediaTypes_Release(pEnumCandidates);
-                } /* if not found */
-            } /* if negotiate media type */
-        } /* if succeeded */
+                        break;
+                    }
+                    CoTaskMemFree(pmtCandidate);
+                } /* while */
+                IEnumMediaTypes_Release(pEnumCandidates);
+            } /* if not found */
+        } /* if negotiate media type */
     } /* if succeeded */
     LeaveCriticalSection(This->pin.pCritSec);
 
+    FIXME(" -- %lx\n", hr);
     return hr;
 }
 
@@ -780,4 +805,532 @@
     OutputPin_BeginFlush,
     OutputPin_EndFlush,
     OutputPin_NewSegment
+};
+
+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
+        {
+            IMemInputPin * pMemInputPin = NULL;
+            IMemAllocator * pAlloc = NULL;
+            
+            /* FIXME: should we cache this? */
+            hr = IPin_QueryInterface(This->pin.pConnectedTo, &IID_IMemInputPin, (LPVOID *)&pMemInputPin);
+
+            if (SUCCEEDED(hr))
+                hr = IMemInputPin_GetAllocator(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);
+            if (pMemInputPin)
+                IMemInputPin_Release(pMemInputPin);
+        }
+    }
+    LeaveCriticalSection(This->pin.pCritSec);
+    
+    return hr;
+}
+
+HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample)
+{
+    HRESULT hr;
+    IMemInputPin * pMemConnected = NULL;
+
+    EnterCriticalSection(This->pin.pCritSec);
+    {
+        if (!This->pin.pConnectedTo)
+            hr = VFW_E_NOT_CONNECTED;
+        else
+        {
+            /* FIXME: should we cache this? - if we do, then we need to keep the local version
+             * and AddRef here instead */
+            hr = IPin_QueryInterface(This->pin.pConnectedTo, &IID_IMemInputPin, (LPVOID *)&pMemConnected);
+        }
+    }
+    LeaveCriticalSection(This->pin.pCritSec);
+
+    if (SUCCEEDED(hr) && pMemConnected)
+    {
+        /* 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;
+}
+
+HRESULT OutputPin_DeliverNewSegment(OutputPin * This, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
+{
+    HRESULT hr;
+
+    EnterCriticalSection(This->pin.pCritSec);
+    {
+        if (!This->pin.pConnectedTo)
+            hr = VFW_E_NOT_CONNECTED;
+        else
+            hr = IPin_NewSegment(This->pin.pConnectedTo, tStart, tStop, dRate);
+    }
+    LeaveCriticalSection(This->pin.pCritSec);
+    
+    return hr;
+}
+
+HRESULT OutputPin_CommitAllocator(OutputPin * This)
+{
+    HRESULT hr;
+
+    TRACE("()\n");
+
+    EnterCriticalSection(This->pin.pCritSec);
+    {
+        if (!This->pin.pConnectedTo)
+            hr = VFW_E_NOT_CONNECTED;
+        else
+        {
+            IMemInputPin * pMemInputPin = NULL;
+            IMemAllocator * pAlloc = NULL;
+            /* FIXME: should we cache this? */
+            hr = IPin_QueryInterface(This->pin.pConnectedTo, &IID_IMemInputPin, (LPVOID *)&pMemInputPin);
+
+            if (SUCCEEDED(hr))
+                hr = IMemInputPin_GetAllocator(pMemInputPin, &pAlloc);
+
+            if (SUCCEEDED(hr))
+                hr = IMemAllocator_Commit(pAlloc);
+
+            if (pAlloc)
+                IMemAllocator_Release(pAlloc);
+
+            if (pMemInputPin)
+                IMemInputPin_Release(pMemInputPin);
+        }
+    }
+    LeaveCriticalSection(This->pin.pCritSec);
+    
+    return hr;
+}
+
+HRESULT OutputPin_DeliverDisconnect(OutputPin * This)
+{
+    HRESULT hr;
+
+    TRACE("()\n");
+
+    EnterCriticalSection(This->pin.pCritSec);
+    {
+        if (!This->pin.pConnectedTo)
+            hr = VFW_E_NOT_CONNECTED;
+        else
+        {
+            IMemInputPin * pMemInputPin = NULL;
+            IMemAllocator * pAlloc = NULL;
+            /* FIXME: should we cache this? */
+            hr = IPin_QueryInterface(This->pin.pConnectedTo, &IID_IMemInputPin, (LPVOID *)&pMemInputPin);
+
+            if (SUCCEEDED(hr))
+                hr = IMemInputPin_GetAllocator(pMemInputPin, &pAlloc);
+
+            if (SUCCEEDED(hr))
+                hr = IMemAllocator_Decommit(pAlloc);
+
+            if (pAlloc)
+                IMemAllocator_Release(pAlloc);
+
+            if (pMemInputPin)
+                IMemInputPin_Release(pMemInputPin);
+
+            if (SUCCEEDED(hr))
+                hr = IPin_Disconnect(This->pin.pConnectedTo);
+        }
+    }
+    LeaveCriticalSection(This->pin.pCritSec);
+
+    return hr;
+}
+
+
+HRESULT PullPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
+{
+    PullPin * pPinImpl;
+
+    *ppPin = NULL;
+
+    if (pPinInfo->dir != PINDIR_INPUT)
+    {
+        ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir);
+        return E_INVALIDARG;
+    }
+
+    pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
+
+    if (!pPinImpl)
+        return E_OUTOFMEMORY;
+
+    if (SUCCEEDED(PullPin_Init(pPinInfo, pSampleProc, pUserData, pQueryAccept, pCritSec, pPinImpl)))
+    {
+        pPinImpl->pin.lpVtbl = &PullPin_Vtbl;
+        
+        *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
+        return S_OK;
+    }
+    return E_FAIL;
+}
+
+HRESULT PullPin_Init(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, PullPin * pPinImpl)
+{
+    /* 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);
+
+    /* Input pin attributes */
+    pPinImpl->fnSampleProc = pSampleProc;
+    pPinImpl->fnPreConnect = NULL;
+    pPinImpl->pAlloc = NULL;
+    pPinImpl->pReader = NULL;
+    pPinImpl->hThread = NULL;
+    pPinImpl->hEventStateChanged = CreateEventW(NULL, FALSE, TRUE, NULL);
+
+    pPinImpl->rtStart = 0;
+    pPinImpl->rtStop = 0x7fffffffffffffff;
+    
+    return S_OK;
+}
+
+HRESULT WINAPI PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
+{
+    PIN_DIRECTION pindirReceive;
+    HRESULT hr = S_OK;
+    ICOM_THIS(PullPin, iface);
+
+    TRACE("(%p, %p)\n", pReceivePin, pmt);
+    dump_AM_MEDIA_TYPE(pmt);
+
+    EnterCriticalSection(This->pin.pCritSec);
+    {
+        if (This->pin.pConnectedTo)
+            hr = VFW_E_ALREADY_CONNECTED;
+
+        if (SUCCEEDED(hr) && (This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK))
+            hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto 
+                                           * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */
+
+        if (SUCCEEDED(hr))
+        {
+            IPin_QueryDirection(pReceivePin, &pindirReceive);
+
+            if (pindirReceive != PINDIR_OUTPUT)
+            {
+                ERR("Can't connect from non-output pin\n");
+                hr = VFW_E_INVALID_DIRECTION;
+            }
+        }
+
+        if (SUCCEEDED(hr))
+        {
+            hr = IPin_QueryInterface(pReceivePin, &IID_IAsyncReader, (LPVOID *)&This->pReader);
+        }
+
+        if (SUCCEEDED(hr))
+        {
+            ALLOCATOR_PROPERTIES props;
+            props.cBuffers = 3;
+            props.cbBuffer = 64 * 1024; /* 64k bytes */
+            props.cbAlign = 1;
+            props.cbPrefix = 0;
+            hr = IAsyncReader_RequestAllocator(This->pReader, NULL, &props, &This->pAlloc);
+        }
+
+        if (SUCCEEDED(hr) && This->fnPreConnect)
+        {
+            hr = This->fnPreConnect(iface, pReceivePin);
+        }
+
+        if (SUCCEEDED(hr))
+        {
+            CopyMediaType(&This->pin.mtCurrent, pmt);
+            This->pin.pConnectedTo = pReceivePin;
+            IPin_AddRef(pReceivePin);
+        }
+    }
+    LeaveCriticalSection(This->pin.pCritSec);
+    return hr;
+}
+
+HRESULT WINAPI PullPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
+{
+    TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
+
+    *ppv = NULL;
+
+    if (IsEqualIID(riid, &IID_IUnknown))
+        *ppv = (LPVOID)iface;
+    else if (IsEqualIID(riid, &IID_IPin))
+        *ppv = (LPVOID)iface;
+
+    if (*ppv)
+    {
+        IUnknown_AddRef((IUnknown *)(*ppv));
+        return S_OK;
+    }
+
+    FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
+
+    return E_NOINTERFACE;
+}
+
+ULONG WINAPI PullPin_Release(IPin * iface)
+{
+    ICOM_THIS(PullPin, iface);
+
+    TRACE("()\n");
+
+    if (!InterlockedDecrement(&This->pin.refCount))
+    {
+        if (This->hThread)
+            PullPin_StopProcessing(This);
+        IMemAllocator_Release(This->pAlloc);
+        IAsyncReader_Release(This->pReader);
+        CloseHandle(This->hEventStateChanged);
+        CoTaskMemFree(This);
+        return 0;
+    }
+    return This->pin.refCount;
+}
+
+static DWORD WINAPI PullPin_Thread_Main(LPVOID pv)
+{
+    for (;;)
+        SleepEx(INFINITE, TRUE);
+}
+
+static void CALLBACK PullPin_Thread_Process(ULONG_PTR iface)
+{
+    ICOM_THIS(PullPin, iface);
+    HRESULT hr;
+
+    REFERENCE_TIME rtCurrent;
+    ALLOCATOR_PROPERTIES allocProps;
+
+    SetEvent(This->hEventStateChanged);
+
+    hr = IMemAllocator_GetProperties(This->pAlloc, &allocProps);
+
+    rtCurrent = MEDIATIME_FROM_BYTES(ALIGNDOWN(BYTES_FROM_MEDIATIME(This->rtStart), allocProps.cbAlign));
+
+    while (rtCurrent < This->rtStop)
+    {
+        /* FIXME: to improve performance by quite a bit this should be changed
+         * so that one sample is processed while one sample is fetched. However,
+         * it is harder to debug so for the moment it will stay as it is */
+        IMediaSample * pSample = NULL;
+        REFERENCE_TIME rtSampleStop;
+        DWORD dwUser;
+
+        hr = IMemAllocator_GetBuffer(This->pAlloc, &pSample, NULL, NULL, 0);
+
+        if (SUCCEEDED(hr))
+        {
+            rtSampleStop = rtCurrent + MEDIATIME_FROM_BYTES(IMediaSample_GetSize(pSample));
+            if (rtSampleStop > This->rtStop)
+                rtSampleStop = MEDIATIME_FROM_BYTES(ALIGNUP(BYTES_FROM_MEDIATIME(This->rtStop), allocProps.cbAlign));
+            hr = IMediaSample_SetTime(pSample, &rtCurrent, &rtSampleStop);
+            rtCurrent = rtSampleStop;
+        }
+
+        if (SUCCEEDED(hr))
+            hr = IAsyncReader_Request(This->pReader, pSample, (ULONG_PTR)0);
+
+        if (SUCCEEDED(hr))
+            hr = IAsyncReader_WaitForNext(This->pReader, 10000, &pSample, &dwUser);
+
+        if (SUCCEEDED(hr))
+            hr = This->fnSampleProc(This->pin.pUserData, pSample);
+        else
+            ERR("Processing error: %lx\n", hr);
+        
+        if (pSample)
+            IMemAllocator_ReleaseBuffer(This->pAlloc, pSample);
+    }
+}
+
+static void CALLBACK PullPin_Thread_Stop(ULONG_PTR iface)
+{
+    ICOM_THIS(PullPin, iface);
+
+    TRACE("()\n");
+
+    EnterCriticalSection(This->pin.pCritSec);
+    {
+        HRESULT hr;
+
+        CloseHandle(This->hThread);
+        This->hThread = NULL;
+        if (FAILED(hr = IMemAllocator_Decommit(This->pAlloc)))
+            ERR("Allocator decommit failed with error %lx. Possible memory leak\n", hr);
+    }
+    LeaveCriticalSection(This->pin.pCritSec);
+
+    SetEvent(This->hEventStateChanged);
+
+    ExitThread(0);
+}
+
+HRESULT PullPin_InitProcessing(PullPin * This)
+{
+    HRESULT hr = S_OK;
+
+    TRACE("()\n");
+
+    assert(!This->hThread);
+
+    /* if we are connected */
+    if (This->pAlloc)
+    {
+        EnterCriticalSection(This->pin.pCritSec);
+        {
+            DWORD dwThreadId;
+            assert(!This->hThread);
+        
+            This->hThread = CreateThread(NULL, 0, PullPin_Thread_Main, NULL, 0, &dwThreadId);
+            if (!This->hThread)
+                hr = HRESULT_FROM_WIN32(GetLastError());
+
+            if (SUCCEEDED(hr))
+                hr = IMemAllocator_Commit(This->pAlloc);
+        }
+        LeaveCriticalSection(This->pin.pCritSec);
+    }
+
+    TRACE(" -- %lx\n", hr);
+
+    return hr;
+}
+
+HRESULT PullPin_StartProcessing(PullPin * This)
+{
+    /* if we are connected */
+    if(This->pAlloc)
+    {
+        assert(This->hThread);
+        
+        ResetEvent(This->hEventStateChanged);
+        
+        if (!QueueUserAPC(PullPin_Thread_Process, This->hThread, (ULONG_PTR)This))
+            return HRESULT_FROM_WIN32(GetLastError());
+    }
+
+    return S_OK;
+}
+
+HRESULT PullPin_PauseProcessing(PullPin * This)
+{
+    /* make the processing function exit its loop */
+    This->rtStop = 0;
+
+    return S_OK;
+}
+
+HRESULT PullPin_StopProcessing(PullPin * This)
+{
+    /* if we are connected */
+    if (This->pAlloc)
+    {
+        assert(This->hThread);
+
+        ResetEvent(This->hEventStateChanged);
+
+        PullPin_PauseProcessing(This);
+
+        if (!QueueUserAPC(PullPin_Thread_Stop, This->hThread, (ULONG_PTR)This))
+            return HRESULT_FROM_WIN32(GetLastError());
+    }
+
+    return S_OK;
+}
+
+HRESULT PullPin_WaitForStateChange(PullPin * This, DWORD dwMilliseconds)
+{
+    if (WaitForSingleObject(This->hEventStateChanged, dwMilliseconds) == WAIT_TIMEOUT)
+        return S_FALSE;
+    return S_OK;
+}
+
+HRESULT PullPin_Seek(PullPin * This, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop)
+{
+    FIXME("(%lx%08lx, %lx%08lx)\n", (LONG)(rtStart >> 32), (LONG)rtStart, (LONG)(rtStop >> 32), (LONG)rtStop);
+
+    PullPin_BeginFlush((IPin *)This);
+    /* FIXME: need critical section? */
+    This->rtStart = rtStart;
+    This->rtStop = rtStop;
+    PullPin_EndFlush((IPin *)This);
+
+    return S_OK;
+}
+
+HRESULT WINAPI PullPin_EndOfStream(IPin * iface)
+{
+    FIXME("()\n");
+    return E_NOTIMPL;
+}
+
+HRESULT WINAPI PullPin_BeginFlush(IPin * iface)
+{
+    FIXME("()\n");
+    return E_NOTIMPL;
+}
+
+HRESULT WINAPI PullPin_EndFlush(IPin * iface)
+{
+    FIXME("()\n");
+    return E_NOTIMPL;
+}
+
+HRESULT WINAPI PullPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
+{
+    FIXME("()\n");
+    return E_NOTIMPL;
+}
+
+static const IPinVtbl PullPin_Vtbl = 
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    PullPin_QueryInterface,
+    IPinImpl_AddRef,
+    PullPin_Release,
+    OutputPin_Connect,
+    PullPin_ReceiveConnection,
+    IPinImpl_Disconnect,
+    IPinImpl_ConnectedTo,
+    IPinImpl_ConnectionMediaType,
+    IPinImpl_QueryPinInfo,
+    IPinImpl_QueryDirection,
+    IPinImpl_QueryId,
+    IPinImpl_QueryAccept,
+    IPinImpl_EnumMediaTypes,
+    IPinImpl_QueryInternalConnections,
+    PullPin_EndOfStream,
+    PullPin_BeginFlush,
+    PullPin_EndFlush,
+    PullPin_NewSegment
 };
Index: wine/dlls/quartz/pin.h
===================================================================
RCS file: /home/wine/wine/dlls/quartz/pin.h,v
retrieving revision 1.1
diff -u -r1.1 pin.h
--- wine/dlls/quartz/pin.h	6 Aug 2003 22:04:45 -0000	1.1
+++ wine/dlls/quartz/pin.h	25 Sep 2003 22:00:28 -0000
@@ -29,6 +29,12 @@
  */
 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;
@@ -38,7 +44,7 @@
 	IPin * pConnectedTo;
 	AM_MEDIA_TYPE mtCurrent;
 	ENUMMEDIADETAILS enumMediaDetails;
-	QUERYACCEPTPROC pQueryAccept;
+	QUERYACCEPTPROC fnQueryAccept;
 	LPVOID pUserData;
 } IPinImpl;
 
@@ -49,7 +55,7 @@
 
 	const IMemInputPinVtbl * lpVtblMemInput;
 	IMemAllocator * pAllocator;
-	SAMPLEPROC pSampleProc;
+	SAMPLEPROC fnSampleProc;
 	REFERENCE_TIME tStart;
 	REFERENCE_TIME tStop;
 	double dRate;
@@ -62,14 +68,33 @@
 
 	IMemInputPin * pMemInputPin;
 	HRESULT (* pConnectSpecific)(IPin * iface, IPin * pReceiver, const AM_MEDIA_TYPE * pmt);
+	ALLOCATOR_PROPERTIES allocProps;
 } OutputPin;
 
+typedef struct PullPin
+{
+	/* inheritance C style! */
+	IPinImpl pin;
+
+	IAsyncReader * pReader;
+	IMemAllocator * pAlloc;
+	SAMPLEPROC fnSampleProc;
+	PRECONNECTPROC fnPreConnect;
+	HANDLE hThread;
+	HANDLE hEventStateChanged;
+	REFERENCE_TIME rtStart;
+	REFERENCE_TIME rtStop;
+} PullPin;
+
 /*** Initializers ***/
 HRESULT InputPin_Init(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, InputPin * pPinImpl);
-HRESULT OutputPin_Init(const PIN_INFO * pPinInfo, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, OutputPin * pPinImpl);
+HRESULT OutputPin_Init(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, OutputPin * pPinImpl);
+HRESULT PullPin_Init(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, PullPin * pPinImpl);
 
 /*** Constructors ***/
 HRESULT InputPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin);
+HRESULT OutputPin_Construct(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin);
+HRESULT PullPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin);
 
 /**************************/
 /*** Pin Implementation ***/
@@ -100,12 +125,19 @@
 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_GetDeliveryBuffer(OutputPin * This, IMediaSample ** ppSample, const REFERENCE_TIME * tStart, const REFERENCE_TIME * tStop, DWORD dwFlags);
+HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample);
+HRESULT OutputPin_DeliverDisconnect(OutputPin * This);
+HRESULT OutputPin_DeliverNewSegment(OutputPin * This, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate);
+
 /**********************************/
 /*** MemInputPin Implementation ***/
 
@@ -118,3 +150,18 @@
 HRESULT WINAPI MemInputPin_Receive(IMemInputPin * iface, IMediaSample * pSample);
 HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin * iface, IMediaSample ** pSamples, long nSamples, long *nSamplesProcessed);
 HRESULT WINAPI MemInputPin_ReceiveCanBlock(IMemInputPin * iface);
+
+/* Pull Pin */
+HRESULT WINAPI PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt);
+HRESULT WINAPI PullPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv);
+ULONG   WINAPI PullPin_Release(IPin * iface);
+HRESULT PullPin_InitProcessing(PullPin * This);
+HRESULT PullPin_StartProcessing(PullPin * This);
+HRESULT PullPin_StopProcessing(PullPin * This);
+HRESULT PullPin_PauseProcessing(PullPin * This);
+HRESULT PullPin_Seek(PullPin * This, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop);
+HRESULT WINAPI PullPin_EndOfStream(IPin * iface);
+HRESULT WINAPI PullPin_BeginFlush(IPin * iface);
+HRESULT WINAPI PullPin_EndFlush(IPin * iface);
+HRESULT WINAPI PullPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate);
+HRESULT PullPin_WaitForStateChange(PullPin * This, DWORD dwMilliseconds);
Index: wine/dlls/quartz/quartz_private.h
===================================================================
RCS file: /home/wine/wine/dlls/quartz/quartz_private.h,v
retrieving revision 1.12
diff -u -r1.12 quartz_private.h
--- wine/dlls/quartz/quartz_private.h	11 Sep 2003 21:18:36 -0000	1.12
+++ wine/dlls/quartz/quartz_private.h	25 Sep 2003 22:00:28 -0000
@@ -32,6 +32,11 @@
 #include "winuser.h"
 #include "dshow.h"
 
+#define MEDIATIME_FROM_BYTES(x) ((LONGLONG)(x) * 10000000)
+#define SEC_FROM_MEDIATIME(time) ((time) / 10000000)
+#define BYTES_FROM_MEDIATIME(time) SEC_FROM_MEDIATIME(time)
+#define MSEC_FROM_MEDIATIME(time) ((time) / 10000)
+
 HRESULT FILTERGRAPH_create(IUnknown *pUnkOuter, LPVOID *ppObj) ;
 HRESULT FilterMapper2_create(IUnknown *pUnkOuter, LPVOID *ppObj);
 HRESULT AsyncReader_create(IUnknown * pUnkOuter, LPVOID * ppv);

[Index of Archives]     [Gimp for Windows]     [Red Hat]     [Samba]     [Yosemite Camping]     [Graphics Cards]     [Wine Home]

  Powered by Linux