From cfbffe6909393dc6f2a63d12a6af8c9b05331aa9 Mon Sep 17 00:00:00 2001 From: Christian Costa Date: Tue, 8 Feb 2005 13:43:59 +0000 Subject: [PATCH] Added parser template and made AVISplitter use it. --- dlls/quartz/Makefile.in | 1 + dlls/quartz/avisplit.c | 748 ++-------------------------------------- dlls/quartz/parser.c | 737 +++++++++++++++++++++++++++++++++++++++ dlls/quartz/parser.h | 57 +++ 4 files changed, 823 insertions(+), 720 deletions(-) create mode 100644 dlls/quartz/parser.c create mode 100644 dlls/quartz/parser.h diff --git a/dlls/quartz/Makefile.in b/dlls/quartz/Makefile.in index 4e0dda5d285..621b8d703c3 100644 --- a/dlls/quartz/Makefile.in +++ b/dlls/quartz/Makefile.in @@ -22,6 +22,7 @@ C_SRCS = \ filtermapper.c \ main.c \ memallocator.c \ + parser.c \ pin.c \ regsvr.c \ systemclock.c \ diff --git a/dlls/quartz/avisplit.c b/dlls/quartz/avisplit.c index fd097bd138f..a7acadd2245 100644 --- a/dlls/quartz/avisplit.c +++ b/dlls/quartz/avisplit.c @@ -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 #include +#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 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); - -static HRESULT AVISplitter_InputPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin); - -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_NextChunk(LONGLONG * pllCurrentChunkOffset, RIFFCHUNK 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 @@ static HRESULT AVISplitter_Sample(LPVOID iface, IMediaSample * pSample) 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 @@ static HRESULT AVISplitter_Sample(LPVOID iface, IMediaSample * pSample) 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 @@ static HRESULT AVISplitter_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt) 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 @@ static HRESULT AVISplitter_ProcessStreamList(AVISplitter * This, const BYTE * pD 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 @@ static HRESULT AVISplitter_ProcessStreamList(AVISplitter * This, const BYTE * pD 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 @@ static HRESULT AVISplitter_InputPin_PreConnect(IPin * iface, IPin * pConnectPin) 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 @@ static HRESULT AVISplitter_InputPin_PreConnect(IPin * iface, IPin * pConnectPin) return hr; } -static HRESULT AVISplitter_ChangeStart(LPVOID iface) +HRESULT AVISplitter_create(IUnknown * pUnkOuter, LPVOID * ppv) { - FIXME("(%p)\n", iface); - return S_OK; -} + HRESULT hr; + AVISplitterImpl * This; -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) -{ - AVISplitter_OutputPin *This = (AVISplitter_OutputPin *)iface; - - 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 (pUnkOuter) + return CLASS_E_NOAGGREGATION; - if (*ppv) - { - IUnknown_AddRef((IUnknown *)(*ppv)); - return S_OK; - } + /* Note: This memory is managed by the transform filter once created */ + This = CoTaskMemAlloc(sizeof(AVISplitterImpl)); - FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); + This->pCurrentSample = NULL; - return E_NOINTERFACE; -} + hr = Parser_Create(&(This->Parser), &CLSID_AviSplitter, AVISplitter_Sample, AVISplitter_QueryAccept, AVISplitter_InputPin_PreConnect); -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; -} + if (FAILED(hr)) + return hr; -static HRESULT WINAPI AVISplitter_OutputPin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum) -{ - ENUMMEDIADETAILS emd; - AVISplitter_OutputPin *This = (AVISplitter_OutputPin *)iface; + *ppv = (LPVOID)This; - 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 -}; - -static HRESULT AVISplitter_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 = &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 -}; diff --git a/dlls/quartz/parser.c b/dlls/quartz/parser.c new file mode 100644 index 00000000000..f14192e40e5 --- /dev/null +++ b/dlls/quartz/parser.c @@ -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 +#include + +#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 +}; diff --git a/dlls/quartz/parser.h b/dlls/quartz/parser.h new file mode 100644 index 00000000000..9677a322eb7 --- /dev/null +++ b/dlls/quartz/parser.h @@ -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);