Fixed some bugs.
[wine] / dlls / quartz / filesink.c
1 /*
2  * Implements CLSID_FileWriter.
3  *
4  * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *      FIXME - not tested
21  */
22
23 #include "config.h"
24
25 #include <stdlib.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winerror.h"
31 #include "mmsystem.h"
32 #include "strmif.h"
33 #include "control.h"
34 #include "vfwmsgs.h"
35 #include "uuids.h"
36 #include "evcode.h"
37
38 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
40
41 #include "quartz_private.h"
42 #include "filesink.h"
43 #include "seekpass.h"
44
45 static const WCHAR QUARTZ_FileWriter_Name[] =
46 { 'F','i','l','e',' ','W','r','i','t','e','r',0 };
47 static const WCHAR QUARTZ_FileWriterPin_Name[] =
48 { 'I','n',0 };
49
50
51 /* FIXME - add this flag to strmif.h */
52 #define AM_FILE_OVERWRITE       0x1
53
54 /***************************************************************************
55  *
56  *      CFileWriterImpl methods
57  *
58  */
59
60 static HRESULT CFileWriterImpl_OnActive( CBaseFilterImpl* pImpl )
61 {
62         CFileWriterImpl_THIS(pImpl,basefilter);
63
64         FIXME( "(%p)\n", This );
65
66         return NOERROR;
67 }
68
69 static HRESULT CFileWriterImpl_OnInactive( CBaseFilterImpl* pImpl )
70 {
71         CFileWriterImpl_THIS(pImpl,basefilter);
72
73         FIXME( "(%p)\n", This );
74
75         return NOERROR;
76 }
77
78 static const CBaseFilterHandlers filterhandlers =
79 {
80         CFileWriterImpl_OnActive, /* pOnActive */
81         CFileWriterImpl_OnInactive, /* pOnInactive */
82         NULL, /* pOnStop */
83 };
84
85
86 /***************************************************************************
87  *
88  *      CFileWriterPinImpl methods
89  *
90  */
91
92 static HRESULT CFileWriterPinImpl_OnPreConnect( CPinBaseImpl* pImpl, IPin* pPin )
93 {
94         CFileWriterPinImpl_THIS(pImpl,pin);
95
96         TRACE("(%p,%p)\n",This,pPin);
97
98         return NOERROR;
99 }
100
101 static HRESULT CFileWriterPinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin )
102 {
103         CFileWriterPinImpl_THIS(pImpl,pin);
104
105         TRACE("(%p,%p)\n",This,pPin);
106
107         return NOERROR;
108 }
109
110 static HRESULT CFileWriterPinImpl_OnDisconnect( CPinBaseImpl* pImpl )
111 {
112         CFileWriterPinImpl_THIS(pImpl,pin);
113
114         TRACE("(%p)\n",This);
115
116         if ( This->meminput.pAllocator != NULL )
117         {
118                 IMemAllocator_Decommit(This->meminput.pAllocator);
119                 IMemAllocator_Release(This->meminput.pAllocator);
120                 This->meminput.pAllocator = NULL;
121         }
122
123         return NOERROR;
124 }
125
126 static HRESULT CFileWriterPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
127 {
128         CFileWriterPinImpl_THIS(pImpl,pin);
129
130         TRACE("(%p,%p)\n",This,pmt);
131
132         if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Stream ) )
133                 return E_FAIL;
134
135         return NOERROR;
136 }
137
138 static HRESULT CFileWriterPinImpl_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample )
139 {
140         CFileWriterPinImpl_THIS(pImpl,pin);
141         BYTE*   pData = NULL;
142         LONG    lLength;
143         ULONG   cbWritten;
144         HRESULT hr;
145         REFERENCE_TIME  rtStart;
146         REFERENCE_TIME  rtEnd;
147         LARGE_INTEGER   dlibMove;
148
149         TRACE( "(%p,%p)\n",This,pSample );
150
151         if ( This->pRender->m_fInFlush )
152                 return S_FALSE;
153         if ( pSample == NULL )
154                 return E_POINTER;
155
156         hr = IMediaSample_GetPointer(pSample,&pData);
157         if ( FAILED(hr) )
158                 return hr;
159         lLength = (LONG)IMediaSample_GetActualDataLength(pSample);
160         if ( lLength == 0 )
161                 return S_OK;
162
163         if ( lLength < 0 )
164         {
165                 ERR( "invalid length: %ld\n", lLength );
166                 return S_OK;
167         }
168
169         hr = IMediaSample_GetTime( pSample, &rtStart, &rtEnd );
170         if ( FAILED(hr) )
171                 return hr;
172
173         dlibMove.QuadPart = rtStart;
174         hr = IStream_Seek(CFileWriterPinImpl_IStream(This),dlibMove,STREAM_SEEK_SET,NULL);
175         if ( FAILED(hr) )
176                 return hr;
177
178         hr = IStream_Write(CFileWriterPinImpl_IStream(This),pData,lLength,&cbWritten);
179
180         return hr;
181 }
182
183 static HRESULT CFileWriterPinImpl_ReceiveCanBlock( CPinBaseImpl* pImpl )
184 {
185         CFileWriterPinImpl_THIS(pImpl,pin);
186
187         TRACE( "(%p)\n", This );
188
189         return S_FALSE;
190 }
191
192 static HRESULT CFileWriterPinImpl_EndOfStream( CPinBaseImpl* pImpl )
193 {
194         CFileWriterPinImpl_THIS(pImpl,pin);
195
196         FIXME( "(%p)\n", This );
197
198         This->pRender->m_fInFlush = FALSE;
199
200         /* FIXME - don't notify twice until stopped or seeked. */
201         return CBaseFilterImpl_MediaEventNotify(
202                 &This->pRender->basefilter, EC_COMPLETE,
203                 (LONG_PTR)S_OK, (LONG_PTR)(IBaseFilter*)(This->pRender) );
204 }
205
206 static HRESULT CFileWriterPinImpl_BeginFlush( CPinBaseImpl* pImpl )
207 {
208         CFileWriterPinImpl_THIS(pImpl,pin);
209
210         FIXME( "(%p)\n", This );
211
212         This->pRender->m_fInFlush = TRUE;
213
214         return NOERROR;
215 }
216
217 static HRESULT CFileWriterPinImpl_EndFlush( CPinBaseImpl* pImpl )
218 {
219         CFileWriterPinImpl_THIS(pImpl,pin);
220
221         FIXME( "(%p)\n", This );
222
223         This->pRender->m_fInFlush = FALSE;
224
225         return NOERROR;
226 }
227
228 static HRESULT CFileWriterPinImpl_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate )
229 {
230         CFileWriterPinImpl_THIS(pImpl,pin);
231
232         FIXME( "(%p)\n", This );
233
234         This->pRender->m_fInFlush = FALSE;
235
236         return NOERROR;
237 }
238
239
240
241
242 static const CBasePinHandlers pinhandlers =
243 {
244         CFileWriterPinImpl_OnPreConnect, /* pOnPreConnect */
245         CFileWriterPinImpl_OnPostConnect, /* pOnPostConnect */
246         CFileWriterPinImpl_OnDisconnect, /* pOnDisconnect */
247         CFileWriterPinImpl_CheckMediaType, /* pCheckMediaType */
248         NULL, /* pQualityNotify */
249         CFileWriterPinImpl_Receive, /* pReceive */
250         CFileWriterPinImpl_ReceiveCanBlock, /* pReceiveCanBlock */
251         CFileWriterPinImpl_EndOfStream, /* pEndOfStream */
252         CFileWriterPinImpl_BeginFlush, /* pBeginFlush */
253         CFileWriterPinImpl_EndFlush, /* pEndFlush */
254         CFileWriterPinImpl_NewSegment, /* pNewSegment */
255 };
256
257
258 /***************************************************************************
259  *
260  *      new/delete CFileWriterImpl
261  *
262  */
263
264 /* can I use offsetof safely? - FIXME? */
265 static QUARTZ_IFEntry FilterIFEntries[] =
266 {
267   { &IID_IPersist, offsetof(CFileWriterImpl,basefilter)-offsetof(CFileWriterImpl,unk) },
268   { &IID_IMediaFilter, offsetof(CFileWriterImpl,basefilter)-offsetof(CFileWriterImpl,unk) },
269   { &IID_IBaseFilter, offsetof(CFileWriterImpl,basefilter)-offsetof(CFileWriterImpl,unk) },
270   { &IID_IFileSinkFilter, offsetof(CFileWriterImpl,filesink)-offsetof(CFileWriterImpl,unk) },
271   { &IID_IFileSinkFilter2, offsetof(CFileWriterImpl,filesink)-offsetof(CFileWriterImpl,unk) },
272 };
273
274 static HRESULT CFileWriterImpl_OnQueryInterface(
275         IUnknown* punk, const IID* piid, void** ppobj )
276 {
277         CFileWriterImpl_THIS(punk,unk);
278
279         if ( This->pSeekPass == NULL )
280                 return E_NOINTERFACE;
281
282         if ( IsEqualGUID( &IID_IMediaPosition, piid ) ||
283                  IsEqualGUID( &IID_IMediaSeeking, piid ) )
284         {
285                 TRACE( "IMediaSeeking(or IMediaPosition) is queried\n" );
286                 return IUnknown_QueryInterface( (IUnknown*)(&This->pSeekPass->unk), piid, ppobj );
287         }
288
289         return E_NOINTERFACE;
290 }
291
292 static void QUARTZ_DestroyFileWriter(IUnknown* punk)
293 {
294         CFileWriterImpl_THIS(punk,unk);
295
296         TRACE( "(%p)\n", This );
297         CFileWriterImpl_OnInactive(&This->basefilter);
298
299         if ( This->pPin != NULL )
300         {
301                 IUnknown_Release(This->pPin->unk.punkControl);
302                 This->pPin = NULL;
303         }
304         if ( This->pSeekPass != NULL )
305         {
306                 IUnknown_Release((IUnknown*)&This->pSeekPass->unk);
307                 This->pSeekPass = NULL;
308         }
309
310         if ( This->m_hFile != INVALID_HANDLE_VALUE )
311         {
312                 CloseHandle( This->m_hFile );
313                 This->m_hFile = INVALID_HANDLE_VALUE;
314         }
315         if ( This->m_pszFileName != NULL )
316         {
317                 QUARTZ_FreeMem( This->m_pszFileName );
318                 This->m_pszFileName = NULL;
319         }
320         QUARTZ_MediaType_Free( &This->m_mt );
321
322         CFileWriterImpl_UninitIFileSinkFilter2(This);
323         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
324
325         DeleteCriticalSection( &This->m_csReceive );
326 }
327
328 HRESULT QUARTZ_CreateFileWriter(IUnknown* punkOuter,void** ppobj)
329 {
330         CFileWriterImpl*        This = NULL;
331         HRESULT hr;
332
333         TRACE("(%p,%p)\n",punkOuter,ppobj);
334
335         This = (CFileWriterImpl*)
336                 QUARTZ_AllocObj( sizeof(CFileWriterImpl) );
337         if ( This == NULL )
338                 return E_OUTOFMEMORY;
339         This->pSeekPass = NULL;
340         This->pPin = NULL;
341         This->m_fInFlush = FALSE;
342
343         This->m_hFile = INVALID_HANDLE_VALUE;
344         This->m_pszFileName = NULL;
345         This->m_cbFileName = 0;
346         This->m_dwMode = 0;
347         ZeroMemory( &This->m_mt, sizeof(AM_MEDIA_TYPE) );
348
349         QUARTZ_IUnkInit( &This->unk, punkOuter );
350         This->qiext.pNext = NULL;
351         This->qiext.pOnQueryInterface = &CFileWriterImpl_OnQueryInterface;
352         QUARTZ_IUnkAddDelegation( &This->unk, &This->qiext );
353
354         hr = CBaseFilterImpl_InitIBaseFilter(
355                 &This->basefilter,
356                 This->unk.punkControl,
357                 &CLSID_FileWriter,
358                 QUARTZ_FileWriter_Name,
359                 &filterhandlers );
360         if ( SUCCEEDED(hr) )
361         {
362                 hr = CFileWriterImpl_InitIFileSinkFilter2(This);
363                 if ( FAILED(hr) )
364                 {
365                         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
366                 }
367         }
368
369         if ( FAILED(hr) )
370         {
371                 QUARTZ_FreeObj(This);
372                 return hr;
373         }
374
375         This->unk.pEntries = FilterIFEntries;
376         This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]);
377         This->unk.pOnFinalRelease = QUARTZ_DestroyFileWriter;
378
379         InitializeCriticalSection( &This->m_csReceive );
380
381         hr = QUARTZ_CreateFileWriterPin(
382                 This,
383                 &This->basefilter.csFilter,
384                 &This->m_csReceive,
385                 &This->pPin );
386         if ( SUCCEEDED(hr) )
387                 hr = QUARTZ_CompList_AddComp(
388                         This->basefilter.pInPins,
389                         (IUnknown*)&This->pPin->pin,
390                         NULL, 0 );
391         if ( SUCCEEDED(hr) )
392                 hr = QUARTZ_CreateSeekingPassThruInternal(
393                         (IUnknown*)&(This->unk), &This->pSeekPass,
394                         TRUE, (IPin*)&(This->pPin->pin) );
395
396         if ( FAILED(hr) )
397         {
398                 IUnknown_Release( This->unk.punkControl );
399                 return hr;
400         }
401
402         *ppobj = (void*)&(This->unk);
403
404         return S_OK;
405 }
406
407 /***************************************************************************
408  *
409  *      new/delete CFileWriterPinImpl
410  *
411  */
412
413 /* can I use offsetof safely? - FIXME? */
414 static QUARTZ_IFEntry PinIFEntries[] =
415 {
416   { &IID_IPin, offsetof(CFileWriterPinImpl,pin)-offsetof(CFileWriterPinImpl,unk) },
417   { &IID_IMemInputPin, offsetof(CFileWriterPinImpl,meminput)-offsetof(CFileWriterPinImpl,unk) },
418   { &IID_IStream, offsetof(CFileWriterPinImpl,stream)-offsetof(CFileWriterPinImpl,unk) },
419 };
420
421 static void QUARTZ_DestroyFileWriterPin(IUnknown* punk)
422 {
423         CFileWriterPinImpl_THIS(punk,unk);
424
425         TRACE( "(%p)\n", This );
426
427         CPinBaseImpl_UninitIPin( &This->pin );
428         CMemInputPinBaseImpl_UninitIMemInputPin( &This->meminput );
429         CFileWriterPinImpl_UninitIStream(This);
430 }
431
432 HRESULT QUARTZ_CreateFileWriterPin(
433         CFileWriterImpl* pFilter,
434         CRITICAL_SECTION* pcsPin,
435         CRITICAL_SECTION* pcsPinReceive,
436         CFileWriterPinImpl** ppPin)
437 {
438         CFileWriterPinImpl*     This = NULL;
439         HRESULT hr;
440
441         TRACE("(%p,%p,%p,%p)\n",pFilter,pcsPin,pcsPinReceive,ppPin);
442
443         This = (CFileWriterPinImpl*)
444                 QUARTZ_AllocObj( sizeof(CFileWriterPinImpl) );
445         if ( This == NULL )
446                 return E_OUTOFMEMORY;
447
448         QUARTZ_IUnkInit( &This->unk, NULL );
449         This->pRender = pFilter;
450
451         hr = CPinBaseImpl_InitIPin(
452                 &This->pin,
453                 This->unk.punkControl,
454                 pcsPin, pcsPinReceive,
455                 &pFilter->basefilter,
456                 QUARTZ_FileWriterPin_Name,
457                 FALSE,
458                 &pinhandlers );
459
460         if ( SUCCEEDED(hr) )
461         {
462                 hr = CMemInputPinBaseImpl_InitIMemInputPin(
463                         &This->meminput,
464                         This->unk.punkControl,
465                         &This->pin );
466                 if ( SUCCEEDED(hr) )
467                 {
468                         hr = CFileWriterPinImpl_InitIStream(This);
469                         if ( FAILED(hr) )
470                         {
471                                 CMemInputPinBaseImpl_UninitIMemInputPin(&This->meminput);
472                         }
473                 }
474
475                 if ( FAILED(hr) )
476                 {
477                         CPinBaseImpl_UninitIPin( &This->pin );
478                 }
479         }
480
481         if ( FAILED(hr) )
482         {
483                 QUARTZ_FreeObj(This);
484                 return hr;
485         }
486
487         This->unk.pEntries = PinIFEntries;
488         This->unk.dwEntries = sizeof(PinIFEntries)/sizeof(PinIFEntries[0]);
489         This->unk.pOnFinalRelease = QUARTZ_DestroyFileWriterPin;
490
491         *ppPin = This;
492
493         TRACE("returned successfully.\n");
494
495         return S_OK;
496 }
497
498 /***************************************************************************
499  *
500  *      CFileWriterPinImpl::IStream
501  *
502  */
503
504 static HRESULT WINAPI
505 IStream_fnQueryInterface(IStream* iface,REFIID riid,void** ppobj)
506 {
507         CFileWriterPinImpl_THIS(iface,stream);
508
509         TRACE("(%p)->()\n",This);
510
511         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
512 }
513
514 static ULONG WINAPI
515 IStream_fnAddRef(IStream* iface)
516 {
517         CFileWriterPinImpl_THIS(iface,stream);
518
519         TRACE("(%p)->()\n",This);
520
521         return IUnknown_AddRef(This->unk.punkControl);
522 }
523
524 static ULONG WINAPI
525 IStream_fnRelease(IStream* iface)
526 {
527         CFileWriterPinImpl_THIS(iface,stream);
528
529         TRACE("(%p)->()\n",This);
530
531         return IUnknown_Release(This->unk.punkControl);
532 }
533
534 static HRESULT WINAPI
535 IStream_fnRead(IStream* iface,void* pv,ULONG cb,ULONG* pcbRead)
536 {
537         CFileWriterPinImpl_THIS(iface,stream);
538
539         FIXME("(%p)->()\n",This);
540
541         return E_FAIL;
542 }
543
544 static HRESULT WINAPI
545 IStream_fnWrite(IStream* iface,const void* pv,ULONG cb,ULONG* pcbWritten)
546 {
547         CFileWriterPinImpl_THIS(iface,stream);
548         HRESULT hr;
549
550         FIXME("(%p)->(%p,%lu,%p)\n",This,pv,cb,pcbWritten);
551
552         EnterCriticalSection( &This->pRender->m_csReceive );
553         if ( This->pRender->m_hFile == INVALID_HANDLE_VALUE )
554         {
555                 hr = E_UNEXPECTED;
556                 goto err;
557         }
558
559         if ( ! WriteFile( This->pRender->m_hFile, pv, cb, pcbWritten, NULL ) )
560         {
561                 hr = E_FAIL;
562                 goto err;
563         }
564
565         hr = S_OK;
566 err:
567         LeaveCriticalSection( &This->pRender->m_csReceive );
568         return hr;
569 }
570
571 static HRESULT WINAPI
572 IStream_fnSeek(IStream* iface,LARGE_INTEGER dlibMove,DWORD dwOrigin,ULARGE_INTEGER* plibNewPosition)
573 {
574         CFileWriterPinImpl_THIS(iface,stream);
575         HRESULT hr;
576         DWORD   dwDistLow;
577         LONG    lDistHigh;
578
579         FIXME("(%p)->() stub!\n",This);
580
581         EnterCriticalSection( &This->pRender->m_csReceive );
582         if ( This->pRender->m_hFile == INVALID_HANDLE_VALUE )
583         {
584                 hr = E_UNEXPECTED;
585                 goto err;
586         }
587
588         dwDistLow = dlibMove.s.LowPart;
589         lDistHigh = dlibMove.s.HighPart;
590
591         SetLastError(0);
592         dwDistLow = SetFilePointer( This->pRender->m_hFile, (LONG)dwDistLow, &lDistHigh, dwOrigin );
593         if ( dwDistLow == 0xffffffff && GetLastError() != 0 )
594         {
595                 hr = E_FAIL;
596                 goto err;
597         }
598
599         if ( plibNewPosition != NULL )
600         {
601                 plibNewPosition->s.LowPart = dwDistLow;
602                 plibNewPosition->s.HighPart = lDistHigh;
603         }
604
605         hr = S_OK;
606 err:
607         LeaveCriticalSection( &This->pRender->m_csReceive );
608         return hr;
609 }
610
611 static HRESULT WINAPI
612 IStream_fnSetSize(IStream* iface,ULARGE_INTEGER libNewSize)
613 {
614         CFileWriterPinImpl_THIS(iface,stream);
615
616         FIXME("(%p)->() stub!\n",This);
617
618         if ( This->pRender->m_hFile == INVALID_HANDLE_VALUE )
619                 return E_UNEXPECTED;
620
621
622         return E_NOTIMPL;
623 }
624
625 static HRESULT WINAPI
626 IStream_fnCopyTo(IStream* iface,IStream* pstrm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten)
627 {
628         CFileWriterPinImpl_THIS(iface,stream);
629
630         FIXME("(%p)->()\n",This);
631
632         return E_FAIL;
633 }
634
635 static HRESULT WINAPI
636 IStream_fnCommit(IStream* iface,DWORD grfCommitFlags)
637 {
638         CFileWriterPinImpl_THIS(iface,stream);
639
640         FIXME("(%p)->() stub!\n",This);
641
642         return E_NOTIMPL;
643 }
644
645 static HRESULT WINAPI
646 IStream_fnRevert(IStream* iface)
647 {
648         CFileWriterPinImpl_THIS(iface,stream);
649
650         FIXME("(%p)->() stub!\n",This);
651
652         return E_NOTIMPL;
653 }
654
655 static HRESULT WINAPI
656 IStream_fnLockRegion(IStream* iface,ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType)
657 {
658         CFileWriterPinImpl_THIS(iface,stream);
659
660         FIXME("(%p)->() stub!\n",This);
661
662         return E_NOTIMPL;
663 }
664
665 static HRESULT WINAPI
666 IStream_fnUnlockRegion(IStream* iface,ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType)
667 {
668         CFileWriterPinImpl_THIS(iface,stream);
669
670         FIXME("(%p)->() stub!\n",This);
671
672         return E_NOTIMPL;
673 }
674
675 static HRESULT WINAPI
676 IStream_fnStat(IStream* iface,STATSTG* pstatstg,DWORD grfStatFlag)
677 {
678         CFileWriterPinImpl_THIS(iface,stream);
679
680         FIXME("(%p)->() stub!\n",This);
681
682         return E_NOTIMPL;
683 }
684
685 static HRESULT WINAPI
686 IStream_fnClone(IStream* iface,IStream** ppstrm)
687 {
688         CFileWriterPinImpl_THIS(iface,stream);
689
690         FIXME("(%p)->() stub!\n",This);
691
692         return E_NOTIMPL;
693 }
694
695 static ICOM_VTABLE(IStream) istream =
696 {
697         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
698         /* IUnknown fields */
699         IStream_fnQueryInterface,
700         IStream_fnAddRef,
701         IStream_fnRelease,
702         /* IStream fields */
703         IStream_fnRead,
704         IStream_fnWrite,
705         IStream_fnSeek,
706         IStream_fnSetSize,
707         IStream_fnCopyTo,
708         IStream_fnCommit,
709         IStream_fnRevert,
710         IStream_fnLockRegion,
711         IStream_fnUnlockRegion,
712         IStream_fnStat,
713         IStream_fnClone,
714 };
715
716 HRESULT CFileWriterPinImpl_InitIStream( CFileWriterPinImpl* This )
717 {
718         TRACE("(%p)\n",This);
719         ICOM_VTBL(&This->stream) = &istream;
720
721         return NOERROR;
722 }
723
724 HRESULT CFileWriterPinImpl_UninitIStream( CFileWriterPinImpl* This )
725 {
726         TRACE("(%p)\n",This);
727
728         return S_OK;
729 }
730
731
732 /***************************************************************************
733  *
734  *      CFileWriterImpl::IFileSinkFilter2
735  *
736  */
737
738 static HRESULT WINAPI
739 IFileSinkFilter2_fnQueryInterface(IFileSinkFilter2* iface,REFIID riid,void** ppobj)
740 {
741         CFileWriterImpl_THIS(iface,filesink);
742
743         TRACE("(%p)->()\n",This);
744
745         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
746 }
747
748 static ULONG WINAPI
749 IFileSinkFilter2_fnAddRef(IFileSinkFilter2* iface)
750 {
751         CFileWriterImpl_THIS(iface,filesink);
752
753         TRACE("(%p)->()\n",This);
754
755         return IUnknown_AddRef(This->unk.punkControl);
756 }
757
758 static ULONG WINAPI
759 IFileSinkFilter2_fnRelease(IFileSinkFilter2* iface)
760 {
761         CFileWriterImpl_THIS(iface,filesink);
762
763         TRACE("(%p)->()\n",This);
764
765         return IUnknown_Release(This->unk.punkControl);
766 }
767
768 static HRESULT WINAPI
769 IFileSinkFilter2_fnSetFileName(IFileSinkFilter2* iface,LPCOLESTR pszFileName,const AM_MEDIA_TYPE* pmt)
770 {
771         CFileWriterImpl_THIS(iface,filesink);
772         HRESULT hr;
773
774         TRACE("(%p)->(%s,%p)\n",This,debugstr_w(pszFileName),pmt);
775
776         if ( pszFileName == NULL )
777                 return E_POINTER;
778
779         if ( This->m_pszFileName != NULL )
780                 return E_UNEXPECTED;
781
782         This->m_cbFileName = sizeof(WCHAR)*(lstrlenW(pszFileName)+1);
783         This->m_pszFileName = (WCHAR*)QUARTZ_AllocMem( This->m_cbFileName );
784         if ( This->m_pszFileName == NULL )
785                 return E_OUTOFMEMORY;
786         memcpy( This->m_pszFileName, pszFileName, This->m_cbFileName );
787
788         if ( pmt != NULL )
789         {
790                 hr = QUARTZ_MediaType_Copy( &This->m_mt, pmt );
791                 if ( FAILED(hr) )
792                         goto err;
793         }
794         else
795         {
796                 ZeroMemory( &This->m_mt, sizeof(AM_MEDIA_TYPE) );
797                 memcpy( &This->m_mt.majortype, &MEDIATYPE_Stream, sizeof(GUID) );
798                 memcpy( &This->m_mt.subtype, &MEDIASUBTYPE_NULL, sizeof(GUID) );
799                 This->m_mt.lSampleSize = 1;
800                 memcpy( &This->m_mt.formattype, &FORMAT_None, sizeof(GUID) );
801         }
802
803         This->m_hFile = CreateFileW(
804                 This->m_pszFileName,
805                 GENERIC_WRITE,
806                 0,
807                 NULL,
808                 ( This->m_dwMode == AM_FILE_OVERWRITE ) ? CREATE_ALWAYS : OPEN_ALWAYS,
809                 FILE_ATTRIBUTE_NORMAL,
810                 (HANDLE)NULL );
811         if ( This->m_hFile == INVALID_HANDLE_VALUE )
812         {
813                 hr = E_FAIL;
814                 goto err;
815         }
816
817         This->pPin->pin.pmtAcceptTypes = &This->m_mt;
818         This->pPin->pin.cAcceptTypes = 1;
819
820         return NOERROR;
821 err:;
822         return hr;
823 }
824
825 static HRESULT WINAPI
826 IFileSinkFilter2_fnGetCurFile(IFileSinkFilter2* iface,LPOLESTR* ppszFileName,AM_MEDIA_TYPE* pmt)
827 {
828         CFileWriterImpl_THIS(iface,filesink);
829         HRESULT hr = E_NOTIMPL;
830
831         TRACE("(%p)->(%p,%p)\n",This,ppszFileName,pmt);
832
833         if ( ppszFileName == NULL || pmt == NULL )
834                 return E_POINTER;
835
836         if ( This->m_pszFileName == NULL )
837                 return E_FAIL;
838
839         hr = QUARTZ_MediaType_Copy( pmt, &This->m_mt );
840         if ( FAILED(hr) )
841                 return hr;
842
843         *ppszFileName = (WCHAR*)CoTaskMemAlloc( This->m_cbFileName );
844         if ( *ppszFileName == NULL )
845         {
846                 QUARTZ_MediaType_Free(pmt);
847                 ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
848                 return E_OUTOFMEMORY;
849         }
850
851         memcpy( *ppszFileName, This->m_pszFileName, This->m_cbFileName );
852
853         return NOERROR;
854 }
855
856 static HRESULT WINAPI
857 IFileSinkFilter2_fnSetMode(IFileSinkFilter2* iface,DWORD dwFlags)
858 {
859         CFileWriterImpl_THIS(iface,filesink);
860
861         TRACE("(%p)->(%08lx)\n",This,dwFlags);
862
863         if ( dwFlags != 0 && dwFlags != AM_FILE_OVERWRITE )
864                 return E_INVALIDARG;
865         This->m_dwMode = dwFlags;
866
867         return S_OK;
868 }
869
870 static HRESULT WINAPI
871 IFileSinkFilter2_fnGetMode(IFileSinkFilter2* iface,DWORD* pdwFlags)
872 {
873         CFileWriterImpl_THIS(iface,filesink);
874
875         TRACE("(%p)->(%p)\n",This,pdwFlags);
876
877         if ( pdwFlags == NULL )
878                 return E_POINTER;
879
880         *pdwFlags = This->m_dwMode;
881
882         return S_OK;
883 }
884
885 static ICOM_VTABLE(IFileSinkFilter2) ifilesink2 =
886 {
887         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
888         /* IUnknown fields */
889         IFileSinkFilter2_fnQueryInterface,
890         IFileSinkFilter2_fnAddRef,
891         IFileSinkFilter2_fnRelease,
892         /* IFileSinkFilter2 fields */
893         IFileSinkFilter2_fnSetFileName,
894         IFileSinkFilter2_fnGetCurFile,
895         IFileSinkFilter2_fnSetMode,
896         IFileSinkFilter2_fnGetMode,
897 };
898
899 HRESULT CFileWriterImpl_InitIFileSinkFilter2( CFileWriterImpl* This )
900 {
901         TRACE("(%p)\n",This);
902         ICOM_VTBL(&This->filesink) = &ifilesink2;
903
904         return NOERROR;
905 }
906
907 HRESULT CFileWriterImpl_UninitIFileSinkFilter2( CFileWriterImpl* This )
908 {
909         TRACE("(%p)\n",This);
910
911         return S_OK;
912 }
913
914