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