Started Implementing Video Renderer.
Started Implementing WAVE/AU/AIFF Parser.
Started Implementing file source.
Fixed some bugs.
diff --git a/dlls/quartz/Makefile.in b/dlls/quartz/Makefile.in
index dd9a5d4..2075644 100644
--- a/dlls/quartz/Makefile.in
+++ b/dlls/quartz/Makefile.in
@@ -10,6 +10,7 @@
C_SRCS = \
amundoc.c \
+ asyncsrc.c \
audren.c \
basefilt.c \
basepin.c \
@@ -34,10 +35,13 @@
main.c \
memalloc.c \
mtype.c \
+ parser.c \
regsvr.c \
sample.c \
seekpass.c \
- sysclock.c
+ sysclock.c \
+ vidren.c \
+ wavparse.c
@MAKE_DLL_RULES@
diff --git a/dlls/quartz/asyncsrc.c b/dlls/quartz/asyncsrc.c
new file mode 100644
index 0000000..a5cd0d0
--- /dev/null
+++ b/dlls/quartz/asyncsrc.c
@@ -0,0 +1,840 @@
+/*
+ * Implements Asynchronous File/URL Source.
+ *
+ * FIXME - not work yet.
+ *
+ * hidenori@a2.ctktv.ne.jp
+ */
+
+#include "config.h"
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winerror.h"
+#include "wine/obj_base.h"
+#include "strmif.h"
+#include "vfwmsgs.h"
+#include "uuids.h"
+
+#include "debugtools.h"
+DEFAULT_DEBUG_CHANNEL(quartz);
+
+#include "quartz_private.h"
+#include "asyncsrc.h"
+#include "memalloc.h"
+
+
+/***************************************************************************
+ *
+ * CAsyncReaderImpl internal methods
+ *
+ */
+
+static DWORD WINAPI
+CAsyncReaderImpl_ThreadEntry( LPVOID pv )
+{
+ CAsyncReaderImpl* This = (CAsyncReaderImpl*)pv;
+ HANDLE hWaitEvents[2];
+ HANDLE hReadEvents[2];
+ DWORD dwRes;
+
+ SetEvent( This->m_hEventInit );
+
+ hWaitEvents[0] = This->m_hEventReqQueued;
+ hWaitEvents[1] = This->m_hEventAbort;
+
+ hReadEvents[0] = This->m_hEventSampQueued;
+ hReadEvents[1] = This->m_hEventAbort;
+
+ while ( 1 )
+ {
+ dwRes = WaitForMultipleObjects(2,hWaitEvents,FALSE,INFINITE);
+ if ( dwRes != WAIT_OBJECT_0 )
+ break;
+
+ /* FIXME - process a queued request */
+
+ dwRes = WaitForMultipleObjects(2,hReadEvents,FALSE,INFINITE);
+ if ( dwRes != WAIT_OBJECT_0 )
+ break;
+ }
+
+ return 0;
+}
+
+static HRESULT
+CAsyncReaderImpl_BeginThread( CAsyncReaderImpl* This )
+{
+ DWORD dwRes;
+ DWORD dwThreadId;
+ HANDLE hEvents[2];
+
+ if ( This->m_hEventInit != (HANDLE)NULL ||
+ This->m_hEventAbort != (HANDLE)NULL ||
+ This->m_hEventReqQueued != (HANDLE)NULL ||
+ This->m_hEventSampQueued != (HANDLE)NULL ||
+ This->m_hEventCompletion != (HANDLE)NULL ||
+ This->m_hThread != (HANDLE)NULL )
+ return E_UNEXPECTED;
+
+ This->m_hEventInit = CreateEventA(NULL,TRUE,FALSE,NULL);
+ if ( This->m_hEventInit == (HANDLE)NULL )
+ return E_OUTOFMEMORY;
+ This->m_hEventAbort = CreateEventA(NULL,TRUE,FALSE,NULL);
+ if ( This->m_hEventAbort == (HANDLE)NULL )
+ return E_OUTOFMEMORY;
+ This->m_hEventReqQueued = CreateEventA(NULL,TRUE,FALSE,NULL);
+ if ( This->m_hEventReqQueued == (HANDLE)NULL )
+ return E_OUTOFMEMORY;
+ This->m_hEventSampQueued = CreateEventA(NULL,TRUE,FALSE,NULL);
+ if ( This->m_hEventSampQueued == (HANDLE)NULL )
+ return E_OUTOFMEMORY;
+ This->m_hEventCompletion = CreateEventA(NULL,TRUE,FALSE,NULL);
+ if ( This->m_hEventCompletion == (HANDLE)NULL )
+ return E_OUTOFMEMORY;
+
+ /* create the processing thread. */
+ This->m_hThread = CreateThread(
+ NULL, 0,
+ CAsyncReaderImpl_ThreadEntry,
+ (LPVOID)This,
+ 0, &dwThreadId );
+ if ( This->m_hThread == (HANDLE)NULL )
+ return E_FAIL;
+
+ hEvents[0] = This->m_hEventInit;
+ hEvents[1] = This->m_hThread;
+
+ dwRes = WaitForMultipleObjects(2,hEvents,FALSE,INFINITE);
+ if ( dwRes != WAIT_OBJECT_0 )
+ return E_FAIL;
+
+ return NOERROR;
+}
+
+static void
+CAsyncReaderImpl_EndThread( CAsyncReaderImpl* This )
+{
+ if ( This->m_hThread != (HANDLE)NULL )
+ {
+ SetEvent( This->m_hEventAbort );
+
+ WaitForSingleObject( This->m_hThread, INFINITE );
+ CloseHandle( This->m_hThread );
+ This->m_hThread = (HANDLE)NULL;
+ }
+ if ( This->m_hEventInit != (HANDLE)NULL )
+ {
+ CloseHandle( This->m_hEventInit );
+ This->m_hEventInit = (HANDLE)NULL;
+ }
+ if ( This->m_hEventAbort != (HANDLE)NULL )
+ {
+ CloseHandle( This->m_hEventAbort );
+ This->m_hEventAbort = (HANDLE)NULL;
+ }
+ if ( This->m_hEventReqQueued != (HANDLE)NULL )
+ {
+ CloseHandle( This->m_hEventReqQueued );
+ This->m_hEventReqQueued = (HANDLE)NULL;
+ }
+ if ( This->m_hEventSampQueued != (HANDLE)NULL )
+ {
+ CloseHandle( This->m_hEventSampQueued );
+ This->m_hEventSampQueued = (HANDLE)NULL;
+ }
+ if ( This->m_hEventCompletion != (HANDLE)NULL )
+ {
+ CloseHandle( This->m_hEventCompletion );
+ This->m_hEventCompletion = (HANDLE)NULL;
+ }
+}
+
+/***************************************************************************
+ *
+ * CAsyncReaderImpl methods
+ *
+ */
+
+static HRESULT WINAPI
+CAsyncReaderImpl_fnQueryInterface(IAsyncReader* iface,REFIID riid,void** ppobj)
+{
+ ICOM_THIS(CAsyncReaderImpl,iface);
+
+ TRACE("(%p)->()\n",This);
+
+ return IUnknown_QueryInterface(This->punkControl,riid,ppobj);
+}
+
+static ULONG WINAPI
+CAsyncReaderImpl_fnAddRef(IAsyncReader* iface)
+{
+ ICOM_THIS(CAsyncReaderImpl,iface);
+
+ TRACE("(%p)->()\n",This);
+
+ return IUnknown_AddRef(This->punkControl);
+}
+
+static ULONG WINAPI
+CAsyncReaderImpl_fnRelease(IAsyncReader* iface)
+{
+ ICOM_THIS(CAsyncReaderImpl,iface);
+
+ TRACE("(%p)->()\n",This);
+
+ return IUnknown_Release(This->punkControl);
+}
+
+static HRESULT WINAPI
+CAsyncReaderImpl_fnRequestAllocator(IAsyncReader* iface,IMemAllocator* pAlloc,ALLOCATOR_PROPERTIES* pProp,IMemAllocator** ppAllocActual)
+{
+ ICOM_THIS(CAsyncReaderImpl,iface);
+ HRESULT hr;
+ ALLOCATOR_PROPERTIES propActual;
+ IUnknown* punk = NULL;
+
+ TRACE("(%p)->(%p,%p,%p)\n",This,pAlloc,pProp,ppAllocActual);
+
+ if ( pAlloc == NULL || pProp == NULL || ppAllocActual == NULL )
+ return E_POINTER;
+
+ IMemAllocator_AddRef(pAlloc);
+ hr = IMemAllocator_SetProperties( pAlloc, pProp, &propActual );
+ if ( SUCCEEDED(hr) )
+ {
+ *ppAllocActual = pAlloc;
+ return S_OK;
+ }
+ IMemAllocator_Release(pAlloc);
+
+ hr = QUARTZ_CreateMemoryAllocator(NULL,(void**)&punk);
+ if ( FAILED(hr) )
+ return hr;
+ hr = IUnknown_QueryInterface( punk, &IID_IMemAllocator, (void**)&pAlloc );
+ IUnknown_Release(punk);
+ if ( FAILED(hr) )
+ return hr;
+
+ hr = IMemAllocator_SetProperties( pAlloc, pProp, &propActual );
+ if ( SUCCEEDED(hr) )
+ {
+ *ppAllocActual = pAlloc;
+ return S_OK;
+ }
+ IMemAllocator_Release(pAlloc);
+
+ return hr;
+}
+
+static HRESULT WINAPI
+CAsyncReaderImpl_fnRequest(IAsyncReader* iface,IMediaSample* pSample,DWORD_PTR dwContext)
+{
+ ICOM_THIS(CAsyncReaderImpl,iface);
+
+ FIXME("(%p)->() stub!\n",This);
+
+ EnterCriticalSection( This->pcsReader );
+ LeaveCriticalSection( This->pcsReader );
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+CAsyncReaderImpl_fnWaitForNext(IAsyncReader* iface,DWORD dwTimeout,IMediaSample** pSample,DWORD_PTR* pdwContext)
+{
+ ICOM_THIS(CAsyncReaderImpl,iface);
+
+ FIXME("(%p)->() stub!\n",This);
+
+ EnterCriticalSection( This->pcsReader );
+ LeaveCriticalSection( This->pcsReader );
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+CAsyncReaderImpl_fnSyncReadAligned(IAsyncReader* iface,IMediaSample* pSample)
+{
+ ICOM_THIS(CAsyncReaderImpl,iface);
+
+ FIXME("(%p)->() stub!\n",This);
+
+ EnterCriticalSection( This->pcsReader );
+ LeaveCriticalSection( This->pcsReader );
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+CAsyncReaderImpl_fnSyncRead(IAsyncReader* iface,LONGLONG llPosStart,LONG lLength,BYTE* pbBuf)
+{
+ ICOM_THIS(CAsyncReaderImpl,iface);
+
+ FIXME("(%p)->() stub!\n",This);
+
+ EnterCriticalSection( This->pcsReader );
+ LeaveCriticalSection( This->pcsReader );
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+CAsyncReaderImpl_fnLength(IAsyncReader* iface,LONGLONG* pllTotal,LONGLONG* pllAvailable)
+{
+ ICOM_THIS(CAsyncReaderImpl,iface);
+ HRESULT hr;
+
+ TRACE("(%p)->()\n",This);
+
+ EnterCriticalSection( This->pcsReader );
+ hr = This->pSource->m_pHandler->pGetLength( This->pSource, pllTotal, pllAvailable );
+ LeaveCriticalSection( This->pcsReader );
+
+ return hr;
+}
+
+static HRESULT WINAPI
+CAsyncReaderImpl_fnBeginFlush(IAsyncReader* iface)
+{
+ ICOM_THIS(CAsyncReaderImpl,iface);
+
+ FIXME("(%p)->() stub!\n",This);
+
+ EnterCriticalSection( This->pcsReader );
+ LeaveCriticalSection( This->pcsReader );
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+CAsyncReaderImpl_fnEndFlush(IAsyncReader* iface)
+{
+ ICOM_THIS(CAsyncReaderImpl,iface);
+
+ FIXME("(%p)->() stub!\n",This);
+
+ EnterCriticalSection( This->pcsReader );
+ LeaveCriticalSection( This->pcsReader );
+
+ return E_NOTIMPL;
+}
+
+
+static ICOM_VTABLE(IAsyncReader) iasyncreader =
+{
+ ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+ /* IUnknown fields */
+ CAsyncReaderImpl_fnQueryInterface,
+ CAsyncReaderImpl_fnAddRef,
+ CAsyncReaderImpl_fnRelease,
+
+ /* IAsyncReader fields */
+ CAsyncReaderImpl_fnRequestAllocator,
+ CAsyncReaderImpl_fnRequest,
+ CAsyncReaderImpl_fnWaitForNext,
+ CAsyncReaderImpl_fnSyncReadAligned,
+ CAsyncReaderImpl_fnSyncRead,
+ CAsyncReaderImpl_fnLength,
+ CAsyncReaderImpl_fnBeginFlush,
+ CAsyncReaderImpl_fnEndFlush,
+};
+
+HRESULT CAsyncReaderImpl_InitIAsyncReader(
+ CAsyncReaderImpl* This, IUnknown* punkControl,
+ CAsyncSourceImpl* pSource,
+ CRITICAL_SECTION* pcsReader )
+{
+ TRACE("(%p,%p)\n",This,punkControl);
+
+ if ( punkControl == NULL )
+ {
+ ERR( "punkControl must not be NULL\n" );
+ return E_INVALIDARG;
+ }
+
+ ICOM_VTBL(This) = &iasyncreader;
+ This->punkControl = punkControl;
+ This->pSource = pSource;
+ This->pcsReader = pcsReader;
+ This->m_hEventInit = (HANDLE)NULL;
+ This->m_hEventAbort = (HANDLE)NULL;
+ This->m_hEventReqQueued = (HANDLE)NULL;
+ This->m_hEventSampQueued = (HANDLE)NULL;
+ This->m_hEventCompletion = (HANDLE)NULL;
+ This->m_hThread = (HANDLE)NULL;
+
+ return NOERROR;
+}
+
+void CAsyncReaderImpl_UninitIAsyncReader(
+ CAsyncReaderImpl* This )
+{
+ TRACE("(%p)\n",This);
+}
+
+/***************************************************************************
+ *
+ * CFileSourceFilterImpl
+ *
+ */
+
+static HRESULT WINAPI
+CFileSourceFilterImpl_fnQueryInterface(IFileSourceFilter* iface,REFIID riid,void** ppobj)
+{
+ ICOM_THIS(CFileSourceFilterImpl,iface);
+
+ TRACE("(%p)->()\n",This);
+
+ return IUnknown_QueryInterface(This->punkControl,riid,ppobj);
+}
+
+static ULONG WINAPI
+CFileSourceFilterImpl_fnAddRef(IFileSourceFilter* iface)
+{
+ ICOM_THIS(CFileSourceFilterImpl,iface);
+
+ TRACE("(%p)->()\n",This);
+
+ return IUnknown_AddRef(This->punkControl);
+}
+
+static ULONG WINAPI
+CFileSourceFilterImpl_fnRelease(IFileSourceFilter* iface)
+{
+ ICOM_THIS(CFileSourceFilterImpl,iface);
+
+ TRACE("(%p)->()\n",This);
+
+ return IUnknown_Release(This->punkControl);
+}
+
+static HRESULT WINAPI
+CFileSourceFilterImpl_fnLoad(IFileSourceFilter* iface,LPCOLESTR pFileName,const AM_MEDIA_TYPE* pmt)
+{
+ ICOM_THIS(CFileSourceFilterImpl,iface);
+ HRESULT hr;
+
+ TRACE("(%p)->(%s,%p)\n",This,debugstr_w(pFileName),pmt);
+
+ if ( pFileName == NULL )
+ return E_POINTER;
+
+ if ( This->m_pwszFileName != NULL )
+ return E_UNEXPECTED;
+
+ This->m_cbFileName = sizeof(WCHAR)*(lstrlenW(pFileName)+1);
+ This->m_pwszFileName = (WCHAR*)QUARTZ_AllocMem( This->m_cbFileName );
+ if ( This->m_pwszFileName == NULL )
+ return E_OUTOFMEMORY;
+ memcpy( This->m_pwszFileName, pFileName, This->m_cbFileName );
+
+ if ( pmt != NULL )
+ {
+ hr = QUARTZ_MediaType_Copy( &This->m_mt, pmt );
+ if ( FAILED(hr) )
+ goto err;
+ }
+ else
+ {
+ ZeroMemory( &This->m_mt, sizeof(AM_MEDIA_TYPE) );
+ memcpy( &This->m_mt.majortype, &MEDIATYPE_Stream, sizeof(GUID) );
+ memcpy( &This->m_mt.subtype, &MEDIASUBTYPE_NULL, sizeof(GUID) );
+ This->m_mt.lSampleSize = 1;
+ memcpy( &This->m_mt.formattype, &FORMAT_None, sizeof(GUID) );
+ }
+
+ hr = This->pSource->m_pHandler->pLoad( This->pSource, pFileName );
+ if ( FAILED(hr) )
+ goto err;
+
+ return NOERROR;
+err:;
+ return hr;
+}
+
+static HRESULT WINAPI
+CFileSourceFilterImpl_fnGetCurFile(IFileSourceFilter* iface,LPOLESTR* ppFileName,AM_MEDIA_TYPE* pmt)
+{
+ ICOM_THIS(CFileSourceFilterImpl,iface);
+ HRESULT hr = E_NOTIMPL;
+
+ TRACE("(%p)->(%p,%p)\n",This,ppFileName,pmt);
+
+ if ( ppFileName == NULL || pmt == NULL )
+ return E_POINTER;
+
+ if ( This->m_pwszFileName == NULL )
+ return E_FAIL;
+
+ hr = QUARTZ_MediaType_Copy( pmt, &This->m_mt );
+ if ( FAILED(hr) )
+ return hr;
+
+ *ppFileName = (WCHAR*)CoTaskMemAlloc( This->m_cbFileName );
+ if ( *ppFileName == NULL )
+ {
+ QUARTZ_MediaType_Free(pmt);
+ ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
+ return E_OUTOFMEMORY;
+ }
+
+ memcpy( *ppFileName, This->m_pwszFileName, This->m_cbFileName );
+
+ return NOERROR;
+}
+
+static ICOM_VTABLE(IFileSourceFilter) ifilesource =
+{
+ ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+ /* IUnknown fields */
+ CFileSourceFilterImpl_fnQueryInterface,
+ CFileSourceFilterImpl_fnAddRef,
+ CFileSourceFilterImpl_fnRelease,
+ /* IFileSourceFilter fields */
+ CFileSourceFilterImpl_fnLoad,
+ CFileSourceFilterImpl_fnGetCurFile,
+};
+
+HRESULT CFileSourceFilterImpl_InitIFileSourceFilter(
+ CFileSourceFilterImpl* This, IUnknown* punkControl,
+ CAsyncSourceImpl* pSource,
+ CRITICAL_SECTION* pcsFileSource )
+{
+ TRACE("(%p,%p)\n",This,punkControl);
+
+ if ( punkControl == NULL )
+ {
+ ERR( "punkControl must not be NULL\n" );
+ return E_INVALIDARG;
+ }
+
+ ICOM_VTBL(This) = &ifilesource;
+ This->punkControl = punkControl;
+ This->pSource = pSource;
+ This->pcsFileSource = pcsFileSource;
+ This->m_pwszFileName = NULL;
+ This->m_cbFileName = 0;
+ ZeroMemory( &This->m_mt, sizeof(AM_MEDIA_TYPE) );
+
+ return NOERROR;
+}
+
+void CFileSourceFilterImpl_UninitIFileSourceFilter(
+ CFileSourceFilterImpl* This )
+{
+ TRACE("(%p)\n",This);
+
+ This->pSource->m_pHandler->pCleanup( This->pSource );
+ if ( This->m_pwszFileName != NULL )
+ QUARTZ_FreeMem( This->m_pwszFileName );
+ QUARTZ_MediaType_Free( &This->m_mt );
+}
+
+/***************************************************************************
+ *
+ * CAsyncSourcePinImpl methods
+ *
+ */
+
+
+static HRESULT CAsyncSourcePinImpl_OnPreConnect( CPinBaseImpl* pImpl, IPin* pPin )
+{
+ CAsyncSourcePinImpl_THIS(pImpl,pin);
+
+ This->bAsyncReaderQueried = FALSE;
+
+ return NOERROR;
+}
+
+static HRESULT CAsyncSourcePinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin )
+{
+ CAsyncSourcePinImpl_THIS(pImpl,pin);
+
+ if ( !This->bAsyncReaderQueried )
+ return E_FAIL;
+
+ return NOERROR;
+}
+
+static HRESULT CAsyncSourcePinImpl_OnDisconnect( CPinBaseImpl* pImpl )
+{
+ CAsyncSourcePinImpl_THIS(pImpl,pin);
+
+ This->bAsyncReaderQueried = FALSE;
+
+ return NOERROR;
+}
+
+static HRESULT CAsyncSourcePinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
+{
+ CAsyncSourcePinImpl_THIS(pImpl,pin);
+
+ TRACE("(%p,%p)\n",This,pmt);
+ if ( pmt == NULL )
+ return E_POINTER;
+
+ if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Stream ) )
+ return E_FAIL;
+
+ return NOERROR;
+}
+
+static const CBasePinHandlers outputpinhandlers =
+{
+ CAsyncSourcePinImpl_OnPreConnect, /* pOnPreConnect */
+ CAsyncSourcePinImpl_OnPostConnect, /* pOnPostConnect */
+ CAsyncSourcePinImpl_OnDisconnect, /* pOnDisconnect */
+ CAsyncSourcePinImpl_CheckMediaType, /* pCheckMediaType */
+ NULL, /* pQualityNotify */
+ NULL, /* pReceive */
+ NULL, /* pReceiveCanBlock */
+ NULL, /* pEndOfStream */
+ NULL, /* pBeginFlush */
+ NULL, /* pEndFlush */
+ NULL, /* pNewSegment */
+};
+
+/***************************************************************************
+ *
+ * CAsyncSourceImpl methods
+ *
+ */
+
+static HRESULT CAsyncSourceImpl_OnActive( CBaseFilterImpl* pImpl )
+{
+ CAsyncSourceImpl_THIS(pImpl,basefilter);
+ HRESULT hr;
+
+ TRACE( "(%p)\n", This );
+
+ hr = CAsyncReaderImpl_BeginThread(&This->pPin->async);
+ if ( FAILED(hr) )
+ return hr;
+
+ return NOERROR;
+}
+
+static HRESULT CAsyncSourceImpl_OnInactive( CBaseFilterImpl* pImpl )
+{
+ CAsyncSourceImpl_THIS(pImpl,basefilter);
+
+ TRACE( "(%p)\n", This );
+
+ CAsyncReaderImpl_EndThread(&This->pPin->async);
+
+ return NOERROR;
+}
+
+static const CBaseFilterHandlers filterhandlers =
+{
+ CAsyncSourceImpl_OnActive, /* pOnActive */
+ CAsyncSourceImpl_OnInactive, /* pOnInactive */
+ NULL, /* pOnStop */
+};
+
+/***************************************************************************
+ *
+ * new/delete CAsyncSourceImpl
+ *
+ */
+
+/* can I use offsetof safely? - FIXME? */
+static QUARTZ_IFEntry FilterIFEntries[] =
+{
+ { &IID_IPersist, offsetof(CAsyncSourceImpl,basefilter)-offsetof(CAsyncSourceImpl,unk) },
+ { &IID_IMediaFilter, offsetof(CAsyncSourceImpl,basefilter)-offsetof(CAsyncSourceImpl,unk) },
+ { &IID_IBaseFilter, offsetof(CAsyncSourceImpl,basefilter)-offsetof(CAsyncSourceImpl,unk) },
+ { &IID_IFileSourceFilter, offsetof(CAsyncSourceImpl,filesrc)-offsetof(CAsyncSourceImpl,unk) },
+};
+
+static void QUARTZ_DestroyAsyncSource(IUnknown* punk)
+{
+ CAsyncSourceImpl_THIS(punk,unk);
+
+ TRACE( "(%p)\n", This );
+
+ if ( This->pPin != NULL )
+ {
+ IUnknown_Release(This->pPin->unk.punkControl);
+ This->pPin = NULL;
+ }
+
+ This->m_pHandler->pCleanup( This );
+
+ CFileSourceFilterImpl_UninitIFileSourceFilter(&This->filesrc);
+ CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
+
+ DeleteCriticalSection( &This->csFilter );
+}
+
+HRESULT QUARTZ_CreateAsyncSource(
+ IUnknown* punkOuter,void** ppobj,
+ const CLSID* pclsidAsyncSource,
+ LPCWSTR pwszAsyncSourceName,
+ LPCWSTR pwszOutPinName,
+ const AsyncSourceHandlers* pHandler )
+{
+ CAsyncSourceImpl* This = NULL;
+ HRESULT hr;
+
+ TRACE("(%p,%p)\n",punkOuter,ppobj);
+
+ This = (CAsyncSourceImpl*)
+ QUARTZ_AllocObj( sizeof(CAsyncSourceImpl) );
+ if ( This == NULL )
+ return E_OUTOFMEMORY;
+
+ This->pPin = NULL;
+ This->m_pHandler = pHandler;
+ This->m_pUserData = NULL;
+
+ QUARTZ_IUnkInit( &This->unk, punkOuter );
+
+ hr = CBaseFilterImpl_InitIBaseFilter(
+ &This->basefilter,
+ This->unk.punkControl,
+ pclsidAsyncSource,
+ pwszAsyncSourceName,
+ &filterhandlers );
+ if ( SUCCEEDED(hr) )
+ {
+ /* construct this class. */
+ hr = CFileSourceFilterImpl_InitIFileSourceFilter(
+ &This->filesrc, This->unk.punkControl,
+ This, &This->csFilter );
+ if ( FAILED(hr) )
+ {
+ CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
+ }
+ }
+
+ if ( FAILED(hr) )
+ {
+ QUARTZ_FreeObj(This);
+ return hr;
+ }
+
+ This->unk.pEntries = FilterIFEntries;
+ This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]);
+ This->unk.pOnFinalRelease = QUARTZ_DestroyAsyncSource;
+ InitializeCriticalSection( &This->csFilter );
+
+ /* create the output pin. */
+ hr = S_OK;
+
+ if ( FAILED(hr) )
+ {
+ IUnknown_Release( This->unk.punkControl );
+ return hr;
+ }
+
+ *ppobj = (void*)&(This->unk);
+
+ return S_OK;
+}
+
+/***************************************************************************
+ *
+ * new/delete CAsyncSourcePinImpl
+ *
+ */
+
+/* can I use offsetof safely? - FIXME? */
+static QUARTZ_IFEntry OutPinIFEntries[] =
+{
+ { &IID_IPin, offsetof(CAsyncSourcePinImpl,pin)-offsetof(CAsyncSourcePinImpl,unk) },
+ /***{ &IID_IAsyncReader, offsetof(CAsyncSourcePinImpl,async)-offsetof(CAsyncSourcePinImpl,unk) },***/
+};
+
+static HRESULT CAsyncSourceImpl_OnQueryInterface(
+ IUnknown* punk, const IID* piid, void** ppobj )
+{
+ CAsyncSourcePinImpl_THIS(punk,unk);
+
+ if ( IsEqualGUID( &IID_IAsyncReader, piid ) )
+ {
+ *ppobj = (void*)&This->async;
+ IUnknown_AddRef(punk);
+ This->bAsyncReaderQueried = TRUE;
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+static void QUARTZ_DestroyAsyncSourcePin(IUnknown* punk)
+{
+ CAsyncSourcePinImpl_THIS(punk,unk);
+
+ TRACE( "(%p)\n", This );
+
+ CAsyncReaderImpl_UninitIAsyncReader( &This->async );
+ CPinBaseImpl_UninitIPin( &This->pin );
+}
+
+HRESULT QUARTZ_CreateAsyncSourcePin(
+ CAsyncSourceImpl* pFilter,
+ CRITICAL_SECTION* pcsPin,
+ CAsyncSourcePinImpl** ppPin,
+ LPCWSTR pwszPinName )
+{
+ CAsyncSourcePinImpl* This = NULL;
+ HRESULT hr;
+
+ TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
+
+ This = (CAsyncSourcePinImpl*)
+ QUARTZ_AllocObj( sizeof(CAsyncSourcePinImpl) );
+ if ( This == NULL )
+ return E_OUTOFMEMORY;
+
+ QUARTZ_IUnkInit( &This->unk, NULL );
+ This->qiext.pNext = NULL;
+ This->qiext.pOnQueryInterface = &CAsyncSourceImpl_OnQueryInterface;
+ QUARTZ_IUnkAddDelegation( &This->unk, &This->qiext );
+
+ This->bAsyncReaderQueried = FALSE;
+ This->pSource = pFilter;
+
+ hr = CPinBaseImpl_InitIPin(
+ &This->pin,
+ This->unk.punkControl,
+ pcsPin,
+ &pFilter->basefilter,
+ pwszPinName,
+ TRUE,
+ &outputpinhandlers );
+
+ if ( SUCCEEDED(hr) )
+ {
+ hr = CAsyncReaderImpl_InitIAsyncReader(
+ &This->async,
+ This->unk.punkControl,
+ pFilter,
+ pcsPin );
+ if ( FAILED(hr) )
+ {
+ CPinBaseImpl_UninitIPin( &This->pin );
+ }
+ }
+
+ if ( FAILED(hr) )
+ {
+ QUARTZ_FreeObj(This);
+ return hr;
+ }
+
+ This->unk.pEntries = OutPinIFEntries;
+ This->unk.dwEntries = sizeof(OutPinIFEntries)/sizeof(OutPinIFEntries[0]);
+ This->unk.pOnFinalRelease = QUARTZ_DestroyAsyncSourcePin;
+
+ *ppPin = This;
+
+ TRACE("returned successfully.\n");
+
+ return S_OK;
+}
+
diff --git a/dlls/quartz/asyncsrc.h b/dlls/quartz/asyncsrc.h
new file mode 100644
index 0000000..57e769d
--- /dev/null
+++ b/dlls/quartz/asyncsrc.h
@@ -0,0 +1,115 @@
+/*
+ * Implements Asynchronous File/URL Source.
+ *
+ * hidenori@a2.ctktv.ne.jp
+ */
+
+#ifndef WINE_DSHOW_ASYNCSRC_H
+#define WINE_DSHOW_ASYNCSRC_H
+
+#include "iunk.h"
+#include "basefilt.h"
+
+typedef struct CAsyncSourceImpl CAsyncSourceImpl;
+typedef struct CAsyncSourcePinImpl CAsyncSourcePinImpl;
+typedef struct AsyncSourceHandlers AsyncSourceHandlers;
+
+typedef struct CAsyncReaderImpl
+{
+ ICOM_VFIELD(IAsyncReader);
+
+ /* IUnknown fields */
+ IUnknown* punkControl;
+ /* IAsyncReader fields */
+ CAsyncSourceImpl* pSource;
+
+ CRITICAL_SECTION* pcsReader;
+ HANDLE m_hEventInit;
+ HANDLE m_hEventAbort;
+ HANDLE m_hEventReqQueued;
+ HANDLE m_hEventSampQueued;
+ HANDLE m_hEventCompletion;
+ HANDLE m_hThread;
+} CAsyncReaderImpl;
+
+typedef struct CFileSourceFilterImpl
+{
+ ICOM_VFIELD(IFileSourceFilter);
+
+ /* IUnknown fields */
+ IUnknown* punkControl;
+ /* IFileSourceFilter fields */
+ CAsyncSourceImpl* pSource;
+
+ CRITICAL_SECTION* pcsFileSource;
+ WCHAR* m_pwszFileName;
+ DWORD m_cbFileName;
+ AM_MEDIA_TYPE m_mt;
+} CFileSourceFilterImpl;
+
+struct CAsyncSourceImpl
+{
+ QUARTZ_IUnkImpl unk;
+ CBaseFilterImpl basefilter;
+ CFileSourceFilterImpl filesrc;
+
+ CRITICAL_SECTION csFilter;
+ CAsyncSourcePinImpl* pPin;
+ const AsyncSourceHandlers* m_pHandler;
+ void* m_pUserData;
+};
+
+struct CAsyncSourcePinImpl
+{
+ QUARTZ_IUnkImpl unk;
+ CPinBaseImpl pin;
+ CAsyncReaderImpl async;
+ QUARTZ_IFDelegation qiext;
+
+ BOOL bAsyncReaderQueried;
+ CAsyncSourceImpl* pSource;
+};
+
+struct AsyncSourceHandlers
+{
+ /* all handlers MUST be implemented. */
+ HRESULT (*pLoad)( CAsyncSourceImpl* pImpl, LPCWSTR lpwszSourceName );
+ HRESULT (*pCleanup)( CAsyncSourceImpl* pImpl );
+ HRESULT (*pGetLength)( CAsyncSourceImpl* pImpl, LONGLONG* pllTotal, LONGLONG* pllAvailable );
+ HRESULT (*pReadAsync)( CAsyncSourceImpl* pImpl, LONGLONG llOfsStart, LONG lLength, BYTE* pBuf, HANDLE hEventCompletion );
+ HRESULT (*pGetResult)( CAsyncSourceImpl* pImpl, LONG* plReturned );
+ HRESULT (*pCancelAsync)( CAsyncSourceImpl* pImpl );
+};
+
+#define CAsyncSourceImpl_THIS(iface,member) CAsyncSourceImpl* This = ((CAsyncSourceImpl*)(((char*)iface)-offsetof(CAsyncSourceImpl,member)))
+#define CAsyncSourcePinImpl_THIS(iface,member) CAsyncSourcePinImpl* This = ((CAsyncSourcePinImpl*)(((char*)iface)-offsetof(CAsyncSourcePinImpl,member)))
+
+
+HRESULT CAsyncReaderImpl_InitIAsyncReader(
+ CAsyncReaderImpl* This, IUnknown* punkControl,
+ CAsyncSourceImpl* pSource,
+ CRITICAL_SECTION* pcsReader );
+void CAsyncReaderImpl_UninitIAsyncReader(
+ CAsyncReaderImpl* This );
+HRESULT CFileSourceFilterImpl_InitIFileSourceFilter(
+ CFileSourceFilterImpl* This, IUnknown* punkControl,
+ CAsyncSourceImpl* pSource,
+ CRITICAL_SECTION* pcsFileSource );
+void CFileSourceFilterImpl_UninitIFileSourceFilter(
+ CFileSourceFilterImpl* This );
+
+
+HRESULT QUARTZ_CreateAsyncSource(
+ IUnknown* punkOuter,void** ppobj,
+ const CLSID* pclsidAsyncSource,
+ LPCWSTR pwszAsyncSourceName,
+ LPCWSTR pwszOutPinName,
+ const AsyncSourceHandlers* pHandler );
+HRESULT QUARTZ_CreateAsyncSourcePin(
+ CAsyncSourceImpl* pFilter,
+ CRITICAL_SECTION* pcsPin,
+ CAsyncSourcePinImpl** ppPin,
+ LPCWSTR pwszPinName );
+
+
+#endif /* WINE_DSHOW_ASYNCSRC_H */
diff --git a/dlls/quartz/audren.c b/dlls/quartz/audren.c
index 0a18103..50e613e 100644
--- a/dlls/quartz/audren.c
+++ b/dlls/quartz/audren.c
@@ -22,6 +22,7 @@
#include "control.h"
#include "vfwmsgs.h"
#include "uuids.h"
+#include "evcode.h"
#include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(quartz);
@@ -365,6 +366,7 @@
{
CAudioRendererImpl_OnActive, /* pOnActive */
CAudioRendererImpl_OnInactive, /* pOnInactive */
+ NULL, /* pOnStop */
};
/***************************************************************************
@@ -378,7 +380,7 @@
CAudioRendererPinImpl_THIS(pImpl,pin);
const WAVEFORMATEX* pwfx;
- TRACE( "(%p,%p)\n",This,pmt );
+ TRACE("(%p,%p)\n",This,pmt);
if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Audio ) )
return E_FAIL;
@@ -463,9 +465,11 @@
FIXME( "(%p)\n", This );
This->pRender->m_fInFlush = FALSE;
- /* IMediaEventSink::Notify(EC_COMPLETE) */
- return NOERROR;
+ /* FIXME - don't notify twice until stopped or seeked. */
+ return CBaseFilterImpl_MediaEventNotify(
+ &This->pRender->basefilter, EC_COMPLETE,
+ (LONG_PTR)S_OK, (LONG_PTR)(IBaseFilter*)(This->pRender) );
}
static HRESULT CAudioRendererPinImpl_BeginFlush( CPinBaseImpl* pImpl )
@@ -497,11 +501,16 @@
FIXME( "(%p)\n", This );
+ This->pRender->m_fInFlush = FALSE;
+
return NOERROR;
}
static const CBasePinHandlers pinhandlers =
{
+ NULL, /* pOnPreConnect */
+ NULL, /* pOnPostConnect */
+ NULL, /* pOnDisconnect */
CAudioRendererPinImpl_CheckMediaType, /* pCheckMediaType */
NULL, /* pQualityNotify */
CAudioRendererPinImpl_Receive, /* pReceive */
diff --git a/dlls/quartz/basefilt.c b/dlls/quartz/basefilt.c
index ef1d57e..c2db042 100644
--- a/dlls/quartz/basefilt.c
+++ b/dlls/quartz/basefilt.c
@@ -23,6 +23,13 @@
#include "basefilt.h"
#include "enumunk.h"
+
+/***************************************************************************
+ *
+ * CBaseFilterImpl::IBaseFilter
+ *
+ */
+
static HRESULT WINAPI
CBaseFilterImpl_fnQueryInterface(IBaseFilter* iface,REFIID riid,void** ppobj)
{
@@ -85,10 +92,17 @@
{
if ( This->pHandlers->pOnInactive != NULL )
hr = This->pHandlers->pOnInactive( This );
+ if ( SUCCEEDED(hr) )
+ This->fstate = State_Paused;
+ }
+ if ( This->fstate == State_Paused )
+ {
+ if ( This->pHandlers->pOnStop != NULL )
+ hr = This->pHandlers->pOnStop( This );
+ if ( SUCCEEDED(hr) )
+ This->fstate = State_Stopped;
}
- if ( SUCCEEDED(hr) )
- This->fstate = State_Stopped;
LeaveCriticalSection( &This->csFilter );
return hr;
@@ -105,16 +119,13 @@
hr = NOERROR;
EnterCriticalSection( &This->csFilter );
-
- if ( This->fstate == State_Running )
+ if ( This->fstate != State_Paused )
{
if ( This->pHandlers->pOnInactive != NULL )
hr = This->pHandlers->pOnInactive( This );
+ if ( SUCCEEDED(hr) )
+ This->fstate = State_Paused;
}
-
- if ( SUCCEEDED(hr) )
- This->fstate = State_Paused;
-
LeaveCriticalSection( &This->csFilter );
TRACE("hr = %08lx\n",hr);
@@ -136,15 +147,21 @@
This->rtStart = rtStart;
- if ( This->fstate != State_Running )
+ if ( This->fstate == State_Stopped )
+ {
+ if ( This->pHandlers->pOnInactive != NULL )
+ hr = This->pHandlers->pOnInactive( This );
+ if ( SUCCEEDED(hr) )
+ This->fstate = State_Paused;
+ }
+ if ( This->fstate == State_Paused )
{
if ( This->pHandlers->pOnActive != NULL )
hr = This->pHandlers->pOnActive( This );
+ if ( SUCCEEDED(hr) )
+ This->fstate = State_Running;
}
- if ( SUCCEEDED(hr) )
- This->fstate = State_Running;
-
LeaveCriticalSection( &This->csFilter );
return hr;
@@ -366,6 +383,11 @@
}
+/***************************************************************************
+ *
+ * construct/destruct CBaseFilterImpl
+ *
+ */
static ICOM_VTABLE(IBaseFilter) ibasefilter =
{
@@ -491,3 +513,41 @@
DeleteCriticalSection( &This->csFilter );
}
+
+/***************************************************************************
+ *
+ * CBaseFilterImpl methods
+ *
+ */
+
+HRESULT CBaseFilterImpl_MediaEventNotify(
+ CBaseFilterImpl* This, long lEvent,LONG_PTR lParam1,LONG_PTR lParam2)
+{
+ IMediaEventSink* pSink = NULL;
+ HRESULT hr = E_NOTIMPL;
+
+ EnterCriticalSection( &This->csFilter );
+
+ if ( This->pfg == NULL )
+ {
+ hr = E_UNEXPECTED;
+ goto err;
+ }
+
+ hr = IFilterGraph_QueryInterface( This->pfg, &IID_IMediaEventSink, (void**)&pSink );
+ if ( FAILED(hr) )
+ goto err;
+ if ( pSink == NULL )
+ {
+ hr = E_FAIL;
+ goto err;
+ }
+
+ hr = IMediaEventSink_Notify(pSink,lEvent,lParam1,lParam2);
+ IMediaEventSink_Release(pSink);
+err:
+ LeaveCriticalSection( &This->csFilter );
+
+ return hr;
+}
+
diff --git a/dlls/quartz/basefilt.h b/dlls/quartz/basefilt.h
index fe41a98..cee3742 100644
--- a/dlls/quartz/basefilt.h
+++ b/dlls/quartz/basefilt.h
@@ -44,6 +44,7 @@
{
HRESULT (*pOnActive)( CBaseFilterImpl* pImpl );
HRESULT (*pOnInactive)( CBaseFilterImpl* pImpl );
+ HRESULT (*pOnStop)( CBaseFilterImpl* pImpl );
};
@@ -54,12 +55,18 @@
void CBaseFilterImpl_UninitIBaseFilter( CBaseFilterImpl* This );
+HRESULT CBaseFilterImpl_MediaEventNotify(
+ CBaseFilterImpl* This, long lEvent,LONG_PTR lParam1,LONG_PTR lParam2);
+
+
/*
* Implements IPin, IMemInputPin, and IQualityControl. (internal)
*
* a base class for implementing IPin.
*/
+typedef struct OutputPinAsyncImpl OutputPinAsyncImpl;
+
typedef struct CPinBaseImpl
{
/* IPin */
@@ -80,7 +87,9 @@
CRITICAL_SECTION* pcsPin;
CBaseFilterImpl* pFilter;
IPin* pPinConnectedTo;
+ IMemInputPin* pMemInputPinConnectedTo;
AM_MEDIA_TYPE* pmtConn;
+ OutputPinAsyncImpl* pAsyncOut; /* for asynchronous output */
} CPinBaseImpl;
typedef struct CMemInputPinBaseImpl
@@ -111,6 +120,9 @@
struct CBasePinHandlers
{
+ HRESULT (*pOnPreConnect)( CPinBaseImpl* pImpl, IPin* pPin );
+ HRESULT (*pOnPostConnect)( CPinBaseImpl* pImpl, IPin* pPin );
+ HRESULT (*pOnDisconnect)( CPinBaseImpl* pImpl );
HRESULT (*pCheckMediaType)( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt );
HRESULT (*pQualityNotify)( CPinBaseImpl* pImpl, IBaseFilter* pFilter, Quality q );
HRESULT (*pReceive)( CPinBaseImpl* pImpl, IMediaSample* pSample );
@@ -146,5 +158,41 @@
CQualityControlPassThruImpl* This );
+HRESULT CPinBaseImpl_SendSample( CPinBaseImpl* This, IMediaSample* pSample );
+HRESULT CPinBaseImpl_SendEndOfStream( CPinBaseImpl* This );
+HRESULT CPinBaseImpl_SendBeginFlush( CPinBaseImpl* This );
+HRESULT CPinBaseImpl_SendEndFlush( CPinBaseImpl* This );
+HRESULT CPinBaseImpl_SendNewSegment( CPinBaseImpl* This, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate );
+
+
+/***************************************************************************
+ *
+ * handlers for output pins.
+ *
+ */
+
+HRESULT OutputPinSync_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample );
+HRESULT OutputPinSync_ReceiveCanBlock( CPinBaseImpl* pImpl );
+HRESULT OutputPinSync_EndOfStream( CPinBaseImpl* pImpl );
+HRESULT OutputPinSync_BeginFlush( CPinBaseImpl* pImpl );
+HRESULT OutputPinSync_EndFlush( CPinBaseImpl* pImpl );
+HRESULT OutputPinSync_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate );
+
+/***************************************************************************
+ *
+ * handlers for output pins (async).
+ *
+ */
+
+HRESULT OutputPinAsync_OnActive( CPinBaseImpl* pImpl );
+HRESULT OutputPinAsync_OnInactive( CPinBaseImpl* pImpl );
+HRESULT OutputPinAsync_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample );
+HRESULT OutputPinAsync_ReceiveCanBlock( CPinBaseImpl* pImpl );
+HRESULT OutputPinAsync_EndOfStream( CPinBaseImpl* pImpl );
+HRESULT OutputPinAsync_BeginFlush( CPinBaseImpl* pImpl );
+HRESULT OutputPinAsync_EndFlush( CPinBaseImpl* pImpl );
+HRESULT OutputPinAsync_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate );
+
+
#endif /* WINE_DSHOW_BASEFILT_H */
diff --git a/dlls/quartz/basepin.c b/dlls/quartz/basepin.c
index 2571135..1f809b7 100644
--- a/dlls/quartz/basepin.c
+++ b/dlls/quartz/basepin.c
@@ -71,9 +71,11 @@
if ( !This->bOutput )
return E_UNEXPECTED;
- if ( pPin == NULL || pmt == NULL )
+ if ( pPin == NULL )
return E_POINTER;
+ TRACE("try to connect to %p\n",pPin);
+
EnterCriticalSection( This->pcsPin );
if ( This->pPinConnectedTo != NULL )
@@ -84,6 +86,13 @@
/* FIXME - return fail if running */
+ if ( This->pHandlers->pOnPreConnect != NULL )
+ {
+ hr = This->pHandlers->pOnPreConnect(This,pPin);
+ if ( FAILED(hr) )
+ goto err;
+ }
+
if ( pmt != NULL )
{
hr = IPin_QueryAccept(iface,pmt);
@@ -113,9 +122,6 @@
goto err;
}
- if ( FAILED(hr) )
- goto err;
-
connected:;
This->pmtConn = QUARTZ_MediaType_Duplicate( pmt );
if ( This->pmtConn == NULL )
@@ -124,11 +130,32 @@
IPin_Disconnect(pPin);
goto err;
}
- hr = S_OK;
This->pPinConnectedTo = pPin; IPin_AddRef(pPin);
+ hr = IPin_QueryInterface(pPin,&IID_IMemInputPin,(void**)&This->pMemInputPinConnectedTo);
+ if ( FAILED(hr) )
+ {
+ IPin_Disconnect(pPin);
+ goto err;
+ }
+
+ if ( This->pHandlers->pOnPostConnect != NULL )
+ {
+ hr = This->pHandlers->pOnPostConnect(This,pPin);
+ if ( FAILED(hr) )
+ {
+ IPin_Disconnect(pPin);
+ goto err;
+ }
+ }
+
+ hr = S_OK;
err:
+ if ( FAILED(hr) )
+ {
+ IPin_Disconnect(iface);
+ }
LeaveCriticalSection( This->pcsPin );
return hr;
@@ -157,6 +184,12 @@
/* FIXME - return fail if running */
+ if ( This->pHandlers->pOnPreConnect != NULL )
+ {
+ hr = This->pHandlers->pOnPreConnect(This,pPin);
+ if ( FAILED(hr) )
+ goto err;
+ }
hr = IPin_QueryAccept(iface,pmt);
if ( FAILED(hr) )
@@ -168,10 +201,20 @@
hr = E_OUTOFMEMORY;
goto err;
}
- hr = S_OK;
+ if ( This->pHandlers->pOnPostConnect != NULL )
+ {
+ hr = This->pHandlers->pOnPostConnect(This,pPin);
+ if ( FAILED(hr) )
+ goto err;
+ }
+
+ hr = S_OK;
This->pPinConnectedTo = pPin; IPin_AddRef(pPin);
+
err:
+ if ( FAILED(hr) )
+ IPin_Disconnect(iface);
LeaveCriticalSection( This->pcsPin );
return hr;
@@ -189,16 +232,23 @@
/* FIXME - return fail if running */
+ if ( This->pHandlers->pOnDisconnect != NULL )
+ hr = This->pHandlers->pOnDisconnect(This);
+
+ if ( This->pmtConn != NULL )
+ {
+ QUARTZ_MediaType_Destroy( This->pmtConn );
+ This->pmtConn = NULL;
+ }
+ if ( This->pMemInputPinConnectedTo != NULL )
+ {
+ IMemInputPin_Release(This->pMemInputPinConnectedTo);
+ This->pMemInputPinConnectedTo = NULL;
+ }
if ( This->pPinConnectedTo != NULL )
{
/* FIXME - cleanup */
- if ( This->pmtConn != NULL )
- {
- QUARTZ_MediaType_Destroy( This->pmtConn );
- This->pmtConn = NULL;
- }
-
IPin_Release(This->pPinConnectedTo);
This->pPinConnectedTo = NULL;
hr = NOERROR;
@@ -517,7 +567,9 @@
This->pcsPin = pcsPin;
This->pFilter = pFilter;
This->pPinConnectedTo = NULL;
+ This->pMemInputPinConnectedTo = NULL;
This->pmtConn = NULL;
+ This->pAsyncOut = NULL;
This->pwszId = (WCHAR*)QUARTZ_AllocMem( This->cbIdLen );
if ( This->pwszId == NULL )
@@ -877,3 +929,463 @@
{
}
+/***************************************************************************
+ *
+ * helper methods for output pins.
+ *
+ */
+
+HRESULT CPinBaseImpl_SendSample( CPinBaseImpl* This, IMediaSample* pSample )
+{
+ if ( This->pHandlers->pReceive == NULL )
+ return E_NOTIMPL;
+
+ return This->pHandlers->pReceive( This, pSample );
+}
+
+HRESULT CPinBaseImpl_SendEndOfStream( CPinBaseImpl* This )
+{
+ if ( This->pHandlers->pEndOfStream == NULL )
+ return E_NOTIMPL;
+
+ return This->pHandlers->pEndOfStream( This );
+}
+
+HRESULT CPinBaseImpl_SendBeginFlush( CPinBaseImpl* This )
+{
+ if ( This->pHandlers->pBeginFlush == NULL )
+ return E_NOTIMPL;
+
+ return This->pHandlers->pBeginFlush( This );
+}
+
+HRESULT CPinBaseImpl_SendEndFlush( CPinBaseImpl* This )
+{
+ if ( This->pHandlers->pEndFlush == NULL )
+ return E_NOTIMPL;
+
+ return This->pHandlers->pEndFlush( This );
+}
+
+HRESULT CPinBaseImpl_SendNewSegment( CPinBaseImpl* This, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate )
+{
+ if ( This->pHandlers->pNewSegment == NULL )
+ return E_NOTIMPL;
+
+ return This->pHandlers->pNewSegment( This, rtStart, rtStop, rate );
+}
+
+
+
+/***************************************************************************
+ *
+ * handlers for output pins.
+ *
+ */
+
+HRESULT OutputPinSync_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample )
+{
+ if ( pImpl->pMemInputPinConnectedTo == NULL )
+ return E_UNEXPECTED;
+
+ return IMemInputPin_Receive(pImpl->pMemInputPinConnectedTo,pSample);
+}
+
+HRESULT OutputPinSync_ReceiveCanBlock( CPinBaseImpl* pImpl )
+{
+ if ( pImpl->pMemInputPinConnectedTo == NULL )
+ return S_FALSE;
+
+ return IMemInputPin_ReceiveCanBlock(pImpl->pMemInputPinConnectedTo);
+}
+
+HRESULT OutputPinSync_EndOfStream( CPinBaseImpl* pImpl )
+{
+ if ( pImpl->pPinConnectedTo == NULL )
+ return NOERROR;
+
+ return IPin_EndOfStream(pImpl->pPinConnectedTo);
+}
+
+HRESULT OutputPinSync_BeginFlush( CPinBaseImpl* pImpl )
+{
+ if ( pImpl->pPinConnectedTo == NULL )
+ return NOERROR;
+
+ return IPin_BeginFlush(pImpl->pPinConnectedTo);
+}
+
+HRESULT OutputPinSync_EndFlush( CPinBaseImpl* pImpl )
+{
+ if ( pImpl->pPinConnectedTo == NULL )
+ return NOERROR;
+
+ return IPin_EndFlush(pImpl->pPinConnectedTo);
+}
+
+HRESULT OutputPinSync_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate )
+{
+ if ( pImpl->pPinConnectedTo == NULL )
+ return NOERROR;
+
+ return IPin_NewSegment(pImpl->pPinConnectedTo,rtStart,rtStop,rate);
+}
+
+/***************************************************************************
+ *
+ * handlers for output pins (async).
+ *
+ */
+
+typedef struct OutputPinTask OutputPinTask;
+
+enum OutputPinTaskType
+{
+ OutTask_ExitThread,
+ OutTask_Receive,
+ OutTask_EndOfStream,
+ OutTask_BeginFlush,
+ OutTask_EndFlush,
+ OutTask_NewSegment,
+};
+
+struct OutputPinTask
+{
+ OutputPinTask* pNext;
+ enum OutputPinTaskType tasktype;
+ IMediaSample* pSample;
+ REFERENCE_TIME rtStart;
+ REFERENCE_TIME rtStop;
+ double rate;
+};
+
+struct OutputPinAsyncImpl
+{
+ HANDLE m_hTaskThread;
+ HANDLE m_hTaskEvent;
+ IPin* m_pPin; /* connected pin */
+ IMemInputPin* m_pMemInputPin; /* connected pin */
+ CRITICAL_SECTION m_csTasks;
+ OutputPinTask* m_pFirst;
+ OutputPinTask* m_pLast;
+ OutputPinTask* m_pTaskExitThread;
+};
+
+static OutputPinTask* OutputPinAsync_AllocTask( enum OutputPinTaskType tasktype )
+{
+ OutputPinTask* pTask;
+
+ pTask = (OutputPinTask*)QUARTZ_AllocMem( sizeof(OutputPinTask) );
+ pTask->pNext = NULL;
+ pTask->tasktype = tasktype;
+ pTask->pSample = NULL;
+
+ return pTask;
+}
+
+static void OutputPinAsync_FreeTask( OutputPinTask* pTask )
+{
+ if ( pTask->pSample != NULL )
+ IMediaSample_Release( pTask->pSample );
+ QUARTZ_FreeMem( pTask );
+}
+
+static void OutputPinAsync_AddTask( OutputPinAsyncImpl* This, OutputPinTask* pTask, BOOL bFirst )
+{
+ EnterCriticalSection( &This->m_csTasks );
+
+ if ( bFirst )
+ {
+ pTask->pNext = This->m_pFirst;
+ This->m_pFirst = pTask;
+ if ( This->m_pLast == NULL )
+ This->m_pLast = pTask;
+ }
+ else
+ {
+ if ( This->m_pLast != NULL )
+ This->m_pLast->pNext = pTask;
+ else
+ This->m_pFirst = pTask;
+ This->m_pLast = pTask;
+ }
+
+ LeaveCriticalSection( &This->m_csTasks );
+
+ SetEvent( This->m_hTaskEvent );
+}
+
+static OutputPinTask* OutputPinAsync_GetNextTask( OutputPinAsyncImpl* This )
+{
+ OutputPinTask* pTask;
+
+ EnterCriticalSection( &This->m_csTasks );
+ pTask = This->m_pFirst;
+ if ( pTask != NULL )
+ {
+ This->m_pFirst = pTask->pNext;
+ if ( This->m_pFirst == NULL )
+ This->m_pLast = NULL;
+ else
+ SetEvent( This->m_hTaskEvent );
+ }
+
+ LeaveCriticalSection( &This->m_csTasks );
+
+ return pTask;
+}
+
+static DWORD WINAPI OutputPinAsync_ThreadEntry( LPVOID pv )
+{
+ OutputPinAsyncImpl* This = ((CPinBaseImpl*)pv)->pAsyncOut;
+ OutputPinTask* pTask;
+ BOOL bLoop = TRUE;
+ BOOL bInFlush = FALSE;
+ HRESULT hr;
+
+ while ( bLoop )
+ {
+ WaitForSingleObject( This->m_hTaskEvent, INFINITE );
+ ResetEvent( This->m_hTaskEvent );
+
+ pTask = OutputPinAsync_GetNextTask( This );
+ if ( pTask == NULL )
+ continue;
+
+ hr = S_OK;
+ switch ( pTask->tasktype )
+ {
+ case OutTask_ExitThread:
+ bLoop = FALSE;
+ break;
+ case OutTask_Receive:
+ if ( !bInFlush )
+ hr = IMemInputPin_Receive( This->m_pMemInputPin, pTask->pSample );
+ break;
+ case OutTask_EndOfStream:
+ hr = IPin_EndOfStream( This->m_pPin );
+ break;
+ case OutTask_BeginFlush:
+ bInFlush = TRUE;
+ hr = IPin_BeginFlush( This->m_pPin );
+ break;
+ case OutTask_EndFlush:
+ bInFlush = FALSE;
+ hr = IPin_EndFlush( This->m_pPin );
+ break;
+ case OutTask_NewSegment:
+ hr = IPin_NewSegment( This->m_pPin, pTask->rtStart, pTask->rtStop, pTask->rate );
+ break;
+ default:
+ ERR( "unexpected task type %d.\n", pTask->tasktype );
+ bLoop = FALSE;
+ break;
+ }
+
+ OutputPinAsync_FreeTask( pTask );
+
+ if ( FAILED(hr) )
+ {
+ ERR( "hresult %08lx\n", hr );
+ bLoop = FALSE;
+ }
+ }
+
+ return 0;
+}
+
+HRESULT OutputPinAsync_OnActive( CPinBaseImpl* pImpl )
+{
+ HRESULT hr;
+ DWORD dwThreadId;
+
+ FIXME("(%p)\n",pImpl);
+
+ if ( pImpl->pMemInputPinConnectedTo == NULL )
+ return NOERROR;
+
+ pImpl->pAsyncOut = (OutputPinAsyncImpl*)
+ QUARTZ_AllocMem( sizeof( OutputPinAsyncImpl ) );
+ if ( pImpl->pAsyncOut == NULL )
+ return E_OUTOFMEMORY;
+
+ InitializeCriticalSection( &pImpl->pAsyncOut->m_csTasks );
+ pImpl->pAsyncOut->m_hTaskThread = (HANDLE)NULL;
+ pImpl->pAsyncOut->m_hTaskEvent = (HANDLE)NULL;
+ pImpl->pAsyncOut->m_pFirst = NULL;
+ pImpl->pAsyncOut->m_pLast = NULL;
+ pImpl->pAsyncOut->m_pTaskExitThread = NULL;
+ pImpl->pAsyncOut->m_pPin = pImpl->pPinConnectedTo;
+ pImpl->pAsyncOut->m_pMemInputPin = pImpl->pMemInputPinConnectedTo;
+
+ pImpl->pAsyncOut->m_hTaskEvent =
+ CreateEventA( NULL, TRUE, FALSE, NULL );
+ if ( pImpl->pAsyncOut->m_hTaskEvent == (HANDLE)NULL )
+ {
+ hr = E_FAIL;
+ goto err;
+ }
+
+ pImpl->pAsyncOut->m_pTaskExitThread =
+ OutputPinAsync_AllocTask( OutTask_ExitThread );
+ if ( pImpl->pAsyncOut->m_pTaskExitThread == NULL )
+ {
+ hr = E_OUTOFMEMORY;
+ goto err;
+ }
+
+ pImpl->pAsyncOut->m_hTaskThread = CreateThread(
+ NULL, 0, OutputPinAsync_ThreadEntry, pImpl,
+ 0, &dwThreadId );
+ if ( pImpl->pAsyncOut->m_hTaskThread == (HANDLE)NULL )
+ {
+ hr = E_FAIL;
+ goto err;
+ }
+
+ return NOERROR;
+err:
+ OutputPinAsync_OnInactive( pImpl );
+ return hr;
+}
+
+HRESULT OutputPinAsync_OnInactive( CPinBaseImpl* pImpl )
+{
+ OutputPinTask* pTask;
+
+ FIXME("(%p)\n",pImpl);
+
+ if ( pImpl->pAsyncOut == NULL )
+ return NOERROR;
+
+ if ( pImpl->pAsyncOut->m_pTaskExitThread != NULL )
+ {
+ OutputPinAsync_AddTask( pImpl->pAsyncOut, pImpl->pAsyncOut->m_pTaskExitThread, TRUE );
+ pImpl->pAsyncOut->m_pTaskExitThread = NULL;
+ }
+
+ if ( pImpl->pAsyncOut->m_hTaskThread != (HANDLE)NULL )
+ {
+ WaitForSingleObject( pImpl->pAsyncOut->m_hTaskThread, INFINITE );
+ CloseHandle( pImpl->pAsyncOut->m_hTaskThread );
+ }
+ if ( pImpl->pAsyncOut->m_hTaskEvent != (HANDLE)NULL )
+ CloseHandle( pImpl->pAsyncOut->m_hTaskEvent );
+
+ /* release all tasks. */
+ while ( 1 )
+ {
+ pTask = OutputPinAsync_GetNextTask( pImpl->pAsyncOut );
+ if ( pTask == NULL )
+ break;
+ OutputPinAsync_FreeTask( pTask );
+ }
+
+ DeleteCriticalSection( &pImpl->pAsyncOut->m_csTasks );
+
+ QUARTZ_FreeMem( pImpl->pAsyncOut );
+ pImpl->pAsyncOut = NULL;
+
+ return NOERROR;
+}
+
+HRESULT OutputPinAsync_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample )
+{
+ OutputPinAsyncImpl* This = pImpl->pAsyncOut;
+ OutputPinTask* pTask;
+
+ TRACE("(%p,%p)\n",pImpl,pSample);
+
+ if ( This == NULL )
+ return NOERROR;
+
+ pTask = OutputPinAsync_AllocTask( OutTask_Receive );
+ if ( pTask == NULL )
+ return E_OUTOFMEMORY;
+ pTask->pSample = pSample; IMediaSample_AddRef( pSample );
+ OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE );
+
+ return NOERROR;
+}
+
+HRESULT OutputPinAsync_ReceiveCanBlock( CPinBaseImpl* pImpl )
+{
+ return S_FALSE;
+}
+
+HRESULT OutputPinAsync_EndOfStream( CPinBaseImpl* pImpl )
+{
+ OutputPinAsyncImpl* This = pImpl->pAsyncOut;
+ OutputPinTask* pTask;
+
+ TRACE("(%p)\n",pImpl);
+
+ if ( This == NULL )
+ return NOERROR;
+
+ pTask = OutputPinAsync_AllocTask( OutTask_EndOfStream );
+ if ( pTask == NULL )
+ return E_OUTOFMEMORY;
+ OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE );
+
+ return NOERROR;
+}
+
+HRESULT OutputPinAsync_BeginFlush( CPinBaseImpl* pImpl )
+{
+ OutputPinAsyncImpl* This = pImpl->pAsyncOut;
+ OutputPinTask* pTask;
+
+ TRACE("(%p)\n",pImpl);
+
+ if ( This == NULL )
+ return NOERROR;
+
+ pTask = OutputPinAsync_AllocTask( OutTask_BeginFlush );
+ if ( pTask == NULL )
+ return E_OUTOFMEMORY;
+ OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, TRUE );
+
+ return NOERROR;
+}
+
+HRESULT OutputPinAsync_EndFlush( CPinBaseImpl* pImpl )
+{
+ OutputPinAsyncImpl* This = pImpl->pAsyncOut;
+ OutputPinTask* pTask;
+
+ TRACE("(%p)\n",pImpl);
+
+ if ( This == NULL )
+ return NOERROR;
+
+ pTask = OutputPinAsync_AllocTask( OutTask_EndFlush );
+ if ( pTask == NULL )
+ return E_OUTOFMEMORY;
+ OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE );
+
+ return NOERROR;
+}
+
+HRESULT OutputPinAsync_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate )
+{
+ OutputPinAsyncImpl* This = pImpl->pAsyncOut;
+ OutputPinTask* pTask;
+
+ TRACE("(%p)\n",pImpl);
+
+ if ( This == NULL )
+ return NOERROR;
+
+ pTask = OutputPinAsync_AllocTask( OutTask_NewSegment );
+ if ( pTask == NULL )
+ return E_OUTOFMEMORY;
+ pTask->rtStart = rtStart;
+ pTask->rtStop = rtStop;
+ pTask->rate = rate;
+ OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE );
+
+ return NOERROR;
+}
+
+
diff --git a/dlls/quartz/igconfig.c b/dlls/quartz/igconfig.c
index 4f7465d..4ab9b08 100644
--- a/dlls/quartz/igconfig.c
+++ b/dlls/quartz/igconfig.c
@@ -73,10 +73,19 @@
IGraphConfig_fnReconfigure(IGraphConfig* iface,IGraphConfigCallback* pCallback,PVOID pvParam,DWORD dwFlags,HANDLE hAbort)
{
CFilterGraph_THIS(iface,grphconf);
+ HRESULT hr;
- FIXME("(%p)->() stub!\n",This);
+ FIXME("(%p)->(%p,%p,%08lx,%08x) stub!\n",This,pCallback,pvParam,dwFlags,hAbort);
- return E_NOTIMPL;
+ QUARTZ_CompList_Lock( This->m_pFilterList );
+ EnterCriticalSection( &This->m_csGraphState );
+
+ hr = IGraphConfigCallback_Reconfigure(pCallback,pvParam,dwFlags);
+
+ LeaveCriticalSection( &This->m_csGraphState );
+ QUARTZ_CompList_Unlock( This->m_pFilterList );
+
+ return hr;
}
static HRESULT WINAPI
diff --git a/dlls/quartz/main.c b/dlls/quartz/main.c
index 9b73116..fb8421c 100644
--- a/dlls/quartz/main.c
+++ b/dlls/quartz/main.c
@@ -32,7 +32,8 @@
#include "fmap2.h"
#include "seekpass.h"
#include "audren.h"
-
+#include "vidren.h"
+#include "parser.h"
typedef struct QUARTZ_CLASSENTRY
{
@@ -77,6 +78,8 @@
{ &CLSID_FilterMapper2, &QUARTZ_CreateFilterMapper2 },
{ &CLSID_SeekingPassThru, &QUARTZ_CreateSeekingPassThru },
{ &CLSID_AudioRender, &QUARTZ_CreateAudioRenderer },
+ { &CLSID_VideoRenderer, &QUARTZ_CreateVideoRenderer },
+ { &CLSID_quartzWaveParser, &QUARTZ_CreateWaveParser },
{ NULL, NULL },
};
diff --git a/dlls/quartz/memalloc.c b/dlls/quartz/memalloc.c
index 59a9c50..31e0e6b 100644
--- a/dlls/quartz/memalloc.c
+++ b/dlls/quartz/memalloc.c
@@ -318,6 +318,8 @@
EnterCriticalSection( &This->csMem );
+ TRACE("(%p) enter critical section\n",This);
+
hr = NOERROR;
if ( This->pData == NULL || This->ppSamples == NULL ||
@@ -353,6 +355,7 @@
end:
LeaveCriticalSection( &This->csMem );
+ TRACE("(%p) leave critical section\n",This);
return hr;
}
@@ -418,3 +421,4 @@
if ( pma->hEventSample != (HANDLE)NULL )
CloseHandle( pma->hEventSample );
}
+
diff --git a/dlls/quartz/mtype.c b/dlls/quartz/mtype.c
index e356218..0510fdf 100644
--- a/dlls/quartz/mtype.c
+++ b/dlls/quartz/mtype.c
@@ -14,6 +14,7 @@
#include "wine/obj_base.h"
#include "strmif.h"
#include "vfwmsgs.h"
+#include "uuids.h"
#include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(quartz);
@@ -101,6 +102,22 @@
CoTaskMemFree( pmt );
}
+void QUARTZ_MediaSubType_FromFourCC(
+ GUID* psubtype, DWORD dwFourCC )
+{
+ memcpy( psubtype, &MEDIASUBTYPE_PCM, sizeof(GUID) );
+ psubtype->Data1 = dwFourCC;
+}
+
+BOOL QUARTZ_MediaSubType_IsFourCC(
+ const GUID* psubtype )
+{
+ GUID guidTemp;
+
+ QUARTZ_MediaSubType_FromFourCC(
+ &guidTemp, psubtype->Data1 );
+ return IsEqualGUID( psubtype, &guidTemp );
+}
/****************************************************************************/
diff --git a/dlls/quartz/mtype.h b/dlls/quartz/mtype.h
index 502b593..9332f3e 100644
--- a/dlls/quartz/mtype.h
+++ b/dlls/quartz/mtype.h
@@ -17,6 +17,10 @@
void QUARTZ_MediaType_Destroy(
AM_MEDIA_TYPE* pmt );
+void QUARTZ_MediaSubType_FromFourCC(
+ GUID* psubtype, DWORD dwFourCC );
+BOOL QUARTZ_MediaSubType_IsFourCC(
+ const GUID* psubtype );
HRESULT QUARTZ_CreateEnumMediaTypes(
IEnumMediaTypes** ppobj,
diff --git a/dlls/quartz/parser.c b/dlls/quartz/parser.c
new file mode 100644
index 0000000..897b31a
--- /dev/null
+++ b/dlls/quartz/parser.c
@@ -0,0 +1,999 @@
+/*
+ * Implements IBaseFilter for parsers. (internal)
+ *
+ * hidenori@a2.ctktv.ne.jp
+ */
+
+#include "config.h"
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "mmsystem.h"
+#include "winerror.h"
+#include "wine/obj_base.h"
+#include "strmif.h"
+#include "vfwmsgs.h"
+#include "uuids.h"
+
+#include "debugtools.h"
+DEFAULT_DEBUG_CHANNEL(quartz);
+
+#include "quartz_private.h"
+#include "parser.h"
+#include "mtype.h"
+#include "memalloc.h"
+
+#define QUARTZ_MSG_BEGINFLUSH (WM_APP+1)
+#define QUARTZ_MSG_ENDFLUSH (WM_APP+2)
+#define QUARTZ_MSG_EXITTHREAD (WM_APP+3)
+#define QUARTZ_MSG_SEEK (WM_APP+0)
+
+/***************************************************************************
+ *
+ * CParserImpl internal methods
+ *
+ */
+
+static
+void CParserImpl_SetAsyncReader( CParserImpl* This, IAsyncReader* pReader )
+{
+ if ( This->m_pReader != NULL )
+ {
+ IAsyncReader_Release( This->m_pReader );
+ This->m_pReader = NULL;
+ }
+ if ( pReader != NULL )
+ {
+ This->m_pReader = pReader;
+ IAsyncReader_AddRef(This->m_pReader);
+ }
+}
+
+static
+void CParserImpl_ReleaseOutPins( CParserImpl* This )
+{
+ ULONG nIndex;
+
+ if ( This->m_ppOutPins != NULL )
+ {
+ for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ )
+ {
+ if ( This->m_ppOutPins[nIndex] != NULL )
+ {
+ IUnknown_Release(This->m_ppOutPins[nIndex]->unk.punkControl);
+ This->m_ppOutPins[nIndex] = NULL;
+ }
+ }
+ QUARTZ_FreeMem(This->m_ppOutPins);
+ This->m_ppOutPins = NULL;
+ }
+ This->m_cOutStreams = 0;
+}
+
+static
+void CParserImpl_ClearAllRequests( CParserImpl* This )
+{
+ ULONG nIndex;
+
+ for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ )
+ This->m_ppOutPins[nIndex]->m_bReqUsed = FALSE;
+}
+
+
+static
+HRESULT CParserImpl_ReleaseAllPendingSamples( CParserImpl* This )
+{
+ HRESULT hr;
+ IMediaSample* pSample;
+ DWORD_PTR dwContext;
+
+ IAsyncReader_BeginFlush(This->m_pReader);
+ while ( 1 )
+ {
+ hr = IAsyncReader_WaitForNext(This->m_pReader,0,&pSample,&dwContext);
+ if ( hr != S_OK )
+ break;
+ IMediaSample_Release(pSample);
+ }
+ IAsyncReader_EndFlush(This->m_pReader);
+
+ if ( hr == VFW_E_TIMEOUT )
+ hr = NOERROR;
+
+ return hr;
+}
+
+static
+HRESULT CParserImpl_ProcessNextSample( CParserImpl* This )
+{
+ IMediaSample* pSample;
+ DWORD_PTR dwContext;
+ ULONG nIndex;
+ HRESULT hr;
+ CParserOutPinImpl* pOutPin;
+ MSG msg;
+
+ while ( 1 )
+ {
+ if ( PeekMessageA( &msg, (HWND)NULL, 0, 0, PM_REMOVE ) )
+ {
+ hr = NOERROR;
+ switch ( msg.message )
+ {
+ case QUARTZ_MSG_BEGINFLUSH:
+ FIXME("BeginFlush\n");
+ hr = IAsyncReader_BeginFlush(This->m_pReader);
+ /* send to all output pins */
+ break;
+ case QUARTZ_MSG_ENDFLUSH:
+ FIXME("EndFlush\n");
+ hr = IAsyncReader_EndFlush(This->m_pReader);
+ /* send to all output pins */
+ break;
+ case QUARTZ_MSG_EXITTHREAD:
+ FIXME("EndThread\n");
+ CParserImpl_ReleaseAllPendingSamples(This);
+ CParserImpl_ClearAllRequests(This);
+ return S_FALSE;
+ case QUARTZ_MSG_SEEK:
+ FIXME("Seek\n");
+ break;
+ default:
+ FIXME( "invalid message %04u\n", (unsigned)msg.message );
+ /* Notify (ABORT) */
+ hr = E_FAIL;
+ }
+
+ return hr;
+ }
+
+ hr = IAsyncReader_WaitForNext(This->m_pReader,PARSER_POLL_INTERVAL,&pSample,&dwContext);
+ nIndex = (ULONG)dwContext;
+ if ( hr != VFW_E_TIMEOUT )
+ break;
+ }
+ if ( FAILED(hr) )
+ return hr;
+
+ pOutPin = This->m_ppOutPins[nIndex];
+ if ( pOutPin != NULL && pOutPin->m_bReqUsed )
+ {
+ if ( This->m_pHandler->pProcessSample != NULL )
+ hr = This->m_pHandler->pProcessSample(This,nIndex,pOutPin->m_llReqStart,pOutPin->m_lReqLength,pSample);
+
+ if ( FAILED(hr) )
+ {
+ /* Notify (ABORT) */
+ }
+ else
+ {
+ /* FIXME - if pin has its own allocator, sample must be copied */
+ hr = CPinBaseImpl_SendSample(&pOutPin->pin,pSample);
+ }
+ pOutPin->m_bReqUsed = FALSE;
+ }
+
+ if ( SUCCEEDED(hr) )
+ hr = NOERROR;
+
+ IMediaSample_Release(pSample);
+ return hr;
+}
+
+static
+DWORD WINAPI CParserImpl_ThreadEntry( LPVOID pv )
+{
+ CParserImpl* This = (CParserImpl*)pv;
+ BOOL bReqNext;
+ ULONG nIndex = 0;
+ HRESULT hr;
+ REFERENCE_TIME rtSampleTimeStart, rtSampleTimeEnd;
+ LONGLONG llReqStart;
+ LONG lReqLength;
+ REFERENCE_TIME rtReqStart, rtReqStop;
+ IMediaSample* pSample;
+ MSG msg;
+
+ /* initialize the message queue. */
+ PeekMessageA( &msg, (HWND)NULL, 0, 0, PM_NOREMOVE );
+
+ CParserImpl_ClearAllRequests(This);
+
+ /* resume the owner thread. */
+ SetEvent( This->m_hEventInit );
+
+ TRACE( "Enter message loop.\n" );
+
+ bReqNext = TRUE;
+ while ( 1 )
+ {
+ if ( bReqNext )
+ {
+ /* Get the next request. */
+ hr = This->m_pHandler->pGetNextRequest( This, &nIndex, &llReqStart, &lReqLength, &rtReqStart, &rtReqStop );
+ if ( FAILED(hr) )
+ {
+ /* Notify (ABORT) */
+ break;
+ }
+ if ( hr != S_OK )
+ {
+ /* Flush */
+ /* Notify (COMPLETE) */
+
+ /* Waiting... */
+ hr = CParserImpl_ProcessNextSample(This);
+ if ( hr != S_OK )
+ {
+ /* notification is already sent */
+ break;
+ }
+ continue;
+ }
+ rtSampleTimeStart = llReqStart * QUARTZ_TIMEUNITS;
+ rtSampleTimeEnd = (llReqStart + lReqLength) * QUARTZ_TIMEUNITS;
+ bReqNext = FALSE;
+ }
+
+ if ( !This->m_ppOutPins[nIndex]->m_bReqUsed )
+ {
+ hr = IMemAllocator_GetBuffer( This->m_pAllocator, &pSample, NULL, NULL, 0 );
+ if ( FAILED(hr) )
+ {
+ /* Notify (ABORT) */
+ break;
+ }
+ hr = IMediaSample_SetTime(pSample,&rtSampleTimeStart,&rtSampleTimeEnd);
+ if ( SUCCEEDED(hr) )
+ hr = IAsyncReader_Request(This->m_pReader,pSample,nIndex);
+ if ( FAILED(hr) )
+ {
+ /* Notify (ABORT) */
+ break;
+ }
+
+ This->m_ppOutPins[nIndex]->m_bReqUsed = TRUE;
+ This->m_ppOutPins[nIndex]->m_llReqStart = llReqStart;
+ This->m_ppOutPins[nIndex]->m_lReqLength = lReqLength;
+ This->m_ppOutPins[nIndex]->m_rtReqStart = rtSampleTimeStart;
+ This->m_ppOutPins[nIndex]->m_rtReqStop = rtSampleTimeEnd;
+ bReqNext = TRUE;
+ continue;
+ }
+
+ hr = CParserImpl_ProcessNextSample(This);
+ if ( hr != S_OK )
+ {
+ /* notification is already sent */
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static
+HRESULT CParserImpl_BeginThread( CParserImpl* This )
+{
+ DWORD dwRes;
+ HANDLE hEvents[2];
+
+ if ( This->m_hEventInit != (HANDLE)NULL ||
+ This->m_hThread != (HANDLE)NULL )
+ return E_UNEXPECTED;
+
+ This->m_hEventInit = CreateEventA(NULL,TRUE,FALSE,NULL);
+ if ( This->m_hEventInit == (HANDLE)NULL )
+ return E_OUTOFMEMORY;
+
+ /* create the processing thread. */
+ This->m_hThread = CreateThread(
+ NULL, 0,
+ CParserImpl_ThreadEntry,
+ (LPVOID)This,
+ 0, &This->m_dwThreadId );
+ if ( This->m_hThread == (HANDLE)NULL )
+ return E_FAIL;
+
+ hEvents[0] = This->m_hEventInit;
+ hEvents[1] = This->m_hThread;
+
+ dwRes = WaitForMultipleObjects(2,hEvents,FALSE,INFINITE);
+ if ( dwRes != WAIT_OBJECT_0 )
+ return E_FAIL;
+
+ return NOERROR;
+}
+
+static
+void CParserImpl_EndThread( CParserImpl* This )
+{
+ if ( This->m_hThread != (HANDLE)NULL )
+ {
+ if ( PostThreadMessageA(
+ This->m_dwThreadId, QUARTZ_MSG_EXITTHREAD, 0, 0 ) )
+ {
+ WaitForSingleObject( This->m_hThread, INFINITE );
+ }
+ CloseHandle( This->m_hThread );
+ This->m_hThread = (HANDLE)NULL;
+ This->m_dwThreadId = 0;
+ }
+ if ( This->m_hEventInit != (HANDLE)NULL )
+ {
+ CloseHandle( This->m_hEventInit );
+ This->m_hEventInit = (HANDLE)NULL;
+ }
+}
+
+static
+HRESULT CParserImpl_MemCommit( CParserImpl* This )
+{
+ HRESULT hr;
+ ULONG nIndex;
+ IMemAllocator* pAlloc;
+
+ if ( This->m_pAllocator == NULL )
+ return E_UNEXPECTED;
+
+ hr = IMemAllocator_Commit( This->m_pAllocator );
+ if ( FAILED(hr) )
+ return hr;
+
+ if ( This->m_ppOutPins != NULL && This->m_cOutStreams > 0 )
+ {
+ for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ )
+ {
+ pAlloc = This->m_ppOutPins[nIndex]->m_pOutPinAllocator;
+ if ( pAlloc != NULL && pAlloc != This->m_pAllocator )
+ {
+ hr = IMemAllocator_Commit( pAlloc );
+ if ( FAILED(hr) )
+ return hr;
+ }
+ }
+ }
+
+ return NOERROR;
+}
+
+static
+void CParserImpl_MemDecommit( CParserImpl* This )
+{
+ ULONG nIndex;
+ IMemAllocator* pAlloc;
+
+ if ( This->m_pAllocator != NULL )
+ IMemAllocator_Decommit( This->m_pAllocator );
+
+ if ( This->m_ppOutPins != NULL && This->m_cOutStreams > 0 )
+ {
+ for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ )
+ {
+ pAlloc = This->m_ppOutPins[nIndex]->m_pOutPinAllocator;
+ if ( pAlloc != NULL )
+ IMemAllocator_Decommit( pAlloc );
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ *
+ * CParserImpl methods
+ *
+ */
+
+static HRESULT CParserImpl_OnActive( CBaseFilterImpl* pImpl )
+{
+ CParserImpl_THIS(pImpl,basefilter);
+ HRESULT hr;
+
+ TRACE( "(%p)\n", This );
+
+ hr = CParserImpl_MemCommit(This);
+ if ( FAILED(hr) )
+ return hr;
+ hr = CParserImpl_BeginThread(This);
+ if ( FAILED(hr) )
+ return hr;
+
+ return NOERROR;
+}
+
+static HRESULT CParserImpl_OnInactive( CBaseFilterImpl* pImpl )
+{
+ CParserImpl_THIS(pImpl,basefilter);
+
+ TRACE( "(%p)\n", This );
+
+ CParserImpl_EndThread(This);
+ CParserImpl_MemDecommit(This);
+
+ return NOERROR;
+}
+
+static HRESULT CParserImpl_OnStop( CBaseFilterImpl* pImpl )
+{
+ CParserImpl_THIS(pImpl,basefilter);
+
+ FIXME( "(%p)\n", This );
+
+ /* FIXME - reset streams. */
+
+ return NOERROR;
+}
+
+
+static const CBaseFilterHandlers filterhandlers =
+{
+ CParserImpl_OnActive, /* pOnActive */
+ CParserImpl_OnInactive, /* pOnInactive */
+ CParserImpl_OnStop, /* pOnStop */
+};
+
+
+/***************************************************************************
+ *
+ * CParserInPinImpl methods
+ *
+ */
+
+static HRESULT CParserInPinImpl_OnPreConnect( CPinBaseImpl* pImpl, IPin* pPin )
+{
+ CParserInPinImpl_THIS(pImpl,pin);
+ HRESULT hr;
+ ULONG nIndex;
+ IUnknown* punk;
+ IAsyncReader* pReader = NULL;
+ LPCWSTR pwszOutPinName;
+ IMemAllocator* pAllocActual;
+ AM_MEDIA_TYPE* pmt;
+
+ TRACE("(%p,%p)\n",This,pPin);
+
+ if ( This->pParser->m_pHandler->pInitParser == NULL ||
+ This->pParser->m_pHandler->pUninitParser == NULL ||
+ This->pParser->m_pHandler->pGetOutPinName == NULL ||
+ This->pParser->m_pHandler->pGetStreamType == NULL ||
+ This->pParser->m_pHandler->pCheckStreamType == NULL ||
+ This->pParser->m_pHandler->pGetAllocProp == NULL ||
+ This->pParser->m_pHandler->pGetNextRequest == NULL )
+ {
+ FIXME("this parser is not implemented.\n");
+ return E_NOTIMPL;
+ }
+
+ CParserImpl_SetAsyncReader( This->pParser, NULL );
+ hr = IPin_QueryInterface( pPin, &IID_IAsyncReader, (void**)&pReader );
+ if ( FAILED(hr) )
+ return hr;
+ CParserImpl_SetAsyncReader( This->pParser, pReader );
+ IAsyncReader_Release(pReader);
+
+ /* initialize parser. */
+ hr = This->pParser->m_pHandler->pInitParser(This->pParser,&This->pParser->m_cOutStreams);
+ if ( FAILED(hr) )
+ return hr;
+ This->pParser->m_ppOutPins = (CParserOutPinImpl**)QUARTZ_AllocMem(
+ sizeof(CParserOutPinImpl*) * This->pParser->m_cOutStreams );
+ if ( This->pParser->m_ppOutPins == NULL )
+ return E_OUTOFMEMORY;
+ for ( nIndex = 0; nIndex < This->pParser->m_cOutStreams; nIndex++ )
+ This->pParser->m_ppOutPins[nIndex] = NULL;
+
+ /* create and initialize an allocator. */
+ hr = This->pParser->m_pHandler->pGetAllocProp(This->pParser,&This->pParser->m_propAlloc);
+ if ( FAILED(hr) )
+ return hr;
+ if ( This->pParser->m_pAllocator == NULL )
+ {
+ hr = QUARTZ_CreateMemoryAllocator(NULL,(void**)&punk);
+ if ( FAILED(hr) )
+ return hr;
+ hr = IUnknown_QueryInterface( punk, &IID_IMemAllocator, (void**)&This->pParser->m_pAllocator );
+ IUnknown_Release(punk);
+ if ( FAILED(hr) )
+ return hr;
+ }
+ pAllocActual = NULL;
+ hr = IAsyncReader_RequestAllocator(pReader,This->pParser->m_pAllocator,&This->pParser->m_propAlloc,&pAllocActual);
+ if ( FAILED(hr) )
+ return hr;
+ IMemAllocator_Release(This->pParser->m_pAllocator);
+ This->pParser->m_pAllocator = pAllocActual;
+
+ /* create output pins. */
+ for ( nIndex = 0; nIndex < This->pParser->m_cOutStreams; nIndex++ )
+ {
+ pwszOutPinName = This->pParser->m_pHandler->pGetOutPinName(This->pParser,nIndex);
+ if ( pwszOutPinName == NULL )
+ return E_FAIL;
+ hr = QUARTZ_CreateParserOutPin(
+ This->pParser,
+ &This->pParser->m_csParser,
+ &This->pParser->m_ppOutPins[nIndex],
+ nIndex, pwszOutPinName );
+ if ( SUCCEEDED(hr) )
+ hr = QUARTZ_CompList_AddComp(
+ This->pParser->basefilter.pOutPins,
+ (IUnknown*)&(This->pParser->m_ppOutPins[nIndex]->pin),
+ NULL, 0 );
+ if ( FAILED(hr) )
+ return hr;
+ pmt = &This->pParser->m_ppOutPins[nIndex]->m_mtOut;
+ QUARTZ_MediaType_Free( pmt );
+ ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
+ hr = This->pParser->m_pHandler->pGetStreamType(This->pParser,nIndex,pmt);
+ if ( FAILED(hr) )
+ {
+ ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
+ return hr;
+ }
+ This->pParser->m_ppOutPins[nIndex]->pin.cAcceptTypes = 1;
+ This->pParser->m_ppOutPins[nIndex]->pin.pmtAcceptTypes = pmt;
+ }
+
+ return NOERROR;
+}
+
+static HRESULT CParserInPinImpl_OnDisconnect( CPinBaseImpl* pImpl )
+{
+ CParserInPinImpl_THIS(pImpl,pin);
+
+ CParserImpl_OnInactive(&This->pParser->basefilter);
+ CParserImpl_OnStop(&This->pParser->basefilter);
+ if ( This->pParser->m_pHandler->pUninitParser != NULL )
+ This->pParser->m_pHandler->pUninitParser(This->pParser);
+ CParserImpl_SetAsyncReader( This->pParser, NULL );
+ if ( This->pParser->m_pAllocator != NULL )
+ {
+ IMemAllocator_Release(This->pParser->m_pAllocator);
+ This->pParser->m_pAllocator = NULL;
+ }
+
+ return NOERROR;
+}
+
+static HRESULT CParserInPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
+{
+ CParserInPinImpl_THIS(pImpl,pin);
+
+ TRACE("(%p,%p)\n",This,pmt);
+
+ if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Stream ) )
+ return E_FAIL;
+
+ return NOERROR;
+}
+
+static const CBasePinHandlers inputpinhandlers =
+{
+ CParserInPinImpl_OnPreConnect, /* pOnPreConnect */
+ NULL, /* pOnPostConnect */
+ CParserInPinImpl_OnDisconnect, /* pOnDisconnect */
+ CParserInPinImpl_CheckMediaType, /* pCheckMediaType */
+ NULL, /* pQualityNotify */
+ NULL, /* pReceive */
+ NULL, /* pReceiveCanBlock */
+ NULL, /* pEndOfStream */
+ NULL, /* pBeginFlush */
+ NULL, /* pEndFlush */
+ NULL, /* pNewSegment */
+};
+
+/***************************************************************************
+ *
+ * CParserOutPinImpl methods
+ *
+ */
+
+static HRESULT CParserOutPinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin )
+{
+ CParserOutPinImpl_THIS(pImpl,pin);
+ ALLOCATOR_PROPERTIES propReq;
+ IMemAllocator* pAllocator;
+ HRESULT hr;
+ BOOL bNewAllocator = FALSE;
+
+ TRACE("(%p,%p)\n",This,pPin);
+
+ if ( This->pin.pMemInputPinConnectedTo == NULL )
+ return E_UNEXPECTED;
+
+ if ( This->m_pOutPinAllocator != NULL )
+ {
+ IMemAllocator_Release(This->m_pOutPinAllocator);
+ This->m_pOutPinAllocator = NULL;
+ }
+
+ /* try to use This->pParser->m_pAllocator. */
+ ZeroMemory( &propReq, sizeof(ALLOCATOR_PROPERTIES) );
+ hr = IMemInputPin_GetAllocatorRequirements(
+ This->pin.pMemInputPinConnectedTo, &propReq );
+ if ( propReq.cbAlign != 0 )
+ {
+ if ( This->pParser->m_propAlloc.cbAlign != ( This->pParser->m_propAlloc.cbAlign / propReq.cbAlign * propReq.cbAlign ) )
+ bNewAllocator = TRUE;
+ }
+ if ( propReq.cbPrefix != 0 )
+ bNewAllocator = TRUE;
+ if ( !bNewAllocator )
+ {
+ hr = IMemInputPin_NotifyAllocator(
+ This->pin.pMemInputPinConnectedTo,
+ This->pParser->m_pAllocator, FALSE );
+ if ( hr == NOERROR )
+ {
+ This->m_pOutPinAllocator = This->pParser->m_pAllocator;
+ IMemAllocator_AddRef(This->m_pOutPinAllocator);
+ return NOERROR;
+ }
+ }
+
+ hr = IMemInputPin_GetAllocator(
+ This->pin.pMemInputPinConnectedTo, &pAllocator );
+ if ( FAILED(hr) )
+ return hr;
+ hr = IMemInputPin_NotifyAllocator(
+ This->pin.pMemInputPinConnectedTo, pAllocator, FALSE );
+ if ( FAILED(hr) )
+ {
+ IMemAllocator_Release(pAllocator);
+ return hr;
+ }
+
+ This->m_pOutPinAllocator = pAllocator;
+ return NOERROR;
+}
+
+static HRESULT CParserOutPinImpl_OnDisconnect( CPinBaseImpl* pImpl )
+{
+ CParserOutPinImpl_THIS(pImpl,pin);
+
+ if ( This->m_pOutPinAllocator != NULL )
+ {
+ IMemAllocator_Release(This->m_pOutPinAllocator);
+ This->m_pOutPinAllocator = NULL;
+ }
+
+ return NOERROR;
+}
+
+static HRESULT CParserOutPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
+{
+ CParserOutPinImpl_THIS(pImpl,pin);
+ HRESULT hr;
+
+ TRACE("(%p,%p)\n",This,pmt);
+ if ( pmt == NULL )
+ return E_POINTER;
+
+ if ( This->pParser->m_pHandler->pCheckStreamType == NULL )
+ return E_NOTIMPL;
+
+ hr = This->pParser->m_pHandler->pCheckStreamType( This->pParser, This->nStreamIndex, pmt );
+ if ( FAILED(hr) )
+ return hr;
+
+ return NOERROR;
+}
+
+
+static const CBasePinHandlers outputpinhandlers =
+{
+ NULL, /* pOnPreConnect */
+ CParserOutPinImpl_OnPostConnect, /* pOnPostConnect */
+ CParserOutPinImpl_OnDisconnect, /* pOnDisconnect */
+ CParserOutPinImpl_CheckMediaType, /* pCheckMediaType */
+ NULL, /* pQualityNotify */
+ OutputPinSync_Receive, /* pReceive */
+ OutputPinSync_ReceiveCanBlock, /* pReceiveCanBlock */
+ OutputPinSync_EndOfStream, /* pEndOfStream */
+ OutputPinSync_BeginFlush, /* pBeginFlush */
+ OutputPinSync_EndFlush, /* pEndFlush */
+ OutputPinSync_NewSegment, /* pNewSegment */
+};
+
+/***************************************************************************
+ *
+ * new/delete CParserImpl
+ *
+ */
+
+/* can I use offsetof safely? - FIXME? */
+static QUARTZ_IFEntry FilterIFEntries[] =
+{
+ { &IID_IPersist, offsetof(CParserImpl,basefilter)-offsetof(CParserImpl,unk) },
+ { &IID_IMediaFilter, offsetof(CParserImpl,basefilter)-offsetof(CParserImpl,unk) },
+ { &IID_IBaseFilter, offsetof(CParserImpl,basefilter)-offsetof(CParserImpl,unk) },
+};
+
+static void QUARTZ_DestroyParser(IUnknown* punk)
+{
+ CParserImpl_THIS(punk,unk);
+
+ TRACE( "(%p)\n", This );
+
+ if ( This->m_pInPin != NULL )
+ CParserInPinImpl_OnDisconnect(&This->m_pInPin->pin);
+
+ CParserImpl_SetAsyncReader( This, NULL );
+ if ( This->m_pAllocator != NULL )
+ {
+ IMemAllocator_Release(This->m_pAllocator);
+ This->m_pAllocator = NULL;
+ }
+ if ( This->m_pInPin != NULL )
+ {
+ IUnknown_Release(This->m_pInPin->unk.punkControl);
+ This->m_pInPin = NULL;
+ }
+ CParserImpl_ReleaseOutPins( This );
+
+ DeleteCriticalSection( &This->m_csParser );
+
+ CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
+}
+
+HRESULT QUARTZ_CreateParser(
+ IUnknown* punkOuter,void** ppobj,
+ const CLSID* pclsidParser,
+ LPCWSTR pwszParserName,
+ LPCWSTR pwszInPinName,
+ const ParserHandlers* pHandler )
+{
+ CParserImpl* This = NULL;
+ HRESULT hr;
+
+ TRACE("(%p,%p)\n",punkOuter,ppobj);
+
+ This = (CParserImpl*)
+ QUARTZ_AllocObj( sizeof(CParserImpl) );
+ if ( This == NULL )
+ return E_OUTOFMEMORY;
+
+ This->m_pInPin = NULL;
+ This->m_cOutStreams = 0;
+ This->m_ppOutPins = NULL;
+ This->m_pReader = NULL;
+ This->m_pAllocator = NULL;
+ ZeroMemory( &This->m_propAlloc, sizeof(ALLOCATOR_PROPERTIES) );
+ This->m_hEventInit = (HANDLE)NULL;
+ This->m_hThread = (HANDLE)NULL;
+ This->m_dwThreadId = 0;
+ This->m_pHandler = pHandler;
+ This->m_pUserData = NULL;
+
+ QUARTZ_IUnkInit( &This->unk, punkOuter );
+
+ hr = CBaseFilterImpl_InitIBaseFilter(
+ &This->basefilter,
+ This->unk.punkControl,
+ pclsidParser,
+ pwszParserName,
+ &filterhandlers );
+ if ( SUCCEEDED(hr) )
+ {
+ /* construct this class. */
+ hr = S_OK;
+
+ if ( FAILED(hr) )
+ {
+ CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
+ }
+ }
+
+ if ( FAILED(hr) )
+ {
+ QUARTZ_FreeObj(This);
+ return hr;
+ }
+
+ This->unk.pEntries = FilterIFEntries;
+ This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]);
+ This->unk.pOnFinalRelease = QUARTZ_DestroyParser;
+ InitializeCriticalSection( &This->m_csParser );
+
+ /* create the input pin. */
+ hr = QUARTZ_CreateParserInPin(
+ This,
+ &This->m_csParser,
+ &This->m_pInPin,
+ pwszInPinName );
+ if ( SUCCEEDED(hr) )
+ hr = QUARTZ_CompList_AddComp(
+ This->basefilter.pInPins,
+ (IUnknown*)&(This->m_pInPin->pin),
+ NULL, 0 );
+
+ if ( FAILED(hr) )
+ {
+ IUnknown_Release( This->unk.punkControl );
+ return hr;
+ }
+
+ *ppobj = (void*)&(This->unk);
+
+ return S_OK;
+}
+
+/***************************************************************************
+ *
+ * new/delete CParserInPinImpl
+ *
+ */
+
+/* can I use offsetof safely? - FIXME? */
+static QUARTZ_IFEntry InPinIFEntries[] =
+{
+ { &IID_IPin, offsetof(CParserInPinImpl,pin)-offsetof(CParserInPinImpl,unk) },
+ { &IID_IMemInputPin, offsetof(CParserInPinImpl,meminput)-offsetof(CParserInPinImpl,unk) },
+};
+
+static void QUARTZ_DestroyParserInPin(IUnknown* punk)
+{
+ CParserInPinImpl_THIS(punk,unk);
+
+ TRACE( "(%p)\n", This );
+
+ CPinBaseImpl_UninitIPin( &This->pin );
+ CMemInputPinBaseImpl_UninitIMemInputPin( &This->meminput );
+}
+
+HRESULT QUARTZ_CreateParserInPin(
+ CParserImpl* pFilter,
+ CRITICAL_SECTION* pcsPin,
+ CParserInPinImpl** ppPin,
+ LPCWSTR pwszPinName )
+{
+ CParserInPinImpl* This = NULL;
+ HRESULT hr;
+
+ TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
+
+ This = (CParserInPinImpl*)
+ QUARTZ_AllocObj( sizeof(CParserInPinImpl) );
+ if ( This == NULL )
+ return E_OUTOFMEMORY;
+
+ QUARTZ_IUnkInit( &This->unk, NULL );
+ This->pParser = pFilter;
+
+ hr = CPinBaseImpl_InitIPin(
+ &This->pin,
+ This->unk.punkControl,
+ pcsPin,
+ &pFilter->basefilter,
+ pwszPinName,
+ FALSE,
+ &inputpinhandlers );
+
+ if ( SUCCEEDED(hr) )
+ {
+ hr = CMemInputPinBaseImpl_InitIMemInputPin(
+ &This->meminput,
+ This->unk.punkControl,
+ &This->pin );
+ if ( FAILED(hr) )
+ {
+ CPinBaseImpl_UninitIPin( &This->pin );
+ }
+ }
+
+ if ( FAILED(hr) )
+ {
+ QUARTZ_FreeObj(This);
+ return hr;
+ }
+
+ This->unk.pEntries = InPinIFEntries;
+ This->unk.dwEntries = sizeof(InPinIFEntries)/sizeof(InPinIFEntries[0]);
+ This->unk.pOnFinalRelease = QUARTZ_DestroyParserInPin;
+
+ *ppPin = This;
+
+ TRACE("returned successfully.\n");
+
+ return S_OK;
+}
+
+
+/***************************************************************************
+ *
+ * new/delete CParserOutPinImpl
+ *
+ */
+
+/* can I use offsetof safely? - FIXME? */
+static QUARTZ_IFEntry OutPinIFEntries[] =
+{
+ { &IID_IPin, offsetof(CParserOutPinImpl,pin)-offsetof(CParserOutPinImpl,unk) },
+ { &IID_IQualityControl, offsetof(CParserOutPinImpl,qcontrol)-offsetof(CParserOutPinImpl,unk) },
+};
+
+static void QUARTZ_DestroyParserOutPin(IUnknown* punk)
+{
+ CParserOutPinImpl_THIS(punk,unk);
+
+ TRACE( "(%p)\n", This );
+
+ QUARTZ_MediaType_Free( &This->m_mtOut );
+ if ( This->m_pOutPinAllocator != NULL )
+ IMemAllocator_Release(This->m_pOutPinAllocator);
+
+ CPinBaseImpl_UninitIPin( &This->pin );
+ CQualityControlPassThruImpl_UninitIQualityControl( &This->qcontrol );
+}
+
+HRESULT QUARTZ_CreateParserOutPin(
+ CParserImpl* pFilter,
+ CRITICAL_SECTION* pcsPin,
+ CParserOutPinImpl** ppPin,
+ ULONG nStreamIndex,
+ LPCWSTR pwszPinName )
+{
+ CParserOutPinImpl* This = NULL;
+ HRESULT hr;
+
+ TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
+
+ This = (CParserOutPinImpl*)
+ QUARTZ_AllocObj( sizeof(CParserOutPinImpl) );
+ if ( This == NULL )
+ return E_OUTOFMEMORY;
+
+ QUARTZ_IUnkInit( &This->unk, NULL );
+ This->pParser = pFilter;
+ This->nStreamIndex = nStreamIndex;
+ ZeroMemory( &This->m_mtOut, sizeof(AM_MEDIA_TYPE) );
+ This->m_pOutPinAllocator = NULL;
+ This->m_pUserData = NULL;
+ This->m_bReqUsed = FALSE;
+ This->m_llReqStart = 0;
+ This->m_lReqLength = 0;
+ This->m_rtReqStart = 0;
+ This->m_rtReqStop = 0;
+
+
+ hr = CPinBaseImpl_InitIPin(
+ &This->pin,
+ This->unk.punkControl,
+ pcsPin,
+ &pFilter->basefilter,
+ pwszPinName,
+ TRUE,
+ &outputpinhandlers );
+
+ if ( SUCCEEDED(hr) )
+ {
+ hr = CQualityControlPassThruImpl_InitIQualityControl(
+ &This->qcontrol,
+ This->unk.punkControl,
+ &This->pin );
+ if ( FAILED(hr) )
+ {
+ CPinBaseImpl_UninitIPin( &This->pin );
+ }
+ }
+
+ if ( FAILED(hr) )
+ {
+ QUARTZ_FreeObj(This);
+ return hr;
+ }
+
+ This->unk.pEntries = OutPinIFEntries;
+ This->unk.dwEntries = sizeof(OutPinIFEntries)/sizeof(OutPinIFEntries[0]);
+ This->unk.pOnFinalRelease = QUARTZ_DestroyParserOutPin;
+
+ *ppPin = This;
+
+ TRACE("returned successfully.\n");
+
+ return S_OK;
+}
+
diff --git a/dlls/quartz/parser.h b/dlls/quartz/parser.h
new file mode 100644
index 0000000..1fb997c
--- /dev/null
+++ b/dlls/quartz/parser.h
@@ -0,0 +1,162 @@
+/*
+ * Implements Parser.
+ *
+ * hidenori@a2.ctktv.ne.jp
+ */
+
+#ifndef WINE_DSHOW_PARSER_H
+#define WINE_DSHOW_PARSER_H
+
+#include "iunk.h"
+#include "basefilt.h"
+
+typedef struct CParserImpl CParserImpl;
+typedef struct CParserInPinImpl CParserInPinImpl;
+typedef struct CParserOutPinImpl CParserOutPinImpl;
+typedef struct ParserHandlers ParserHandlers;
+
+/* {D51BD5A1-7548-11CF-A520-0080C77EF58A} */
+DEFINE_GUID(CLSID_quartzWaveParser,
+0xD51BD5A1,0x7548,0x11CF,0xA5,0x20,0x00,0x80,0xC7,0x7E,0xF5,0x8A);
+
+struct CParserImpl
+{
+ QUARTZ_IUnkImpl unk;
+ CBaseFilterImpl basefilter;
+
+ CParserInPinImpl* m_pInPin;
+ ULONG m_cOutStreams;
+ CParserOutPinImpl** m_ppOutPins;
+
+ CRITICAL_SECTION m_csParser;
+ IAsyncReader* m_pReader;
+ IMemAllocator* m_pAllocator;
+ ALLOCATOR_PROPERTIES m_propAlloc;
+ HANDLE m_hEventInit;
+ DWORD m_dwThreadId;
+ HANDLE m_hThread;
+ const ParserHandlers* m_pHandler;
+
+ void* m_pUserData;
+};
+
+struct CParserInPinImpl
+{
+ QUARTZ_IUnkImpl unk;
+ CPinBaseImpl pin;
+ CMemInputPinBaseImpl meminput;
+
+ CParserImpl* pParser;
+};
+
+struct CParserOutPinImpl
+{
+ QUARTZ_IUnkImpl unk;
+ CPinBaseImpl pin;
+ CQualityControlPassThruImpl qcontrol;
+
+ CParserImpl* pParser;
+ ULONG nStreamIndex;
+
+ AM_MEDIA_TYPE m_mtOut;
+ IMemAllocator* m_pOutPinAllocator;
+ void* m_pUserData;
+
+ /* for parser */
+ BOOL m_bReqUsed;
+ LONGLONG m_llReqStart;
+ LONG m_lReqLength;
+ REFERENCE_TIME m_rtReqStart;
+ REFERENCE_TIME m_rtReqStop;
+};
+
+
+
+struct ParserHandlers
+{
+ HRESULT (*pInitParser)( CParserImpl* pImpl, ULONG* pcStreams );
+ HRESULT (*pUninitParser)( CParserImpl* pImpl );
+ LPCWSTR (*pGetOutPinName)( CParserImpl* pImpl, ULONG nStreamIndex );
+ HRESULT (*pGetStreamType)( CParserImpl* pImpl, ULONG nStreamIndex, AM_MEDIA_TYPE* pmt );
+ HRESULT (*pCheckStreamType)( CParserImpl* pImpl, ULONG nStreamIndex, const AM_MEDIA_TYPE* pmt );
+ HRESULT (*pGetAllocProp)( CParserImpl* pImpl, ALLOCATOR_PROPERTIES* pReqProp );
+ /* S_OK - ok, S_FALSE - end of stream */
+ HRESULT (*pGetNextRequest)( CParserImpl* pImpl, ULONG* pnStreamIndex, LONGLONG* pllStart, LONG* plLength, REFERENCE_TIME* prtStart, REFERENCE_TIME* prtStop );
+ HRESULT (*pProcessSample)( CParserImpl* pImpl, ULONG nStreamIndex, LONGLONG llStart, LONG lLength, IMediaSample* pSample );
+
+ /* for IQualityControl */
+ HRESULT (*pQualityNotify)( CParserImpl* pImpl, ULONG nStreamIndex, Quality q );
+
+ /* for seeking */
+ HRESULT (*pGetSeekingCaps)( CParserImpl* pImpl, DWORD* pdwCaps );
+ HRESULT (*pIsTimeFormatSupported)( CParserImpl* pImpl, const GUID* pTimeFormat );
+ HRESULT (*pGetCurPos)( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG* pllPos );
+ HRESULT (*pSetCurPos)( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG llPos );
+ HRESULT (*pGetDuration)( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG* pllDuration );
+ HRESULT (*pSetDuration)( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG llDuration );
+ HRESULT (*pGetStopPos)( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG* pllPos );
+ HRESULT (*pSetStopPos)( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG llPos );
+ HRESULT (*pGetPreroll)( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG* pllPreroll );
+ HRESULT (*pSetPreroll)( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG llPreroll );
+};
+
+#define CParserImpl_THIS(iface,member) CParserImpl* This = ((CParserImpl*)(((char*)iface)-offsetof(CParserImpl,member)))
+#define CParserInPinImpl_THIS(iface,member) CParserInPinImpl* This = ((CParserInPinImpl*)(((char*)iface)-offsetof(CParserInPinImpl,member)))
+#define CParserOutPinImpl_THIS(iface,member) CParserOutPinImpl* This = ((CParserOutPinImpl*)(((char*)iface)-offsetof(CParserOutPinImpl,member)))
+
+
+HRESULT QUARTZ_CreateParser(
+ IUnknown* punkOuter,void** ppobj,
+ const CLSID* pclsidParser,
+ LPCWSTR pwszParserName,
+ LPCWSTR pwszInPinName,
+ const ParserHandlers* pHandler );
+HRESULT QUARTZ_CreateParserInPin(
+ CParserImpl* pFilter,
+ CRITICAL_SECTION* pcsPin,
+ CParserInPinImpl** ppPin,
+ LPCWSTR pwszPinName );
+HRESULT QUARTZ_CreateParserOutPin(
+ CParserImpl* pFilter,
+ CRITICAL_SECTION* pcsPin,
+ CParserOutPinImpl** ppPin,
+ ULONG nStreamIndex,
+ LPCWSTR pwszPinName );
+
+
+#define QUARTZ_TIMEUNITS ((LONGLONG)10000000)
+#define PARSER_POLL_INTERVAL 100
+
+#define PARSER_RIFF_OfsFirst 12
+#define PARSER_WAVE mmioFOURCC('W','A','V','E')
+#define PARSER_AVI mmioFOURCC('A','V','I',' ')
+#define PARSER_AVIX mmioFOURCC('A','V','I','X')
+
+#define PARSER_fmt mmioFOURCC('f','m','t',' ')
+#define PARSER_fact mmioFOURCC('f','a','c','t')
+#define PARSER_data mmioFOURCC('d','a','t','a')
+
+#define PARSER_avih mmioFOURCC('a','v','i','h')
+#define PARSER_strl mmioFOURCC('s','t','r','l')
+#define PARSER_strh mmioFOURCC('s','t','r','h')
+#define PARSER_strf mmioFOURCC('s','t','r','f')
+#define PARSER_idx1 mmioFOURCC('i','d','x','1')
+#define PARSER_indx mmioFOURCC('i','n','d','x')
+#define PARSER_movi mmioFOURCC('m','o','v','i')
+#define PARSER_JUNK mmioFOURCC('J','U','N','K')
+
+#define PARSER_vids mmioFOURCC('v','i','d','s')
+#define PARSER_auds mmioFOURCC('a','u','d','s')
+#define PARSER_mids mmioFOURCC('m','i','d','s')
+#define PARSER_txts mmioFOURCC('t','x','t','s')
+
+#define PARSER_LE_UINT16(ptr) (((DWORD)(ptr)[0])|((DWORD)(ptr)[1]<<8))
+#define PARSER_LE_UINT32(ptr) (((DWORD)(ptr)[0])|((DWORD)(ptr)[1]<<8)|((DWORD)(ptr)[2]<<16)|((DWORD)(ptr)[3]<<24))
+#define PARSER_BE_UINT16(ptr) (((DWORD)(ptr)[0]<<8)|((DWORD)(ptr)[1]))
+#define PARSER_BE_UINT32(ptr) (((DWORD)(ptr)[0]<<24)|((DWORD)(ptr)[1]<<16)|((DWORD)(ptr)[2]<<8)|((DWORD)(ptr)[3]))
+
+HRESULT QUARTZ_CreateWaveParser(IUnknown* punkOuter,void** ppobj);
+
+
+
+#endif /* WINE_DSHOW_PARSER_H */
diff --git a/dlls/quartz/quartz.spec b/dlls/quartz/quartz.spec
index 64e4926..92aa19d 100644
--- a/dlls/quartz/quartz.spec
+++ b/dlls/quartz/quartz.spec
@@ -6,7 +6,7 @@
import ole32.dll
import winmm.dll
import user32.dll
-#import gdi32.dll
+import gdi32.dll
import advapi32.dll
import kernel32.dll
import ntdll.dll
diff --git a/dlls/quartz/sample.c b/dlls/quartz/sample.c
index 03a8f0e..6b30408 100644
--- a/dlls/quartz/sample.c
+++ b/dlls/quartz/sample.c
@@ -25,6 +25,147 @@
/***************************************************************************
*
+ * Helper functions
+ *
+ */
+
+HRESULT QUARTZ_IMediaSample_GetProperties(
+ IMediaSample* pSample,
+ AM_SAMPLE2_PROPERTIES* pProp )
+{
+ HRESULT hr;
+ AM_SAMPLE2_PROPERTIES prop;
+ IMediaSample2* pSample2 = NULL;
+
+ ZeroMemory( &prop, sizeof(AM_SAMPLE2_PROPERTIES) );
+
+#if 0 /* not yet */
+ hr = IMediaSample_QueryInterface( pSample, &IID_IMediaSample2, (void**)&pSample2 );
+ if ( hr == S_OK )
+ {
+ hr = IMediaSample2_GetProperties(pSample2,sizeof(AM_SAMPLE2_PROPERTIES),&prop);
+ IMediaSample2_Release(pSample2);
+ if ( hr == S_OK )
+ {
+ memcpy( pProp, &prop, sizeof(AM_SAMPLE2_PROPERTIES) );
+ pProp->pMediaType =
+ QUARTZ_MediaType_Duplicate( &prop.pMediaType );
+
+ return NOERROR;
+ }
+ }
+#endif
+
+ pProp->cbData = sizeof(AM_SAMPLE2_PROPERTIES);
+ pProp->dwTypeSpecificFlags = 0;
+ pProp->dwSampleFlags = 0;
+ if ( IMediaSample_IsSyncPoint(pSample) == S_OK )
+ pProp->dwSampleFlags |= AM_SAMPLE_SPLICEPOINT;
+ if ( IMediaSample_IsPreroll(pSample) == S_OK )
+ pProp->dwSampleFlags |= AM_SAMPLE_PREROLL;
+ if ( IMediaSample_IsDiscontinuity(pSample) == S_OK )
+ pProp->dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY;
+ pProp->lActual = (LONG)IMediaSample_GetActualDataLength(pSample);
+ if ( IMediaSample_GetTime(pSample,&pProp->tStart,&pProp->tStop) == S_OK )
+ pProp->dwSampleFlags |= AM_SAMPLE_TIMEVALID | AM_SAMPLE_STOPVALID;
+ pProp->dwStreamId = 0;
+ if ( IMediaSample_GetMediaType(pSample,&(pProp->pMediaType)) == S_OK )
+ pProp->dwSampleFlags |= AM_SAMPLE_TYPECHANGED;
+ IMediaSample_GetPointer(pSample,&(pProp->pbBuffer));
+ pProp->cbBuffer = (LONG)IMediaSample_GetSize(pSample);
+
+ return NOERROR;
+}
+
+HRESULT QUARTZ_IMediaSample_SetProperties(
+ IMediaSample* pSample,
+ const AM_SAMPLE2_PROPERTIES* pProp )
+{
+ HRESULT hr;
+ AM_SAMPLE2_PROPERTIES prop;
+ IMediaSample2* pSample2 = NULL;
+
+ memcpy( &prop, pProp, sizeof(AM_SAMPLE2_PROPERTIES) );
+ prop.cbData = sizeof(AM_SAMPLE2_PROPERTIES);
+ prop.pbBuffer = NULL;
+ prop.cbBuffer = 0;
+
+#if 0 /* not yet */
+ hr = IMediaSample_QueryInterface( pSample, &IID_IMediaSample2, (void**)&pSample2 );
+ if ( hr == S_OK )
+ {
+ hr = IMediaSample2_SetProperties(pSample2,sizeof(AM_SAMPLE2_PROPERTIES),&prop);
+ IMediaSample2_Release(pSample2);
+ if ( hr == S_OK )
+ return NOERROR;
+ }
+#endif
+
+ hr = S_OK;
+
+ if ( SUCCEEDED(hr) )
+ hr = IMediaSample_SetSyncPoint(pSample,
+ (prop.dwSampleFlags & AM_SAMPLE_SPLICEPOINT) ? TRUE : FALSE);
+ if ( SUCCEEDED(hr) )
+ hr = IMediaSample_SetPreroll(pSample,
+ (prop.dwSampleFlags & AM_SAMPLE_PREROLL) ? TRUE : FALSE);
+ if ( SUCCEEDED(hr) )
+ hr = IMediaSample_SetDiscontinuity(pSample,
+ (prop.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) ? TRUE : FALSE);
+ if ( SUCCEEDED(hr) )
+ hr = IMediaSample_SetActualDataLength(pSample,prop.lActual);
+ if ( SUCCEEDED(hr) )
+ {
+ if ( ( prop.dwSampleFlags & AM_SAMPLE_TIMEVALID) &&
+ ( prop.dwSampleFlags & AM_SAMPLE_STOPVALID) )
+ hr = IMediaSample_SetTime(pSample,&prop.tStart,&prop.tStop);
+ else
+ hr = IMediaSample_SetTime(pSample,NULL,NULL);
+ }
+ if ( SUCCEEDED(hr) )
+ hr = IMediaSample_SetMediaType(pSample,
+ (prop.dwSampleFlags & AM_SAMPLE_TYPECHANGED) ?
+ prop.pMediaType : NULL);
+
+ return hr;
+}
+
+HRESULT QUARTZ_IMediaSample_Copy(
+ IMediaSample* pDstSample,
+ IMediaSample* pSrcSample,
+ BOOL bCopyData )
+{
+ HRESULT hr;
+ AM_SAMPLE2_PROPERTIES prop;
+ BYTE* pDataSrc = NULL;
+ BYTE* pDataDst = NULL;
+
+ hr = QUARTZ_IMediaSample_GetProperties( pSrcSample, &prop );
+ if ( FAILED(hr) )
+ return hr;
+ hr = QUARTZ_IMediaSample_SetProperties( pDstSample, &prop );
+ if ( prop.pMediaType != NULL )
+ QUARTZ_MediaType_Destroy( prop.pMediaType );
+
+ if ( SUCCEEDED(hr) && bCopyData )
+ {
+ hr = IMediaSample_GetPointer(pSrcSample,&pDataSrc);
+ if ( SUCCEEDED(hr) )
+ hr = IMediaSample_GetPointer(pDstSample,&pDataDst);
+ if ( SUCCEEDED(hr) )
+ {
+ if ( pDataSrc != NULL && pDataDst != NULL )
+ memcpy( pDataDst, pDataSrc, prop.lActual );
+ else
+ hr = E_FAIL;
+ }
+ }
+
+ return hr;
+}
+
+/***************************************************************************
+ *
* CMemMediaSample::IMediaSample2
*
*/
@@ -69,6 +210,12 @@
TRACE("(%p)->()\n",This);
+ if ( This->ref == 0 )
+ {
+ ERR("(%p) - released sample!\n",This);
+ return 0;
+ }
+
ref = InterlockedExchangeAdd(&(This->ref),-1) - 1;
if ( ref > 0 )
return (ULONG)ref;
@@ -97,6 +244,12 @@
TRACE("(%p)->()\n",This);
+ if ( This->ref == 0 )
+ {
+ ERR("(%p) - released sample!\n",This);
+ return E_UNEXPECTED;
+ }
+
if ( ppData == NULL )
return E_POINTER;
@@ -121,6 +274,12 @@
TRACE("(%p)->(%p,%p)\n",This,prtStart,prtEnd);
+ if ( This->ref == 0 )
+ {
+ ERR("(%p) - released sample!\n",This);
+ return E_UNEXPECTED;
+ }
+
if ( prtStart == NULL || prtEnd == NULL )
return E_POINTER;
@@ -226,7 +385,7 @@
TRACE("(%p)->(%ld)\n",This,lLength);
- if ( This->prop.cbBuffer > lLength )
+ if ( This->prop.cbBuffer < lLength )
return E_INVALIDARG;
This->prop.lActual = lLength;
diff --git a/dlls/quartz/sample.h b/dlls/quartz/sample.h
index 834e866..bf0c9d5 100644
--- a/dlls/quartz/sample.h
+++ b/dlls/quartz/sample.h
@@ -31,4 +31,18 @@
void QUARTZ_DestroyMemMediaSample(
CMemMediaSample* pSample );
+
+HRESULT QUARTZ_IMediaSample_GetProperties(
+ IMediaSample* pSample,
+ AM_SAMPLE2_PROPERTIES* pProp );
+HRESULT QUARTZ_IMediaSample_SetProperties(
+ IMediaSample* pSample,
+ const AM_SAMPLE2_PROPERTIES* pProp );
+HRESULT QUARTZ_IMediaSample_Copy(
+ IMediaSample* pDstSample,
+ IMediaSample* pSrcSample,
+ BOOL bCopyData );
+
+
+
#endif /* WINE_DSHOW_SAMPLE_H */
diff --git a/dlls/quartz/vidren.c b/dlls/quartz/vidren.c
new file mode 100644
index 0000000..e30a076
--- /dev/null
+++ b/dlls/quartz/vidren.c
@@ -0,0 +1,1774 @@
+/*
+ * Implements CLSID_VideoRenderer.
+ *
+ * hidenori@a2.ctktv.ne.jp
+ *
+ * FIXME - use clock
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winerror.h"
+#include "wine/obj_base.h"
+#include "wine/obj_oleaut.h"
+#include "mmsystem.h"
+#include "strmif.h"
+#include "control.h"
+#include "vfwmsgs.h"
+#include "uuids.h"
+#include "amvideo.h"
+#include "evcode.h"
+
+#include "debugtools.h"
+DEFAULT_DEBUG_CHANNEL(quartz);
+
+#include "quartz_private.h"
+#include "vidren.h"
+
+
+static const WCHAR QUARTZ_VideoRenderer_Name[] =
+{ 'V','i','d','e','o',' ','R','e','n','d','e','r','e','r',0 };
+static const WCHAR QUARTZ_VideoRendererPin_Name[] =
+{ 'I','n',0 };
+
+#define VIDRENMSG_UPDATE (WM_APP+0)
+#define VIDRENMSG_ENDTHREAD (WM_APP+1)
+
+static const CHAR VIDREN_szWndClass[] = "Wine_VideoRenderer";
+static const CHAR VIDREN_szWndName[] = "Wine Video Renderer";
+
+
+
+
+static void VIDREN_OnPaint( CVideoRendererImpl* This, HWND hwnd )
+{
+ PAINTSTRUCT ps;
+ const VIDEOINFOHEADER* pinfo;
+ const AM_MEDIA_TYPE* pmt;
+
+ TRACE("(%p,%08x)\n",This,hwnd);
+
+ if ( !BeginPaint( hwnd, &ps ) )
+ return;
+
+ pmt = This->pPin->pin.pmtConn;
+ if ( (!This->m_bSampleIsValid) || pmt == NULL )
+ goto err;
+
+ pinfo = (const VIDEOINFOHEADER*)pmt->pbFormat;
+
+ StretchDIBits(
+ ps.hdc,
+ 0, 0,
+ abs(pinfo->bmiHeader.biWidth), abs(pinfo->bmiHeader.biHeight),
+ 0, 0,
+ abs(pinfo->bmiHeader.biWidth), abs(pinfo->bmiHeader.biHeight),
+ This->m_pSampleData, (BITMAPINFO*)(&pinfo->bmiHeader),
+ DIB_RGB_COLORS, SRCCOPY );
+
+err:
+ EndPaint( hwnd, &ps );
+}
+
+static void VIDREN_OnQueryNewPalette( CVideoRendererImpl* This, HWND hwnd )
+{
+ FIXME("(%p,%08x)\n",This,hwnd);
+}
+
+static void VIDREN_OnUpdate( CVideoRendererImpl* This, HWND hwnd )
+{
+ MSG msg;
+
+ TRACE("(%p,%08x)\n",This,hwnd);
+
+ InvalidateRect(hwnd,NULL,FALSE);
+ UpdateWindow(hwnd);
+
+ /* FIXME */
+ while ( PeekMessageA(&msg,hwnd,
+ VIDRENMSG_UPDATE,VIDRENMSG_UPDATE,
+ PM_REMOVE) != FALSE )
+ {
+ /* discard this message. */
+ }
+}
+
+
+static LRESULT CALLBACK
+VIDREN_WndProc(
+ HWND hwnd, UINT message,
+ WPARAM wParam, LPARAM lParam )
+{
+ CVideoRendererImpl* This = (CVideoRendererImpl*)
+ GetWindowLongA( hwnd, 0L );
+
+ TRACE("(%p) - %u/%u/%ld\n",This,message,wParam,lParam);
+
+ if ( message == WM_NCCREATE )
+ {
+ This = (CVideoRendererImpl*)(((CREATESTRUCTA*)lParam)->lpCreateParams);
+ SetWindowLongA( hwnd, 0L, (LONG)This );
+ This->m_hwnd = hwnd;
+ }
+
+ if ( message == WM_NCDESTROY )
+ {
+ PostQuitMessage(0);
+ This->m_hwnd = (HWND)NULL;
+ SetWindowLongA( hwnd, 0L, (LONG)NULL );
+ This = NULL;
+ }
+
+ if ( This != NULL )
+ {
+ switch ( message )
+ {
+ case WM_PAINT:
+ TRACE("WM_PAINT begin\n");
+ EnterCriticalSection( &This->m_csSample );
+ VIDREN_OnPaint( This, hwnd );
+ LeaveCriticalSection( &This->m_csSample );
+ TRACE("WM_PAINT end\n");
+ return 0;
+ case WM_CLOSE:
+ ShowWindow( hwnd, SW_HIDE );
+ return 0;
+ case WM_PALETTECHANGED:
+ if ( hwnd == (HWND)wParam )
+ break;
+ /* fall through */
+ case WM_QUERYNEWPALETTE:
+ VIDREN_OnQueryNewPalette( This, hwnd );
+ break;
+ case VIDRENMSG_UPDATE:
+ VIDREN_OnUpdate( This, hwnd );
+ return 0;
+ case VIDRENMSG_ENDTHREAD:
+ DestroyWindow(hwnd);
+ return 0;
+ default:
+ break;
+ }
+ }
+
+ return DefWindowProcA( hwnd, message, wParam, lParam );
+}
+
+static BOOL VIDREN_Register( HINSTANCE hInst )
+{
+ WNDCLASSA wc;
+ ATOM atom;
+
+ wc.style = 0;
+ wc.lpfnWndProc = VIDREN_WndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = sizeof(LONG);
+ wc.hInstance = hInst;
+ wc.hIcon = LoadIconA((HINSTANCE)NULL,IDI_WINLOGOA);
+ wc.hCursor = LoadCursorA((HINSTANCE)NULL,IDC_ARROWA);
+ wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = VIDREN_szWndClass;
+
+ atom = RegisterClassA( &wc );
+ if ( atom != (ATOM)0 )
+ return TRUE;
+
+ /* FIXME */
+ return FALSE;
+}
+
+static HWND VIDREN_Create( HWND hwndOwner, CVideoRendererImpl* This )
+{
+ HINSTANCE hInst = (HINSTANCE)GetModuleHandleA(NULL);
+ const VIDEOINFOHEADER* pinfo;
+ DWORD dwExStyle = 0;
+ DWORD dwStyle = WS_OVERLAPPED|WS_CAPTION|WS_MINIMIZEBOX|WS_MAXIMIZEBOX;
+ RECT rcWnd;
+
+ if ( !VIDREN_Register( hInst ) )
+ return (HWND)NULL;
+
+ pinfo = (const VIDEOINFOHEADER*)This->pPin->pin.pmtConn->pbFormat;
+
+ TRACE("width %ld, height %ld\n", pinfo->bmiHeader.biWidth, pinfo->bmiHeader.biHeight);
+
+ rcWnd.left = 0;
+ rcWnd.top = 0;
+ rcWnd.right = pinfo->bmiHeader.biWidth;
+ rcWnd.bottom = abs(pinfo->bmiHeader.biHeight);
+ AdjustWindowRectEx( &rcWnd, dwStyle, FALSE, dwExStyle );
+
+ TRACE("window width %d,height %d\n",
+ rcWnd.right-rcWnd.left,rcWnd.bottom-rcWnd.top);
+
+ return CreateWindowExA(
+ dwExStyle,
+ VIDREN_szWndClass, VIDREN_szWndName,
+ dwStyle | WS_VISIBLE,
+ 100,100, /* FIXME */
+ rcWnd.right-rcWnd.left, rcWnd.bottom-rcWnd.top,
+ hwndOwner, (HMENU)NULL,
+ hInst, (LPVOID)This );
+}
+
+static DWORD WINAPI VIDREN_ThreadEntry( LPVOID pv )
+{
+ CVideoRendererImpl* This = (CVideoRendererImpl*)pv;
+ MSG msg;
+
+ TRACE("(%p)\n",This);
+ if ( !VIDREN_Create( (HWND)NULL, This ) )
+ return 0;
+ TRACE("VIDREN_Create succeeded\n");
+
+ SetEvent( This->m_hEventInit );
+ TRACE("Enter message loop\n");
+
+ while ( GetMessageA(&msg,(HWND)NULL,0,0) )
+ {
+ TranslateMessage(&msg);
+ DispatchMessageA(&msg);
+ }
+
+ return 0;
+}
+
+static HRESULT VIDREN_StartThread( CVideoRendererImpl* This )
+{
+ DWORD dwRes;
+ DWORD dwThreadId;
+ HANDLE hEvents[2];
+
+ if ( This->m_hEventInit != (HANDLE)NULL ||
+ This->m_hwnd != (HWND)NULL ||
+ This->m_hThread != (HANDLE)NULL ||
+ This->pPin->pin.pmtConn == NULL )
+ return E_UNEXPECTED;
+
+ This->m_hEventInit = CreateEventA(NULL,TRUE,FALSE,NULL);
+ if ( This->m_hEventInit == (HANDLE)NULL )
+ return E_OUTOFMEMORY;
+
+ This->m_hThread = CreateThread(
+ NULL, 0,
+ VIDREN_ThreadEntry,
+ (LPVOID)This,
+ 0, &dwThreadId );
+ if ( This->m_hThread == (HANDLE)NULL )
+ return E_FAIL;
+
+ hEvents[0] = This->m_hEventInit;
+ hEvents[1] = This->m_hThread;
+
+ dwRes = WaitForMultipleObjects(2,hEvents,FALSE,INFINITE);
+ if ( dwRes != WAIT_OBJECT_0 )
+ return E_FAIL;
+
+ return S_OK;
+}
+
+static void VIDREN_EndThread( CVideoRendererImpl* This )
+{
+ if ( This->m_hwnd != (HWND)NULL )
+ PostMessageA( This->m_hwnd, VIDRENMSG_ENDTHREAD, 0, 0 );
+
+ if ( This->m_hThread != (HANDLE)NULL )
+ {
+ WaitForSingleObject( This->m_hThread, INFINITE );
+ CloseHandle( This->m_hThread );
+ This->m_hThread = (HANDLE)NULL;
+ }
+ if ( This->m_hEventInit != (HANDLE)NULL )
+ {
+ CloseHandle( This->m_hEventInit );
+ This->m_hEventInit = (HANDLE)NULL;
+ }
+}
+
+
+
+/***************************************************************************
+ *
+ * CVideoRendererImpl methods
+ *
+ */
+
+static HRESULT CVideoRendererImpl_OnActive( CBaseFilterImpl* pImpl )
+{
+ CVideoRendererImpl_THIS(pImpl,basefilter);
+
+ FIXME( "(%p)\n", This );
+
+ This->m_bSampleIsValid = FALSE;
+
+ return NOERROR;
+}
+
+static HRESULT CVideoRendererImpl_OnInactive( CBaseFilterImpl* pImpl )
+{
+ CVideoRendererImpl_THIS(pImpl,basefilter);
+
+ FIXME( "(%p)\n", This );
+
+ EnterCriticalSection( &This->m_csSample );
+ This->m_bSampleIsValid = FALSE;
+ LeaveCriticalSection( &This->m_csSample );
+
+ return NOERROR;
+}
+
+static const CBaseFilterHandlers filterhandlers =
+{
+ CVideoRendererImpl_OnActive, /* pOnActive */
+ CVideoRendererImpl_OnInactive, /* pOnInactive */
+ NULL, /* pOnStop */
+};
+
+/***************************************************************************
+ *
+ * CVideoRendererPinImpl methods
+ *
+ */
+
+static HRESULT CVideoRendererPinImpl_OnPreConnect( CPinBaseImpl* pImpl, IPin* pPin )
+{
+ CVideoRendererPinImpl_THIS(pImpl,pin);
+
+ TRACE("(%p,%p)\n",This,pPin);
+
+ return NOERROR;
+}
+
+static HRESULT CVideoRendererPinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin )
+{
+ CVideoRendererPinImpl_THIS(pImpl,pin);
+ const VIDEOINFOHEADER* pinfo;
+ HRESULT hr;
+
+ TRACE("(%p,%p)\n",This,pPin);
+
+ if ( This->pRender->m_pSampleData != NULL )
+ {
+ QUARTZ_FreeMem(This->pRender->m_pSampleData);
+ This->pRender->m_pSampleData = NULL;
+ }
+ This->pRender->m_cbSampleData = 0;
+ This->pRender->m_bSampleIsValid = FALSE;
+
+ pinfo = (const VIDEOINFOHEADER*)This->pin.pmtConn->pbFormat;
+ if ( pinfo == NULL )
+ return E_FAIL;
+
+ This->pRender->m_bSampleIsValid = FALSE;
+ This->pRender->m_cbSampleData = DIBSIZE(pinfo->bmiHeader);
+ This->pRender->m_pSampleData = (BYTE*)QUARTZ_AllocMem(This->pRender->m_cbSampleData);
+ if ( This->pRender->m_pSampleData == NULL )
+ return E_OUTOFMEMORY;
+
+ hr = VIDREN_StartThread(This->pRender);
+ if ( FAILED(hr) )
+ return hr;
+
+ return NOERROR;
+}
+
+static HRESULT CVideoRendererPinImpl_OnDisconnect( CPinBaseImpl* pImpl )
+{
+ CVideoRendererPinImpl_THIS(pImpl,pin);
+
+ TRACE("(%p)\n",This);
+
+ VIDREN_EndThread(This->pRender);
+
+ if ( This->pRender->m_pSampleData != NULL )
+ {
+ QUARTZ_FreeMem(This->pRender->m_pSampleData);
+ This->pRender->m_pSampleData = NULL;
+ }
+ This->pRender->m_cbSampleData = 0;
+ This->pRender->m_bSampleIsValid = FALSE;
+
+ return NOERROR;
+}
+
+static HRESULT CVideoRendererPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
+{
+ CVideoRendererPinImpl_THIS(pImpl,pin);
+ const VIDEOINFOHEADER* pinfo;
+
+ TRACE("(%p,%p)\n",This,pmt);
+
+ if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Video ) )
+ return E_FAIL;
+ if ( !IsEqualGUID( &pmt->formattype, &FORMAT_VideoInfo ) )
+ return E_FAIL;
+ /*
+ * check subtype.
+ */
+ if ( !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_RGB555 ) &&
+ !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_RGB565 ) &&
+ !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_RGB24 ) &&
+ !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_RGB32 ) )
+ return E_FAIL;
+
+ /****
+ *
+ *
+ if ( !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_RGB8 ) &&
+ !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_RGB555 ) &&
+ !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_RGB565 ) &&
+ !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_RGB24 ) &&
+ !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_RGB32 ) )
+ return E_FAIL;
+ *
+ ****/
+
+ pinfo = (const VIDEOINFOHEADER*)pmt->pbFormat;
+ if ( pinfo == NULL ||
+ pinfo->bmiHeader.biSize < sizeof(BITMAPINFOHEADER) ||
+ pinfo->bmiHeader.biWidth <= 0 ||
+ pinfo->bmiHeader.biHeight == 0 ||
+ pinfo->bmiHeader.biPlanes != 1 ||
+ pinfo->bmiHeader.biCompression != 0 )
+ return E_FAIL;
+
+ return NOERROR;
+}
+
+static HRESULT CVideoRendererPinImpl_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample )
+{
+ CVideoRendererPinImpl_THIS(pImpl,pin);
+ HWND hwnd;
+ BYTE* pData = NULL;
+ LONG lLength;
+ HRESULT hr;
+
+ TRACE( "(%p,%p)\n",This,pSample );
+
+ hwnd = This->pRender->m_hwnd;
+ if ( hwnd == (HWND)NULL ||
+ This->pRender->m_hThread == (HWND)NULL )
+ return E_UNEXPECTED;
+ if ( This->pRender->m_fInFlush )
+ return S_FALSE;
+ if ( pSample == NULL )
+ return E_POINTER;
+
+ /* FIXME - wait/skip/qualitycontrol */
+
+
+ /* duplicate this sample. */
+ hr = IMediaSample_GetPointer(pSample,&pData);
+ if ( FAILED(hr) )
+ return hr;
+ lLength = (LONG)IMediaSample_GetActualDataLength(pSample);
+ if ( lLength <= 0 || (lLength < (LONG)This->pRender->m_cbSampleData) )
+ {
+ ERR( "invalid length: %ld\n", lLength );
+ return NOERROR;
+ }
+
+ EnterCriticalSection( &This->pRender->m_csSample );
+ memcpy(This->pRender->m_pSampleData,pData,lLength);
+ This->pRender->m_bSampleIsValid = TRUE;
+ PostMessageA( hwnd, VIDRENMSG_UPDATE, 0, 0 );
+ LeaveCriticalSection( &This->pRender->m_csSample );
+
+ return NOERROR;
+}
+
+static HRESULT CVideoRendererPinImpl_ReceiveCanBlock( CPinBaseImpl* pImpl )
+{
+ CVideoRendererPinImpl_THIS(pImpl,pin);
+
+ TRACE( "(%p)\n", This );
+
+ /* might block. */
+ return S_OK;
+}
+
+static HRESULT CVideoRendererPinImpl_EndOfStream( CPinBaseImpl* pImpl )
+{
+ CVideoRendererPinImpl_THIS(pImpl,pin);
+
+ FIXME( "(%p)\n", This );
+
+ This->pRender->m_fInFlush = FALSE;
+
+ /* FIXME - don't notify twice until stopped or seeked. */
+ return CBaseFilterImpl_MediaEventNotify(
+ &This->pRender->basefilter, EC_COMPLETE,
+ (LONG_PTR)S_OK, (LONG_PTR)(IBaseFilter*)(This->pRender) );
+}
+
+static HRESULT CVideoRendererPinImpl_BeginFlush( CPinBaseImpl* pImpl )
+{
+ CVideoRendererPinImpl_THIS(pImpl,pin);
+
+ FIXME( "(%p)\n", This );
+
+ This->pRender->m_fInFlush = TRUE;
+ EnterCriticalSection( &This->pRender->m_csSample );
+ This->pRender->m_bSampleIsValid = FALSE;
+ LeaveCriticalSection( &This->pRender->m_csSample );
+
+ return NOERROR;
+}
+
+static HRESULT CVideoRendererPinImpl_EndFlush( CPinBaseImpl* pImpl )
+{
+ CVideoRendererPinImpl_THIS(pImpl,pin);
+
+ FIXME( "(%p)\n", This );
+
+ This->pRender->m_fInFlush = FALSE;
+
+ return NOERROR;
+}
+
+static HRESULT CVideoRendererPinImpl_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate )
+{
+ CVideoRendererPinImpl_THIS(pImpl,pin);
+
+ FIXME( "(%p)\n", This );
+
+ This->pRender->m_fInFlush = FALSE;
+
+ return NOERROR;
+}
+
+
+
+
+static const CBasePinHandlers pinhandlers =
+{
+ CVideoRendererPinImpl_OnPreConnect, /* pOnPreConnect */
+ CVideoRendererPinImpl_OnPostConnect, /* pOnPostConnect */
+ CVideoRendererPinImpl_OnDisconnect, /* pOnDisconnect */
+ CVideoRendererPinImpl_CheckMediaType, /* pCheckMediaType */
+ NULL, /* pQualityNotify */
+ CVideoRendererPinImpl_Receive, /* pReceive */
+ CVideoRendererPinImpl_ReceiveCanBlock, /* pReceiveCanBlock */
+ CVideoRendererPinImpl_EndOfStream, /* pEndOfStream */
+ CVideoRendererPinImpl_BeginFlush, /* pBeginFlush */
+ CVideoRendererPinImpl_EndFlush, /* pEndFlush */
+ CVideoRendererPinImpl_NewSegment, /* pNewSegment */
+};
+
+
+/***************************************************************************
+ *
+ * new/delete CVideoRendererImpl
+ *
+ */
+
+/* can I use offsetof safely? - FIXME? */
+static QUARTZ_IFEntry FilterIFEntries[] =
+{
+ { &IID_IPersist, offsetof(CVideoRendererImpl,basefilter)-offsetof(CVideoRendererImpl,unk) },
+ { &IID_IMediaFilter, offsetof(CVideoRendererImpl,basefilter)-offsetof(CVideoRendererImpl,unk) },
+ { &IID_IBaseFilter, offsetof(CVideoRendererImpl,basefilter)-offsetof(CVideoRendererImpl,unk) },
+ { &IID_IBasicVideo, offsetof(CVideoRendererImpl,basvid)-offsetof(CVideoRendererImpl,unk) },
+ { &IID_IBasicVideo2, offsetof(CVideoRendererImpl,basvid)-offsetof(CVideoRendererImpl,unk) },
+ { &IID_IVideoWindow, offsetof(CVideoRendererImpl,vidwin)-offsetof(CVideoRendererImpl,unk) },
+};
+
+static void QUARTZ_DestroyVideoRenderer(IUnknown* punk)
+{
+ CVideoRendererImpl_THIS(punk,unk);
+
+ TRACE( "(%p)\n", This );
+ CVideoRendererImpl_OnInactive(&This->basefilter);
+ VIDREN_EndThread(This);
+
+ if ( This->pPin != NULL )
+ {
+ IUnknown_Release(This->pPin->unk.punkControl);
+ This->pPin = NULL;
+ }
+
+ CVideoRendererImpl_UninitIBasicVideo2(This);
+ CVideoRendererImpl_UninitIVideoWindow(This);
+ CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
+
+ DeleteCriticalSection( &This->m_csSample );
+}
+
+HRESULT QUARTZ_CreateVideoRenderer(IUnknown* punkOuter,void** ppobj)
+{
+ CVideoRendererImpl* This = NULL;
+ HRESULT hr;
+
+ TRACE("(%p,%p)\n",punkOuter,ppobj);
+
+ This = (CVideoRendererImpl*)
+ QUARTZ_AllocObj( sizeof(CVideoRendererImpl) );
+ if ( This == NULL )
+ return E_OUTOFMEMORY;
+ This->pPin = NULL;
+ This->m_fInFlush = FALSE;
+
+ This->m_hEventInit = (HANDLE)NULL;
+ This->m_hThread = (HANDLE)NULL;
+ This->m_hwnd = (HWND)NULL;
+ This->m_bSampleIsValid = FALSE;
+ This->m_pSampleData = NULL;
+ This->m_cbSampleData = 0;
+
+ QUARTZ_IUnkInit( &This->unk, punkOuter );
+
+ hr = CBaseFilterImpl_InitIBaseFilter(
+ &This->basefilter,
+ This->unk.punkControl,
+ &CLSID_VideoRenderer,
+ QUARTZ_VideoRenderer_Name,
+ &filterhandlers );
+ if ( SUCCEEDED(hr) )
+ {
+ hr = CVideoRendererImpl_InitIBasicVideo2(This);
+ if ( SUCCEEDED(hr) )
+ {
+ hr = CVideoRendererImpl_InitIVideoWindow(This);
+ if ( FAILED(hr) )
+ {
+ CVideoRendererImpl_UninitIBasicVideo2(This);
+ }
+ }
+ if ( FAILED(hr) )
+ {
+ CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
+ }
+ }
+
+ if ( FAILED(hr) )
+ {
+ QUARTZ_FreeObj(This);
+ return hr;
+ }
+
+ This->unk.pEntries = FilterIFEntries;
+ This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]);
+ This->unk.pOnFinalRelease = QUARTZ_DestroyVideoRenderer;
+
+ hr = QUARTZ_CreateVideoRendererPin(
+ This,
+ &This->basefilter.csFilter,
+ &This->pPin );
+ if ( SUCCEEDED(hr) )
+ hr = QUARTZ_CompList_AddComp(
+ This->basefilter.pInPins,
+ (IUnknown*)&This->pPin->pin,
+ NULL, 0 );
+ if ( FAILED(hr) )
+ {
+ IUnknown_Release( This->unk.punkControl );
+ return hr;
+ }
+
+ InitializeCriticalSection( &This->m_csSample );
+
+ *ppobj = (void*)&(This->unk);
+
+ return S_OK;
+}
+
+/***************************************************************************
+ *
+ * new/delete CVideoRendererPinImpl
+ *
+ */
+
+/* can I use offsetof safely? - FIXME? */
+static QUARTZ_IFEntry PinIFEntries[] =
+{
+ { &IID_IPin, offsetof(CVideoRendererPinImpl,pin)-offsetof(CVideoRendererPinImpl,unk) },
+ { &IID_IMemInputPin, offsetof(CVideoRendererPinImpl,meminput)-offsetof(CVideoRendererPinImpl,unk) },
+};
+
+static void QUARTZ_DestroyVideoRendererPin(IUnknown* punk)
+{
+ CVideoRendererPinImpl_THIS(punk,unk);
+
+ TRACE( "(%p)\n", This );
+
+ CPinBaseImpl_UninitIPin( &This->pin );
+ CMemInputPinBaseImpl_UninitIMemInputPin( &This->meminput );
+}
+
+HRESULT QUARTZ_CreateVideoRendererPin(
+ CVideoRendererImpl* pFilter,
+ CRITICAL_SECTION* pcsPin,
+ CVideoRendererPinImpl** ppPin)
+{
+ CVideoRendererPinImpl* This = NULL;
+ HRESULT hr;
+
+ TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
+
+ This = (CVideoRendererPinImpl*)
+ QUARTZ_AllocObj( sizeof(CVideoRendererPinImpl) );
+ if ( This == NULL )
+ return E_OUTOFMEMORY;
+
+ QUARTZ_IUnkInit( &This->unk, NULL );
+ This->pRender = pFilter;
+
+ hr = CPinBaseImpl_InitIPin(
+ &This->pin,
+ This->unk.punkControl,
+ pcsPin,
+ &pFilter->basefilter,
+ QUARTZ_VideoRendererPin_Name,
+ FALSE,
+ &pinhandlers );
+
+ if ( SUCCEEDED(hr) )
+ {
+ hr = CMemInputPinBaseImpl_InitIMemInputPin(
+ &This->meminput,
+ This->unk.punkControl,
+ &This->pin );
+ if ( FAILED(hr) )
+ {
+ CPinBaseImpl_UninitIPin( &This->pin );
+ }
+ }
+
+ if ( FAILED(hr) )
+ {
+ QUARTZ_FreeObj(This);
+ return hr;
+ }
+
+ This->unk.pEntries = PinIFEntries;
+ This->unk.dwEntries = sizeof(PinIFEntries)/sizeof(PinIFEntries[0]);
+ This->unk.pOnFinalRelease = QUARTZ_DestroyVideoRendererPin;
+
+ *ppPin = This;
+
+ TRACE("returned successfully.\n");
+
+ return S_OK;
+}
+
+/***************************************************************************
+ *
+ * CVideoRendererImpl::IBasicVideo2
+ *
+ */
+
+
+static HRESULT WINAPI
+IBasicVideo2_fnQueryInterface(IBasicVideo2* iface,REFIID riid,void** ppobj)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ TRACE("(%p)->()\n",This);
+
+ return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
+}
+
+static ULONG WINAPI
+IBasicVideo2_fnAddRef(IBasicVideo2* iface)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ TRACE("(%p)->()\n",This);
+
+ return IUnknown_AddRef(This->unk.punkControl);
+}
+
+static ULONG WINAPI
+IBasicVideo2_fnRelease(IBasicVideo2* iface)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ TRACE("(%p)->()\n",This);
+
+ return IUnknown_Release(This->unk.punkControl);
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnGetTypeInfoCount(IBasicVideo2* iface,UINT* pcTypeInfo)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnGetTypeInfo(IBasicVideo2* iface,UINT iTypeInfo, LCID lcid, ITypeInfo** ppobj)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnGetIDsOfNames(IBasicVideo2* iface,REFIID riid, LPOLESTR* ppwszName, UINT cNames, LCID lcid, DISPID* pDispId)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnInvoke(IBasicVideo2* iface,DISPID DispId, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarRes, EXCEPINFO* pExcepInfo, UINT* puArgErr)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+
+static HRESULT WINAPI
+IBasicVideo2_fnget_AvgTimePerFrame(IBasicVideo2* iface,REFTIME* prefTime)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnget_BitRate(IBasicVideo2* iface,long* plRate)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnget_BitErrorRate(IBasicVideo2* iface,long* plRate)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnget_VideoWidth(IBasicVideo2* iface,long* plWidth)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnget_VideoHeight(IBasicVideo2* iface,long* plHeight)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnput_SourceLeft(IBasicVideo2* iface,long lLeft)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnget_SourceLeft(IBasicVideo2* iface,long* plLeft)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnput_SourceWidth(IBasicVideo2* iface,long lWidth)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnget_SourceWidth(IBasicVideo2* iface,long* plWidth)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnput_SourceTop(IBasicVideo2* iface,long lTop)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnget_SourceTop(IBasicVideo2* iface,long* plTop)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnput_SourceHeight(IBasicVideo2* iface,long lHeight)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnget_SourceHeight(IBasicVideo2* iface,long* plHeight)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnput_DestinationLeft(IBasicVideo2* iface,long lLeft)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnget_DestinationLeft(IBasicVideo2* iface,long* plLeft)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnput_DestinationWidth(IBasicVideo2* iface,long lWidth)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnget_DestinationWidth(IBasicVideo2* iface,long* plWidth)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnput_DestinationTop(IBasicVideo2* iface,long lTop)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnget_DestinationTop(IBasicVideo2* iface,long* plTop)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnput_DestinationHeight(IBasicVideo2* iface,long lHeight)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnget_DestinationHeight(IBasicVideo2* iface,long* plHeight)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnSetSourcePosition(IBasicVideo2* iface,long lLeft,long lTop,long lWidth,long lHeight)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnGetSourcePosition(IBasicVideo2* iface,long* plLeft,long* plTop,long* plWidth,long* plHeight)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnSetDefaultSourcePosition(IBasicVideo2* iface)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnSetDestinationPosition(IBasicVideo2* iface,long lLeft,long lTop,long lWidth,long lHeight)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnGetDestinationPosition(IBasicVideo2* iface,long* plLeft,long* plTop,long* plWidth,long* plHeight)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnSetDefaultDestinationPosition(IBasicVideo2* iface)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnGetVideoSize(IBasicVideo2* iface,long* plWidth,long* plHeight)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnGetVideoPaletteEntries(IBasicVideo2* iface,long lStart,long lCount,long* plRet,long* plPaletteEntry)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnGetCurrentImage(IBasicVideo2* iface,long* plBufferSize,long* plDIBBuffer)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnIsUsingDefaultSource(IBasicVideo2* iface)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnIsUsingDefaultDestination(IBasicVideo2* iface)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IBasicVideo2_fnGetPreferredAspectRatio(IBasicVideo2* iface,long* plRateX,long* plRateY)
+{
+ CVideoRendererImpl_THIS(iface,basvid);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+
+
+
+static ICOM_VTABLE(IBasicVideo2) ibasicvideo =
+{
+ ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+ /* IUnknown fields */
+ IBasicVideo2_fnQueryInterface,
+ IBasicVideo2_fnAddRef,
+ IBasicVideo2_fnRelease,
+ /* IDispatch fields */
+ IBasicVideo2_fnGetTypeInfoCount,
+ IBasicVideo2_fnGetTypeInfo,
+ IBasicVideo2_fnGetIDsOfNames,
+ IBasicVideo2_fnInvoke,
+ /* IBasicVideo fields */
+ IBasicVideo2_fnget_AvgTimePerFrame,
+ IBasicVideo2_fnget_BitRate,
+ IBasicVideo2_fnget_BitErrorRate,
+ IBasicVideo2_fnget_VideoWidth,
+ IBasicVideo2_fnget_VideoHeight,
+ IBasicVideo2_fnput_SourceLeft,
+ IBasicVideo2_fnget_SourceLeft,
+ IBasicVideo2_fnput_SourceWidth,
+ IBasicVideo2_fnget_SourceWidth,
+ IBasicVideo2_fnput_SourceTop,
+ IBasicVideo2_fnget_SourceTop,
+ IBasicVideo2_fnput_SourceHeight,
+ IBasicVideo2_fnget_SourceHeight,
+ IBasicVideo2_fnput_DestinationLeft,
+ IBasicVideo2_fnget_DestinationLeft,
+ IBasicVideo2_fnput_DestinationWidth,
+ IBasicVideo2_fnget_DestinationWidth,
+ IBasicVideo2_fnput_DestinationTop,
+ IBasicVideo2_fnget_DestinationTop,
+ IBasicVideo2_fnput_DestinationHeight,
+ IBasicVideo2_fnget_DestinationHeight,
+ IBasicVideo2_fnSetSourcePosition,
+ IBasicVideo2_fnGetSourcePosition,
+ IBasicVideo2_fnSetDefaultSourcePosition,
+ IBasicVideo2_fnSetDestinationPosition,
+ IBasicVideo2_fnGetDestinationPosition,
+ IBasicVideo2_fnSetDefaultDestinationPosition,
+ IBasicVideo2_fnGetVideoSize,
+ IBasicVideo2_fnGetVideoPaletteEntries,
+ IBasicVideo2_fnGetCurrentImage,
+ IBasicVideo2_fnIsUsingDefaultSource,
+ IBasicVideo2_fnIsUsingDefaultDestination,
+ /* IBasicVideo2 fields */
+ IBasicVideo2_fnGetPreferredAspectRatio,
+};
+
+
+HRESULT CVideoRendererImpl_InitIBasicVideo2( CVideoRendererImpl* This )
+{
+ TRACE("(%p)\n",This);
+ ICOM_VTBL(&This->basvid) = &ibasicvideo;
+
+ return NOERROR;
+}
+
+void CVideoRendererImpl_UninitIBasicVideo2( CVideoRendererImpl* This )
+{
+ TRACE("(%p)\n",This);
+}
+
+/***************************************************************************
+ *
+ * CVideoRendererImpl::IVideoWindow
+ *
+ */
+
+
+static HRESULT WINAPI
+IVideoWindow_fnQueryInterface(IVideoWindow* iface,REFIID riid,void** ppobj)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ TRACE("(%p)->()\n",This);
+
+ return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
+}
+
+static ULONG WINAPI
+IVideoWindow_fnAddRef(IVideoWindow* iface)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ TRACE("(%p)->()\n",This);
+
+ return IUnknown_AddRef(This->unk.punkControl);
+}
+
+static ULONG WINAPI
+IVideoWindow_fnRelease(IVideoWindow* iface)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ TRACE("(%p)->()\n",This);
+
+ return IUnknown_Release(This->unk.punkControl);
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnGetTypeInfoCount(IVideoWindow* iface,UINT* pcTypeInfo)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnGetTypeInfo(IVideoWindow* iface,UINT iTypeInfo, LCID lcid, ITypeInfo** ppobj)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnGetIDsOfNames(IVideoWindow* iface,REFIID riid, LPOLESTR* ppwszName, UINT cNames, LCID lcid, DISPID* pDispId)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnInvoke(IVideoWindow* iface,DISPID DispId, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarRes, EXCEPINFO* pExcepInfo, UINT* puArgErr)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+
+
+static HRESULT WINAPI
+IVideoWindow_fnput_Caption(IVideoWindow* iface,BSTR strCaption)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnget_Caption(IVideoWindow* iface,BSTR* pstrCaption)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnput_WindowStyle(IVideoWindow* iface,long lStyle)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnget_WindowStyle(IVideoWindow* iface,long* plStyle)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnput_WindowStyleEx(IVideoWindow* iface,long lExStyle)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnget_WindowStyleEx(IVideoWindow* iface,long* plExStyle)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnput_AutoShow(IVideoWindow* iface,long lAutoShow)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnget_AutoShow(IVideoWindow* iface,long* plAutoShow)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnput_WindowState(IVideoWindow* iface,long lState)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnget_WindowState(IVideoWindow* iface,long* plState)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnput_BackgroundPalette(IVideoWindow* iface,long lBackPal)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnget_BackgroundPalette(IVideoWindow* iface,long* plBackPal)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnput_Visible(IVideoWindow* iface,long lVisible)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnget_Visible(IVideoWindow* iface,long* plVisible)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnput_Left(IVideoWindow* iface,long lLeft)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnget_Left(IVideoWindow* iface,long* plLeft)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnput_Width(IVideoWindow* iface,long lWidth)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnget_Width(IVideoWindow* iface,long* plWidth)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnput_Top(IVideoWindow* iface,long lTop)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnget_Top(IVideoWindow* iface,long* plTop)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnput_Height(IVideoWindow* iface,long lHeight)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnget_Height(IVideoWindow* iface,long* plHeight)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnput_Owner(IVideoWindow* iface,OAHWND hwnd)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnget_Owner(IVideoWindow* iface,OAHWND* phwnd)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnput_MessageDrain(IVideoWindow* iface,OAHWND hwnd)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnget_MessageDrain(IVideoWindow* iface,OAHWND* phwnd)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnget_BorderColor(IVideoWindow* iface,long* plColor)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnput_BorderColor(IVideoWindow* iface,long lColor)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnget_FullScreenMode(IVideoWindow* iface,long* plMode)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnput_FullScreenMode(IVideoWindow* iface,long lMode)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnSetWindowForeground(IVideoWindow* iface,long lFocus)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnNotifyOwnerMessage(IVideoWindow* iface,OAHWND hwnd,long message,LONG_PTR wParam,LONG_PTR lParam)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnSetWindowPosition(IVideoWindow* iface,long lLeft,long lTop,long lWidth,long lHeight)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnGetWindowPosition(IVideoWindow* iface,long* plLeft,long* plTop,long* plWidth,long* plHeight)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnGetMinIdealImageSize(IVideoWindow* iface,long* plWidth,long* plHeight)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnGetMaxIdealImageSize(IVideoWindow* iface,long* plWidth,long* plHeight)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnGetRestorePosition(IVideoWindow* iface,long* plLeft,long* plTop,long* plWidth,long* plHeight)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnHideCursor(IVideoWindow* iface,long lHide)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IVideoWindow_fnIsCursorHidden(IVideoWindow* iface,long* plHide)
+{
+ CVideoRendererImpl_THIS(iface,vidwin);
+
+ FIXME("(%p)->()\n",This);
+
+ return E_NOTIMPL;
+}
+
+
+
+
+static ICOM_VTABLE(IVideoWindow) ivideowindow =
+{
+ ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+ /* IUnknown fields */
+ IVideoWindow_fnQueryInterface,
+ IVideoWindow_fnAddRef,
+ IVideoWindow_fnRelease,
+ /* IDispatch fields */
+ IVideoWindow_fnGetTypeInfoCount,
+ IVideoWindow_fnGetTypeInfo,
+ IVideoWindow_fnGetIDsOfNames,
+ IVideoWindow_fnInvoke,
+ /* IVideoWindow fields */
+ IVideoWindow_fnput_Caption,
+ IVideoWindow_fnget_Caption,
+ IVideoWindow_fnput_WindowStyle,
+ IVideoWindow_fnget_WindowStyle,
+ IVideoWindow_fnput_WindowStyleEx,
+ IVideoWindow_fnget_WindowStyleEx,
+ IVideoWindow_fnput_AutoShow,
+ IVideoWindow_fnget_AutoShow,
+ IVideoWindow_fnput_WindowState,
+ IVideoWindow_fnget_WindowState,
+ IVideoWindow_fnput_BackgroundPalette,
+ IVideoWindow_fnget_BackgroundPalette,
+ IVideoWindow_fnput_Visible,
+ IVideoWindow_fnget_Visible,
+ IVideoWindow_fnput_Left,
+ IVideoWindow_fnget_Left,
+ IVideoWindow_fnput_Width,
+ IVideoWindow_fnget_Width,
+ IVideoWindow_fnput_Top,
+ IVideoWindow_fnget_Top,
+ IVideoWindow_fnput_Height,
+ IVideoWindow_fnget_Height,
+ IVideoWindow_fnput_Owner,
+ IVideoWindow_fnget_Owner,
+ IVideoWindow_fnput_MessageDrain,
+ IVideoWindow_fnget_MessageDrain,
+ IVideoWindow_fnget_BorderColor,
+ IVideoWindow_fnput_BorderColor,
+ IVideoWindow_fnget_FullScreenMode,
+ IVideoWindow_fnput_FullScreenMode,
+ IVideoWindow_fnSetWindowForeground,
+ IVideoWindow_fnNotifyOwnerMessage,
+ IVideoWindow_fnSetWindowPosition,
+ IVideoWindow_fnGetWindowPosition,
+ IVideoWindow_fnGetMinIdealImageSize,
+ IVideoWindow_fnGetMaxIdealImageSize,
+ IVideoWindow_fnGetRestorePosition,
+ IVideoWindow_fnHideCursor,
+ IVideoWindow_fnIsCursorHidden,
+
+};
+
+
+HRESULT CVideoRendererImpl_InitIVideoWindow( CVideoRendererImpl* This )
+{
+ TRACE("(%p)\n",This);
+ ICOM_VTBL(&This->vidwin) = &ivideowindow;
+
+ return NOERROR;
+}
+
+void CVideoRendererImpl_UninitIVideoWindow( CVideoRendererImpl* This )
+{
+ TRACE("(%p)\n",This);
+}
+
diff --git a/dlls/quartz/vidren.h b/dlls/quartz/vidren.h
new file mode 100644
index 0000000..f3b6123
--- /dev/null
+++ b/dlls/quartz/vidren.h
@@ -0,0 +1,74 @@
+/*
+ * Implements CLSID_VideoRenderer.
+ *
+ * hidenori@a2.ctktv.ne.jp
+ */
+
+#ifndef WINE_DSHOW_VIDREN_H
+#define WINE_DSHOW_VIDREN_H
+
+#include "iunk.h"
+#include "basefilt.h"
+
+typedef struct CVideoRendererImpl CVideoRendererImpl;
+typedef struct CVideoRendererPinImpl CVideoRendererPinImpl;
+
+
+typedef struct VidRen_IBasicVideo
+{
+ ICOM_VFIELD(IBasicVideo2);
+} VidRen_IBasicVideo;
+
+typedef struct VidRen_IVideoWindow
+{
+ ICOM_VFIELD(IVideoWindow);
+} VidRen_IVideoWindow;
+
+struct CVideoRendererImpl
+{
+ QUARTZ_IUnkImpl unk;
+ CBaseFilterImpl basefilter;
+ VidRen_IBasicVideo basvid;
+ VidRen_IVideoWindow vidwin;
+
+ CVideoRendererPinImpl* pPin;
+
+ BOOL m_fInFlush;
+
+ /* for rendering */
+ HANDLE m_hEventInit;
+ HANDLE m_hThread;
+ HWND m_hwnd;
+ CRITICAL_SECTION m_csSample;
+ BOOL m_bSampleIsValid;
+ BYTE* m_pSampleData;
+ DWORD m_cbSampleData;
+};
+
+struct CVideoRendererPinImpl
+{
+ QUARTZ_IUnkImpl unk;
+ CPinBaseImpl pin;
+ CMemInputPinBaseImpl meminput;
+
+ CVideoRendererImpl* pRender;
+};
+
+
+
+#define CVideoRendererImpl_THIS(iface,member) CVideoRendererImpl* This = ((CVideoRendererImpl*)(((char*)iface)-offsetof(CVideoRendererImpl,member)))
+#define CVideoRendererPinImpl_THIS(iface,member) CVideoRendererPinImpl* This = ((CVideoRendererPinImpl*)(((char*)iface)-offsetof(CVideoRendererPinImpl,member)))
+
+HRESULT CVideoRendererImpl_InitIBasicVideo2( CVideoRendererImpl* This );
+void CVideoRendererImpl_UninitIBasicVideo2( CVideoRendererImpl* This );
+HRESULT CVideoRendererImpl_InitIVideoWindow( CVideoRendererImpl* This );
+void CVideoRendererImpl_UninitIVideoWindow( CVideoRendererImpl* This );
+
+HRESULT QUARTZ_CreateVideoRenderer(IUnknown* punkOuter,void** ppobj);
+HRESULT QUARTZ_CreateVideoRendererPin(
+ CVideoRendererImpl* pFilter,
+ CRITICAL_SECTION* pcsPin,
+ CVideoRendererPinImpl** ppPin);
+
+
+#endif /* WINE_DSHOW_VIDREN_H */
diff --git a/dlls/quartz/wavparse.c b/dlls/quartz/wavparse.c
new file mode 100644
index 0000000..6514e99
--- /dev/null
+++ b/dlls/quartz/wavparse.c
@@ -0,0 +1,473 @@
+/*
+ * Implements WAVE/AU/AIFF Parser.
+ *
+ * hidenori@a2.ctktv.ne.jp
+ */
+
+#include "config.h"
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "mmsystem.h"
+#include "winerror.h"
+#include "wine/obj_base.h"
+#include "strmif.h"
+#include "vfwmsgs.h"
+#include "uuids.h"
+
+#include "debugtools.h"
+DEFAULT_DEBUG_CHANNEL(quartz);
+
+#include "quartz_private.h"
+
+/* for CLSID_quartzWaveParser. */
+#include "initguid.h"
+#include "parser.h"
+
+
+static const WCHAR QUARTZ_WaveParser_Name[] =
+{ 'W','a','v','e',' ','P','a','r','s','e','r',0 };
+static const WCHAR QUARTZ_WaveParserInPin_Name[] =
+{ 'I','n',0 };
+static const WCHAR QUARTZ_WaveParserOutPin_Name[] =
+{ 'O','u','t',0 };
+
+
+/****************************************************************************/
+
+/* S_OK = found, S_FALSE = not found */
+HRESULT RIFF_GetNext(
+ CParserImpl* pImpl, LONGLONG llOfs,
+ DWORD* pdwCode, DWORD* pdwLength )
+{
+ BYTE bTemp[8];
+ HRESULT hr;
+
+ hr = IAsyncReader_SyncRead( pImpl->m_pReader, llOfs, 8, bTemp );
+ if ( hr == S_OK )
+ {
+ *pdwCode = mmioFOURCC(bTemp[0],bTemp[1],bTemp[2],bTemp[3]);
+ *pdwLength = PARSER_LE_UINT32(&bTemp[4]);
+ }
+ else
+ {
+ *pdwCode = 0;
+ *pdwLength = 0;
+ }
+
+ return hr;
+}
+
+/* S_OK = found, S_FALSE = not found */
+HRESULT RIFF_SearchChunk(
+ CParserImpl* pImpl,
+ LONGLONG llOfs, DWORD dwChunk,
+ LONGLONG* pllOfs, DWORD* pdwChunkLength )
+{
+ HRESULT hr;
+ DWORD dwCurCode;
+ DWORD dwCurLen;
+
+ while ( 1 )
+ {
+ hr = RIFF_GetNext( pImpl, llOfs, &dwCurCode, &dwCurLen );
+ if ( hr != S_OK )
+ break;
+ if ( dwChunk == dwCurCode )
+ break;
+ llOfs += 8 + (LONGLONG)((dwCurLen+1)&(~1));
+ }
+
+ *pllOfs = llOfs;
+ *pdwChunkLength = dwCurLen;
+
+ return hr;
+}
+
+
+
+
+/****************************************************************************
+ *
+ * CWavParseImpl
+ */
+
+typedef enum WavParseFmtType
+{
+ WaveParse_Native,
+ WaveParse_Signed8,
+ WaveParse_Signed16BE,
+ WaveParse_Unsigned16LE,
+ WaveParse_Unsigned16BE,
+} WavParseFmtType;
+
+typedef struct CWavParseImpl
+{
+ DWORD cbFmt;
+ WAVEFORMATEX* pFmt;
+ DWORD dwBlockSize;
+ LONGLONG llDataStart;
+ LONGLONG llBytesTotal;
+ LONGLONG llBytesProcessed;
+ WavParseFmtType iFmtType;
+} CWavParseImpl;
+
+
+static HRESULT CWavParseImpl_InitWAV( CParserImpl* pImpl, CWavParseImpl* This )
+{
+ HRESULT hr;
+ LONGLONG llOfs;
+ DWORD dwChunkLength;
+
+ hr = RIFF_SearchChunk(
+ pImpl, PARSER_RIFF_OfsFirst,
+ PARSER_fmt, &llOfs, &dwChunkLength );
+ if ( FAILED(hr) )
+ return hr;
+ if ( hr != S_OK || ( dwChunkLength < (sizeof(WAVEFORMATEX)-2) ) )
+ return E_FAIL;
+ llOfs += 8;
+
+ This->cbFmt = dwChunkLength;
+ if ( dwChunkLength < sizeof(WAVEFORMATEX) )
+ This->cbFmt = sizeof(WAVEFORMATEX);
+ This->pFmt = (WAVEFORMATEX*)QUARTZ_AllocMem( dwChunkLength );
+ if ( This->pFmt == NULL )
+ return E_OUTOFMEMORY;
+ ZeroMemory( This->pFmt, This->cbFmt );
+
+ hr = IAsyncReader_SyncRead(
+ pImpl->m_pReader, llOfs, dwChunkLength, (BYTE*)This->pFmt );
+ if ( hr != S_OK )
+ {
+ if ( SUCCEEDED(hr) )
+ hr = E_FAIL;
+ return hr;
+ }
+
+
+ hr = RIFF_SearchChunk(
+ pImpl, PARSER_RIFF_OfsFirst,
+ PARSER_data, &llOfs, &dwChunkLength );
+ if ( FAILED(hr) )
+ return hr;
+ if ( hr != S_OK || dwChunkLength == 0 )
+ return E_FAIL;
+
+ This->llDataStart = llOfs;
+ This->llBytesTotal = (LONGLONG)dwChunkLength;
+
+ return NOERROR;
+}
+
+static HRESULT CWavParseImpl_InitAU( CParserImpl* pImpl, CWavParseImpl* This )
+{
+ BYTE au_hdr[24];
+ DWORD dataofs;
+ DWORD datalen;
+ DWORD datafmt;
+ DWORD datarate;
+ DWORD datachannels;
+ HRESULT hr;
+ WAVEFORMATEX wfx;
+
+ hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 24, au_hdr );
+ if ( FAILED(hr) )
+ return hr;
+
+ dataofs = PARSER_BE_UINT32(&au_hdr[4]);
+ datalen = PARSER_BE_UINT32(&au_hdr[8]);
+ datafmt = PARSER_BE_UINT32(&au_hdr[12]);
+ datarate = PARSER_BE_UINT32(&au_hdr[16]);
+ datachannels = PARSER_BE_UINT32(&au_hdr[20]);
+
+ if ( dataofs < 24U || datalen == 0U )
+ return E_FAIL;
+ if ( datachannels != 1 && datachannels != 2 )
+ return E_FAIL;
+
+ ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
+ wfx.nChannels = datachannels;
+ wfx.nSamplesPerSec = datarate;
+
+ switch ( datafmt )
+ {
+ case 1:
+ wfx.wFormatTag = 7;
+ wfx.nBlockAlign = datachannels;
+ wfx.wBitsPerSample = 8;
+ break;
+ case 2:
+ wfx.wFormatTag = 1;
+ wfx.nBlockAlign = datachannels;
+ wfx.wBitsPerSample = 8;
+ This->iFmtType = WaveParse_Signed8;
+ break;
+ case 3:
+ wfx.wFormatTag = 1;
+ wfx.nBlockAlign = datachannels;
+ wfx.wBitsPerSample = 16;
+ This->iFmtType = WaveParse_Signed16BE;
+ break;
+ default:
+ FIXME("audio/basic - unknown format %lu\n", datafmt );
+ return E_FAIL;
+ }
+ wfx.nAvgBytesPerSec = (datarate * datachannels * (DWORD)wfx.wBitsPerSample) >> 3;
+
+ This->cbFmt = sizeof(WAVEFORMATEX);
+ This->pFmt = (WAVEFORMATEX*)QUARTZ_AllocMem( sizeof(WAVEFORMATEX) );
+ if ( This->pFmt == NULL )
+ return E_OUTOFMEMORY;
+ memcpy( This->pFmt, &wfx, sizeof(WAVEFORMATEX) );
+
+ This->llDataStart = dataofs;
+ This->llBytesTotal = datalen;
+
+ return NOERROR;
+}
+
+static HRESULT CWavParseImpl_InitAIFF( CParserImpl* pImpl, CWavParseImpl* This )
+{
+ FIXME( "AIFF is not supported now.\n" );
+ return E_FAIL;
+}
+
+static HRESULT CWavParseImpl_InitParser( CParserImpl* pImpl, ULONG* pcStreams )
+{
+ CWavParseImpl* This = NULL;
+ HRESULT hr;
+ BYTE header[12];
+
+ TRACE("(%p,%p)\n",pImpl,pcStreams);
+
+ if ( pImpl->m_pReader == NULL )
+ return E_UNEXPECTED;
+
+ This = (CWavParseImpl*)QUARTZ_AllocMem( sizeof(CWavParseImpl) );
+ if ( This == NULL )
+ return E_OUTOFMEMORY;
+ pImpl->m_pUserData = This;
+
+ /* construct */
+ This->cbFmt = 0;
+ This->pFmt = NULL;
+ This->dwBlockSize = 0;
+ This->llDataStart = 0;
+ This->llBytesTotal = 0;
+ This->llBytesProcessed = 0;
+ This->iFmtType = WaveParse_Native;
+
+ hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 12, header );
+ if ( FAILED(hr) )
+ return hr;
+ if ( hr != S_OK )
+ return E_FAIL;
+
+ if ( !memcmp( &header[0], "RIFF", 4 ) &&
+ !memcmp( &header[8], "WAVE", 4 ) )
+ {
+ TRACE( "(%p) - it's audio/wav.\n", pImpl );
+ hr = CWavParseImpl_InitWAV( pImpl, This );
+ }
+ else
+ if ( !memcmp( &header[0], ".snd", 4 ) )
+ {
+ TRACE( "(%p) - it's audio/basic.\n", pImpl );
+ hr = CWavParseImpl_InitAU( pImpl, This );
+ }
+ else
+ if ( !memcmp( &header[0], "FORM", 4 ) &&
+ !memcmp( &header[8], "AIFF", 4 ) )
+ {
+ TRACE( "(%p) - it's audio/aiff.\n", pImpl );
+ hr = CWavParseImpl_InitAIFF( pImpl, This );
+ }
+ else
+ {
+ FIXME( "(%p) - unknown format.\n", pImpl );
+ hr = E_FAIL;
+ }
+
+ if ( FAILED(hr) )
+ {
+ return hr;
+ }
+
+ /* initialized successfully. */
+ *pcStreams = 1;
+
+ This->dwBlockSize = (This->pFmt->nAvgBytesPerSec + (DWORD)This->pFmt->nBlockAlign - 1U) / (DWORD)This->pFmt->nBlockAlign;
+
+ TRACE( "(%p) returned successfully.\n", pImpl );
+
+ return NOERROR;
+}
+
+static HRESULT CWavParseImpl_UninitParser( CParserImpl* pImpl )
+{
+ CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
+
+ TRACE("(%p)\n",This);
+
+ if ( This == NULL )
+ return NOERROR;
+
+ /* destruct */
+ if ( This->pFmt != NULL ) QUARTZ_FreeMem(This->pFmt);
+
+ QUARTZ_FreeMem( This );
+ pImpl->m_pUserData = NULL;
+
+ return NOERROR;
+}
+
+static LPCWSTR CWavParseImpl_GetOutPinName( CParserImpl* pImpl, ULONG nStreamIndex )
+{
+ CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
+
+ TRACE("(%p)\n",This);
+
+ return QUARTZ_WaveParserOutPin_Name;
+}
+
+static HRESULT CWavParseImpl_GetStreamType( CParserImpl* pImpl, ULONG nStreamIndex, AM_MEDIA_TYPE* pmt )
+{
+ CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
+
+ TRACE("(%p)\n",This);
+
+ if ( This == NULL || This->pFmt == NULL )
+ return E_UNEXPECTED;
+
+ ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
+ memcpy( &pmt->majortype, &MEDIATYPE_Audio, sizeof(GUID) );
+ QUARTZ_MediaSubType_FromFourCC( &pmt->subtype, (DWORD)This->pFmt->wFormatTag );
+ pmt->bFixedSizeSamples = 1;
+ pmt->bTemporalCompression = 0;
+ pmt->lSampleSize = This->pFmt->nBlockAlign;
+ memcpy( &pmt->formattype, &FORMAT_WaveFormatEx, sizeof(GUID) );
+ pmt->pUnk = NULL;
+
+ pmt->pbFormat = (BYTE*)CoTaskMemAlloc( This->cbFmt );
+ if ( pmt->pbFormat == NULL )
+ return E_OUTOFMEMORY;
+ pmt->cbFormat = This->cbFmt;
+ memcpy( pmt->pbFormat, This->pFmt, This->cbFmt );
+
+ return NOERROR;
+}
+
+static HRESULT CWavParseImpl_CheckStreamType( CParserImpl* pImpl, ULONG nStreamIndex, const AM_MEDIA_TYPE* pmt )
+{
+ if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Audio ) ||
+ !IsEqualGUID( &pmt->formattype, &FORMAT_WaveFormatEx ) )
+ return E_FAIL;
+ if ( pmt->pbFormat == NULL || pmt->cbFormat < sizeof(WAVEFORMATEX) )
+ return E_FAIL;
+
+ return NOERROR;
+}
+
+static HRESULT CWavParseImpl_GetAllocProp( CParserImpl* pImpl, ALLOCATOR_PROPERTIES* pReqProp )
+{
+ CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
+
+ TRACE("(%p)\n",This);
+
+ if ( This == NULL || This->pFmt == NULL )
+ return E_UNEXPECTED;
+
+ ZeroMemory( pReqProp, sizeof(ALLOCATOR_PROPERTIES) );
+ pReqProp->cBuffers = 1;
+ pReqProp->cbBuffer = This->dwBlockSize;
+
+ return NOERROR;
+}
+
+static HRESULT CWavParseImpl_GetNextRequest( CParserImpl* pImpl, ULONG* pnStreamIndex, LONGLONG* pllStart, LONG* plLength, REFERENCE_TIME* prtStart, REFERENCE_TIME* prtStop )
+{
+ CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
+ LONGLONG llAvail;
+ LONGLONG llStart;
+ LONGLONG llEnd;
+
+ TRACE("(%p)\n",This);
+
+ if ( This == NULL || This->pFmt == NULL )
+ return E_UNEXPECTED;
+
+ llAvail = This->llBytesTotal - This->llBytesProcessed;
+ if ( llAvail > (LONGLONG)This->dwBlockSize )
+ llAvail = (LONGLONG)This->dwBlockSize;
+ llStart = This->llBytesProcessed;
+ llEnd = llStart + llAvail;
+ This->llBytesProcessed = llEnd;
+
+ *pllStart = This->llBytesProcessed;
+ *plLength = (LONG)llAvail;
+ *prtStart = llStart * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec;
+ *prtStop = llEnd * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec;
+
+ return NOERROR;
+}
+
+static HRESULT CWavParseImpl_ProcessSample( CParserImpl* pImpl, ULONG nStreamIndex, LONGLONG llStart, LONG lLength, IMediaSample* pSample )
+{
+ CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData;
+
+ TRACE("(%p)\n",This);
+
+ switch ( This->iFmtType )
+ {
+ case WaveParse_Native:
+ break;
+ default:
+ FIXME("(%p) - %d not implemented\n", This, This->iFmtType );
+ return E_FAIL;
+ }
+
+ return NOERROR;
+}
+
+
+static const struct ParserHandlers CWavParseImpl_Handlers =
+{
+ CWavParseImpl_InitParser,
+ CWavParseImpl_UninitParser,
+ CWavParseImpl_GetOutPinName,
+ CWavParseImpl_GetStreamType,
+ CWavParseImpl_CheckStreamType,
+ CWavParseImpl_GetAllocProp,
+ CWavParseImpl_GetNextRequest,
+ CWavParseImpl_ProcessSample,
+
+ /* for IQualityControl */
+ NULL, /* pQualityNotify */
+
+ /* for seeking */
+ NULL, /* pGetSeekingCaps */
+ NULL, /* pIsTimeFormatSupported */
+ NULL, /* pGetCurPos */
+ NULL, /* pSetCurPos */
+ NULL, /* pGetDuration */
+ NULL, /* pSetDuration */
+ NULL, /* pGetStopPos */
+ NULL, /* pSetStopPos */
+ NULL, /* pGetPreroll */
+ NULL, /* pSetPreroll */
+};
+
+HRESULT QUARTZ_CreateWaveParser(IUnknown* punkOuter,void** ppobj)
+{
+ return QUARTZ_CreateParser(
+ punkOuter,ppobj,
+ &CLSID_quartzWaveParser,
+ QUARTZ_WaveParser_Name,
+ QUARTZ_WaveParserInPin_Name,
+ &CWavParseImpl_Handlers );
+}
+
+
diff --git a/include/amvideo.h b/include/amvideo.h
index 20fd693..19dabb6 100644
--- a/include/amvideo.h
+++ b/include/amvideo.h
@@ -4,12 +4,76 @@
#include "ole2.h"
#include "ddraw.h"
+
typedef struct IBaseVideoMixer IBaseVideoMixer;
typedef struct IDirectDrawVideo IDirectDrawVideo;
typedef struct IFullScreenVideo IFullScreenVideo;
typedef struct IFullScreenVideoEx IFullScreenVideoEx;
typedef struct IQualProp IQualProp;
+
+#define iEGA_COLORS 16
+#define iPALETTE_COLORS 256
+#define iMASK_COLORS 3
+#define iRED 0
+#define iGREEN 1
+#define iBLUE 2
+
+#define WIDTHBYTES(bits) ((DWORD)((((DWORD)(bits)+31U)&(~31U))>>3))
+#define DIBWIDTHBYTES(bi) ((DWORD)WIDTHBYTES((bi).biWidth*(bi).biBitCount))
+#define DIBSIZE(bi) (DIBWIDTHBYTES(bi)*(DWORD)abs((bi).biHeight))
+
+
+typedef struct
+{
+ DWORD dwBitMasks[iMASK_COLORS];
+ RGBQUAD bmiColors[iPALETTE_COLORS];
+} TRUECOLORINFO;
+
+typedef struct
+{
+ RECT rcSource;
+ RECT rcTarget;
+ DWORD dwBitRate;
+ DWORD dwBitErrorRate;
+ REFERENCE_TIME AvgTimePerFrame;
+ BITMAPINFOHEADER bmiHeader;
+} VIDEOINFOHEADER;
+
+typedef struct
+{
+ RECT rcSource;
+ RECT rcTarget;
+ DWORD dwBitRate;
+ DWORD dwBitErrorRate;
+ REFERENCE_TIME AvgTimePerFrame;
+ BITMAPINFOHEADER bmiHeader;
+
+ union {
+ RGBQUAD bmiColors[iPALETTE_COLORS];
+ DWORD dwBitMasks[iMASK_COLORS];
+ TRUECOLORINFO TrueColorInfo;
+ } DUMMYUNIONNAME;
+} VIDEOINFO;
+
+typedef struct
+{
+ VIDEOINFOHEADER hdr;
+ DWORD dwStartTimeCode;
+ DWORD cbSequenceHeader;
+ BYTE bSequenceHeader[1];
+} MPEG1VIDEOINFO;
+
+typedef struct
+{
+ RECT rcSource;
+ RECT rcTarget;
+ DWORD dwActiveWidth;
+ DWORD dwActiveHeight;
+ REFERENCE_TIME AvgTimePerFrame;
+} ANALOGVIDEOINFO;
+
+
/**************************************************************************
*
* IBaseVideoMixer interface
diff --git a/winedefault.reg b/winedefault.reg
index 9dd68f3..5cacfe2 100644
--- a/winedefault.reg
+++ b/winedefault.reg
@@ -328,6 +328,88 @@
"CLSID"="{e30629d1-27e5-11ce-875d-00608cb78066}"
"FriendlyName"="Waveout audio renderer"
+# CLSID_VideoRenderer
+
+[HKEY_CLASSES_ROOT\CLSID\{70e102b0-5556-11ce-97c0-00aa0055595a}\InprocServer32]
+@="quartz.dll"
+"ThreadingModel"="Both"
+
+[HKEY_CLASSES_ROOT\CLSID\{083863F1-70DE-11D0-BD40-00A0C911CE86}\Instance\{70e102b0-5556-11ce-97c0-00aa0055595a}]
+"CLSID"="{70e102b0-5556-11ce-97c0-00aa0055595a}"
+"FriendlyName"="Video Renderer"
+
+# Wave Parser
+
+[HKEY_CLASSES_ROOT\CLSID\{D51BD5A1-7548-11CF-A520-0080C77EF58A}\InprocServer32]
+@="quartz.dll"
+"ThreadingModel"="Both"
+
+[HKEY_CLASSES_ROOT\CLSID\{083863F1-70DE-11D0-BD40-00A0C911CE86}\Instance\{D51BD5A1-7548-11CF-A520-0080C77EF58A}]
+"CLSID"="{D51BD5A1-7548-11CF-A520-0080C77EF58A}"
+"FriendlyName"="Wave Parser"
+
+# CLSID_AVIDec(AVI Decompressor) (not implemented yet)
+
+[HKEY_CLASSES_ROOT\CLSID\{CF49D4E0-1115-11CE-B03A-0020AF0BA770}\InprocServer32]
+@="quartz.dll"
+"ThreadingModel"="Both"
+
+[HKEY_CLASSES_ROOT\CLSID\{083863F1-70DE-11D0-BD40-00A0C911CE86}\Instance\{CF49D4E0-1115-11CE-B03A-0020AF0BA770}]
+"CLSID"="{CF49D4E0-1115-11CE-B03A-0020AF0BA770}"
+"FriendlyName"="AVI Decompressor"
+
+# CLSID_AsyncReader (not implemented yet)
+
+[HKEY_CLASSES_ROOT\CLSID\{E436EBB5-524F-11CE-9F53-0020AF0BA770}\InprocServer32]
+@="quartz.dll"
+"ThreadingModel"="Both"
+
+[HKEY_CLASSES_ROOT\CLSID\{083863F1-70DE-11D0-BD40-00A0C911CE86}\Instance\{E436EBB5-524F-11CE-9F53-0020AF0BA770}]
+"CLSID"="{E436EBB5-524F-11CE-9F53-0020AF0BA770}"
+"FriendlyName"="Async Reader"
+
+# CLSID_URLReader (not implemented yet)
+
+[HKEY_CLASSES_ROOT\CLSID\{E436EBB6-524F-11CE-9F53-0020AF0BA770}\InprocServer32]
+@="quartz.dll"
+"ThreadingModel"="Both"
+
+[HKEY_CLASSES_ROOT\CLSID\{083863F1-70DE-11D0-BD40-00A0C911CE86}\Instance\{E436EBB6-524F-11CE-9F53-0020AF0BA770}]
+"CLSID"="{E436EBB6-524F-11CE-9F53-0020AF0BA770}"
+"FriendlyName"="URL Reader"
+
+# CLSID_AviSplitter (not implemented yet)
+
+[HKEY_CLASSES_ROOT\CLSID\{1B544C20-FD0B-11CE-8C63-00AA0044B51E}\InprocServer32]
+@="quartz.dll"
+"ThreadingModel"="Both"
+
+[HKEY_CLASSES_ROOT\CLSID\{083863F1-70DE-11D0-BD40-00A0C911CE86}\Instance\{1B544C20-FD0B-11CE-8C63-00AA0044B51E}]
+"CLSID"="{1B544C20-FD0B-11CE-8C63-00AA0044B51E}"
+"FriendlyName"="AVI Splitter"
+
+# CLSID_QuickTimeParser (not implemented yet)
+
+[HKEY_CLASSES_ROOT\CLSID\{D51BD5A0-7548-11CF-A520-0080C77EF58A}\InprocServer32]
+@="quartz.dll"
+"ThreadingModel"="Both"
+
+[HKEY_CLASSES_ROOT\CLSID\{083863F1-70DE-11D0-BD40-00A0C911CE86}\Instance\{D51BD5A0-7548-11CF-A520-0080C77EF58A}]
+"CLSID"="{D51BD5A0-7548-11CF-A520-0080C77EF58A}"
+"FriendlyName"="QuickTime Movie Parser"
+
+# CLSID_Colour(Color space converter) (not implemented yet)
+
+[HKEY_CLASSES_ROOT\CLSID\{1643E180-90F5-11CE-97D5-00AA0055595A}\InprocServer32]
+@="quartz.dll"
+"ThreadingModel"="Both"
+
+[HKEY_CLASSES_ROOT\CLSID\{083863F1-70DE-11D0-BD40-00A0C911CE86}\Instance\{1643E180-90F5-11CE-97D5-00AA0055595A}]
+"CLSID"="{1643E180-90F5-11CE-97D5-00AA0055595A}"
+"FriendlyName"="Color space converter"
+
+
+
#
# Entries for Mozilla ActiveX control support