From ccd066e8037bb1132f7caffabd5831f19ac19353 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 22 Jul 2008 09:00:20 -0700 Subject: [PATCH] quartz: Move a huge chunk to a separate 'strmbase' library --- configure.ac | 1 + dlls/Makefile.in | 3 + dlls/quartz/Makefile.in | 9 +- dlls/quartz/acmwrapper.c | 3 - dlls/quartz/avidec.c | 3 - dlls/quartz/avisplit.c | 4 - dlls/quartz/control.c | 919 ------------------- dlls/quartz/control_private.h | 62 -- dlls/quartz/dsoundrender.c | 2 - dlls/quartz/enummedia.c | 260 ------ dlls/quartz/enumpins.c | 211 ----- dlls/quartz/filesource.c | 1 - dlls/quartz/main.c | 49 - dlls/quartz/memallocator.c | 883 ------------------ dlls/quartz/mpegsplit.c | 3 - dlls/quartz/nullrenderer.c | 2 - dlls/quartz/parser.c | 787 ---------------- dlls/quartz/parser.h | 80 -- dlls/quartz/pin.c | 1866 -------------------------------------- dlls/quartz/pin.h | 218 ----- dlls/quartz/quartz_private.h | 117 +-- dlls/quartz/transform.c | 652 ------------- dlls/quartz/transform.h | 53 -- dlls/quartz/videorenderer.c | 2 - dlls/quartz/waveparser.c | 3 - dlls/strmbase/Makefile.in | 18 + dlls/strmbase/control.c | 918 +++++++++++++++++++ dlls/strmbase/enummedia.c | 308 +++++++ dlls/strmbase/enumpins.c | 211 +++++ dlls/strmbase/memallocator.c | 876 ++++++++++++++++++ dlls/strmbase/parser.c | 783 ++++++++++++++++ dlls/strmbase/pin.c | 1861 +++++++++++++++++++++++++++++++++++++ dlls/strmbase/strmbase_private.h | 35 + dlls/strmbase/transform.c | 648 +++++++++++++ include/strmbase/control.h | 62 ++ include/strmbase/misc.h | 94 ++ include/strmbase/parser.h | 80 ++ include/strmbase/pin.h | 218 +++++ include/strmbase/strmbase.h | 26 + include/strmbase/transform.h | 51 + 40 files changed, 6216 insertions(+), 6166 deletions(-) delete mode 100644 dlls/quartz/control.c delete mode 100644 dlls/quartz/control_private.h delete mode 100644 dlls/quartz/enummedia.c delete mode 100644 dlls/quartz/enumpins.c delete mode 100644 dlls/quartz/memallocator.c delete mode 100644 dlls/quartz/parser.c delete mode 100644 dlls/quartz/parser.h delete mode 100644 dlls/quartz/pin.c delete mode 100644 dlls/quartz/pin.h delete mode 100644 dlls/quartz/transform.c delete mode 100644 dlls/quartz/transform.h create mode 100644 dlls/strmbase/Makefile.in create mode 100644 dlls/strmbase/control.c create mode 100644 dlls/strmbase/enummedia.c create mode 100644 dlls/strmbase/enumpins.c create mode 100644 dlls/strmbase/memallocator.c create mode 100644 dlls/strmbase/parser.c create mode 100644 dlls/strmbase/pin.c create mode 100644 dlls/strmbase/strmbase_private.h create mode 100644 dlls/strmbase/transform.c create mode 100644 include/strmbase/control.h create mode 100644 include/strmbase/misc.h create mode 100644 include/strmbase/parser.h create mode 100644 include/strmbase/pin.h create mode 100644 include/strmbase/strmbase.h create mode 100644 include/strmbase/transform.h diff --git a/configure.ac b/configure.ac index 7417f30..330b7c5 100644 --- a/configure.ac +++ b/configure.ac @@ -1995,6 +1995,7 @@ AC_CONFIG_FILES([dlls/spoolss/tests/Makefile]) AC_CONFIG_FILES([dlls/stdole2.tlb/Makefile]) AC_CONFIG_FILES([dlls/stdole32.tlb/Makefile]) AC_CONFIG_FILES([dlls/sti/Makefile]) +AC_CONFIG_FILES([dlls/strmbase/Makefile]) AC_CONFIG_FILES([dlls/strmiids/Makefile]) AC_CONFIG_FILES([dlls/svrapi/Makefile]) AC_CONFIG_FILES([dlls/sxs/Makefile]) diff --git a/dlls/Makefile.in b/dlls/Makefile.in index 0eac4a0..3431d20 100644 --- a/dlls/Makefile.in +++ b/dlls/Makefile.in @@ -281,6 +281,7 @@ IMPLIBSUBDIRS = \ dxerr8 \ dxerr9 \ dxguid \ + strmbase \ strmiids \ uuid \ winecrt0 @@ -541,6 +542,7 @@ IMPORT_LIBS = \ dxerr8/libdxerr8.a \ dxerr9/libdxerr9.a \ dxguid/libdxguid.a \ + strmbase/libstrmbase.a \ strmiids/libstrmiids.a \ uuid/libuuid.a \ winecrt0/libwinecrt0.a \ @@ -1239,6 +1241,7 @@ adsiid/libadsiid.a: adsiid dxerr8/libdxerr8.a: dxerr8 dxerr9/libdxerr9.a: dxerr9 dxguid/libdxguid.a: dxguid +strmbase/libstrmbase.a: strmbase strmiids/libstrmiids.a: strmiids uuid/libuuid.a: uuid winecrt0/libwinecrt0.a: winecrt0 diff --git a/dlls/quartz/Makefile.in b/dlls/quartz/Makefile.in index c5114b9..537c8b1 100644 --- a/dlls/quartz/Makefile.in +++ b/dlls/quartz/Makefile.in @@ -4,31 +4,24 @@ SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = quartz.dll IMPORTLIB = quartz -IMPORTS = strmiids uuid dsound msacm32 msvfw32 ole32 oleaut32 shlwapi user32 gdi32 advapi32 kernel32 +IMPORTS = strmiids strmbase uuid dsound msacm32 msvfw32 ole32 oleaut32 shlwapi user32 gdi32 advapi32 kernel32 C_SRCS = \ acmwrapper.c \ avidec.c \ avisplit.c \ - control.c \ dsoundrender.c \ enumfilters.c \ - enummedia.c \ enummoniker.c \ - enumpins.c \ enumregfilters.c \ filesource.c \ filtergraph.c \ filtermapper.c \ main.c \ - memallocator.c \ mpegsplit.c \ nullrenderer.c \ - parser.c \ - pin.c \ regsvr.c \ systemclock.c \ - transform.c \ videorenderer.c \ waveparser.c diff --git a/dlls/quartz/acmwrapper.c b/dlls/quartz/acmwrapper.c index 2dc49da..8ba6774 100644 --- a/dlls/quartz/acmwrapper.c +++ b/dlls/quartz/acmwrapper.c @@ -21,7 +21,6 @@ #include "config.h" #include "quartz_private.h" -#include "pin.h" #include "uuids.h" #include "mmreg.h" @@ -37,8 +36,6 @@ #include "wine/unicode.h" #include "wine/debug.h" -#include "transform.h" - WINE_DEFAULT_DEBUG_CHANNEL(quartz); typedef struct ACMWrapperImpl diff --git a/dlls/quartz/avidec.c b/dlls/quartz/avidec.c index 476e0d3..ae6bb0e 100644 --- a/dlls/quartz/avidec.c +++ b/dlls/quartz/avidec.c @@ -21,7 +21,6 @@ #include "config.h" #include "quartz_private.h" -#include "pin.h" #include "uuids.h" #include "amvideo.h" @@ -38,8 +37,6 @@ #include "wine/unicode.h" #include "wine/debug.h" -#include "transform.h" - WINE_DEFAULT_DEBUG_CHANNEL(quartz); static HRESULT AVIDec_Cleanup(TransformFilterImpl* pTransformFilter); diff --git a/dlls/quartz/avisplit.c b/dlls/quartz/avisplit.c index e712eb9..2553e87 100644 --- a/dlls/quartz/avisplit.c +++ b/dlls/quartz/avisplit.c @@ -30,8 +30,6 @@ */ #include "quartz_private.h" -#include "control_private.h" -#include "pin.h" #include "uuids.h" #include "vfw.h" @@ -45,8 +43,6 @@ #include #include -#include "parser.h" - #define TWOCCFromFOURCC(fcc) HIWORD(fcc) /* four character codes used in AVI files */ diff --git a/dlls/quartz/control.c b/dlls/quartz/control.c deleted file mode 100644 index e719831..0000000 --- a/dlls/quartz/control.c +++ /dev/null @@ -1,919 +0,0 @@ -/* - * Filter Seeking and Control Interfaces - * - * Copyright 2003 Robert Shearman - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ -/* FIXME: critical sections */ - -#include "quartz_private.h" -#include "control_private.h" - -#include "uuids.h" -#include "wine/debug.h" - -#include - -WINE_DEFAULT_DEBUG_CHANNEL(quartz); - -static const IMediaSeekingVtbl IMediaSeekingPassThru_Vtbl; - -typedef struct PassThruImpl { - const ISeekingPassThruVtbl *IPassThru_vtbl; - const IUnknownVtbl *IInner_vtbl; - const IMediaSeekingVtbl *IMediaSeeking_vtbl; - - LONG ref; - IUnknown * pUnkOuter; - IPin * pin; - BOOL bUnkOuterValid; - BOOL bAggregatable; - BOOL renderer; -} PassThruImpl; - -static HRESULT WINAPI SeekInner_QueryInterface(IUnknown * iface, - REFIID riid, - LPVOID *ppvObj) { - ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface); - TRACE("(%p)->(%s (%p), %p)\n", This, debugstr_guid(riid), riid, ppvObj); - - if (This->bAggregatable) - This->bUnkOuterValid = TRUE; - - if (IsEqualGUID(&IID_IUnknown, riid)) - { - *ppvObj = &(This->IInner_vtbl); - TRACE(" returning IUnknown interface (%p)\n", *ppvObj); - } else if (IsEqualGUID(&IID_ISeekingPassThru, riid)) { - *ppvObj = &(This->IPassThru_vtbl); - TRACE(" returning ISeekingPassThru interface (%p)\n", *ppvObj); - } else if (IsEqualGUID(&IID_IMediaSeeking, riid)) { - *ppvObj = &(This->IMediaSeeking_vtbl); - TRACE(" returning IMediaSeeking interface (%p)\n", *ppvObj); - } else { - *ppvObj = NULL; - FIXME("unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; - } - - IUnknown_AddRef((IUnknown *)(*ppvObj)); - return S_OK; -} - -static ULONG WINAPI SeekInner_AddRef(IUnknown * iface) { - ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface); - ULONG ref = InterlockedIncrement(&This->ref); - - TRACE("(%p)->(): new ref = %d\n", This, ref); - - return ref; -} - -static ULONG WINAPI SeekInner_Release(IUnknown * iface) { - ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface); - ULONG ref = InterlockedDecrement(&This->ref); - - TRACE("(%p)->(): new ref = %d\n", This, ref); - - if (ref == 0) - { - CoTaskMemFree(This); - } - return ref; -} - -static const IUnknownVtbl IInner_VTable = -{ - SeekInner_QueryInterface, - SeekInner_AddRef, - SeekInner_Release -}; - -/* Generic functions for aggregation */ -static HRESULT WINAPI SeekOuter_QueryInterface(PassThruImpl *This, REFIID riid, LPVOID *ppv) -{ - if (This->bAggregatable) - This->bUnkOuterValid = TRUE; - - if (This->pUnkOuter) - { - if (This->bAggregatable) - return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv); - - if (IsEqualIID(riid, &IID_IUnknown)) - { - HRESULT hr; - - IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl)); - hr = IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv); - IUnknown_Release((IUnknown *)&(This->IInner_vtbl)); - This->bAggregatable = TRUE; - return hr; - } - - *ppv = NULL; - return E_NOINTERFACE; - } - - return IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv); -} - -static ULONG WINAPI SeekOuter_AddRef(PassThruImpl *This) -{ - if (This->pUnkOuter && This->bUnkOuterValid) - return IUnknown_AddRef(This->pUnkOuter); - return IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl)); -} - -static ULONG WINAPI SeekOuter_Release(PassThruImpl *This) -{ - if (This->pUnkOuter && This->bUnkOuterValid) - return IUnknown_Release(This->pUnkOuter); - return IUnknown_Release((IUnknown *)&(This->IInner_vtbl)); -} - -static HRESULT WINAPI SeekingPassThru_QueryInterface(ISeekingPassThru *iface, REFIID riid, LPVOID *ppvObj) -{ - ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface); - - TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj); - - return SeekOuter_QueryInterface(This, riid, ppvObj); -} - -static ULONG WINAPI SeekingPassThru_AddRef(ISeekingPassThru *iface) -{ - ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface); - - TRACE("(%p/%p)->()\n", This, iface); - - return SeekOuter_AddRef(This); -} - -static ULONG WINAPI SeekingPassThru_Release(ISeekingPassThru *iface) -{ - ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface); - - TRACE("(%p/%p)->()\n", This, iface); - - return SeekOuter_Release(This); -} - -static HRESULT WINAPI SeekingPassThru_Init(ISeekingPassThru *iface, BOOL renderer, IPin *pin) -{ - ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface); - - TRACE("(%p/%p)->(%d, %p)\n", This, iface, renderer, pin); - - if (This->pin) - FIXME("Re-initializing?\n"); - - This->renderer = renderer; - This->pin = pin; - - return S_OK; -} - -static const ISeekingPassThruVtbl ISeekingPassThru_Vtbl = -{ - SeekingPassThru_QueryInterface, - SeekingPassThru_AddRef, - SeekingPassThru_Release, - SeekingPassThru_Init -}; - -HRESULT SeekingPassThru_create(IUnknown *pUnkOuter, LPVOID *ppObj) -{ - PassThruImpl *fimpl; - - TRACE("(%p,%p)\n", pUnkOuter, ppObj); - - *ppObj = fimpl = CoTaskMemAlloc(sizeof(*fimpl)); - if (!fimpl) - return E_OUTOFMEMORY; - - fimpl->pUnkOuter = pUnkOuter; - fimpl->bUnkOuterValid = FALSE; - fimpl->bAggregatable = FALSE; - fimpl->IInner_vtbl = &IInner_VTable; - fimpl->IPassThru_vtbl = &ISeekingPassThru_Vtbl; - fimpl->IMediaSeeking_vtbl = &IMediaSeekingPassThru_Vtbl; - fimpl->ref = 1; - fimpl->pin = NULL; - return S_OK; -} - -typedef HRESULT (*SeekFunc)( IMediaSeeking *to, LPVOID arg ); - -static HRESULT ForwardCmdSeek( PCRITICAL_SECTION crit_sect, IBaseFilter* from, SeekFunc fnSeek, LPVOID arg ) -{ - HRESULT hr = S_OK; - HRESULT hr_return = S_OK; - IEnumPins *enumpins = NULL; - BOOL foundend = FALSE, allnotimpl = TRUE; - - hr = IBaseFilter_EnumPins( from, &enumpins ); - if (FAILED(hr)) - goto out; - - hr = IEnumPins_Reset( enumpins ); - while (hr == S_OK) { - IPin *pin = NULL; - hr = IEnumPins_Next( enumpins, 1, &pin, NULL ); - if (hr == VFW_E_ENUM_OUT_OF_SYNC) - { - hr = IEnumPins_Reset( enumpins ); - continue; - } - if (pin) - { - PIN_DIRECTION dir; - - IPin_QueryDirection( pin, &dir ); - if (dir == PINDIR_INPUT) - { - IPin *connected = NULL; - - IPin_ConnectedTo( pin, &connected ); - if (connected) - { - HRESULT hr_local; - IMediaSeeking *seek = NULL; - - hr_local = IPin_QueryInterface( connected, &IID_IMediaSeeking, (void**)&seek ); - if (!hr_local) - { - foundend = TRUE; - if (crit_sect) - { - LeaveCriticalSection( crit_sect ); - hr_local = fnSeek( seek , arg ); - EnterCriticalSection( crit_sect ); - } - else - hr_local = fnSeek( seek , arg ); - - if (hr_local != E_NOTIMPL) - allnotimpl = FALSE; - - hr_return = updatehres( hr_return, hr_local ); - IMediaSeeking_Release( seek ); - } - IPin_Release(connected); - } - } - IPin_Release( pin ); - } - } - if (foundend && allnotimpl) - hr = E_NOTIMPL; - else - hr = hr_return; - -out: - TRACE("Returning: %08x\n", hr); - return hr; -} - - -HRESULT MediaSeekingImpl_Init(IBaseFilter *pUserData, CHANGEPROC fnChangeStop, CHANGEPROC fnChangeCurrent, CHANGEPROC fnChangeRate, MediaSeekingImpl * pSeeking, PCRITICAL_SECTION crit_sect) -{ - assert(fnChangeStop && fnChangeCurrent && fnChangeRate); - - pSeeking->refCount = 1; - pSeeking->pUserData = pUserData; - pSeeking->fnChangeRate = fnChangeRate; - pSeeking->fnChangeStop = fnChangeStop; - pSeeking->fnChangeCurrent = fnChangeCurrent; - pSeeking->dwCapabilities = AM_SEEKING_CanSeekForwards | - AM_SEEKING_CanSeekBackwards | - AM_SEEKING_CanSeekAbsolute | - AM_SEEKING_CanGetStopPos | - AM_SEEKING_CanGetDuration; - pSeeking->llCurrent = 0; - pSeeking->llStop = ((ULONGLONG)0x80000000) << 32; - pSeeking->llDuration = pSeeking->llStop; - pSeeking->dRate = 1.0; - pSeeking->timeformat = TIME_FORMAT_MEDIA_TIME; - pSeeking->crst = crit_sect; - - return S_OK; -} - -struct pos_args { - LONGLONG* current, *stop; - DWORD curflags, stopflags; -}; - -static HRESULT fwd_setposition(IMediaSeeking *seek, LPVOID pargs) -{ - struct pos_args *args = (void*)pargs; - - return IMediaSeeking_SetPositions(seek, args->current, args->curflags, args->stop, args->stopflags); -} - -static HRESULT fwd_checkcaps(IMediaSeeking *iface, LPVOID pcaps) -{ - DWORD *caps = pcaps; - return IMediaSeeking_CheckCapabilities(iface, caps); -} - -static HRESULT fwd_settimeformat(IMediaSeeking *iface, LPVOID pformat) -{ - const GUID *format = pformat; - return IMediaSeeking_SetTimeFormat(iface, format); -} - -static HRESULT fwd_getduration(IMediaSeeking *iface, LPVOID pdur) -{ - LONGLONG *duration = pdur; - LONGLONG mydur = *duration; - HRESULT hr; - - hr = IMediaSeeking_GetDuration(iface, &mydur); - if (FAILED(hr)) - return hr; - - if ((mydur < *duration) || (*duration < 0 && mydur > 0)) - *duration = mydur; - return hr; -} - -static HRESULT fwd_getstopposition(IMediaSeeking *iface, LPVOID pdur) -{ - LONGLONG *duration = pdur; - LONGLONG mydur = *duration; - HRESULT hr; - - hr = IMediaSeeking_GetStopPosition(iface, &mydur); - if (FAILED(hr)) - return hr; - - if ((mydur < *duration) || (*duration < 0 && mydur > 0)) - *duration = mydur; - return hr; -} - -static HRESULT fwd_getcurposition(IMediaSeeking *iface, LPVOID pdur) -{ - LONGLONG *duration = pdur; - LONGLONG mydur = *duration; - HRESULT hr; - - hr = IMediaSeeking_GetCurrentPosition(iface, &mydur); - if (FAILED(hr)) - return hr; - - if ((mydur < *duration) || (*duration < 0 && mydur > 0)) - *duration = mydur; - return hr; -} - -static HRESULT fwd_setrate(IMediaSeeking *iface, LPVOID prate) -{ - double *rate = prate; - - HRESULT hr; - - hr = IMediaSeeking_SetRate(iface, *rate); - if (FAILED(hr)) - return hr; - - return hr; -} - - -HRESULT WINAPI MediaSeekingImpl_GetCapabilities(IMediaSeeking * iface, DWORD * pCapabilities) -{ - MediaSeekingImpl *This = (MediaSeekingImpl *)iface; - - TRACE("(%p)\n", pCapabilities); - - *pCapabilities = This->dwCapabilities; - - return S_OK; -} - -HRESULT WINAPI MediaSeekingImpl_CheckCapabilities(IMediaSeeking * iface, DWORD * pCapabilities) -{ - MediaSeekingImpl *This = (MediaSeekingImpl *)iface; - HRESULT hr; - DWORD dwCommonCaps; - - TRACE("(%p)\n", pCapabilities); - - if (!pCapabilities) - return E_POINTER; - - EnterCriticalSection(This->crst); - hr = ForwardCmdSeek(This->crst, This->pUserData, fwd_checkcaps, pCapabilities); - LeaveCriticalSection(This->crst); - if (FAILED(hr) && hr != E_NOTIMPL) - return hr; - - dwCommonCaps = *pCapabilities & This->dwCapabilities; - - if (!dwCommonCaps) - hr = E_FAIL; - else - hr = (*pCapabilities == dwCommonCaps) ? S_OK : S_FALSE; - *pCapabilities = dwCommonCaps; - - return hr; -} - -HRESULT WINAPI MediaSeekingImpl_IsFormatSupported(IMediaSeeking * iface, const GUID * pFormat) -{ - TRACE("(%s)\n", qzdebugstr_guid(pFormat)); - - return (IsEqualIID(pFormat, &TIME_FORMAT_MEDIA_TIME) ? S_OK : S_FALSE); -} - -HRESULT WINAPI MediaSeekingImpl_QueryPreferredFormat(IMediaSeeking * iface, GUID * pFormat) -{ - TRACE("(%s)\n", qzdebugstr_guid(pFormat)); - - *pFormat = TIME_FORMAT_MEDIA_TIME; - return S_OK; -} - -HRESULT WINAPI MediaSeekingImpl_GetTimeFormat(IMediaSeeking * iface, GUID * pFormat) -{ - MediaSeekingImpl *This = (MediaSeekingImpl *)iface; - TRACE("(%s)\n", qzdebugstr_guid(pFormat)); - - EnterCriticalSection(This->crst); - *pFormat = This->timeformat; - LeaveCriticalSection(This->crst); - - return S_OK; -} - -HRESULT WINAPI MediaSeekingImpl_IsUsingTimeFormat(IMediaSeeking * iface, const GUID * pFormat) -{ - MediaSeekingImpl *This = (MediaSeekingImpl *)iface; - HRESULT hr = S_OK; - - TRACE("(%s)\n", qzdebugstr_guid(pFormat)); - - EnterCriticalSection(This->crst); - if (!IsEqualIID(pFormat, &This->timeformat)) - hr = S_FALSE; - LeaveCriticalSection(This->crst); - - return hr; -} - - -HRESULT WINAPI MediaSeekingImpl_SetTimeFormat(IMediaSeeking * iface, const GUID * pFormat) -{ - MediaSeekingImpl *This = (MediaSeekingImpl *)iface; - TRACE("(%s)\n", qzdebugstr_guid(pFormat)); - - EnterCriticalSection(This->crst); - ForwardCmdSeek(This->crst, This->pUserData, fwd_settimeformat, (LPVOID)pFormat); - LeaveCriticalSection(This->crst); - - return (IsEqualIID(pFormat, &TIME_FORMAT_MEDIA_TIME) ? S_OK : S_FALSE); -} - - -HRESULT WINAPI MediaSeekingImpl_GetDuration(IMediaSeeking * iface, LONGLONG * pDuration) -{ - MediaSeekingImpl *This = (MediaSeekingImpl *)iface; - - TRACE("(%p)\n", pDuration); - - EnterCriticalSection(This->crst); - *pDuration = This->llDuration; - ForwardCmdSeek(This->crst, This->pUserData, fwd_getduration, pDuration); - LeaveCriticalSection(This->crst); - - return S_OK; -} - -HRESULT WINAPI MediaSeekingImpl_GetStopPosition(IMediaSeeking * iface, LONGLONG * pStop) -{ - MediaSeekingImpl *This = (MediaSeekingImpl *)iface; - - TRACE("(%p)\n", pStop); - - EnterCriticalSection(This->crst); - *pStop = This->llStop; - ForwardCmdSeek(This->crst, This->pUserData, fwd_getstopposition, pStop); - LeaveCriticalSection(This->crst); - - return S_OK; -} - -/* FIXME: Make use of the info the filter should expose */ -HRESULT WINAPI MediaSeekingImpl_GetCurrentPosition(IMediaSeeking * iface, LONGLONG * pCurrent) -{ - MediaSeekingImpl *This = (MediaSeekingImpl *)iface; - - TRACE("(%p)\n", pCurrent); - - EnterCriticalSection(This->crst); - *pCurrent = This->llCurrent; - ForwardCmdSeek(This->crst, This->pUserData, fwd_getcurposition, pCurrent); - LeaveCriticalSection(This->crst); - - return S_OK; -} - -HRESULT WINAPI MediaSeekingImpl_ConvertTimeFormat(IMediaSeeking * iface, LONGLONG * pTarget, const GUID * pTargetFormat, LONGLONG Source, const GUID * pSourceFormat) -{ - if (IsEqualIID(pTargetFormat, &TIME_FORMAT_MEDIA_TIME) && IsEqualIID(pSourceFormat, &TIME_FORMAT_MEDIA_TIME)) - { - *pTarget = Source; - return S_OK; - } - /* FIXME: clear pTarget? */ - return E_INVALIDARG; -} - -static inline LONGLONG Adjust(LONGLONG value, const LONGLONG * pModifier, DWORD dwFlags) -{ - switch (dwFlags & AM_SEEKING_PositioningBitsMask) - { - case AM_SEEKING_NoPositioning: - return value; - case AM_SEEKING_AbsolutePositioning: - return *pModifier; - case AM_SEEKING_RelativePositioning: - case AM_SEEKING_IncrementalPositioning: - return value + *pModifier; - default: - assert(FALSE); - return 0; - } -} - -HRESULT WINAPI MediaSeekingImpl_SetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, DWORD dwCurrentFlags, LONGLONG * pStop, DWORD dwStopFlags) -{ - MediaSeekingImpl *This = (MediaSeekingImpl *)iface; - BOOL bChangeCurrent = FALSE, bChangeStop = FALSE; - LONGLONG llNewCurrent, llNewStop; - struct pos_args args; - - TRACE("(%p, %x, %p, %x)\n", pCurrent, dwCurrentFlags, pStop, dwStopFlags); - - args.current = pCurrent; - args.stop = pStop; - args.curflags = dwCurrentFlags; - args.stopflags = dwStopFlags; - - EnterCriticalSection(This->crst); - - llNewCurrent = Adjust(This->llCurrent, pCurrent, dwCurrentFlags); - llNewStop = Adjust(This->llStop, pStop, dwStopFlags); - - if (pCurrent) - bChangeCurrent = TRUE; - if (llNewStop != This->llStop) - bChangeStop = TRUE; - - TRACE("Old: %u, New: %u\n", (DWORD)(This->llCurrent/10000000), (DWORD)(llNewCurrent/10000000)); - - This->llCurrent = llNewCurrent; - This->llStop = llNewStop; - - if (dwCurrentFlags & AM_SEEKING_ReturnTime) - *pCurrent = llNewCurrent; - if (dwStopFlags & AM_SEEKING_ReturnTime) - *pStop = llNewStop; - - ForwardCmdSeek(This->crst, This->pUserData, fwd_setposition, &args); - LeaveCriticalSection(This->crst); - - if (bChangeCurrent) - This->fnChangeCurrent(This->pUserData); - if (bChangeStop) - This->fnChangeStop(This->pUserData); - - return S_OK; -} - -HRESULT WINAPI MediaSeekingImpl_GetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, LONGLONG * pStop) -{ - MediaSeekingImpl *This = (MediaSeekingImpl *)iface; - - TRACE("(%p, %p)\n", pCurrent, pStop); - - EnterCriticalSection(This->crst); - *pCurrent = This->llCurrent; - *pStop = This->llStop; - LeaveCriticalSection(This->crst); - - return S_OK; -} - -HRESULT WINAPI MediaSeekingImpl_GetAvailable(IMediaSeeking * iface, LONGLONG * pEarliest, LONGLONG * pLatest) -{ - MediaSeekingImpl *This = (MediaSeekingImpl *)iface; - - TRACE("(%p, %p)\n", pEarliest, pLatest); - - EnterCriticalSection(This->crst); - *pEarliest = 0; - *pLatest = This->llDuration; - LeaveCriticalSection(This->crst); - - return S_OK; -} - -HRESULT WINAPI MediaSeekingImpl_SetRate(IMediaSeeking * iface, double dRate) -{ - MediaSeekingImpl *This = (MediaSeekingImpl *)iface; - BOOL bChangeRate = (dRate != This->dRate); - HRESULT hr = S_OK; - - TRACE("(%e)\n", dRate); - - if (dRate > 100 || dRate < .001) - { - FIXME("Excessive rate %e, ignoring\n", dRate); - return VFW_E_UNSUPPORTED_AUDIO; - } - - EnterCriticalSection(This->crst); - This->dRate = dRate; - if (bChangeRate) - hr = This->fnChangeRate(This->pUserData); - ForwardCmdSeek(This->crst, This->pUserData, fwd_setrate, &dRate); - LeaveCriticalSection(This->crst); - - return hr; -} - -HRESULT WINAPI MediaSeekingImpl_GetRate(IMediaSeeking * iface, double * dRate) -{ - MediaSeekingImpl *This = (MediaSeekingImpl *)iface; - - TRACE("(%p)\n", dRate); - - EnterCriticalSection(This->crst); - /* Forward? */ - *dRate = This->dRate; - LeaveCriticalSection(This->crst); - - return S_OK; -} - -HRESULT WINAPI MediaSeekingImpl_GetPreroll(IMediaSeeking * iface, LONGLONG * pPreroll) -{ - TRACE("(%p)\n", pPreroll); - - *pPreroll = 0; - return S_OK; -} - -static HRESULT WINAPI MediaSeekingPassThru_QueryInterface(IMediaSeeking *iface, REFIID riid, LPVOID *ppvObj) -{ - ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); - - TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj); - - return SeekOuter_QueryInterface(This, riid, ppvObj); -} - -static ULONG WINAPI MediaSeekingPassThru_AddRef(IMediaSeeking *iface) -{ - ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); - - TRACE("(%p/%p)->()\n", iface, This); - - return SeekOuter_AddRef(This); -} - -static ULONG WINAPI MediaSeekingPassThru_Release(IMediaSeeking *iface) -{ - ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); - - TRACE("(%p/%p)->()\n", iface, This); - - return SeekOuter_Release(This); -} - -static HRESULT WINAPI MediaSeekingPassThru_GetCapabilities(IMediaSeeking * iface, DWORD * pCapabilities) -{ - ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); - - TRACE("(%p/%p)->(%p)\n", iface, This, pCapabilities); - - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI MediaSeekingPassThru_CheckCapabilities(IMediaSeeking * iface, DWORD * pCapabilities) -{ - ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); - - TRACE("(%p/%p)->(%p)\n", iface, This, pCapabilities); - - if (!pCapabilities) - return E_POINTER; - - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI MediaSeekingPassThru_IsFormatSupported(IMediaSeeking * iface, const GUID * pFormat) -{ - ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); - TRACE("(%p/%p)->(%s)\n", iface, This, qzdebugstr_guid(pFormat)); - - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI MediaSeekingPassThru_QueryPreferredFormat(IMediaSeeking * iface, GUID * pFormat) -{ - ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); - TRACE("(%p/%p)->(%p)\n", iface, This, pFormat); - - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI MediaSeekingPassThru_GetTimeFormat(IMediaSeeking * iface, GUID * pFormat) -{ - ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); - TRACE("(%p/%p)->(%p)\n", iface, This, pFormat); - - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI MediaSeekingPassThru_IsUsingTimeFormat(IMediaSeeking * iface, const GUID * pFormat) -{ - ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); - - TRACE("(%p/%p)->(%s)\n", iface, This, qzdebugstr_guid(pFormat)); - - FIXME("stub\n"); - return E_NOTIMPL; -} - - -static HRESULT WINAPI MediaSeekingPassThru_SetTimeFormat(IMediaSeeking * iface, const GUID * pFormat) -{ - ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); - TRACE("(%p/%p)->(%s)\n", iface, This, qzdebugstr_guid(pFormat)); - - FIXME("stub\n"); - return E_NOTIMPL; -} - - -static HRESULT WINAPI MediaSeekingPassThru_GetDuration(IMediaSeeking * iface, LONGLONG * pDuration) -{ - ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); - PIN_INFO info; - HRESULT hr; - - TRACE("(%p/%p)->(%p)\n", iface, This, pDuration); - - IPin_QueryPinInfo(This->pin, &info); - - hr = ForwardCmdSeek(NULL, info.pFilter, fwd_getduration, pDuration); - IBaseFilter_Release(info.pFilter); - - return hr; -} - -static HRESULT WINAPI MediaSeekingPassThru_GetStopPosition(IMediaSeeking * iface, LONGLONG * pStop) -{ - ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); - - TRACE("(%p/%p)->(%p)\n", iface, This, pStop); - - FIXME("stub\n"); - return E_NOTIMPL; -} - -/* FIXME: Make use of the info the filter should expose */ -static HRESULT WINAPI MediaSeekingPassThru_GetCurrentPosition(IMediaSeeking * iface, LONGLONG * pCurrent) -{ - ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); - - TRACE("(%p/%p)->(%p)\n", iface, This, pCurrent); - - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI MediaSeekingPassThru_ConvertTimeFormat(IMediaSeeking * iface, LONGLONG * pTarget, const GUID * pTargetFormat, LONGLONG Source, const GUID * pSourceFormat) -{ - ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); - - TRACE("(%p/%p)->(%p,%s,%x%08x,%s)\n", iface, This, pTarget, debugstr_guid(pTargetFormat), (DWORD)(Source>>32), (DWORD)Source, debugstr_guid(pSourceFormat)); - - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI MediaSeekingPassThru_SetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, DWORD dwCurrentFlags, LONGLONG * pStop, DWORD dwStopFlags) -{ - ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); - struct pos_args args; - PIN_INFO info; - HRESULT hr; - - TRACE("(%p/%p)->(%p, %p)\n", iface, This, pCurrent, pStop); - args.current = pCurrent; - args.stop = pStop; - args.curflags = dwCurrentFlags; - args.stopflags = dwStopFlags; - - IPin_QueryPinInfo(This->pin, &info); - - hr = ForwardCmdSeek(NULL, info.pFilter, fwd_setposition, &args); - IBaseFilter_Release(info.pFilter); - return hr; -} - -static HRESULT WINAPI MediaSeekingPassThru_GetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, LONGLONG * pStop) -{ - ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); - - TRACE("(%p/%p)->(%p, %p)\n", iface, This, pCurrent, pStop); - - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI MediaSeekingPassThru_GetAvailable(IMediaSeeking * iface, LONGLONG * pEarliest, LONGLONG * pLatest) -{ - ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); - - TRACE("(%p/%p)->(%p,%p)\n", iface, This, pEarliest, pLatest); - - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI MediaSeekingPassThru_SetRate(IMediaSeeking * iface, double dRate) -{ - ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); - - TRACE("(%p/%p)->(%e)\n", iface, This, dRate); - - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI MediaSeekingPassThru_GetRate(IMediaSeeking * iface, double * dRate) -{ - ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); - - TRACE("(%p/%p)->(%p)\n", iface, This, dRate); - - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI MediaSeekingPassThru_GetPreroll(IMediaSeeking * iface, LONGLONG * pPreroll) -{ - TRACE("(%p)\n", pPreroll); - - FIXME("stub\n"); - return E_NOTIMPL; -} - -static const IMediaSeekingVtbl IMediaSeekingPassThru_Vtbl = -{ - MediaSeekingPassThru_QueryInterface, - MediaSeekingPassThru_AddRef, - MediaSeekingPassThru_Release, - MediaSeekingPassThru_GetCapabilities, - MediaSeekingPassThru_CheckCapabilities, - MediaSeekingPassThru_IsFormatSupported, - MediaSeekingPassThru_QueryPreferredFormat, - MediaSeekingPassThru_GetTimeFormat, - MediaSeekingPassThru_IsUsingTimeFormat, - MediaSeekingPassThru_SetTimeFormat, - MediaSeekingPassThru_GetDuration, - MediaSeekingPassThru_GetStopPosition, - MediaSeekingPassThru_GetCurrentPosition, - MediaSeekingPassThru_ConvertTimeFormat, - MediaSeekingPassThru_SetPositions, - MediaSeekingPassThru_GetPositions, - MediaSeekingPassThru_GetAvailable, - MediaSeekingPassThru_SetRate, - MediaSeekingPassThru_GetRate, - MediaSeekingPassThru_GetPreroll -}; diff --git a/dlls/quartz/control_private.h b/dlls/quartz/control_private.h deleted file mode 100644 index b5e3997..0000000 --- a/dlls/quartz/control_private.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Filter Seeking and Control Interfaces - * - * Copyright 2003 Robert Shearman - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#ifndef QUARTZ_CONTROL_H -#define QUARTZ_CONTROL_H - -typedef HRESULT (* CHANGEPROC)(IBaseFilter *pUserData); - -typedef struct MediaSeekingImpl -{ - const IMediaSeekingVtbl * lpVtbl; - - ULONG refCount; - IBaseFilter *pUserData; - CHANGEPROC fnChangeStop; - CHANGEPROC fnChangeCurrent; - CHANGEPROC fnChangeRate; - DWORD dwCapabilities; - double dRate; - LONGLONG llCurrent, llStop, llDuration; - GUID timeformat; - PCRITICAL_SECTION crst; -} MediaSeekingImpl; - -HRESULT MediaSeekingImpl_Init(IBaseFilter *pUserData, CHANGEPROC fnChangeStop, CHANGEPROC fnChangeCurrent, CHANGEPROC fnChangeRate, MediaSeekingImpl * pSeeking, PCRITICAL_SECTION crit_sect); - -HRESULT WINAPI MediaSeekingImpl_GetCapabilities(IMediaSeeking * iface, DWORD * pCapabilities); -HRESULT WINAPI MediaSeekingImpl_CheckCapabilities(IMediaSeeking * iface, DWORD * pCapabilities); -HRESULT WINAPI MediaSeekingImpl_IsFormatSupported(IMediaSeeking * iface, const GUID * pFormat); -HRESULT WINAPI MediaSeekingImpl_QueryPreferredFormat(IMediaSeeking * iface, GUID * pFormat); -HRESULT WINAPI MediaSeekingImpl_GetTimeFormat(IMediaSeeking * iface, GUID * pFormat); -HRESULT WINAPI MediaSeekingImpl_IsUsingTimeFormat(IMediaSeeking * iface, const GUID * pFormat); -HRESULT WINAPI MediaSeekingImpl_SetTimeFormat(IMediaSeeking * iface, const GUID * pFormat); -HRESULT WINAPI MediaSeekingImpl_GetDuration(IMediaSeeking * iface, LONGLONG * pDuration); -HRESULT WINAPI MediaSeekingImpl_GetStopPosition(IMediaSeeking * iface, LONGLONG * pStop); -HRESULT WINAPI MediaSeekingImpl_GetCurrentPosition(IMediaSeeking * iface, LONGLONG * pCurrent); -HRESULT WINAPI MediaSeekingImpl_ConvertTimeFormat(IMediaSeeking * iface, LONGLONG * pTarget, const GUID * pTargetFormat, LONGLONG Source, const GUID * pSourceFormat); -HRESULT WINAPI MediaSeekingImpl_SetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, DWORD dwCurrentFlags, LONGLONG * pStop, DWORD dwStopFlags); -HRESULT WINAPI MediaSeekingImpl_GetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, LONGLONG * pStop); -HRESULT WINAPI MediaSeekingImpl_GetAvailable(IMediaSeeking * iface, LONGLONG * pEarliest, LONGLONG * pLatest); -HRESULT WINAPI MediaSeekingImpl_SetRate(IMediaSeeking * iface, double dRate); -HRESULT WINAPI MediaSeekingImpl_GetRate(IMediaSeeking * iface, double * dRate); -HRESULT WINAPI MediaSeekingImpl_GetPreroll(IMediaSeeking * iface, LONGLONG * pPreroll); - -#endif /*QUARTZ_CONTROL_H*/ diff --git a/dlls/quartz/dsoundrender.c b/dlls/quartz/dsoundrender.c index aae7e68..4bd79a2 100644 --- a/dlls/quartz/dsoundrender.c +++ b/dlls/quartz/dsoundrender.c @@ -21,8 +21,6 @@ #include "config.h" #include "quartz_private.h" -#include "control_private.h" -#include "pin.h" #include "uuids.h" #include "vfwmsgs.h" diff --git a/dlls/quartz/enummedia.c b/dlls/quartz/enummedia.c deleted file mode 100644 index ed5edb3..0000000 --- a/dlls/quartz/enummedia.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Implementation of IEnumMediaTypes Interface - * - * Copyright 2003 Robert Shearman - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "quartz_private.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(quartz); - -HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc) -{ - *pDest = *pSrc; - if (!pSrc->pbFormat) return S_OK; - if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat))) - return E_OUTOFMEMORY; - memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat); - if (pDest->pUnk) - IUnknown_AddRef(pDest->pUnk); - return S_OK; -} - -void FreeMediaType(AM_MEDIA_TYPE * pMediaType) -{ - if (pMediaType->pbFormat) - { - CoTaskMemFree(pMediaType->pbFormat); - pMediaType->pbFormat = NULL; - } - if (pMediaType->pUnk) - { - IUnknown_Release(pMediaType->pUnk); - pMediaType->pUnk = NULL; - } -} - -static AM_MEDIA_TYPE * CreateMediaType(AM_MEDIA_TYPE const * pSrc) -{ - AM_MEDIA_TYPE * pDest; - - pDest = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); - if (!pDest) - return NULL; - - if (FAILED(CopyMediaType(pDest, pSrc))) - { - CoTaskMemFree(pDest); - return NULL; - } - - return pDest; -} - -void DeleteMediaType(AM_MEDIA_TYPE * pMediaType) -{ - FreeMediaType(pMediaType); - CoTaskMemFree(pMediaType); -} - -BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards) -{ - TRACE("pmt1: "); - dump_AM_MEDIA_TYPE(pmt1); - TRACE("pmt2: "); - dump_AM_MEDIA_TYPE(pmt2); - return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) && - ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype))); -} - -void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt) -{ - if (!pmt) - return; - TRACE("\t%s\n\t%s\n\t...\n\t%s\n", qzdebugstr_guid(&pmt->majortype), qzdebugstr_guid(&pmt->subtype), qzdebugstr_guid(&pmt->formattype)); -} - -typedef struct IEnumMediaTypesImpl -{ - const IEnumMediaTypesVtbl * lpVtbl; - LONG refCount; - ENUMMEDIADETAILS enumMediaDetails; - ULONG uIndex; -} IEnumMediaTypesImpl; - -static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl; - -HRESULT IEnumMediaTypesImpl_Construct(const ENUMMEDIADETAILS * pDetails, IEnumMediaTypes ** ppEnum) -{ - ULONG i; - IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl)); - - if (!pEnumMediaTypes) - { - *ppEnum = NULL; - return E_OUTOFMEMORY; - } - pEnumMediaTypes->lpVtbl = &IEnumMediaTypesImpl_Vtbl; - pEnumMediaTypes->refCount = 1; - pEnumMediaTypes->uIndex = 0; - pEnumMediaTypes->enumMediaDetails.cMediaTypes = pDetails->cMediaTypes; - pEnumMediaTypes->enumMediaDetails.pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * pDetails->cMediaTypes); - for (i = 0; i < pDetails->cMediaTypes; i++) - if (FAILED(CopyMediaType(&pEnumMediaTypes->enumMediaDetails.pMediaTypes[i], &pDetails->pMediaTypes[i]))) - { - while (i--) - CoTaskMemFree(pEnumMediaTypes->enumMediaDetails.pMediaTypes[i].pbFormat); - CoTaskMemFree(pEnumMediaTypes->enumMediaDetails.pMediaTypes); - return E_OUTOFMEMORY; - } - *ppEnum = (IEnumMediaTypes *)(&pEnumMediaTypes->lpVtbl); - return S_OK; -} - -static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv) -{ - TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv); - - *ppv = NULL; - - if (IsEqualIID(riid, &IID_IUnknown)) - *ppv = (LPVOID)iface; - else if (IsEqualIID(riid, &IID_IEnumMediaTypes)) - *ppv = (LPVOID)iface; - - if (*ppv) - { - IUnknown_AddRef((IUnknown *)(*ppv)); - return S_OK; - } - - FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); - - return E_NOINTERFACE; -} - -static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface) -{ - IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface; - ULONG refCount = InterlockedIncrement(&This->refCount); - - TRACE("(%p)->() AddRef from %d\n", iface, refCount - 1); - - return refCount; -} - -static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface) -{ - IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface; - ULONG refCount = InterlockedDecrement(&This->refCount); - - TRACE("(%p)->() Release from %d\n", iface, refCount + 1); - - if (!refCount) - { - int i; - for (i = 0; i < This->enumMediaDetails.cMediaTypes; i++) - if (This->enumMediaDetails.pMediaTypes[i].pbFormat) - CoTaskMemFree(This->enumMediaDetails.pMediaTypes[i].pbFormat); - CoTaskMemFree(This->enumMediaDetails.pMediaTypes); - CoTaskMemFree(This); - } - return refCount; -} - -static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched) -{ - ULONG cFetched; - IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface; - - cFetched = min(This->enumMediaDetails.cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex; - - TRACE("(%u, %p, %p)\n", cMediaTypes, ppMediaTypes, pcFetched); - TRACE("Next uIndex: %u, cFetched: %u\n", This->uIndex, cFetched); - - if (cFetched > 0) - { - ULONG i; - for (i = 0; i < cFetched; i++) - if (!(ppMediaTypes[i] = CreateMediaType(&This->enumMediaDetails.pMediaTypes[This->uIndex + i]))) - { - while (i--) - DeleteMediaType(ppMediaTypes[i]); - *pcFetched = 0; - return E_OUTOFMEMORY; - } - } - - if ((cMediaTypes != 1) || pcFetched) - *pcFetched = cFetched; - - This->uIndex += cFetched; - - if (cFetched != cMediaTypes) - return S_FALSE; - return S_OK; -} - -static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes) -{ - IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface; - - TRACE("(%u)\n", cMediaTypes); - - if (This->uIndex + cMediaTypes < This->enumMediaDetails.cMediaTypes) - { - This->uIndex += cMediaTypes; - return S_OK; - } - return S_FALSE; -} - -static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface) -{ - IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface; - - TRACE("()\n"); - - This->uIndex = 0; - return S_OK; -} - -static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum) -{ - HRESULT hr; - IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface; - - TRACE("(%p)\n", ppEnum); - - hr = IEnumMediaTypesImpl_Construct(&This->enumMediaDetails, ppEnum); - if (FAILED(hr)) - return hr; - return IEnumMediaTypes_Skip(*ppEnum, This->uIndex); -} - -static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl = -{ - IEnumMediaTypesImpl_QueryInterface, - IEnumMediaTypesImpl_AddRef, - IEnumMediaTypesImpl_Release, - IEnumMediaTypesImpl_Next, - IEnumMediaTypesImpl_Skip, - IEnumMediaTypesImpl_Reset, - IEnumMediaTypesImpl_Clone -}; diff --git a/dlls/quartz/enumpins.c b/dlls/quartz/enumpins.c deleted file mode 100644 index 82dac9d..0000000 --- a/dlls/quartz/enumpins.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Implementation of IEnumPins Interface - * - * Copyright 2003 Robert Shearman - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "quartz_private.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(quartz); - -typedef struct IEnumPinsImpl -{ - const IEnumPinsVtbl * lpVtbl; - LONG refCount; - ULONG uIndex; - IBaseFilter *base; - FNOBTAINPIN receive_pin; - DWORD synctime; -} IEnumPinsImpl; - -static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl; - -HRESULT IEnumPinsImpl_Construct(IEnumPins ** ppEnum, FNOBTAINPIN receive_pin, IBaseFilter *base) -{ - IEnumPinsImpl * pEnumPins; - - if (!ppEnum) - return E_POINTER; - - pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl)); - if (!pEnumPins) - { - *ppEnum = NULL; - return E_OUTOFMEMORY; - } - pEnumPins->lpVtbl = &IEnumPinsImpl_Vtbl; - pEnumPins->refCount = 1; - pEnumPins->uIndex = 0; - pEnumPins->receive_pin = receive_pin; - pEnumPins->base = base; - IBaseFilter_AddRef(base); - *ppEnum = (IEnumPins *)(&pEnumPins->lpVtbl); - - receive_pin(base, ~0, NULL, &pEnumPins->synctime); - - TRACE("Created new enumerator (%p)\n", *ppEnum); - return S_OK; -} - -static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv) -{ - TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv); - - *ppv = NULL; - - if (IsEqualIID(riid, &IID_IUnknown)) - *ppv = (LPVOID)iface; - else if (IsEqualIID(riid, &IID_IEnumPins)) - *ppv = (LPVOID)iface; - - if (*ppv) - { - IUnknown_AddRef((IUnknown *)(*ppv)); - return S_OK; - } - - FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); - - return E_NOINTERFACE; -} - -static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface) -{ - IEnumPinsImpl *This = (IEnumPinsImpl *)iface; - ULONG refCount = InterlockedIncrement(&This->refCount); - - TRACE("(%p)->() AddRef from %d\n", This, refCount - 1); - - return refCount; -} - -static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface) -{ - IEnumPinsImpl *This = (IEnumPinsImpl *)iface; - ULONG refCount = InterlockedDecrement(&This->refCount); - - TRACE("(%p)->() Release from %d\n", This, refCount + 1); - - if (!refCount) - { - IBaseFilter_Release(This->base); - CoTaskMemFree(This); - return 0; - } - else - return refCount; -} - -static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched) -{ - IEnumPinsImpl *This = (IEnumPinsImpl *)iface; - DWORD synctime = This->synctime; - HRESULT hr = S_OK; - ULONG i = 0; - - TRACE("(%u, %p, %p)\n", cPins, ppPins, pcFetched); - - if (!ppPins) - return E_POINTER; - - if (cPins > 1 && !pcFetched) - return E_INVALIDARG; - - if (pcFetched) - *pcFetched = 0; - - while (i < cPins && hr == S_OK) - { - hr = This->receive_pin(This->base, This->uIndex + i, &ppPins[i], &synctime); - - if (hr == S_OK) - ++i; - - if (synctime != This->synctime) - break; - } - - if (!i && synctime != This->synctime) - return VFW_E_ENUM_OUT_OF_SYNC; - - if (pcFetched) - *pcFetched = i; - This->uIndex += i; - - if (i < cPins) - return S_FALSE; - return S_OK; -} - -static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins) -{ - IEnumPinsImpl *This = (IEnumPinsImpl *)iface; - DWORD synctime = This->synctime; - HRESULT hr; - IPin *pin = NULL; - - TRACE("(%u)\n", cPins); - - hr = This->receive_pin(This->base, This->uIndex + cPins, &pin, &synctime); - if (pin) - IPin_Release(pin); - - if (synctime != This->synctime) - return VFW_E_ENUM_OUT_OF_SYNC; - - if (hr == S_OK) - This->uIndex += cPins; - - return hr; -} - -static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface) -{ - IEnumPinsImpl *This = (IEnumPinsImpl *)iface; - - TRACE("IEnumPinsImpl::Reset()\n"); - This->receive_pin(This->base, ~0, NULL, &This->synctime); - - This->uIndex = 0; - return S_OK; -} - -static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum) -{ - HRESULT hr; - IEnumPinsImpl *This = (IEnumPinsImpl *)iface; - - TRACE("(%p)\n", ppEnum); - - hr = IEnumPinsImpl_Construct(ppEnum, This->receive_pin, This->base); - if (FAILED(hr)) - return hr; - return IEnumPins_Skip(*ppEnum, This->uIndex); -} - -static const IEnumPinsVtbl IEnumPinsImpl_Vtbl = -{ - IEnumPinsImpl_QueryInterface, - IEnumPinsImpl_AddRef, - IEnumPinsImpl_Release, - IEnumPinsImpl_Next, - IEnumPinsImpl_Skip, - IEnumPinsImpl_Reset, - IEnumPinsImpl_Clone -}; diff --git a/dlls/quartz/filesource.c b/dlls/quartz/filesource.c index 2a063e2..c8aeb05 100644 --- a/dlls/quartz/filesource.c +++ b/dlls/quartz/filesource.c @@ -25,7 +25,6 @@ #include "wine/debug.h" #include "wine/unicode.h" -#include "pin.h" #include "uuids.h" #include "vfwmsgs.h" #include "winbase.h" diff --git a/dlls/quartz/main.c b/dlls/quartz/main.c index daefdc5..8541550 100644 --- a/dlls/quartz/main.c +++ b/dlls/quartz/main.c @@ -211,55 +211,6 @@ HRESULT WINAPI DllCanUnloadNow(void) return dll_ref != 0 ? S_FALSE : S_OK; } - -#define OUR_GUID_ENTRY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ - { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } , #name }, - -static const struct { - const GUID riid; - const char *name; -} InterfaceDesc[] = -{ -#include "uuids.h" - { { 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0} }, NULL } -}; - -/*********************************************************************** - * qzdebugstr_guid (internal) - * - * Gives a text version of DirectShow GUIDs - */ -const char * qzdebugstr_guid( const GUID * id ) -{ - int i; - char * name = NULL; - - for (i=0;InterfaceDesc[i].name && !name;i++) { - if (IsEqualGUID(&InterfaceDesc[i].riid, id)) return InterfaceDesc[i].name; - } - return debugstr_guid(id); -} - -/*********************************************************************** - * qzdebugstr_State (internal) - * - * Gives a text version of the FILTER_STATE enumeration - */ -const char * qzdebugstr_State(FILTER_STATE state) -{ - switch (state) - { - case State_Stopped: - return "State_Stopped"; - case State_Running: - return "State_Running"; - case State_Paused: - return "State_Paused"; - default: - return "State_Unknown"; - } -} - LONG WINAPI AmpFactorToDB(LONG ampfactor) { FIXME("(%d) Stub!\n", ampfactor); diff --git a/dlls/quartz/memallocator.c b/dlls/quartz/memallocator.c deleted file mode 100644 index 2ee8d71..0000000 --- a/dlls/quartz/memallocator.c +++ /dev/null @@ -1,883 +0,0 @@ -/* - * Memory Allocator and Media Sample Implementation - * - * Copyright 2003 Robert Shearman - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "vfwmsgs.h" - -#include "quartz_private.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(quartz); - -void dump_AM_SAMPLE2_PROPERTIES(const AM_SAMPLE2_PROPERTIES * pProps) -{ - if (!pProps) - { - TRACE("AM_SAMPLE2_PROPERTIES: (null)\n"); - return; - } - TRACE("\tcbData: %d\n", pProps->cbData); - TRACE("\tdwTypeSpecificFlags: 0x%8x\n", pProps->dwTypeSpecificFlags); - TRACE("\tdwSampleFlags: 0x%8x\n", pProps->dwSampleFlags); - TRACE("\tlActual: %d\n", pProps->lActual); - TRACE("\ttStart: %x%08x%s\n", (LONG)(pProps->tStart >> 32), (LONG)pProps->tStart, pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID ? "" : " (not valid)"); - TRACE("\ttStop: %x%08x%s\n", (LONG)(pProps->tStop >> 32), (LONG)pProps->tStop, pProps->dwSampleFlags & AM_SAMPLE_STOPVALID ? "" : " (not valid)"); - TRACE("\tdwStreamId: 0x%x\n", pProps->dwStreamId); - TRACE("\tpMediaType: %p\n", pProps->pMediaType); - TRACE("\tpbBuffer: %p\n", pProps->pbBuffer); - TRACE("\tcbBuffer: %d\n", pProps->cbBuffer); -} - -static const IMemAllocatorVtbl BaseMemAllocator_VTable; -static const IMediaSample2Vtbl StdMediaSample2_VTable; - -#define AM_SAMPLE2_PROP_SIZE_WRITABLE (unsigned int)(&((AM_SAMPLE2_PROPERTIES *)0)->pbBuffer) - -#define INVALID_MEDIA_TIME (((ULONGLONG)0x7fffffff << 32) | 0xffffffff) - -HRESULT BaseMemAllocator_Init(HRESULT (* fnAlloc)(IMemAllocator *), - HRESULT (* fnFree)(IMemAllocator *), - HRESULT (* fnVerify)(IMemAllocator *, ALLOCATOR_PROPERTIES *), - HRESULT (* fnBufferPrepare)(IMemAllocator *, StdMediaSample2 *, DWORD), - HRESULT (* fnBufferReleased)(IMemAllocator *, StdMediaSample2 *), - void (* fnDestroyed)(IMemAllocator *), - CRITICAL_SECTION *pCritSect, - BaseMemAllocator * pMemAlloc) -{ - assert(fnAlloc && fnFree && fnDestroyed); - - pMemAlloc->lpVtbl = &BaseMemAllocator_VTable; - - pMemAlloc->ref = 1; - ZeroMemory(&pMemAlloc->props, sizeof(pMemAlloc->props)); - list_init(&pMemAlloc->free_list); - list_init(&pMemAlloc->used_list); - pMemAlloc->fnAlloc = fnAlloc; - pMemAlloc->fnFree = fnFree; - pMemAlloc->fnVerify = fnVerify; - pMemAlloc->fnBufferPrepare = fnBufferPrepare; - pMemAlloc->fnBufferReleased = fnBufferReleased; - pMemAlloc->fnDestroyed = fnDestroyed; - pMemAlloc->bDecommitQueued = FALSE; - pMemAlloc->bCommitted = FALSE; - pMemAlloc->hSemWaiting = NULL; - pMemAlloc->lWaiting = 0; - pMemAlloc->pCritSect = pCritSect; - - return S_OK; -} - -static HRESULT WINAPI BaseMemAllocator_QueryInterface(IMemAllocator * iface, REFIID riid, LPVOID * ppv) -{ - BaseMemAllocator *This = (BaseMemAllocator *)iface; - TRACE("(%p)->(%s, %p)\n", This, qzdebugstr_guid(riid), ppv); - - *ppv = NULL; - - if (IsEqualIID(riid, &IID_IUnknown)) - *ppv = (LPVOID)This; - else if (IsEqualIID(riid, &IID_IMemAllocator)) - *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 BaseMemAllocator_AddRef(IMemAllocator * iface) -{ - BaseMemAllocator *This = (BaseMemAllocator *)iface; - ULONG ref = InterlockedIncrement(&This->ref); - - TRACE("(%p)->() AddRef from %d\n", iface, ref - 1); - - return ref; -} - -static ULONG WINAPI BaseMemAllocator_Release(IMemAllocator * iface) -{ - BaseMemAllocator *This = (BaseMemAllocator *)iface; - ULONG ref = InterlockedDecrement(&This->ref); - - TRACE("(%p)->() Release from %d\n", iface, ref + 1); - - if (!ref) - { - CloseHandle(This->hSemWaiting); - if (This->bCommitted) - This->fnFree(iface); - - This->fnDestroyed(iface); - return 0; - } - return ref; -} - -static HRESULT WINAPI BaseMemAllocator_SetProperties(IMemAllocator * iface, ALLOCATOR_PROPERTIES *pRequest, ALLOCATOR_PROPERTIES *pActual) -{ - BaseMemAllocator *This = (BaseMemAllocator *)iface; - HRESULT hr; - - TRACE("(%p)->(%p, %p)\n", This, pRequest, pActual); - - EnterCriticalSection(This->pCritSect); - { - if (!list_empty(&This->used_list)) - hr = VFW_E_BUFFERS_OUTSTANDING; - else if (This->bCommitted) - hr = VFW_E_ALREADY_COMMITTED; - else if (pRequest->cbAlign == 0) - hr = VFW_E_BADALIGN; - else - { - if (This->fnVerify) - hr = This->fnVerify(iface, pRequest); - else - hr = S_OK; - - if (SUCCEEDED(hr)) - This->props = *pRequest; - - *pActual = This->props; - } - } - LeaveCriticalSection(This->pCritSect); - - return hr; -} - -static HRESULT WINAPI BaseMemAllocator_GetProperties(IMemAllocator * iface, ALLOCATOR_PROPERTIES *pProps) -{ - BaseMemAllocator *This = (BaseMemAllocator *)iface; - HRESULT hr = S_OK; - - TRACE("(%p)->(%p)\n", This, pProps); - - EnterCriticalSection(This->pCritSect); - { - memcpy(pProps, &This->props, sizeof(*pProps)); - } - LeaveCriticalSection(This->pCritSect); - - return hr; -} - -static HRESULT WINAPI BaseMemAllocator_Commit(IMemAllocator * iface) -{ - BaseMemAllocator *This = (BaseMemAllocator *)iface; - HRESULT hr; - - TRACE("(%p)->()\n", This); - - EnterCriticalSection(This->pCritSect); - { - if (!This->props.cbAlign) - hr = VFW_E_BADALIGN; - else if (!This->props.cbBuffer) - hr = VFW_E_SIZENOTSET; - else if (!This->props.cBuffers) - hr = VFW_E_BUFFER_NOTSET; - else if (This->bDecommitQueued && This->bCommitted) - { - This->bDecommitQueued = FALSE; - hr = S_OK; - } - else if (This->bCommitted) - hr = S_OK; - else - { - if (!(This->hSemWaiting = CreateSemaphoreW(NULL, This->props.cBuffers, This->props.cBuffers, NULL))) - { - ERR("Couldn't create semaphore (error was %u)\n", GetLastError()); - hr = HRESULT_FROM_WIN32(GetLastError()); - } - else - { - hr = This->fnAlloc(iface); - if (SUCCEEDED(hr)) - This->bCommitted = TRUE; - else - ERR("fnAlloc failed with error 0x%x\n", hr); - } - } - } - LeaveCriticalSection(This->pCritSect); - - return hr; -} - -static HRESULT WINAPI BaseMemAllocator_Decommit(IMemAllocator * iface) -{ - BaseMemAllocator *This = (BaseMemAllocator *)iface; - HRESULT hr; - - TRACE("(%p)->()\n", This); - - EnterCriticalSection(This->pCritSect); - { - if (!This->bCommitted) - hr = S_OK; - else - { - if (!list_empty(&This->used_list)) - { - This->bDecommitQueued = TRUE; - /* notify ALL waiting threads that they cannot be allocated a buffer any more */ - ReleaseSemaphore(This->hSemWaiting, This->lWaiting, NULL); - - hr = S_OK; - } - else - { - if (This->lWaiting != 0) - ERR("Waiting: %d\n", This->lWaiting); - - This->bCommitted = FALSE; - CloseHandle(This->hSemWaiting); - This->hSemWaiting = NULL; - - hr = This->fnFree(iface); - if (FAILED(hr)) - ERR("fnFree failed with error 0x%x\n", hr); - } - } - } - LeaveCriticalSection(This->pCritSect); - - return hr; -} - -static HRESULT WINAPI BaseMemAllocator_GetBuffer(IMemAllocator * iface, IMediaSample ** pSample, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime, DWORD dwFlags) -{ - BaseMemAllocator *This = (BaseMemAllocator *)iface; - HRESULT hr = S_OK; - - /* NOTE: The pStartTime and pEndTime parameters are not applied to the sample. - * The allocator might use these values to determine which buffer it retrieves */ - - TRACE("(%p)->(%p, %p, %p, %x)\n", This, pSample, pStartTime, pEndTime, dwFlags); - - *pSample = NULL; - - EnterCriticalSection(This->pCritSect); - if (!This->bCommitted || This->bDecommitQueued) - { - WARN("Not committed\n"); - hr = VFW_E_NOT_COMMITTED; - } - else - ++This->lWaiting; - LeaveCriticalSection(This->pCritSect); - if (FAILED(hr)) - return hr; - - if (WaitForSingleObject(This->hSemWaiting, (dwFlags & AM_GBF_NOWAIT) ? 0 : INFINITE) != WAIT_OBJECT_0) - { - EnterCriticalSection(This->pCritSect); - --This->lWaiting; - LeaveCriticalSection(This->pCritSect); - WARN("Timed out\n"); - return VFW_E_TIMEOUT; - } - - EnterCriticalSection(This->pCritSect); - { - --This->lWaiting; - if (!This->bCommitted) - hr = VFW_E_NOT_COMMITTED; - else if (This->bDecommitQueued) - hr = VFW_E_TIMEOUT; - else - { - struct list * free = list_head(&This->free_list); - list_remove(free); - list_add_head(&This->used_list, free); - - *pSample = (IMediaSample *)LIST_ENTRY(free, StdMediaSample2, listentry); - - assert(((StdMediaSample2 *)*pSample)->ref == 0); - - IMediaSample_AddRef(*pSample); - } - } - LeaveCriticalSection(This->pCritSect); - - if (hr != S_OK) - WARN("%08x\n", hr); - return hr; -} - -static HRESULT WINAPI BaseMemAllocator_ReleaseBuffer(IMemAllocator * iface, IMediaSample * pSample) -{ - BaseMemAllocator *This = (BaseMemAllocator *)iface; - StdMediaSample2 * pStdSample = (StdMediaSample2 *)pSample; - HRESULT hr = S_OK; - - TRACE("(%p)->(%p)\n", This, pSample); - - /* FIXME: make sure that sample is currently on the used list */ - - /* FIXME: we should probably check the ref count on the sample before freeing - * it to make sure that it is not still in use */ - EnterCriticalSection(This->pCritSect); - { - if (!This->bCommitted) - ERR("Releasing a buffer when the allocator is not committed?!?\n"); - - /* remove from used_list */ - list_remove(&pStdSample->listentry); - - list_add_head(&This->free_list, &pStdSample->listentry); - - if (list_empty(&This->used_list) && This->bDecommitQueued && This->bCommitted) - { - HRESULT hrfree; - - if (This->lWaiting != 0) - ERR("Waiting: %d\n", This->lWaiting); - - This->bCommitted = FALSE; - This->bDecommitQueued = FALSE; - - CloseHandle(This->hSemWaiting); - This->hSemWaiting = NULL; - - if (FAILED(hrfree = This->fnFree(iface))) - ERR("fnFree failed with error 0x%x\n", hrfree); - } - } - LeaveCriticalSection(This->pCritSect); - - /* notify a waiting thread that there is now a free buffer */ - if (This->hSemWaiting && !ReleaseSemaphore(This->hSemWaiting, 1, NULL)) - { - ERR("ReleaseSemaphore failed with error %u\n", GetLastError()); - hr = HRESULT_FROM_WIN32(GetLastError()); - } - - return hr; -} - -static const IMemAllocatorVtbl BaseMemAllocator_VTable = -{ - BaseMemAllocator_QueryInterface, - BaseMemAllocator_AddRef, - BaseMemAllocator_Release, - BaseMemAllocator_SetProperties, - BaseMemAllocator_GetProperties, - BaseMemAllocator_Commit, - BaseMemAllocator_Decommit, - BaseMemAllocator_GetBuffer, - BaseMemAllocator_ReleaseBuffer -}; - -HRESULT StdMediaSample2_Construct(BYTE * pbBuffer, LONG cbBuffer, IMemAllocator * pParent, StdMediaSample2 ** ppSample) -{ - assert(pbBuffer && pParent && (cbBuffer > 0)); - - if (!(*ppSample = CoTaskMemAlloc(sizeof(StdMediaSample2)))) - return E_OUTOFMEMORY; - - (*ppSample)->lpvtbl = &StdMediaSample2_VTable; - (*ppSample)->ref = 0; - ZeroMemory(&(*ppSample)->props, sizeof((*ppSample)->props)); - - /* NOTE: no need to AddRef as the parent is guaranteed to be around - * at least as long as us and we don't want to create circular - * dependencies on the ref count */ - (*ppSample)->pParent = pParent; - (*ppSample)->props.cbData = sizeof(AM_SAMPLE2_PROPERTIES); - (*ppSample)->props.cbBuffer = (*ppSample)->props.lActual = cbBuffer; - (*ppSample)->props.pbBuffer = pbBuffer; - (*ppSample)->tMediaStart = INVALID_MEDIA_TIME; - (*ppSample)->tMediaEnd = 0; - - return S_OK; -} - -void StdMediaSample2_Delete(StdMediaSample2 * This) -{ - /* NOTE: does not remove itself from the list it belongs to */ - CoTaskMemFree(This); -} - -static HRESULT WINAPI StdMediaSample2_QueryInterface(IMediaSample2 * iface, REFIID riid, LPVOID * ppv) -{ - StdMediaSample2 *This = (StdMediaSample2 *)iface; - TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv); - - *ppv = NULL; - - if (IsEqualIID(riid, &IID_IUnknown)) - *ppv = (LPVOID)This; - else if (IsEqualIID(riid, &IID_IMediaSample)) - *ppv = (LPVOID)This; - else if (IsEqualIID(riid, &IID_IMediaSample2)) - *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 StdMediaSample2_AddRef(IMediaSample2 * iface) -{ - StdMediaSample2 *This = (StdMediaSample2 *)iface; - ULONG ref = InterlockedIncrement(&This->ref); - - TRACE("(%p)->() AddRef from %d\n", iface, ref - 1); - - return ref; -} - -static ULONG WINAPI StdMediaSample2_Release(IMediaSample2 * iface) -{ - StdMediaSample2 *This = (StdMediaSample2 *)iface; - ULONG ref = InterlockedDecrement(&This->ref); - - TRACE("(%p)->() Release from %d\n", iface, ref + 1); - - if (!ref) - { - if (This->pParent) - IMemAllocator_ReleaseBuffer(This->pParent, (IMediaSample *)iface); - else - StdMediaSample2_Delete(This); - return 0; - } - return ref; -} - -static HRESULT WINAPI StdMediaSample2_GetPointer(IMediaSample2 * iface, BYTE ** ppBuffer) -{ - StdMediaSample2 *This = (StdMediaSample2 *)iface; - - TRACE("(%p)\n", ppBuffer); - - *ppBuffer = This->props.pbBuffer; - - if (!*ppBuffer) - { - ERR("Requested an unlocked surface and trying to lock regardless\n"); - return E_FAIL; - } - - return S_OK; -} - -static long WINAPI StdMediaSample2_GetSize(IMediaSample2 * iface) -{ - StdMediaSample2 *This = (StdMediaSample2 *)iface; - - TRACE("StdMediaSample2_GetSize()\n"); - - return This->props.cbBuffer; -} - -static HRESULT WINAPI StdMediaSample2_GetTime(IMediaSample2 * iface, REFERENCE_TIME * pStart, REFERENCE_TIME * pEnd) -{ - HRESULT hr; - StdMediaSample2 *This = (StdMediaSample2 *)iface; - - TRACE("(%p, %p)\n", pStart, pEnd); - - if (!(This->props.dwSampleFlags & AM_SAMPLE_TIMEVALID)) - hr = VFW_E_SAMPLE_TIME_NOT_SET; - else if (!(This->props.dwSampleFlags & AM_SAMPLE_STOPVALID)) - { - *pStart = This->props.tStart; - *pEnd = This->props.tStart + 1; - - hr = VFW_S_NO_STOP_TIME; - } - else - { - *pStart = This->props.tStart; - *pEnd = This->props.tStop; - - hr = S_OK; - } - - return S_OK; -} - -static HRESULT WINAPI StdMediaSample2_SetTime(IMediaSample2 * iface, REFERENCE_TIME * pStart, REFERENCE_TIME * pEnd) -{ - StdMediaSample2 *This = (StdMediaSample2 *)iface; - - TRACE("(%p, %p)\n", pStart, pEnd); - - if (pStart) - { - This->props.tStart = *pStart; - This->props.dwSampleFlags |= AM_SAMPLE_TIMEVALID; - } - else - This->props.dwSampleFlags &= ~AM_SAMPLE_TIMEVALID; - - if (pEnd) - { - This->props.tStop = *pEnd; - This->props.dwSampleFlags |= AM_SAMPLE_STOPVALID; - } - else - This->props.dwSampleFlags &= ~AM_SAMPLE_STOPVALID; - - return S_OK; -} - -static HRESULT WINAPI StdMediaSample2_IsSyncPoint(IMediaSample2 * iface) -{ - StdMediaSample2 *This = (StdMediaSample2 *)iface; - - TRACE("()\n"); - - return (This->props.dwSampleFlags & AM_SAMPLE_SPLICEPOINT) ? S_OK : S_FALSE; -} - -static HRESULT WINAPI StdMediaSample2_SetSyncPoint(IMediaSample2 * iface, BOOL bIsSyncPoint) -{ - StdMediaSample2 *This = (StdMediaSample2 *)iface; - - TRACE("(%s)\n", bIsSyncPoint ? "TRUE" : "FALSE"); - - if (bIsSyncPoint) - This->props.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT; - else - This->props.dwSampleFlags &= ~AM_SAMPLE_SPLICEPOINT; - - return S_OK; -} - -static HRESULT WINAPI StdMediaSample2_IsPreroll(IMediaSample2 * iface) -{ - StdMediaSample2 *This = (StdMediaSample2 *)iface; - - TRACE("()\n"); - - return (This->props.dwSampleFlags & AM_SAMPLE_PREROLL) ? S_OK : S_FALSE; -} - -static HRESULT WINAPI StdMediaSample2_SetPreroll(IMediaSample2 * iface, BOOL bIsPreroll) -{ - StdMediaSample2 *This = (StdMediaSample2 *)iface; - - TRACE("(%s)\n", bIsPreroll ? "TRUE" : "FALSE"); - - if (bIsPreroll) - This->props.dwSampleFlags |= AM_SAMPLE_PREROLL; - else - This->props.dwSampleFlags &= ~AM_SAMPLE_PREROLL; - - return S_OK; -} - -static LONG WINAPI StdMediaSample2_GetActualDataLength(IMediaSample2 * iface) -{ - StdMediaSample2 *This = (StdMediaSample2 *)iface; - - TRACE("()\n"); - - return This->props.lActual; -} - -static HRESULT WINAPI StdMediaSample2_SetActualDataLength(IMediaSample2 * iface, LONG len) -{ - StdMediaSample2 *This = (StdMediaSample2 *)iface; - - TRACE("(%d)\n", len); - - if ((len > This->props.cbBuffer) || (len < 0)) - { - WARN("Tried to set length to %d, while max is %d\n", len, This->props.cbBuffer); - return VFW_E_BUFFER_OVERFLOW; - } - else - { - This->props.lActual = len; - return S_OK; - } -} - -static HRESULT WINAPI StdMediaSample2_GetMediaType(IMediaSample2 * iface, AM_MEDIA_TYPE ** ppMediaType) -{ - StdMediaSample2 *This = (StdMediaSample2 *)iface; - - TRACE("(%p)\n", ppMediaType); - - if (!This->props.pMediaType) { - /* Make sure we return a NULL pointer (required by native Quartz dll) */ - if (ppMediaType) - *ppMediaType = NULL; - return S_FALSE; - } - - if (!(*ppMediaType = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)))) - return E_OUTOFMEMORY; - - return CopyMediaType(*ppMediaType, This->props.pMediaType); -} - -static HRESULT WINAPI StdMediaSample2_SetMediaType(IMediaSample2 * iface, AM_MEDIA_TYPE * pMediaType) -{ - StdMediaSample2 *This = (StdMediaSample2 *)iface; - - TRACE("(%p)\n", pMediaType); - - if (This->props.pMediaType) - FreeMediaType(This->props.pMediaType); - else if (!(This->props.pMediaType = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)))) - return E_OUTOFMEMORY; - - return CopyMediaType(This->props.pMediaType, pMediaType); -} - -static HRESULT WINAPI StdMediaSample2_IsDiscontinuity(IMediaSample2 * iface) -{ - StdMediaSample2 *This = (StdMediaSample2 *)iface; - - TRACE("()\n"); - - return (This->props.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) ? S_OK : S_FALSE; -} - -static HRESULT WINAPI StdMediaSample2_SetDiscontinuity(IMediaSample2 * iface, BOOL bIsDiscontinuity) -{ - StdMediaSample2 *This = (StdMediaSample2 *)iface; - - TRACE("(%s)\n", bIsDiscontinuity ? "TRUE" : "FALSE"); - - if (bIsDiscontinuity) - This->props.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY; - else - This->props.dwSampleFlags &= ~AM_SAMPLE_DATADISCONTINUITY; - - return S_OK; -} - -static HRESULT WINAPI StdMediaSample2_GetMediaTime(IMediaSample2 * iface, LONGLONG * pStart, LONGLONG * pEnd) -{ - StdMediaSample2 *This = (StdMediaSample2 *)iface; - - TRACE("(%p, %p)\n", pStart, pEnd); - - if (This->tMediaStart == INVALID_MEDIA_TIME) - return VFW_E_MEDIA_TIME_NOT_SET; - - *pStart = This->tMediaStart; - *pEnd = This->tMediaEnd; - - return E_NOTIMPL; -} - -static HRESULT WINAPI StdMediaSample2_SetMediaTime(IMediaSample2 * iface, LONGLONG * pStart, LONGLONG * pEnd) -{ - StdMediaSample2 *This = (StdMediaSample2 *)iface; - - TRACE("(%p, %p)\n", pStart, pEnd); - - if (pStart) - This->tMediaStart = *pStart; - else - This->tMediaStart = INVALID_MEDIA_TIME; - - if (pEnd) - This->tMediaEnd = *pEnd; - else - This->tMediaEnd = 0; - - return S_OK; -} - -static HRESULT WINAPI StdMediaSample2_GetProperties(IMediaSample2 * iface, DWORD cbProperties, BYTE * pbProperties) -{ - StdMediaSample2 *This = (StdMediaSample2 *)iface; - - TRACE("(%d, %p)\n", cbProperties, pbProperties); - - memcpy(pbProperties, &This->props, min(cbProperties, sizeof(This->props))); - - return S_OK; -} - -static HRESULT WINAPI StdMediaSample2_SetProperties(IMediaSample2 * iface, DWORD cbProperties, const BYTE * pbProperties) -{ - StdMediaSample2 *This = (StdMediaSample2 *)iface; - - TRACE("(%d, %p)\n", cbProperties, pbProperties); - - /* NOTE: pbBuffer and cbBuffer are read-only */ - memcpy(&This->props, pbProperties, min(cbProperties, AM_SAMPLE2_PROP_SIZE_WRITABLE)); - - return S_OK; -} - -static const IMediaSample2Vtbl StdMediaSample2_VTable = -{ - StdMediaSample2_QueryInterface, - StdMediaSample2_AddRef, - StdMediaSample2_Release, - StdMediaSample2_GetPointer, - StdMediaSample2_GetSize, - StdMediaSample2_GetTime, - StdMediaSample2_SetTime, - StdMediaSample2_IsSyncPoint, - StdMediaSample2_SetSyncPoint, - StdMediaSample2_IsPreroll, - StdMediaSample2_SetPreroll, - StdMediaSample2_GetActualDataLength, - StdMediaSample2_SetActualDataLength, - StdMediaSample2_GetMediaType, - StdMediaSample2_SetMediaType, - StdMediaSample2_IsDiscontinuity, - StdMediaSample2_SetDiscontinuity, - StdMediaSample2_GetMediaTime, - StdMediaSample2_SetMediaTime, - StdMediaSample2_GetProperties, - StdMediaSample2_SetProperties -}; - -typedef struct StdMemAllocator -{ - BaseMemAllocator base; - CRITICAL_SECTION csState; - LPVOID pMemory; -} StdMemAllocator; - -static HRESULT StdMemAllocator_Alloc(IMemAllocator * iface) -{ - StdMemAllocator *This = (StdMemAllocator *)iface; - StdMediaSample2 * pSample = NULL; - SYSTEM_INFO si; - long i; - - assert(list_empty(&This->base.free_list)); - - /* check alignment */ - GetSystemInfo(&si); - - /* we do not allow a courser alignment than the OS page size */ - if ((si.dwPageSize % This->base.props.cbAlign) != 0) - return VFW_E_BADALIGN; - - /* FIXME: each sample has to have its buffer start on the right alignment. - * We don't do this at the moment */ - - /* allocate memory */ - This->pMemory = VirtualAlloc(NULL, (This->base.props.cbBuffer + This->base.props.cbPrefix) * This->base.props.cBuffers, MEM_COMMIT, PAGE_READWRITE); - - for (i = This->base.props.cBuffers - 1; i >= 0; i--) - { - /* pbBuffer does not start at the base address, it starts at base + cbPrefix */ - BYTE * pbBuffer = (BYTE *)This->pMemory + i * (This->base.props.cbBuffer + This->base.props.cbPrefix) + This->base.props.cbPrefix; - - StdMediaSample2_Construct(pbBuffer, This->base.props.cbBuffer, iface, &pSample); - - list_add_head(&This->base.free_list, &pSample->listentry); - } - - return S_OK; -} - -static HRESULT StdMemAllocator_Free(IMemAllocator * iface) -{ - StdMemAllocator *This = (StdMemAllocator *)iface; - struct list * cursor; - - if (!list_empty(&This->base.used_list)) - { - WARN("Freeing allocator with outstanding samples!\n"); - while ((cursor = list_head(&This->base.used_list)) != NULL) - { - StdMediaSample2 *pSample; - list_remove(cursor); - pSample = LIST_ENTRY(cursor, StdMediaSample2, listentry); - pSample->pParent = NULL; - } - } - - while ((cursor = list_head(&This->base.free_list)) != NULL) - { - list_remove(cursor); - StdMediaSample2_Delete(LIST_ENTRY(cursor, StdMediaSample2, listentry)); - } - - /* free memory */ - if (!VirtualFree(This->pMemory, 0, MEM_RELEASE)) - { - ERR("Couldn't free memory. Error: %u\n", GetLastError()); - return HRESULT_FROM_WIN32(GetLastError()); - } - - return S_OK; -} - -static void StdMemAllocator_Destroy(IMemAllocator *iface) -{ - StdMemAllocator *This = (StdMemAllocator *)iface; - - This->csState.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&This->csState); - - CoTaskMemFree(This); -} - -HRESULT StdMemAllocator_create(LPUNKNOWN lpUnkOuter, LPVOID * ppv) -{ - StdMemAllocator * pMemAlloc; - HRESULT hr; - - *ppv = NULL; - - if (lpUnkOuter) - return CLASS_E_NOAGGREGATION; - - if (!(pMemAlloc = CoTaskMemAlloc(sizeof(*pMemAlloc)))) - return E_OUTOFMEMORY; - - InitializeCriticalSection(&pMemAlloc->csState); - pMemAlloc->csState.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": StdMemAllocator.csState"); - - pMemAlloc->pMemory = NULL; - - if (SUCCEEDED(hr = BaseMemAllocator_Init(StdMemAllocator_Alloc, StdMemAllocator_Free, NULL, NULL, NULL, StdMemAllocator_Destroy, &pMemAlloc->csState, &pMemAlloc->base))) - *ppv = (LPVOID)pMemAlloc; - else - CoTaskMemFree(pMemAlloc); - - return hr; -} diff --git a/dlls/quartz/mpegsplit.c b/dlls/quartz/mpegsplit.c index ee93e2e..750c53f 100644 --- a/dlls/quartz/mpegsplit.c +++ b/dlls/quartz/mpegsplit.c @@ -25,8 +25,6 @@ #include #include "quartz_private.h" -#include "control_private.h" -#include "pin.h" #include "uuids.h" #include "mmreg.h" @@ -37,7 +35,6 @@ #include "wine/unicode.h" #include "wine/debug.h" -#include "parser.h" WINE_DEFAULT_DEBUG_CHANNEL(quartz); diff --git a/dlls/quartz/nullrenderer.c b/dlls/quartz/nullrenderer.c index 2f9ec94..10fe199 100644 --- a/dlls/quartz/nullrenderer.c +++ b/dlls/quartz/nullrenderer.c @@ -24,8 +24,6 @@ #define NONAMELESSSTRUCT #define NONAMELESSUNION #include "quartz_private.h" -#include "control_private.h" -#include "pin.h" #include "uuids.h" #include "vfwmsgs.h" diff --git a/dlls/quartz/parser.c b/dlls/quartz/parser.c deleted file mode 100644 index 7f25300..0000000 --- a/dlls/quartz/parser.c +++ /dev/null @@ -1,787 +0,0 @@ -/* - * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "quartz_private.h" -#include "control_private.h" -#include "pin.h" - -#include "vfwmsgs.h" -#include "amvideo.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 IMediaSeekingVtbl Parser_Seeking_Vtbl; -static const IPinVtbl Parser_OutputPin_Vtbl; -static const IPinVtbl Parser_InputPin_Vtbl; - -static HRESULT Parser_OutputPin_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt); -static HRESULT Parser_ChangeCurrent(IBaseFilter *iface); -static HRESULT Parser_ChangeStop(IBaseFilter *iface); -static HRESULT Parser_ChangeRate(IBaseFilter *iface); - -static inline ParserImpl *impl_from_IMediaSeeking( IMediaSeeking *iface ) -{ - return (ParserImpl *)((char*)iface - FIELD_OFFSET(ParserImpl, mediaSeeking.lpVtbl)); -} - - -HRESULT Parser_Create(ParserImpl* pParser, const IBaseFilterVtbl *Parser_Vtbl, const CLSID* pClsid, PFN_PROCESS_SAMPLE fnProcessSample, PFN_QUERY_ACCEPT fnQueryAccept, PFN_PRE_CONNECT fnPreConnect, PFN_CLEANUP fnCleanup, PFN_DISCONNECT fnDisconnect, REQUESTPROC fnRequest, STOPPROCESSPROC fnDone, CHANGEPROC stop, CHANGEPROC current, CHANGEPROC rate) -{ - HRESULT hr; - PIN_INFO piInput; - - /* pTransformFilter is already allocated */ - pParser->clsid = *pClsid; - pParser->lpVtbl = Parser_Vtbl; - pParser->refCount = 1; - InitializeCriticalSection(&pParser->csFilter); - pParser->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ParserImpl.csFilter"); - pParser->state = State_Stopped; - pParser->pClock = NULL; - pParser->fnDisconnect = fnDisconnect; - ZeroMemory(&pParser->filterInfo, sizeof(FILTER_INFO)); - pParser->lastpinchange = GetTickCount(); - - pParser->cStreams = 0; - pParser->ppPins = CoTaskMemAlloc(1 * sizeof(IPin *)); - - /* construct input pin */ - piInput.dir = PINDIR_INPUT; - piInput.pFilter = (IBaseFilter *)pParser; - lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0])); - - if (!current) - current = Parser_ChangeCurrent; - - if (!stop) - stop = Parser_ChangeStop; - - if (!rate) - rate = Parser_ChangeRate; - - MediaSeekingImpl_Init((IBaseFilter*)pParser, stop, current, rate, &pParser->mediaSeeking, &pParser->csFilter); - pParser->mediaSeeking.lpVtbl = &Parser_Seeking_Vtbl; - - hr = PullPin_Construct(&Parser_InputPin_Vtbl, &piInput, fnProcessSample, (LPVOID)pParser, fnQueryAccept, fnCleanup, fnRequest, fnDone, &pParser->csFilter, (IPin **)&pParser->pInputPin); - - if (SUCCEEDED(hr)) - { - pParser->ppPins[0] = (IPin *)pParser->pInputPin; - pParser->pInputPin->fnPreConnect = fnPreConnect; - } - else - { - CoTaskMemFree(pParser->ppPins); - pParser->csFilter.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&pParser->csFilter); - CoTaskMemFree(pParser); - } - - return hr; -} - -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; - else if (IsEqualIID(riid, &IID_IMediaSeeking)) - *ppv = (LPVOID)&This->mediaSeeking; - - if (*ppv) - { - IUnknown_AddRef((IUnknown *)(*ppv)); - return S_OK; - } - - if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow)) - FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); - - return E_NOINTERFACE; -} - -ULONG WINAPI Parser_AddRef(IBaseFilter * iface) -{ - ParserImpl *This = (ParserImpl *)iface; - ULONG refCount = InterlockedIncrement(&This->refCount); - - TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1); - - return refCount; -} - -void Parser_Destroy(ParserImpl *This) -{ - IPin *connected = NULL; - ULONG pinref; - - assert(!This->refCount); - PullPin_WaitForStateChange(This->pInputPin, INFINITE); - - if (This->pClock) - IReferenceClock_Release(This->pClock); - - /* Don't need to clean up output pins, freeing input pin will do that */ - IPin_ConnectedTo((IPin *)This->pInputPin, &connected); - if (connected) - { - assert(IPin_Disconnect(connected) == S_OK); - IPin_Release(connected); - assert(IPin_Disconnect((IPin *)This->pInputPin) == S_OK); - } - pinref = IPin_Release((IPin *)This->pInputPin); - if (pinref) - { - /* Valgrind could find this, if I kill it here */ - ERR("pinref should be null, is %u, destroying anyway\n", pinref); - assert((LONG)pinref > 0); - - while (pinref) - pinref = IPin_Release((IPin *)This->pInputPin); - } - - CoTaskMemFree(This->ppPins); - This->lpVtbl = NULL; - - This->csFilter.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&This->csFilter); - - TRACE("Destroying parser\n"); - CoTaskMemFree(This); -} - -ULONG WINAPI Parser_Release(IBaseFilter * iface) -{ - ParserImpl *This = (ParserImpl *)iface; - ULONG refCount = InterlockedDecrement(&This->refCount); - - TRACE("(%p)->() Release from %d\n", This, refCount + 1); - - if (!refCount) - Parser_Destroy(This); - - return refCount; -} - -/** IPersist methods **/ - -HRESULT WINAPI Parser_GetClassID(IBaseFilter * iface, CLSID * pClsid) -{ - ParserImpl *This = (ParserImpl *)iface; - - TRACE("(%p)\n", pClsid); - - *pClsid = This->clsid; - - return S_OK; -} - -/** IMediaFilter methods **/ - -HRESULT WINAPI Parser_Stop(IBaseFilter * iface) -{ - ParserImpl *This = (ParserImpl *)iface; - PullPin *pin = (PullPin *)This->ppPins[0]; - int i; - - TRACE("()\n"); - - EnterCriticalSection(&pin->thread_lock); - - IAsyncReader_BeginFlush(This->pInputPin->pReader); - EnterCriticalSection(&This->csFilter); - - if (This->state == State_Stopped) - { - LeaveCriticalSection(&This->csFilter); - LeaveCriticalSection(&pin->thread_lock); - return S_OK; - } - - This->state = State_Stopped; - - for (i = 1; i < (This->cStreams + 1); i++) - { - OutputPin_DecommitAllocator((OutputPin *)This->ppPins[i]); - } - - LeaveCriticalSection(&This->csFilter); - - PullPin_PauseProcessing(This->pInputPin); - PullPin_WaitForStateChange(This->pInputPin, INFINITE); - - LeaveCriticalSection(&pin->thread_lock); - return S_OK; -} - -HRESULT WINAPI Parser_Pause(IBaseFilter * iface) -{ - HRESULT hr = S_OK; - ParserImpl *This = (ParserImpl *)iface; - PullPin *pin = (PullPin *)This->ppPins[0]; - - TRACE("()\n"); - - EnterCriticalSection(&pin->thread_lock); - EnterCriticalSection(&This->csFilter); - - if (This->state == State_Paused) - { - LeaveCriticalSection(&This->csFilter); - LeaveCriticalSection(&pin->thread_lock); - return S_OK; - } - - if (This->state == State_Stopped) - { - LeaveCriticalSection(&This->csFilter); - hr = IBaseFilter_Run(iface, -1); - EnterCriticalSection(&This->csFilter); - } - - if (SUCCEEDED(hr)) - This->state = State_Paused; - - LeaveCriticalSection(&This->csFilter); - LeaveCriticalSection(&pin->thread_lock); - - return hr; -} - -HRESULT WINAPI Parser_Run(IBaseFilter * iface, REFERENCE_TIME tStart) -{ - HRESULT hr = S_OK; - ParserImpl *This = (ParserImpl *)iface; - PullPin *pin = (PullPin *)This->ppPins[0]; - - int i; - - TRACE("(%s)\n", wine_dbgstr_longlong(tStart)); - - EnterCriticalSection(&pin->thread_lock); - EnterCriticalSection(&This->csFilter); - { - HRESULT hr_any = VFW_E_NOT_CONNECTED; - - if (This->state == State_Running || This->state == State_Paused) - { - This->state = State_Running; - LeaveCriticalSection(&This->csFilter); - LeaveCriticalSection(&pin->thread_lock); - return S_OK; - } - - This->rtStreamStart = tStart; - - for (i = 1; i < (This->cStreams + 1); i++) - { - hr = OutputPin_CommitAllocator((OutputPin *)This->ppPins[i]); - if (SUCCEEDED(hr)) - hr_any = hr; - } - - hr = hr_any; - if (SUCCEEDED(hr)) - { - LeaveCriticalSection(&This->csFilter); - hr = PullPin_StartProcessing(This->pInputPin); - EnterCriticalSection(&This->csFilter); - } - - if (SUCCEEDED(hr)) - This->state = State_Running; - } - LeaveCriticalSection(&This->csFilter); - LeaveCriticalSection(&pin->thread_lock); - - return hr; -} - -HRESULT WINAPI Parser_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState) -{ - ParserImpl *This = (ParserImpl *)iface; - PullPin *pin = (PullPin *)This->ppPins[0]; - HRESULT hr = S_OK; - - TRACE("(%d, %p)\n", dwMilliSecsTimeout, pState); - - EnterCriticalSection(&pin->thread_lock); - EnterCriticalSection(&This->csFilter); - { - *pState = This->state; - } - LeaveCriticalSection(&This->csFilter); - - if (This->pInputPin && (PullPin_WaitForStateChange(This->pInputPin, dwMilliSecsTimeout) == S_FALSE)) - hr = VFW_S_STATE_INTERMEDIATE; - LeaveCriticalSection(&pin->thread_lock); - - return hr; -} - -HRESULT WINAPI Parser_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock) -{ - ParserImpl *This = (ParserImpl *)iface; - PullPin *pin = (PullPin *)This->ppPins[0]; - - TRACE("(%p)\n", pClock); - - EnterCriticalSection(&pin->thread_lock); - EnterCriticalSection(&This->csFilter); - { - if (This->pClock) - IReferenceClock_Release(This->pClock); - This->pClock = pClock; - if (This->pClock) - IReferenceClock_AddRef(This->pClock); - } - LeaveCriticalSection(&This->csFilter); - LeaveCriticalSection(&pin->thread_lock); - - return S_OK; -} - -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 **/ - -/* FIXME: WRONG */ -static HRESULT Parser_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick) -{ - ParserImpl *This = (ParserImpl *)iface; - - *lastsynctick = This->lastpinchange; - - TRACE("Asking for pos %x\n", pos); - - /* Input pin also has a pin, hence the > and not >= */ - if (pos > This->cStreams) - return S_FALSE; - - *pin = This->ppPins[pos]; - IPin_AddRef(*pin); - return S_OK; -} - -HRESULT WINAPI Parser_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum) -{ - ParserImpl *This = (ParserImpl *)iface; - - TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum); - - return IEnumPinsImpl_Construct(ppEnum, Parser_GetPin, iface); -} - -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; -} - -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; -} - -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; -} - -HRESULT WINAPI Parser_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo) -{ - TRACE("(%p)\n", pVendorInfo); - return E_NOTIMPL; -} - -HRESULT Parser_AddPin(ParserImpl * This, const PIN_INFO * piOutput, ALLOCATOR_PROPERTIES * props, const AM_MEDIA_TYPE * amt) -{ - IPin ** ppOldPins; - HRESULT hr; - - ppOldPins = This->ppPins; - - This->ppPins = CoTaskMemAlloc((This->cStreams + 2) * sizeof(IPin *)); - memcpy(This->ppPins, ppOldPins, (This->cStreams + 1) * sizeof(IPin *)); - - hr = OutputPin_Construct(&Parser_OutputPin_Vtbl, sizeof(Parser_OutputPin), piOutput, props, NULL, Parser_OutputPin_QueryAccept, &This->csFilter, This->ppPins + (This->cStreams + 1)); - - if (SUCCEEDED(hr)) - { - IPin *pPin = This->ppPins[This->cStreams + 1]; - Parser_OutputPin *pin = (Parser_OutputPin *)pPin; - pin->pmt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); - CopyMediaType(pin->pmt, amt); - pin->dwSamplesProcessed = 0; - - pin->pin.pin.pUserData = (LPVOID)This->ppPins[This->cStreams + 1]; - pin->pin.pin.pinInfo.pFilter = (LPVOID)This; - pin->pin.custom_allocator = 1; - This->cStreams++; - This->lastpinchange = GetTickCount(); - CoTaskMemFree(ppOldPins); - } - else - { - CoTaskMemFree(This->ppPins); - This->ppPins = ppOldPins; - ERR("Failed with error %x\n", hr); - } - - return hr; -} - -static HRESULT Parser_RemoveOutputPins(ParserImpl * This) -{ - /* NOTE: should be in critical section when calling this function */ - HRESULT hr; - ULONG i; - IPin ** ppOldPins = This->ppPins; - - TRACE("(%p)\n", This); - - /* reduce the pin array down to 1 (just our input pin) */ - This->ppPins = CoTaskMemAlloc(sizeof(IPin *) * 1); - memcpy(This->ppPins, ppOldPins, sizeof(IPin *) * 1); - - for (i = 0; i < This->cStreams; i++) - { - hr = OutputPin_DeliverDisconnect((OutputPin *)ppOldPins[i + 1]); - TRACE("Disconnect: %08x\n", hr); - IPin_Release(ppOldPins[i + 1]); - } - - This->lastpinchange = GetTickCount(); - This->cStreams = 0; - CoTaskMemFree(ppOldPins); - - return S_OK; -} - -static HRESULT Parser_ChangeCurrent(IBaseFilter *iface) -{ - FIXME("(%p) filter hasn't implemented current position change!\n", iface); - return S_OK; -} - -static HRESULT Parser_ChangeStop(IBaseFilter *iface) -{ - FIXME("(%p) filter hasn't implemented stop position change!\n", iface); - return S_OK; -} - -static HRESULT Parser_ChangeRate(IBaseFilter *iface) -{ - FIXME("(%p) filter hasn't implemented rate change!\n", iface); - return S_OK; -} - - -static HRESULT WINAPI Parser_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv) -{ - ParserImpl *This = impl_from_IMediaSeeking(iface); - - return IUnknown_QueryInterface((IUnknown *)This, riid, ppv); -} - -static ULONG WINAPI Parser_Seeking_AddRef(IMediaSeeking * iface) -{ - ParserImpl *This = impl_from_IMediaSeeking(iface); - - return IUnknown_AddRef((IUnknown *)This); -} - -static ULONG WINAPI Parser_Seeking_Release(IMediaSeeking * iface) -{ - ParserImpl *This = impl_from_IMediaSeeking(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 -}; - -static 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)) - { - return IBaseFilter_QueryInterface(This->pin.pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv); - } - - if (*ppv) - { - IUnknown_AddRef((IUnknown *)(*ppv)); - return S_OK; - } - - FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); - - return E_NOINTERFACE; -} - -static ULONG WINAPI Parser_OutputPin_Release(IPin * iface) -{ - Parser_OutputPin *This = (Parser_OutputPin *)iface; - ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount); - - TRACE("(%p)->() Release from %d\n", iface, refCount + 1); - - if (!refCount) - { - FreeMediaType(This->pmt); - CoTaskMemFree(This->pmt); - FreeMediaType(&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 WINAPI Parser_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) -{ - Parser_OutputPin *This = (Parser_OutputPin *)iface; - ParserImpl *parser = (ParserImpl *)This->pin.pin.pinInfo.pFilter; - - /* Set the allocator to our input pin's */ - EnterCriticalSection(This->pin.pin.pCritSec); - This->pin.alloc = parser->pInputPin->pAlloc; - LeaveCriticalSection(This->pin.pin.pCritSec); - - return OutputPin_Connect(iface, pReceivePin, pmt); -} - -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, - Parser_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 WINAPI Parser_PullPin_Disconnect(IPin * iface) -{ - HRESULT hr; - PullPin *This = (PullPin *)iface; - - TRACE("()\n"); - - EnterCriticalSection(&This->thread_lock); - EnterCriticalSection(This->pin.pCritSec); - { - if (This->pin.pConnectedTo) - { - FILTER_STATE state; - ParserImpl *Parser = (ParserImpl *)This->pin.pinInfo.pFilter; - - LeaveCriticalSection(This->pin.pCritSec); - hr = IBaseFilter_GetState(This->pin.pinInfo.pFilter, INFINITE, &state); - EnterCriticalSection(This->pin.pCritSec); - - if (SUCCEEDED(hr) && (state == State_Stopped) && SUCCEEDED(Parser->fnDisconnect(Parser))) - { - LeaveCriticalSection(This->pin.pCritSec); - PullPin_Disconnect(iface); - EnterCriticalSection(This->pin.pCritSec); - hr = Parser_RemoveOutputPins((ParserImpl *)This->pin.pinInfo.pFilter); - } - else - hr = VFW_E_NOT_STOPPED; - } - else - hr = S_FALSE; - } - LeaveCriticalSection(This->pin.pCritSec); - LeaveCriticalSection(&This->thread_lock); - - return hr; -} - -HRESULT WINAPI Parser_PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) -{ - HRESULT hr; - - TRACE("()\n"); - - hr = PullPin_ReceiveConnection(iface, pReceivePin, pmt); - if (FAILED(hr)) - { - IPinImpl *This = (IPinImpl *)iface; - - EnterCriticalSection(This->pCritSec); - Parser_RemoveOutputPins((ParserImpl *)This->pinInfo.pFilter); - LeaveCriticalSection(This->pCritSec); - } - - return hr; -} - -static const IPinVtbl Parser_InputPin_Vtbl = -{ - PullPin_QueryInterface, - IPinImpl_AddRef, - PullPin_Release, - InputPin_Connect, - Parser_PullPin_ReceiveConnection, - Parser_PullPin_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 deleted file mode 100644 index b542388..0000000 --- a/dlls/quartz/parser.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -typedef struct ParserImpl ParserImpl; - -typedef HRESULT (*PFN_PROCESS_SAMPLE) (LPVOID iface, IMediaSample * pSample, DWORD_PTR cookie); -typedef HRESULT (*PFN_QUERY_ACCEPT) (LPVOID iface, const AM_MEDIA_TYPE * pmt); -typedef HRESULT (*PFN_PRE_CONNECT) (IPin * iface, IPin * pConnectPin, ALLOCATOR_PROPERTIES *prop); -typedef HRESULT (*PFN_CLEANUP) (LPVOID iface); -typedef HRESULT (*PFN_DISCONNECT) (LPVOID iface); - -struct ParserImpl -{ - const IBaseFilterVtbl *lpVtbl; - - LONG refCount; - CRITICAL_SECTION csFilter; - FILTER_STATE state; - REFERENCE_TIME rtStreamStart; - IReferenceClock * pClock; - PFN_CLEANUP fnCleanup; - PFN_DISCONNECT fnDisconnect; - FILTER_INFO filterInfo; - CLSID clsid; - - PullPin * pInputPin; - IPin ** ppPins; - ULONG cStreams; - DWORD lastpinchange; - MediaSeekingImpl mediaSeeking; -}; - -typedef struct Parser_OutputPin -{ - OutputPin pin; - - AM_MEDIA_TYPE * pmt; - LONGLONG dwSamplesProcessed; -} Parser_OutputPin; - -extern HRESULT Parser_AddPin(ParserImpl * This, const PIN_INFO * piOutput, ALLOCATOR_PROPERTIES * props, const AM_MEDIA_TYPE * amt); - -extern HRESULT Parser_Create(ParserImpl*, const IBaseFilterVtbl *, const CLSID*, PFN_PROCESS_SAMPLE, PFN_QUERY_ACCEPT, PFN_PRE_CONNECT, - PFN_CLEANUP, PFN_DISCONNECT, REQUESTPROC, STOPPROCESSPROC, CHANGEPROC stop, CHANGEPROC current, CHANGEPROC rate); - -/* Override the _Release function and call this when releasing */ -extern void Parser_Destroy(ParserImpl *This); - -extern HRESULT WINAPI Parser_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv); -extern ULONG WINAPI Parser_AddRef(IBaseFilter * iface); -extern ULONG WINAPI Parser_Release(IBaseFilter * iface); -extern HRESULT WINAPI Parser_GetClassID(IBaseFilter * iface, CLSID * pClsid); -extern HRESULT WINAPI Parser_Stop(IBaseFilter * iface); -extern HRESULT WINAPI Parser_Pause(IBaseFilter * iface); -extern HRESULT WINAPI Parser_Run(IBaseFilter * iface, REFERENCE_TIME tStart); -extern HRESULT WINAPI Parser_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState); -extern HRESULT WINAPI Parser_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock); -extern HRESULT WINAPI Parser_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock); -extern HRESULT WINAPI Parser_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum); -extern HRESULT WINAPI Parser_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin); -extern HRESULT WINAPI Parser_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo); -extern HRESULT WINAPI Parser_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName); -extern HRESULT WINAPI Parser_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo); diff --git a/dlls/quartz/pin.c b/dlls/quartz/pin.c deleted file mode 100644 index e2b868e..0000000 --- a/dlls/quartz/pin.c +++ /dev/null @@ -1,1866 +0,0 @@ -/* - * Generic Implementation of IPin Interface - * - * Copyright 2003 Robert Shearman - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "quartz_private.h" -#include "pin.h" - -#include "wine/debug.h" -#include "wine/unicode.h" -#include "uuids.h" -#include "vfwmsgs.h" -#include - -WINE_DEFAULT_DEBUG_CHANNEL(quartz); - -static const IPinVtbl InputPin_Vtbl; -static const IPinVtbl OutputPin_Vtbl; -static const IMemInputPinVtbl MemInputPin_Vtbl; -static const IPinVtbl PullPin_Vtbl; - -#define ALIGNDOWN(value,boundary) ((value)/(boundary)*(boundary)) -#define ALIGNUP(value,boundary) (ALIGNDOWN((value)+(boundary)-1, (boundary))) - -typedef HRESULT (*SendPinFunc)( IPin *to, LPVOID arg ); - -/** Helper function, there are a lot of places where the error code is inherited - * The following rules apply: - * - * Return the first received error code (E_NOTIMPL is ignored) - * If no errors occur: return the first received non-error-code that isn't S_OK - */ -HRESULT updatehres( HRESULT original, HRESULT new ) -{ - if (FAILED( original ) || new == E_NOTIMPL) - return original; - - if (FAILED( new ) || original == S_OK) - return new; - - return original; -} - -/** Sends a message from a pin further to other, similar pins - * fnMiddle is called on each pin found further on the stream. - * fnEnd (can be NULL) is called when the message can't be sent any further (this is a renderer or source) - * - * If the pin given is an input pin, the message will be sent downstream to other input pins - * If the pin given is an output pin, the message will be sent upstream to other output pins - */ -static HRESULT SendFurther( IPin *from, SendPinFunc fnMiddle, LPVOID arg, SendPinFunc fnEnd ) -{ - PIN_INFO pin_info; - ULONG amount = 0; - HRESULT hr = S_OK; - HRESULT hr_return = S_OK; - IEnumPins *enumpins = NULL; - BOOL foundend = TRUE; - PIN_DIRECTION from_dir; - - IPin_QueryDirection( from, &from_dir ); - - hr = IPin_QueryInternalConnections( from, NULL, &amount ); - if (hr != E_NOTIMPL && amount) - FIXME("Use QueryInternalConnections!\n"); - hr = S_OK; - - pin_info.pFilter = NULL; - hr = IPin_QueryPinInfo( from, &pin_info ); - if (FAILED(hr)) - goto out; - - hr = IBaseFilter_EnumPins( pin_info.pFilter, &enumpins ); - if (FAILED(hr)) - goto out; - - hr = IEnumPins_Reset( enumpins ); - while (hr == S_OK) { - IPin *pin = NULL; - hr = IEnumPins_Next( enumpins, 1, &pin, NULL ); - if (hr == VFW_E_ENUM_OUT_OF_SYNC) - { - hr = IEnumPins_Reset( enumpins ); - continue; - } - if (pin) - { - PIN_DIRECTION dir; - - IPin_QueryDirection( pin, &dir ); - if (dir != from_dir) - { - IPin *connected = NULL; - - foundend = FALSE; - IPin_ConnectedTo( pin, &connected ); - if (connected) - { - HRESULT hr_local; - - hr_local = fnMiddle( connected, arg ); - hr_return = updatehres( hr_return, hr_local ); - IPin_Release(connected); - } - } - IPin_Release( pin ); - } - else - { - hr = S_OK; - break; - } - } - - if (!foundend) - hr = hr_return; - else if (fnEnd) { - HRESULT hr_local; - - hr_local = fnEnd( from, arg ); - hr_return = updatehres( hr_return, hr_local ); - } - -out: - if (pin_info.pFilter) - IBaseFilter_Release( pin_info.pFilter ); - return hr; -} - -static inline InputPin *impl_from_IMemInputPin( IMemInputPin *iface ) -{ - return (InputPin *)((char*)iface - FIELD_OFFSET(InputPin, lpVtblMemInput)); -} - - -static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc) -{ - /* Tempting to just do a memcpy, but the name field is - 128 characters long! We will probably never exceed 10 - most of the time, so we are better off copying - each field manually */ - strcpyW(pDest->achName, pSrc->achName); - pDest->dir = pSrc->dir; - pDest->pFilter = pSrc->pFilter; -} - -/* Function called as a helper to IPin_Connect */ -/* specific AM_MEDIA_TYPE - it cannot be NULL */ -/* NOTE: not part of standard interface */ -static HRESULT OutputPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) -{ - OutputPin *This = (OutputPin *)iface; - HRESULT hr; - IMemAllocator * pMemAlloc = NULL; - ALLOCATOR_PROPERTIES actual; /* FIXME: should we put the actual props back in to This? */ - - TRACE("(%p, %p)\n", pReceivePin, pmt); - dump_AM_MEDIA_TYPE(pmt); - - /* FIXME: call queryacceptproc */ - - This->pin.pConnectedTo = pReceivePin; - IPin_AddRef(pReceivePin); - CopyMediaType(&This->pin.mtCurrent, pmt); - - hr = IPin_ReceiveConnection(pReceivePin, iface, pmt); - - /* get the IMemInputPin interface we will use to deliver samples to the - * connected pin */ - if (SUCCEEDED(hr)) - { - This->pMemInputPin = NULL; - hr = IPin_QueryInterface(pReceivePin, &IID_IMemInputPin, (LPVOID)&This->pMemInputPin); - - if (SUCCEEDED(hr) && !This->custom_allocator) - { - hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pMemAlloc); - - if (hr == VFW_E_NO_ALLOCATOR) - /* Input pin provides no allocator, use standard memory allocator */ - hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (LPVOID*)&pMemAlloc); - - if (SUCCEEDED(hr)) - hr = IMemAllocator_SetProperties(pMemAlloc, &This->allocProps, &actual); - - if (SUCCEEDED(hr)) - hr = IMemInputPin_NotifyAllocator(This->pMemInputPin, pMemAlloc, This->readonly); - - if (pMemAlloc) - IMemAllocator_Release(pMemAlloc); - } - else if (SUCCEEDED(hr)) - { - if (This->alloc) - { - hr = IMemInputPin_NotifyAllocator(This->pMemInputPin, This->alloc, This->readonly); - } - else - hr = VFW_E_NO_ALLOCATOR; - } - - /* break connection if we couldn't get the allocator */ - if (FAILED(hr)) - { - if (This->pMemInputPin) - IMemInputPin_Release(This->pMemInputPin); - This->pMemInputPin = NULL; - - IPin_Disconnect(pReceivePin); - } - } - - if (FAILED(hr)) - { - IPin_Release(This->pin.pConnectedTo); - This->pin.pConnectedTo = NULL; - FreeMediaType(&This->pin.mtCurrent); - } - - TRACE(" -- %x\n", hr); - return hr; -} - -static HRESULT InputPin_Init(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PUSH pSampleProc, LPVOID pUserData, - QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, LPCRITICAL_SECTION pCritSec, IMemAllocator *allocator, InputPin * pPinImpl) -{ - TRACE("\n"); - - /* Common attributes */ - pPinImpl->pin.refCount = 1; - pPinImpl->pin.pConnectedTo = NULL; - pPinImpl->pin.fnQueryAccept = pQueryAccept; - pPinImpl->pin.pUserData = pUserData; - pPinImpl->pin.pCritSec = pCritSec; - Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo); - ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE)); - - /* Input pin attributes */ - pPinImpl->fnSampleProc = pSampleProc; - pPinImpl->fnCleanProc = pCleanUp; - pPinImpl->pAllocator = pPinImpl->preferred_allocator = allocator; - if (pPinImpl->preferred_allocator) - IMemAllocator_AddRef(pPinImpl->preferred_allocator); - pPinImpl->tStart = 0; - pPinImpl->tStop = 0; - pPinImpl->dRate = 1.0; - pPinImpl->pin.lpVtbl = InputPin_Vtbl; - pPinImpl->lpVtblMemInput = &MemInputPin_Vtbl; - pPinImpl->flushing = pPinImpl->end_of_stream = 0; - - return S_OK; -} - -static HRESULT OutputPin_Init(const IPinVtbl *OutputPin_Vtbl, const PIN_INFO * pPinInfo, const ALLOCATOR_PROPERTIES * props, LPVOID pUserData, - QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, OutputPin * pPinImpl) -{ - TRACE("\n"); - - /* Common attributes */ - pPinImpl->pin.lpVtbl = OutputPin_Vtbl; - pPinImpl->pin.refCount = 1; - pPinImpl->pin.pConnectedTo = NULL; - pPinImpl->pin.fnQueryAccept = pQueryAccept; - pPinImpl->pin.pUserData = pUserData; - pPinImpl->pin.pCritSec = pCritSec; - Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo); - ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE)); - - /* Output pin attributes */ - pPinImpl->pMemInputPin = NULL; - pPinImpl->pConnectSpecific = OutputPin_ConnectSpecific; - /* If custom_allocator is set, you will need to specify an allocator - * in the alloc member of the struct before an output pin can connect - */ - pPinImpl->custom_allocator = 0; - pPinImpl->alloc = NULL; - pPinImpl->readonly = FALSE; - if (props) - { - pPinImpl->allocProps = *props; - if (pPinImpl->allocProps.cbAlign == 0) - pPinImpl->allocProps.cbAlign = 1; - } - else - ZeroMemory(&pPinImpl->allocProps, sizeof(pPinImpl->allocProps)); - - return S_OK; -} - -HRESULT InputPin_Construct(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PUSH pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, LPCRITICAL_SECTION pCritSec, IMemAllocator *allocator, IPin ** ppPin) -{ - InputPin * pPinImpl; - - *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(InputPin_Init(InputPin_Vtbl, pPinInfo, pSampleProc, pUserData, pQueryAccept, pCleanUp, pCritSec, allocator, pPinImpl))) - { - *ppPin = (IPin *)pPinImpl; - return S_OK; - } - - CoTaskMemFree(pPinImpl); - return E_FAIL; -} - -HRESULT OutputPin_Construct(const IPinVtbl *OutputPin_Vtbl, long outputpin_size, const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin) -{ - OutputPin * pPinImpl; - - *ppPin = NULL; - - if (pPinInfo->dir != PINDIR_OUTPUT) - { - ERR("Pin direction(%x) != PINDIR_OUTPUT\n", pPinInfo->dir); - return E_INVALIDARG; - } - - assert(outputpin_size >= sizeof(OutputPin)); - - pPinImpl = CoTaskMemAlloc(outputpin_size); - - if (!pPinImpl) - return E_OUTOFMEMORY; - - if (SUCCEEDED(OutputPin_Init(OutputPin_Vtbl, pPinInfo, props, pUserData, pQueryAccept, pCritSec, pPinImpl))) - { - *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl); - return S_OK; - } - - CoTaskMemFree(pPinImpl); - return E_FAIL; -} - -/*** Common pin functions ***/ - -ULONG WINAPI IPinImpl_AddRef(IPin * iface) -{ - IPinImpl *This = (IPinImpl *)iface; - ULONG refCount = InterlockedIncrement(&This->refCount); - - TRACE("(%p)->() AddRef from %d\n", iface, refCount - 1); - - return refCount; -} - -HRESULT WINAPI IPinImpl_Disconnect(IPin * iface) -{ - HRESULT hr; - IPinImpl *This = (IPinImpl *)iface; - - TRACE("()\n"); - - EnterCriticalSection(This->pCritSec); - { - if (This->pConnectedTo) - { - IPin_Release(This->pConnectedTo); - This->pConnectedTo = NULL; - FreeMediaType(&This->mtCurrent); - ZeroMemory(&This->mtCurrent, sizeof(This->mtCurrent)); - hr = S_OK; - } - else - hr = S_FALSE; - } - LeaveCriticalSection(This->pCritSec); - - return hr; -} - -HRESULT WINAPI IPinImpl_ConnectedTo(IPin * iface, IPin ** ppPin) -{ - HRESULT hr; - IPinImpl *This = (IPinImpl *)iface; - - TRACE("(%p)\n", ppPin); - - EnterCriticalSection(This->pCritSec); - { - if (This->pConnectedTo) - { - *ppPin = This->pConnectedTo; - IPin_AddRef(*ppPin); - hr = S_OK; - } - else - { - hr = VFW_E_NOT_CONNECTED; - *ppPin = NULL; - } - } - LeaveCriticalSection(This->pCritSec); - - return hr; -} - -HRESULT WINAPI IPinImpl_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt) -{ - HRESULT hr; - IPinImpl *This = (IPinImpl *)iface; - - TRACE("(%p/%p)->(%p)\n", This, iface, pmt); - - EnterCriticalSection(This->pCritSec); - { - if (This->pConnectedTo) - { - CopyMediaType(pmt, &This->mtCurrent); - hr = S_OK; - } - else - { - ZeroMemory(pmt, sizeof(*pmt)); - hr = VFW_E_NOT_CONNECTED; - } - } - LeaveCriticalSection(This->pCritSec); - - return hr; -} - -HRESULT WINAPI IPinImpl_QueryPinInfo(IPin * iface, PIN_INFO * pInfo) -{ - IPinImpl *This = (IPinImpl *)iface; - - TRACE("(%p/%p)->(%p)\n", This, iface, pInfo); - - Copy_PinInfo(pInfo, &This->pinInfo); - IBaseFilter_AddRef(pInfo->pFilter); - - return S_OK; -} - -HRESULT WINAPI IPinImpl_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir) -{ - IPinImpl *This = (IPinImpl *)iface; - - TRACE("(%p/%p)->(%p)\n", This, iface, pPinDir); - - *pPinDir = This->pinInfo.dir; - - return S_OK; -} - -HRESULT WINAPI IPinImpl_QueryId(IPin * iface, LPWSTR * Id) -{ - IPinImpl *This = (IPinImpl *)iface; - - TRACE("(%p/%p)->(%p)\n", This, iface, Id); - - *Id = CoTaskMemAlloc((strlenW(This->pinInfo.achName) + 1) * sizeof(WCHAR)); - if (!*Id) - return E_OUTOFMEMORY; - - strcpyW(*Id, This->pinInfo.achName); - - return S_OK; -} - -HRESULT WINAPI IPinImpl_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt) -{ - IPinImpl *This = (IPinImpl *)iface; - - TRACE("(%p/%p)->(%p)\n", This, iface, pmt); - - return (This->fnQueryAccept(This->pUserData, pmt) == S_OK ? S_OK : S_FALSE); -} - -HRESULT WINAPI IPinImpl_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum) -{ - IPinImpl *This = (IPinImpl *)iface; - ENUMMEDIADETAILS emd; - - TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum); - - /* override this method to allow enumeration of your types */ - emd.cMediaTypes = 0; - emd.pMediaTypes = NULL; - - return IEnumMediaTypesImpl_Construct(&emd, ppEnum); -} - -HRESULT WINAPI IPinImpl_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin) -{ - IPinImpl *This = (IPinImpl *)iface; - - TRACE("(%p/%p)->(%p, %p)\n", This, iface, apPin, cPin); - - return E_NOTIMPL; /* to tell caller that all input pins connected to all output pins */ -} - -/*** IPin implementation for an input pin ***/ - -HRESULT WINAPI InputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) -{ - InputPin *This = (InputPin *)iface; - - TRACE("(%p)->(%s, %p)\n", iface, 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_IMemInputPin)) - *ppv = (LPVOID)&This->lpVtblMemInput; - else if (IsEqualIID(riid, &IID_IMediaSeeking)) - { - return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv); - } - - if (*ppv) - { - IUnknown_AddRef((IUnknown *)(*ppv)); - return S_OK; - } - - FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); - - return E_NOINTERFACE; -} - -ULONG WINAPI InputPin_Release(IPin * iface) -{ - InputPin *This = (InputPin *)iface; - ULONG refCount = InterlockedDecrement(&This->pin.refCount); - - TRACE("(%p)->() Release from %d\n", iface, refCount + 1); - - if (!refCount) - { - FreeMediaType(&This->pin.mtCurrent); - if (This->pAllocator) - IMemAllocator_Release(This->pAllocator); - This->pAllocator = NULL; - This->pin.lpVtbl = NULL; - CoTaskMemFree(This); - return 0; - } - else - return refCount; -} - -HRESULT WINAPI InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt) -{ - ERR("Outgoing connection on an input pin! (%p, %p)\n", pConnector, pmt); - - return E_UNEXPECTED; -} - - -HRESULT WINAPI InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) -{ - InputPin *This = (InputPin *)iface; - PIN_DIRECTION pindirReceive; - HRESULT hr = S_OK; - - TRACE("(%p, %p)\n", pReceivePin, pmt); - dump_AM_MEDIA_TYPE(pmt); - - EnterCriticalSection(This->pin.pCritSec); - { - if (This->pin.pConnectedTo) - hr = VFW_E_ALREADY_CONNECTED; - - if (SUCCEEDED(hr) && This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK) - hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto - * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */ - - if (SUCCEEDED(hr)) - { - IPin_QueryDirection(pReceivePin, &pindirReceive); - - if (pindirReceive != PINDIR_OUTPUT) - { - ERR("Can't connect from non-output pin\n"); - hr = VFW_E_INVALID_DIRECTION; - } - } - - if (SUCCEEDED(hr)) - { - CopyMediaType(&This->pin.mtCurrent, pmt); - This->pin.pConnectedTo = pReceivePin; - IPin_AddRef(pReceivePin); - } - } - LeaveCriticalSection(This->pin.pCritSec); - - return hr; -} - -static HRESULT deliver_endofstream(IPin* pin, LPVOID unused) -{ - return IPin_EndOfStream( pin ); -} - -HRESULT WINAPI InputPin_EndOfStream(IPin * iface) -{ - HRESULT hr = S_OK; - InputPin *This = (InputPin *)iface; - - TRACE("(%p)\n", This); - - EnterCriticalSection(This->pin.pCritSec); - if (This->flushing) - hr = S_FALSE; - else - This->end_of_stream = 1; - LeaveCriticalSection(This->pin.pCritSec); - - if (hr == S_OK) - hr = SendFurther( iface, deliver_endofstream, NULL, NULL ); - return hr; -} - -static HRESULT deliver_beginflush(IPin* pin, LPVOID unused) -{ - return IPin_BeginFlush( pin ); -} - -HRESULT WINAPI InputPin_BeginFlush(IPin * iface) -{ - InputPin *This = (InputPin *)iface; - HRESULT hr; - TRACE("() semi-stub\n"); - - EnterCriticalSection(This->pin.pCritSec); - This->flushing = 1; - - if (This->fnCleanProc) - This->fnCleanProc(This->pin.pUserData); - - hr = SendFurther( iface, deliver_beginflush, NULL, NULL ); - LeaveCriticalSection(This->pin.pCritSec); - - return hr; -} - -static HRESULT deliver_endflush(IPin* pin, LPVOID unused) -{ - return IPin_EndFlush( pin ); -} - -HRESULT WINAPI InputPin_EndFlush(IPin * iface) -{ - InputPin *This = (InputPin *)iface; - HRESULT hr; - TRACE("(%p)\n", This); - - EnterCriticalSection(This->pin.pCritSec); - This->flushing = This->end_of_stream = 0; - - hr = SendFurther( iface, deliver_endflush, NULL, NULL ); - LeaveCriticalSection(This->pin.pCritSec); - - return hr; -} - -typedef struct newsegmentargs -{ - REFERENCE_TIME tStart, tStop; - double rate; -} newsegmentargs; - -static HRESULT deliver_newsegment(IPin *pin, LPVOID data) -{ - newsegmentargs *args = data; - return IPin_NewSegment(pin, args->tStart, args->tStop, args->rate); -} - -HRESULT WINAPI InputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - InputPin *This = (InputPin *)iface; - newsegmentargs args; - - TRACE("(%x%08x, %x%08x, %e)\n", (ULONG)(tStart >> 32), (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)tStop, dRate); - - args.tStart = This->tStart = tStart; - args.tStop = This->tStop = tStop; - args.rate = This->dRate = dRate; - - return SendFurther( iface, deliver_newsegment, &args, NULL ); -} - -static const IPinVtbl InputPin_Vtbl = -{ - InputPin_QueryInterface, - IPinImpl_AddRef, - InputPin_Release, - InputPin_Connect, - InputPin_ReceiveConnection, - IPinImpl_Disconnect, - IPinImpl_ConnectedTo, - IPinImpl_ConnectionMediaType, - IPinImpl_QueryPinInfo, - IPinImpl_QueryDirection, - IPinImpl_QueryId, - IPinImpl_QueryAccept, - IPinImpl_EnumMediaTypes, - IPinImpl_QueryInternalConnections, - InputPin_EndOfStream, - InputPin_BeginFlush, - InputPin_EndFlush, - InputPin_NewSegment -}; - -/*** IMemInputPin implementation ***/ - -HRESULT WINAPI MemInputPin_QueryInterface(IMemInputPin * iface, REFIID riid, LPVOID * ppv) -{ - InputPin *This = impl_from_IMemInputPin(iface); - - return IPin_QueryInterface((IPin *)&This->pin, riid, ppv); -} - -ULONG WINAPI MemInputPin_AddRef(IMemInputPin * iface) -{ - InputPin *This = impl_from_IMemInputPin(iface); - - return IPin_AddRef((IPin *)&This->pin); -} - -ULONG WINAPI MemInputPin_Release(IMemInputPin * iface) -{ - InputPin *This = impl_from_IMemInputPin(iface); - - return IPin_Release((IPin *)&This->pin); -} - -HRESULT WINAPI MemInputPin_GetAllocator(IMemInputPin * iface, IMemAllocator ** ppAllocator) -{ - InputPin *This = impl_from_IMemInputPin(iface); - - TRACE("(%p/%p)->(%p)\n", This, iface, ppAllocator); - - *ppAllocator = This->pAllocator; - if (*ppAllocator) - IMemAllocator_AddRef(*ppAllocator); - - return *ppAllocator ? S_OK : VFW_E_NO_ALLOCATOR; -} - -HRESULT WINAPI MemInputPin_NotifyAllocator(IMemInputPin * iface, IMemAllocator * pAllocator, BOOL bReadOnly) -{ - InputPin *This = impl_from_IMemInputPin(iface); - - TRACE("(%p/%p)->(%p, %d)\n", This, iface, pAllocator, bReadOnly); - - if (bReadOnly) - FIXME("Read only flag not handled yet!\n"); - - /* FIXME: Should we release the allocator on disconnection? */ - if (!pAllocator) - { - WARN("Null allocator\n"); - return E_POINTER; - } - - if (This->preferred_allocator && pAllocator != This->preferred_allocator) - return E_FAIL; - - if (This->pAllocator) - IMemAllocator_Release(This->pAllocator); - This->pAllocator = pAllocator; - if (This->pAllocator) - IMemAllocator_AddRef(This->pAllocator); - - return S_OK; -} - -HRESULT WINAPI MemInputPin_GetAllocatorRequirements(IMemInputPin * iface, ALLOCATOR_PROPERTIES * pProps) -{ - InputPin *This = impl_from_IMemInputPin(iface); - - TRACE("(%p/%p)->(%p)\n", This, iface, pProps); - - /* override this method if you have any specific requirements */ - - return E_NOTIMPL; -} - -HRESULT WINAPI MemInputPin_Receive(IMemInputPin * iface, IMediaSample * pSample) -{ - InputPin *This = impl_from_IMemInputPin(iface); - HRESULT hr; - - /* this trace commented out for performance reasons */ - /*TRACE("(%p/%p)->(%p)\n", This, iface, pSample);*/ - hr = This->fnSampleProc(This->pin.pUserData, pSample); - return hr; -} - -HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin * iface, IMediaSample ** pSamples, long nSamples, long *nSamplesProcessed) -{ - HRESULT hr = S_OK; - InputPin *This = impl_from_IMemInputPin(iface); - - TRACE("(%p/%p)->(%p, %ld, %p)\n", This, iface, pSamples, nSamples, nSamplesProcessed); - - for (*nSamplesProcessed = 0; *nSamplesProcessed < nSamples; (*nSamplesProcessed)++) - { - hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]); - if (hr != S_OK) - break; - } - - return hr; -} - -HRESULT WINAPI MemInputPin_ReceiveCanBlock(IMemInputPin * iface) -{ - InputPin *This = impl_from_IMemInputPin(iface); - - TRACE("(%p/%p)->()\n", This, iface); - - return S_OK; -} - -static const IMemInputPinVtbl MemInputPin_Vtbl = -{ - MemInputPin_QueryInterface, - MemInputPin_AddRef, - MemInputPin_Release, - MemInputPin_GetAllocator, - MemInputPin_NotifyAllocator, - MemInputPin_GetAllocatorRequirements, - MemInputPin_Receive, - MemInputPin_ReceiveMultiple, - MemInputPin_ReceiveCanBlock -}; - -HRESULT WINAPI OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) -{ - OutputPin *This = (OutputPin *)iface; - - TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv); - - *ppv = NULL; - - if (IsEqualIID(riid, &IID_IUnknown)) - *ppv = (LPVOID)iface; - else if (IsEqualIID(riid, &IID_IPin)) - *ppv = (LPVOID)iface; - else if (IsEqualIID(riid, &IID_IMediaSeeking)) - { - return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv); - } - - if (*ppv) - { - IUnknown_AddRef((IUnknown *)(*ppv)); - return S_OK; - } - - FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); - - return E_NOINTERFACE; -} - -ULONG WINAPI OutputPin_Release(IPin * iface) -{ - OutputPin *This = (OutputPin *)iface; - ULONG refCount = InterlockedDecrement(&This->pin.refCount); - - TRACE("(%p)->() Release from %d\n", iface, refCount + 1); - - if (!refCount) - { - FreeMediaType(&This->pin.mtCurrent); - CoTaskMemFree(This); - return 0; - } - return refCount; -} - -HRESULT WINAPI OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) -{ - HRESULT hr; - OutputPin *This = (OutputPin *)iface; - - TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt); - dump_AM_MEDIA_TYPE(pmt); - - /* If we try to connect to ourself, we will definitely deadlock. - * There are other cases where we could deadlock too, but this - * catches the obvious case */ - assert(pReceivePin != iface); - - EnterCriticalSection(This->pin.pCritSec); - { - /* if we have been a specific type to connect with, then we can either connect - * with that or fail. We cannot choose different AM_MEDIA_TYPE */ - if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL)) - hr = This->pConnectSpecific(iface, pReceivePin, pmt); - else - { - /* negotiate media type */ - - IEnumMediaTypes * pEnumCandidates; - AM_MEDIA_TYPE * pmtCandidate = NULL; /* Candidate media type */ - - if (SUCCEEDED(hr = IPin_EnumMediaTypes(iface, &pEnumCandidates))) - { - hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */ - - /* try this filter's media types first */ - while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL)) - { - assert(pmtCandidate); - dump_AM_MEDIA_TYPE(pmtCandidate); - if (!IsEqualGUID(&FORMAT_None, &pmtCandidate->formattype) - && !IsEqualGUID(&GUID_NULL, &pmtCandidate->formattype)) - assert(pmtCandidate->pbFormat); - if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && - (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK)) - { - hr = S_OK; - DeleteMediaType(pmtCandidate); - break; - } - DeleteMediaType(pmtCandidate); - pmtCandidate = NULL; - } - IEnumMediaTypes_Release(pEnumCandidates); - } - - /* then try receiver filter's media types */ - if (hr != S_OK && SUCCEEDED(hr = IPin_EnumMediaTypes(pReceivePin, &pEnumCandidates))) /* if we haven't already connected successfully */ - { - hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */ - - while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL)) - { - assert(pmtCandidate); - dump_AM_MEDIA_TYPE(pmtCandidate); - if (!IsEqualGUID(&FORMAT_None, &pmtCandidate->formattype) - && !IsEqualGUID(&GUID_NULL, &pmtCandidate->formattype)) - assert(pmtCandidate->pbFormat); - if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && - (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK)) - { - hr = S_OK; - DeleteMediaType(pmtCandidate); - break; - } - DeleteMediaType(pmtCandidate); - pmtCandidate = NULL; - } /* while */ - IEnumMediaTypes_Release(pEnumCandidates); - } /* if not found */ - } /* if negotiate media type */ - } /* if succeeded */ - LeaveCriticalSection(This->pin.pCritSec); - - TRACE(" -- %x\n", hr); - return hr; -} - -HRESULT WINAPI OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) -{ - ERR("Incoming connection on an output pin! (%p, %p)\n", pReceivePin, pmt); - - return E_UNEXPECTED; -} - -HRESULT WINAPI OutputPin_Disconnect(IPin * iface) -{ - HRESULT hr; - OutputPin *This = (OutputPin *)iface; - - TRACE("()\n"); - - EnterCriticalSection(This->pin.pCritSec); - { - if (This->pMemInputPin) - { - IMemInputPin_Release(This->pMemInputPin); - This->pMemInputPin = NULL; - } - if (This->pin.pConnectedTo) - { - IPin_Release(This->pin.pConnectedTo); - This->pin.pConnectedTo = NULL; - FreeMediaType(&This->pin.mtCurrent); - ZeroMemory(&This->pin.mtCurrent, sizeof(This->pin.mtCurrent)); - hr = S_OK; - } - else - hr = S_FALSE; - } - LeaveCriticalSection(This->pin.pCritSec); - - return hr; -} - -HRESULT WINAPI OutputPin_EndOfStream(IPin * iface) -{ - TRACE("()\n"); - - /* not supposed to do anything in an output pin */ - - return E_UNEXPECTED; -} - -HRESULT WINAPI OutputPin_BeginFlush(IPin * iface) -{ - TRACE("(%p)->()\n", iface); - - /* not supposed to do anything in an output pin */ - - return E_UNEXPECTED; -} - -HRESULT WINAPI OutputPin_EndFlush(IPin * iface) -{ - TRACE("(%p)->()\n", iface); - - /* not supposed to do anything in an output pin */ - - return E_UNEXPECTED; -} - -HRESULT WINAPI OutputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - TRACE("(%p)->(%x%08x, %x%08x, %e)\n", iface, (ULONG)(tStart >> 32), (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)tStop, dRate); - - /* not supposed to do anything in an output pin */ - - return E_UNEXPECTED; -} - -static const IPinVtbl OutputPin_Vtbl = -{ - OutputPin_QueryInterface, - IPinImpl_AddRef, - OutputPin_Release, - OutputPin_Connect, - OutputPin_ReceiveConnection, - OutputPin_Disconnect, - IPinImpl_ConnectedTo, - IPinImpl_ConnectionMediaType, - IPinImpl_QueryPinInfo, - IPinImpl_QueryDirection, - IPinImpl_QueryId, - IPinImpl_QueryAccept, - IPinImpl_EnumMediaTypes, - IPinImpl_QueryInternalConnections, - OutputPin_EndOfStream, - OutputPin_BeginFlush, - OutputPin_EndFlush, - OutputPin_NewSegment -}; - -HRESULT OutputPin_GetDeliveryBuffer(OutputPin * This, IMediaSample ** ppSample, REFERENCE_TIME * tStart, REFERENCE_TIME * tStop, DWORD dwFlags) -{ - HRESULT hr; - - TRACE("(%p, %p, %p, %x)\n", ppSample, tStart, tStop, dwFlags); - - EnterCriticalSection(This->pin.pCritSec); - { - if (!This->pin.pConnectedTo) - hr = VFW_E_NOT_CONNECTED; - else - { - IMemAllocator * pAlloc = NULL; - - hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc); - - if (SUCCEEDED(hr)) - hr = IMemAllocator_GetBuffer(pAlloc, ppSample, tStart, tStop, dwFlags); - - if (SUCCEEDED(hr)) - hr = IMediaSample_SetTime(*ppSample, tStart, tStop); - - if (pAlloc) - IMemAllocator_Release(pAlloc); - } - } - LeaveCriticalSection(This->pin.pCritSec); - - return hr; -} - -HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample) -{ - HRESULT hr = S_OK; - IMemInputPin * pMemConnected = NULL; - PIN_INFO pinInfo; - - EnterCriticalSection(This->pin.pCritSec); - { - if (!This->pin.pConnectedTo || !This->pMemInputPin) - hr = VFW_E_NOT_CONNECTED; - else - { - /* we don't have the lock held when using This->pMemInputPin, - * so we need to AddRef it to stop it being deleted while we are - * using it. Same with its filter. */ - pMemConnected = This->pMemInputPin; - IMemInputPin_AddRef(pMemConnected); - hr = IPin_QueryPinInfo(This->pin.pConnectedTo, &pinInfo); - } - } - LeaveCriticalSection(This->pin.pCritSec); - - if (SUCCEEDED(hr)) - { - /* NOTE: if we are in a critical section when Receive is called - * then it causes some problems (most notably with the native Video - * Renderer) if we are re-entered for whatever reason */ - hr = IMemInputPin_Receive(pMemConnected, pSample); - - /* If the filter's destroyed, tell upstream to stop sending data */ - if(IBaseFilter_Release(pinInfo.pFilter) == 0 && SUCCEEDED(hr)) - hr = S_FALSE; - } - if (pMemConnected) - IMemInputPin_Release(pMemConnected); - - return hr; -} - -HRESULT OutputPin_DeliverNewSegment(OutputPin * This, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - HRESULT hr; - - EnterCriticalSection(This->pin.pCritSec); - { - if (!This->pin.pConnectedTo) - hr = VFW_E_NOT_CONNECTED; - else - hr = IPin_NewSegment(This->pin.pConnectedTo, tStart, tStop, dRate); - } - LeaveCriticalSection(This->pin.pCritSec); - - return hr; -} - -HRESULT OutputPin_CommitAllocator(OutputPin * This) -{ - HRESULT hr = S_OK; - - TRACE("(%p)->()\n", This); - - EnterCriticalSection(This->pin.pCritSec); - { - if (!This->pin.pConnectedTo || !This->pMemInputPin) - hr = VFW_E_NOT_CONNECTED; - else - { - IMemAllocator * pAlloc = NULL; - - hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc); - - if (SUCCEEDED(hr)) - hr = IMemAllocator_Commit(pAlloc); - - if (pAlloc) - IMemAllocator_Release(pAlloc); - } - } - LeaveCriticalSection(This->pin.pCritSec); - - TRACE("--> %08x\n", hr); - return hr; -} - -HRESULT OutputPin_DecommitAllocator(OutputPin * This) -{ - HRESULT hr = S_OK; - - TRACE("(%p)->()\n", This); - - EnterCriticalSection(This->pin.pCritSec); - { - if (!This->pin.pConnectedTo || !This->pMemInputPin) - hr = VFW_E_NOT_CONNECTED; - else - { - IMemAllocator * pAlloc = NULL; - - hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc); - - if (SUCCEEDED(hr)) - hr = IMemAllocator_Decommit(pAlloc); - - if (pAlloc) - IMemAllocator_Release(pAlloc); - } - } - LeaveCriticalSection(This->pin.pCritSec); - - TRACE("--> %08x\n", hr); - return hr; -} - -HRESULT OutputPin_DeliverDisconnect(OutputPin * This) -{ - HRESULT hr; - - TRACE("(%p)->()\n", This); - - EnterCriticalSection(This->pin.pCritSec); - { - if (!This->pin.pConnectedTo || !This->pMemInputPin) - hr = VFW_E_NOT_CONNECTED; - else if (!This->custom_allocator) - { - IMemAllocator * pAlloc = NULL; - - hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc); - - if (SUCCEEDED(hr)) - hr = IMemAllocator_Decommit(pAlloc); - - if (pAlloc) - IMemAllocator_Release(pAlloc); - - if (SUCCEEDED(hr)) - hr = IPin_Disconnect(This->pin.pConnectedTo); - } - else /* Kill the allocator! */ - { - hr = IPin_Disconnect(This->pin.pConnectedTo); - } - IPin_Disconnect((IPin *)This); - } - LeaveCriticalSection(This->pin.pCritSec); - - return hr; -} - - -static HRESULT PullPin_Init(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PULL pSampleProc, LPVOID pUserData, - QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, REQUESTPROC pCustomRequest, STOPPROCESSPROC pDone, LPCRITICAL_SECTION pCritSec, PullPin * pPinImpl) -{ - /* Common attributes */ - pPinImpl->pin.lpVtbl = PullPin_Vtbl; - pPinImpl->pin.refCount = 1; - pPinImpl->pin.pConnectedTo = NULL; - pPinImpl->pin.fnQueryAccept = pQueryAccept; - pPinImpl->pin.pUserData = pUserData; - pPinImpl->pin.pCritSec = pCritSec; - Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo); - ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE)); - - /* Input pin attributes */ - pPinImpl->fnSampleProc = pSampleProc; - pPinImpl->fnCleanProc = pCleanUp; - pPinImpl->fnDone = pDone; - pPinImpl->fnPreConnect = NULL; - pPinImpl->pAlloc = NULL; - pPinImpl->pReader = NULL; - pPinImpl->hThread = NULL; - pPinImpl->hEventStateChanged = CreateEventW(NULL, TRUE, TRUE, NULL); - pPinImpl->thread_sleepy = CreateEventW(NULL, FALSE, FALSE, NULL); - - pPinImpl->rtStart = 0; - pPinImpl->rtCurrent = 0; - pPinImpl->rtStop = ((LONGLONG)0x7fffffff << 32) | 0xffffffff; - pPinImpl->dRate = 1.0; - pPinImpl->state = Req_Die; - pPinImpl->fnCustomRequest = pCustomRequest; - pPinImpl->stop_playback = 1; - - InitializeCriticalSection(&pPinImpl->thread_lock); - pPinImpl->thread_lock.DebugInfo->Spare[0] = (DWORD_PTR)( __FILE__ ": PullPin.thread_lock"); - - return S_OK; -} - -HRESULT PullPin_Construct(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PULL pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, REQUESTPROC pCustomRequest, STOPPROCESSPROC pDone, 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(PullPin_Vtbl, pPinInfo, pSampleProc, pUserData, pQueryAccept, pCleanUp, pCustomRequest, pDone, pCritSec, pPinImpl))) - { - *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl); - return S_OK; - } - - CoTaskMemFree(pPinImpl); - return E_FAIL; -} - -static HRESULT PullPin_InitProcessing(PullPin * This); - -HRESULT WINAPI PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) -{ - PIN_DIRECTION pindirReceive; - HRESULT hr = S_OK; - PullPin *This = (PullPin *)iface; - - TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt); - dump_AM_MEDIA_TYPE(pmt); - - EnterCriticalSection(This->pin.pCritSec); - if (!This->pin.pConnectedTo) - { - ALLOCATOR_PROPERTIES props; - - props.cBuffers = 3; - props.cbBuffer = 64 * 1024; /* 64k bytes */ - props.cbAlign = 1; - props.cbPrefix = 0; - - if (SUCCEEDED(hr) && (This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK)) - hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto - * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */ - - if (SUCCEEDED(hr)) - { - IPin_QueryDirection(pReceivePin, &pindirReceive); - - if (pindirReceive != PINDIR_OUTPUT) - { - ERR("Can't connect from non-output pin\n"); - hr = VFW_E_INVALID_DIRECTION; - } - } - - This->pReader = NULL; - This->pAlloc = NULL; - if (SUCCEEDED(hr)) - { - hr = IPin_QueryInterface(pReceivePin, &IID_IAsyncReader, (LPVOID *)&This->pReader); - } - - if (SUCCEEDED(hr) && This->fnPreConnect) - { - hr = This->fnPreConnect(iface, pReceivePin, &props); - } - - if (SUCCEEDED(hr)) - { - hr = IAsyncReader_RequestAllocator(This->pReader, NULL, &props, &This->pAlloc); - } - - if (SUCCEEDED(hr)) - { - CopyMediaType(&This->pin.mtCurrent, pmt); - This->pin.pConnectedTo = pReceivePin; - IPin_AddRef(pReceivePin); - hr = IMemAllocator_Commit(This->pAlloc); - } - - if (SUCCEEDED(hr)) - hr = PullPin_InitProcessing(This); - - if (FAILED(hr)) - { - if (This->pReader) - IAsyncReader_Release(This->pReader); - This->pReader = NULL; - if (This->pAlloc) - IMemAllocator_Release(This->pAlloc); - This->pAlloc = NULL; - } - } - else - hr = VFW_E_ALREADY_CONNECTED; - LeaveCriticalSection(This->pin.pCritSec); - return hr; -} - -HRESULT WINAPI PullPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) -{ - PullPin *This = (PullPin *)iface; - - TRACE("(%p/%p)->(%s, %p)\n", This, iface, 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)) - { - return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv); - } - - if (*ppv) - { - IUnknown_AddRef((IUnknown *)(*ppv)); - return S_OK; - } - - FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); - - return E_NOINTERFACE; -} - -ULONG WINAPI PullPin_Release(IPin *iface) -{ - PullPin *This = (PullPin *)iface; - ULONG refCount = InterlockedDecrement(&This->pin.refCount); - - TRACE("(%p)->() Release from %d\n", This, refCount + 1); - - if (!refCount) - { - WaitForSingleObject(This->hEventStateChanged, INFINITE); - assert(!This->hThread); - - if(This->pAlloc) - IMemAllocator_Release(This->pAlloc); - if(This->pReader) - IAsyncReader_Release(This->pReader); - CloseHandle(This->thread_sleepy); - CloseHandle(This->hEventStateChanged); - This->thread_lock.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&This->thread_lock); - CoTaskMemFree(This); - return 0; - } - return refCount; -} - -static void CALLBACK PullPin_Flush(PullPin *This) -{ - IMediaSample *pSample; - TRACE("Flushing!\n"); - - if (This->pReader) - { - /* Flush outstanding samples */ - IAsyncReader_BeginFlush(This->pReader); - - for (;;) - { - DWORD_PTR dwUser; - - IAsyncReader_WaitForNext(This->pReader, 0, &pSample, &dwUser); - - if (!pSample) - break; - - assert(!IMediaSample_GetActualDataLength(pSample)); - - IMediaSample_Release(pSample); - } - - IAsyncReader_EndFlush(This->pReader); - } -} - -static void CALLBACK PullPin_Thread_Process(PullPin *This) -{ - HRESULT hr; - IMediaSample * pSample = NULL; - ALLOCATOR_PROPERTIES allocProps; - - hr = IMemAllocator_GetProperties(This->pAlloc, &allocProps); - - This->cbAlign = allocProps.cbAlign; - - if (This->rtCurrent < This->rtStart) - This->rtCurrent = MEDIATIME_FROM_BYTES(ALIGNDOWN(BYTES_FROM_MEDIATIME(This->rtStart), This->cbAlign)); - - TRACE("Start\n"); - - if (This->rtCurrent >= This->rtStop) - { - IPin_EndOfStream((IPin *)This); - return; - } - - /* There is no sample in our buffer */ - hr = This->fnCustomRequest(This->pin.pUserData); - - if (FAILED(hr)) - ERR("Request error: %x\n", hr); - - EnterCriticalSection(This->pin.pCritSec); - SetEvent(This->hEventStateChanged); - LeaveCriticalSection(This->pin.pCritSec); - - if (SUCCEEDED(hr)) - do - { - DWORD_PTR dwUser; - - TRACE("Process sample\n"); - - hr = IAsyncReader_WaitForNext(This->pReader, 10000, &pSample, &dwUser); - - /* Return an empty sample on error to the implementation in case it does custom parsing, so it knows it's gone */ - if (SUCCEEDED(hr)) - { - hr = This->fnSampleProc(This->pin.pUserData, pSample, dwUser); - } - else - { - /* FIXME: This is not well handled yet! */ - ERR("Processing error: %x\n", hr); - } - - if (pSample) - { - IMediaSample_Release(pSample); - pSample = NULL; - } - } while (This->rtCurrent < This->rtStop && hr == S_OK && !This->stop_playback); - - /* Sample was rejected, and we are asked to terminate */ - if (pSample) - { - IMediaSample_Release(pSample); - } - - /* Can't reset state to Sleepy here because that might race, instead PauseProcessing will do that for us - * Flush remaining samples - */ - if (This->fnDone) - This->fnDone(This->pin.pUserData); - - TRACE("End: %08x, %d\n", hr, This->stop_playback); -} - -static void CALLBACK PullPin_Thread_Pause(PullPin *This) -{ - PullPin_Flush(This); - - EnterCriticalSection(This->pin.pCritSec); - This->state = Req_Sleepy; - SetEvent(This->hEventStateChanged); - LeaveCriticalSection(This->pin.pCritSec); -} - -static void CALLBACK PullPin_Thread_Stop(PullPin *This) -{ - TRACE("(%p)->()\n", This); - - EnterCriticalSection(This->pin.pCritSec); - { - CloseHandle(This->hThread); - This->hThread = NULL; - SetEvent(This->hEventStateChanged); - } - LeaveCriticalSection(This->pin.pCritSec); - - IBaseFilter_Release(This->pin.pinInfo.pFilter); - - CoUninitialize(); - ExitThread(0); -} - -static DWORD WINAPI PullPin_Thread_Main(LPVOID pv) -{ - PullPin *This = pv; - CoInitializeEx(NULL, COINIT_MULTITHREADED); - - PullPin_Flush(This); - - for (;;) - { - WaitForSingleObject(This->thread_sleepy, INFINITE); - - TRACE("State: %d\n", This->state); - - switch (This->state) - { - case Req_Die: PullPin_Thread_Stop(This); break; - case Req_Run: PullPin_Thread_Process(This); break; - case Req_Pause: PullPin_Thread_Pause(This); break; - case Req_Sleepy: ERR("Should not be signalled with SLEEPY!\n"); break; - default: ERR("Unknown state request: %d\n", This->state); break; - } - } -} - -static HRESULT PullPin_InitProcessing(PullPin * This) -{ - HRESULT hr = S_OK; - - TRACE("(%p)->()\n", This); - - /* if we are connected */ - if (This->pAlloc) - { - DWORD dwThreadId; - - WaitForSingleObject(This->hEventStateChanged, INFINITE); - EnterCriticalSection(This->pin.pCritSec); - - assert(!This->hThread); - assert(This->state == Req_Die); - assert(This->stop_playback); - assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT); - This->state = Req_Sleepy; - - /* AddRef the filter to make sure it and it's pins will be around - * as long as the thread */ - IBaseFilter_AddRef(This->pin.pinInfo.pFilter); - - - This->hThread = CreateThread(NULL, 0, PullPin_Thread_Main, This, 0, &dwThreadId); - if (!This->hThread) - { - hr = HRESULT_FROM_WIN32(GetLastError()); - IBaseFilter_Release(This->pin.pinInfo.pFilter); - } - - if (SUCCEEDED(hr)) - { - SetEvent(This->hEventStateChanged); - /* If assert fails, that means a command was not processed before the thread previously terminated */ - } - LeaveCriticalSection(This->pin.pCritSec); - } - - TRACE(" -- %x\n", hr); - - return hr; -} - -HRESULT PullPin_StartProcessing(PullPin * This) -{ - /* if we are connected */ - TRACE("(%p)->()\n", This); - if(This->pAlloc) - { - assert(This->hThread); - - PullPin_WaitForStateChange(This, INFINITE); - - assert(This->state == Req_Sleepy); - - /* Wake up! */ - assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT); - This->state = Req_Run; - This->stop_playback = 0; - ResetEvent(This->hEventStateChanged); - SetEvent(This->thread_sleepy); - } - - return S_OK; -} - -HRESULT PullPin_PauseProcessing(PullPin * This) -{ - /* if we are connected */ - TRACE("(%p)->()\n", This); - if(This->pAlloc) - { - assert(This->hThread); - - PullPin_WaitForStateChange(This, INFINITE); - - EnterCriticalSection(This->pin.pCritSec); - - assert(!This->stop_playback); - assert(This->state == Req_Run|| This->state == Req_Sleepy); - - assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT); - This->state = Req_Pause; - This->stop_playback = 1; - ResetEvent(This->hEventStateChanged); - SetEvent(This->thread_sleepy); - - LeaveCriticalSection(This->pin.pCritSec); - } - - return S_OK; -} - -static HRESULT PullPin_StopProcessing(PullPin * This) -{ - TRACE("(%p)->()\n", This); - - /* if we are alive */ - assert(This->hThread); - - PullPin_WaitForStateChange(This, INFINITE); - - assert(This->state == Req_Pause || This->state == Req_Sleepy); - - This->stop_playback = 1; - This->state = Req_Die; - assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT); - ResetEvent(This->hEventStateChanged); - SetEvent(This->thread_sleepy); - return S_OK; -} - -HRESULT PullPin_WaitForStateChange(PullPin * This, DWORD dwMilliseconds) -{ - if (WaitForSingleObject(This->hEventStateChanged, dwMilliseconds) == WAIT_TIMEOUT) - return S_FALSE; - return S_OK; -} - -HRESULT WINAPI PullPin_EndOfStream(IPin * iface) -{ - FIXME("(%p)->() stub\n", iface); - - return SendFurther( iface, deliver_endofstream, NULL, NULL ); -} - -HRESULT WINAPI PullPin_BeginFlush(IPin * iface) -{ - PullPin *This = (PullPin *)iface; - TRACE("(%p)->()\n", This); - - EnterCriticalSection(This->pin.pCritSec); - { - SendFurther( iface, deliver_beginflush, NULL, NULL ); - } - LeaveCriticalSection(This->pin.pCritSec); - - EnterCriticalSection(&This->thread_lock); - { - if (This->pReader) - IAsyncReader_BeginFlush(This->pReader); - PullPin_WaitForStateChange(This, INFINITE); - - if (This->hThread && This->state == Req_Run) - { - PullPin_PauseProcessing(This); - PullPin_WaitForStateChange(This, INFINITE); - } - } - LeaveCriticalSection(&This->thread_lock); - - EnterCriticalSection(This->pin.pCritSec); - { - This->fnCleanProc(This->pin.pUserData); - } - LeaveCriticalSection(This->pin.pCritSec); - - return S_OK; -} - -HRESULT WINAPI PullPin_EndFlush(IPin * iface) -{ - PullPin *This = (PullPin *)iface; - - TRACE("(%p)->()\n", iface); - - /* Send further first: Else a race condition might terminate processing early */ - EnterCriticalSection(This->pin.pCritSec); - SendFurther( iface, deliver_endflush, NULL, NULL ); - LeaveCriticalSection(This->pin.pCritSec); - - EnterCriticalSection(&This->thread_lock); - { - FILTER_STATE state; - IBaseFilter_GetState(This->pin.pinInfo.pFilter, INFINITE, &state); - - if (state != State_Stopped) - PullPin_StartProcessing(This); - - PullPin_WaitForStateChange(This, INFINITE); - } - LeaveCriticalSection(&This->thread_lock); - - return S_OK; -} - -HRESULT WINAPI PullPin_Disconnect(IPin *iface) -{ - HRESULT hr; - PullPin *This = (PullPin *)iface; - - TRACE("()\n"); - - EnterCriticalSection(This->pin.pCritSec); - { - if (FAILED(hr = IMemAllocator_Decommit(This->pAlloc))) - ERR("Allocator decommit failed with error %x. Possible memory leak\n", hr); - - if (This->pin.pConnectedTo) - { - IPin_Release(This->pin.pConnectedTo); - This->pin.pConnectedTo = NULL; - PullPin_StopProcessing(This); - - FreeMediaType(&This->pin.mtCurrent); - ZeroMemory(&This->pin.mtCurrent, sizeof(This->pin.mtCurrent)); - hr = S_OK; - } - else - hr = S_FALSE; - } - LeaveCriticalSection(This->pin.pCritSec); - - return hr; -} - -HRESULT WINAPI PullPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - newsegmentargs args; - FIXME("(%p)->(%s, %s, %g) stub\n", iface, wine_dbgstr_longlong(tStart), wine_dbgstr_longlong(tStop), dRate); - - args.tStart = tStart; - args.tStop = tStop; - args.rate = dRate; - - return SendFurther( iface, deliver_newsegment, &args, NULL ); -} - -static const IPinVtbl PullPin_Vtbl = -{ - PullPin_QueryInterface, - IPinImpl_AddRef, - PullPin_Release, - InputPin_Connect, - PullPin_ReceiveConnection, - PullPin_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/pin.h b/dlls/quartz/pin.h deleted file mode 100644 index 3a9719c..0000000 --- a/dlls/quartz/pin.h +++ /dev/null @@ -1,218 +0,0 @@ -/* - * IPin function declarations to allow inheritance - * - * Copyright 2003 Robert Shearman - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -/* This function will process incoming samples to the pin. - * Any return value valid in IMemInputPin::Receive is allowed here - * - * Cookie is the cookie that was set when requesting the buffer, if you don't - * implement custom requesting, you can safely ignore this - */ -typedef HRESULT (* SAMPLEPROC_PUSH)(LPVOID userdata, IMediaSample * pSample); -typedef HRESULT (* SAMPLEPROC_PULL)(LPVOID userdata, IMediaSample * pSample, DWORD_PTR cookie); - -/* This function will determine whether a type is supported or not. - * It is allowed to return any error value (within reason), as opposed - * to IPin::QueryAccept which is only allowed to return S_OK or S_FALSE. - */ -typedef HRESULT (* QUERYACCEPTPROC)(LPVOID userdata, const AM_MEDIA_TYPE * pmt); - -/* This function is called prior to finalizing a connection with - * another pin and can be used to get things from the other pin - * like IMemInput interfaces. - * - * props contains some defaults, but you can safely override them to your liking - */ -typedef HRESULT (* PRECONNECTPROC)(IPin * iface, IPin * pConnectPin, ALLOCATOR_PROPERTIES *props); - -/* This function is called whenever a cleanup operation has to occur, - * this is usually after a flush, seek, or end of stream notification. - * This code may even be repeated multiple times, so build your code to - * tolerate this behavior. Return value is ignored and should be S_OK. - */ -typedef HRESULT (* CLEANUPPROC) (LPVOID userdata); - -/* This function is called whenever a request for a new sample is made, - * If you implement it (it can be NULL for default behavior), you have to - * call IMemAllocator_GetBuffer and IMemAllocator_RequestBuffer - * This is useful if you want to request more than 1 buffer at simultaneously - * - * This will also cause the Sample Proc to be called with empty buffers to indicate - * failure in retrieving the sample. - */ -typedef HRESULT (* REQUESTPROC) (LPVOID userdata); - -/* This function is called after processing is done (for whatever reason that is caused) - * This is useful if you create processing threads that need to die - */ -typedef HRESULT (* STOPPROCESSPROC) (LPVOID userdata); - -#define ALIGNDOWN(value,boundary) ((value)/(boundary)*(boundary)) -#define ALIGNUP(value,boundary) (ALIGNDOWN((value)+(boundary)-1, (boundary))) - -typedef struct IPinImpl -{ - const struct IPinVtbl * lpVtbl; - LONG refCount; - LPCRITICAL_SECTION pCritSec; - PIN_INFO pinInfo; - IPin * pConnectedTo; - AM_MEDIA_TYPE mtCurrent; - ENUMMEDIADETAILS enumMediaDetails; - QUERYACCEPTPROC fnQueryAccept; - LPVOID pUserData; -} IPinImpl; - -typedef struct InputPin -{ - /* inheritance C style! */ - IPinImpl pin; - - const IMemInputPinVtbl * lpVtblMemInput; - IMemAllocator * pAllocator; - SAMPLEPROC_PUSH fnSampleProc; - CLEANUPPROC fnCleanProc; - REFERENCE_TIME tStart; - REFERENCE_TIME tStop; - double dRate; - BOOL flushing, end_of_stream; - IMemAllocator *preferred_allocator; -} InputPin; - -typedef struct OutputPin -{ - /* inheritance C style! */ - IPinImpl pin; - - IMemInputPin * pMemInputPin; - HRESULT (* pConnectSpecific)(IPin * iface, IPin * pReceiver, const AM_MEDIA_TYPE * pmt); - BOOL custom_allocator; - IMemAllocator *alloc; - BOOL readonly; - ALLOCATOR_PROPERTIES allocProps; -} OutputPin; - -typedef struct PullPin -{ - /* inheritance C style! */ - IPinImpl pin; - - REFERENCE_TIME rtStart, rtCurrent, rtNext, rtStop; - IAsyncReader * pReader; - IMemAllocator * pAlloc; - SAMPLEPROC_PULL fnSampleProc; - PRECONNECTPROC fnPreConnect; - REQUESTPROC fnCustomRequest; - CLEANUPPROC fnCleanProc; - STOPPROCESSPROC fnDone; - double dRate; - BOOL stop_playback; - DWORD cbAlign; - - /* Any code that touches the thread must hold the thread lock, - * lock order: thread_lock and then the filter critical section - * also signal thread_sleepy so the thread knows to wake up - */ - CRITICAL_SECTION thread_lock; - HANDLE hThread; - DWORD requested_state; - HANDLE hEventStateChanged, thread_sleepy; - DWORD state; -} PullPin; - -#define Req_Sleepy 0 -#define Req_Die 1 -#define Req_Run 2 -#define Req_Pause 3 - -/*** Constructors ***/ -HRESULT InputPin_Construct(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PUSH pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, LPCRITICAL_SECTION pCritSec, IMemAllocator *, IPin ** ppPin); -HRESULT OutputPin_Construct(const IPinVtbl *OutputPin_Vtbl, long outputpin_size, const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin); -HRESULT PullPin_Construct(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PULL pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, STOPPROCESSPROC, REQUESTPROC pCustomRequest, LPCRITICAL_SECTION pCritSec, IPin ** ppPin); - -/**************************/ -/*** Pin Implementation ***/ - -/* Common */ -ULONG WINAPI IPinImpl_AddRef(IPin * iface); -HRESULT WINAPI IPinImpl_Disconnect(IPin * iface); -HRESULT WINAPI IPinImpl_ConnectedTo(IPin * iface, IPin ** ppPin); -HRESULT WINAPI IPinImpl_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt); -HRESULT WINAPI IPinImpl_QueryPinInfo(IPin * iface, PIN_INFO * pInfo); -HRESULT WINAPI IPinImpl_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir); -HRESULT WINAPI IPinImpl_QueryId(IPin * iface, LPWSTR * Id); -HRESULT WINAPI IPinImpl_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt); -HRESULT WINAPI IPinImpl_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum); -HRESULT WINAPI IPinImpl_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin); - -/* Input Pin */ -HRESULT WINAPI InputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv); -ULONG WINAPI InputPin_Release(IPin * iface); -HRESULT WINAPI InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt); -HRESULT WINAPI InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt); -HRESULT WINAPI InputPin_EndOfStream(IPin * iface); -HRESULT WINAPI InputPin_BeginFlush(IPin * iface); -HRESULT WINAPI InputPin_EndFlush(IPin * iface); -HRESULT WINAPI InputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - -/* Output Pin */ -HRESULT WINAPI OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv); -ULONG WINAPI OutputPin_Release(IPin * iface); -HRESULT WINAPI OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt); -HRESULT WINAPI OutputPin_Disconnect(IPin * iface); -HRESULT WINAPI OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt); -HRESULT WINAPI OutputPin_EndOfStream(IPin * iface); -HRESULT WINAPI OutputPin_BeginFlush(IPin * iface); -HRESULT WINAPI OutputPin_EndFlush(IPin * iface); -HRESULT WINAPI OutputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - -HRESULT OutputPin_CommitAllocator(OutputPin * This); -HRESULT OutputPin_DecommitAllocator(OutputPin * This); -HRESULT OutputPin_GetDeliveryBuffer(OutputPin * This, IMediaSample ** ppSample, REFERENCE_TIME * tStart, REFERENCE_TIME * tStop, DWORD dwFlags); -HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample); -HRESULT OutputPin_DeliverDisconnect(OutputPin * This); -HRESULT OutputPin_DeliverNewSegment(OutputPin * This, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - -/**********************************/ -/*** MemInputPin Implementation ***/ - -HRESULT WINAPI MemInputPin_QueryInterface(IMemInputPin * iface, REFIID riid, LPVOID * ppv); -ULONG WINAPI MemInputPin_AddRef(IMemInputPin * iface); -ULONG WINAPI MemInputPin_Release(IMemInputPin * iface); -HRESULT WINAPI MemInputPin_GetAllocator(IMemInputPin * iface, IMemAllocator ** ppAllocator); -HRESULT WINAPI MemInputPin_NotifyAllocator(IMemInputPin * iface, IMemAllocator * pAllocator, BOOL bReadOnly); -HRESULT WINAPI MemInputPin_GetAllocatorRequirements(IMemInputPin * iface, ALLOCATOR_PROPERTIES * pProps); -HRESULT WINAPI MemInputPin_Receive(IMemInputPin * iface, IMediaSample * pSample); -HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin * iface, IMediaSample ** pSamples, long nSamples, long *nSamplesProcessed); -HRESULT WINAPI MemInputPin_ReceiveCanBlock(IMemInputPin * iface); - -/* Pull Pin */ -HRESULT WINAPI PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt); -HRESULT WINAPI PullPin_Disconnect(IPin * iface); -HRESULT WINAPI PullPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv); -ULONG WINAPI PullPin_Release(IPin * iface); -HRESULT WINAPI PullPin_EndOfStream(IPin * iface); -HRESULT WINAPI PullPin_BeginFlush(IPin * iface); -HRESULT WINAPI PullPin_EndFlush(IPin * iface); -HRESULT WINAPI PullPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - -/* Thread interaction functions: Hold the thread_lock before calling them */ -HRESULT PullPin_StartProcessing(PullPin * This); -HRESULT PullPin_PauseProcessing(PullPin * This); -HRESULT PullPin_WaitForStateChange(PullPin * This, DWORD dwMilliseconds); diff --git a/dlls/quartz/quartz_private.h b/dlls/quartz/quartz_private.h index e025078..c0fd430 100644 --- a/dlls/quartz/quartz_private.h +++ b/dlls/quartz/quartz_private.h @@ -34,100 +34,27 @@ #include "winuser.h" #include "dshow.h" #include "wine/list.h" - -#define MEDIATIME_FROM_BYTES(x) ((LONGLONG)(x) * 10000000) -#define SEC_FROM_MEDIATIME(time) ((time) / 10000000) -#define BYTES_FROM_MEDIATIME(time) SEC_FROM_MEDIATIME(time) -#define MSEC_FROM_MEDIATIME(time) ((time) / 10000) - -#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field)) - -HRESULT FilterGraph_create(IUnknown *pUnkOuter, LPVOID *ppObj); -HRESULT FilterGraphNoThread_create(IUnknown *pUnkOuter, LPVOID *ppObj); -HRESULT FilterMapper2_create(IUnknown *pUnkOuter, LPVOID *ppObj); -HRESULT FilterMapper_create(IUnknown *pUnkOuter, LPVOID *ppObj); -HRESULT AsyncReader_create(IUnknown * pUnkOuter, LPVOID * ppv); -HRESULT StdMemAllocator_create(IUnknown * pUnkOuter, LPVOID * ppv); -HRESULT AVISplitter_create(IUnknown * pUnkOuter, LPVOID * ppv); -HRESULT MPEGSplitter_create(IUnknown * pUnkOuter, LPVOID * ppv); -HRESULT AVIDec_create(IUnknown * pUnkOuter, LPVOID * ppv); -HRESULT DSoundRender_create(IUnknown * pUnkOuter, LPVOID * ppv); -HRESULT VideoRenderer_create(IUnknown * pUnkOuter, LPVOID * ppv); -HRESULT NullRenderer_create(IUnknown * pUnkOuter, LPVOID * ppv); -HRESULT VideoRendererDefault_create(IUnknown * pUnkOuter, LPVOID * ppv); -HRESULT QUARTZ_CreateSystemClock(IUnknown * pUnkOuter, LPVOID * ppv); -HRESULT ACMWrapper_create(IUnknown * pUnkOuter, LPVOID * ppv); -HRESULT WAVEParser_create(IUnknown * pUnkOuter, LPVOID * ppv); -HRESULT SeekingPassThru_create(IUnknown *pUnkOuter, LPVOID *ppObj); - -HRESULT EnumMonikerImpl_Create(IMoniker ** ppMoniker, ULONG nMonikerCount, IEnumMoniker ** ppEnum); - -typedef struct tagENUMEDIADETAILS -{ - ULONG cMediaTypes; - AM_MEDIA_TYPE * pMediaTypes; -} ENUMMEDIADETAILS; - -typedef HRESULT (* FNOBTAINPIN)(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick); - -HRESULT IEnumPinsImpl_Construct(IEnumPins ** ppEnum, FNOBTAINPIN receive_pin, IBaseFilter *base); -HRESULT IEnumMediaTypesImpl_Construct(const ENUMMEDIADETAILS * pDetails, IEnumMediaTypes ** ppEnum); -HRESULT IEnumRegFiltersImpl_Construct(REGFILTER * pInRegFilters, const ULONG size, IEnumRegFilters ** ppEnum); -HRESULT IEnumFiltersImpl_Construct(IBaseFilter ** ppFilters, ULONG nFilters, IEnumFilters ** ppEnum); - -extern const char * qzdebugstr_guid(const GUID * id); -extern const char * qzdebugstr_State(FILTER_STATE state); - -HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc); -void FreeMediaType(AM_MEDIA_TYPE * pmt); -void DeleteMediaType(AM_MEDIA_TYPE * pmt); -BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards); -void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt); -HRESULT updatehres( HRESULT original, HRESULT new ); - -typedef struct StdMediaSample2 -{ - const IMediaSample2Vtbl * lpvtbl; - - LONG ref; - AM_SAMPLE2_PROPERTIES props; - IMemAllocator * pParent; - struct list listentry; - LONGLONG tMediaStart; - LONGLONG tMediaEnd; -} StdMediaSample2; - -typedef struct BaseMemAllocator -{ - const IMemAllocatorVtbl * lpVtbl; - - LONG ref; - ALLOCATOR_PROPERTIES props; - HRESULT (* fnAlloc) (IMemAllocator *); - HRESULT (* fnFree)(IMemAllocator *); - HRESULT (* fnVerify)(IMemAllocator *, ALLOCATOR_PROPERTIES *); - HRESULT (* fnBufferPrepare)(IMemAllocator *, StdMediaSample2 *, DWORD flags); - HRESULT (* fnBufferReleased)(IMemAllocator *, StdMediaSample2 *); - void (* fnDestroyed)(IMemAllocator *); - HANDLE hSemWaiting; - BOOL bDecommitQueued; - BOOL bCommitted; - LONG lWaiting; - struct list free_list; - struct list used_list; - CRITICAL_SECTION *pCritSect; -} BaseMemAllocator; - -HRESULT BaseMemAllocator_Init(HRESULT (* fnAlloc)(IMemAllocator *), - HRESULT (* fnFree)(IMemAllocator *), - HRESULT (* fnVerify)(IMemAllocator *, ALLOCATOR_PROPERTIES *), - HRESULT (* fnBufferPrepare)(IMemAllocator *, StdMediaSample2 *, DWORD), - HRESULT (* fnBufferReleased)(IMemAllocator *, StdMediaSample2 *), - void (* fnDestroyed)(IMemAllocator *), - CRITICAL_SECTION *pCritSect, - BaseMemAllocator * pMemAlloc); - -HRESULT StdMediaSample2_Construct(BYTE * pbBuffer, LONG cbBuffer, IMemAllocator * pParent, StdMediaSample2 ** ppSample); -void StdMediaSample2_Delete(StdMediaSample2 * This); +#include "strmbase/strmbase.h" + +extern HRESULT FilterGraph_create(IUnknown *pUnkOuter, LPVOID *ppObj); +extern HRESULT FilterGraphNoThread_create(IUnknown *pUnkOuter, LPVOID *ppObj); +extern HRESULT FilterMapper2_create(IUnknown *pUnkOuter, LPVOID *ppObj); +extern HRESULT FilterMapper_create(IUnknown *pUnkOuter, LPVOID *ppObj); +extern HRESULT AsyncReader_create(IUnknown * pUnkOuter, LPVOID * ppv); +extern HRESULT StdMemAllocator_create(IUnknown * pUnkOuter, LPVOID * ppv); +extern HRESULT AVISplitter_create(IUnknown * pUnkOuter, LPVOID * ppv); +extern HRESULT MPEGSplitter_create(IUnknown * pUnkOuter, LPVOID * ppv); +extern HRESULT AVIDec_create(IUnknown * pUnkOuter, LPVOID * ppv); +extern HRESULT DSoundRender_create(IUnknown * pUnkOuter, LPVOID * ppv); +extern HRESULT VideoRenderer_create(IUnknown * pUnkOuter, LPVOID * ppv); +extern HRESULT NullRenderer_create(IUnknown * pUnkOuter, LPVOID * ppv); +extern HRESULT VideoRendererDefault_create(IUnknown * pUnkOuter, LPVOID * ppv); +extern HRESULT QUARTZ_CreateSystemClock(IUnknown * pUnkOuter, LPVOID * ppv); +extern HRESULT ACMWrapper_create(IUnknown * pUnkOuter, LPVOID * ppv); +extern HRESULT WAVEParser_create(IUnknown * pUnkOuter, LPVOID * ppv); +extern HRESULT SeekingPassThru_create(IUnknown *pUnkOuter, LPVOID *ppObj); +extern HRESULT EnumMonikerImpl_Create(IMoniker ** ppMoniker, ULONG nMonikerCount, IEnumMoniker ** ppEnum); +extern HRESULT IEnumRegFiltersImpl_Construct(REGFILTER * pInRegFilters, const ULONG size, IEnumRegFilters ** ppEnum); +extern HRESULT IEnumFiltersImpl_Construct(IBaseFilter ** ppFilters, ULONG nFilters, IEnumFilters ** ppEnum); #endif /* __QUARTZ_PRIVATE_INCLUDED__ */ diff --git a/dlls/quartz/transform.c b/dlls/quartz/transform.c deleted file mode 100644 index 322c76a..0000000 --- a/dlls/quartz/transform.c +++ /dev/null @@ -1,652 +0,0 @@ -/* - * Transform Filter (Base for decoders, etc...) - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "config.h" - -#include "quartz_private.h" -#include "control_private.h" -#include "pin.h" - -#include "amvideo.h" -#include "windef.h" -#include "winbase.h" -#include "dshow.h" -#include "strmif.h" -#include "vfw.h" - -#include - -#include "wine/unicode.h" -#include "wine/debug.h" - -#include "transform.h" - -WINE_DEFAULT_DEBUG_CHANNEL(quartz); - -static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0}; -static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0}; - -static const IBaseFilterVtbl TransformFilter_Vtbl; -static const IPinVtbl TransformFilter_InputPin_Vtbl; -static const IMemInputPinVtbl MemInputPin_Vtbl; -static const IPinVtbl TransformFilter_OutputPin_Vtbl; - -static HRESULT TransformFilter_Input_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt) -{ - TransformFilterImpl* This = (TransformFilterImpl*)iface; - TRACE("%p\n", iface); - dump_AM_MEDIA_TYPE(pmt); - - if (This->pFuncsTable->pfnQueryConnect) - return This->pFuncsTable->pfnQueryConnect(This, pmt); - /* Assume OK if there's no query method (the connection will fail if - needed) */ - return S_OK; -} - - -static HRESULT TransformFilter_Output_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt) -{ - TransformFilterImpl* pTransformFilter = (TransformFilterImpl*)iface; - AM_MEDIA_TYPE* outpmt = &((OutputPin*)pTransformFilter->ppPins[1])->pin.mtCurrent; - TRACE("%p\n", iface); - - if (IsEqualIID(&pmt->majortype, &outpmt->majortype) && IsEqualIID(&pmt->subtype, &outpmt->subtype)) - return S_OK; - return S_FALSE; -} - - -static inline TransformFilterImpl *impl_from_IMediaSeeking( IMediaSeeking *iface ) -{ - return (TransformFilterImpl *)((char*)iface - FIELD_OFFSET(TransformFilterImpl, mediaSeeking.lpVtbl)); -} - -static HRESULT WINAPI TransformFilter_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv) -{ - TransformFilterImpl *This = impl_from_IMediaSeeking(iface); - - return IUnknown_QueryInterface((IUnknown *)This, riid, ppv); -} - -static ULONG WINAPI TransformFilter_Seeking_AddRef(IMediaSeeking * iface) -{ - TransformFilterImpl *This = impl_from_IMediaSeeking(iface); - - return IUnknown_AddRef((IUnknown *)This); -} - -static ULONG WINAPI TransformFilter_Seeking_Release(IMediaSeeking * iface) -{ - TransformFilterImpl *This = impl_from_IMediaSeeking(iface); - - return IUnknown_Release((IUnknown *)This); -} - -static const IMediaSeekingVtbl TransformFilter_Seeking_Vtbl = -{ - TransformFilter_Seeking_QueryInterface, - TransformFilter_Seeking_AddRef, - TransformFilter_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 -}; - -/* These shouldn't be implemented by default. - * Usually only source filters should implement these - * and even it's not needed all of the time - */ -static HRESULT TransformFilter_ChangeCurrent(IBaseFilter *iface) -{ - TRACE("(%p) filter hasn't implemented current position change!\n", iface); - return S_OK; -} - -static HRESULT TransformFilter_ChangeStop(IBaseFilter *iface) -{ - TRACE("(%p) filter hasn't implemented stop position change!\n", iface); - return S_OK; -} - -static HRESULT TransformFilter_ChangeRate(IBaseFilter *iface) -{ - TRACE("(%p) filter hasn't implemented rate change!\n", iface); - return S_OK; -} - -HRESULT TransformFilter_Create(TransformFilterImpl* pTransformFilter, const CLSID* pClsid, const TransformFuncsTable* pFuncsTable, CHANGEPROC stop, CHANGEPROC current, CHANGEPROC rate) -{ - HRESULT hr; - PIN_INFO piInput; - PIN_INFO piOutput; - - /* pTransformFilter is already allocated */ - pTransformFilter->clsid = *pClsid; - pTransformFilter->pFuncsTable = pFuncsTable; - - pTransformFilter->lpVtbl = &TransformFilter_Vtbl; - - pTransformFilter->refCount = 1; - InitializeCriticalSection(&pTransformFilter->csFilter); - pTransformFilter->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TransformFilterImpl.csFilter"); - pTransformFilter->state = State_Stopped; - pTransformFilter->pClock = NULL; - ZeroMemory(&pTransformFilter->filterInfo, sizeof(FILTER_INFO)); - ZeroMemory(&pTransformFilter->pmt, sizeof(pTransformFilter->pmt)); - - pTransformFilter->ppPins = CoTaskMemAlloc(2 * sizeof(IPin *)); - - /* construct input pin */ - piInput.dir = PINDIR_INPUT; - piInput.pFilter = (IBaseFilter *)pTransformFilter; - lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0])); - piOutput.dir = PINDIR_OUTPUT; - piOutput.pFilter = (IBaseFilter *)pTransformFilter; - lstrcpynW(piOutput.achName, wcsOutputPinName, sizeof(piOutput.achName) / sizeof(piOutput.achName[0])); - - hr = InputPin_Construct(&TransformFilter_InputPin_Vtbl, &piInput, (SAMPLEPROC_PUSH)pFuncsTable->pfnProcessSampleData, pTransformFilter, TransformFilter_Input_QueryAccept, NULL, &pTransformFilter->csFilter, NULL, &pTransformFilter->ppPins[0]); - - if (SUCCEEDED(hr)) - { - ALLOCATOR_PROPERTIES props; - props.cbAlign = 1; - props.cbPrefix = 0; - props.cbBuffer = 0; /* Will be updated at connection time */ - props.cBuffers = 1; - - hr = OutputPin_Construct(&TransformFilter_OutputPin_Vtbl, sizeof(OutputPin), &piOutput, &props, pTransformFilter, TransformFilter_Output_QueryAccept, &pTransformFilter->csFilter, &pTransformFilter->ppPins[1]); - - if (FAILED(hr)) - ERR("Cannot create output pin (%x)\n", hr); - else - { - if (!stop) - stop = TransformFilter_ChangeStop; - if (!current) - current = TransformFilter_ChangeCurrent; - if (!rate) - rate = TransformFilter_ChangeRate; - - MediaSeekingImpl_Init((IBaseFilter*)pTransformFilter, stop, current, rate, &pTransformFilter->mediaSeeking, &pTransformFilter->csFilter); - pTransformFilter->mediaSeeking.lpVtbl = &TransformFilter_Seeking_Vtbl; - } - } - else - { - CoTaskMemFree(pTransformFilter->ppPins); - pTransformFilter->csFilter.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&pTransformFilter->csFilter); - CoTaskMemFree(pTransformFilter); - } - - return hr; -} - -static HRESULT WINAPI TransformFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv) -{ - TransformFilterImpl *This = (TransformFilterImpl *)iface; - TRACE("(%p/%p)->(%s, %p)\n", This, iface, 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; - else if (IsEqualIID(riid, &IID_IMediaSeeking)) - *ppv = &This->mediaSeeking; - - if (*ppv) - { - IUnknown_AddRef((IUnknown *)(*ppv)); - return S_OK; - } - - if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow)) - FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); - - return E_NOINTERFACE; -} - -static ULONG WINAPI TransformFilter_AddRef(IBaseFilter * iface) -{ - TransformFilterImpl *This = (TransformFilterImpl *)iface; - ULONG refCount = InterlockedIncrement(&This->refCount); - - TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1); - - return refCount; -} - -static ULONG WINAPI TransformFilter_Release(IBaseFilter * iface) -{ - TransformFilterImpl *This = (TransformFilterImpl *)iface; - ULONG refCount = InterlockedDecrement(&This->refCount); - - TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1); - - if (!refCount) - { - ULONG i; - - if (This->pClock) - IReferenceClock_Release(This->pClock); - - for (i = 0; i < 2; i++) - { - IPin *pConnectedTo; - - if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo))) - { - IPin_Disconnect(pConnectedTo); - IPin_Release(pConnectedTo); - } - IPin_Disconnect(This->ppPins[i]); - - IPin_Release(This->ppPins[i]); - } - - CoTaskMemFree(This->ppPins); - This->lpVtbl = NULL; - - This->csFilter.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&This->csFilter); - - TRACE("Destroying transform filter\n"); - FreeMediaType(&This->pmt); - CoTaskMemFree(This); - - return 0; - } - else - return refCount; -} - -/** IPersist methods **/ - -static HRESULT WINAPI TransformFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid) -{ - TransformFilterImpl *This = (TransformFilterImpl *)iface; - - TRACE("(%p/%p)->(%p)\n", This, iface, pClsid); - - *pClsid = This->clsid; - - return S_OK; -} - -/** IMediaFilter methods **/ - -static HRESULT WINAPI TransformFilter_Stop(IBaseFilter * iface) -{ - TransformFilterImpl *This = (TransformFilterImpl *)iface; - - TRACE("(%p/%p)\n", This, iface); - - EnterCriticalSection(&This->csFilter); - { - This->state = State_Stopped; - if (This->pFuncsTable->pfnProcessEnd) - This->pFuncsTable->pfnProcessEnd(This); - } - LeaveCriticalSection(&This->csFilter); - - return S_OK; -} - -static HRESULT WINAPI TransformFilter_Pause(IBaseFilter * iface) -{ - TransformFilterImpl *This = (TransformFilterImpl *)iface; - - TRACE("(%p/%p)->()\n", This, iface); - - EnterCriticalSection(&This->csFilter); - { - if (This->state == State_Stopped) - IBaseFilter_Run(iface, -1); - - This->state = State_Paused; - } - LeaveCriticalSection(&This->csFilter); - - return S_OK; -} - -static HRESULT WINAPI TransformFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart) -{ - HRESULT hr = S_OK; - TransformFilterImpl *This = (TransformFilterImpl *)iface; - - TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart)); - - EnterCriticalSection(&This->csFilter); - { - if (This->state == State_Stopped) - { - ((InputPin *)This->ppPins[0])->end_of_stream = 0; - if (This->pFuncsTable->pfnProcessBegin) - This->pFuncsTable->pfnProcessBegin(This); - OutputPin_CommitAllocator((OutputPin *)This->ppPins[1]); - } - - This->rtStreamStart = tStart; - This->state = State_Running; - } - LeaveCriticalSection(&This->csFilter); - - return hr; -} - -static HRESULT WINAPI TransformFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState) -{ - TransformFilterImpl *This = (TransformFilterImpl *)iface; - - TRACE("(%p/%p)->(%d, %p)\n", This, iface, dwMilliSecsTimeout, pState); - - EnterCriticalSection(&This->csFilter); - { - *pState = This->state; - } - LeaveCriticalSection(&This->csFilter); - - return S_OK; -} - -static HRESULT WINAPI TransformFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock) -{ - TransformFilterImpl *This = (TransformFilterImpl *)iface; - - TRACE("(%p/%p)->(%p)\n", This, iface, 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 TransformFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock) -{ - TransformFilterImpl *This = (TransformFilterImpl *)iface; - - TRACE("(%p/%p)->(%p)\n", This, iface, ppClock); - - EnterCriticalSection(&This->csFilter); - { - *ppClock = This->pClock; - if (This->pClock) - IReferenceClock_AddRef(This->pClock); - } - LeaveCriticalSection(&This->csFilter); - - return S_OK; -} - -/** IBaseFilter implementation **/ - -static HRESULT TransformFilter_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick) -{ - TransformFilterImpl *This = (TransformFilterImpl *)iface; - - /* Our pins are static, not changing so setting static tick count is ok */ - *lastsynctick = 0; - - if (pos >= 2) - return S_FALSE; - - *pin = This->ppPins[pos]; - IPin_AddRef(*pin); - return S_OK; -} - -static HRESULT WINAPI TransformFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum) -{ - TransformFilterImpl *This = (TransformFilterImpl *)iface; - - TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum); - - return IEnumPinsImpl_Construct(ppEnum, TransformFilter_GetPin, iface); -} - -static HRESULT WINAPI TransformFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin) -{ - TransformFilterImpl *This = (TransformFilterImpl *)iface; - - TRACE("(%p/%p)->(%p,%p)\n", This, iface, debugstr_w(Id), ppPin); - - return E_NOTIMPL; -} - -static HRESULT WINAPI TransformFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo) -{ - TransformFilterImpl *This = (TransformFilterImpl *)iface; - - TRACE("(%p/%p)->(%p)\n", This, iface, 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 TransformFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName) -{ - HRESULT hr = S_OK; - TransformFilterImpl *This = (TransformFilterImpl *)iface; - - TRACE("(%p/%p)->(%p, %s)\n", This, iface, 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 TransformFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo) -{ - TransformFilterImpl *This = (TransformFilterImpl *)iface; - TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo); - return E_NOTIMPL; -} - -static const IBaseFilterVtbl TransformFilter_Vtbl = -{ - TransformFilter_QueryInterface, - TransformFilter_AddRef, - TransformFilter_Release, - TransformFilter_GetClassID, - TransformFilter_Stop, - TransformFilter_Pause, - TransformFilter_Run, - TransformFilter_GetState, - TransformFilter_SetSyncSource, - TransformFilter_GetSyncSource, - TransformFilter_EnumPins, - TransformFilter_FindPin, - TransformFilter_QueryFilterInfo, - TransformFilter_JoinFilterGraph, - TransformFilter_QueryVendorInfo -}; - -static HRESULT WINAPI TransformFilter_InputPin_EndOfStream(IPin * iface) -{ - InputPin* This = (InputPin*) iface; - TransformFilterImpl* pTransform; - IPin* ppin; - HRESULT hr; - - TRACE("(%p)->()\n", iface); - - /* Since we process samples synchronously, just forward notification downstream */ - pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter; - if (!pTransform) - hr = E_FAIL; - else - hr = IPin_ConnectedTo(pTransform->ppPins[1], &ppin); - if (SUCCEEDED(hr)) - { - hr = IPin_EndOfStream(ppin); - IPin_Release(ppin); - } - - if (FAILED(hr)) - ERR("%x\n", hr); - return hr; -} - -static HRESULT WINAPI TransformFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) -{ - InputPin* This = (InputPin*) iface; - TransformFilterImpl* pTransform; - HRESULT hr; - - TRACE("(%p)->(%p, %p)\n", iface, pReceivePin, pmt); - - pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter; - - hr = pTransform->pFuncsTable->pfnConnectInput(pTransform, pmt); - if (SUCCEEDED(hr)) - { - hr = InputPin_ReceiveConnection(iface, pReceivePin, pmt); - if (FAILED(hr)) - pTransform->pFuncsTable->pfnCleanup(pTransform); - } - - return hr; -} - -static HRESULT WINAPI TransformFilter_InputPin_Disconnect(IPin * iface) -{ - InputPin* This = (InputPin*) iface; - TransformFilterImpl* pTransform; - - TRACE("(%p)->()\n", iface); - - pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter; - pTransform->pFuncsTable->pfnCleanup(pTransform); - - return IPinImpl_Disconnect(iface); -} - -static const IPinVtbl TransformFilter_InputPin_Vtbl = -{ - InputPin_QueryInterface, - IPinImpl_AddRef, - InputPin_Release, - InputPin_Connect, - TransformFilter_InputPin_ReceiveConnection, - TransformFilter_InputPin_Disconnect, - IPinImpl_ConnectedTo, - IPinImpl_ConnectionMediaType, - IPinImpl_QueryPinInfo, - IPinImpl_QueryDirection, - IPinImpl_QueryId, - IPinImpl_QueryAccept, - IPinImpl_EnumMediaTypes, - IPinImpl_QueryInternalConnections, - TransformFilter_InputPin_EndOfStream, - InputPin_BeginFlush, - InputPin_EndFlush, - InputPin_NewSegment -}; - -static HRESULT WINAPI TransformFilter_Output_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum) -{ - IPinImpl *This = (IPinImpl *)iface; - TransformFilterImpl *pTransform = (TransformFilterImpl *)This->pinInfo.pFilter; - ENUMMEDIADETAILS emd; - - TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum); - - emd.cMediaTypes = 1; - emd.pMediaTypes = &pTransform->pmt; - - return IEnumMediaTypesImpl_Construct(&emd, ppEnum); -} - -static const IPinVtbl TransformFilter_OutputPin_Vtbl = -{ - OutputPin_QueryInterface, - IPinImpl_AddRef, - OutputPin_Release, - OutputPin_Connect, - OutputPin_ReceiveConnection, - OutputPin_Disconnect, - IPinImpl_ConnectedTo, - IPinImpl_ConnectionMediaType, - IPinImpl_QueryPinInfo, - IPinImpl_QueryDirection, - IPinImpl_QueryId, - IPinImpl_QueryAccept, - TransformFilter_Output_EnumMediaTypes, - IPinImpl_QueryInternalConnections, - OutputPin_EndOfStream, - OutputPin_BeginFlush, - OutputPin_EndFlush, - OutputPin_NewSegment -}; - -static const IMemInputPinVtbl MemInputPin_Vtbl = -{ - MemInputPin_QueryInterface, - MemInputPin_AddRef, - MemInputPin_Release, - MemInputPin_GetAllocator, - MemInputPin_NotifyAllocator, - MemInputPin_GetAllocatorRequirements, - MemInputPin_Receive, - MemInputPin_ReceiveMultiple, - MemInputPin_ReceiveCanBlock -}; diff --git a/dlls/quartz/transform.h b/dlls/quartz/transform.h deleted file mode 100644 index 0f20b6e..0000000 --- a/dlls/quartz/transform.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Transform Filter 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "control_private.h" - -typedef struct TransformFilterImpl TransformFilterImpl; - -typedef struct TransformFuncsTable { - HRESULT (*pfnProcessBegin) (TransformFilterImpl* This); - HRESULT (*pfnProcessSampleData) (TransformFilterImpl* This, IMediaSample *pSample); - HRESULT (*pfnProcessEnd) (TransformFilterImpl* This); - HRESULT (*pfnQueryConnect) (TransformFilterImpl* This, const AM_MEDIA_TYPE * pmt); - HRESULT (*pfnConnectInput) (TransformFilterImpl* This, const AM_MEDIA_TYPE * pmt); - HRESULT (*pfnCleanup) (TransformFilterImpl* This); -} TransformFuncsTable; - -struct TransformFilterImpl -{ - const IBaseFilterVtbl * lpVtbl; - - LONG refCount; - CRITICAL_SECTION csFilter; - FILTER_STATE state; - REFERENCE_TIME rtStreamStart; - IReferenceClock * pClock; - FILTER_INFO filterInfo; - CLSID clsid; - struct MediaSeekingImpl mediaSeeking; - - IPin ** ppPins; - AM_MEDIA_TYPE pmt; - - const TransformFuncsTable * pFuncsTable; -}; - -HRESULT TransformFilter_Create(TransformFilterImpl*, const CLSID*, const TransformFuncsTable* pFuncsTable, CHANGEPROC stop, CHANGEPROC current, CHANGEPROC rate); diff --git a/dlls/quartz/videorenderer.c b/dlls/quartz/videorenderer.c index 629ad1d..e3162b0 100644 --- a/dlls/quartz/videorenderer.c +++ b/dlls/quartz/videorenderer.c @@ -23,8 +23,6 @@ #define NONAMELESSSTRUCT #define NONAMELESSUNION #include "quartz_private.h" -#include "control_private.h" -#include "pin.h" #include "uuids.h" #include "vfwmsgs.h" diff --git a/dlls/quartz/waveparser.c b/dlls/quartz/waveparser.c index dbc096c..f5d5fde 100644 --- a/dlls/quartz/waveparser.c +++ b/dlls/quartz/waveparser.c @@ -19,8 +19,6 @@ */ #include "quartz_private.h" -#include "control_private.h" -#include "pin.h" #include "uuids.h" #include "aviriff.h" @@ -33,7 +31,6 @@ #include #include -#include "parser.h" WINE_DEFAULT_DEBUG_CHANNEL(quartz); diff --git a/dlls/strmbase/Makefile.in b/dlls/strmbase/Makefile.in new file mode 100644 index 0000000..45307ea --- /dev/null +++ b/dlls/strmbase/Makefile.in @@ -0,0 +1,18 @@ +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +MODULE = strmbase + +C_SRCS = \ + control.c \ + enummedia.c \ + enumpins.c \ + memallocator.c \ + parser.c \ + pin.c \ + transform.c + +@MAKE_IMPLIB_RULES@ + +@DEPENDENCIES@ # everything below this line is overwritten by make depend diff --git a/dlls/strmbase/control.c b/dlls/strmbase/control.c new file mode 100644 index 0000000..fcd2ccc --- /dev/null +++ b/dlls/strmbase/control.c @@ -0,0 +1,918 @@ +/* + * Filter Seeking and Control Interfaces + * + * Copyright 2003 Robert Shearman + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +/* FIXME: critical sections */ + +#include "strmbase_private.h" + +#include "uuids.h" +#include "wine/debug.h" + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(strmbase); + +static const IMediaSeekingVtbl IMediaSeekingPassThru_Vtbl; + +typedef struct PassThruImpl { + const ISeekingPassThruVtbl *IPassThru_vtbl; + const IUnknownVtbl *IInner_vtbl; + const IMediaSeekingVtbl *IMediaSeeking_vtbl; + + LONG ref; + IUnknown * pUnkOuter; + IPin * pin; + BOOL bUnkOuterValid; + BOOL bAggregatable; + BOOL renderer; +} PassThruImpl; + +static HRESULT WINAPI SeekInner_QueryInterface(IUnknown * iface, + REFIID riid, + LPVOID *ppvObj) { + ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface); + TRACE("(%p)->(%s (%p), %p)\n", This, debugstr_guid(riid), riid, ppvObj); + + if (This->bAggregatable) + This->bUnkOuterValid = TRUE; + + if (IsEqualGUID(&IID_IUnknown, riid)) + { + *ppvObj = &(This->IInner_vtbl); + TRACE(" returning IUnknown interface (%p)\n", *ppvObj); + } else if (IsEqualGUID(&IID_ISeekingPassThru, riid)) { + *ppvObj = &(This->IPassThru_vtbl); + TRACE(" returning ISeekingPassThru interface (%p)\n", *ppvObj); + } else if (IsEqualGUID(&IID_IMediaSeeking, riid)) { + *ppvObj = &(This->IMediaSeeking_vtbl); + TRACE(" returning IMediaSeeking interface (%p)\n", *ppvObj); + } else { + *ppvObj = NULL; + FIXME("unknown interface %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)(*ppvObj)); + return S_OK; +} + +static ULONG WINAPI SeekInner_AddRef(IUnknown * iface) { + ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface); + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p)->(): new ref = %d\n", This, ref); + + return ref; +} + +static ULONG WINAPI SeekInner_Release(IUnknown * iface) { + ICOM_THIS_MULTI(PassThruImpl, IInner_vtbl, iface); + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p)->(): new ref = %d\n", This, ref); + + if (ref == 0) + { + CoTaskMemFree(This); + } + return ref; +} + +static const IUnknownVtbl IInner_VTable = +{ + SeekInner_QueryInterface, + SeekInner_AddRef, + SeekInner_Release +}; + +/* Generic functions for aggregation */ +static HRESULT WINAPI SeekOuter_QueryInterface(PassThruImpl *This, REFIID riid, LPVOID *ppv) +{ + if (This->bAggregatable) + This->bUnkOuterValid = TRUE; + + if (This->pUnkOuter) + { + if (This->bAggregatable) + return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv); + + if (IsEqualIID(riid, &IID_IUnknown)) + { + HRESULT hr; + + IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl)); + hr = IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv); + IUnknown_Release((IUnknown *)&(This->IInner_vtbl)); + This->bAggregatable = TRUE; + return hr; + } + + *ppv = NULL; + return E_NOINTERFACE; + } + + return IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv); +} + +static ULONG WINAPI SeekOuter_AddRef(PassThruImpl *This) +{ + if (This->pUnkOuter && This->bUnkOuterValid) + return IUnknown_AddRef(This->pUnkOuter); + return IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl)); +} + +static ULONG WINAPI SeekOuter_Release(PassThruImpl *This) +{ + if (This->pUnkOuter && This->bUnkOuterValid) + return IUnknown_Release(This->pUnkOuter); + return IUnknown_Release((IUnknown *)&(This->IInner_vtbl)); +} + +static HRESULT WINAPI SeekingPassThru_QueryInterface(ISeekingPassThru *iface, REFIID riid, LPVOID *ppvObj) +{ + ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface); + + TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj); + + return SeekOuter_QueryInterface(This, riid, ppvObj); +} + +static ULONG WINAPI SeekingPassThru_AddRef(ISeekingPassThru *iface) +{ + ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface); + + TRACE("(%p/%p)->()\n", This, iface); + + return SeekOuter_AddRef(This); +} + +static ULONG WINAPI SeekingPassThru_Release(ISeekingPassThru *iface) +{ + ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface); + + TRACE("(%p/%p)->()\n", This, iface); + + return SeekOuter_Release(This); +} + +static HRESULT WINAPI SeekingPassThru_Init(ISeekingPassThru *iface, BOOL renderer, IPin *pin) +{ + ICOM_THIS_MULTI(PassThruImpl, IPassThru_vtbl, iface); + + TRACE("(%p/%p)->(%d, %p)\n", This, iface, renderer, pin); + + if (This->pin) + FIXME("Re-initializing?\n"); + + This->renderer = renderer; + This->pin = pin; + + return S_OK; +} + +static const ISeekingPassThruVtbl ISeekingPassThru_Vtbl = +{ + SeekingPassThru_QueryInterface, + SeekingPassThru_AddRef, + SeekingPassThru_Release, + SeekingPassThru_Init +}; + +HRESULT SeekingPassThru_create(IUnknown *pUnkOuter, LPVOID *ppObj) +{ + PassThruImpl *fimpl; + + TRACE("(%p,%p)\n", pUnkOuter, ppObj); + + *ppObj = fimpl = CoTaskMemAlloc(sizeof(*fimpl)); + if (!fimpl) + return E_OUTOFMEMORY; + + fimpl->pUnkOuter = pUnkOuter; + fimpl->bUnkOuterValid = FALSE; + fimpl->bAggregatable = FALSE; + fimpl->IInner_vtbl = &IInner_VTable; + fimpl->IPassThru_vtbl = &ISeekingPassThru_Vtbl; + fimpl->IMediaSeeking_vtbl = &IMediaSeekingPassThru_Vtbl; + fimpl->ref = 1; + fimpl->pin = NULL; + return S_OK; +} + +typedef HRESULT (*SeekFunc)( IMediaSeeking *to, LPVOID arg ); + +static HRESULT ForwardCmdSeek( PCRITICAL_SECTION crit_sect, IBaseFilter* from, SeekFunc fnSeek, LPVOID arg ) +{ + HRESULT hr = S_OK; + HRESULT hr_return = S_OK; + IEnumPins *enumpins = NULL; + BOOL foundend = FALSE, allnotimpl = TRUE; + + hr = IBaseFilter_EnumPins( from, &enumpins ); + if (FAILED(hr)) + goto out; + + hr = IEnumPins_Reset( enumpins ); + while (hr == S_OK) { + IPin *pin = NULL; + hr = IEnumPins_Next( enumpins, 1, &pin, NULL ); + if (hr == VFW_E_ENUM_OUT_OF_SYNC) + { + hr = IEnumPins_Reset( enumpins ); + continue; + } + if (pin) + { + PIN_DIRECTION dir; + + IPin_QueryDirection( pin, &dir ); + if (dir == PINDIR_INPUT) + { + IPin *connected = NULL; + + IPin_ConnectedTo( pin, &connected ); + if (connected) + { + HRESULT hr_local; + IMediaSeeking *seek = NULL; + + hr_local = IPin_QueryInterface( connected, &IID_IMediaSeeking, (void**)&seek ); + if (!hr_local) + { + foundend = TRUE; + if (crit_sect) + { + LeaveCriticalSection( crit_sect ); + hr_local = fnSeek( seek , arg ); + EnterCriticalSection( crit_sect ); + } + else + hr_local = fnSeek( seek , arg ); + + if (hr_local != E_NOTIMPL) + allnotimpl = FALSE; + + hr_return = updatehres( hr_return, hr_local ); + IMediaSeeking_Release( seek ); + } + IPin_Release(connected); + } + } + IPin_Release( pin ); + } + } + if (foundend && allnotimpl) + hr = E_NOTIMPL; + else + hr = hr_return; + +out: + TRACE("Returning: %08x\n", hr); + return hr; +} + + +HRESULT MediaSeekingImpl_Init(IBaseFilter *pUserData, CHANGEPROC fnChangeStop, CHANGEPROC fnChangeCurrent, CHANGEPROC fnChangeRate, MediaSeekingImpl * pSeeking, PCRITICAL_SECTION crit_sect) +{ + assert(fnChangeStop && fnChangeCurrent && fnChangeRate); + + pSeeking->refCount = 1; + pSeeking->pUserData = pUserData; + pSeeking->fnChangeRate = fnChangeRate; + pSeeking->fnChangeStop = fnChangeStop; + pSeeking->fnChangeCurrent = fnChangeCurrent; + pSeeking->dwCapabilities = AM_SEEKING_CanSeekForwards | + AM_SEEKING_CanSeekBackwards | + AM_SEEKING_CanSeekAbsolute | + AM_SEEKING_CanGetStopPos | + AM_SEEKING_CanGetDuration; + pSeeking->llCurrent = 0; + pSeeking->llStop = ((ULONGLONG)0x80000000) << 32; + pSeeking->llDuration = pSeeking->llStop; + pSeeking->dRate = 1.0; + pSeeking->timeformat = TIME_FORMAT_MEDIA_TIME; + pSeeking->crst = crit_sect; + + return S_OK; +} + +struct pos_args { + LONGLONG* current, *stop; + DWORD curflags, stopflags; +}; + +static HRESULT fwd_setposition(IMediaSeeking *seek, LPVOID pargs) +{ + struct pos_args *args = (void*)pargs; + + return IMediaSeeking_SetPositions(seek, args->current, args->curflags, args->stop, args->stopflags); +} + +static HRESULT fwd_checkcaps(IMediaSeeking *iface, LPVOID pcaps) +{ + DWORD *caps = pcaps; + return IMediaSeeking_CheckCapabilities(iface, caps); +} + +static HRESULT fwd_settimeformat(IMediaSeeking *iface, LPVOID pformat) +{ + const GUID *format = pformat; + return IMediaSeeking_SetTimeFormat(iface, format); +} + +static HRESULT fwd_getduration(IMediaSeeking *iface, LPVOID pdur) +{ + LONGLONG *duration = pdur; + LONGLONG mydur = *duration; + HRESULT hr; + + hr = IMediaSeeking_GetDuration(iface, &mydur); + if (FAILED(hr)) + return hr; + + if ((mydur < *duration) || (*duration < 0 && mydur > 0)) + *duration = mydur; + return hr; +} + +static HRESULT fwd_getstopposition(IMediaSeeking *iface, LPVOID pdur) +{ + LONGLONG *duration = pdur; + LONGLONG mydur = *duration; + HRESULT hr; + + hr = IMediaSeeking_GetStopPosition(iface, &mydur); + if (FAILED(hr)) + return hr; + + if ((mydur < *duration) || (*duration < 0 && mydur > 0)) + *duration = mydur; + return hr; +} + +static HRESULT fwd_getcurposition(IMediaSeeking *iface, LPVOID pdur) +{ + LONGLONG *duration = pdur; + LONGLONG mydur = *duration; + HRESULT hr; + + hr = IMediaSeeking_GetCurrentPosition(iface, &mydur); + if (FAILED(hr)) + return hr; + + if ((mydur < *duration) || (*duration < 0 && mydur > 0)) + *duration = mydur; + return hr; +} + +static HRESULT fwd_setrate(IMediaSeeking *iface, LPVOID prate) +{ + double *rate = prate; + + HRESULT hr; + + hr = IMediaSeeking_SetRate(iface, *rate); + if (FAILED(hr)) + return hr; + + return hr; +} + + +HRESULT WINAPI MediaSeekingImpl_GetCapabilities(IMediaSeeking * iface, DWORD * pCapabilities) +{ + MediaSeekingImpl *This = (MediaSeekingImpl *)iface; + + TRACE("(%p)\n", pCapabilities); + + *pCapabilities = This->dwCapabilities; + + return S_OK; +} + +HRESULT WINAPI MediaSeekingImpl_CheckCapabilities(IMediaSeeking * iface, DWORD * pCapabilities) +{ + MediaSeekingImpl *This = (MediaSeekingImpl *)iface; + HRESULT hr; + DWORD dwCommonCaps; + + TRACE("(%p)\n", pCapabilities); + + if (!pCapabilities) + return E_POINTER; + + EnterCriticalSection(This->crst); + hr = ForwardCmdSeek(This->crst, This->pUserData, fwd_checkcaps, pCapabilities); + LeaveCriticalSection(This->crst); + if (FAILED(hr) && hr != E_NOTIMPL) + return hr; + + dwCommonCaps = *pCapabilities & This->dwCapabilities; + + if (!dwCommonCaps) + hr = E_FAIL; + else + hr = (*pCapabilities == dwCommonCaps) ? S_OK : S_FALSE; + *pCapabilities = dwCommonCaps; + + return hr; +} + +HRESULT WINAPI MediaSeekingImpl_IsFormatSupported(IMediaSeeking * iface, const GUID * pFormat) +{ + TRACE("(%s)\n", qzdebugstr_guid(pFormat)); + + return (IsEqualIID(pFormat, &TIME_FORMAT_MEDIA_TIME) ? S_OK : S_FALSE); +} + +HRESULT WINAPI MediaSeekingImpl_QueryPreferredFormat(IMediaSeeking * iface, GUID * pFormat) +{ + TRACE("(%s)\n", qzdebugstr_guid(pFormat)); + + *pFormat = TIME_FORMAT_MEDIA_TIME; + return S_OK; +} + +HRESULT WINAPI MediaSeekingImpl_GetTimeFormat(IMediaSeeking * iface, GUID * pFormat) +{ + MediaSeekingImpl *This = (MediaSeekingImpl *)iface; + TRACE("(%s)\n", qzdebugstr_guid(pFormat)); + + EnterCriticalSection(This->crst); + *pFormat = This->timeformat; + LeaveCriticalSection(This->crst); + + return S_OK; +} + +HRESULT WINAPI MediaSeekingImpl_IsUsingTimeFormat(IMediaSeeking * iface, const GUID * pFormat) +{ + MediaSeekingImpl *This = (MediaSeekingImpl *)iface; + HRESULT hr = S_OK; + + TRACE("(%s)\n", qzdebugstr_guid(pFormat)); + + EnterCriticalSection(This->crst); + if (!IsEqualIID(pFormat, &This->timeformat)) + hr = S_FALSE; + LeaveCriticalSection(This->crst); + + return hr; +} + + +HRESULT WINAPI MediaSeekingImpl_SetTimeFormat(IMediaSeeking * iface, const GUID * pFormat) +{ + MediaSeekingImpl *This = (MediaSeekingImpl *)iface; + TRACE("(%s)\n", qzdebugstr_guid(pFormat)); + + EnterCriticalSection(This->crst); + ForwardCmdSeek(This->crst, This->pUserData, fwd_settimeformat, (LPVOID)pFormat); + LeaveCriticalSection(This->crst); + + return (IsEqualIID(pFormat, &TIME_FORMAT_MEDIA_TIME) ? S_OK : S_FALSE); +} + + +HRESULT WINAPI MediaSeekingImpl_GetDuration(IMediaSeeking * iface, LONGLONG * pDuration) +{ + MediaSeekingImpl *This = (MediaSeekingImpl *)iface; + + TRACE("(%p)\n", pDuration); + + EnterCriticalSection(This->crst); + *pDuration = This->llDuration; + ForwardCmdSeek(This->crst, This->pUserData, fwd_getduration, pDuration); + LeaveCriticalSection(This->crst); + + return S_OK; +} + +HRESULT WINAPI MediaSeekingImpl_GetStopPosition(IMediaSeeking * iface, LONGLONG * pStop) +{ + MediaSeekingImpl *This = (MediaSeekingImpl *)iface; + + TRACE("(%p)\n", pStop); + + EnterCriticalSection(This->crst); + *pStop = This->llStop; + ForwardCmdSeek(This->crst, This->pUserData, fwd_getstopposition, pStop); + LeaveCriticalSection(This->crst); + + return S_OK; +} + +/* FIXME: Make use of the info the filter should expose */ +HRESULT WINAPI MediaSeekingImpl_GetCurrentPosition(IMediaSeeking * iface, LONGLONG * pCurrent) +{ + MediaSeekingImpl *This = (MediaSeekingImpl *)iface; + + TRACE("(%p)\n", pCurrent); + + EnterCriticalSection(This->crst); + *pCurrent = This->llCurrent; + ForwardCmdSeek(This->crst, This->pUserData, fwd_getcurposition, pCurrent); + LeaveCriticalSection(This->crst); + + return S_OK; +} + +HRESULT WINAPI MediaSeekingImpl_ConvertTimeFormat(IMediaSeeking * iface, LONGLONG * pTarget, const GUID * pTargetFormat, LONGLONG Source, const GUID * pSourceFormat) +{ + if (IsEqualIID(pTargetFormat, &TIME_FORMAT_MEDIA_TIME) && IsEqualIID(pSourceFormat, &TIME_FORMAT_MEDIA_TIME)) + { + *pTarget = Source; + return S_OK; + } + /* FIXME: clear pTarget? */ + return E_INVALIDARG; +} + +static inline LONGLONG Adjust(LONGLONG value, const LONGLONG * pModifier, DWORD dwFlags) +{ + switch (dwFlags & AM_SEEKING_PositioningBitsMask) + { + case AM_SEEKING_NoPositioning: + return value; + case AM_SEEKING_AbsolutePositioning: + return *pModifier; + case AM_SEEKING_RelativePositioning: + case AM_SEEKING_IncrementalPositioning: + return value + *pModifier; + default: + assert(FALSE); + return 0; + } +} + +HRESULT WINAPI MediaSeekingImpl_SetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, DWORD dwCurrentFlags, LONGLONG * pStop, DWORD dwStopFlags) +{ + MediaSeekingImpl *This = (MediaSeekingImpl *)iface; + BOOL bChangeCurrent = FALSE, bChangeStop = FALSE; + LONGLONG llNewCurrent, llNewStop; + struct pos_args args; + + TRACE("(%p, %x, %p, %x)\n", pCurrent, dwCurrentFlags, pStop, dwStopFlags); + + args.current = pCurrent; + args.stop = pStop; + args.curflags = dwCurrentFlags; + args.stopflags = dwStopFlags; + + EnterCriticalSection(This->crst); + + llNewCurrent = Adjust(This->llCurrent, pCurrent, dwCurrentFlags); + llNewStop = Adjust(This->llStop, pStop, dwStopFlags); + + if (pCurrent) + bChangeCurrent = TRUE; + if (llNewStop != This->llStop) + bChangeStop = TRUE; + + TRACE("Old: %u, New: %u\n", (DWORD)(This->llCurrent/10000000), (DWORD)(llNewCurrent/10000000)); + + This->llCurrent = llNewCurrent; + This->llStop = llNewStop; + + if (dwCurrentFlags & AM_SEEKING_ReturnTime) + *pCurrent = llNewCurrent; + if (dwStopFlags & AM_SEEKING_ReturnTime) + *pStop = llNewStop; + + ForwardCmdSeek(This->crst, This->pUserData, fwd_setposition, &args); + LeaveCriticalSection(This->crst); + + if (bChangeCurrent) + This->fnChangeCurrent(This->pUserData); + if (bChangeStop) + This->fnChangeStop(This->pUserData); + + return S_OK; +} + +HRESULT WINAPI MediaSeekingImpl_GetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, LONGLONG * pStop) +{ + MediaSeekingImpl *This = (MediaSeekingImpl *)iface; + + TRACE("(%p, %p)\n", pCurrent, pStop); + + EnterCriticalSection(This->crst); + *pCurrent = This->llCurrent; + *pStop = This->llStop; + LeaveCriticalSection(This->crst); + + return S_OK; +} + +HRESULT WINAPI MediaSeekingImpl_GetAvailable(IMediaSeeking * iface, LONGLONG * pEarliest, LONGLONG * pLatest) +{ + MediaSeekingImpl *This = (MediaSeekingImpl *)iface; + + TRACE("(%p, %p)\n", pEarliest, pLatest); + + EnterCriticalSection(This->crst); + *pEarliest = 0; + *pLatest = This->llDuration; + LeaveCriticalSection(This->crst); + + return S_OK; +} + +HRESULT WINAPI MediaSeekingImpl_SetRate(IMediaSeeking * iface, double dRate) +{ + MediaSeekingImpl *This = (MediaSeekingImpl *)iface; + BOOL bChangeRate = (dRate != This->dRate); + HRESULT hr = S_OK; + + TRACE("(%e)\n", dRate); + + if (dRate > 100 || dRate < .001) + { + FIXME("Excessive rate %e, ignoring\n", dRate); + return VFW_E_UNSUPPORTED_AUDIO; + } + + EnterCriticalSection(This->crst); + This->dRate = dRate; + if (bChangeRate) + hr = This->fnChangeRate(This->pUserData); + ForwardCmdSeek(This->crst, This->pUserData, fwd_setrate, &dRate); + LeaveCriticalSection(This->crst); + + return hr; +} + +HRESULT WINAPI MediaSeekingImpl_GetRate(IMediaSeeking * iface, double * dRate) +{ + MediaSeekingImpl *This = (MediaSeekingImpl *)iface; + + TRACE("(%p)\n", dRate); + + EnterCriticalSection(This->crst); + /* Forward? */ + *dRate = This->dRate; + LeaveCriticalSection(This->crst); + + return S_OK; +} + +HRESULT WINAPI MediaSeekingImpl_GetPreroll(IMediaSeeking * iface, LONGLONG * pPreroll) +{ + TRACE("(%p)\n", pPreroll); + + *pPreroll = 0; + return S_OK; +} + +static HRESULT WINAPI MediaSeekingPassThru_QueryInterface(IMediaSeeking *iface, REFIID riid, LPVOID *ppvObj) +{ + ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); + + TRACE("(%p/%p)->(%s (%p), %p)\n", This, iface, debugstr_guid(riid), riid, ppvObj); + + return SeekOuter_QueryInterface(This, riid, ppvObj); +} + +static ULONG WINAPI MediaSeekingPassThru_AddRef(IMediaSeeking *iface) +{ + ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); + + TRACE("(%p/%p)->()\n", iface, This); + + return SeekOuter_AddRef(This); +} + +static ULONG WINAPI MediaSeekingPassThru_Release(IMediaSeeking *iface) +{ + ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); + + TRACE("(%p/%p)->()\n", iface, This); + + return SeekOuter_Release(This); +} + +static HRESULT WINAPI MediaSeekingPassThru_GetCapabilities(IMediaSeeking * iface, DWORD * pCapabilities) +{ + ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); + + TRACE("(%p/%p)->(%p)\n", iface, This, pCapabilities); + + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI MediaSeekingPassThru_CheckCapabilities(IMediaSeeking * iface, DWORD * pCapabilities) +{ + ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); + + TRACE("(%p/%p)->(%p)\n", iface, This, pCapabilities); + + if (!pCapabilities) + return E_POINTER; + + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI MediaSeekingPassThru_IsFormatSupported(IMediaSeeking * iface, const GUID * pFormat) +{ + ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); + TRACE("(%p/%p)->(%s)\n", iface, This, qzdebugstr_guid(pFormat)); + + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI MediaSeekingPassThru_QueryPreferredFormat(IMediaSeeking * iface, GUID * pFormat) +{ + ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); + TRACE("(%p/%p)->(%p)\n", iface, This, pFormat); + + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI MediaSeekingPassThru_GetTimeFormat(IMediaSeeking * iface, GUID * pFormat) +{ + ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); + TRACE("(%p/%p)->(%p)\n", iface, This, pFormat); + + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI MediaSeekingPassThru_IsUsingTimeFormat(IMediaSeeking * iface, const GUID * pFormat) +{ + ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); + + TRACE("(%p/%p)->(%s)\n", iface, This, qzdebugstr_guid(pFormat)); + + FIXME("stub\n"); + return E_NOTIMPL; +} + + +static HRESULT WINAPI MediaSeekingPassThru_SetTimeFormat(IMediaSeeking * iface, const GUID * pFormat) +{ + ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); + TRACE("(%p/%p)->(%s)\n", iface, This, qzdebugstr_guid(pFormat)); + + FIXME("stub\n"); + return E_NOTIMPL; +} + + +static HRESULT WINAPI MediaSeekingPassThru_GetDuration(IMediaSeeking * iface, LONGLONG * pDuration) +{ + ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); + PIN_INFO info; + HRESULT hr; + + TRACE("(%p/%p)->(%p)\n", iface, This, pDuration); + + IPin_QueryPinInfo(This->pin, &info); + + hr = ForwardCmdSeek(NULL, info.pFilter, fwd_getduration, pDuration); + IBaseFilter_Release(info.pFilter); + + return hr; +} + +static HRESULT WINAPI MediaSeekingPassThru_GetStopPosition(IMediaSeeking * iface, LONGLONG * pStop) +{ + ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); + + TRACE("(%p/%p)->(%p)\n", iface, This, pStop); + + FIXME("stub\n"); + return E_NOTIMPL; +} + +/* FIXME: Make use of the info the filter should expose */ +static HRESULT WINAPI MediaSeekingPassThru_GetCurrentPosition(IMediaSeeking * iface, LONGLONG * pCurrent) +{ + ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); + + TRACE("(%p/%p)->(%p)\n", iface, This, pCurrent); + + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI MediaSeekingPassThru_ConvertTimeFormat(IMediaSeeking * iface, LONGLONG * pTarget, const GUID * pTargetFormat, LONGLONG Source, const GUID * pSourceFormat) +{ + ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); + + TRACE("(%p/%p)->(%p,%s,%x%08x,%s)\n", iface, This, pTarget, debugstr_guid(pTargetFormat), (DWORD)(Source>>32), (DWORD)Source, debugstr_guid(pSourceFormat)); + + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI MediaSeekingPassThru_SetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, DWORD dwCurrentFlags, LONGLONG * pStop, DWORD dwStopFlags) +{ + ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); + struct pos_args args; + PIN_INFO info; + HRESULT hr; + + TRACE("(%p/%p)->(%p, %p)\n", iface, This, pCurrent, pStop); + args.current = pCurrent; + args.stop = pStop; + args.curflags = dwCurrentFlags; + args.stopflags = dwStopFlags; + + IPin_QueryPinInfo(This->pin, &info); + + hr = ForwardCmdSeek(NULL, info.pFilter, fwd_setposition, &args); + IBaseFilter_Release(info.pFilter); + return hr; +} + +static HRESULT WINAPI MediaSeekingPassThru_GetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, LONGLONG * pStop) +{ + ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); + + TRACE("(%p/%p)->(%p, %p)\n", iface, This, pCurrent, pStop); + + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI MediaSeekingPassThru_GetAvailable(IMediaSeeking * iface, LONGLONG * pEarliest, LONGLONG * pLatest) +{ + ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); + + TRACE("(%p/%p)->(%p,%p)\n", iface, This, pEarliest, pLatest); + + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI MediaSeekingPassThru_SetRate(IMediaSeeking * iface, double dRate) +{ + ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); + + TRACE("(%p/%p)->(%e)\n", iface, This, dRate); + + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI MediaSeekingPassThru_GetRate(IMediaSeeking * iface, double * dRate) +{ + ICOM_THIS_MULTI(PassThruImpl, IMediaSeeking_vtbl, iface); + + TRACE("(%p/%p)->(%p)\n", iface, This, dRate); + + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI MediaSeekingPassThru_GetPreroll(IMediaSeeking * iface, LONGLONG * pPreroll) +{ + TRACE("(%p)\n", pPreroll); + + FIXME("stub\n"); + return E_NOTIMPL; +} + +static const IMediaSeekingVtbl IMediaSeekingPassThru_Vtbl = +{ + MediaSeekingPassThru_QueryInterface, + MediaSeekingPassThru_AddRef, + MediaSeekingPassThru_Release, + MediaSeekingPassThru_GetCapabilities, + MediaSeekingPassThru_CheckCapabilities, + MediaSeekingPassThru_IsFormatSupported, + MediaSeekingPassThru_QueryPreferredFormat, + MediaSeekingPassThru_GetTimeFormat, + MediaSeekingPassThru_IsUsingTimeFormat, + MediaSeekingPassThru_SetTimeFormat, + MediaSeekingPassThru_GetDuration, + MediaSeekingPassThru_GetStopPosition, + MediaSeekingPassThru_GetCurrentPosition, + MediaSeekingPassThru_ConvertTimeFormat, + MediaSeekingPassThru_SetPositions, + MediaSeekingPassThru_GetPositions, + MediaSeekingPassThru_GetAvailable, + MediaSeekingPassThru_SetRate, + MediaSeekingPassThru_GetRate, + MediaSeekingPassThru_GetPreroll +}; diff --git a/dlls/strmbase/enummedia.c b/dlls/strmbase/enummedia.c new file mode 100644 index 0000000..f5f47cf --- /dev/null +++ b/dlls/strmbase/enummedia.c @@ -0,0 +1,308 @@ +/* + * Implementation of IEnumMediaTypes Interface + * + * Copyright 2003 Robert Shearman + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "strmbase_private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(strmbase); + +#define OUR_GUID_ENTRY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } , #name }, + +static const struct { + const GUID riid; + const char *name; +} InterfaceDesc[] = +{ +#include "uuids.h" + { { 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0} }, NULL } +}; + +/*********************************************************************** + * qzdebugstr_guid (internal) + * + * Gives a text version of DirectShow GUIDs + */ +const char * qzdebugstr_guid( const GUID * id ) +{ + int i; + char * name = NULL; + + for (i=0;InterfaceDesc[i].name && !name;i++) { + if (IsEqualGUID(&InterfaceDesc[i].riid, id)) return InterfaceDesc[i].name; + } + return debugstr_guid(id); +} + +/*********************************************************************** + * qzdebugstr_State (internal) + * + * Gives a text version of the FILTER_STATE enumeration + */ +const char * qzdebugstr_State(FILTER_STATE state) +{ + switch (state) + { + case State_Stopped: + return "State_Stopped"; + case State_Running: + return "State_Running"; + case State_Paused: + return "State_Paused"; + default: + return "State_Unknown"; + } +} + +HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc) +{ + *pDest = *pSrc; + if (!pSrc->pbFormat) return S_OK; + if (!(pDest->pbFormat = CoTaskMemAlloc(pSrc->cbFormat))) + return E_OUTOFMEMORY; + memcpy(pDest->pbFormat, pSrc->pbFormat, pSrc->cbFormat); + if (pDest->pUnk) + IUnknown_AddRef(pDest->pUnk); + return S_OK; +} + +void FreeMediaType(AM_MEDIA_TYPE * pMediaType) +{ + if (pMediaType->pbFormat) + { + CoTaskMemFree(pMediaType->pbFormat); + pMediaType->pbFormat = NULL; + } + if (pMediaType->pUnk) + { + IUnknown_Release(pMediaType->pUnk); + pMediaType->pUnk = NULL; + } +} + +static AM_MEDIA_TYPE * CreateMediaType(AM_MEDIA_TYPE const * pSrc) +{ + AM_MEDIA_TYPE * pDest; + + pDest = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); + if (!pDest) + return NULL; + + if (FAILED(CopyMediaType(pDest, pSrc))) + { + CoTaskMemFree(pDest); + return NULL; + } + + return pDest; +} + +void DeleteMediaType(AM_MEDIA_TYPE * pMediaType) +{ + FreeMediaType(pMediaType); + CoTaskMemFree(pMediaType); +} + +BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards) +{ + TRACE("pmt1: "); + dump_AM_MEDIA_TYPE(pmt1); + TRACE("pmt2: "); + dump_AM_MEDIA_TYPE(pmt2); + return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) && + ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL) || IsEqualGUID(&pmt2->subtype, &GUID_NULL))) || IsEqualGUID(&pmt1->subtype, &pmt2->subtype))); +} + +void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt) +{ + if (!pmt) + return; + TRACE("\t%s\n\t%s\n\t...\n\t%s\n", qzdebugstr_guid(&pmt->majortype), qzdebugstr_guid(&pmt->subtype), qzdebugstr_guid(&pmt->formattype)); +} + +typedef struct IEnumMediaTypesImpl +{ + const IEnumMediaTypesVtbl * lpVtbl; + LONG refCount; + ENUMMEDIADETAILS enumMediaDetails; + ULONG uIndex; +} IEnumMediaTypesImpl; + +static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl; + +HRESULT IEnumMediaTypesImpl_Construct(const ENUMMEDIADETAILS * pDetails, IEnumMediaTypes ** ppEnum) +{ + ULONG i; + IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl)); + + if (!pEnumMediaTypes) + { + *ppEnum = NULL; + return E_OUTOFMEMORY; + } + pEnumMediaTypes->lpVtbl = &IEnumMediaTypesImpl_Vtbl; + pEnumMediaTypes->refCount = 1; + pEnumMediaTypes->uIndex = 0; + pEnumMediaTypes->enumMediaDetails.cMediaTypes = pDetails->cMediaTypes; + pEnumMediaTypes->enumMediaDetails.pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * pDetails->cMediaTypes); + for (i = 0; i < pDetails->cMediaTypes; i++) + if (FAILED(CopyMediaType(&pEnumMediaTypes->enumMediaDetails.pMediaTypes[i], &pDetails->pMediaTypes[i]))) + { + while (i--) + CoTaskMemFree(pEnumMediaTypes->enumMediaDetails.pMediaTypes[i].pbFormat); + CoTaskMemFree(pEnumMediaTypes->enumMediaDetails.pMediaTypes); + return E_OUTOFMEMORY; + } + *ppEnum = (IEnumMediaTypes *)(&pEnumMediaTypes->lpVtbl); + return S_OK; +} + +static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, LPVOID * ppv) +{ + TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv); + + *ppv = NULL; + + if (IsEqualIID(riid, &IID_IUnknown)) + *ppv = (LPVOID)iface; + else if (IsEqualIID(riid, &IID_IEnumMediaTypes)) + *ppv = (LPVOID)iface; + + if (*ppv) + { + IUnknown_AddRef((IUnknown *)(*ppv)); + return S_OK; + } + + FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); + + return E_NOINTERFACE; +} + +static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface) +{ + IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface; + ULONG refCount = InterlockedIncrement(&This->refCount); + + TRACE("(%p)->() AddRef from %d\n", iface, refCount - 1); + + return refCount; +} + +static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface) +{ + IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface; + ULONG refCount = InterlockedDecrement(&This->refCount); + + TRACE("(%p)->() Release from %d\n", iface, refCount + 1); + + if (!refCount) + { + int i; + for (i = 0; i < This->enumMediaDetails.cMediaTypes; i++) + if (This->enumMediaDetails.pMediaTypes[i].pbFormat) + CoTaskMemFree(This->enumMediaDetails.pMediaTypes[i].pbFormat); + CoTaskMemFree(This->enumMediaDetails.pMediaTypes); + CoTaskMemFree(This); + } + return refCount; +} + +static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched) +{ + ULONG cFetched; + IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface; + + cFetched = min(This->enumMediaDetails.cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex; + + TRACE("(%u, %p, %p)\n", cMediaTypes, ppMediaTypes, pcFetched); + TRACE("Next uIndex: %u, cFetched: %u\n", This->uIndex, cFetched); + + if (cFetched > 0) + { + ULONG i; + for (i = 0; i < cFetched; i++) + if (!(ppMediaTypes[i] = CreateMediaType(&This->enumMediaDetails.pMediaTypes[This->uIndex + i]))) + { + while (i--) + DeleteMediaType(ppMediaTypes[i]); + *pcFetched = 0; + return E_OUTOFMEMORY; + } + } + + if ((cMediaTypes != 1) || pcFetched) + *pcFetched = cFetched; + + This->uIndex += cFetched; + + if (cFetched != cMediaTypes) + return S_FALSE; + return S_OK; +} + +static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes) +{ + IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface; + + TRACE("(%u)\n", cMediaTypes); + + if (This->uIndex + cMediaTypes < This->enumMediaDetails.cMediaTypes) + { + This->uIndex += cMediaTypes; + return S_OK; + } + return S_FALSE; +} + +static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface) +{ + IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface; + + TRACE("()\n"); + + This->uIndex = 0; + return S_OK; +} + +static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum) +{ + HRESULT hr; + IEnumMediaTypesImpl *This = (IEnumMediaTypesImpl *)iface; + + TRACE("(%p)\n", ppEnum); + + hr = IEnumMediaTypesImpl_Construct(&This->enumMediaDetails, ppEnum); + if (FAILED(hr)) + return hr; + return IEnumMediaTypes_Skip(*ppEnum, This->uIndex); +} + +static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl = +{ + IEnumMediaTypesImpl_QueryInterface, + IEnumMediaTypesImpl_AddRef, + IEnumMediaTypesImpl_Release, + IEnumMediaTypesImpl_Next, + IEnumMediaTypesImpl_Skip, + IEnumMediaTypesImpl_Reset, + IEnumMediaTypesImpl_Clone +}; diff --git a/dlls/strmbase/enumpins.c b/dlls/strmbase/enumpins.c new file mode 100644 index 0000000..f9f97fd --- /dev/null +++ b/dlls/strmbase/enumpins.c @@ -0,0 +1,211 @@ +/* + * Implementation of IEnumPins Interface + * + * Copyright 2003 Robert Shearman + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "strmbase_private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(strmbase); + +typedef struct IEnumPinsImpl +{ + const IEnumPinsVtbl * lpVtbl; + LONG refCount; + ULONG uIndex; + IBaseFilter *base; + FNOBTAINPIN receive_pin; + DWORD synctime; +} IEnumPinsImpl; + +static const struct IEnumPinsVtbl IEnumPinsImpl_Vtbl; + +HRESULT IEnumPinsImpl_Construct(IEnumPins ** ppEnum, FNOBTAINPIN receive_pin, IBaseFilter *base) +{ + IEnumPinsImpl * pEnumPins; + + if (!ppEnum) + return E_POINTER; + + pEnumPins = CoTaskMemAlloc(sizeof(IEnumPinsImpl)); + if (!pEnumPins) + { + *ppEnum = NULL; + return E_OUTOFMEMORY; + } + pEnumPins->lpVtbl = &IEnumPinsImpl_Vtbl; + pEnumPins->refCount = 1; + pEnumPins->uIndex = 0; + pEnumPins->receive_pin = receive_pin; + pEnumPins->base = base; + IBaseFilter_AddRef(base); + *ppEnum = (IEnumPins *)(&pEnumPins->lpVtbl); + + receive_pin(base, ~0, NULL, &pEnumPins->synctime); + + TRACE("Created new enumerator (%p)\n", *ppEnum); + return S_OK; +} + +static HRESULT WINAPI IEnumPinsImpl_QueryInterface(IEnumPins * iface, REFIID riid, LPVOID * ppv) +{ + TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv); + + *ppv = NULL; + + if (IsEqualIID(riid, &IID_IUnknown)) + *ppv = (LPVOID)iface; + else if (IsEqualIID(riid, &IID_IEnumPins)) + *ppv = (LPVOID)iface; + + if (*ppv) + { + IUnknown_AddRef((IUnknown *)(*ppv)); + return S_OK; + } + + FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); + + return E_NOINTERFACE; +} + +static ULONG WINAPI IEnumPinsImpl_AddRef(IEnumPins * iface) +{ + IEnumPinsImpl *This = (IEnumPinsImpl *)iface; + ULONG refCount = InterlockedIncrement(&This->refCount); + + TRACE("(%p)->() AddRef from %d\n", This, refCount - 1); + + return refCount; +} + +static ULONG WINAPI IEnumPinsImpl_Release(IEnumPins * iface) +{ + IEnumPinsImpl *This = (IEnumPinsImpl *)iface; + ULONG refCount = InterlockedDecrement(&This->refCount); + + TRACE("(%p)->() Release from %d\n", This, refCount + 1); + + if (!refCount) + { + IBaseFilter_Release(This->base); + CoTaskMemFree(This); + return 0; + } + else + return refCount; +} + +static HRESULT WINAPI IEnumPinsImpl_Next(IEnumPins * iface, ULONG cPins, IPin ** ppPins, ULONG * pcFetched) +{ + IEnumPinsImpl *This = (IEnumPinsImpl *)iface; + DWORD synctime = This->synctime; + HRESULT hr = S_OK; + ULONG i = 0; + + TRACE("(%u, %p, %p)\n", cPins, ppPins, pcFetched); + + if (!ppPins) + return E_POINTER; + + if (cPins > 1 && !pcFetched) + return E_INVALIDARG; + + if (pcFetched) + *pcFetched = 0; + + while (i < cPins && hr == S_OK) + { + hr = This->receive_pin(This->base, This->uIndex + i, &ppPins[i], &synctime); + + if (hr == S_OK) + ++i; + + if (synctime != This->synctime) + break; + } + + if (!i && synctime != This->synctime) + return VFW_E_ENUM_OUT_OF_SYNC; + + if (pcFetched) + *pcFetched = i; + This->uIndex += i; + + if (i < cPins) + return S_FALSE; + return S_OK; +} + +static HRESULT WINAPI IEnumPinsImpl_Skip(IEnumPins * iface, ULONG cPins) +{ + IEnumPinsImpl *This = (IEnumPinsImpl *)iface; + DWORD synctime = This->synctime; + HRESULT hr; + IPin *pin = NULL; + + TRACE("(%u)\n", cPins); + + hr = This->receive_pin(This->base, This->uIndex + cPins, &pin, &synctime); + if (pin) + IPin_Release(pin); + + if (synctime != This->synctime) + return VFW_E_ENUM_OUT_OF_SYNC; + + if (hr == S_OK) + This->uIndex += cPins; + + return hr; +} + +static HRESULT WINAPI IEnumPinsImpl_Reset(IEnumPins * iface) +{ + IEnumPinsImpl *This = (IEnumPinsImpl *)iface; + + TRACE("IEnumPinsImpl::Reset()\n"); + This->receive_pin(This->base, ~0, NULL, &This->synctime); + + This->uIndex = 0; + return S_OK; +} + +static HRESULT WINAPI IEnumPinsImpl_Clone(IEnumPins * iface, IEnumPins ** ppEnum) +{ + HRESULT hr; + IEnumPinsImpl *This = (IEnumPinsImpl *)iface; + + TRACE("(%p)\n", ppEnum); + + hr = IEnumPinsImpl_Construct(ppEnum, This->receive_pin, This->base); + if (FAILED(hr)) + return hr; + return IEnumPins_Skip(*ppEnum, This->uIndex); +} + +static const IEnumPinsVtbl IEnumPinsImpl_Vtbl = +{ + IEnumPinsImpl_QueryInterface, + IEnumPinsImpl_AddRef, + IEnumPinsImpl_Release, + IEnumPinsImpl_Next, + IEnumPinsImpl_Skip, + IEnumPinsImpl_Reset, + IEnumPinsImpl_Clone +}; diff --git a/dlls/strmbase/memallocator.c b/dlls/strmbase/memallocator.c new file mode 100644 index 0000000..56ca461 --- /dev/null +++ b/dlls/strmbase/memallocator.c @@ -0,0 +1,876 @@ +/* + * Memory Allocator and Media Sample Implementation + * + * Copyright 2003 Robert Shearman + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "strmbase_private.h" +#include "wine/debug.h" +#include "assert.h" + +WINE_DEFAULT_DEBUG_CHANNEL(strmbase); + +void dump_AM_SAMPLE2_PROPERTIES(const AM_SAMPLE2_PROPERTIES * pProps) +{ + if (!pProps) + { + TRACE("AM_SAMPLE2_PROPERTIES: (null)\n"); + return; + } + TRACE("\tcbData: %d\n", pProps->cbData); + TRACE("\tdwTypeSpecificFlags: 0x%8x\n", pProps->dwTypeSpecificFlags); + TRACE("\tdwSampleFlags: 0x%8x\n", pProps->dwSampleFlags); + TRACE("\tlActual: %d\n", pProps->lActual); + TRACE("\ttStart: %x%08x%s\n", (LONG)(pProps->tStart >> 32), (LONG)pProps->tStart, pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID ? "" : " (not valid)"); + TRACE("\ttStop: %x%08x%s\n", (LONG)(pProps->tStop >> 32), (LONG)pProps->tStop, pProps->dwSampleFlags & AM_SAMPLE_STOPVALID ? "" : " (not valid)"); + TRACE("\tdwStreamId: 0x%x\n", pProps->dwStreamId); + TRACE("\tpMediaType: %p\n", pProps->pMediaType); + TRACE("\tpbBuffer: %p\n", pProps->pbBuffer); + TRACE("\tcbBuffer: %d\n", pProps->cbBuffer); +} + +static const IMemAllocatorVtbl BaseMemAllocator_VTable; +static const IMediaSample2Vtbl StdMediaSample2_VTable; + +#define AM_SAMPLE2_PROP_SIZE_WRITABLE (unsigned int)(&((AM_SAMPLE2_PROPERTIES *)0)->pbBuffer) + +#define INVALID_MEDIA_TIME (((ULONGLONG)0x7fffffff << 32) | 0xffffffff) + +HRESULT BaseMemAllocator_Init(HRESULT (* fnAlloc)(IMemAllocator *), + HRESULT (* fnFree)(IMemAllocator *), + HRESULT (* fnVerify)(IMemAllocator *, ALLOCATOR_PROPERTIES *), + HRESULT (* fnBufferPrepare)(IMemAllocator *, StdMediaSample2 *, DWORD), + HRESULT (* fnBufferReleased)(IMemAllocator *, StdMediaSample2 *), + void (* fnDestroyed)(IMemAllocator *), + CRITICAL_SECTION *pCritSect, + BaseMemAllocator * pMemAlloc) +{ + assert(fnAlloc && fnFree && fnDestroyed); + + pMemAlloc->lpVtbl = &BaseMemAllocator_VTable; + + pMemAlloc->ref = 1; + ZeroMemory(&pMemAlloc->props, sizeof(pMemAlloc->props)); + list_init(&pMemAlloc->free_list); + list_init(&pMemAlloc->used_list); + pMemAlloc->fnAlloc = fnAlloc; + pMemAlloc->fnFree = fnFree; + pMemAlloc->fnVerify = fnVerify; + pMemAlloc->fnBufferPrepare = fnBufferPrepare; + pMemAlloc->fnBufferReleased = fnBufferReleased; + pMemAlloc->fnDestroyed = fnDestroyed; + pMemAlloc->bDecommitQueued = FALSE; + pMemAlloc->bCommitted = FALSE; + pMemAlloc->hSemWaiting = NULL; + pMemAlloc->lWaiting = 0; + pMemAlloc->pCritSect = pCritSect; + + return S_OK; +} + +static HRESULT WINAPI BaseMemAllocator_QueryInterface(IMemAllocator * iface, REFIID riid, LPVOID * ppv) +{ + BaseMemAllocator *This = (BaseMemAllocator *)iface; + TRACE("(%p)->(%s, %p)\n", This, qzdebugstr_guid(riid), ppv); + + *ppv = NULL; + + if (IsEqualIID(riid, &IID_IUnknown)) + *ppv = (LPVOID)This; + else if (IsEqualIID(riid, &IID_IMemAllocator)) + *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 BaseMemAllocator_AddRef(IMemAllocator * iface) +{ + BaseMemAllocator *This = (BaseMemAllocator *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p)->() AddRef from %d\n", iface, ref - 1); + + return ref; +} + +static ULONG WINAPI BaseMemAllocator_Release(IMemAllocator * iface) +{ + BaseMemAllocator *This = (BaseMemAllocator *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p)->() Release from %d\n", iface, ref + 1); + + if (!ref) + { + CloseHandle(This->hSemWaiting); + if (This->bCommitted) + This->fnFree(iface); + + This->fnDestroyed(iface); + return 0; + } + return ref; +} + +static HRESULT WINAPI BaseMemAllocator_SetProperties(IMemAllocator * iface, ALLOCATOR_PROPERTIES *pRequest, ALLOCATOR_PROPERTIES *pActual) +{ + BaseMemAllocator *This = (BaseMemAllocator *)iface; + HRESULT hr; + + TRACE("(%p)->(%p, %p)\n", This, pRequest, pActual); + + EnterCriticalSection(This->pCritSect); + { + if (!list_empty(&This->used_list)) + hr = VFW_E_BUFFERS_OUTSTANDING; + else if (This->bCommitted) + hr = VFW_E_ALREADY_COMMITTED; + else if (pRequest->cbAlign == 0) + hr = VFW_E_BADALIGN; + else + { + if (This->fnVerify) + hr = This->fnVerify(iface, pRequest); + else + hr = S_OK; + + if (SUCCEEDED(hr)) + This->props = *pRequest; + + *pActual = This->props; + } + } + LeaveCriticalSection(This->pCritSect); + + return hr; +} + +static HRESULT WINAPI BaseMemAllocator_GetProperties(IMemAllocator * iface, ALLOCATOR_PROPERTIES *pProps) +{ + BaseMemAllocator *This = (BaseMemAllocator *)iface; + HRESULT hr = S_OK; + + TRACE("(%p)->(%p)\n", This, pProps); + + EnterCriticalSection(This->pCritSect); + { + memcpy(pProps, &This->props, sizeof(*pProps)); + } + LeaveCriticalSection(This->pCritSect); + + return hr; +} + +static HRESULT WINAPI BaseMemAllocator_Commit(IMemAllocator * iface) +{ + BaseMemAllocator *This = (BaseMemAllocator *)iface; + HRESULT hr; + + TRACE("(%p)->()\n", This); + + EnterCriticalSection(This->pCritSect); + { + if (!This->props.cbAlign) + hr = VFW_E_BADALIGN; + else if (!This->props.cbBuffer) + hr = VFW_E_SIZENOTSET; + else if (!This->props.cBuffers) + hr = VFW_E_BUFFER_NOTSET; + else if (This->bDecommitQueued && This->bCommitted) + { + This->bDecommitQueued = FALSE; + hr = S_OK; + } + else if (This->bCommitted) + hr = S_OK; + else + { + if (!(This->hSemWaiting = CreateSemaphoreW(NULL, This->props.cBuffers, This->props.cBuffers, NULL))) + { + ERR("Couldn't create semaphore (error was %u)\n", GetLastError()); + hr = HRESULT_FROM_WIN32(GetLastError()); + } + else + { + hr = This->fnAlloc(iface); + if (SUCCEEDED(hr)) + This->bCommitted = TRUE; + else + ERR("fnAlloc failed with error 0x%x\n", hr); + } + } + } + LeaveCriticalSection(This->pCritSect); + + return hr; +} + +static HRESULT WINAPI BaseMemAllocator_Decommit(IMemAllocator * iface) +{ + BaseMemAllocator *This = (BaseMemAllocator *)iface; + HRESULT hr; + + TRACE("(%p)->()\n", This); + + EnterCriticalSection(This->pCritSect); + { + if (!This->bCommitted) + hr = S_OK; + else + { + if (!list_empty(&This->used_list)) + { + This->bDecommitQueued = TRUE; + /* notify ALL waiting threads that they cannot be allocated a buffer any more */ + ReleaseSemaphore(This->hSemWaiting, This->lWaiting, NULL); + + hr = S_OK; + } + else + { + if (This->lWaiting != 0) + ERR("Waiting: %d\n", This->lWaiting); + + This->bCommitted = FALSE; + CloseHandle(This->hSemWaiting); + This->hSemWaiting = NULL; + + hr = This->fnFree(iface); + if (FAILED(hr)) + ERR("fnFree failed with error 0x%x\n", hr); + } + } + } + LeaveCriticalSection(This->pCritSect); + + return hr; +} + +static HRESULT WINAPI BaseMemAllocator_GetBuffer(IMemAllocator * iface, IMediaSample ** pSample, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime, DWORD dwFlags) +{ + BaseMemAllocator *This = (BaseMemAllocator *)iface; + HRESULT hr = S_OK; + + /* NOTE: The pStartTime and pEndTime parameters are not applied to the sample. + * The allocator might use these values to determine which buffer it retrieves */ + + TRACE("(%p)->(%p, %p, %p, %x)\n", This, pSample, pStartTime, pEndTime, dwFlags); + + *pSample = NULL; + + EnterCriticalSection(This->pCritSect); + if (!This->bCommitted || This->bDecommitQueued) + { + WARN("Not committed\n"); + hr = VFW_E_NOT_COMMITTED; + } + else + ++This->lWaiting; + LeaveCriticalSection(This->pCritSect); + if (FAILED(hr)) + return hr; + + if (WaitForSingleObject(This->hSemWaiting, (dwFlags & AM_GBF_NOWAIT) ? 0 : INFINITE) != WAIT_OBJECT_0) + { + EnterCriticalSection(This->pCritSect); + --This->lWaiting; + LeaveCriticalSection(This->pCritSect); + WARN("Timed out\n"); + return VFW_E_TIMEOUT; + } + + EnterCriticalSection(This->pCritSect); + { + --This->lWaiting; + if (!This->bCommitted) + hr = VFW_E_NOT_COMMITTED; + else if (This->bDecommitQueued) + hr = VFW_E_TIMEOUT; + else + { + struct list * free = list_head(&This->free_list); + list_remove(free); + list_add_head(&This->used_list, free); + + *pSample = (IMediaSample *)LIST_ENTRY(free, StdMediaSample2, listentry); + + assert(((StdMediaSample2 *)*pSample)->ref == 0); + + IMediaSample_AddRef(*pSample); + } + } + LeaveCriticalSection(This->pCritSect); + + if (hr != S_OK) + WARN("%08x\n", hr); + return hr; +} + +static HRESULT WINAPI BaseMemAllocator_ReleaseBuffer(IMemAllocator * iface, IMediaSample * pSample) +{ + BaseMemAllocator *This = (BaseMemAllocator *)iface; + StdMediaSample2 * pStdSample = (StdMediaSample2 *)pSample; + HRESULT hr = S_OK; + + TRACE("(%p)->(%p)\n", This, pSample); + + /* FIXME: make sure that sample is currently on the used list */ + + /* FIXME: we should probably check the ref count on the sample before freeing + * it to make sure that it is not still in use */ + EnterCriticalSection(This->pCritSect); + { + if (!This->bCommitted) + ERR("Releasing a buffer when the allocator is not committed?!?\n"); + + /* remove from used_list */ + list_remove(&pStdSample->listentry); + + list_add_head(&This->free_list, &pStdSample->listentry); + + if (list_empty(&This->used_list) && This->bDecommitQueued && This->bCommitted) + { + HRESULT hrfree; + + if (This->lWaiting != 0) + ERR("Waiting: %d\n", This->lWaiting); + + This->bCommitted = FALSE; + This->bDecommitQueued = FALSE; + + CloseHandle(This->hSemWaiting); + This->hSemWaiting = NULL; + + if (FAILED(hrfree = This->fnFree(iface))) + ERR("fnFree failed with error 0x%x\n", hrfree); + } + } + LeaveCriticalSection(This->pCritSect); + + /* notify a waiting thread that there is now a free buffer */ + if (This->hSemWaiting && !ReleaseSemaphore(This->hSemWaiting, 1, NULL)) + { + ERR("ReleaseSemaphore failed with error %u\n", GetLastError()); + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + return hr; +} + +static const IMemAllocatorVtbl BaseMemAllocator_VTable = +{ + BaseMemAllocator_QueryInterface, + BaseMemAllocator_AddRef, + BaseMemAllocator_Release, + BaseMemAllocator_SetProperties, + BaseMemAllocator_GetProperties, + BaseMemAllocator_Commit, + BaseMemAllocator_Decommit, + BaseMemAllocator_GetBuffer, + BaseMemAllocator_ReleaseBuffer +}; + +HRESULT StdMediaSample2_Construct(BYTE * pbBuffer, LONG cbBuffer, IMemAllocator * pParent, StdMediaSample2 ** ppSample) +{ + assert(pbBuffer && pParent && (cbBuffer > 0)); + + if (!(*ppSample = CoTaskMemAlloc(sizeof(StdMediaSample2)))) + return E_OUTOFMEMORY; + + (*ppSample)->lpvtbl = &StdMediaSample2_VTable; + (*ppSample)->ref = 0; + ZeroMemory(&(*ppSample)->props, sizeof((*ppSample)->props)); + + /* NOTE: no need to AddRef as the parent is guaranteed to be around + * at least as long as us and we don't want to create circular + * dependencies on the ref count */ + (*ppSample)->pParent = pParent; + (*ppSample)->props.cbData = sizeof(AM_SAMPLE2_PROPERTIES); + (*ppSample)->props.cbBuffer = (*ppSample)->props.lActual = cbBuffer; + (*ppSample)->props.pbBuffer = pbBuffer; + (*ppSample)->tMediaStart = INVALID_MEDIA_TIME; + (*ppSample)->tMediaEnd = 0; + + return S_OK; +} + +void StdMediaSample2_Delete(StdMediaSample2 * This) +{ + /* NOTE: does not remove itself from the list it belongs to */ + CoTaskMemFree(This); +} + +static HRESULT WINAPI StdMediaSample2_QueryInterface(IMediaSample2 * iface, REFIID riid, LPVOID * ppv) +{ + StdMediaSample2 *This = (StdMediaSample2 *)iface; + TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv); + + *ppv = NULL; + + if (IsEqualIID(riid, &IID_IUnknown)) + *ppv = (LPVOID)This; + else if (IsEqualIID(riid, &IID_IMediaSample)) + *ppv = (LPVOID)This; + else if (IsEqualIID(riid, &IID_IMediaSample2)) + *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 StdMediaSample2_AddRef(IMediaSample2 * iface) +{ + StdMediaSample2 *This = (StdMediaSample2 *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p)->() AddRef from %d\n", iface, ref - 1); + + return ref; +} + +static ULONG WINAPI StdMediaSample2_Release(IMediaSample2 * iface) +{ + StdMediaSample2 *This = (StdMediaSample2 *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p)->() Release from %d\n", iface, ref + 1); + + if (!ref) + { + if (This->pParent) + IMemAllocator_ReleaseBuffer(This->pParent, (IMediaSample *)iface); + else + StdMediaSample2_Delete(This); + return 0; + } + return ref; +} + +static HRESULT WINAPI StdMediaSample2_GetPointer(IMediaSample2 * iface, BYTE ** ppBuffer) +{ + StdMediaSample2 *This = (StdMediaSample2 *)iface; + + TRACE("(%p)\n", ppBuffer); + + *ppBuffer = This->props.pbBuffer; + + if (!*ppBuffer) + { + ERR("Requested an unlocked surface and trying to lock regardless\n"); + return E_FAIL; + } + + return S_OK; +} + +static long WINAPI StdMediaSample2_GetSize(IMediaSample2 * iface) +{ + StdMediaSample2 *This = (StdMediaSample2 *)iface; + + TRACE("StdMediaSample2_GetSize()\n"); + + return This->props.cbBuffer; +} + +static HRESULT WINAPI StdMediaSample2_GetTime(IMediaSample2 * iface, REFERENCE_TIME * pStart, REFERENCE_TIME * pEnd) +{ + HRESULT hr; + StdMediaSample2 *This = (StdMediaSample2 *)iface; + + TRACE("(%p, %p)\n", pStart, pEnd); + + if (!(This->props.dwSampleFlags & AM_SAMPLE_TIMEVALID)) + hr = VFW_E_SAMPLE_TIME_NOT_SET; + else if (!(This->props.dwSampleFlags & AM_SAMPLE_STOPVALID)) + { + *pStart = This->props.tStart; + *pEnd = This->props.tStart + 1; + + hr = VFW_S_NO_STOP_TIME; + } + else + { + *pStart = This->props.tStart; + *pEnd = This->props.tStop; + + hr = S_OK; + } + + return S_OK; +} + +static HRESULT WINAPI StdMediaSample2_SetTime(IMediaSample2 * iface, REFERENCE_TIME * pStart, REFERENCE_TIME * pEnd) +{ + StdMediaSample2 *This = (StdMediaSample2 *)iface; + + TRACE("(%p, %p)\n", pStart, pEnd); + + if (pStart) + { + This->props.tStart = *pStart; + This->props.dwSampleFlags |= AM_SAMPLE_TIMEVALID; + } + else + This->props.dwSampleFlags &= ~AM_SAMPLE_TIMEVALID; + + if (pEnd) + { + This->props.tStop = *pEnd; + This->props.dwSampleFlags |= AM_SAMPLE_STOPVALID; + } + else + This->props.dwSampleFlags &= ~AM_SAMPLE_STOPVALID; + + return S_OK; +} + +static HRESULT WINAPI StdMediaSample2_IsSyncPoint(IMediaSample2 * iface) +{ + StdMediaSample2 *This = (StdMediaSample2 *)iface; + + TRACE("()\n"); + + return (This->props.dwSampleFlags & AM_SAMPLE_SPLICEPOINT) ? S_OK : S_FALSE; +} + +static HRESULT WINAPI StdMediaSample2_SetSyncPoint(IMediaSample2 * iface, BOOL bIsSyncPoint) +{ + StdMediaSample2 *This = (StdMediaSample2 *)iface; + + TRACE("(%s)\n", bIsSyncPoint ? "TRUE" : "FALSE"); + + if (bIsSyncPoint) + This->props.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT; + else + This->props.dwSampleFlags &= ~AM_SAMPLE_SPLICEPOINT; + + return S_OK; +} + +static HRESULT WINAPI StdMediaSample2_IsPreroll(IMediaSample2 * iface) +{ + StdMediaSample2 *This = (StdMediaSample2 *)iface; + + TRACE("()\n"); + + return (This->props.dwSampleFlags & AM_SAMPLE_PREROLL) ? S_OK : S_FALSE; +} + +static HRESULT WINAPI StdMediaSample2_SetPreroll(IMediaSample2 * iface, BOOL bIsPreroll) +{ + StdMediaSample2 *This = (StdMediaSample2 *)iface; + + TRACE("(%s)\n", bIsPreroll ? "TRUE" : "FALSE"); + + if (bIsPreroll) + This->props.dwSampleFlags |= AM_SAMPLE_PREROLL; + else + This->props.dwSampleFlags &= ~AM_SAMPLE_PREROLL; + + return S_OK; +} + +static LONG WINAPI StdMediaSample2_GetActualDataLength(IMediaSample2 * iface) +{ + StdMediaSample2 *This = (StdMediaSample2 *)iface; + + TRACE("()\n"); + + return This->props.lActual; +} + +static HRESULT WINAPI StdMediaSample2_SetActualDataLength(IMediaSample2 * iface, LONG len) +{ + StdMediaSample2 *This = (StdMediaSample2 *)iface; + + TRACE("(%d)\n", len); + + if ((len > This->props.cbBuffer) || (len < 0)) + { + WARN("Tried to set length to %d, while max is %d\n", len, This->props.cbBuffer); + return VFW_E_BUFFER_OVERFLOW; + } + else + { + This->props.lActual = len; + return S_OK; + } +} + +static HRESULT WINAPI StdMediaSample2_GetMediaType(IMediaSample2 * iface, AM_MEDIA_TYPE ** ppMediaType) +{ + StdMediaSample2 *This = (StdMediaSample2 *)iface; + + TRACE("(%p)\n", ppMediaType); + + if (!This->props.pMediaType) { + /* Make sure we return a NULL pointer (required by native Quartz dll) */ + if (ppMediaType) + *ppMediaType = NULL; + return S_FALSE; + } + + if (!(*ppMediaType = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)))) + return E_OUTOFMEMORY; + + return CopyMediaType(*ppMediaType, This->props.pMediaType); +} + +static HRESULT WINAPI StdMediaSample2_SetMediaType(IMediaSample2 * iface, AM_MEDIA_TYPE * pMediaType) +{ + StdMediaSample2 *This = (StdMediaSample2 *)iface; + + TRACE("(%p)\n", pMediaType); + + if (This->props.pMediaType) + FreeMediaType(This->props.pMediaType); + else if (!(This->props.pMediaType = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)))) + return E_OUTOFMEMORY; + + return CopyMediaType(This->props.pMediaType, pMediaType); +} + +static HRESULT WINAPI StdMediaSample2_IsDiscontinuity(IMediaSample2 * iface) +{ + StdMediaSample2 *This = (StdMediaSample2 *)iface; + + TRACE("()\n"); + + return (This->props.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) ? S_OK : S_FALSE; +} + +static HRESULT WINAPI StdMediaSample2_SetDiscontinuity(IMediaSample2 * iface, BOOL bIsDiscontinuity) +{ + StdMediaSample2 *This = (StdMediaSample2 *)iface; + + TRACE("(%s)\n", bIsDiscontinuity ? "TRUE" : "FALSE"); + + if (bIsDiscontinuity) + This->props.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY; + else + This->props.dwSampleFlags &= ~AM_SAMPLE_DATADISCONTINUITY; + + return S_OK; +} + +static HRESULT WINAPI StdMediaSample2_GetMediaTime(IMediaSample2 * iface, LONGLONG * pStart, LONGLONG * pEnd) +{ + StdMediaSample2 *This = (StdMediaSample2 *)iface; + + TRACE("(%p, %p)\n", pStart, pEnd); + + if (This->tMediaStart == INVALID_MEDIA_TIME) + return VFW_E_MEDIA_TIME_NOT_SET; + + *pStart = This->tMediaStart; + *pEnd = This->tMediaEnd; + + return E_NOTIMPL; +} + +static HRESULT WINAPI StdMediaSample2_SetMediaTime(IMediaSample2 * iface, LONGLONG * pStart, LONGLONG * pEnd) +{ + StdMediaSample2 *This = (StdMediaSample2 *)iface; + + TRACE("(%p, %p)\n", pStart, pEnd); + + if (pStart) + This->tMediaStart = *pStart; + else + This->tMediaStart = INVALID_MEDIA_TIME; + + if (pEnd) + This->tMediaEnd = *pEnd; + else + This->tMediaEnd = 0; + + return S_OK; +} + +static HRESULT WINAPI StdMediaSample2_GetProperties(IMediaSample2 * iface, DWORD cbProperties, BYTE * pbProperties) +{ + StdMediaSample2 *This = (StdMediaSample2 *)iface; + + TRACE("(%d, %p)\n", cbProperties, pbProperties); + + memcpy(pbProperties, &This->props, min(cbProperties, sizeof(This->props))); + + return S_OK; +} + +static HRESULT WINAPI StdMediaSample2_SetProperties(IMediaSample2 * iface, DWORD cbProperties, const BYTE * pbProperties) +{ + StdMediaSample2 *This = (StdMediaSample2 *)iface; + + TRACE("(%d, %p)\n", cbProperties, pbProperties); + + /* NOTE: pbBuffer and cbBuffer are read-only */ + memcpy(&This->props, pbProperties, min(cbProperties, AM_SAMPLE2_PROP_SIZE_WRITABLE)); + + return S_OK; +} + +static const IMediaSample2Vtbl StdMediaSample2_VTable = +{ + StdMediaSample2_QueryInterface, + StdMediaSample2_AddRef, + StdMediaSample2_Release, + StdMediaSample2_GetPointer, + StdMediaSample2_GetSize, + StdMediaSample2_GetTime, + StdMediaSample2_SetTime, + StdMediaSample2_IsSyncPoint, + StdMediaSample2_SetSyncPoint, + StdMediaSample2_IsPreroll, + StdMediaSample2_SetPreroll, + StdMediaSample2_GetActualDataLength, + StdMediaSample2_SetActualDataLength, + StdMediaSample2_GetMediaType, + StdMediaSample2_SetMediaType, + StdMediaSample2_IsDiscontinuity, + StdMediaSample2_SetDiscontinuity, + StdMediaSample2_GetMediaTime, + StdMediaSample2_SetMediaTime, + StdMediaSample2_GetProperties, + StdMediaSample2_SetProperties +}; + +typedef struct StdMemAllocator +{ + BaseMemAllocator base; + CRITICAL_SECTION csState; + LPVOID pMemory; +} StdMemAllocator; + +static HRESULT StdMemAllocator_Alloc(IMemAllocator * iface) +{ + StdMemAllocator *This = (StdMemAllocator *)iface; + StdMediaSample2 * pSample = NULL; + SYSTEM_INFO si; + long i; + + assert(list_empty(&This->base.free_list)); + + /* check alignment */ + GetSystemInfo(&si); + + /* we do not allow a courser alignment than the OS page size */ + if ((si.dwPageSize % This->base.props.cbAlign) != 0) + return VFW_E_BADALIGN; + + /* FIXME: each sample has to have its buffer start on the right alignment. + * We don't do this at the moment */ + + /* allocate memory */ + This->pMemory = VirtualAlloc(NULL, (This->base.props.cbBuffer + This->base.props.cbPrefix) * This->base.props.cBuffers, MEM_COMMIT, PAGE_READWRITE); + + for (i = This->base.props.cBuffers - 1; i >= 0; i--) + { + /* pbBuffer does not start at the base address, it starts at base + cbPrefix */ + BYTE * pbBuffer = (BYTE *)This->pMemory + i * (This->base.props.cbBuffer + This->base.props.cbPrefix) + This->base.props.cbPrefix; + + StdMediaSample2_Construct(pbBuffer, This->base.props.cbBuffer, iface, &pSample); + + list_add_head(&This->base.free_list, &pSample->listentry); + } + + return S_OK; +} + +static HRESULT StdMemAllocator_Free(IMemAllocator * iface) +{ + StdMemAllocator *This = (StdMemAllocator *)iface; + struct list * cursor; + + if (!list_empty(&This->base.used_list)) + { + WARN("Freeing allocator with outstanding samples!\n"); + while ((cursor = list_head(&This->base.used_list)) != NULL) + { + StdMediaSample2 *pSample; + list_remove(cursor); + pSample = LIST_ENTRY(cursor, StdMediaSample2, listentry); + pSample->pParent = NULL; + } + } + + while ((cursor = list_head(&This->base.free_list)) != NULL) + { + list_remove(cursor); + StdMediaSample2_Delete(LIST_ENTRY(cursor, StdMediaSample2, listentry)); + } + + /* free memory */ + if (!VirtualFree(This->pMemory, 0, MEM_RELEASE)) + { + ERR("Couldn't free memory. Error: %u\n", GetLastError()); + return HRESULT_FROM_WIN32(GetLastError()); + } + + return S_OK; +} + +static void StdMemAllocator_Destroy(IMemAllocator *iface) +{ + StdMemAllocator *This = (StdMemAllocator *)iface; + + This->csState.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&This->csState); + + CoTaskMemFree(This); +} + +HRESULT StdMemAllocator_create(LPUNKNOWN lpUnkOuter, LPVOID * ppv) +{ + StdMemAllocator * pMemAlloc; + HRESULT hr; + + *ppv = NULL; + + if (lpUnkOuter) + return CLASS_E_NOAGGREGATION; + + if (!(pMemAlloc = CoTaskMemAlloc(sizeof(*pMemAlloc)))) + return E_OUTOFMEMORY; + + InitializeCriticalSection(&pMemAlloc->csState); + pMemAlloc->csState.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": StdMemAllocator.csState"); + + pMemAlloc->pMemory = NULL; + + if (SUCCEEDED(hr = BaseMemAllocator_Init(StdMemAllocator_Alloc, StdMemAllocator_Free, NULL, NULL, NULL, StdMemAllocator_Destroy, &pMemAlloc->csState, &pMemAlloc->base))) + *ppv = (LPVOID)pMemAlloc; + else + CoTaskMemFree(pMemAlloc); + + return hr; +} diff --git a/dlls/strmbase/parser.c b/dlls/strmbase/parser.c new file mode 100644 index 0000000..0157c1e --- /dev/null +++ b/dlls/strmbase/parser.c @@ -0,0 +1,783 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "strmbase_private.h" + +#include "vfwmsgs.h" +#include "amvideo.h" + +#include "wine/unicode.h" +#include "wine/debug.h" + +#include +#include + +WINE_DEFAULT_DEBUG_CHANNEL(strmbase); + +static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0}; +static const IMediaSeekingVtbl Parser_Seeking_Vtbl; +static const IPinVtbl Parser_OutputPin_Vtbl; +static const IPinVtbl Parser_InputPin_Vtbl; + +static HRESULT Parser_OutputPin_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt); +static HRESULT Parser_ChangeCurrent(IBaseFilter *iface); +static HRESULT Parser_ChangeStop(IBaseFilter *iface); +static HRESULT Parser_ChangeRate(IBaseFilter *iface); + +static inline ParserImpl *impl_from_IMediaSeeking( IMediaSeeking *iface ) +{ + return (ParserImpl *)((char*)iface - FIELD_OFFSET(ParserImpl, mediaSeeking.lpVtbl)); +} + + +HRESULT Parser_Create(ParserImpl* pParser, const IBaseFilterVtbl *Parser_Vtbl, const CLSID* pClsid, PFN_PROCESS_SAMPLE fnProcessSample, PFN_QUERY_ACCEPT fnQueryAccept, PFN_PRE_CONNECT fnPreConnect, PFN_CLEANUP fnCleanup, PFN_DISCONNECT fnDisconnect, REQUESTPROC fnRequest, STOPPROCESSPROC fnDone, CHANGEPROC stop, CHANGEPROC current, CHANGEPROC rate) +{ + HRESULT hr; + PIN_INFO piInput; + + /* pTransformFilter is already allocated */ + pParser->clsid = *pClsid; + pParser->lpVtbl = Parser_Vtbl; + pParser->refCount = 1; + InitializeCriticalSection(&pParser->csFilter); + pParser->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ParserImpl.csFilter"); + pParser->state = State_Stopped; + pParser->pClock = NULL; + pParser->fnDisconnect = fnDisconnect; + ZeroMemory(&pParser->filterInfo, sizeof(FILTER_INFO)); + pParser->lastpinchange = GetTickCount(); + + pParser->cStreams = 0; + pParser->ppPins = CoTaskMemAlloc(1 * sizeof(IPin *)); + + /* construct input pin */ + piInput.dir = PINDIR_INPUT; + piInput.pFilter = (IBaseFilter *)pParser; + lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0])); + + if (!current) + current = Parser_ChangeCurrent; + + if (!stop) + stop = Parser_ChangeStop; + + if (!rate) + rate = Parser_ChangeRate; + + MediaSeekingImpl_Init((IBaseFilter*)pParser, stop, current, rate, &pParser->mediaSeeking, &pParser->csFilter); + pParser->mediaSeeking.lpVtbl = &Parser_Seeking_Vtbl; + + hr = PullPin_Construct(&Parser_InputPin_Vtbl, &piInput, fnProcessSample, (LPVOID)pParser, fnQueryAccept, fnCleanup, fnRequest, fnDone, &pParser->csFilter, (IPin **)&pParser->pInputPin); + + if (SUCCEEDED(hr)) + { + pParser->ppPins[0] = (IPin *)pParser->pInputPin; + pParser->pInputPin->fnPreConnect = fnPreConnect; + } + else + { + CoTaskMemFree(pParser->ppPins); + pParser->csFilter.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&pParser->csFilter); + CoTaskMemFree(pParser); + } + + return hr; +} + +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; + else if (IsEqualIID(riid, &IID_IMediaSeeking)) + *ppv = (LPVOID)&This->mediaSeeking; + + if (*ppv) + { + IUnknown_AddRef((IUnknown *)(*ppv)); + return S_OK; + } + + if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow)) + FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); + + return E_NOINTERFACE; +} + +ULONG WINAPI Parser_AddRef(IBaseFilter * iface) +{ + ParserImpl *This = (ParserImpl *)iface; + ULONG refCount = InterlockedIncrement(&This->refCount); + + TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1); + + return refCount; +} + +void Parser_Destroy(ParserImpl *This) +{ + IPin *connected = NULL; + ULONG pinref; + + assert(!This->refCount); + PullPin_WaitForStateChange(This->pInputPin, INFINITE); + + if (This->pClock) + IReferenceClock_Release(This->pClock); + + /* Don't need to clean up output pins, freeing input pin will do that */ + IPin_ConnectedTo((IPin *)This->pInputPin, &connected); + if (connected) + { + assert(IPin_Disconnect(connected) == S_OK); + IPin_Release(connected); + assert(IPin_Disconnect((IPin *)This->pInputPin) == S_OK); + } + pinref = IPin_Release((IPin *)This->pInputPin); + if (pinref) + { + /* Valgrind could find this, if I kill it here */ + ERR("pinref should be null, is %u, destroying anyway\n", pinref); + assert((LONG)pinref > 0); + + while (pinref) + pinref = IPin_Release((IPin *)This->pInputPin); + } + + CoTaskMemFree(This->ppPins); + This->lpVtbl = NULL; + + This->csFilter.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&This->csFilter); + + TRACE("Destroying parser\n"); + CoTaskMemFree(This); +} + +ULONG WINAPI Parser_Release(IBaseFilter * iface) +{ + ParserImpl *This = (ParserImpl *)iface; + ULONG refCount = InterlockedDecrement(&This->refCount); + + TRACE("(%p)->() Release from %d\n", This, refCount + 1); + + if (!refCount) + Parser_Destroy(This); + + return refCount; +} + +/** IPersist methods **/ + +HRESULT WINAPI Parser_GetClassID(IBaseFilter * iface, CLSID * pClsid) +{ + ParserImpl *This = (ParserImpl *)iface; + + TRACE("(%p)\n", pClsid); + + *pClsid = This->clsid; + + return S_OK; +} + +/** IMediaFilter methods **/ + +HRESULT WINAPI Parser_Stop(IBaseFilter * iface) +{ + ParserImpl *This = (ParserImpl *)iface; + PullPin *pin = (PullPin *)This->ppPins[0]; + int i; + + TRACE("()\n"); + + EnterCriticalSection(&pin->thread_lock); + + IAsyncReader_BeginFlush(This->pInputPin->pReader); + EnterCriticalSection(&This->csFilter); + + if (This->state == State_Stopped) + { + LeaveCriticalSection(&This->csFilter); + LeaveCriticalSection(&pin->thread_lock); + return S_OK; + } + + This->state = State_Stopped; + + for (i = 1; i < (This->cStreams + 1); i++) + { + OutputPin_DecommitAllocator((OutputPin *)This->ppPins[i]); + } + + LeaveCriticalSection(&This->csFilter); + + PullPin_PauseProcessing(This->pInputPin); + PullPin_WaitForStateChange(This->pInputPin, INFINITE); + + LeaveCriticalSection(&pin->thread_lock); + return S_OK; +} + +HRESULT WINAPI Parser_Pause(IBaseFilter * iface) +{ + HRESULT hr = S_OK; + ParserImpl *This = (ParserImpl *)iface; + PullPin *pin = (PullPin *)This->ppPins[0]; + + TRACE("()\n"); + + EnterCriticalSection(&pin->thread_lock); + EnterCriticalSection(&This->csFilter); + + if (This->state == State_Paused) + { + LeaveCriticalSection(&This->csFilter); + LeaveCriticalSection(&pin->thread_lock); + return S_OK; + } + + if (This->state == State_Stopped) + { + LeaveCriticalSection(&This->csFilter); + hr = IBaseFilter_Run(iface, -1); + EnterCriticalSection(&This->csFilter); + } + + if (SUCCEEDED(hr)) + This->state = State_Paused; + + LeaveCriticalSection(&This->csFilter); + LeaveCriticalSection(&pin->thread_lock); + + return hr; +} + +HRESULT WINAPI Parser_Run(IBaseFilter * iface, REFERENCE_TIME tStart) +{ + HRESULT hr = S_OK; + ParserImpl *This = (ParserImpl *)iface; + PullPin *pin = (PullPin *)This->ppPins[0]; + + int i; + + TRACE("(%s)\n", wine_dbgstr_longlong(tStart)); + + EnterCriticalSection(&pin->thread_lock); + EnterCriticalSection(&This->csFilter); + { + HRESULT hr_any = VFW_E_NOT_CONNECTED; + + if (This->state == State_Running || This->state == State_Paused) + { + This->state = State_Running; + LeaveCriticalSection(&This->csFilter); + LeaveCriticalSection(&pin->thread_lock); + return S_OK; + } + + This->rtStreamStart = tStart; + + for (i = 1; i < (This->cStreams + 1); i++) + { + hr = OutputPin_CommitAllocator((OutputPin *)This->ppPins[i]); + if (SUCCEEDED(hr)) + hr_any = hr; + } + + hr = hr_any; + if (SUCCEEDED(hr)) + { + LeaveCriticalSection(&This->csFilter); + hr = PullPin_StartProcessing(This->pInputPin); + EnterCriticalSection(&This->csFilter); + } + + if (SUCCEEDED(hr)) + This->state = State_Running; + } + LeaveCriticalSection(&This->csFilter); + LeaveCriticalSection(&pin->thread_lock); + + return hr; +} + +HRESULT WINAPI Parser_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState) +{ + ParserImpl *This = (ParserImpl *)iface; + PullPin *pin = (PullPin *)This->ppPins[0]; + HRESULT hr = S_OK; + + TRACE("(%d, %p)\n", dwMilliSecsTimeout, pState); + + EnterCriticalSection(&pin->thread_lock); + EnterCriticalSection(&This->csFilter); + { + *pState = This->state; + } + LeaveCriticalSection(&This->csFilter); + + if (This->pInputPin && (PullPin_WaitForStateChange(This->pInputPin, dwMilliSecsTimeout) == S_FALSE)) + hr = VFW_S_STATE_INTERMEDIATE; + LeaveCriticalSection(&pin->thread_lock); + + return hr; +} + +HRESULT WINAPI Parser_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock) +{ + ParserImpl *This = (ParserImpl *)iface; + PullPin *pin = (PullPin *)This->ppPins[0]; + + TRACE("(%p)\n", pClock); + + EnterCriticalSection(&pin->thread_lock); + EnterCriticalSection(&This->csFilter); + { + if (This->pClock) + IReferenceClock_Release(This->pClock); + This->pClock = pClock; + if (This->pClock) + IReferenceClock_AddRef(This->pClock); + } + LeaveCriticalSection(&This->csFilter); + LeaveCriticalSection(&pin->thread_lock); + + return S_OK; +} + +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 **/ + +/* FIXME: WRONG */ +static HRESULT Parser_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick) +{ + ParserImpl *This = (ParserImpl *)iface; + + *lastsynctick = This->lastpinchange; + + TRACE("Asking for pos %x\n", pos); + + /* Input pin also has a pin, hence the > and not >= */ + if (pos > This->cStreams) + return S_FALSE; + + *pin = This->ppPins[pos]; + IPin_AddRef(*pin); + return S_OK; +} + +HRESULT WINAPI Parser_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum) +{ + ParserImpl *This = (ParserImpl *)iface; + + TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum); + + return IEnumPinsImpl_Construct(ppEnum, Parser_GetPin, iface); +} + +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; +} + +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; +} + +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; +} + +HRESULT WINAPI Parser_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo) +{ + TRACE("(%p)\n", pVendorInfo); + return E_NOTIMPL; +} + +HRESULT Parser_AddPin(ParserImpl * This, const PIN_INFO * piOutput, ALLOCATOR_PROPERTIES * props, const AM_MEDIA_TYPE * amt) +{ + IPin ** ppOldPins; + HRESULT hr; + + ppOldPins = This->ppPins; + + This->ppPins = CoTaskMemAlloc((This->cStreams + 2) * sizeof(IPin *)); + memcpy(This->ppPins, ppOldPins, (This->cStreams + 1) * sizeof(IPin *)); + + hr = OutputPin_Construct(&Parser_OutputPin_Vtbl, sizeof(Parser_OutputPin), piOutput, props, NULL, Parser_OutputPin_QueryAccept, &This->csFilter, This->ppPins + (This->cStreams + 1)); + + if (SUCCEEDED(hr)) + { + IPin *pPin = This->ppPins[This->cStreams + 1]; + Parser_OutputPin *pin = (Parser_OutputPin *)pPin; + pin->pmt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); + CopyMediaType(pin->pmt, amt); + pin->dwSamplesProcessed = 0; + + pin->pin.pin.pUserData = (LPVOID)This->ppPins[This->cStreams + 1]; + pin->pin.pin.pinInfo.pFilter = (LPVOID)This; + pin->pin.custom_allocator = 1; + This->cStreams++; + This->lastpinchange = GetTickCount(); + CoTaskMemFree(ppOldPins); + } + else + { + CoTaskMemFree(This->ppPins); + This->ppPins = ppOldPins; + ERR("Failed with error %x\n", hr); + } + + return hr; +} + +static HRESULT Parser_RemoveOutputPins(ParserImpl * This) +{ + /* NOTE: should be in critical section when calling this function */ + HRESULT hr; + ULONG i; + IPin ** ppOldPins = This->ppPins; + + TRACE("(%p)\n", This); + + /* reduce the pin array down to 1 (just our input pin) */ + This->ppPins = CoTaskMemAlloc(sizeof(IPin *) * 1); + memcpy(This->ppPins, ppOldPins, sizeof(IPin *) * 1); + + for (i = 0; i < This->cStreams; i++) + { + hr = OutputPin_DeliverDisconnect((OutputPin *)ppOldPins[i + 1]); + TRACE("Disconnect: %08x\n", hr); + IPin_Release(ppOldPins[i + 1]); + } + + This->lastpinchange = GetTickCount(); + This->cStreams = 0; + CoTaskMemFree(ppOldPins); + + return S_OK; +} + +static HRESULT Parser_ChangeCurrent(IBaseFilter *iface) +{ + FIXME("(%p) filter hasn't implemented current position change!\n", iface); + return S_OK; +} + +static HRESULT Parser_ChangeStop(IBaseFilter *iface) +{ + FIXME("(%p) filter hasn't implemented stop position change!\n", iface); + return S_OK; +} + +static HRESULT Parser_ChangeRate(IBaseFilter *iface) +{ + FIXME("(%p) filter hasn't implemented rate change!\n", iface); + return S_OK; +} + + +static HRESULT WINAPI Parser_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv) +{ + ParserImpl *This = impl_from_IMediaSeeking(iface); + + return IUnknown_QueryInterface((IUnknown *)This, riid, ppv); +} + +static ULONG WINAPI Parser_Seeking_AddRef(IMediaSeeking * iface) +{ + ParserImpl *This = impl_from_IMediaSeeking(iface); + + return IUnknown_AddRef((IUnknown *)This); +} + +static ULONG WINAPI Parser_Seeking_Release(IMediaSeeking * iface) +{ + ParserImpl *This = impl_from_IMediaSeeking(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 +}; + +static 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)) + { + return IBaseFilter_QueryInterface(This->pin.pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv); + } + + if (*ppv) + { + IUnknown_AddRef((IUnknown *)(*ppv)); + return S_OK; + } + + FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); + + return E_NOINTERFACE; +} + +static ULONG WINAPI Parser_OutputPin_Release(IPin * iface) +{ + Parser_OutputPin *This = (Parser_OutputPin *)iface; + ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount); + + TRACE("(%p)->() Release from %d\n", iface, refCount + 1); + + if (!refCount) + { + FreeMediaType(This->pmt); + CoTaskMemFree(This->pmt); + FreeMediaType(&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 WINAPI Parser_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) +{ + Parser_OutputPin *This = (Parser_OutputPin *)iface; + ParserImpl *parser = (ParserImpl *)This->pin.pin.pinInfo.pFilter; + + /* Set the allocator to our input pin's */ + EnterCriticalSection(This->pin.pin.pCritSec); + This->pin.alloc = parser->pInputPin->pAlloc; + LeaveCriticalSection(This->pin.pin.pCritSec); + + return OutputPin_Connect(iface, pReceivePin, pmt); +} + +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, + Parser_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 WINAPI Parser_PullPin_Disconnect(IPin * iface) +{ + HRESULT hr; + PullPin *This = (PullPin *)iface; + + TRACE("()\n"); + + EnterCriticalSection(&This->thread_lock); + EnterCriticalSection(This->pin.pCritSec); + { + if (This->pin.pConnectedTo) + { + FILTER_STATE state; + ParserImpl *Parser = (ParserImpl *)This->pin.pinInfo.pFilter; + + LeaveCriticalSection(This->pin.pCritSec); + hr = IBaseFilter_GetState(This->pin.pinInfo.pFilter, INFINITE, &state); + EnterCriticalSection(This->pin.pCritSec); + + if (SUCCEEDED(hr) && (state == State_Stopped) && SUCCEEDED(Parser->fnDisconnect(Parser))) + { + LeaveCriticalSection(This->pin.pCritSec); + PullPin_Disconnect(iface); + EnterCriticalSection(This->pin.pCritSec); + hr = Parser_RemoveOutputPins((ParserImpl *)This->pin.pinInfo.pFilter); + } + else + hr = VFW_E_NOT_STOPPED; + } + else + hr = S_FALSE; + } + LeaveCriticalSection(This->pin.pCritSec); + LeaveCriticalSection(&This->thread_lock); + + return hr; +} + +HRESULT WINAPI Parser_PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) +{ + HRESULT hr; + + TRACE("()\n"); + + hr = PullPin_ReceiveConnection(iface, pReceivePin, pmt); + if (FAILED(hr)) + { + IPinImpl *This = (IPinImpl *)iface; + + EnterCriticalSection(This->pCritSec); + Parser_RemoveOutputPins((ParserImpl *)This->pinInfo.pFilter); + LeaveCriticalSection(This->pCritSec); + } + + return hr; +} + +static const IPinVtbl Parser_InputPin_Vtbl = +{ + PullPin_QueryInterface, + IPinImpl_AddRef, + PullPin_Release, + InputPin_Connect, + Parser_PullPin_ReceiveConnection, + Parser_PullPin_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/strmbase/pin.c b/dlls/strmbase/pin.c new file mode 100644 index 0000000..1a3aba1 --- /dev/null +++ b/dlls/strmbase/pin.c @@ -0,0 +1,1861 @@ +/* + * Generic Implementation of IPin Interface + * + * Copyright 2003 Robert Shearman + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "strmbase_private.h" +#include "wine/debug.h" +#include + +WINE_DEFAULT_DEBUG_CHANNEL(strmbase); + +static const IPinVtbl InputPin_Vtbl; +static const IPinVtbl OutputPin_Vtbl; +static const IMemInputPinVtbl MemInputPin_Vtbl; +static const IPinVtbl PullPin_Vtbl; + +#define ALIGNDOWN(value,boundary) ((value)/(boundary)*(boundary)) +#define ALIGNUP(value,boundary) (ALIGNDOWN((value)+(boundary)-1, (boundary))) + +typedef HRESULT (*SendPinFunc)( IPin *to, LPVOID arg ); + +/** Helper function, there are a lot of places where the error code is inherited + * The following rules apply: + * + * Return the first received error code (E_NOTIMPL is ignored) + * If no errors occur: return the first received non-error-code that isn't S_OK + */ +HRESULT updatehres( HRESULT original, HRESULT new ) +{ + if (FAILED( original ) || new == E_NOTIMPL) + return original; + + if (FAILED( new ) || original == S_OK) + return new; + + return original; +} + +/** Sends a message from a pin further to other, similar pins + * fnMiddle is called on each pin found further on the stream. + * fnEnd (can be NULL) is called when the message can't be sent any further (this is a renderer or source) + * + * If the pin given is an input pin, the message will be sent downstream to other input pins + * If the pin given is an output pin, the message will be sent upstream to other output pins + */ +static HRESULT SendFurther( IPin *from, SendPinFunc fnMiddle, LPVOID arg, SendPinFunc fnEnd ) +{ + PIN_INFO pin_info; + ULONG amount = 0; + HRESULT hr = S_OK; + HRESULT hr_return = S_OK; + IEnumPins *enumpins = NULL; + BOOL foundend = TRUE; + PIN_DIRECTION from_dir; + + IPin_QueryDirection( from, &from_dir ); + + hr = IPin_QueryInternalConnections( from, NULL, &amount ); + if (hr != E_NOTIMPL && amount) + FIXME("Use QueryInternalConnections!\n"); + hr = S_OK; + + pin_info.pFilter = NULL; + hr = IPin_QueryPinInfo( from, &pin_info ); + if (FAILED(hr)) + goto out; + + hr = IBaseFilter_EnumPins( pin_info.pFilter, &enumpins ); + if (FAILED(hr)) + goto out; + + hr = IEnumPins_Reset( enumpins ); + while (hr == S_OK) { + IPin *pin = NULL; + hr = IEnumPins_Next( enumpins, 1, &pin, NULL ); + if (hr == VFW_E_ENUM_OUT_OF_SYNC) + { + hr = IEnumPins_Reset( enumpins ); + continue; + } + if (pin) + { + PIN_DIRECTION dir; + + IPin_QueryDirection( pin, &dir ); + if (dir != from_dir) + { + IPin *connected = NULL; + + foundend = FALSE; + IPin_ConnectedTo( pin, &connected ); + if (connected) + { + HRESULT hr_local; + + hr_local = fnMiddle( connected, arg ); + hr_return = updatehres( hr_return, hr_local ); + IPin_Release(connected); + } + } + IPin_Release( pin ); + } + else + { + hr = S_OK; + break; + } + } + + if (!foundend) + hr = hr_return; + else if (fnEnd) { + HRESULT hr_local; + + hr_local = fnEnd( from, arg ); + hr_return = updatehres( hr_return, hr_local ); + } + +out: + if (pin_info.pFilter) + IBaseFilter_Release( pin_info.pFilter ); + return hr; +} + +static inline InputPin *impl_from_IMemInputPin( IMemInputPin *iface ) +{ + return (InputPin *)((char*)iface - FIELD_OFFSET(InputPin, lpVtblMemInput)); +} + + +static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc) +{ + /* Tempting to just do a memcpy, but the name field is + 128 characters long! We will probably never exceed 10 + most of the time, so we are better off copying + each field manually */ + lstrcpyW(pDest->achName, pSrc->achName); + pDest->dir = pSrc->dir; + pDest->pFilter = pSrc->pFilter; +} + +/* Function called as a helper to IPin_Connect */ +/* specific AM_MEDIA_TYPE - it cannot be NULL */ +/* NOTE: not part of standard interface */ +static HRESULT OutputPin_ConnectSpecific(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) +{ + OutputPin *This = (OutputPin *)iface; + HRESULT hr; + IMemAllocator * pMemAlloc = NULL; + ALLOCATOR_PROPERTIES actual; /* FIXME: should we put the actual props back in to This? */ + + TRACE("(%p, %p)\n", pReceivePin, pmt); + dump_AM_MEDIA_TYPE(pmt); + + /* FIXME: call queryacceptproc */ + + This->pin.pConnectedTo = pReceivePin; + IPin_AddRef(pReceivePin); + CopyMediaType(&This->pin.mtCurrent, pmt); + + hr = IPin_ReceiveConnection(pReceivePin, iface, pmt); + + /* get the IMemInputPin interface we will use to deliver samples to the + * connected pin */ + if (SUCCEEDED(hr)) + { + This->pMemInputPin = NULL; + hr = IPin_QueryInterface(pReceivePin, &IID_IMemInputPin, (LPVOID)&This->pMemInputPin); + + if (SUCCEEDED(hr) && !This->custom_allocator) + { + hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pMemAlloc); + + if (hr == VFW_E_NO_ALLOCATOR) + /* Input pin provides no allocator, use standard memory allocator */ + hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (LPVOID*)&pMemAlloc); + + if (SUCCEEDED(hr)) + hr = IMemAllocator_SetProperties(pMemAlloc, &This->allocProps, &actual); + + if (SUCCEEDED(hr)) + hr = IMemInputPin_NotifyAllocator(This->pMemInputPin, pMemAlloc, This->readonly); + + if (pMemAlloc) + IMemAllocator_Release(pMemAlloc); + } + else if (SUCCEEDED(hr)) + { + if (This->alloc) + { + hr = IMemInputPin_NotifyAllocator(This->pMemInputPin, This->alloc, This->readonly); + } + else + hr = VFW_E_NO_ALLOCATOR; + } + + /* break connection if we couldn't get the allocator */ + if (FAILED(hr)) + { + if (This->pMemInputPin) + IMemInputPin_Release(This->pMemInputPin); + This->pMemInputPin = NULL; + + IPin_Disconnect(pReceivePin); + } + } + + if (FAILED(hr)) + { + IPin_Release(This->pin.pConnectedTo); + This->pin.pConnectedTo = NULL; + FreeMediaType(&This->pin.mtCurrent); + } + + TRACE(" -- %x\n", hr); + return hr; +} + +static HRESULT InputPin_Init(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PUSH pSampleProc, LPVOID pUserData, + QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, LPCRITICAL_SECTION pCritSec, IMemAllocator *allocator, InputPin * pPinImpl) +{ + TRACE("\n"); + + /* Common attributes */ + pPinImpl->pin.refCount = 1; + pPinImpl->pin.pConnectedTo = NULL; + pPinImpl->pin.fnQueryAccept = pQueryAccept; + pPinImpl->pin.pUserData = pUserData; + pPinImpl->pin.pCritSec = pCritSec; + Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo); + ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE)); + + /* Input pin attributes */ + pPinImpl->fnSampleProc = pSampleProc; + pPinImpl->fnCleanProc = pCleanUp; + pPinImpl->pAllocator = pPinImpl->preferred_allocator = allocator; + if (pPinImpl->preferred_allocator) + IMemAllocator_AddRef(pPinImpl->preferred_allocator); + pPinImpl->tStart = 0; + pPinImpl->tStop = 0; + pPinImpl->dRate = 1.0; + pPinImpl->pin.lpVtbl = InputPin_Vtbl; + pPinImpl->lpVtblMemInput = &MemInputPin_Vtbl; + pPinImpl->flushing = pPinImpl->end_of_stream = 0; + + return S_OK; +} + +static HRESULT OutputPin_Init(const IPinVtbl *OutputPin_Vtbl, const PIN_INFO * pPinInfo, const ALLOCATOR_PROPERTIES * props, LPVOID pUserData, + QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, OutputPin * pPinImpl) +{ + TRACE("\n"); + + /* Common attributes */ + pPinImpl->pin.lpVtbl = OutputPin_Vtbl; + pPinImpl->pin.refCount = 1; + pPinImpl->pin.pConnectedTo = NULL; + pPinImpl->pin.fnQueryAccept = pQueryAccept; + pPinImpl->pin.pUserData = pUserData; + pPinImpl->pin.pCritSec = pCritSec; + Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo); + ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE)); + + /* Output pin attributes */ + pPinImpl->pMemInputPin = NULL; + pPinImpl->pConnectSpecific = OutputPin_ConnectSpecific; + /* If custom_allocator is set, you will need to specify an allocator + * in the alloc member of the struct before an output pin can connect + */ + pPinImpl->custom_allocator = 0; + pPinImpl->alloc = NULL; + pPinImpl->readonly = FALSE; + if (props) + { + pPinImpl->allocProps = *props; + if (pPinImpl->allocProps.cbAlign == 0) + pPinImpl->allocProps.cbAlign = 1; + } + else + ZeroMemory(&pPinImpl->allocProps, sizeof(pPinImpl->allocProps)); + + return S_OK; +} + +HRESULT InputPin_Construct(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PUSH pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, LPCRITICAL_SECTION pCritSec, IMemAllocator *allocator, IPin ** ppPin) +{ + InputPin * pPinImpl; + + *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(InputPin_Init(InputPin_Vtbl, pPinInfo, pSampleProc, pUserData, pQueryAccept, pCleanUp, pCritSec, allocator, pPinImpl))) + { + *ppPin = (IPin *)pPinImpl; + return S_OK; + } + + CoTaskMemFree(pPinImpl); + return E_FAIL; +} + +HRESULT OutputPin_Construct(const IPinVtbl *OutputPin_Vtbl, long outputpin_size, const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin) +{ + OutputPin * pPinImpl; + + *ppPin = NULL; + + if (pPinInfo->dir != PINDIR_OUTPUT) + { + ERR("Pin direction(%x) != PINDIR_OUTPUT\n", pPinInfo->dir); + return E_INVALIDARG; + } + + assert(outputpin_size >= sizeof(OutputPin)); + + pPinImpl = CoTaskMemAlloc(outputpin_size); + + if (!pPinImpl) + return E_OUTOFMEMORY; + + if (SUCCEEDED(OutputPin_Init(OutputPin_Vtbl, pPinInfo, props, pUserData, pQueryAccept, pCritSec, pPinImpl))) + { + *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl); + return S_OK; + } + + CoTaskMemFree(pPinImpl); + return E_FAIL; +} + +/*** Common pin functions ***/ + +ULONG WINAPI IPinImpl_AddRef(IPin * iface) +{ + IPinImpl *This = (IPinImpl *)iface; + ULONG refCount = InterlockedIncrement(&This->refCount); + + TRACE("(%p)->() AddRef from %d\n", iface, refCount - 1); + + return refCount; +} + +HRESULT WINAPI IPinImpl_Disconnect(IPin * iface) +{ + HRESULT hr; + IPinImpl *This = (IPinImpl *)iface; + + TRACE("()\n"); + + EnterCriticalSection(This->pCritSec); + { + if (This->pConnectedTo) + { + IPin_Release(This->pConnectedTo); + This->pConnectedTo = NULL; + FreeMediaType(&This->mtCurrent); + ZeroMemory(&This->mtCurrent, sizeof(This->mtCurrent)); + hr = S_OK; + } + else + hr = S_FALSE; + } + LeaveCriticalSection(This->pCritSec); + + return hr; +} + +HRESULT WINAPI IPinImpl_ConnectedTo(IPin * iface, IPin ** ppPin) +{ + HRESULT hr; + IPinImpl *This = (IPinImpl *)iface; + + TRACE("(%p)\n", ppPin); + + EnterCriticalSection(This->pCritSec); + { + if (This->pConnectedTo) + { + *ppPin = This->pConnectedTo; + IPin_AddRef(*ppPin); + hr = S_OK; + } + else + { + hr = VFW_E_NOT_CONNECTED; + *ppPin = NULL; + } + } + LeaveCriticalSection(This->pCritSec); + + return hr; +} + +HRESULT WINAPI IPinImpl_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt) +{ + HRESULT hr; + IPinImpl *This = (IPinImpl *)iface; + + TRACE("(%p/%p)->(%p)\n", This, iface, pmt); + + EnterCriticalSection(This->pCritSec); + { + if (This->pConnectedTo) + { + CopyMediaType(pmt, &This->mtCurrent); + hr = S_OK; + } + else + { + ZeroMemory(pmt, sizeof(*pmt)); + hr = VFW_E_NOT_CONNECTED; + } + } + LeaveCriticalSection(This->pCritSec); + + return hr; +} + +HRESULT WINAPI IPinImpl_QueryPinInfo(IPin * iface, PIN_INFO * pInfo) +{ + IPinImpl *This = (IPinImpl *)iface; + + TRACE("(%p/%p)->(%p)\n", This, iface, pInfo); + + Copy_PinInfo(pInfo, &This->pinInfo); + IBaseFilter_AddRef(pInfo->pFilter); + + return S_OK; +} + +HRESULT WINAPI IPinImpl_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir) +{ + IPinImpl *This = (IPinImpl *)iface; + + TRACE("(%p/%p)->(%p)\n", This, iface, pPinDir); + + *pPinDir = This->pinInfo.dir; + + return S_OK; +} + +HRESULT WINAPI IPinImpl_QueryId(IPin * iface, LPWSTR * Id) +{ + IPinImpl *This = (IPinImpl *)iface; + + TRACE("(%p/%p)->(%p)\n", This, iface, Id); + + *Id = CoTaskMemAlloc((lstrlenW(This->pinInfo.achName) + 1) * sizeof(WCHAR)); + if (!*Id) + return E_OUTOFMEMORY; + + lstrcpyW(*Id, This->pinInfo.achName); + + return S_OK; +} + +HRESULT WINAPI IPinImpl_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt) +{ + IPinImpl *This = (IPinImpl *)iface; + + TRACE("(%p/%p)->(%p)\n", This, iface, pmt); + + return (This->fnQueryAccept(This->pUserData, pmt) == S_OK ? S_OK : S_FALSE); +} + +HRESULT WINAPI IPinImpl_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum) +{ + IPinImpl *This = (IPinImpl *)iface; + ENUMMEDIADETAILS emd; + + TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum); + + /* override this method to allow enumeration of your types */ + emd.cMediaTypes = 0; + emd.pMediaTypes = NULL; + + return IEnumMediaTypesImpl_Construct(&emd, ppEnum); +} + +HRESULT WINAPI IPinImpl_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin) +{ + IPinImpl *This = (IPinImpl *)iface; + + TRACE("(%p/%p)->(%p, %p)\n", This, iface, apPin, cPin); + + return E_NOTIMPL; /* to tell caller that all input pins connected to all output pins */ +} + +/*** IPin implementation for an input pin ***/ + +HRESULT WINAPI InputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) +{ + InputPin *This = (InputPin *)iface; + + TRACE("(%p)->(%s, %p)\n", iface, 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_IMemInputPin)) + *ppv = (LPVOID)&This->lpVtblMemInput; + else if (IsEqualIID(riid, &IID_IMediaSeeking)) + { + return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv); + } + + if (*ppv) + { + IUnknown_AddRef((IUnknown *)(*ppv)); + return S_OK; + } + + FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); + + return E_NOINTERFACE; +} + +ULONG WINAPI InputPin_Release(IPin * iface) +{ + InputPin *This = (InputPin *)iface; + ULONG refCount = InterlockedDecrement(&This->pin.refCount); + + TRACE("(%p)->() Release from %d\n", iface, refCount + 1); + + if (!refCount) + { + FreeMediaType(&This->pin.mtCurrent); + if (This->pAllocator) + IMemAllocator_Release(This->pAllocator); + This->pAllocator = NULL; + This->pin.lpVtbl = NULL; + CoTaskMemFree(This); + return 0; + } + else + return refCount; +} + +HRESULT WINAPI InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt) +{ + ERR("Outgoing connection on an input pin! (%p, %p)\n", pConnector, pmt); + + return E_UNEXPECTED; +} + + +HRESULT WINAPI InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) +{ + InputPin *This = (InputPin *)iface; + PIN_DIRECTION pindirReceive; + HRESULT hr = S_OK; + + TRACE("(%p, %p)\n", pReceivePin, pmt); + dump_AM_MEDIA_TYPE(pmt); + + EnterCriticalSection(This->pin.pCritSec); + { + if (This->pin.pConnectedTo) + hr = VFW_E_ALREADY_CONNECTED; + + if (SUCCEEDED(hr) && This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK) + hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto + * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */ + + if (SUCCEEDED(hr)) + { + IPin_QueryDirection(pReceivePin, &pindirReceive); + + if (pindirReceive != PINDIR_OUTPUT) + { + ERR("Can't connect from non-output pin\n"); + hr = VFW_E_INVALID_DIRECTION; + } + } + + if (SUCCEEDED(hr)) + { + CopyMediaType(&This->pin.mtCurrent, pmt); + This->pin.pConnectedTo = pReceivePin; + IPin_AddRef(pReceivePin); + } + } + LeaveCriticalSection(This->pin.pCritSec); + + return hr; +} + +static HRESULT deliver_endofstream(IPin* pin, LPVOID unused) +{ + return IPin_EndOfStream( pin ); +} + +HRESULT WINAPI InputPin_EndOfStream(IPin * iface) +{ + HRESULT hr = S_OK; + InputPin *This = (InputPin *)iface; + + TRACE("(%p)\n", This); + + EnterCriticalSection(This->pin.pCritSec); + if (This->flushing) + hr = S_FALSE; + else + This->end_of_stream = 1; + LeaveCriticalSection(This->pin.pCritSec); + + if (hr == S_OK) + hr = SendFurther( iface, deliver_endofstream, NULL, NULL ); + return hr; +} + +static HRESULT deliver_beginflush(IPin* pin, LPVOID unused) +{ + return IPin_BeginFlush( pin ); +} + +HRESULT WINAPI InputPin_BeginFlush(IPin * iface) +{ + InputPin *This = (InputPin *)iface; + HRESULT hr; + TRACE("() semi-stub\n"); + + EnterCriticalSection(This->pin.pCritSec); + This->flushing = 1; + + if (This->fnCleanProc) + This->fnCleanProc(This->pin.pUserData); + + hr = SendFurther( iface, deliver_beginflush, NULL, NULL ); + LeaveCriticalSection(This->pin.pCritSec); + + return hr; +} + +static HRESULT deliver_endflush(IPin* pin, LPVOID unused) +{ + return IPin_EndFlush( pin ); +} + +HRESULT WINAPI InputPin_EndFlush(IPin * iface) +{ + InputPin *This = (InputPin *)iface; + HRESULT hr; + TRACE("(%p)\n", This); + + EnterCriticalSection(This->pin.pCritSec); + This->flushing = This->end_of_stream = 0; + + hr = SendFurther( iface, deliver_endflush, NULL, NULL ); + LeaveCriticalSection(This->pin.pCritSec); + + return hr; +} + +typedef struct newsegmentargs +{ + REFERENCE_TIME tStart, tStop; + double rate; +} newsegmentargs; + +static HRESULT deliver_newsegment(IPin *pin, LPVOID data) +{ + newsegmentargs *args = data; + return IPin_NewSegment(pin, args->tStart, args->tStop, args->rate); +} + +HRESULT WINAPI InputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + InputPin *This = (InputPin *)iface; + newsegmentargs args; + + TRACE("(%x%08x, %x%08x, %e)\n", (ULONG)(tStart >> 32), (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)tStop, dRate); + + args.tStart = This->tStart = tStart; + args.tStop = This->tStop = tStop; + args.rate = This->dRate = dRate; + + return SendFurther( iface, deliver_newsegment, &args, NULL ); +} + +static const IPinVtbl InputPin_Vtbl = +{ + InputPin_QueryInterface, + IPinImpl_AddRef, + InputPin_Release, + InputPin_Connect, + InputPin_ReceiveConnection, + IPinImpl_Disconnect, + IPinImpl_ConnectedTo, + IPinImpl_ConnectionMediaType, + IPinImpl_QueryPinInfo, + IPinImpl_QueryDirection, + IPinImpl_QueryId, + IPinImpl_QueryAccept, + IPinImpl_EnumMediaTypes, + IPinImpl_QueryInternalConnections, + InputPin_EndOfStream, + InputPin_BeginFlush, + InputPin_EndFlush, + InputPin_NewSegment +}; + +/*** IMemInputPin implementation ***/ + +HRESULT WINAPI MemInputPin_QueryInterface(IMemInputPin * iface, REFIID riid, LPVOID * ppv) +{ + InputPin *This = impl_from_IMemInputPin(iface); + + return IPin_QueryInterface((IPin *)&This->pin, riid, ppv); +} + +ULONG WINAPI MemInputPin_AddRef(IMemInputPin * iface) +{ + InputPin *This = impl_from_IMemInputPin(iface); + + return IPin_AddRef((IPin *)&This->pin); +} + +ULONG WINAPI MemInputPin_Release(IMemInputPin * iface) +{ + InputPin *This = impl_from_IMemInputPin(iface); + + return IPin_Release((IPin *)&This->pin); +} + +HRESULT WINAPI MemInputPin_GetAllocator(IMemInputPin * iface, IMemAllocator ** ppAllocator) +{ + InputPin *This = impl_from_IMemInputPin(iface); + + TRACE("(%p/%p)->(%p)\n", This, iface, ppAllocator); + + *ppAllocator = This->pAllocator; + if (*ppAllocator) + IMemAllocator_AddRef(*ppAllocator); + + return *ppAllocator ? S_OK : VFW_E_NO_ALLOCATOR; +} + +HRESULT WINAPI MemInputPin_NotifyAllocator(IMemInputPin * iface, IMemAllocator * pAllocator, BOOL bReadOnly) +{ + InputPin *This = impl_from_IMemInputPin(iface); + + TRACE("(%p/%p)->(%p, %d)\n", This, iface, pAllocator, bReadOnly); + + if (bReadOnly) + FIXME("Read only flag not handled yet!\n"); + + /* FIXME: Should we release the allocator on disconnection? */ + if (!pAllocator) + { + WARN("Null allocator\n"); + return E_POINTER; + } + + if (This->preferred_allocator && pAllocator != This->preferred_allocator) + return E_FAIL; + + if (This->pAllocator) + IMemAllocator_Release(This->pAllocator); + This->pAllocator = pAllocator; + if (This->pAllocator) + IMemAllocator_AddRef(This->pAllocator); + + return S_OK; +} + +HRESULT WINAPI MemInputPin_GetAllocatorRequirements(IMemInputPin * iface, ALLOCATOR_PROPERTIES * pProps) +{ + InputPin *This = impl_from_IMemInputPin(iface); + + TRACE("(%p/%p)->(%p)\n", This, iface, pProps); + + /* override this method if you have any specific requirements */ + + return E_NOTIMPL; +} + +HRESULT WINAPI MemInputPin_Receive(IMemInputPin * iface, IMediaSample * pSample) +{ + InputPin *This = impl_from_IMemInputPin(iface); + HRESULT hr; + + /* this trace commented out for performance reasons */ + /*TRACE("(%p/%p)->(%p)\n", This, iface, pSample);*/ + hr = This->fnSampleProc(This->pin.pUserData, pSample); + return hr; +} + +HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin * iface, IMediaSample ** pSamples, long nSamples, long *nSamplesProcessed) +{ + HRESULT hr = S_OK; + InputPin *This = impl_from_IMemInputPin(iface); + + TRACE("(%p/%p)->(%p, %ld, %p)\n", This, iface, pSamples, nSamples, nSamplesProcessed); + + for (*nSamplesProcessed = 0; *nSamplesProcessed < nSamples; (*nSamplesProcessed)++) + { + hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]); + if (hr != S_OK) + break; + } + + return hr; +} + +HRESULT WINAPI MemInputPin_ReceiveCanBlock(IMemInputPin * iface) +{ + InputPin *This = impl_from_IMemInputPin(iface); + + TRACE("(%p/%p)->()\n", This, iface); + + return S_OK; +} + +static const IMemInputPinVtbl MemInputPin_Vtbl = +{ + MemInputPin_QueryInterface, + MemInputPin_AddRef, + MemInputPin_Release, + MemInputPin_GetAllocator, + MemInputPin_NotifyAllocator, + MemInputPin_GetAllocatorRequirements, + MemInputPin_Receive, + MemInputPin_ReceiveMultiple, + MemInputPin_ReceiveCanBlock +}; + +HRESULT WINAPI OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) +{ + OutputPin *This = (OutputPin *)iface; + + TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv); + + *ppv = NULL; + + if (IsEqualIID(riid, &IID_IUnknown)) + *ppv = (LPVOID)iface; + else if (IsEqualIID(riid, &IID_IPin)) + *ppv = (LPVOID)iface; + else if (IsEqualIID(riid, &IID_IMediaSeeking)) + { + return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv); + } + + if (*ppv) + { + IUnknown_AddRef((IUnknown *)(*ppv)); + return S_OK; + } + + FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); + + return E_NOINTERFACE; +} + +ULONG WINAPI OutputPin_Release(IPin * iface) +{ + OutputPin *This = (OutputPin *)iface; + ULONG refCount = InterlockedDecrement(&This->pin.refCount); + + TRACE("(%p)->() Release from %d\n", iface, refCount + 1); + + if (!refCount) + { + FreeMediaType(&This->pin.mtCurrent); + CoTaskMemFree(This); + return 0; + } + return refCount; +} + +HRESULT WINAPI OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) +{ + HRESULT hr; + OutputPin *This = (OutputPin *)iface; + + TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt); + dump_AM_MEDIA_TYPE(pmt); + + /* If we try to connect to ourself, we will definitely deadlock. + * There are other cases where we could deadlock too, but this + * catches the obvious case */ + assert(pReceivePin != iface); + + EnterCriticalSection(This->pin.pCritSec); + { + /* if we have been a specific type to connect with, then we can either connect + * with that or fail. We cannot choose different AM_MEDIA_TYPE */ + if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL)) + hr = This->pConnectSpecific(iface, pReceivePin, pmt); + else + { + /* negotiate media type */ + + IEnumMediaTypes * pEnumCandidates; + AM_MEDIA_TYPE * pmtCandidate = NULL; /* Candidate media type */ + + if (SUCCEEDED(hr = IPin_EnumMediaTypes(iface, &pEnumCandidates))) + { + hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */ + + /* try this filter's media types first */ + while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL)) + { + assert(pmtCandidate); + dump_AM_MEDIA_TYPE(pmtCandidate); + if (!IsEqualGUID(&FORMAT_None, &pmtCandidate->formattype) + && !IsEqualGUID(&GUID_NULL, &pmtCandidate->formattype)) + assert(pmtCandidate->pbFormat); + if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && + (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK)) + { + hr = S_OK; + DeleteMediaType(pmtCandidate); + break; + } + DeleteMediaType(pmtCandidate); + pmtCandidate = NULL; + } + IEnumMediaTypes_Release(pEnumCandidates); + } + + /* then try receiver filter's media types */ + if (hr != S_OK && SUCCEEDED(hr = IPin_EnumMediaTypes(pReceivePin, &pEnumCandidates))) /* if we haven't already connected successfully */ + { + hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */ + + while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL)) + { + assert(pmtCandidate); + dump_AM_MEDIA_TYPE(pmtCandidate); + if (!IsEqualGUID(&FORMAT_None, &pmtCandidate->formattype) + && !IsEqualGUID(&GUID_NULL, &pmtCandidate->formattype)) + assert(pmtCandidate->pbFormat); + if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) && + (This->pConnectSpecific(iface, pReceivePin, pmtCandidate) == S_OK)) + { + hr = S_OK; + DeleteMediaType(pmtCandidate); + break; + } + DeleteMediaType(pmtCandidate); + pmtCandidate = NULL; + } /* while */ + IEnumMediaTypes_Release(pEnumCandidates); + } /* if not found */ + } /* if negotiate media type */ + } /* if succeeded */ + LeaveCriticalSection(This->pin.pCritSec); + + TRACE(" -- %x\n", hr); + return hr; +} + +HRESULT WINAPI OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) +{ + ERR("Incoming connection on an output pin! (%p, %p)\n", pReceivePin, pmt); + + return E_UNEXPECTED; +} + +HRESULT WINAPI OutputPin_Disconnect(IPin * iface) +{ + HRESULT hr; + OutputPin *This = (OutputPin *)iface; + + TRACE("()\n"); + + EnterCriticalSection(This->pin.pCritSec); + { + if (This->pMemInputPin) + { + IMemInputPin_Release(This->pMemInputPin); + This->pMemInputPin = NULL; + } + if (This->pin.pConnectedTo) + { + IPin_Release(This->pin.pConnectedTo); + This->pin.pConnectedTo = NULL; + FreeMediaType(&This->pin.mtCurrent); + ZeroMemory(&This->pin.mtCurrent, sizeof(This->pin.mtCurrent)); + hr = S_OK; + } + else + hr = S_FALSE; + } + LeaveCriticalSection(This->pin.pCritSec); + + return hr; +} + +HRESULT WINAPI OutputPin_EndOfStream(IPin * iface) +{ + TRACE("()\n"); + + /* not supposed to do anything in an output pin */ + + return E_UNEXPECTED; +} + +HRESULT WINAPI OutputPin_BeginFlush(IPin * iface) +{ + TRACE("(%p)->()\n", iface); + + /* not supposed to do anything in an output pin */ + + return E_UNEXPECTED; +} + +HRESULT WINAPI OutputPin_EndFlush(IPin * iface) +{ + TRACE("(%p)->()\n", iface); + + /* not supposed to do anything in an output pin */ + + return E_UNEXPECTED; +} + +HRESULT WINAPI OutputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + TRACE("(%p)->(%x%08x, %x%08x, %e)\n", iface, (ULONG)(tStart >> 32), (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)tStop, dRate); + + /* not supposed to do anything in an output pin */ + + return E_UNEXPECTED; +} + +static const IPinVtbl OutputPin_Vtbl = +{ + OutputPin_QueryInterface, + IPinImpl_AddRef, + OutputPin_Release, + OutputPin_Connect, + OutputPin_ReceiveConnection, + OutputPin_Disconnect, + IPinImpl_ConnectedTo, + IPinImpl_ConnectionMediaType, + IPinImpl_QueryPinInfo, + IPinImpl_QueryDirection, + IPinImpl_QueryId, + IPinImpl_QueryAccept, + IPinImpl_EnumMediaTypes, + IPinImpl_QueryInternalConnections, + OutputPin_EndOfStream, + OutputPin_BeginFlush, + OutputPin_EndFlush, + OutputPin_NewSegment +}; + +HRESULT OutputPin_GetDeliveryBuffer(OutputPin * This, IMediaSample ** ppSample, REFERENCE_TIME * tStart, REFERENCE_TIME * tStop, DWORD dwFlags) +{ + HRESULT hr; + + TRACE("(%p, %p, %p, %x)\n", ppSample, tStart, tStop, dwFlags); + + EnterCriticalSection(This->pin.pCritSec); + { + if (!This->pin.pConnectedTo) + hr = VFW_E_NOT_CONNECTED; + else + { + IMemAllocator * pAlloc = NULL; + + hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc); + + if (SUCCEEDED(hr)) + hr = IMemAllocator_GetBuffer(pAlloc, ppSample, tStart, tStop, dwFlags); + + if (SUCCEEDED(hr)) + hr = IMediaSample_SetTime(*ppSample, tStart, tStop); + + if (pAlloc) + IMemAllocator_Release(pAlloc); + } + } + LeaveCriticalSection(This->pin.pCritSec); + + return hr; +} + +HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample) +{ + HRESULT hr = S_OK; + IMemInputPin * pMemConnected = NULL; + PIN_INFO pinInfo; + + EnterCriticalSection(This->pin.pCritSec); + { + if (!This->pin.pConnectedTo || !This->pMemInputPin) + hr = VFW_E_NOT_CONNECTED; + else + { + /* we don't have the lock held when using This->pMemInputPin, + * so we need to AddRef it to stop it being deleted while we are + * using it. Same with its filter. */ + pMemConnected = This->pMemInputPin; + IMemInputPin_AddRef(pMemConnected); + hr = IPin_QueryPinInfo(This->pin.pConnectedTo, &pinInfo); + } + } + LeaveCriticalSection(This->pin.pCritSec); + + if (SUCCEEDED(hr)) + { + /* NOTE: if we are in a critical section when Receive is called + * then it causes some problems (most notably with the native Video + * Renderer) if we are re-entered for whatever reason */ + hr = IMemInputPin_Receive(pMemConnected, pSample); + + /* If the filter's destroyed, tell upstream to stop sending data */ + if(IBaseFilter_Release(pinInfo.pFilter) == 0 && SUCCEEDED(hr)) + hr = S_FALSE; + } + if (pMemConnected) + IMemInputPin_Release(pMemConnected); + + return hr; +} + +HRESULT OutputPin_DeliverNewSegment(OutputPin * This, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + HRESULT hr; + + EnterCriticalSection(This->pin.pCritSec); + { + if (!This->pin.pConnectedTo) + hr = VFW_E_NOT_CONNECTED; + else + hr = IPin_NewSegment(This->pin.pConnectedTo, tStart, tStop, dRate); + } + LeaveCriticalSection(This->pin.pCritSec); + + return hr; +} + +HRESULT OutputPin_CommitAllocator(OutputPin * This) +{ + HRESULT hr = S_OK; + + TRACE("(%p)->()\n", This); + + EnterCriticalSection(This->pin.pCritSec); + { + if (!This->pin.pConnectedTo || !This->pMemInputPin) + hr = VFW_E_NOT_CONNECTED; + else + { + IMemAllocator * pAlloc = NULL; + + hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc); + + if (SUCCEEDED(hr)) + hr = IMemAllocator_Commit(pAlloc); + + if (pAlloc) + IMemAllocator_Release(pAlloc); + } + } + LeaveCriticalSection(This->pin.pCritSec); + + TRACE("--> %08x\n", hr); + return hr; +} + +HRESULT OutputPin_DecommitAllocator(OutputPin * This) +{ + HRESULT hr = S_OK; + + TRACE("(%p)->()\n", This); + + EnterCriticalSection(This->pin.pCritSec); + { + if (!This->pin.pConnectedTo || !This->pMemInputPin) + hr = VFW_E_NOT_CONNECTED; + else + { + IMemAllocator * pAlloc = NULL; + + hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc); + + if (SUCCEEDED(hr)) + hr = IMemAllocator_Decommit(pAlloc); + + if (pAlloc) + IMemAllocator_Release(pAlloc); + } + } + LeaveCriticalSection(This->pin.pCritSec); + + TRACE("--> %08x\n", hr); + return hr; +} + +HRESULT OutputPin_DeliverDisconnect(OutputPin * This) +{ + HRESULT hr; + + TRACE("(%p)->()\n", This); + + EnterCriticalSection(This->pin.pCritSec); + { + if (!This->pin.pConnectedTo || !This->pMemInputPin) + hr = VFW_E_NOT_CONNECTED; + else if (!This->custom_allocator) + { + IMemAllocator * pAlloc = NULL; + + hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc); + + if (SUCCEEDED(hr)) + hr = IMemAllocator_Decommit(pAlloc); + + if (pAlloc) + IMemAllocator_Release(pAlloc); + + if (SUCCEEDED(hr)) + hr = IPin_Disconnect(This->pin.pConnectedTo); + } + else /* Kill the allocator! */ + { + hr = IPin_Disconnect(This->pin.pConnectedTo); + } + IPin_Disconnect((IPin *)This); + } + LeaveCriticalSection(This->pin.pCritSec); + + return hr; +} + + +static HRESULT PullPin_Init(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PULL pSampleProc, LPVOID pUserData, + QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, REQUESTPROC pCustomRequest, STOPPROCESSPROC pDone, LPCRITICAL_SECTION pCritSec, PullPin * pPinImpl) +{ + /* Common attributes */ + pPinImpl->pin.lpVtbl = PullPin_Vtbl; + pPinImpl->pin.refCount = 1; + pPinImpl->pin.pConnectedTo = NULL; + pPinImpl->pin.fnQueryAccept = pQueryAccept; + pPinImpl->pin.pUserData = pUserData; + pPinImpl->pin.pCritSec = pCritSec; + Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo); + ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE)); + + /* Input pin attributes */ + pPinImpl->fnSampleProc = pSampleProc; + pPinImpl->fnCleanProc = pCleanUp; + pPinImpl->fnDone = pDone; + pPinImpl->fnPreConnect = NULL; + pPinImpl->pAlloc = NULL; + pPinImpl->pReader = NULL; + pPinImpl->hThread = NULL; + pPinImpl->hEventStateChanged = CreateEventW(NULL, TRUE, TRUE, NULL); + pPinImpl->thread_sleepy = CreateEventW(NULL, FALSE, FALSE, NULL); + + pPinImpl->rtStart = 0; + pPinImpl->rtCurrent = 0; + pPinImpl->rtStop = ((LONGLONG)0x7fffffff << 32) | 0xffffffff; + pPinImpl->dRate = 1.0; + pPinImpl->state = Req_Die; + pPinImpl->fnCustomRequest = pCustomRequest; + pPinImpl->stop_playback = 1; + + InitializeCriticalSection(&pPinImpl->thread_lock); + pPinImpl->thread_lock.DebugInfo->Spare[0] = (DWORD_PTR)( __FILE__ ": PullPin.thread_lock"); + + return S_OK; +} + +HRESULT PullPin_Construct(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PULL pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, REQUESTPROC pCustomRequest, STOPPROCESSPROC pDone, 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(PullPin_Vtbl, pPinInfo, pSampleProc, pUserData, pQueryAccept, pCleanUp, pCustomRequest, pDone, pCritSec, pPinImpl))) + { + *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl); + return S_OK; + } + + CoTaskMemFree(pPinImpl); + return E_FAIL; +} + +static HRESULT PullPin_InitProcessing(PullPin * This); + +HRESULT WINAPI PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) +{ + PIN_DIRECTION pindirReceive; + HRESULT hr = S_OK; + PullPin *This = (PullPin *)iface; + + TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt); + dump_AM_MEDIA_TYPE(pmt); + + EnterCriticalSection(This->pin.pCritSec); + if (!This->pin.pConnectedTo) + { + ALLOCATOR_PROPERTIES props; + + props.cBuffers = 3; + props.cbBuffer = 64 * 1024; /* 64k bytes */ + props.cbAlign = 1; + props.cbPrefix = 0; + + if (SUCCEEDED(hr) && (This->pin.fnQueryAccept(This->pin.pUserData, pmt) != S_OK)) + hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto + * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */ + + if (SUCCEEDED(hr)) + { + IPin_QueryDirection(pReceivePin, &pindirReceive); + + if (pindirReceive != PINDIR_OUTPUT) + { + ERR("Can't connect from non-output pin\n"); + hr = VFW_E_INVALID_DIRECTION; + } + } + + This->pReader = NULL; + This->pAlloc = NULL; + if (SUCCEEDED(hr)) + { + hr = IPin_QueryInterface(pReceivePin, &IID_IAsyncReader, (LPVOID *)&This->pReader); + } + + if (SUCCEEDED(hr) && This->fnPreConnect) + { + hr = This->fnPreConnect(iface, pReceivePin, &props); + } + + if (SUCCEEDED(hr)) + { + hr = IAsyncReader_RequestAllocator(This->pReader, NULL, &props, &This->pAlloc); + } + + if (SUCCEEDED(hr)) + { + CopyMediaType(&This->pin.mtCurrent, pmt); + This->pin.pConnectedTo = pReceivePin; + IPin_AddRef(pReceivePin); + hr = IMemAllocator_Commit(This->pAlloc); + } + + if (SUCCEEDED(hr)) + hr = PullPin_InitProcessing(This); + + if (FAILED(hr)) + { + if (This->pReader) + IAsyncReader_Release(This->pReader); + This->pReader = NULL; + if (This->pAlloc) + IMemAllocator_Release(This->pAlloc); + This->pAlloc = NULL; + } + } + else + hr = VFW_E_ALREADY_CONNECTED; + LeaveCriticalSection(This->pin.pCritSec); + return hr; +} + +HRESULT WINAPI PullPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) +{ + PullPin *This = (PullPin *)iface; + + TRACE("(%p/%p)->(%s, %p)\n", This, iface, 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)) + { + return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv); + } + + if (*ppv) + { + IUnknown_AddRef((IUnknown *)(*ppv)); + return S_OK; + } + + FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); + + return E_NOINTERFACE; +} + +ULONG WINAPI PullPin_Release(IPin *iface) +{ + PullPin *This = (PullPin *)iface; + ULONG refCount = InterlockedDecrement(&This->pin.refCount); + + TRACE("(%p)->() Release from %d\n", This, refCount + 1); + + if (!refCount) + { + WaitForSingleObject(This->hEventStateChanged, INFINITE); + assert(!This->hThread); + + if(This->pAlloc) + IMemAllocator_Release(This->pAlloc); + if(This->pReader) + IAsyncReader_Release(This->pReader); + CloseHandle(This->thread_sleepy); + CloseHandle(This->hEventStateChanged); + This->thread_lock.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&This->thread_lock); + CoTaskMemFree(This); + return 0; + } + return refCount; +} + +static void CALLBACK PullPin_Flush(PullPin *This) +{ + IMediaSample *pSample; + TRACE("Flushing!\n"); + + if (This->pReader) + { + /* Flush outstanding samples */ + IAsyncReader_BeginFlush(This->pReader); + + for (;;) + { + DWORD_PTR dwUser; + + IAsyncReader_WaitForNext(This->pReader, 0, &pSample, &dwUser); + + if (!pSample) + break; + + assert(!IMediaSample_GetActualDataLength(pSample)); + + IMediaSample_Release(pSample); + } + + IAsyncReader_EndFlush(This->pReader); + } +} + +static void CALLBACK PullPin_Thread_Process(PullPin *This) +{ + HRESULT hr; + IMediaSample * pSample = NULL; + ALLOCATOR_PROPERTIES allocProps; + + hr = IMemAllocator_GetProperties(This->pAlloc, &allocProps); + + This->cbAlign = allocProps.cbAlign; + + if (This->rtCurrent < This->rtStart) + This->rtCurrent = MEDIATIME_FROM_BYTES(ALIGNDOWN(BYTES_FROM_MEDIATIME(This->rtStart), This->cbAlign)); + + TRACE("Start\n"); + + if (This->rtCurrent >= This->rtStop) + { + IPin_EndOfStream((IPin *)This); + return; + } + + /* There is no sample in our buffer */ + hr = This->fnCustomRequest(This->pin.pUserData); + + if (FAILED(hr)) + ERR("Request error: %x\n", hr); + + EnterCriticalSection(This->pin.pCritSec); + SetEvent(This->hEventStateChanged); + LeaveCriticalSection(This->pin.pCritSec); + + if (SUCCEEDED(hr)) + do + { + DWORD_PTR dwUser; + + TRACE("Process sample\n"); + + hr = IAsyncReader_WaitForNext(This->pReader, 10000, &pSample, &dwUser); + + /* Return an empty sample on error to the implementation in case it does custom parsing, so it knows it's gone */ + if (SUCCEEDED(hr)) + { + hr = This->fnSampleProc(This->pin.pUserData, pSample, dwUser); + } + else + { + /* FIXME: This is not well handled yet! */ + ERR("Processing error: %x\n", hr); + } + + if (pSample) + { + IMediaSample_Release(pSample); + pSample = NULL; + } + } while (This->rtCurrent < This->rtStop && hr == S_OK && !This->stop_playback); + + /* Sample was rejected, and we are asked to terminate */ + if (pSample) + { + IMediaSample_Release(pSample); + } + + /* Can't reset state to Sleepy here because that might race, instead PauseProcessing will do that for us + * Flush remaining samples + */ + if (This->fnDone) + This->fnDone(This->pin.pUserData); + + TRACE("End: %08x, %d\n", hr, This->stop_playback); +} + +static void CALLBACK PullPin_Thread_Pause(PullPin *This) +{ + PullPin_Flush(This); + + EnterCriticalSection(This->pin.pCritSec); + This->state = Req_Sleepy; + SetEvent(This->hEventStateChanged); + LeaveCriticalSection(This->pin.pCritSec); +} + +static void CALLBACK PullPin_Thread_Stop(PullPin *This) +{ + TRACE("(%p)->()\n", This); + + EnterCriticalSection(This->pin.pCritSec); + { + CloseHandle(This->hThread); + This->hThread = NULL; + SetEvent(This->hEventStateChanged); + } + LeaveCriticalSection(This->pin.pCritSec); + + IBaseFilter_Release(This->pin.pinInfo.pFilter); + + CoUninitialize(); + ExitThread(0); +} + +static DWORD WINAPI PullPin_Thread_Main(LPVOID pv) +{ + PullPin *This = pv; + CoInitializeEx(NULL, COINIT_MULTITHREADED); + + PullPin_Flush(This); + + for (;;) + { + WaitForSingleObject(This->thread_sleepy, INFINITE); + + TRACE("State: %d\n", This->state); + + switch (This->state) + { + case Req_Die: PullPin_Thread_Stop(This); break; + case Req_Run: PullPin_Thread_Process(This); break; + case Req_Pause: PullPin_Thread_Pause(This); break; + case Req_Sleepy: ERR("Should not be signalled with SLEEPY!\n"); break; + default: ERR("Unknown state request: %d\n", This->state); break; + } + } +} + +static HRESULT PullPin_InitProcessing(PullPin * This) +{ + HRESULT hr = S_OK; + + TRACE("(%p)->()\n", This); + + /* if we are connected */ + if (This->pAlloc) + { + DWORD dwThreadId; + + WaitForSingleObject(This->hEventStateChanged, INFINITE); + EnterCriticalSection(This->pin.pCritSec); + + assert(!This->hThread); + assert(This->state == Req_Die); + assert(This->stop_playback); + assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT); + This->state = Req_Sleepy; + + /* AddRef the filter to make sure it and it's pins will be around + * as long as the thread */ + IBaseFilter_AddRef(This->pin.pinInfo.pFilter); + + + This->hThread = CreateThread(NULL, 0, PullPin_Thread_Main, This, 0, &dwThreadId); + if (!This->hThread) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + IBaseFilter_Release(This->pin.pinInfo.pFilter); + } + + if (SUCCEEDED(hr)) + { + SetEvent(This->hEventStateChanged); + /* If assert fails, that means a command was not processed before the thread previously terminated */ + } + LeaveCriticalSection(This->pin.pCritSec); + } + + TRACE(" -- %x\n", hr); + + return hr; +} + +HRESULT PullPin_StartProcessing(PullPin * This) +{ + /* if we are connected */ + TRACE("(%p)->()\n", This); + if(This->pAlloc) + { + assert(This->hThread); + + PullPin_WaitForStateChange(This, INFINITE); + + assert(This->state == Req_Sleepy); + + /* Wake up! */ + assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT); + This->state = Req_Run; + This->stop_playback = 0; + ResetEvent(This->hEventStateChanged); + SetEvent(This->thread_sleepy); + } + + return S_OK; +} + +HRESULT PullPin_PauseProcessing(PullPin * This) +{ + /* if we are connected */ + TRACE("(%p)->()\n", This); + if(This->pAlloc) + { + assert(This->hThread); + + PullPin_WaitForStateChange(This, INFINITE); + + EnterCriticalSection(This->pin.pCritSec); + + assert(!This->stop_playback); + assert(This->state == Req_Run|| This->state == Req_Sleepy); + + assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT); + This->state = Req_Pause; + This->stop_playback = 1; + ResetEvent(This->hEventStateChanged); + SetEvent(This->thread_sleepy); + + LeaveCriticalSection(This->pin.pCritSec); + } + + return S_OK; +} + +static HRESULT PullPin_StopProcessing(PullPin * This) +{ + TRACE("(%p)->()\n", This); + + /* if we are alive */ + assert(This->hThread); + + PullPin_WaitForStateChange(This, INFINITE); + + assert(This->state == Req_Pause || This->state == Req_Sleepy); + + This->stop_playback = 1; + This->state = Req_Die; + assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT); + ResetEvent(This->hEventStateChanged); + SetEvent(This->thread_sleepy); + return S_OK; +} + +HRESULT PullPin_WaitForStateChange(PullPin * This, DWORD dwMilliseconds) +{ + if (WaitForSingleObject(This->hEventStateChanged, dwMilliseconds) == WAIT_TIMEOUT) + return S_FALSE; + return S_OK; +} + +HRESULT WINAPI PullPin_EndOfStream(IPin * iface) +{ + FIXME("(%p)->() stub\n", iface); + + return SendFurther( iface, deliver_endofstream, NULL, NULL ); +} + +HRESULT WINAPI PullPin_BeginFlush(IPin * iface) +{ + PullPin *This = (PullPin *)iface; + TRACE("(%p)->()\n", This); + + EnterCriticalSection(This->pin.pCritSec); + { + SendFurther( iface, deliver_beginflush, NULL, NULL ); + } + LeaveCriticalSection(This->pin.pCritSec); + + EnterCriticalSection(&This->thread_lock); + { + if (This->pReader) + IAsyncReader_BeginFlush(This->pReader); + PullPin_WaitForStateChange(This, INFINITE); + + if (This->hThread && This->state == Req_Run) + { + PullPin_PauseProcessing(This); + PullPin_WaitForStateChange(This, INFINITE); + } + } + LeaveCriticalSection(&This->thread_lock); + + EnterCriticalSection(This->pin.pCritSec); + { + This->fnCleanProc(This->pin.pUserData); + } + LeaveCriticalSection(This->pin.pCritSec); + + return S_OK; +} + +HRESULT WINAPI PullPin_EndFlush(IPin * iface) +{ + PullPin *This = (PullPin *)iface; + + TRACE("(%p)->()\n", iface); + + /* Send further first: Else a race condition might terminate processing early */ + EnterCriticalSection(This->pin.pCritSec); + SendFurther( iface, deliver_endflush, NULL, NULL ); + LeaveCriticalSection(This->pin.pCritSec); + + EnterCriticalSection(&This->thread_lock); + { + FILTER_STATE state; + IBaseFilter_GetState(This->pin.pinInfo.pFilter, INFINITE, &state); + + if (state != State_Stopped) + PullPin_StartProcessing(This); + + PullPin_WaitForStateChange(This, INFINITE); + } + LeaveCriticalSection(&This->thread_lock); + + return S_OK; +} + +HRESULT WINAPI PullPin_Disconnect(IPin *iface) +{ + HRESULT hr; + PullPin *This = (PullPin *)iface; + + TRACE("()\n"); + + EnterCriticalSection(This->pin.pCritSec); + { + if (FAILED(hr = IMemAllocator_Decommit(This->pAlloc))) + ERR("Allocator decommit failed with error %x. Possible memory leak\n", hr); + + if (This->pin.pConnectedTo) + { + IPin_Release(This->pin.pConnectedTo); + This->pin.pConnectedTo = NULL; + PullPin_StopProcessing(This); + + FreeMediaType(&This->pin.mtCurrent); + ZeroMemory(&This->pin.mtCurrent, sizeof(This->pin.mtCurrent)); + hr = S_OK; + } + else + hr = S_FALSE; + } + LeaveCriticalSection(This->pin.pCritSec); + + return hr; +} + +HRESULT WINAPI PullPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) +{ + newsegmentargs args; + FIXME("(%p)->(%s, %s, %g) stub\n", iface, wine_dbgstr_longlong(tStart), wine_dbgstr_longlong(tStop), dRate); + + args.tStart = tStart; + args.tStop = tStop; + args.rate = dRate; + + return SendFurther( iface, deliver_newsegment, &args, NULL ); +} + +static const IPinVtbl PullPin_Vtbl = +{ + PullPin_QueryInterface, + IPinImpl_AddRef, + PullPin_Release, + InputPin_Connect, + PullPin_ReceiveConnection, + PullPin_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/strmbase/strmbase_private.h b/dlls/strmbase/strmbase_private.h new file mode 100644 index 0000000..e41e1fc --- /dev/null +++ b/dlls/strmbase/strmbase_private.h @@ -0,0 +1,35 @@ +/* DirectShow BaseClasses + * + * Copyright 2008 Google (Maarten Lankhorst) + * + * This file contains the (internal) driver registration functions, + * driver enumeration APIs and DirectDraw creation functions. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "wtypes.h" +#include "wingdi.h" +#include "winuser.h" +#include "dshow.h" +#include "wine/list.h" + +#include "strmbase/strmbase.h" diff --git a/dlls/strmbase/transform.c b/dlls/strmbase/transform.c new file mode 100644 index 0000000..8bd021d --- /dev/null +++ b/dlls/strmbase/transform.c @@ -0,0 +1,648 @@ +/* + * Transform Filter (Base for decoders, etc...) + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" + +#include "strmbase_private.h" + +#include "amvideo.h" +#include "windef.h" +#include "winbase.h" +#include "dshow.h" +#include "strmif.h" +#include "vfw.h" + +#include + +#include "wine/unicode.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(strmbase); + +static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0}; +static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0}; + +static const IBaseFilterVtbl TransformFilter_Vtbl; +static const IPinVtbl TransformFilter_InputPin_Vtbl; +static const IMemInputPinVtbl MemInputPin_Vtbl; +static const IPinVtbl TransformFilter_OutputPin_Vtbl; + +static HRESULT TransformFilter_Input_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt) +{ + TransformFilterImpl* This = (TransformFilterImpl*)iface; + TRACE("%p\n", iface); + dump_AM_MEDIA_TYPE(pmt); + + if (This->pFuncsTable->pfnQueryConnect) + return This->pFuncsTable->pfnQueryConnect(This, pmt); + /* Assume OK if there's no query method (the connection will fail if + needed) */ + return S_OK; +} + + +static HRESULT TransformFilter_Output_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt) +{ + TransformFilterImpl* pTransformFilter = (TransformFilterImpl*)iface; + AM_MEDIA_TYPE* outpmt = &((OutputPin*)pTransformFilter->ppPins[1])->pin.mtCurrent; + TRACE("%p\n", iface); + + if (IsEqualIID(&pmt->majortype, &outpmt->majortype) && IsEqualIID(&pmt->subtype, &outpmt->subtype)) + return S_OK; + return S_FALSE; +} + + +static inline TransformFilterImpl *impl_from_IMediaSeeking( IMediaSeeking *iface ) +{ + return (TransformFilterImpl *)((char*)iface - FIELD_OFFSET(TransformFilterImpl, mediaSeeking.lpVtbl)); +} + +static HRESULT WINAPI TransformFilter_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv) +{ + TransformFilterImpl *This = impl_from_IMediaSeeking(iface); + + return IUnknown_QueryInterface((IUnknown *)This, riid, ppv); +} + +static ULONG WINAPI TransformFilter_Seeking_AddRef(IMediaSeeking * iface) +{ + TransformFilterImpl *This = impl_from_IMediaSeeking(iface); + + return IUnknown_AddRef((IUnknown *)This); +} + +static ULONG WINAPI TransformFilter_Seeking_Release(IMediaSeeking * iface) +{ + TransformFilterImpl *This = impl_from_IMediaSeeking(iface); + + return IUnknown_Release((IUnknown *)This); +} + +static const IMediaSeekingVtbl TransformFilter_Seeking_Vtbl = +{ + TransformFilter_Seeking_QueryInterface, + TransformFilter_Seeking_AddRef, + TransformFilter_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 +}; + +/* These shouldn't be implemented by default. + * Usually only source filters should implement these + * and even it's not needed all of the time + */ +static HRESULT TransformFilter_ChangeCurrent(IBaseFilter *iface) +{ + TRACE("(%p) filter hasn't implemented current position change!\n", iface); + return S_OK; +} + +static HRESULT TransformFilter_ChangeStop(IBaseFilter *iface) +{ + TRACE("(%p) filter hasn't implemented stop position change!\n", iface); + return S_OK; +} + +static HRESULT TransformFilter_ChangeRate(IBaseFilter *iface) +{ + TRACE("(%p) filter hasn't implemented rate change!\n", iface); + return S_OK; +} + +HRESULT TransformFilter_Create(TransformFilterImpl* pTransformFilter, const CLSID* pClsid, const TransformFuncsTable* pFuncsTable, CHANGEPROC stop, CHANGEPROC current, CHANGEPROC rate) +{ + HRESULT hr; + PIN_INFO piInput; + PIN_INFO piOutput; + + /* pTransformFilter is already allocated */ + pTransformFilter->clsid = *pClsid; + pTransformFilter->pFuncsTable = pFuncsTable; + + pTransformFilter->lpVtbl = &TransformFilter_Vtbl; + + pTransformFilter->refCount = 1; + InitializeCriticalSection(&pTransformFilter->csFilter); + pTransformFilter->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TransformFilterImpl.csFilter"); + pTransformFilter->state = State_Stopped; + pTransformFilter->pClock = NULL; + ZeroMemory(&pTransformFilter->filterInfo, sizeof(FILTER_INFO)); + ZeroMemory(&pTransformFilter->pmt, sizeof(pTransformFilter->pmt)); + + pTransformFilter->ppPins = CoTaskMemAlloc(2 * sizeof(IPin *)); + + /* construct input pin */ + piInput.dir = PINDIR_INPUT; + piInput.pFilter = (IBaseFilter *)pTransformFilter; + lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0])); + piOutput.dir = PINDIR_OUTPUT; + piOutput.pFilter = (IBaseFilter *)pTransformFilter; + lstrcpynW(piOutput.achName, wcsOutputPinName, sizeof(piOutput.achName) / sizeof(piOutput.achName[0])); + + hr = InputPin_Construct(&TransformFilter_InputPin_Vtbl, &piInput, (SAMPLEPROC_PUSH)pFuncsTable->pfnProcessSampleData, pTransformFilter, TransformFilter_Input_QueryAccept, NULL, &pTransformFilter->csFilter, NULL, &pTransformFilter->ppPins[0]); + + if (SUCCEEDED(hr)) + { + ALLOCATOR_PROPERTIES props; + props.cbAlign = 1; + props.cbPrefix = 0; + props.cbBuffer = 0; /* Will be updated at connection time */ + props.cBuffers = 1; + + hr = OutputPin_Construct(&TransformFilter_OutputPin_Vtbl, sizeof(OutputPin), &piOutput, &props, pTransformFilter, TransformFilter_Output_QueryAccept, &pTransformFilter->csFilter, &pTransformFilter->ppPins[1]); + + if (FAILED(hr)) + ERR("Cannot create output pin (%x)\n", hr); + else + { + if (!stop) + stop = TransformFilter_ChangeStop; + if (!current) + current = TransformFilter_ChangeCurrent; + if (!rate) + rate = TransformFilter_ChangeRate; + + MediaSeekingImpl_Init((IBaseFilter*)pTransformFilter, stop, current, rate, &pTransformFilter->mediaSeeking, &pTransformFilter->csFilter); + pTransformFilter->mediaSeeking.lpVtbl = &TransformFilter_Seeking_Vtbl; + } + } + else + { + CoTaskMemFree(pTransformFilter->ppPins); + pTransformFilter->csFilter.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&pTransformFilter->csFilter); + CoTaskMemFree(pTransformFilter); + } + + return hr; +} + +static HRESULT WINAPI TransformFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv) +{ + TransformFilterImpl *This = (TransformFilterImpl *)iface; + TRACE("(%p/%p)->(%s, %p)\n", This, iface, 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; + else if (IsEqualIID(riid, &IID_IMediaSeeking)) + *ppv = &This->mediaSeeking; + + if (*ppv) + { + IUnknown_AddRef((IUnknown *)(*ppv)); + return S_OK; + } + + if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow)) + FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); + + return E_NOINTERFACE; +} + +static ULONG WINAPI TransformFilter_AddRef(IBaseFilter * iface) +{ + TransformFilterImpl *This = (TransformFilterImpl *)iface; + ULONG refCount = InterlockedIncrement(&This->refCount); + + TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1); + + return refCount; +} + +static ULONG WINAPI TransformFilter_Release(IBaseFilter * iface) +{ + TransformFilterImpl *This = (TransformFilterImpl *)iface; + ULONG refCount = InterlockedDecrement(&This->refCount); + + TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1); + + if (!refCount) + { + ULONG i; + + if (This->pClock) + IReferenceClock_Release(This->pClock); + + for (i = 0; i < 2; i++) + { + IPin *pConnectedTo; + + if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo))) + { + IPin_Disconnect(pConnectedTo); + IPin_Release(pConnectedTo); + } + IPin_Disconnect(This->ppPins[i]); + + IPin_Release(This->ppPins[i]); + } + + CoTaskMemFree(This->ppPins); + This->lpVtbl = NULL; + + This->csFilter.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&This->csFilter); + + TRACE("Destroying transform filter\n"); + FreeMediaType(&This->pmt); + CoTaskMemFree(This); + + return 0; + } + else + return refCount; +} + +/** IPersist methods **/ + +static HRESULT WINAPI TransformFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid) +{ + TransformFilterImpl *This = (TransformFilterImpl *)iface; + + TRACE("(%p/%p)->(%p)\n", This, iface, pClsid); + + *pClsid = This->clsid; + + return S_OK; +} + +/** IMediaFilter methods **/ + +static HRESULT WINAPI TransformFilter_Stop(IBaseFilter * iface) +{ + TransformFilterImpl *This = (TransformFilterImpl *)iface; + + TRACE("(%p/%p)\n", This, iface); + + EnterCriticalSection(&This->csFilter); + { + This->state = State_Stopped; + if (This->pFuncsTable->pfnProcessEnd) + This->pFuncsTable->pfnProcessEnd(This); + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static HRESULT WINAPI TransformFilter_Pause(IBaseFilter * iface) +{ + TransformFilterImpl *This = (TransformFilterImpl *)iface; + + TRACE("(%p/%p)->()\n", This, iface); + + EnterCriticalSection(&This->csFilter); + { + if (This->state == State_Stopped) + IBaseFilter_Run(iface, -1); + + This->state = State_Paused; + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static HRESULT WINAPI TransformFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart) +{ + HRESULT hr = S_OK; + TransformFilterImpl *This = (TransformFilterImpl *)iface; + + TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart)); + + EnterCriticalSection(&This->csFilter); + { + if (This->state == State_Stopped) + { + ((InputPin *)This->ppPins[0])->end_of_stream = 0; + if (This->pFuncsTable->pfnProcessBegin) + This->pFuncsTable->pfnProcessBegin(This); + OutputPin_CommitAllocator((OutputPin *)This->ppPins[1]); + } + + This->rtStreamStart = tStart; + This->state = State_Running; + } + LeaveCriticalSection(&This->csFilter); + + return hr; +} + +static HRESULT WINAPI TransformFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState) +{ + TransformFilterImpl *This = (TransformFilterImpl *)iface; + + TRACE("(%p/%p)->(%d, %p)\n", This, iface, dwMilliSecsTimeout, pState); + + EnterCriticalSection(&This->csFilter); + { + *pState = This->state; + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +static HRESULT WINAPI TransformFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock) +{ + TransformFilterImpl *This = (TransformFilterImpl *)iface; + + TRACE("(%p/%p)->(%p)\n", This, iface, 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 TransformFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock) +{ + TransformFilterImpl *This = (TransformFilterImpl *)iface; + + TRACE("(%p/%p)->(%p)\n", This, iface, ppClock); + + EnterCriticalSection(&This->csFilter); + { + *ppClock = This->pClock; + if (This->pClock) + IReferenceClock_AddRef(This->pClock); + } + LeaveCriticalSection(&This->csFilter); + + return S_OK; +} + +/** IBaseFilter implementation **/ + +static HRESULT TransformFilter_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick) +{ + TransformFilterImpl *This = (TransformFilterImpl *)iface; + + /* Our pins are static, not changing so setting static tick count is ok */ + *lastsynctick = 0; + + if (pos >= 2) + return S_FALSE; + + *pin = This->ppPins[pos]; + IPin_AddRef(*pin); + return S_OK; +} + +static HRESULT WINAPI TransformFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum) +{ + TransformFilterImpl *This = (TransformFilterImpl *)iface; + + TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum); + + return IEnumPinsImpl_Construct(ppEnum, TransformFilter_GetPin, iface); +} + +static HRESULT WINAPI TransformFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin) +{ + TransformFilterImpl *This = (TransformFilterImpl *)iface; + + TRACE("(%p/%p)->(%p,%p)\n", This, iface, debugstr_w(Id), ppPin); + + return E_NOTIMPL; +} + +static HRESULT WINAPI TransformFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo) +{ + TransformFilterImpl *This = (TransformFilterImpl *)iface; + + TRACE("(%p/%p)->(%p)\n", This, iface, 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 TransformFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName) +{ + HRESULT hr = S_OK; + TransformFilterImpl *This = (TransformFilterImpl *)iface; + + TRACE("(%p/%p)->(%p, %s)\n", This, iface, 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 TransformFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo) +{ + TransformFilterImpl *This = (TransformFilterImpl *)iface; + TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo); + return E_NOTIMPL; +} + +static const IBaseFilterVtbl TransformFilter_Vtbl = +{ + TransformFilter_QueryInterface, + TransformFilter_AddRef, + TransformFilter_Release, + TransformFilter_GetClassID, + TransformFilter_Stop, + TransformFilter_Pause, + TransformFilter_Run, + TransformFilter_GetState, + TransformFilter_SetSyncSource, + TransformFilter_GetSyncSource, + TransformFilter_EnumPins, + TransformFilter_FindPin, + TransformFilter_QueryFilterInfo, + TransformFilter_JoinFilterGraph, + TransformFilter_QueryVendorInfo +}; + +static HRESULT WINAPI TransformFilter_InputPin_EndOfStream(IPin * iface) +{ + InputPin* This = (InputPin*) iface; + TransformFilterImpl* pTransform; + IPin* ppin; + HRESULT hr; + + TRACE("(%p)->()\n", iface); + + /* Since we process samples synchronously, just forward notification downstream */ + pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter; + if (!pTransform) + hr = E_FAIL; + else + hr = IPin_ConnectedTo(pTransform->ppPins[1], &ppin); + if (SUCCEEDED(hr)) + { + hr = IPin_EndOfStream(ppin); + IPin_Release(ppin); + } + + if (FAILED(hr)) + ERR("%x\n", hr); + return hr; +} + +static HRESULT WINAPI TransformFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) +{ + InputPin* This = (InputPin*) iface; + TransformFilterImpl* pTransform; + HRESULT hr; + + TRACE("(%p)->(%p, %p)\n", iface, pReceivePin, pmt); + + pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter; + + hr = pTransform->pFuncsTable->pfnConnectInput(pTransform, pmt); + if (SUCCEEDED(hr)) + { + hr = InputPin_ReceiveConnection(iface, pReceivePin, pmt); + if (FAILED(hr)) + pTransform->pFuncsTable->pfnCleanup(pTransform); + } + + return hr; +} + +static HRESULT WINAPI TransformFilter_InputPin_Disconnect(IPin * iface) +{ + InputPin* This = (InputPin*) iface; + TransformFilterImpl* pTransform; + + TRACE("(%p)->()\n", iface); + + pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter; + pTransform->pFuncsTable->pfnCleanup(pTransform); + + return IPinImpl_Disconnect(iface); +} + +static const IPinVtbl TransformFilter_InputPin_Vtbl = +{ + InputPin_QueryInterface, + IPinImpl_AddRef, + InputPin_Release, + InputPin_Connect, + TransformFilter_InputPin_ReceiveConnection, + TransformFilter_InputPin_Disconnect, + IPinImpl_ConnectedTo, + IPinImpl_ConnectionMediaType, + IPinImpl_QueryPinInfo, + IPinImpl_QueryDirection, + IPinImpl_QueryId, + IPinImpl_QueryAccept, + IPinImpl_EnumMediaTypes, + IPinImpl_QueryInternalConnections, + TransformFilter_InputPin_EndOfStream, + InputPin_BeginFlush, + InputPin_EndFlush, + InputPin_NewSegment +}; + +static HRESULT WINAPI TransformFilter_Output_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum) +{ + IPinImpl *This = (IPinImpl *)iface; + TransformFilterImpl *pTransform = (TransformFilterImpl *)This->pinInfo.pFilter; + ENUMMEDIADETAILS emd; + + TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum); + + emd.cMediaTypes = 1; + emd.pMediaTypes = &pTransform->pmt; + + return IEnumMediaTypesImpl_Construct(&emd, ppEnum); +} + +static const IPinVtbl TransformFilter_OutputPin_Vtbl = +{ + OutputPin_QueryInterface, + IPinImpl_AddRef, + OutputPin_Release, + OutputPin_Connect, + OutputPin_ReceiveConnection, + OutputPin_Disconnect, + IPinImpl_ConnectedTo, + IPinImpl_ConnectionMediaType, + IPinImpl_QueryPinInfo, + IPinImpl_QueryDirection, + IPinImpl_QueryId, + IPinImpl_QueryAccept, + TransformFilter_Output_EnumMediaTypes, + IPinImpl_QueryInternalConnections, + OutputPin_EndOfStream, + OutputPin_BeginFlush, + OutputPin_EndFlush, + OutputPin_NewSegment +}; + +static const IMemInputPinVtbl MemInputPin_Vtbl = +{ + MemInputPin_QueryInterface, + MemInputPin_AddRef, + MemInputPin_Release, + MemInputPin_GetAllocator, + MemInputPin_NotifyAllocator, + MemInputPin_GetAllocatorRequirements, + MemInputPin_Receive, + MemInputPin_ReceiveMultiple, + MemInputPin_ReceiveCanBlock +}; diff --git a/include/strmbase/control.h b/include/strmbase/control.h new file mode 100644 index 0000000..b5e3997 --- /dev/null +++ b/include/strmbase/control.h @@ -0,0 +1,62 @@ +/* + * Filter Seeking and Control Interfaces + * + * Copyright 2003 Robert Shearman + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef QUARTZ_CONTROL_H +#define QUARTZ_CONTROL_H + +typedef HRESULT (* CHANGEPROC)(IBaseFilter *pUserData); + +typedef struct MediaSeekingImpl +{ + const IMediaSeekingVtbl * lpVtbl; + + ULONG refCount; + IBaseFilter *pUserData; + CHANGEPROC fnChangeStop; + CHANGEPROC fnChangeCurrent; + CHANGEPROC fnChangeRate; + DWORD dwCapabilities; + double dRate; + LONGLONG llCurrent, llStop, llDuration; + GUID timeformat; + PCRITICAL_SECTION crst; +} MediaSeekingImpl; + +HRESULT MediaSeekingImpl_Init(IBaseFilter *pUserData, CHANGEPROC fnChangeStop, CHANGEPROC fnChangeCurrent, CHANGEPROC fnChangeRate, MediaSeekingImpl * pSeeking, PCRITICAL_SECTION crit_sect); + +HRESULT WINAPI MediaSeekingImpl_GetCapabilities(IMediaSeeking * iface, DWORD * pCapabilities); +HRESULT WINAPI MediaSeekingImpl_CheckCapabilities(IMediaSeeking * iface, DWORD * pCapabilities); +HRESULT WINAPI MediaSeekingImpl_IsFormatSupported(IMediaSeeking * iface, const GUID * pFormat); +HRESULT WINAPI MediaSeekingImpl_QueryPreferredFormat(IMediaSeeking * iface, GUID * pFormat); +HRESULT WINAPI MediaSeekingImpl_GetTimeFormat(IMediaSeeking * iface, GUID * pFormat); +HRESULT WINAPI MediaSeekingImpl_IsUsingTimeFormat(IMediaSeeking * iface, const GUID * pFormat); +HRESULT WINAPI MediaSeekingImpl_SetTimeFormat(IMediaSeeking * iface, const GUID * pFormat); +HRESULT WINAPI MediaSeekingImpl_GetDuration(IMediaSeeking * iface, LONGLONG * pDuration); +HRESULT WINAPI MediaSeekingImpl_GetStopPosition(IMediaSeeking * iface, LONGLONG * pStop); +HRESULT WINAPI MediaSeekingImpl_GetCurrentPosition(IMediaSeeking * iface, LONGLONG * pCurrent); +HRESULT WINAPI MediaSeekingImpl_ConvertTimeFormat(IMediaSeeking * iface, LONGLONG * pTarget, const GUID * pTargetFormat, LONGLONG Source, const GUID * pSourceFormat); +HRESULT WINAPI MediaSeekingImpl_SetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, DWORD dwCurrentFlags, LONGLONG * pStop, DWORD dwStopFlags); +HRESULT WINAPI MediaSeekingImpl_GetPositions(IMediaSeeking * iface, LONGLONG * pCurrent, LONGLONG * pStop); +HRESULT WINAPI MediaSeekingImpl_GetAvailable(IMediaSeeking * iface, LONGLONG * pEarliest, LONGLONG * pLatest); +HRESULT WINAPI MediaSeekingImpl_SetRate(IMediaSeeking * iface, double dRate); +HRESULT WINAPI MediaSeekingImpl_GetRate(IMediaSeeking * iface, double * dRate); +HRESULT WINAPI MediaSeekingImpl_GetPreroll(IMediaSeeking * iface, LONGLONG * pPreroll); + +#endif /*QUARTZ_CONTROL_H*/ diff --git a/include/strmbase/misc.h b/include/strmbase/misc.h new file mode 100644 index 0000000..63aabe0 --- /dev/null +++ b/include/strmbase/misc.h @@ -0,0 +1,94 @@ +/* + * Miscelleanous declarations + * + * Copyright 2002 Lionel Ulmer + * Copyright 2008 Google (Maarten Lankhorst) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define MEDIATIME_FROM_BYTES(x) ((LONGLONG)(x) * 10000000) +#define SEC_FROM_MEDIATIME(time) ((time) / 10000000) +#define BYTES_FROM_MEDIATIME(time) SEC_FROM_MEDIATIME(time) +#define MSEC_FROM_MEDIATIME(time) ((time) / 10000) + +#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field)) + +typedef struct tagENUMEDIADETAILS +{ + ULONG cMediaTypes; + AM_MEDIA_TYPE * pMediaTypes; +} ENUMMEDIADETAILS; + +typedef HRESULT (* FNOBTAINPIN)(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick); + +HRESULT IEnumPinsImpl_Construct(IEnumPins ** ppEnum, FNOBTAINPIN receive_pin, IBaseFilter *base); +HRESULT IEnumMediaTypesImpl_Construct(const ENUMMEDIADETAILS * pDetails, IEnumMediaTypes ** ppEnum); + +extern const char * qzdebugstr_guid(const GUID * id); +extern const char * qzdebugstr_State(FILTER_STATE state); + +extern HRESULT CopyMediaType(AM_MEDIA_TYPE * pDest, const AM_MEDIA_TYPE *pSrc); +extern void FreeMediaType(AM_MEDIA_TYPE * pmt); +extern void DeleteMediaType(AM_MEDIA_TYPE * pmt); +extern BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards); +extern void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt); +extern HRESULT updatehres( HRESULT original, HRESULT new ); + +typedef struct StdMediaSample2 +{ + const IMediaSample2Vtbl * lpvtbl; + + LONG ref; + AM_SAMPLE2_PROPERTIES props; + IMemAllocator * pParent; + struct list listentry; + LONGLONG tMediaStart; + LONGLONG tMediaEnd; +} StdMediaSample2; + +typedef struct BaseMemAllocator +{ + const IMemAllocatorVtbl * lpVtbl; + + LONG ref; + ALLOCATOR_PROPERTIES props; + HRESULT (* fnAlloc) (IMemAllocator *); + HRESULT (* fnFree)(IMemAllocator *); + HRESULT (* fnVerify)(IMemAllocator *, ALLOCATOR_PROPERTIES *); + HRESULT (* fnBufferPrepare)(IMemAllocator *, StdMediaSample2 *, DWORD flags); + HRESULT (* fnBufferReleased)(IMemAllocator *, StdMediaSample2 *); + void (* fnDestroyed)(IMemAllocator *); + HANDLE hSemWaiting; + BOOL bDecommitQueued; + BOOL bCommitted; + LONG lWaiting; + struct list free_list; + struct list used_list; + CRITICAL_SECTION *pCritSect; +} BaseMemAllocator; + +extern HRESULT BaseMemAllocator_Init(HRESULT (* fnAlloc)(IMemAllocator *), + HRESULT (* fnFree)(IMemAllocator *), + HRESULT (* fnVerify)(IMemAllocator *, ALLOCATOR_PROPERTIES *), + HRESULT (* fnBufferPrepare)(IMemAllocator *, StdMediaSample2 *, DWORD), + HRESULT (* fnBufferReleased)(IMemAllocator *, StdMediaSample2 *), + void (* fnDestroyed)(IMemAllocator *), + CRITICAL_SECTION *pCritSect, + BaseMemAllocator * pMemAlloc); + +extern HRESULT StdMediaSample2_Construct(BYTE * pbBuffer, LONG cbBuffer, IMemAllocator * pParent, StdMediaSample2 ** ppSample); +extern void StdMediaSample2_Delete(StdMediaSample2 * This); + diff --git a/include/strmbase/parser.h b/include/strmbase/parser.h new file mode 100644 index 0000000..b542388 --- /dev/null +++ b/include/strmbase/parser.h @@ -0,0 +1,80 @@ +/* + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +typedef struct ParserImpl ParserImpl; + +typedef HRESULT (*PFN_PROCESS_SAMPLE) (LPVOID iface, IMediaSample * pSample, DWORD_PTR cookie); +typedef HRESULT (*PFN_QUERY_ACCEPT) (LPVOID iface, const AM_MEDIA_TYPE * pmt); +typedef HRESULT (*PFN_PRE_CONNECT) (IPin * iface, IPin * pConnectPin, ALLOCATOR_PROPERTIES *prop); +typedef HRESULT (*PFN_CLEANUP) (LPVOID iface); +typedef HRESULT (*PFN_DISCONNECT) (LPVOID iface); + +struct ParserImpl +{ + const IBaseFilterVtbl *lpVtbl; + + LONG refCount; + CRITICAL_SECTION csFilter; + FILTER_STATE state; + REFERENCE_TIME rtStreamStart; + IReferenceClock * pClock; + PFN_CLEANUP fnCleanup; + PFN_DISCONNECT fnDisconnect; + FILTER_INFO filterInfo; + CLSID clsid; + + PullPin * pInputPin; + IPin ** ppPins; + ULONG cStreams; + DWORD lastpinchange; + MediaSeekingImpl mediaSeeking; +}; + +typedef struct Parser_OutputPin +{ + OutputPin pin; + + AM_MEDIA_TYPE * pmt; + LONGLONG dwSamplesProcessed; +} Parser_OutputPin; + +extern HRESULT Parser_AddPin(ParserImpl * This, const PIN_INFO * piOutput, ALLOCATOR_PROPERTIES * props, const AM_MEDIA_TYPE * amt); + +extern HRESULT Parser_Create(ParserImpl*, const IBaseFilterVtbl *, const CLSID*, PFN_PROCESS_SAMPLE, PFN_QUERY_ACCEPT, PFN_PRE_CONNECT, + PFN_CLEANUP, PFN_DISCONNECT, REQUESTPROC, STOPPROCESSPROC, CHANGEPROC stop, CHANGEPROC current, CHANGEPROC rate); + +/* Override the _Release function and call this when releasing */ +extern void Parser_Destroy(ParserImpl *This); + +extern HRESULT WINAPI Parser_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv); +extern ULONG WINAPI Parser_AddRef(IBaseFilter * iface); +extern ULONG WINAPI Parser_Release(IBaseFilter * iface); +extern HRESULT WINAPI Parser_GetClassID(IBaseFilter * iface, CLSID * pClsid); +extern HRESULT WINAPI Parser_Stop(IBaseFilter * iface); +extern HRESULT WINAPI Parser_Pause(IBaseFilter * iface); +extern HRESULT WINAPI Parser_Run(IBaseFilter * iface, REFERENCE_TIME tStart); +extern HRESULT WINAPI Parser_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState); +extern HRESULT WINAPI Parser_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock); +extern HRESULT WINAPI Parser_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock); +extern HRESULT WINAPI Parser_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum); +extern HRESULT WINAPI Parser_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin); +extern HRESULT WINAPI Parser_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo); +extern HRESULT WINAPI Parser_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName); +extern HRESULT WINAPI Parser_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo); diff --git a/include/strmbase/pin.h b/include/strmbase/pin.h new file mode 100644 index 0000000..3a9719c --- /dev/null +++ b/include/strmbase/pin.h @@ -0,0 +1,218 @@ +/* + * IPin function declarations to allow inheritance + * + * Copyright 2003 Robert Shearman + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* This function will process incoming samples to the pin. + * Any return value valid in IMemInputPin::Receive is allowed here + * + * Cookie is the cookie that was set when requesting the buffer, if you don't + * implement custom requesting, you can safely ignore this + */ +typedef HRESULT (* SAMPLEPROC_PUSH)(LPVOID userdata, IMediaSample * pSample); +typedef HRESULT (* SAMPLEPROC_PULL)(LPVOID userdata, IMediaSample * pSample, DWORD_PTR cookie); + +/* This function will determine whether a type is supported or not. + * It is allowed to return any error value (within reason), as opposed + * to IPin::QueryAccept which is only allowed to return S_OK or S_FALSE. + */ +typedef HRESULT (* QUERYACCEPTPROC)(LPVOID userdata, const AM_MEDIA_TYPE * pmt); + +/* This function is called prior to finalizing a connection with + * another pin and can be used to get things from the other pin + * like IMemInput interfaces. + * + * props contains some defaults, but you can safely override them to your liking + */ +typedef HRESULT (* PRECONNECTPROC)(IPin * iface, IPin * pConnectPin, ALLOCATOR_PROPERTIES *props); + +/* This function is called whenever a cleanup operation has to occur, + * this is usually after a flush, seek, or end of stream notification. + * This code may even be repeated multiple times, so build your code to + * tolerate this behavior. Return value is ignored and should be S_OK. + */ +typedef HRESULT (* CLEANUPPROC) (LPVOID userdata); + +/* This function is called whenever a request for a new sample is made, + * If you implement it (it can be NULL for default behavior), you have to + * call IMemAllocator_GetBuffer and IMemAllocator_RequestBuffer + * This is useful if you want to request more than 1 buffer at simultaneously + * + * This will also cause the Sample Proc to be called with empty buffers to indicate + * failure in retrieving the sample. + */ +typedef HRESULT (* REQUESTPROC) (LPVOID userdata); + +/* This function is called after processing is done (for whatever reason that is caused) + * This is useful if you create processing threads that need to die + */ +typedef HRESULT (* STOPPROCESSPROC) (LPVOID userdata); + +#define ALIGNDOWN(value,boundary) ((value)/(boundary)*(boundary)) +#define ALIGNUP(value,boundary) (ALIGNDOWN((value)+(boundary)-1, (boundary))) + +typedef struct IPinImpl +{ + const struct IPinVtbl * lpVtbl; + LONG refCount; + LPCRITICAL_SECTION pCritSec; + PIN_INFO pinInfo; + IPin * pConnectedTo; + AM_MEDIA_TYPE mtCurrent; + ENUMMEDIADETAILS enumMediaDetails; + QUERYACCEPTPROC fnQueryAccept; + LPVOID pUserData; +} IPinImpl; + +typedef struct InputPin +{ + /* inheritance C style! */ + IPinImpl pin; + + const IMemInputPinVtbl * lpVtblMemInput; + IMemAllocator * pAllocator; + SAMPLEPROC_PUSH fnSampleProc; + CLEANUPPROC fnCleanProc; + REFERENCE_TIME tStart; + REFERENCE_TIME tStop; + double dRate; + BOOL flushing, end_of_stream; + IMemAllocator *preferred_allocator; +} InputPin; + +typedef struct OutputPin +{ + /* inheritance C style! */ + IPinImpl pin; + + IMemInputPin * pMemInputPin; + HRESULT (* pConnectSpecific)(IPin * iface, IPin * pReceiver, const AM_MEDIA_TYPE * pmt); + BOOL custom_allocator; + IMemAllocator *alloc; + BOOL readonly; + ALLOCATOR_PROPERTIES allocProps; +} OutputPin; + +typedef struct PullPin +{ + /* inheritance C style! */ + IPinImpl pin; + + REFERENCE_TIME rtStart, rtCurrent, rtNext, rtStop; + IAsyncReader * pReader; + IMemAllocator * pAlloc; + SAMPLEPROC_PULL fnSampleProc; + PRECONNECTPROC fnPreConnect; + REQUESTPROC fnCustomRequest; + CLEANUPPROC fnCleanProc; + STOPPROCESSPROC fnDone; + double dRate; + BOOL stop_playback; + DWORD cbAlign; + + /* Any code that touches the thread must hold the thread lock, + * lock order: thread_lock and then the filter critical section + * also signal thread_sleepy so the thread knows to wake up + */ + CRITICAL_SECTION thread_lock; + HANDLE hThread; + DWORD requested_state; + HANDLE hEventStateChanged, thread_sleepy; + DWORD state; +} PullPin; + +#define Req_Sleepy 0 +#define Req_Die 1 +#define Req_Run 2 +#define Req_Pause 3 + +/*** Constructors ***/ +HRESULT InputPin_Construct(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PUSH pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, LPCRITICAL_SECTION pCritSec, IMemAllocator *, IPin ** ppPin); +HRESULT OutputPin_Construct(const IPinVtbl *OutputPin_Vtbl, long outputpin_size, const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES *props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin); +HRESULT PullPin_Construct(const IPinVtbl *PullPin_Vtbl, const PIN_INFO * pPinInfo, SAMPLEPROC_PULL pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, STOPPROCESSPROC, REQUESTPROC pCustomRequest, LPCRITICAL_SECTION pCritSec, IPin ** ppPin); + +/**************************/ +/*** Pin Implementation ***/ + +/* Common */ +ULONG WINAPI IPinImpl_AddRef(IPin * iface); +HRESULT WINAPI IPinImpl_Disconnect(IPin * iface); +HRESULT WINAPI IPinImpl_ConnectedTo(IPin * iface, IPin ** ppPin); +HRESULT WINAPI IPinImpl_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt); +HRESULT WINAPI IPinImpl_QueryPinInfo(IPin * iface, PIN_INFO * pInfo); +HRESULT WINAPI IPinImpl_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir); +HRESULT WINAPI IPinImpl_QueryId(IPin * iface, LPWSTR * Id); +HRESULT WINAPI IPinImpl_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt); +HRESULT WINAPI IPinImpl_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum); +HRESULT WINAPI IPinImpl_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin); + +/* Input Pin */ +HRESULT WINAPI InputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv); +ULONG WINAPI InputPin_Release(IPin * iface); +HRESULT WINAPI InputPin_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt); +HRESULT WINAPI InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt); +HRESULT WINAPI InputPin_EndOfStream(IPin * iface); +HRESULT WINAPI InputPin_BeginFlush(IPin * iface); +HRESULT WINAPI InputPin_EndFlush(IPin * iface); +HRESULT WINAPI InputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + +/* Output Pin */ +HRESULT WINAPI OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv); +ULONG WINAPI OutputPin_Release(IPin * iface); +HRESULT WINAPI OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt); +HRESULT WINAPI OutputPin_Disconnect(IPin * iface); +HRESULT WINAPI OutputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt); +HRESULT WINAPI OutputPin_EndOfStream(IPin * iface); +HRESULT WINAPI OutputPin_BeginFlush(IPin * iface); +HRESULT WINAPI OutputPin_EndFlush(IPin * iface); +HRESULT WINAPI OutputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + +HRESULT OutputPin_CommitAllocator(OutputPin * This); +HRESULT OutputPin_DecommitAllocator(OutputPin * This); +HRESULT OutputPin_GetDeliveryBuffer(OutputPin * This, IMediaSample ** ppSample, REFERENCE_TIME * tStart, REFERENCE_TIME * tStop, DWORD dwFlags); +HRESULT OutputPin_SendSample(OutputPin * This, IMediaSample * pSample); +HRESULT OutputPin_DeliverDisconnect(OutputPin * This); +HRESULT OutputPin_DeliverNewSegment(OutputPin * This, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + +/**********************************/ +/*** MemInputPin Implementation ***/ + +HRESULT WINAPI MemInputPin_QueryInterface(IMemInputPin * iface, REFIID riid, LPVOID * ppv); +ULONG WINAPI MemInputPin_AddRef(IMemInputPin * iface); +ULONG WINAPI MemInputPin_Release(IMemInputPin * iface); +HRESULT WINAPI MemInputPin_GetAllocator(IMemInputPin * iface, IMemAllocator ** ppAllocator); +HRESULT WINAPI MemInputPin_NotifyAllocator(IMemInputPin * iface, IMemAllocator * pAllocator, BOOL bReadOnly); +HRESULT WINAPI MemInputPin_GetAllocatorRequirements(IMemInputPin * iface, ALLOCATOR_PROPERTIES * pProps); +HRESULT WINAPI MemInputPin_Receive(IMemInputPin * iface, IMediaSample * pSample); +HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin * iface, IMediaSample ** pSamples, long nSamples, long *nSamplesProcessed); +HRESULT WINAPI MemInputPin_ReceiveCanBlock(IMemInputPin * iface); + +/* Pull Pin */ +HRESULT WINAPI PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt); +HRESULT WINAPI PullPin_Disconnect(IPin * iface); +HRESULT WINAPI PullPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv); +ULONG WINAPI PullPin_Release(IPin * iface); +HRESULT WINAPI PullPin_EndOfStream(IPin * iface); +HRESULT WINAPI PullPin_BeginFlush(IPin * iface); +HRESULT WINAPI PullPin_EndFlush(IPin * iface); +HRESULT WINAPI PullPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); + +/* Thread interaction functions: Hold the thread_lock before calling them */ +HRESULT PullPin_StartProcessing(PullPin * This); +HRESULT PullPin_PauseProcessing(PullPin * This); +HRESULT PullPin_WaitForStateChange(PullPin * This, DWORD dwMilliseconds); diff --git a/include/strmbase/strmbase.h b/include/strmbase/strmbase.h new file mode 100644 index 0000000..3becd46 --- /dev/null +++ b/include/strmbase/strmbase.h @@ -0,0 +1,26 @@ +/* + * Generic header that includes all other headers + * + * Copyright 2008 Google (Maarten Lankhorst) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "strmbase/misc.h" +#include "strmbase/control.h" +#include "strmbase/pin.h" +#include "strmbase/transform.h" +#include "strmbase/parser.h" + diff --git a/include/strmbase/transform.h b/include/strmbase/transform.h new file mode 100644 index 0000000..cb1de55 --- /dev/null +++ b/include/strmbase/transform.h @@ -0,0 +1,51 @@ +/* + * Transform Filter 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +typedef struct TransformFilterImpl TransformFilterImpl; + +typedef struct TransformFuncsTable { + HRESULT (*pfnProcessBegin) (TransformFilterImpl* This); + HRESULT (*pfnProcessSampleData) (TransformFilterImpl* This, IMediaSample *pSample); + HRESULT (*pfnProcessEnd) (TransformFilterImpl* This); + HRESULT (*pfnQueryConnect) (TransformFilterImpl* This, const AM_MEDIA_TYPE * pmt); + HRESULT (*pfnConnectInput) (TransformFilterImpl* This, const AM_MEDIA_TYPE * pmt); + HRESULT (*pfnCleanup) (TransformFilterImpl* This); +} TransformFuncsTable; + +struct TransformFilterImpl +{ + const IBaseFilterVtbl * lpVtbl; + + LONG refCount; + CRITICAL_SECTION csFilter; + FILTER_STATE state; + REFERENCE_TIME rtStreamStart; + IReferenceClock * pClock; + FILTER_INFO filterInfo; + CLSID clsid; + struct MediaSeekingImpl mediaSeeking; + + IPin ** ppPins; + AM_MEDIA_TYPE pmt; + + const TransformFuncsTable * pFuncsTable; +}; + +HRESULT TransformFilter_Create(TransformFilterImpl*, const CLSID*, const TransformFuncsTable* pFuncsTable, CHANGEPROC stop, CHANGEPROC current, CHANGEPROC rate); -- 1.5.4.1