From c2503b55830e3a43398163296494e575f750fe4b Mon Sep 17 00:00:00 2001
From: Hidenori Takeshima <hidenori@a2.ctktv.ne.jp>
Date: Mon, 11 Mar 2002 01:18:30 +0000
Subject: [PATCH] Added some stubs.

---
 dlls/quartz/Makefile.in |   2 +
 dlls/quartz/capgraph.c  | 412 ++++++++++++++++++
 dlls/quartz/capgraph.h  |  53 +++
 dlls/quartz/filesink.c  | 902 ++++++++++++++++++++++++++++++++++++++++
 dlls/quartz/filesink.h  |  90 ++++
 dlls/quartz/main.c      |   6 +
 6 files changed, 1465 insertions(+)
 create mode 100644 dlls/quartz/capgraph.c
 create mode 100644 dlls/quartz/capgraph.h
 create mode 100644 dlls/quartz/filesink.c
 create mode 100644 dlls/quartz/filesink.h

diff --git a/dlls/quartz/Makefile.in b/dlls/quartz/Makefile.in
index 3624c5774ff..130c51a73f9 100644
--- a/dlls/quartz/Makefile.in
+++ b/dlls/quartz/Makefile.in
@@ -17,6 +17,7 @@ C_SRCS = \
 	aviparse.c \
 	basefilt.c \
 	basepin.c \
+	capgraph.c \
 	complist.c \
 	csconv.c \
 	devenum.c \
@@ -24,6 +25,7 @@ C_SRCS = \
 	fgevent.c \
 	fgpass.c \
 	fgraph.c \
+	filesink.c \
 	fmap.c \
 	ifgraph.c \
 	imcntl.c \
