[QUARTZ] Added parser template and made AVISplitter use it.

Christian Costa titan.costa at wanadoo.fr
Mon Feb 7 15:09:43 CST 2005


Hi,

Changelog:
Added parser template and made AVISplitter use it.

Christian Costa   titan.costa at wanadoo.fr

-------------- next part --------------
Index: dlls/quartz/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/quartz/Makefile.in,v
retrieving revision 1.42
diff -u -r1.42 Makefile.in
--- dlls/quartz/Makefile.in	1 Feb 2005 14:22:00 -0000	1.42
+++ dlls/quartz/Makefile.in	7 Feb 2005 19:54:35 -0000
@@ -22,6 +22,7 @@
 	filtermapper.c \
 	main.c \
 	memallocator.c \
+	parser.c \
 	pin.c \
 	regsvr.c \
 	systemclock.c \
Index: dlls/quartz/avisplit.c
===================================================================
RCS file: /home/wine/wine/dlls/quartz/avisplit.c,v
retrieving revision 1.12
diff -u -r1.12 avisplit.c
--- dlls/quartz/avisplit.c	6 Jan 2005 19:36:47 -0000	1.12
+++ dlls/quartz/avisplit.c	7 Feb 2005 19:54:39 -0000
@@ -2,6 +2,7 @@
  * AVI Splitter Filter
  *
  * Copyright 2003 Robert Shearman
+ * Copyright 2004-2005 Christian Costa
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -40,460 +41,19 @@
 #include <math.h>
 #include <assert.h>
 
-WINE_DEFAULT_DEBUG_CHANNEL(quartz);
-
-static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
-static const struct IBaseFilterVtbl AVISplitter_Vtbl;
-static const struct IMediaSeekingVtbl AVISplitter_Seeking_Vtbl;
-static const struct IPinVtbl AVISplitter_OutputPin_Vtbl;
-static const struct IPinVtbl AVISplitter_InputPin_Vtbl;
-
-static HRESULT AVISplitter_Sample(LPVOID iface, IMediaSample * pSample);
-static HRESULT AVISplitter_OutputPin_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt);
-static HRESULT AVISplitter_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt);
-static HRESULT AVISplitter_InputPin_PreConnect(IPin * iface, IPin * pConnectPin);
-static HRESULT AVISplitter_ChangeStart(LPVOID iface);
-static HRESULT AVISplitter_ChangeStop(LPVOID iface);
-static HRESULT AVISplitter_ChangeRate(LPVOID iface);
+#include "parser.h"
 
-static HRESULT AVISplitter_InputPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin);
+WINE_DEFAULT_DEBUG_CHANNEL(quartz);
 