diff --git a/dlls/quartz/capgraph.c b/dlls/quartz/capgraph.c
new file mode 100644
index 00000000000..a1232054d7e
--- /dev/null
+++ b/dlls/quartz/capgraph.c
@@ -0,0 +1,412 @@
+/*
+ * Implementation of CLSID_CaptureGraphBuilder[2].
+ *
+ * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *	FIXME - stub
+ *	FIXME - not tested
+ */
+
+#include "config.h"
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winerror.h"
+#include "strmif.h"
+#include "control.h"
+#include "uuids.h"
+
+#include "wine/debug.h"
+WINE_DEFAULT_DEBUG_CHANNEL(quartz);
+
+#include "quartz_private.h"
+#include "capgraph.h"
+
+
+/***************************************************************************
+ *
+ *	CCaptureGraph::ICaptureGraphBuilder
+ *
+ */
+
+static HRESULT WINAPI
+ICaptureGraphBuilder_fnQueryInterface(ICaptureGraphBuilder* iface,REFIID riid,void** ppobj)
+{
+	CCaptureGraph_THIS(iface,capgraph1);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
+}
+
+static ULONG WINAPI
+ICaptureGraphBuilder_fnAddRef(ICaptureGraphBuilder* iface)
+{
+	CCaptureGraph_THIS(iface,capgraph1);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_AddRef(This->unk.punkControl);
+}
+
+static ULONG WINAPI
+ICaptureGraphBuilder_fnRelease(ICaptureGraphBuilder* iface)
+{
+	CCaptureGraph_THIS(iface,capgraph1);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_Release(This->unk.punkControl);
+}
+
+
+static HRESULT WINAPI
+ICaptureGraphBuilder_fnSetFiltergraph(ICaptureGraphBuilder* iface,IGraphBuilder* pgb)
+{
+	CCaptureGraph_THIS(iface,capgraph1);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+ICaptureGraphBuilder_fnGetFiltergraph(ICaptureGraphBuilder* iface,IGraphBuilder** ppgb)
+{
+	CCaptureGraph_THIS(iface,capgraph1);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+ICaptureGraphBuilder_fnSetOutputFileName(ICaptureGraphBuilder* iface,const GUID* pguidType,LPCOLESTR pName,IBaseFilter** ppFilter,IFileSinkFilter** ppSink)
+{
+	CCaptureGraph_THIS(iface,capgraph1);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+ICaptureGraphBuilder_fnFindInterface(ICaptureGraphBuilder* iface,const GUID* pguidCat,IBaseFilter* pFilter,REFIID riid,void** ppvobj)
+{
+	CCaptureGraph_THIS(iface,capgraph1);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+ICaptureGraphBuilder_fnRenderStream(ICaptureGraphBuilder* iface,const GUID* pguidCat,IUnknown* pSource,IBaseFilter* pCompressor,IBaseFilter* pRenderer)
+{
+	CCaptureGraph_THIS(iface,capgraph1);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+ICaptureGraphBuilder_fnControlStream(ICaptureGraphBuilder* iface,const GUID* pguidCat,IBaseFilter* pFilter,REFERENCE_TIME* prtStart,REFERENCE_TIME* prtStop,WORD wStartCookie,WORD wStopCookie)
+{
+	CCaptureGraph_THIS(iface,capgraph1);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+ICaptureGraphBuilder_fnAllocCapFile(ICaptureGraphBuilder* iface,LPCOLESTR pName,DWORDLONG llSize)
+{
+	CCaptureGraph_THIS(iface,capgraph1);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+ICaptureGraphBuilder_fnCopyCaptureFile(ICaptureGraphBuilder* iface,LPOLESTR pOrgName,LPOLESTR pNewName,int fAllowEscAbort,IAMCopyCaptureFileProgress* pCallback)
+{
+	CCaptureGraph_THIS(iface,capgraph1);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static ICOM_VTABLE(ICaptureGraphBuilder) icapgraph1 =
+{
+	ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+	/* IUnknown fields */
+	ICaptureGraphBuilder_fnQueryInterface,
+	ICaptureGraphBuilder_fnAddRef,
+	ICaptureGraphBuilder_fnRelease,
+	/* ICaptureGraphBuilder fields */
+	ICaptureGraphBuilder_fnSetFiltergraph,
+	ICaptureGraphBuilder_fnGetFiltergraph,
+	ICaptureGraphBuilder_fnSetOutputFileName,
+	ICaptureGraphBuilder_fnFindInterface,
+	ICaptureGraphBuilder_fnRenderStream,
+	ICaptureGraphBuilder_fnControlStream,
+	ICaptureGraphBuilder_fnAllocCapFile,
+	ICaptureGraphBuilder_fnCopyCaptureFile,
+};
+
+
+static HRESULT CCaptureGraph_InitICaptureGraphBuilder( CCaptureGraph* This )
+{
+	TRACE("(%p)\n",This);
+	ICOM_VTBL(&This->capgraph1) = &icapgraph1;
+
+	return NOERROR;
+}
+
+static void CCaptureGraph_UninitICaptureGraphBuilder( CCaptureGraph* This )
+{
+	TRACE("(%p)\n",This);
+}
+
+
+/***************************************************************************
+ *
+ *	CCaptureGraph::ICaptureGraphBuilder2
+ *
+ */
+
+static HRESULT WINAPI
+ICaptureGraphBuilder2_fnQueryInterface(ICaptureGraphBuilder2* iface,REFIID riid,void** ppobj)
+{
+	CCaptureGraph_THIS(iface,capgraph2);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
+}
+
+static ULONG WINAPI
+ICaptureGraphBuilder2_fnAddRef(ICaptureGraphBuilder2* iface)
+{
+	CCaptureGraph_THIS(iface,capgraph2);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_AddRef(This->unk.punkControl);
+}
+
+static ULONG WINAPI
+ICaptureGraphBuilder2_fnRelease(ICaptureGraphBuilder2* iface)
+{
+	CCaptureGraph_THIS(iface,capgraph2);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_Release(This->unk.punkControl);
+}
+
+static HRESULT WINAPI
+ICaptureGraphBuilder2_fnSetFiltergraph(ICaptureGraphBuilder2* iface,IGraphBuilder* pgb)
+{
+	CCaptureGraph_THIS(iface,capgraph2);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+ICaptureGraphBuilder2_fnGetFiltergraph(ICaptureGraphBuilder2* iface,IGraphBuilder** ppgb)
+{
+	CCaptureGraph_THIS(iface,capgraph2);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+ICaptureGraphBuilder2_fnSetOutputFileName(ICaptureGraphBuilder2* iface,const GUID* pguid,LPCOLESTR pName,IBaseFilter** ppFilter,IFileSinkFilter** ppSink)
+{
+	CCaptureGraph_THIS(iface,capgraph2);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+ICaptureGraphBuilder2_fnFindInterface(ICaptureGraphBuilder2* iface,const GUID* pguidCat,const GUID* pguidType,IBaseFilter* pFilter,REFIID riid,void** ppvobj)
+{
+	CCaptureGraph_THIS(iface,capgraph2);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+ICaptureGraphBuilder2_fnRenderStream(ICaptureGraphBuilder2* iface,const GUID* pguidCat,const GUID* pguidType,IUnknown* pSource,IBaseFilter* pCompressor,IBaseFilter* pRenderer)
+{
+	CCaptureGraph_THIS(iface,capgraph2);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+ICaptureGraphBuilder2_fnControlStream(ICaptureGraphBuilder2* iface,const GUID* pguidCat,const GUID* pguidType,IBaseFilter* pFilter,REFERENCE_TIME* prtStart,REFERENCE_TIME* prtStop,WORD wStartCookie,WORD wStopCookie)
+{
+	CCaptureGraph_THIS(iface,capgraph2);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+ICaptureGraphBuilder2_fnAllocCapFile(ICaptureGraphBuilder2* iface,LPCOLESTR pName,DWORDLONG llSize)
+{
+	CCaptureGraph_THIS(iface,capgraph2);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+ICaptureGraphBuilder2_fnCopyCaptureFile(ICaptureGraphBuilder2* iface,LPOLESTR pOrgName,LPOLESTR pNewName,int fAllowEscAbort,IAMCopyCaptureFileProgress* pCallback)
+{
+	CCaptureGraph_THIS(iface,capgraph2);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+ICaptureGraphBuilder2_fnFindPin(ICaptureGraphBuilder2* iface,IUnknown* pSource,PIN_DIRECTION pindir,const GUID* pguidCat,const GUID* pguidType,BOOL bUnconnected,int num,IPin** ppPin)
+{
+	CCaptureGraph_THIS(iface,capgraph2);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+
+static ICOM_VTABLE(ICaptureGraphBuilder2) icapgraph2 =
+{
+	ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+	/* IUnknown fields */
+	ICaptureGraphBuilder2_fnQueryInterface,
+	ICaptureGraphBuilder2_fnAddRef,
+	ICaptureGraphBuilder2_fnRelease,
+	/* ICaptureGraphBuilder2 fields */
+	ICaptureGraphBuilder2_fnSetFiltergraph,
+	ICaptureGraphBuilder2_fnGetFiltergraph,
+	ICaptureGraphBuilder2_fnSetOutputFileName,
+	ICaptureGraphBuilder2_fnFindInterface,
+	ICaptureGraphBuilder2_fnRenderStream,
+	ICaptureGraphBuilder2_fnControlStream,
+	ICaptureGraphBuilder2_fnAllocCapFile,
+	ICaptureGraphBuilder2_fnCopyCaptureFile,
+	ICaptureGraphBuilder2_fnFindPin,
+};
+
+static HRESULT CCaptureGraph_InitICaptureGraphBuilder2( CCaptureGraph* This )
+{
+	TRACE("(%p)\n",This);
+	ICOM_VTBL(&This->capgraph2) = &icapgraph2;
+
+	return NOERROR;
+}
+
+static void CCaptureGraph_UninitICaptureGraphBuilder2( CCaptureGraph* This )
+{
+	TRACE("(%p)\n",This);
+}
+
+
+/***************************************************************************
+ *
+ *	new/delete for CCaptureGraph
+ *
+ */
+
+/* can I use offsetof safely? - FIXME? */
+static QUARTZ_IFEntry IFEntries[] =
+{
+  { &IID_ICaptureGraphBuilder, offsetof(CCaptureGraph,capgraph1)-offsetof(CCaptureGraph,unk) },
+  { &IID_ICaptureGraphBuilder2, offsetof(CCaptureGraph,capgraph2)-offsetof(CCaptureGraph,unk) },
+};
+
+static void QUARTZ_DestroyCaptureGraph(IUnknown* punk)
+{
+	CCaptureGraph_THIS(punk,unk);
+
+	TRACE( "(%p)\n", This );
+
+	CCaptureGraph_UninitICaptureGraphBuilder(This);
+	CCaptureGraph_UninitICaptureGraphBuilder2(This);
+}
+
+HRESULT QUARTZ_CreateCaptureGraph(IUnknown* punkOuter,void** ppobj)
+{
+	CCaptureGraph*	pcg;
+	HRESULT	hr;
+
+	TRACE("(%p,%p)\n",punkOuter,ppobj);
+
+	pcg = (CCaptureGraph*)QUARTZ_AllocObj( sizeof(CCaptureGraph) );
+	if ( pcg == NULL )
+		return E_OUTOFMEMORY;
+
+	QUARTZ_IUnkInit( &pcg->unk, punkOuter );
+	pcg->m_pfg = NULL;
+
+	hr = CCaptureGraph_InitICaptureGraphBuilder(pcg);
+	if ( SUCCEEDED(hr) )
+	{
+		hr = CCaptureGraph_InitICaptureGraphBuilder2(pcg);
+		if ( FAILED(hr) )
+		{
+			CCaptureGraph_UninitICaptureGraphBuilder(pcg);
+		}
+	}
+
+	if ( FAILED(hr) )
+	{
+		QUARTZ_FreeObj(pcg);
+		return hr;
+	}
+
+	pcg->unk.pEntries = IFEntries;
+	pcg->unk.dwEntries = sizeof(IFEntries)/sizeof(IFEntries[0]);
+	pcg->unk.pOnFinalRelease = QUARTZ_DestroyCaptureGraph;
+
+	*ppobj = (void*)(&pcg->unk);
+
+	return S_OK;
+}
diff --git a/dlls/quartz/capgraph.h b/dlls/quartz/capgraph.h
new file mode 100644
index 00000000000..c09d4084cf6
--- /dev/null
+++ b/dlls/quartz/capgraph.h
@@ -0,0 +1,53 @@
+/*
+ * Implementation of CLSID_CaptureGraphBuilder[2].
+ *
+ * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef	WINE_DSHOW_CAPGRAPH_H
+#define	WINE_DSHOW_CAPGRAPH_H
+
+#include "iunk.h"
+
+typedef struct CapGraph_ICaptureGraphBuilderImpl
+{
+	ICOM_VFIELD(ICaptureGraphBuilder);
+} CapGraph_ICaptureGraphBuilderImpl;
+
+typedef struct CapGraph_ICaptureGraphBuilder2Impl
+{
+	ICOM_VFIELD(ICaptureGraphBuilder2);
+} CapGraph_ICaptureGraphBuilder2Impl;
+
+typedef struct CCaptureGraph
+{
+	QUARTZ_IUnkImpl	unk;
+	CapGraph_ICaptureGraphBuilderImpl	capgraph1;
+	CapGraph_ICaptureGraphBuilder2Impl	capgraph2;
+
+	/* ICaptureGraphBuilder fields. */
+	/* ICaptureGraphBuilder2 fields. */
+	IGraphBuilder*	m_pfg;
+} CCaptureGraph;
+
+#define	CCaptureGraph_THIS(iface,member)	CCaptureGraph*	This = ((CCaptureGraph*)(((char*)iface)-offsetof(CCaptureGraph,member)))
+
+
+HRESULT QUARTZ_CreateCaptureGraph(IUnknown* punkOuter,void** ppobj);
+
+
+#endif	/* WINE_DSHOW_CAPGRAPH_H */
diff --git a/dlls/quartz/filesink.c b/dlls/quartz/filesink.c
new file mode 100644
index 00000000000..1ab43984524
--- /dev/null
+++ b/dlls/quartz/filesink.c
@@ -0,0 +1,902 @@
+/*
+ * Implements CLSID_FileWriter.
+ *
+ * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *	FIXME - not tested
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winerror.h"
+#include "mmsystem.h"
+#include "strmif.h"
+#include "control.h"
+#include "vfwmsgs.h"
+#include "uuids.h"
+#include "evcode.h"
+
+#include "wine/debug.h"
+WINE_DEFAULT_DEBUG_CHANNEL(quartz);
+
+#include "quartz_private.h"
+#include "filesink.h"
+#include "seekpass.h"
+
+static const WCHAR QUARTZ_FileWriter_Name[] =
+{ 'F','i','l','e',' ','W','r','i','t','e','r',0 };
+static const WCHAR QUARTZ_FileWriterPin_Name[] =
+{ 'I','n',0 };
+
+
+/* FIXME - add this flag to strmif.h */
+#define AM_FILE_OVERWRITE	0x1
+
+/***************************************************************************
+ *
+ *	CFileWriterImpl methods
+ *
+ */
+
+static HRESULT CFileWriterImpl_OnActive( CBaseFilterImpl* pImpl )
+{
+	CFileWriterImpl_THIS(pImpl,basefilter);
+
+	FIXME( "(%p)\n", This );
+
+	return NOERROR;
+}
+
+static HRESULT CFileWriterImpl_OnInactive( CBaseFilterImpl* pImpl )
+{
+	CFileWriterImpl_THIS(pImpl,basefilter);
+
+	FIXME( "(%p)\n", This );
+
+	return NOERROR;
+}
+
+static const CBaseFilterHandlers filterhandlers =
+{
+	CFileWriterImpl_OnActive, /* pOnActive */
+	CFileWriterImpl_OnInactive, /* pOnInactive */
+	NULL, /* pOnStop */
+};
+
+
+/***************************************************************************
+ *
+ *	CFileWriterPinImpl methods
+ *
+ */
+
+static HRESULT CFileWriterPinImpl_OnPreConnect( CPinBaseImpl* pImpl, IPin* pPin )
+{
+	CFileWriterPinImpl_THIS(pImpl,pin);
+
+	TRACE("(%p,%p)\n",This,pPin);
+
+	return NOERROR;
+}
+
+static HRESULT CFileWriterPinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin )
+{
+	CFileWriterPinImpl_THIS(pImpl,pin);
+
+	TRACE("(%p,%p)\n",This,pPin);
+
+	return NOERROR;
+}
+
+static HRESULT CFileWriterPinImpl_OnDisconnect( CPinBaseImpl* pImpl )
+{
+	CFileWriterPinImpl_THIS(pImpl,pin);
+
+	TRACE("(%p)\n",This);
+
+	if ( This->meminput.pAllocator != NULL )
+	{
+		IMemAllocator_Decommit(This->meminput.pAllocator);
+		IMemAllocator_Release(This->meminput.pAllocator);
+		This->meminput.pAllocator = NULL;
+	}
+
+	return NOERROR;
+}
+
+static HRESULT CFileWriterPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
+{
+	CFileWriterPinImpl_THIS(pImpl,pin);
+
+	TRACE("(%p,%p)\n",This,pmt);
+
+	if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Stream ) )
+		return E_FAIL;
+
+	return NOERROR;
+}
+
+static HRESULT CFileWriterPinImpl_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample )
+{
+	CFileWriterPinImpl_THIS(pImpl,pin);
+	BYTE*	pData = NULL;
+	LONG	lLength;
+	ULONG	cbWritten;
+	HRESULT hr;
+
+	TRACE( "(%p,%p)\n",This,pSample );
+
+	if ( This->pRender->m_fInFlush )
+		return S_FALSE;
+	if ( pSample == NULL )
+		return E_POINTER;
+
+	hr = IMediaSample_GetPointer(pSample,&pData);
+	if ( FAILED(hr) )
+		return hr;
+	lLength = (LONG)IMediaSample_GetActualDataLength(pSample);
+	if ( lLength == 0 )
+		return S_OK;
+
+	if ( lLength < 0 )
+	{
+		ERR( "invalid length: %ld\n", lLength );
+		return S_OK;
+	}
+
+	hr = IStream_Write((IStream*)(&This->stream),pData,lLength,&cbWritten);
+
+	return hr;
+}
+
+static HRESULT CFileWriterPinImpl_ReceiveCanBlock( CPinBaseImpl* pImpl )
+{
+	CFileWriterPinImpl_THIS(pImpl,pin);
+
+	TRACE( "(%p)\n", This );
+
+	return S_FALSE;
+}
+
+static HRESULT CFileWriterPinImpl_EndOfStream( CPinBaseImpl* pImpl )
+{
+	CFileWriterPinImpl_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 CFileWriterPinImpl_BeginFlush( CPinBaseImpl* pImpl )
+{
+	CFileWriterPinImpl_THIS(pImpl,pin);
+
+	FIXME( "(%p)\n", This );
+
+	This->pRender->m_fInFlush = TRUE;
+
+	return NOERROR;
+}
+
+static HRESULT CFileWriterPinImpl_EndFlush( CPinBaseImpl* pImpl )
+{
+	CFileWriterPinImpl_THIS(pImpl,pin);
+
+	FIXME( "(%p)\n", This );
+
+	This->pRender->m_fInFlush = FALSE;
+
+	return NOERROR;
+}
+
+static HRESULT CFileWriterPinImpl_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate )
+{
+	CFileWriterPinImpl_THIS(pImpl,pin);
+
+	FIXME( "(%p)\n", This );
+
+	This->pRender->m_fInFlush = FALSE;
+
+	return NOERROR;
+}
+
+
+
+
+static const CBasePinHandlers pinhandlers =
+{
+	CFileWriterPinImpl_OnPreConnect, /* pOnPreConnect */
+	CFileWriterPinImpl_OnPostConnect, /* pOnPostConnect */
+	CFileWriterPinImpl_OnDisconnect, /* pOnDisconnect */
+	CFileWriterPinImpl_CheckMediaType, /* pCheckMediaType */
+	NULL, /* pQualityNotify */
+	CFileWriterPinImpl_Receive, /* pReceive */
+	CFileWriterPinImpl_ReceiveCanBlock, /* pReceiveCanBlock */
+	CFileWriterPinImpl_EndOfStream, /* pEndOfStream */
+	CFileWriterPinImpl_BeginFlush, /* pBeginFlush */
+	CFileWriterPinImpl_EndFlush, /* pEndFlush */
+	CFileWriterPinImpl_NewSegment, /* pNewSegment */
+};
+
+
+/***************************************************************************
+ *
+ *	new/delete CFileWriterImpl
+ *
+ */
+
+/* can I use offsetof safely? - FIXME? */
+static QUARTZ_IFEntry FilterIFEntries[] =
+{
+  { &IID_IPersist, offsetof(CFileWriterImpl,basefilter)-offsetof(CFileWriterImpl,unk) },
+  { &IID_IMediaFilter, offsetof(CFileWriterImpl,basefilter)-offsetof(CFileWriterImpl,unk) },
+  { &IID_IBaseFilter, offsetof(CFileWriterImpl,basefilter)-offsetof(CFileWriterImpl,unk) },
+  { &IID_IFileSinkFilter, offsetof(CFileWriterImpl,filesink)-offsetof(CFileWriterImpl,unk) },
+  { &IID_IFileSinkFilter2, offsetof(CFileWriterImpl,filesink)-offsetof(CFileWriterImpl,unk) },
+};
+
+static HRESULT CFileWriterImpl_OnQueryInterface(
+	IUnknown* punk, const IID* piid, void** ppobj )
+{
+	CFileWriterImpl_THIS(punk,unk);
+
+	if ( This->pSeekPass == NULL )
+		return E_NOINTERFACE;
+
+	if ( IsEqualGUID( &IID_IMediaPosition, piid ) ||
+		 IsEqualGUID( &IID_IMediaSeeking, piid ) )
+	{
+		TRACE( "IMediaSeeking(or IMediaPosition) is queried\n" );
+		return IUnknown_QueryInterface( (IUnknown*)(&This->pSeekPass->unk), piid, ppobj );
+	}
+
+	return E_NOINTERFACE;
+}
+
+static void QUARTZ_DestroyFileWriter(IUnknown* punk)
+{
+	CFileWriterImpl_THIS(punk,unk);
+
+	TRACE( "(%p)\n", This );
+	CFileWriterImpl_OnInactive(&This->basefilter);
+
+	if ( This->pPin != NULL )
+	{
+		IUnknown_Release(This->pPin->unk.punkControl);
+		This->pPin = NULL;
+	}
+	if ( This->pSeekPass != NULL )
+	{
+		IUnknown_Release((IUnknown*)&This->pSeekPass->unk);
+		This->pSeekPass = NULL;
+	}
+
+	if ( This->m_hFile != INVALID_HANDLE_VALUE )
+	{
+		CloseHandle( This->m_hFile );
+		This->m_hFile = INVALID_HANDLE_VALUE;
+	}
+	if ( This->m_pszFileName != NULL )
+	{
+		QUARTZ_FreeMem( This->m_pszFileName );
+		This->m_pszFileName = NULL;
+	}
+	QUARTZ_MediaType_Free( &This->m_mt );
+
+	CFileWriterImpl_UninitIFileSinkFilter2(This);
+	CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
+
+	DeleteCriticalSection( &This->m_csReceive );
+}
+
+HRESULT QUARTZ_CreateFileWriter(IUnknown* punkOuter,void** ppobj)
+{
+	CFileWriterImpl*	This = NULL;
+	HRESULT hr;
+
+	TRACE("(%p,%p)\n",punkOuter,ppobj);
+
+	This = (CFileWriterImpl*)
+		QUARTZ_AllocObj( sizeof(CFileWriterImpl) );
+	if ( This == NULL )
+		return E_OUTOFMEMORY;
+	This->pSeekPass = NULL;
+	This->pPin = NULL;
+	This->m_fInFlush = FALSE;
+
+	This->m_hFile = INVALID_HANDLE_VALUE;
+	This->m_pszFileName = NULL;
+	This->m_cbFileName = 0;
+	This->m_dwMode = 0;
+	ZeroMemory( &This->m_mt, sizeof(AM_MEDIA_TYPE) );
+
+	QUARTZ_IUnkInit( &This->unk, punkOuter );
+	This->qiext.pNext = NULL;
+	This->qiext.pOnQueryInterface = &CFileWriterImpl_OnQueryInterface;
+	QUARTZ_IUnkAddDelegation( &This->unk, &This->qiext );
+
+	hr = CBaseFilterImpl_InitIBaseFilter(
+		&This->basefilter,
+		This->unk.punkControl,
+		&CLSID_FileWriter,
+		QUARTZ_FileWriter_Name,
+		&filterhandlers );
+	if ( SUCCEEDED(hr) )
+	{
+		hr = CFileWriterImpl_InitIFileSinkFilter2(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_DestroyFileWriter;
+
+	InitializeCriticalSection( &This->m_csReceive );
+
+	hr = QUARTZ_CreateFileWriterPin(
+		This,
+		&This->basefilter.csFilter,
+		&This->m_csReceive,
+		&This->pPin );
+	if ( SUCCEEDED(hr) )
+		hr = QUARTZ_CompList_AddComp(
+			This->basefilter.pInPins,
+			(IUnknown*)&This->pPin->pin,
+			NULL, 0 );
+	if ( SUCCEEDED(hr) )
+		hr = QUARTZ_CreateSeekingPassThruInternal(
+			(IUnknown*)&(This->unk), &This->pSeekPass,
+			TRUE, (IPin*)&(This->pPin->pin) );
+
+	if ( FAILED(hr) )
+	{
+		IUnknown_Release( This->unk.punkControl );
+		return hr;
+	}
+
+	*ppobj = (void*)&(This->unk);
+
+	return S_OK;
+}
+
+/***************************************************************************
+ *
+ *	new/delete CFileWriterPinImpl
+ *
+ */
+
+/* can I use offsetof safely? - FIXME? */
+static QUARTZ_IFEntry PinIFEntries[] =
+{
+  { &IID_IPin, offsetof(CFileWriterPinImpl,pin)-offsetof(CFileWriterPinImpl,unk) },
+  { &IID_IMemInputPin, offsetof(CFileWriterPinImpl,meminput)-offsetof(CFileWriterPinImpl,unk) },
+  { &IID_IStream, offsetof(CFileWriterPinImpl,stream)-offsetof(CFileWriterPinImpl,unk) },
+};
+
+static void QUARTZ_DestroyFileWriterPin(IUnknown* punk)
+{
+	CFileWriterPinImpl_THIS(punk,unk);
+
+	TRACE( "(%p)\n", This );
+
+	CPinBaseImpl_UninitIPin( &This->pin );
+	CMemInputPinBaseImpl_UninitIMemInputPin( &This->meminput );
+	CFileWriterPinImpl_UninitIStream(This);
+}
+
+HRESULT QUARTZ_CreateFileWriterPin(
+        CFileWriterImpl* pFilter,
+        CRITICAL_SECTION* pcsPin,
+        CRITICAL_SECTION* pcsPinReceive,
+        CFileWriterPinImpl** ppPin)
+{
+	CFileWriterPinImpl*	This = NULL;
+	HRESULT hr;
+
+	TRACE("(%p,%p,%p,%p)\n",pFilter,pcsPin,pcsPinReceive,ppPin);
+
+	This = (CFileWriterPinImpl*)
+		QUARTZ_AllocObj( sizeof(CFileWriterPinImpl) );
+	if ( This == NULL )
+		return E_OUTOFMEMORY;
+
+	QUARTZ_IUnkInit( &This->unk, NULL );
+	This->pRender = pFilter;
+
+	hr = CPinBaseImpl_InitIPin(
+		&This->pin,
+		This->unk.punkControl,
+		pcsPin, pcsPinReceive,
+		&pFilter->basefilter,
+		QUARTZ_FileWriterPin_Name,
+		FALSE,
+		&pinhandlers );
+
+	if ( SUCCEEDED(hr) )
+	{
+		hr = CMemInputPinBaseImpl_InitIMemInputPin(
+			&This->meminput,
+			This->unk.punkControl,
+			&This->pin );
+		if ( SUCCEEDED(hr) )
+		{
+			hr = CFileWriterPinImpl_InitIStream(This);
+			if ( FAILED(hr) )
+			{
+				CMemInputPinBaseImpl_UninitIMemInputPin(&This->meminput);
+			}
+		}
+
+		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_DestroyFileWriterPin;
+
+	*ppPin = This;
+
+	TRACE("returned successfully.\n");
+
+	return S_OK;
+}
+
+/***************************************************************************
+ *
+ *	CFileWriterPinImpl::IStream
+ *
+ */
+
+static HRESULT WINAPI
+IStream_fnQueryInterface(IStream* iface,REFIID riid,void** ppobj)
+{
+	CFileWriterPinImpl_THIS(iface,stream);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
+}
+
+static ULONG WINAPI
+IStream_fnAddRef(IStream* iface)
+{
+	CFileWriterPinImpl_THIS(iface,stream);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_AddRef(This->unk.punkControl);
+}
+
+static ULONG WINAPI
+IStream_fnRelease(IStream* iface)
+{
+	CFileWriterPinImpl_THIS(iface,stream);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_Release(This->unk.punkControl);
+}
+
+static HRESULT WINAPI
+IStream_fnRead(IStream* iface,void* pv,ULONG cb,ULONG* pcbRead)
+{
+	CFileWriterPinImpl_THIS(iface,stream);
+
+	FIXME("(%p)->()\n",This);
+
+	return E_FAIL;
+}
+
+static HRESULT WINAPI
+IStream_fnWrite(IStream* iface,const void* pv,ULONG cb,ULONG* pcbWritten)
+{
+	CFileWriterPinImpl_THIS(iface,stream);
+	HRESULT hr;
+
+	FIXME("(%p)->(%p,%lu,%p)\n",This,pv,cb,pcbWritten);
+
+	EnterCriticalSection( &This->pRender->m_csReceive );
+	if ( This->pRender->m_hFile == INVALID_HANDLE_VALUE )
+	{
+		hr = E_UNEXPECTED;
+		goto err;
+	}
+
+	if ( ! WriteFile( This->pRender->m_hFile, pv, cb, pcbWritten, NULL ) )
+	{
+		hr = E_FAIL;
+		goto err;
+	}
+
+	hr = S_OK;
+err:
+	LeaveCriticalSection( &This->pRender->m_csReceive );
+	return hr;
+}
+
+static HRESULT WINAPI
+IStream_fnSeek(IStream* iface,LARGE_INTEGER dlibMove,DWORD dwOrigin,ULARGE_INTEGER* plibNewPosition)
+{
+	CFileWriterPinImpl_THIS(iface,stream);
+	HRESULT hr;
+	DWORD	dwDistLow;
+	LONG	lDistHigh;
+
+	FIXME("(%p)->() stub!\n",This);
+
+	EnterCriticalSection( &This->pRender->m_csReceive );
+	if ( This->pRender->m_hFile == INVALID_HANDLE_VALUE )
+	{
+		hr = E_UNEXPECTED;
+		goto err;
+	}
+
+	dwDistLow = dlibMove.s.LowPart;
+	lDistHigh = dlibMove.s.HighPart;
+
+	SetLastError(0);
+	dwDistLow = SetFilePointer( This->pRender->m_hFile, (LONG)dwDistLow, &lDistHigh, dwOrigin );
+	if ( dwDistLow == 0xffffffff && GetLastError() != 0 )
+	{
+		hr = E_FAIL;
+		goto err;
+	}
+
+	if ( plibNewPosition != NULL )
+	{
+		plibNewPosition->s.LowPart = dwDistLow;
+		plibNewPosition->s.HighPart = lDistHigh;
+	}
+
+	hr = S_OK;
+err:
+	LeaveCriticalSection( &This->pRender->m_csReceive );
+	return hr;
+}
+
+static HRESULT WINAPI
+IStream_fnSetSize(IStream* iface,ULARGE_INTEGER libNewSize)
+{
+	CFileWriterPinImpl_THIS(iface,stream);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	if ( This->pRender->m_hFile == INVALID_HANDLE_VALUE )
+		return E_UNEXPECTED;
+
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IStream_fnCopyTo(IStream* iface,IStream* pstrm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten)
+{
+	CFileWriterPinImpl_THIS(iface,stream);
+
+	FIXME("(%p)->()\n",This);
+
+	return E_FAIL;
+}
+
+static HRESULT WINAPI
+IStream_fnCommit(IStream* iface,DWORD grfCommitFlags)
+{
+	CFileWriterPinImpl_THIS(iface,stream);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IStream_fnRevert(IStream* iface)
+{
+	CFileWriterPinImpl_THIS(iface,stream);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IStream_fnLockRegion(IStream* iface,ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType)
+{
+	CFileWriterPinImpl_THIS(iface,stream);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IStream_fnUnlockRegion(IStream* iface,ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType)
+{
+	CFileWriterPinImpl_THIS(iface,stream);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IStream_fnStat(IStream* iface,STATSTG* pstatstg,DWORD grfStatFlag)
+{
+	CFileWriterPinImpl_THIS(iface,stream);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static HRESULT WINAPI
+IStream_fnClone(IStream* iface,IStream** ppstrm)
+{
+	CFileWriterPinImpl_THIS(iface,stream);
+
+	FIXME("(%p)->() stub!\n",This);
+
+	return E_NOTIMPL;
+}
+
+static ICOM_VTABLE(IStream) istream =
+{
+	ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+	/* IUnknown fields */
+	IStream_fnQueryInterface,
+	IStream_fnAddRef,
+	IStream_fnRelease,
+	/* IStream fields */
+	IStream_fnRead,
+	IStream_fnWrite,
+	IStream_fnSeek,
+	IStream_fnSetSize,
+	IStream_fnCopyTo,
+	IStream_fnCommit,
+	IStream_fnRevert,
+	IStream_fnLockRegion,
+	IStream_fnUnlockRegion,
+	IStream_fnStat,
+	IStream_fnClone,
+};
+
+HRESULT CFileWriterPinImpl_InitIStream( CFileWriterPinImpl* This )
+{
+	TRACE("(%p)\n",This);
+	ICOM_VTBL(&This->stream) = &istream;
+
+	return NOERROR;
+}
+
+HRESULT CFileWriterPinImpl_UninitIStream( CFileWriterPinImpl* This )
+{
+	TRACE("(%p)\n",This);
+
+	return S_OK;
+}
+
+
+/***************************************************************************
+ *
+ *	CFileWriterImpl::IFileSinkFilter2
+ *
+ */
+
+static HRESULT WINAPI
+IFileSinkFilter2_fnQueryInterface(IFileSinkFilter2* iface,REFIID riid,void** ppobj)
+{
+	CFileWriterImpl_THIS(iface,filesink);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
+}
+
+static ULONG WINAPI
+IFileSinkFilter2_fnAddRef(IFileSinkFilter2* iface)
+{
+	CFileWriterImpl_THIS(iface,filesink);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_AddRef(This->unk.punkControl);
+}
+
+static ULONG WINAPI
+IFileSinkFilter2_fnRelease(IFileSinkFilter2* iface)
+{
+	CFileWriterImpl_THIS(iface,filesink);
+
+	TRACE("(%p)->()\n",This);
+
+	return IUnknown_Release(This->unk.punkControl);
+}
+
+static HRESULT WINAPI
+IFileSinkFilter2_fnSetFileName(IFileSinkFilter2* iface,LPCOLESTR pszFileName,const AM_MEDIA_TYPE* pmt)
+{
+	CFileWriterImpl_THIS(iface,filesink);
+	HRESULT hr;
+
+	TRACE("(%p)->(%s,%p)\n",This,debugstr_w(pszFileName),pmt);
+
+	if ( pszFileName == NULL )
+		return E_POINTER;
+
+	if ( This->m_pszFileName != NULL )
+		return E_UNEXPECTED;
+
+	This->m_cbFileName = sizeof(WCHAR)*(lstrlenW(pszFileName)+1);
+	This->m_pszFileName = (WCHAR*)QUARTZ_AllocMem( This->m_cbFileName );
+	if ( This->m_pszFileName == NULL )
+		return E_OUTOFMEMORY;
+	memcpy( This->m_pszFileName, pszFileName, 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) );
+	}
+
+	This->m_hFile = CreateFileW(
+		This->m_pszFileName,
+		GENERIC_WRITE,
+		0,
+		NULL,
+		( This->m_dwMode == AM_FILE_OVERWRITE ) ? CREATE_ALWAYS : OPEN_ALWAYS,
+		FILE_ATTRIBUTE_NORMAL,
+		(HANDLE)NULL );
+	if ( This->m_hFile == INVALID_HANDLE_VALUE )
+	{
+		hr = E_FAIL;
+		goto err;
+	}
+
+	This->pPin->pin.pmtAcceptTypes = &This->m_mt;
+	This->pPin->pin.cAcceptTypes = 1;
+
+	return NOERROR;
+err:;
+	return hr;
+}
+
+static HRESULT WINAPI
+IFileSinkFilter2_fnGetCurFile(IFileSinkFilter2* iface,LPOLESTR* ppszFileName,AM_MEDIA_TYPE* pmt)
+{
+	CFileWriterImpl_THIS(iface,filesink);
+	HRESULT hr = E_NOTIMPL;
+
+	TRACE("(%p)->(%p,%p)\n",This,ppszFileName,pmt);
+
+	if ( ppszFileName == NULL || pmt == NULL )
+		return E_POINTER;
+
+	if ( This->m_pszFileName == NULL )
+		return E_FAIL;
+
+	hr = QUARTZ_MediaType_Copy( pmt, &This->m_mt );
+	if ( FAILED(hr) )
+		return hr;
+
+	*ppszFileName = (WCHAR*)CoTaskMemAlloc( This->m_cbFileName );
+	if ( *ppszFileName == NULL )
+	{
+		QUARTZ_MediaType_Free(pmt);
+		ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
+		return E_OUTOFMEMORY;
+	}
+
+	memcpy( *ppszFileName, This->m_pszFileName, This->m_cbFileName );
+
+	return NOERROR;
+}
+
+static HRESULT WINAPI
+IFileSinkFilter2_fnSetMode(IFileSinkFilter2* iface,DWORD dwFlags)
+{
+	CFileWriterImpl_THIS(iface,filesink);
+
+	TRACE("(%p)->(%08lx)\n",This,dwFlags);
+
+	if ( dwFlags != 0 && dwFlags != AM_FILE_OVERWRITE )
+		return E_INVALIDARG;
+	This->m_dwMode = dwFlags;
+
+	return S_OK;
+}
+
+static HRESULT WINAPI
+IFileSinkFilter2_fnGetMode(IFileSinkFilter2* iface,DWORD* pdwFlags)
+{
+	CFileWriterImpl_THIS(iface,filesink);
+
+	TRACE("(%p)->(%p)\n",This,pdwFlags);
+
+	if ( pdwFlags == NULL )
+		return E_POINTER;
+
+	*pdwFlags = This->m_dwMode;
+
+	return S_OK;
+}
+
+static ICOM_VTABLE(IFileSinkFilter2) ifilesink2 =
+{
+	ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+	/* IUnknown fields */
+	IFileSinkFilter2_fnQueryInterface,
+	IFileSinkFilter2_fnAddRef,
+	IFileSinkFilter2_fnRelease,
+	/* IFileSinkFilter2 fields */
+	IFileSinkFilter2_fnSetFileName,
+	IFileSinkFilter2_fnGetCurFile,
+	IFileSinkFilter2_fnSetMode,
+	IFileSinkFilter2_fnGetMode,
+};
+
+HRESULT CFileWriterImpl_InitIFileSinkFilter2( CFileWriterImpl* This )
+{
+	TRACE("(%p)\n",This);
+	ICOM_VTBL(&This->filesink) = &ifilesink2;
+
+	return NOERROR;
+}
+
+HRESULT CFileWriterImpl_UninitIFileSinkFilter2( CFileWriterImpl* This )
+{
+	TRACE("(%p)\n",This);
+
+	return S_OK;
+}
+
+
diff --git a/dlls/quartz/filesink.h b/dlls/quartz/filesink.h
new file mode 100644
index 00000000000..222e60015b8
--- /dev/null
+++ b/dlls/quartz/filesink.h
@@ -0,0 +1,90 @@
+/*
+ * Implements CLSID_FileWriter.
+ *
+ * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef	WINE_DSHOW_FILESINK_H
+#define	WINE_DSHOW_FILESINK_H
+
+#include "iunk.h"
+#include "basefilt.h"
+#include "seekpass.h"
+
+typedef struct CFileWriterImpl	CFileWriterImpl;
+typedef struct CFileWriterPinImpl	CFileWriterPinImpl;
+
+
+typedef struct FileWriterPin_IStreamImpl
+{
+	ICOM_VFIELD(IStream);
+} FileWriterPin_IStreamImpl;
+
+typedef struct FileWriter_IFileSinkFilter2Impl
+{
+	ICOM_VFIELD(IFileSinkFilter2);
+} FileWriter_IFileSinkFilter2Impl;
+
+struct CFileWriterImpl
+{
+	QUARTZ_IUnkImpl	unk;
+	CBaseFilterImpl	basefilter;
+	FileWriter_IFileSinkFilter2Impl	filesink;
+	QUARTZ_IFDelegation	qiext;
+
+	CSeekingPassThru*	pSeekPass;
+	CFileWriterPinImpl* pPin;
+
+	CRITICAL_SECTION	m_csReceive;
+	BOOL	m_fInFlush;
+
+	/* for writing */
+	HANDLE	m_hFile;
+	WCHAR*	m_pszFileName;
+	DWORD	m_cbFileName;
+	DWORD	m_dwMode;
+	AM_MEDIA_TYPE	m_mt;
+};
+
+struct CFileWriterPinImpl
+{
+	QUARTZ_IUnkImpl	unk;
+	CPinBaseImpl	pin;
+	CMemInputPinBaseImpl	meminput;
+	FileWriterPin_IStreamImpl	stream;
+
+	CFileWriterImpl* pRender;
+};
+
+#define	CFileWriterImpl_THIS(iface,member)	CFileWriterImpl*	This = ((CFileWriterImpl*)(((char*)iface)-offsetof(CFileWriterImpl,member)))
+#define	CFileWriterPinImpl_THIS(iface,member)	CFileWriterPinImpl*	This = ((CFileWriterPinImpl*)(((char*)iface)-offsetof(CFileWriterPinImpl,member)))
+
+
+HRESULT CFileWriterPinImpl_InitIStream( CFileWriterPinImpl* This );
+HRESULT CFileWriterPinImpl_UninitIStream( CFileWriterPinImpl* This );
+HRESULT CFileWriterImpl_InitIFileSinkFilter2( CFileWriterImpl* This );
+HRESULT CFileWriterImpl_UninitIFileSinkFilter2( CFileWriterImpl* This );
+
+HRESULT QUARTZ_CreateFileWriter(IUnknown* punkOuter,void** ppobj);
+HRESULT QUARTZ_CreateFileWriterPin(
+        CFileWriterImpl* pFilter,
+        CRITICAL_SECTION* pcsPin,
+        CRITICAL_SECTION* pcsPinReceive,
+        CFileWriterPinImpl** ppPin);
+
+
+#endif	/* WINE_DSHOW_FILESINK_H */
diff --git a/dlls/quartz/main.c b/dlls/quartz/main.c
index 04cb7bd9433..4b81729ed09 100644
--- a/dlls/quartz/main.c
+++ b/dlls/quartz/main.c
@@ -50,6 +50,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(quartz);
 #include "parser.h"
 #include "asyncsrc.h"
 #include "xform.h"
+#include "capgraph.h"
+#include "filesink.h"
 
 
 typedef struct QUARTZ_CLASSENTRY
@@ -94,6 +96,9 @@ static const QUARTZ_CLASSENTRY QUARTZ_ClassList[] =
 	{ &CLSID_FilterMapper, &QUARTZ_CreateFilterMapper },
 	{ &CLSID_FilterMapper2, &QUARTZ_CreateFilterMapper2 },
 	{ &CLSID_SeekingPassThru, &QUARTZ_CreateSeekingPassThru },
+	{ &CLSID_CaptureGraphBuilder, &QUARTZ_CreateCaptureGraph },
+	{ &CLSID_CaptureGraphBuilder2, &QUARTZ_CreateCaptureGraph },
+
 	{ &CLSID_AudioRender, &QUARTZ_CreateAudioRenderer },
 	{ &CLSID_VideoRenderer, &QUARTZ_CreateVideoRenderer },
 	{ &CLSID_quartzWaveParser, &QUARTZ_CreateWaveParser },
@@ -102,6 +107,7 @@ static const QUARTZ_CLASSENTRY QUARTZ_ClassList[] =
 	{ &CLSID_URLReader, &QUARTZ_CreateURLReader },
 	{ &CLSID_AVIDec, &QUARTZ_CreateAVIDec },
 	{ &CLSID_Colour, &QUARTZ_CreateColour },
+	{ &CLSID_FileWriter, &QUARTZ_CreateFileWriter },
 	{ NULL, NULL },
 };
 
-- 
GitLab