-typedef struct AVISplitter
+typedef struct AVISplitterImpl
 {
-    const IBaseFilterVtbl * lpVtbl;
-
-    ULONG refCount;
-    CRITICAL_SECTION csFilter;
-    FILTER_STATE state;
-    REFERENCE_TIME rtStreamStart;
-    IReferenceClock * pClock;
-    FILTER_INFO filterInfo;
-
-    PullPin * pInputPin;
-    ULONG cStreams;
-    IPin ** ppPins;
+    ParserImpl Parser;
     IMediaSample * pCurrentSample;
     RIFFCHUNK CurrentChunk;
     LONGLONG CurrentChunkOffset; /* in media time */
     LONGLONG EndOfFile;
     AVIMAINHEADER AviHeader;
-} AVISplitter;
-
-typedef struct AVISplitter_OutputPin
-{
-    OutputPin pin;
-
-    AM_MEDIA_TYPE * pmt;
-    float fSamplesPerSec;
-    DWORD dwSamplesProcessed;
-    DWORD dwSampleSize;
-    DWORD dwLength;
-    MediaSeekingImpl mediaSeeking;
-} AVISplitter_OutputPin;
-
-
-#define _IMediaSeeking_Offset ((int)(&(((AVISplitter_OutputPin*)0)->mediaSeeking)))
-#define ICOM_THIS_From_IMediaSeeking(impl, iface) impl* This = (impl*)(((char*)iface)-_IMediaSeeking_Offset);
-
-HRESULT AVISplitter_create(IUnknown * pUnkOuter, LPVOID * ppv)
-{
-    HRESULT hr;
-    PIN_INFO piInput;
-    AVISplitter * pAviSplit;
-
-    TRACE("(%p, %p)\n", pUnkOuter, ppv);
-
-    *ppv = NULL;
-
-    if (pUnkOuter)
-        return CLASS_E_NOAGGREGATION;
-    
-    pAviSplit = CoTaskMemAlloc(sizeof(AVISplitter));
-
-    pAviSplit->lpVtbl = &AVISplitter_Vtbl;
-    pAviSplit->refCount = 1;
-    InitializeCriticalSection(&pAviSplit->csFilter);
-    pAviSplit->state = State_Stopped;
-    pAviSplit->pClock = NULL;
-    pAviSplit->pCurrentSample = NULL;
-    ZeroMemory(&pAviSplit->filterInfo, sizeof(FILTER_INFO));
-
-    pAviSplit->cStreams = 0;
-    pAviSplit->ppPins = CoTaskMemAlloc(1 * sizeof(IPin *));
-
-    /* construct input pin */
-    piInput.dir = PINDIR_INPUT;
-    piInput.pFilter = (IBaseFilter *)pAviSplit;
-    strncpyW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
-
-    hr = AVISplitter_InputPin_Construct(&piInput, AVISplitter_Sample, (LPVOID)pAviSplit, AVISplitter_QueryAccept, &pAviSplit->csFilter, (IPin **)&pAviSplit->pInputPin);
-
-    if (SUCCEEDED(hr))
-    {
-        pAviSplit->ppPins[0] = (IPin *)pAviSplit->pInputPin;
-        pAviSplit->pInputPin->fnPreConnect = AVISplitter_InputPin_PreConnect;
-        *ppv = (LPVOID)pAviSplit;
-    }
-    else
-    {
-        CoTaskMemFree(pAviSplit->ppPins);
-        DeleteCriticalSection(&pAviSplit->csFilter);
-        CoTaskMemFree(pAviSplit);
-    }
-
-    return hr;
-}
-
-static HRESULT AVISplitter_OutputPin_Init(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES * props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, const AM_MEDIA_TYPE * pmt, float fSamplesPerSec, LPCRITICAL_SECTION pCritSec, AVISplitter_OutputPin * pPinImpl)
-{
-    pPinImpl->pmt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
-    CopyMediaType(pPinImpl->pmt, pmt);
-    pPinImpl->dwSamplesProcessed = 0;
-    pPinImpl->dwSampleSize = 0;
-    pPinImpl->fSamplesPerSec = fSamplesPerSec;
-
-    MediaSeekingImpl_Init((LPVOID)pPinInfo->pFilter, AVISplitter_ChangeStop, AVISplitter_ChangeStart, AVISplitter_ChangeRate, &pPinImpl->mediaSeeking);
-    pPinImpl->mediaSeeking.lpVtbl = &AVISplitter_Seeking_Vtbl;
-
-    return OutputPin_Init(pPinInfo, props, pUserData, pQueryAccept, pCritSec, &pPinImpl->pin);
-}
-
-static HRESULT AVISplitter_OutputPin_Construct(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES * props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, const AM_MEDIA_TYPE * pmt, float fSamplesPerSec, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
-{
-    AVISplitter_OutputPin * pPinImpl;
-
-    *ppPin = NULL;
-
-    assert(pPinInfo->dir == PINDIR_OUTPUT);
-
-    pPinImpl = CoTaskMemAlloc(sizeof(AVISplitter_OutputPin));
-
-    if (!pPinImpl)
-        return E_OUTOFMEMORY;
-
-    if (SUCCEEDED(AVISplitter_OutputPin_Init(pPinInfo, props, pUserData, pQueryAccept, pmt, fSamplesPerSec, pCritSec, pPinImpl)))
-    {
-        pPinImpl->pin.pin.lpVtbl = &AVISplitter_OutputPin_Vtbl;
-        
-        *ppPin = (IPin *)pPinImpl;
-        return S_OK;
-    }
-    return E_FAIL;
-}
-
-static HRESULT WINAPI AVISplitter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
-{
-    AVISplitter *This = (AVISplitter *)iface;
-    TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
-
-    *ppv = NULL;
-
-    if (IsEqualIID(riid, &IID_IUnknown))
-        *ppv = (LPVOID)This;
-    else if (IsEqualIID(riid, &IID_IPersist))
-        *ppv = (LPVOID)This;
-    else if (IsEqualIID(riid, &IID_IMediaFilter))
-        *ppv = (LPVOID)This;
-    else if (IsEqualIID(riid, &IID_IBaseFilter))
-        *ppv = (LPVOID)This;
-
-    if (*ppv)
-    {
-        IUnknown_AddRef((IUnknown *)(*ppv));
-        return S_OK;
-    }
-
-    FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
-
-    return E_NOINTERFACE;
-}
-
-static ULONG WINAPI AVISplitter_AddRef(IBaseFilter * iface)
-{
-    AVISplitter *This = (AVISplitter *)iface;
-    ULONG refCount = InterlockedIncrement(&This->refCount);
-
-    TRACE("(%p/%p)->() AddRef from %ld\n", This, iface, refCount - 1);
-
-    return refCount;
-}
-
-static ULONG WINAPI AVISplitter_Release(IBaseFilter * iface)
-{
-    AVISplitter *This = (AVISplitter *)iface;
-    ULONG refCount = InterlockedDecrement(&This->refCount);
-
-    TRACE("(%p/%p)->() Release from %ld\n", This, iface, refCount + 1);
-    
-    if (!refCount)
-    {
-        ULONG i;
-
-        DeleteCriticalSection(&This->csFilter);
-        if (This->pClock)
-            IReferenceClock_Release(This->pClock);
-        
-        for (i = 0; i < This->cStreams + 1; i++)
-            IPin_Release(This->ppPins[i]);
-        
-        HeapFree(GetProcessHeap(), 0, This->ppPins);
-        This->lpVtbl = NULL;
-        
-        TRACE("Destroying AVI splitter\n");
-        CoTaskMemFree(This);
-        
-        return 0;
-    }
-    else
-        return refCount;
-}
-
-/** IPersist methods **/
-
-static HRESULT WINAPI AVISplitter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
-{
-    TRACE("(%p)\n", pClsid);
-
-    *pClsid = CLSID_AviSplitter;
-
-    return S_OK;
-}
-
-/** IMediaFilter methods **/
-
-static HRESULT WINAPI AVISplitter_Stop(IBaseFilter * iface)
-{
-    HRESULT hr;
-    AVISplitter *This = (AVISplitter *)iface;
-
-    TRACE("()\n");
-
-    EnterCriticalSection(&This->csFilter);
-    {
-        hr = PullPin_StopProcessing(This->pInputPin);
-        This->state = State_Stopped;
-    }
-    LeaveCriticalSection(&This->csFilter);
-    
-    return hr;
-}
-
-static HRESULT WINAPI AVISplitter_Pause(IBaseFilter * iface)
-{
-    HRESULT hr = S_OK;
-    BOOL bInit;
-    AVISplitter *This = (AVISplitter *)iface;
-    
-    TRACE("()\n");
-
-    EnterCriticalSection(&This->csFilter);
-    {
-        bInit = (This->state == State_Stopped);
-        This->state = State_Paused;
-    }
-    LeaveCriticalSection(&This->csFilter);
-
-    if (bInit)
-    {
-        unsigned int i;
-
-        hr = PullPin_Seek(This->pInputPin, This->CurrentChunkOffset, This->EndOfFile);
-
-        if (SUCCEEDED(hr))
-            hr = PullPin_InitProcessing(This->pInputPin);
-
-        if (SUCCEEDED(hr))
-        {
-            for (i = 1; i < This->cStreams + 1; i++)
-            {
-                AVISplitter_OutputPin* StreamPin = (AVISplitter_OutputPin *)This->ppPins[i];
-                OutputPin_DeliverNewSegment((OutputPin *)This->ppPins[i], 0, (LONGLONG)ceil(10000000.0 * (float)StreamPin->dwLength / StreamPin->fSamplesPerSec), 1.0);
-                StreamPin->mediaSeeking.llDuration = (LONGLONG)ceil(10000000.0 * (float)StreamPin->dwLength / StreamPin->fSamplesPerSec);
-                StreamPin->mediaSeeking.llStop = (LONGLONG)ceil(10000000.0 * (float)StreamPin->dwLength / StreamPin->fSamplesPerSec);
-                OutputPin_CommitAllocator((OutputPin *)This->ppPins[i]);
-            }
-
-            /* FIXME: this is a little hacky: we have to deliver (at least?) one sample
-             * to each renderer before they will complete their transitions. We should probably
-             * seek through the stream for the first of each, rather than do it this way which is
-             * probably a bit prone to deadlocking */
-            hr = PullPin_StartProcessing(This->pInputPin);
-        }
-    }
-    /* FIXME: else pause thread */
-
-    return hr;
-}
-
-static HRESULT WINAPI AVISplitter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
-{
-    HRESULT hr = S_OK;
-    AVISplitter *This = (AVISplitter *)iface;
-    int i;
-
-    TRACE("(%s)\n", wine_dbgstr_longlong(tStart));
-
-    EnterCriticalSection(&This->csFilter);
-    {
-        This->rtStreamStart = tStart;
-        This->state = State_Running;
-
-        hr = PullPin_InitProcessing(This->pInputPin);
-
-        if (SUCCEEDED(hr))
-        { 
-            for (i = 1; i < This->cStreams + 1; i++)
-            {
-                OutputPin_CommitAllocator((OutputPin *)This->ppPins[i]);
-            }
-            hr = PullPin_StartProcessing(This->pInputPin);
-        }
-    }
-    LeaveCriticalSection(&This->csFilter);
-
-    return hr;
-}
-
-static HRESULT WINAPI AVISplitter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
-{
-    AVISplitter *This = (AVISplitter *)iface;
-
-    TRACE("(%ld, %p)\n", dwMilliSecsTimeout, pState);
-
-    EnterCriticalSection(&This->csFilter);
-    {
-        *pState = This->state;
-    }
-    LeaveCriticalSection(&This->csFilter);
-
-    /* FIXME: this is a little bit unsafe, but I don't see that we can do this
-     * while in the critical section. Maybe we could copy the pointer and addref in the
-     * critical section and then release after this.
-     */
-    if (This->pInputPin && (PullPin_WaitForStateChange(This->pInputPin, dwMilliSecsTimeout) == S_FALSE))
-        return VFW_S_STATE_INTERMEDIATE;
-
-    return S_OK;
-}
-
-static HRESULT WINAPI AVISplitter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
-{
-    AVISplitter *This = (AVISplitter *)iface;
-
-    TRACE("(%p)\n", pClock);
-
-    EnterCriticalSection(&This->csFilter);
-    {
-        if (This->pClock)
-            IReferenceClock_Release(This->pClock);
-        This->pClock = pClock;
-        if (This->pClock)
-            IReferenceClock_AddRef(This->pClock);
-    }
-    LeaveCriticalSection(&This->csFilter);
-
-    return S_OK;
-}
-
-static HRESULT WINAPI AVISplitter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
-{
-    AVISplitter *This = (AVISplitter *)iface;
-
-    TRACE("(%p)\n", ppClock);
-
-    EnterCriticalSection(&This->csFilter);
-    {
-        *ppClock = This->pClock;
-        if (This->pClock)
-            IReferenceClock_AddRef(This->pClock);
-    }
-    LeaveCriticalSection(&This->csFilter);
-    
-    return S_OK;
-}
-
-/** IBaseFilter implementation **/
-
-static HRESULT WINAPI AVISplitter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
-{
-    ENUMPINDETAILS epd;
-    AVISplitter *This = (AVISplitter *)iface;
-
-    TRACE("(%p)\n", ppEnum);
-
-    epd.cPins = This->cStreams + 1; /* +1 for input pin */
-    epd.ppPins = This->ppPins;
-    return IEnumPinsImpl_Construct(&epd, ppEnum);
-}
-
-static HRESULT WINAPI AVISplitter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
-{
-    FIXME("AVISplitter::FindPin(...)\n");
-
-    /* FIXME: critical section */
-
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI AVISplitter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
-{
-    AVISplitter *This = (AVISplitter *)iface;
-
-    TRACE("(%p)\n", pInfo);
-
-    strcpyW(pInfo->achName, This->filterInfo.achName);
-    pInfo->pGraph = This->filterInfo.pGraph;
-
-    if (pInfo->pGraph)
-        IFilterGraph_AddRef(pInfo->pGraph);
-    
-    return S_OK;
-}
-
-static HRESULT WINAPI AVISplitter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
-{
-    HRESULT hr = S_OK;
-    AVISplitter *This = (AVISplitter *)iface;
-
-    TRACE("(%p, %s)\n", pGraph, debugstr_w(pName));
-
-    EnterCriticalSection(&This->csFilter);
-    {
-        if (pName)
-            strcpyW(This->filterInfo.achName, pName);
-        else
-            *This->filterInfo.achName = '\0';
-        This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
-    }
-    LeaveCriticalSection(&This->csFilter);
-
-    return hr;
-}
-
-static HRESULT WINAPI AVISplitter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
-{
-    TRACE("(%p)\n", pVendorInfo);
-    return E_NOTIMPL;
-}
-
-static const IBaseFilterVtbl AVISplitter_Vtbl =
-{
-    AVISplitter_QueryInterface,
-    AVISplitter_AddRef,
-    AVISplitter_Release,
-    AVISplitter_GetClassID,
-    AVISplitter_Stop,
-    AVISplitter_Pause,
-    AVISplitter_Run,
-    AVISplitter_GetState,
-    AVISplitter_SetSyncSource,
-    AVISplitter_GetSyncSource,
-    AVISplitter_EnumPins,
-    AVISplitter_FindPin,
-    AVISplitter_QueryFilterInfo,
-    AVISplitter_JoinFilterGraph,
-    AVISplitter_QueryVendorInfo
-};
+} AVISplitterImpl;
 
 static HRESULT AVISplitter_NextChunk(LONGLONG * pllCurrentChunkOffset, RIFFCHUNK * pCurrentChunk, const REFERENCE_TIME * tStart, const REFERENCE_TIME * tStop, const BYTE * pbSrcStream)
 {
@@ -514,7 +74,7 @@
 
 static HRESULT AVISplitter_Sample(LPVOID iface, IMediaSample * pSample)
 {
-    AVISplitter *This = (AVISplitter *)iface;
+    AVISplitterImpl *This = (AVISplitterImpl *)iface;
     LPBYTE pbSrcStream = NULL;
     long cbSrcStream = 0;
     REFERENCE_TIME tStart, tStop;
@@ -559,7 +119,7 @@
         long chunk_remaining_bytes = 0;
         long offset_src;
         WORD streamId;
-        AVISplitter_OutputPin * pOutputPin;
+        Parser_OutputPin * pOutputPin;
         BOOL bSyncPoint = TRUE;
 
         if (This->CurrentChunkOffset >= tStart)
@@ -617,13 +177,13 @@
 
         streamId = StreamFromFOURCC(This->CurrentChunk.fcc);
 
-        if (streamId > This->cStreams)
+        if (streamId > This->Parser.cStreams)
         {
-            ERR("Corrupted AVI file (contains stream id %d, but supposed to only have %ld streams)\n", streamId, This->cStreams);
+            ERR("Corrupted AVI file (contains stream id %d, but supposed to only have %ld streams)\n", streamId, This->Parser.cStreams);
             return E_FAIL;
         }
 
-        pOutputPin = (AVISplitter_OutputPin *)This->ppPins[streamId + 1];
+        pOutputPin = (Parser_OutputPin *)This->Parser.ppPins[streamId + 1];
 
         if (!This->pCurrentSample)
         {
@@ -726,11 +286,10 @@
     return S_FALSE;
 }
 
-static HRESULT AVISplitter_ProcessStreamList(AVISplitter * This, const BYTE * pData, DWORD cb)
+static HRESULT AVISplitter_ProcessStreamList(AVISplitterImpl * This, const BYTE * pData, DWORD cb)
 {
     PIN_INFO piOutput;
     const RIFFCHUNK * pChunk;
-    IPin ** ppOldPins;
     HRESULT hr;
     AM_MEDIA_TYPE amt;
     float fSamplesPerSec = 0.0f;
@@ -747,7 +306,7 @@
     ZeroMemory(&amt, sizeof(amt));
     piOutput.dir = PINDIR_OUTPUT;
     piOutput.pFilter = (IBaseFilter *)This;
-    wsprintfW(piOutput.achName, wszStreamTemplate, This->cStreams);
+    wsprintfW(piOutput.achName, wszStreamTemplate, This->Parser.cStreams);
 
     for (pChunk = (const RIFFCHUNK *)pData; 
          ((const BYTE *)pChunk >= pData) && ((const BYTE *)pChunk + sizeof(RIFFCHUNK) < pData + cb) && (pChunk->cb > 0); 
@@ -858,54 +417,11 @@
     TRACE("dwSampleSize = %lx\n", dwSampleSize);
     TRACE("dwLength = %lx\n", dwLength);
 
-    ppOldPins = This->ppPins;
-
-    This->ppPins = HeapAlloc(GetProcessHeap(), 0, (This->cStreams + 2) * sizeof(IPin *));
-    memcpy(This->ppPins, ppOldPins, (This->cStreams + 1) * sizeof(IPin *));
-
-    hr = AVISplitter_OutputPin_Construct(&piOutput, &props, NULL, AVISplitter_OutputPin_QueryAccept, &amt, fSamplesPerSec, &This->csFilter, This->ppPins + This->cStreams + 1);
-
-    if (SUCCEEDED(hr))
-    {
-        ((AVISplitter_OutputPin *)(This->ppPins[This->cStreams + 1]))->dwSampleSize = dwSampleSize;
-        ((AVISplitter_OutputPin *)(This->ppPins[This->cStreams + 1]))->dwLength = dwLength;
-        ((AVISplitter_OutputPin *)(This->ppPins[This->cStreams + 1]))->pin.pin.pUserData = (LPVOID)This->ppPins[This->cStreams + 1];
-        This->cStreams++;
-        HeapFree(GetProcessHeap(), 0, ppOldPins);
-    }
-    else
-    {
-        HeapFree(GetProcessHeap(), 0, This->ppPins);
-        This->ppPins = ppOldPins;
-        ERR("Failed with error %lx\n", hr);
-    }
+    hr = Parser_AddPin(&(This->Parser), &piOutput, &props, &amt, fSamplesPerSec, dwSampleSize, dwLength);
 
     return hr;
 }
 
-static HRESULT AVISplitter_RemoveOutputPins(AVISplitter * This)
-{
-    /* NOTE: should be in critical section when calling this function */
-
-    ULONG i;
-    IPin ** ppOldPins = This->ppPins;
-
-    /* reduce the pin array down to 1 (just our input pin) */
-    This->ppPins = HeapAlloc(GetProcessHeap(), 0, sizeof(IPin *) * 1);
-    memcpy(This->ppPins, ppOldPins, sizeof(IPin *) * 1);
-
-    for (i = 0; i < This->cStreams; i++)
-    {
-        OutputPin_DeliverDisconnect((OutputPin *)ppOldPins[i + 1]);
-        IPin_Release(ppOldPins[i + 1]);
-    }
-
-    This->cStreams = 0;
-    HeapFree(GetProcessHeap(), 0, ppOldPins);
-
-    return S_OK;
-}
-
 /* FIXME: fix leaks on failure here */
 static HRESULT AVISplitter_InputPin_PreConnect(IPin * iface, IPin * pConnectPin)
 {
@@ -915,7 +431,7 @@
     LONGLONG pos = 0; /* in bytes */
     BYTE * pBuffer;
     RIFFCHUNK * pCurrentChunk;
-    AVISplitter * pAviSplit = (AVISplitter *)This->pin.pinInfo.pFilter;
+    AVISplitterImpl * pAviSplit = (AVISplitterImpl *)This->pin.pinInfo.pFilter;
 
     hr = IAsyncReader_SyncRead(This->pReader, pos, sizeof(list), (BYTE *)&list);
     pos += sizeof(list);
@@ -1025,237 +541,29 @@
     return hr;
 }
 
-static HRESULT AVISplitter_ChangeStart(LPVOID iface)
-{
-    FIXME("(%p)\n", iface);
-    return S_OK;
-}
-
-static HRESULT AVISplitter_ChangeStop(LPVOID iface)
-{
-    FIXME("(%p)\n", iface);
-    return S_OK;
-}
-
-static HRESULT AVISplitter_ChangeRate(LPVOID iface)
-{
-    FIXME("(%p)\n", iface);
-    return S_OK;
-}
-
-
-static HRESULT WINAPI AVISplitter_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv)
-{
-    ICOM_THIS_From_IMediaSeeking(AVISplitter_OutputPin, iface);
-
-    return IUnknown_QueryInterface((IUnknown *)This, riid, ppv);
-}
-
-static ULONG WINAPI AVISplitter_Seeking_AddRef(IMediaSeeking * iface)
-{
-    ICOM_THIS_From_IMediaSeeking(AVISplitter_OutputPin, iface);
-
-    return IUnknown_AddRef((IUnknown *)This);
-}
-
-static ULONG WINAPI AVISplitter_Seeking_Release(IMediaSeeking * iface)
-{
-    ICOM_THIS_From_IMediaSeeking(AVISplitter_OutputPin, iface);
-
-    return IUnknown_Release((IUnknown *)This);
-}
-
-static const IMediaSeekingVtbl AVISplitter_Seeking_Vtbl =
-{
-    AVISplitter_Seeking_QueryInterface,
-    AVISplitter_Seeking_AddRef,
-    AVISplitter_Seeking_Release,
-    MediaSeekingImpl_GetCapabilities,
-    MediaSeekingImpl_CheckCapabilities,
-    MediaSeekingImpl_IsFormatSupported,
-    MediaSeekingImpl_QueryPreferredFormat,
-    MediaSeekingImpl_GetTimeFormat,
-    MediaSeekingImpl_IsUsingTimeFormat,
-    MediaSeekingImpl_SetTimeFormat,
-    MediaSeekingImpl_GetDuration,
-    MediaSeekingImpl_GetStopPosition,
-    MediaSeekingImpl_GetCurrentPosition,
-    MediaSeekingImpl_ConvertTimeFormat,
-    MediaSeekingImpl_SetPositions,
-    MediaSeekingImpl_GetPositions,
-    MediaSeekingImpl_GetAvailable,
-    MediaSeekingImpl_SetRate,
-    MediaSeekingImpl_GetRate,
-    MediaSeekingImpl_GetPreroll
-};
-
-HRESULT WINAPI AVISplitter_OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
+HRESULT AVISplitter_create(IUnknown * pUnkOuter, LPVOID * ppv)
 {
-    AVISplitter_OutputPin *This = (AVISplitter_OutputPin *)iface;
+    HRESULT hr;
+    AVISplitterImpl * This;
 
-    TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
+    TRACE("(%p, %p)\n", pUnkOuter, ppv);
 
     *ppv = NULL;
 
-    if (IsEqualIID(riid, &IID_IUnknown))
-        *ppv = (LPVOID)iface;
-    else if (IsEqualIID(riid, &IID_IPin))
-        *ppv = (LPVOID)iface;
-    else if (IsEqualIID(riid, &IID_IMediaSeeking))
-        *ppv = (LPVOID)&This->mediaSeeking;
-
-    if (*ppv)
-    {
-        IUnknown_AddRef((IUnknown *)(*ppv));
-        return S_OK;
-    }
-
-    FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
-
-    return E_NOINTERFACE;
-}
-
-static ULONG WINAPI AVISplitter_OutputPin_Release(IPin * iface)
-{
-    AVISplitter_OutputPin *This = (AVISplitter_OutputPin *)iface;
-    ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount);
-    
-    TRACE("()\n");
-    
-    if (!refCount)
-    {
-        DeleteMediaType(This->pmt);
-        CoTaskMemFree(This->pmt);
-        DeleteMediaType(&This->pin.pin.mtCurrent);
-        CoTaskMemFree(This);
-        return 0;
-    }
-    return refCount;
-}
-
-static HRESULT WINAPI AVISplitter_OutputPin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
-{
-    ENUMMEDIADETAILS emd;
-    AVISplitter_OutputPin *This = (AVISplitter_OutputPin *)iface;
-
-    TRACE("(%p)\n", ppEnum);
-
-    /* override this method to allow enumeration of your types */
-    emd.cMediaTypes = 1;
-    emd.pMediaTypes = This->pmt;
-
-    return IEnumMediaTypesImpl_Construct(&emd, ppEnum);
-}
-
-static HRESULT AVISplitter_OutputPin_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
-{
-    AVISplitter_OutputPin *This = (AVISplitter_OutputPin *)iface;
-
-    TRACE("()\n");
-    dump_AM_MEDIA_TYPE(pmt);
-
-    return (memcmp(This->pmt, pmt, sizeof(AM_MEDIA_TYPE)) == 0);
-}
-
-static const IPinVtbl AVISplitter_OutputPin_Vtbl = 
-{
-    AVISplitter_OutputPin_QueryInterface,
-    IPinImpl_AddRef,
-    AVISplitter_OutputPin_Release,
-    OutputPin_Connect,
-    OutputPin_ReceiveConnection,
-    OutputPin_Disconnect,
-    IPinImpl_ConnectedTo,
-    IPinImpl_ConnectionMediaType,
-    IPinImpl_QueryPinInfo,
-    IPinImpl_QueryDirection,
-    IPinImpl_QueryId,
-    IPinImpl_QueryAccept,
-    AVISplitter_OutputPin_EnumMediaTypes,
-    IPinImpl_QueryInternalConnections,
-    OutputPin_EndOfStream,
-    OutputPin_BeginFlush,
-    OutputPin_EndFlush,
-    OutputPin_NewSegment
-};
+    if (pUnkOuter)
+        return CLASS_E_NOAGGREGATION;
 
-static HRESULT AVISplitter_InputPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
-{
-    PullPin * pPinImpl;
+    /* Note: This memory is managed by the transform filter once created */
+    This = CoTaskMemAlloc(sizeof(AVISplitterImpl));
 
-    *ppPin = NULL;
+    This->pCurrentSample = NULL;
 
-    if (pPinInfo->dir != PINDIR_INPUT)
-    {
-        ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir);
-        return E_INVALIDARG;
-    }
+    hr = Parser_Create(&(This->Parser), &CLSID_AviSplitter, AVISplitter_Sample, AVISplitter_QueryAccept, AVISplitter_InputPin_PreConnect);
 
-    pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
+    if (FAILED(hr))
+        return hr;
 
-    if (!pPinImpl)
-        return E_OUTOFMEMORY;
+    *ppv = (LPVOID)This;
 
-    if (SUCCEEDED(PullPin_Init(pPinInfo, pSampleProc, pUserData, pQueryAccept, pCritSec, pPinImpl)))
-    {
-        pPinImpl->pin.lpVtbl = &AVISplitter_InputPin_Vtbl;
-        
-        *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
-        return S_OK;
-    }
-    return E_FAIL;
-}
-
-static HRESULT WINAPI AVISplitter_InputPin_Disconnect(IPin * iface)
-{
-    HRESULT hr;
-    IPinImpl *This = (IPinImpl *)iface;
-
-    TRACE("()\n");
-
-    EnterCriticalSection(This->pCritSec);
-    {
-        if (This->pConnectedTo)
-        {
-            FILTER_STATE state;
-
-            hr = IBaseFilter_GetState(This->pinInfo.pFilter, 0, &state);
-
-            if (SUCCEEDED(hr) && (state == State_Stopped))
-            {
-                IPin_Release(This->pConnectedTo);
-                This->pConnectedTo = NULL;
-                hr = AVISplitter_RemoveOutputPins((AVISplitter *)This->pinInfo.pFilter);
-            }
-            else
-                hr = VFW_E_NOT_STOPPED;
-        }
-        else
-            hr = S_FALSE;
-    }
-    LeaveCriticalSection(This->pCritSec);
-    
     return hr;
 }
-
-static const IPinVtbl AVISplitter_InputPin_Vtbl =
-{
-    PullPin_QueryInterface,
-    IPinImpl_AddRef,
-    PullPin_Release,
-    OutputPin_Connect,
-    PullPin_ReceiveConnection,
-    AVISplitter_InputPin_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
-};
--- /dev/null	1970-01-01 01:00:00.000000000 +0100
+++ dlls/quartz/parser.h	2005-02-05 19:39:54.000000000 +0000
@@ -0,0 +1,57 @@
+/*
+ * Parser declarations
+ *
+ * Copyright 2005 Christian Costa
+ *
+ * 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
+ */
+
+typedef struct ParserImpl ParserImpl;
+
+typedef HRESULT (*PFN_PROCESS_SAMPLE) (LPVOID iface, IMediaSample * pSample);
+typedef HRESULT (*PFN_QUERY_ACCEPT) (LPVOID iface, const AM_MEDIA_TYPE * pmt);
+typedef HRESULT (*PFN_PRE_CONNECT) (IPin * iface, IPin * pConnectPin);
+
+struct ParserImpl
+{
+    const IBaseFilterVtbl * lpVtbl;
+
+    ULONG refCount;
+    CRITICAL_SECTION csFilter;
+    FILTER_STATE state;
+    REFERENCE_TIME rtStreamStart;
+    IReferenceClock * pClock;
+    FILTER_INFO filterInfo;
+    CLSID clsid;
+
+    PullPin * pInputPin;
+    IPin ** ppPins;
+    ULONG cStreams;
+};
+
+typedef struct Parser_OutputPin
+{
+    OutputPin pin;
+
+    AM_MEDIA_TYPE * pmt;
+    float fSamplesPerSec;
+    DWORD dwSamplesProcessed;
+    DWORD dwSampleSize;
+    DWORD dwLength;
+    MediaSeekingImpl mediaSeeking;
+} Parser_OutputPin;
+
+HRESULT Parser_AddPin(ParserImpl * This, PIN_INFO * piOutput, ALLOCATOR_PROPERTIES * props, AM_MEDIA_TYPE * amt, float fSamplesPerSec, DWORD dwSampleSize, DWORD dwLength);
+HRESULT Parser_Create(ParserImpl*, const CLSID*, PFN_PROCESS_SAMPLE, PFN_QUERY_ACCEPT, PFN_PRE_CONNECT);
--- /dev/null	1970-01-01 01:00:00.000000000 +0100
+++ dlls/quartz/parser.c	2005-02-05 19:02:30.000000000 +0000
@@ -0,0 +1,737 @@
+/*
+ * Parser (Base for parsers and splitters)
+ *
+ * Copyright 2003 Robert Shearman
+ * Copyright 2004-2005 Christian Costa
+ *
+ * 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 "quartz_private.h"
+#include "control_private.h"
+#include "pin.h"
+
+#include "uuids.h"
+#include "aviriff.h"
+#include "mmreg.h"
+#include "vfwmsgs.h"
+#include "amvideo.h"
+
+#include "fourcc.h"
+
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+#include <math.h>
+#include <assert.h>
+
+#include "parser.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(quartz);
+
+static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
+static const struct IBaseFilterVtbl Parser_Vtbl;
+static const struct IMediaSeekingVtbl Parser_Seeking_Vtbl;
+static const struct IPinVtbl Parser_OutputPin_Vtbl;
+static const struct IPinVtbl Parser_InputPin_Vtbl;
+
+static HRESULT Parser_OutputPin_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt);
+static HRESULT Parser_ChangeStart(LPVOID iface);
+static HRESULT Parser_ChangeStop(LPVOID iface);
+static HRESULT Parser_ChangeRate(LPVOID iface);
+
+static HRESULT Parser_InputPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin);
+
+#define _IMediaSeeking_Offset ((int)(&(((Parser_OutputPin*)0)->mediaSeeking)))
+#define ICOM_THIS_From_IMediaSeeking(impl, iface) impl* This = (impl*)(((char*)iface)-_IMediaSeeking_Offset);
+
+HRESULT Parser_Create(ParserImpl* pParser, const CLSID* pClsid, PFN_PROCESS_SAMPLE fnProcessSample, PFN_QUERY_ACCEPT fnQueryAccept, PFN_PRE_CONNECT fnPreConnect)
+{
+    HRESULT hr;
+    PIN_INFO piInput;
+
+    /* pTransformFilter is already allocated */
+    pParser->clsid = *pClsid;
+
+    pParser->lpVtbl = &Parser_Vtbl;
+    pParser->refCount = 1;
+    InitializeCriticalSection(&pParser->csFilter);
+    pParser->state = State_Stopped;
+    pParser->pClock = NULL;
+    ZeroMemory(&pParser->filterInfo, sizeof(FILTER_INFO));
+
+    pParser->cStreams = 0;
+    pParser->ppPins = CoTaskMemAlloc(1 * sizeof(IPin *));
+
+    /* construct input pin */
+    piInput.dir = PINDIR_INPUT;
+    piInput.pFilter = (IBaseFilter *)pParser;
+    strncpyW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
+
+    hr = Parser_InputPin_Construct(&piInput, fnProcessSample, (LPVOID)pParser, fnQueryAccept, &pParser->csFilter, (IPin **)&pParser->pInputPin);
+
+    if (SUCCEEDED(hr))
+    {
+        pParser->ppPins[0] = (IPin *)pParser->pInputPin;
+        pParser->pInputPin->fnPreConnect = fnPreConnect;
+    }
+    else
+    {
+        CoTaskMemFree(pParser->ppPins);
+        DeleteCriticalSection(&pParser->csFilter);
+        CoTaskMemFree(pParser);
+    }
+
+    return hr;
+}
+
+static HRESULT Parser_OutputPin_Init(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES * props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, const AM_MEDIA_TYPE * pmt, float fSamplesPerSec, LPCRITICAL_SECTION pCritSec, Parser_OutputPin * pPinImpl)
+{
+    pPinImpl->pmt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
+    CopyMediaType(pPinImpl->pmt, pmt);
+    pPinImpl->dwSamplesProcessed = 0;
+    pPinImpl->dwSampleSize = 0;
+    pPinImpl->fSamplesPerSec = fSamplesPerSec;
+
+    MediaSeekingImpl_Init((LPVOID)pPinInfo->pFilter, Parser_ChangeStop, Parser_ChangeStart, Parser_ChangeRate, &pPinImpl->mediaSeeking);
+    pPinImpl->mediaSeeking.lpVtbl = &Parser_Seeking_Vtbl;
+
+    return OutputPin_Init(pPinInfo, props, pUserData, pQueryAccept, pCritSec, &pPinImpl->pin);
+}
+
+static HRESULT Parser_OutputPin_Construct(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES * props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, const AM_MEDIA_TYPE * pmt, float fSamplesPerSec, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
+{
+    Parser_OutputPin * pPinImpl;
+
+    *ppPin = NULL;
+
+    assert(pPinInfo->dir == PINDIR_OUTPUT);
+
+    pPinImpl = CoTaskMemAlloc(sizeof(Parser_OutputPin));
+
+    if (!pPinImpl)
+        return E_OUTOFMEMORY;
+
+    if (SUCCEEDED(Parser_OutputPin_Init(pPinInfo, props, pUserData, pQueryAccept, pmt, fSamplesPerSec, pCritSec, pPinImpl)))
+    {
+        pPinImpl->pin.pin.lpVtbl = &Parser_OutputPin_Vtbl;
+        
+        *ppPin = (IPin *)pPinImpl;
+        return S_OK;
+    }
+    return E_FAIL;
+}
+
+static HRESULT WINAPI Parser_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
+{
+    ParserImpl *This = (ParserImpl *)iface;
+    TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
+
+    *ppv = NULL;
+
+    if (IsEqualIID(riid, &IID_IUnknown))
+        *ppv = (LPVOID)This;
+    else if (IsEqualIID(riid, &IID_IPersist))
+        *ppv = (LPVOID)This;
+    else if (IsEqualIID(riid, &IID_IMediaFilter))
+        *ppv = (LPVOID)This;
+    else if (IsEqualIID(riid, &IID_IBaseFilter))
+        *ppv = (LPVOID)This;
+
+    if (*ppv)
+    {
+        IUnknown_AddRef((IUnknown *)(*ppv));
+        return S_OK;
+    }
+
+    FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
+
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI Parser_AddRef(IBaseFilter * iface)
+{
+    ParserImpl *This = (ParserImpl *)iface;
+    ULONG refCount = InterlockedIncrement(&This->refCount);
+
+    TRACE("(%p/%p)->() AddRef from %ld\n", This, iface, refCount - 1);
+
+    return refCount;
+}
+
+static ULONG WINAPI Parser_Release(IBaseFilter * iface)
+{
+    ParserImpl *This = (ParserImpl *)iface;
+    ULONG refCount = InterlockedDecrement(&This->refCount);
+
+    TRACE("(%p/%p)->() Release from %ld\n", This, iface, refCount + 1);
+    
+    if (!refCount)
+    {
+        ULONG i;
+
+        DeleteCriticalSection(&This->csFilter);
+        if (This->pClock)
+            IReferenceClock_Release(This->pClock);
+        
+        for (i = 0; i < This->cStreams + 1; i++)
+            IPin_Release(This->ppPins[i]);
+        
+        HeapFree(GetProcessHeap(), 0, This->ppPins);
+        This->lpVtbl = NULL;
+        
+        TRACE("Destroying AVI splitter\n");
+        CoTaskMemFree(This);
+        
+        return 0;
+    }
+    else
+        return refCount;
+}
+
+/** IPersist methods **/
+
+static HRESULT WINAPI Parser_GetClassID(IBaseFilter * iface, CLSID * pClsid)
+{
+    TRACE("(%p)\n", pClsid);
+
+    *pClsid = CLSID_AviSplitter;
+
+    return S_OK;
+}
+
+/** IMediaFilter methods **/
+
+static HRESULT WINAPI Parser_Stop(IBaseFilter * iface)
+{
+    HRESULT hr;
+    ParserImpl *This = (ParserImpl *)iface;
+
+    TRACE("()\n");
+
+    EnterCriticalSection(&This->csFilter);
+    {
+        hr = PullPin_StopProcessing(This->pInputPin);
+        This->state = State_Stopped;
+    }
+    LeaveCriticalSection(&This->csFilter);
+    
+    return hr;
+}
+
+static HRESULT WINAPI Parser_Pause(IBaseFilter * iface)
+{
+    HRESULT hr = S_OK;
+    BOOL bInit;
+    ParserImpl *This = (ParserImpl *)iface;
+    
+    TRACE("()\n");
+
+    EnterCriticalSection(&This->csFilter);
+    {
+        bInit = (This->state == State_Stopped);
+        This->state = State_Paused;
+    }
+    LeaveCriticalSection(&This->csFilter);
+
+    if (bInit)
+    {
+        unsigned int i;
+
+        //hr = PullPin_Seek(This->pInputPin, This->CurrentChunkOffset, This->EndOfFile);
+
+        if (SUCCEEDED(hr))
+            hr = PullPin_InitProcessing(This->pInputPin);
+
+        if (SUCCEEDED(hr))
+        {
+            for (i = 1; i < This->cStreams + 1; i++)
+            {
+                Parser_OutputPin* StreamPin = (Parser_OutputPin *)This->ppPins[i];
+                OutputPin_DeliverNewSegment((OutputPin *)This->ppPins[i], 0, (LONGLONG)ceil(10000000.0 * (float)StreamPin->dwLength / StreamPin->fSamplesPerSec), 1.0);
+                StreamPin->mediaSeeking.llDuration = (LONGLONG)ceil(10000000.0 * (float)StreamPin->dwLength / StreamPin->fSamplesPerSec);
+                StreamPin->mediaSeeking.llStop = (LONGLONG)ceil(10000000.0 * (float)StreamPin->dwLength / StreamPin->fSamplesPerSec);
+                OutputPin_CommitAllocator((OutputPin *)This->ppPins[i]);
+            }
+
+            /* FIXME: this is a little hacky: we have to deliver (at least?) one sample
+             * to each renderer before they will complete their transitions. We should probably
+             * seek through the stream for the first of each, rather than do it this way which is
+             * probably a bit prone to deadlocking */
+            hr = PullPin_StartProcessing(This->pInputPin);
+        }
+    }
+    /* FIXME: else pause thread */
+
+    return hr;
+}
+
+static HRESULT WINAPI Parser_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
+{
+    HRESULT hr = S_OK;
+    ParserImpl *This = (ParserImpl *)iface;
+    int i;
+
+    TRACE("(%s)\n", wine_dbgstr_longlong(tStart));
+
+    EnterCriticalSection(&This->csFilter);
+    {
+        This->rtStreamStart = tStart;
+        This->state = State_Running;
+
+        hr = PullPin_InitProcessing(This->pInputPin);
+
+        if (SUCCEEDED(hr))
+        { 
+            for (i = 1; i < This->cStreams + 1; i++)
+            {
+                OutputPin_CommitAllocator((OutputPin *)This->ppPins[i]);
+            }
+            hr = PullPin_StartProcessing(This->pInputPin);
+        }
+    }
+    LeaveCriticalSection(&This->csFilter);
+
+    return hr;
+}
+
+static HRESULT WINAPI Parser_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
+{
+    ParserImpl *This = (ParserImpl *)iface;
+
+    TRACE("(%ld, %p)\n", dwMilliSecsTimeout, pState);
+
+    EnterCriticalSection(&This->csFilter);
+    {
+        *pState = This->state;
+    }
+    LeaveCriticalSection(&This->csFilter);
+
+    /* FIXME: this is a little bit unsafe, but I don't see that we can do this
+     * while in the critical section. Maybe we could copy the pointer and addref in the
+     * critical section and then release after this.
+     */
+    if (This->pInputPin && (PullPin_WaitForStateChange(This->pInputPin, dwMilliSecsTimeout) == S_FALSE))
+        return VFW_S_STATE_INTERMEDIATE;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI Parser_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
+{
+    ParserImpl *This = (ParserImpl *)iface;
+
+    TRACE("(%p)\n", pClock);
+
+    EnterCriticalSection(&This->csFilter);
+    {
+        if (This->pClock)
+            IReferenceClock_Release(This->pClock);
+        This->pClock = pClock;
+        if (This->pClock)
+            IReferenceClock_AddRef(This->pClock);
+    }
+    LeaveCriticalSection(&This->csFilter);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI Parser_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
+{
+    ParserImpl *This = (ParserImpl *)iface;
+
+    TRACE("(%p)\n", ppClock);
+
+    EnterCriticalSection(&This->csFilter);
+    {
+        *ppClock = This->pClock;
+        if (This->pClock)
+            IReferenceClock_AddRef(This->pClock);
+    }
+    LeaveCriticalSection(&This->csFilter);
+    
+    return S_OK;
+}
+
+/** IBaseFilter implementation **/
+
+static HRESULT WINAPI Parser_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
+{
+    ENUMPINDETAILS epd;
+    ParserImpl *This = (ParserImpl *)iface;
+
+    TRACE("(%p)\n", ppEnum);
+
+    epd.cPins = This->cStreams + 1; /* +1 for input pin */
+    epd.ppPins = This->ppPins;
+    return IEnumPinsImpl_Construct(&epd, ppEnum);
+}
+
+static HRESULT WINAPI Parser_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
+{
+    FIXME("(%p)->(%s,%p)\n", iface, debugstr_w(Id), ppPin);
+
+    /* FIXME: critical section */
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI Parser_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
+{
+    ParserImpl *This = (ParserImpl *)iface;
+
+    TRACE("(%p)\n", pInfo);
+
+    strcpyW(pInfo->achName, This->filterInfo.achName);
+    pInfo->pGraph = This->filterInfo.pGraph;
+
+    if (pInfo->pGraph)
+        IFilterGraph_AddRef(pInfo->pGraph);
+    
+    return S_OK;
+}
+
+static HRESULT WINAPI Parser_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
+{
+    HRESULT hr = S_OK;
+    ParserImpl *This = (ParserImpl *)iface;
+
+    TRACE("(%p, %s)\n", pGraph, debugstr_w(pName));
+
+    EnterCriticalSection(&This->csFilter);
+    {
+        if (pName)
+            strcpyW(This->filterInfo.achName, pName);
+        else
+            *This->filterInfo.achName = '\0';
+        This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
+    }
+    LeaveCriticalSection(&This->csFilter);
+
+    return hr;
+}
+
+static HRESULT WINAPI Parser_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
+{
+    TRACE("(%p)\n", pVendorInfo);
+    return E_NOTIMPL;
+}
+
+static const IBaseFilterVtbl Parser_Vtbl =
+{
+    Parser_QueryInterface,
+    Parser_AddRef,
+    Parser_Release,
+    Parser_GetClassID,
+    Parser_Stop,
+    Parser_Pause,
+    Parser_Run,
+    Parser_GetState,
+    Parser_SetSyncSource,
+    Parser_GetSyncSource,
+    Parser_EnumPins,
+    Parser_FindPin,
+    Parser_QueryFilterInfo,
+    Parser_JoinFilterGraph,
+    Parser_QueryVendorInfo
+};
+
+HRESULT Parser_AddPin(ParserImpl * This, PIN_INFO * piOutput, ALLOCATOR_PROPERTIES * props, AM_MEDIA_TYPE * amt, float fSamplesPerSec, DWORD dwSampleSize, DWORD dwLength)
+{
+    IPin ** ppOldPins;
+    HRESULT hr;
+
+    ppOldPins = This->ppPins;
+
+    This->ppPins = HeapAlloc(GetProcessHeap(), 0, (This->cStreams + 2) * sizeof(IPin *));
+    memcpy(This->ppPins, ppOldPins, (This->cStreams + 1) * sizeof(IPin *));
+
+    hr = Parser_OutputPin_Construct(piOutput, props, NULL, Parser_OutputPin_QueryAccept, amt, fSamplesPerSec, &This->csFilter, This->ppPins + This->cStreams + 1);
+
+    if (SUCCEEDED(hr))
+    {
+        ((Parser_OutputPin *)(This->ppPins[This->cStreams + 1]))->dwSampleSize = dwSampleSize;
+        ((Parser_OutputPin *)(This->ppPins[This->cStreams + 1]))->dwLength = dwLength;
+        ((Parser_OutputPin *)(This->ppPins[This->cStreams + 1]))->pin.pin.pUserData = (LPVOID)This->ppPins[This->cStreams + 1];
+        This->cStreams++;
+        HeapFree(GetProcessHeap(), 0, ppOldPins);
+    }
+    else
+    {
+        HeapFree(GetProcessHeap(), 0, This->ppPins);
+        This->ppPins = ppOldPins;
+        ERR("Failed with error %lx\n", hr);
+    }
+
+    return hr;
+}
+
+static HRESULT Parser_RemoveOutputPins(ParserImpl * This)
+{
+    /* NOTE: should be in critical section when calling this function */
+
+    ULONG i;
+    IPin ** ppOldPins = This->ppPins;
+
+    /* reduce the pin array down to 1 (just our input pin) */
+    This->ppPins = HeapAlloc(GetProcessHeap(), 0, sizeof(IPin *) * 1);
+    memcpy(This->ppPins, ppOldPins, sizeof(IPin *) * 1);
+
+    for (i = 0; i < This->cStreams; i++)
+    {
+        OutputPin_DeliverDisconnect((OutputPin *)ppOldPins[i + 1]);
+        IPin_Release(ppOldPins[i + 1]);
+    }
+
+    This->cStreams = 0;
+    HeapFree(GetProcessHeap(), 0, ppOldPins);
+
+    return S_OK;
+}
+
+static HRESULT Parser_ChangeStart(LPVOID iface)
+{
+    FIXME("(%p)\n", iface);
+    return S_OK;
+}
+
+static HRESULT Parser_ChangeStop(LPVOID iface)
+{
+    FIXME("(%p)\n", iface);
+    return S_OK;
+}
+
+static HRESULT Parser_ChangeRate(LPVOID iface)
+{
+    FIXME("(%p)\n", iface);
+    return S_OK;
+}
+
+
+static HRESULT WINAPI Parser_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv)
+{
+    ICOM_THIS_From_IMediaSeeking(Parser_OutputPin, iface);
+
+    return IUnknown_QueryInterface((IUnknown *)This, riid, ppv);
+}
+
+static ULONG WINAPI Parser_Seeking_AddRef(IMediaSeeking * iface)
+{
+    ICOM_THIS_From_IMediaSeeking(Parser_OutputPin, iface);
+
+    return IUnknown_AddRef((IUnknown *)This);
+}
+
+static ULONG WINAPI Parser_Seeking_Release(IMediaSeeking * iface)
+{
+    ICOM_THIS_From_IMediaSeeking(Parser_OutputPin, iface);
+
+    return IUnknown_Release((IUnknown *)This);
+}
+
+static const IMediaSeekingVtbl Parser_Seeking_Vtbl =
+{
+    Parser_Seeking_QueryInterface,
+    Parser_Seeking_AddRef,
+    Parser_Seeking_Release,
+    MediaSeekingImpl_GetCapabilities,
+    MediaSeekingImpl_CheckCapabilities,
+    MediaSeekingImpl_IsFormatSupported,
+    MediaSeekingImpl_QueryPreferredFormat,
+    MediaSeekingImpl_GetTimeFormat,
+    MediaSeekingImpl_IsUsingTimeFormat,
+    MediaSeekingImpl_SetTimeFormat,
+    MediaSeekingImpl_GetDuration,
+    MediaSeekingImpl_GetStopPosition,
+    MediaSeekingImpl_GetCurrentPosition,
+    MediaSeekingImpl_ConvertTimeFormat,
+    MediaSeekingImpl_SetPositions,
+    MediaSeekingImpl_GetPositions,
+    MediaSeekingImpl_GetAvailable,
+    MediaSeekingImpl_SetRate,
+    MediaSeekingImpl_GetRate,
+    MediaSeekingImpl_GetPreroll
+};
+
+HRESULT WINAPI Parser_OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
+{
+    Parser_OutputPin *This = (Parser_OutputPin *)iface;
+
+    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;
+    else if (IsEqualIID(riid, &IID_IMediaSeeking))
+        *ppv = (LPVOID)&This->mediaSeeking;
+
+    if (*ppv)
+    {
+        IUnknown_AddRef((IUnknown *)(*ppv));
+        return S_OK;
+    }
+
+    FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
+
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI Parser_OutputPin_Release(IPin * iface)
+{
+    Parser_OutputPin *This = (Parser_OutputPin *)iface;
+    ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount);
+    
+    TRACE("()\n");
+    
+    if (!refCount)
+    {
+        DeleteMediaType(This->pmt);
+        CoTaskMemFree(This->pmt);
+        DeleteMediaType(&This->pin.pin.mtCurrent);
+        CoTaskMemFree(This);
+        return 0;
+    }
+    return refCount;
+}
+
+static HRESULT WINAPI Parser_OutputPin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
+{
+    ENUMMEDIADETAILS emd;
+    Parser_OutputPin *This = (Parser_OutputPin *)iface;
+
+    TRACE("(%p)\n", ppEnum);
+
+    /* override this method to allow enumeration of your types */
+    emd.cMediaTypes = 1;
+    emd.pMediaTypes = This->pmt;
+
+    return IEnumMediaTypesImpl_Construct(&emd, ppEnum);
+}
+
+static HRESULT Parser_OutputPin_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
+{
+    Parser_OutputPin *This = (Parser_OutputPin *)iface;
+
+    TRACE("()\n");
+    dump_AM_MEDIA_TYPE(pmt);
+
+    return (memcmp(This->pmt, pmt, sizeof(AM_MEDIA_TYPE)) == 0);
+}
+
+static const IPinVtbl Parser_OutputPin_Vtbl = 
+{
+    Parser_OutputPin_QueryInterface,
+    IPinImpl_AddRef,
+    Parser_OutputPin_Release,
+    OutputPin_Connect,
+    OutputPin_ReceiveConnection,
+    OutputPin_Disconnect,
+    IPinImpl_ConnectedTo,
+    IPinImpl_ConnectionMediaType,
+    IPinImpl_QueryPinInfo,
+    IPinImpl_QueryDirection,
+    IPinImpl_QueryId,
+    IPinImpl_QueryAccept,
+    Parser_OutputPin_EnumMediaTypes,
+    IPinImpl_QueryInternalConnections,
+    OutputPin_EndOfStream,
+    OutputPin_BeginFlush,
+    OutputPin_EndFlush,
+    OutputPin_NewSegment
+};
+
+static HRESULT Parser_InputPin_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 = &Parser_InputPin_Vtbl;
+        
+        *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
+        return S_OK;
+    }
+    return E_FAIL;
+}
+
+static HRESULT WINAPI Parser_InputPin_Disconnect(IPin * iface)
+{
+    HRESULT hr;
+    IPinImpl *This = (IPinImpl *)iface;
+
+    TRACE("()\n");
+
+    EnterCriticalSection(This->pCritSec);
+    {
+        if (This->pConnectedTo)
+        {
+            FILTER_STATE state;
+
+            hr = IBaseFilter_GetState(This->pinInfo.pFilter, 0, &state);
+
+            if (SUCCEEDED(hr) && (state == State_Stopped))
+            {
+                IPin_Release(This->pConnectedTo);
+                This->pConnectedTo = NULL;
+                hr = Parser_RemoveOutputPins((ParserImpl *)This->pinInfo.pFilter);
+            }
+            else
+                hr = VFW_E_NOT_STOPPED;
+        }
+        else
+            hr = S_FALSE;
+    }
+    LeaveCriticalSection(This->pCritSec);
+    
+    return hr;
+}
+
+static const IPinVtbl Parser_InputPin_Vtbl =
+{
+    PullPin_QueryInterface,
+    IPinImpl_AddRef,
+    PullPin_Release,
+    OutputPin_Connect,
+    PullPin_ReceiveConnection,
+    Parser_InputPin_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
+};


More information about the wine-patches mailing list