Started Implementing Video Renderer.
[wine] / dlls / quartz / asyncsrc.c
1 /*
2  * Implements Asynchronous File/URL Source.
3  *
4  * FIXME - not work yet.
5  *
6  * hidenori@a2.ctktv.ne.jp
7  */
8
9 #include "config.h"
10
11 #include "windef.h"
12 #include "winbase.h"
13 #include "wingdi.h"
14 #include "winuser.h"
15 #include "winerror.h"
16 #include "wine/obj_base.h"
17 #include "strmif.h"
18 #include "vfwmsgs.h"
19 #include "uuids.h"
20
21 #include "debugtools.h"
22 DEFAULT_DEBUG_CHANNEL(quartz);
23
24 #include "quartz_private.h"
25 #include "asyncsrc.h"
26 #include "memalloc.h"
27
28
29 /***************************************************************************
30  *
31  *      CAsyncReaderImpl internal methods
32  *
33  */
34
35 static DWORD WINAPI
36 CAsyncReaderImpl_ThreadEntry( LPVOID pv )
37 {
38         CAsyncReaderImpl*       This = (CAsyncReaderImpl*)pv;
39         HANDLE hWaitEvents[2];
40         HANDLE hReadEvents[2];
41         DWORD   dwRes;
42
43         SetEvent( This->m_hEventInit );
44
45         hWaitEvents[0] = This->m_hEventReqQueued;
46         hWaitEvents[1] = This->m_hEventAbort;
47
48         hReadEvents[0] = This->m_hEventSampQueued;
49         hReadEvents[1] = This->m_hEventAbort;
50
51         while ( 1 )
52         {
53                 dwRes = WaitForMultipleObjects(2,hWaitEvents,FALSE,INFINITE);
54                 if ( dwRes != WAIT_OBJECT_0 )
55                         break;
56
57                 /* FIXME - process a queued request */
58
59                 dwRes = WaitForMultipleObjects(2,hReadEvents,FALSE,INFINITE);
60                 if ( dwRes != WAIT_OBJECT_0 )
61                         break;
62         }
63
64         return 0;
65 }
66
67 static HRESULT
68 CAsyncReaderImpl_BeginThread( CAsyncReaderImpl* This )
69 {
70         DWORD dwRes;
71         DWORD dwThreadId;
72         HANDLE hEvents[2];
73
74         if ( This->m_hEventInit != (HANDLE)NULL ||
75                  This->m_hEventAbort != (HANDLE)NULL ||
76                  This->m_hEventReqQueued != (HANDLE)NULL ||
77                  This->m_hEventSampQueued != (HANDLE)NULL ||
78                  This->m_hEventCompletion != (HANDLE)NULL ||
79                  This->m_hThread != (HANDLE)NULL )
80                 return E_UNEXPECTED;
81
82         This->m_hEventInit = CreateEventA(NULL,TRUE,FALSE,NULL);
83         if ( This->m_hEventInit == (HANDLE)NULL )
84                 return E_OUTOFMEMORY;
85         This->m_hEventAbort = CreateEventA(NULL,TRUE,FALSE,NULL);
86         if ( This->m_hEventAbort == (HANDLE)NULL )
87                 return E_OUTOFMEMORY;
88         This->m_hEventReqQueued = CreateEventA(NULL,TRUE,FALSE,NULL);
89         if ( This->m_hEventReqQueued == (HANDLE)NULL )
90                 return E_OUTOFMEMORY;
91         This->m_hEventSampQueued = CreateEventA(NULL,TRUE,FALSE,NULL);
92         if ( This->m_hEventSampQueued == (HANDLE)NULL )
93                 return E_OUTOFMEMORY;
94         This->m_hEventCompletion = CreateEventA(NULL,TRUE,FALSE,NULL);
95         if ( This->m_hEventCompletion == (HANDLE)NULL )
96                 return E_OUTOFMEMORY;
97
98         /* create the processing thread. */
99         This->m_hThread = CreateThread(
100                 NULL, 0,
101                 CAsyncReaderImpl_ThreadEntry,
102                 (LPVOID)This,
103                 0, &dwThreadId );
104         if ( This->m_hThread == (HANDLE)NULL )
105                 return E_FAIL;
106
107         hEvents[0] = This->m_hEventInit;
108         hEvents[1] = This->m_hThread;
109
110         dwRes = WaitForMultipleObjects(2,hEvents,FALSE,INFINITE);
111         if ( dwRes != WAIT_OBJECT_0 )
112                 return E_FAIL;
113
114         return NOERROR;
115 }
116
117 static void
118 CAsyncReaderImpl_EndThread( CAsyncReaderImpl* This )
119 {
120         if ( This->m_hThread != (HANDLE)NULL )
121         {
122                 SetEvent( This->m_hEventAbort );
123
124                 WaitForSingleObject( This->m_hThread, INFINITE );
125                 CloseHandle( This->m_hThread );
126                 This->m_hThread = (HANDLE)NULL;
127         }
128         if ( This->m_hEventInit != (HANDLE)NULL )
129         {
130                 CloseHandle( This->m_hEventInit );
131                 This->m_hEventInit = (HANDLE)NULL;
132         }
133         if ( This->m_hEventAbort != (HANDLE)NULL )
134         {
135                 CloseHandle( This->m_hEventAbort );
136                 This->m_hEventAbort = (HANDLE)NULL;
137         }
138         if ( This->m_hEventReqQueued != (HANDLE)NULL )
139         {
140                 CloseHandle( This->m_hEventReqQueued );
141                 This->m_hEventReqQueued = (HANDLE)NULL;
142         }
143         if ( This->m_hEventSampQueued != (HANDLE)NULL )
144         {
145                 CloseHandle( This->m_hEventSampQueued );
146                 This->m_hEventSampQueued = (HANDLE)NULL;
147         }
148         if ( This->m_hEventCompletion != (HANDLE)NULL )
149         {
150                 CloseHandle( This->m_hEventCompletion );
151                 This->m_hEventCompletion = (HANDLE)NULL;
152         }
153 }
154
155 /***************************************************************************
156  *
157  *      CAsyncReaderImpl methods
158  *
159  */
160
161 static HRESULT WINAPI
162 CAsyncReaderImpl_fnQueryInterface(IAsyncReader* iface,REFIID riid,void** ppobj)
163 {
164         ICOM_THIS(CAsyncReaderImpl,iface);
165
166         TRACE("(%p)->()\n",This);
167
168         return IUnknown_QueryInterface(This->punkControl,riid,ppobj);
169 }
170
171 static ULONG WINAPI
172 CAsyncReaderImpl_fnAddRef(IAsyncReader* iface)
173 {
174         ICOM_THIS(CAsyncReaderImpl,iface);
175
176         TRACE("(%p)->()\n",This);
177
178         return IUnknown_AddRef(This->punkControl);
179 }
180
181 static ULONG WINAPI
182 CAsyncReaderImpl_fnRelease(IAsyncReader* iface)
183 {
184         ICOM_THIS(CAsyncReaderImpl,iface);
185
186         TRACE("(%p)->()\n",This);
187
188         return IUnknown_Release(This->punkControl);
189 }
190
191 static HRESULT WINAPI
192 CAsyncReaderImpl_fnRequestAllocator(IAsyncReader* iface,IMemAllocator* pAlloc,ALLOCATOR_PROPERTIES* pProp,IMemAllocator** ppAllocActual)
193 {
194         ICOM_THIS(CAsyncReaderImpl,iface);
195         HRESULT hr;
196         ALLOCATOR_PROPERTIES    propActual;
197         IUnknown* punk = NULL;
198
199         TRACE("(%p)->(%p,%p,%p)\n",This,pAlloc,pProp,ppAllocActual);
200
201         if ( pAlloc == NULL || pProp == NULL || ppAllocActual == NULL )
202                 return E_POINTER;
203
204         IMemAllocator_AddRef(pAlloc);
205         hr = IMemAllocator_SetProperties( pAlloc, pProp, &propActual );
206         if ( SUCCEEDED(hr) )
207         {
208                 *ppAllocActual = pAlloc;
209                 return S_OK;
210         }
211         IMemAllocator_Release(pAlloc);
212
213         hr = QUARTZ_CreateMemoryAllocator(NULL,(void**)&punk);
214         if ( FAILED(hr) )
215                 return hr;
216         hr = IUnknown_QueryInterface( punk, &IID_IMemAllocator, (void**)&pAlloc );
217         IUnknown_Release(punk);
218         if ( FAILED(hr) )
219                 return hr;
220
221         hr = IMemAllocator_SetProperties( pAlloc, pProp, &propActual );
222         if ( SUCCEEDED(hr) )
223         {
224                 *ppAllocActual = pAlloc;
225                 return S_OK;
226         }
227         IMemAllocator_Release(pAlloc);
228
229         return hr;
230 }
231
232 static HRESULT WINAPI
233 CAsyncReaderImpl_fnRequest(IAsyncReader* iface,IMediaSample* pSample,DWORD_PTR dwContext)
234 {
235         ICOM_THIS(CAsyncReaderImpl,iface);
236
237         FIXME("(%p)->() stub!\n",This);
238
239         EnterCriticalSection( This->pcsReader );
240         LeaveCriticalSection( This->pcsReader );
241
242         return E_NOTIMPL;
243 }
244
245 static HRESULT WINAPI
246 CAsyncReaderImpl_fnWaitForNext(IAsyncReader* iface,DWORD dwTimeout,IMediaSample** pSample,DWORD_PTR* pdwContext)
247 {
248         ICOM_THIS(CAsyncReaderImpl,iface);
249
250         FIXME("(%p)->() stub!\n",This);
251
252         EnterCriticalSection( This->pcsReader );
253         LeaveCriticalSection( This->pcsReader );
254
255         return E_NOTIMPL;
256 }
257
258 static HRESULT WINAPI
259 CAsyncReaderImpl_fnSyncReadAligned(IAsyncReader* iface,IMediaSample* pSample)
260 {
261         ICOM_THIS(CAsyncReaderImpl,iface);
262
263         FIXME("(%p)->() stub!\n",This);
264
265         EnterCriticalSection( This->pcsReader );
266         LeaveCriticalSection( This->pcsReader );
267
268         return E_NOTIMPL;
269 }
270
271 static HRESULT WINAPI
272 CAsyncReaderImpl_fnSyncRead(IAsyncReader* iface,LONGLONG llPosStart,LONG lLength,BYTE* pbBuf)
273 {
274         ICOM_THIS(CAsyncReaderImpl,iface);
275
276         FIXME("(%p)->() stub!\n",This);
277
278         EnterCriticalSection( This->pcsReader );
279         LeaveCriticalSection( This->pcsReader );
280
281         return E_NOTIMPL;
282 }
283
284 static HRESULT WINAPI
285 CAsyncReaderImpl_fnLength(IAsyncReader* iface,LONGLONG* pllTotal,LONGLONG* pllAvailable)
286 {
287         ICOM_THIS(CAsyncReaderImpl,iface);
288         HRESULT hr;
289
290         TRACE("(%p)->()\n",This);
291
292         EnterCriticalSection( This->pcsReader );
293         hr = This->pSource->m_pHandler->pGetLength( This->pSource, pllTotal, pllAvailable );
294         LeaveCriticalSection( This->pcsReader );
295
296         return hr;
297 }
298
299 static HRESULT WINAPI
300 CAsyncReaderImpl_fnBeginFlush(IAsyncReader* iface)
301 {
302         ICOM_THIS(CAsyncReaderImpl,iface);
303
304         FIXME("(%p)->() stub!\n",This);
305
306         EnterCriticalSection( This->pcsReader );
307         LeaveCriticalSection( This->pcsReader );
308
309         return E_NOTIMPL;
310 }
311
312 static HRESULT WINAPI
313 CAsyncReaderImpl_fnEndFlush(IAsyncReader* iface)
314 {
315         ICOM_THIS(CAsyncReaderImpl,iface);
316
317         FIXME("(%p)->() stub!\n",This);
318
319         EnterCriticalSection( This->pcsReader );
320         LeaveCriticalSection( This->pcsReader );
321
322         return E_NOTIMPL;
323 }
324
325
326 static ICOM_VTABLE(IAsyncReader) iasyncreader =
327 {
328         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
329         /* IUnknown fields */
330         CAsyncReaderImpl_fnQueryInterface,
331         CAsyncReaderImpl_fnAddRef,
332         CAsyncReaderImpl_fnRelease,
333
334         /* IAsyncReader fields */
335         CAsyncReaderImpl_fnRequestAllocator,
336         CAsyncReaderImpl_fnRequest,
337         CAsyncReaderImpl_fnWaitForNext,
338         CAsyncReaderImpl_fnSyncReadAligned,
339         CAsyncReaderImpl_fnSyncRead,
340         CAsyncReaderImpl_fnLength,
341         CAsyncReaderImpl_fnBeginFlush,
342         CAsyncReaderImpl_fnEndFlush,
343 };
344
345 HRESULT CAsyncReaderImpl_InitIAsyncReader(
346         CAsyncReaderImpl* This, IUnknown* punkControl,
347         CAsyncSourceImpl* pSource,
348         CRITICAL_SECTION* pcsReader )
349 {
350         TRACE("(%p,%p)\n",This,punkControl);
351
352         if ( punkControl == NULL )
353         {
354                 ERR( "punkControl must not be NULL\n" );
355                 return E_INVALIDARG;
356         }
357
358         ICOM_VTBL(This) = &iasyncreader;
359         This->punkControl = punkControl;
360         This->pSource = pSource;
361         This->pcsReader = pcsReader;
362         This->m_hEventInit = (HANDLE)NULL;
363         This->m_hEventAbort = (HANDLE)NULL;
364         This->m_hEventReqQueued = (HANDLE)NULL;
365         This->m_hEventSampQueued = (HANDLE)NULL;
366         This->m_hEventCompletion = (HANDLE)NULL;
367         This->m_hThread = (HANDLE)NULL;
368
369         return NOERROR;
370 }
371
372 void CAsyncReaderImpl_UninitIAsyncReader(
373         CAsyncReaderImpl* This )
374 {
375         TRACE("(%p)\n",This);
376 }
377
378 /***************************************************************************
379  *
380  *      CFileSourceFilterImpl
381  *
382  */
383
384 static HRESULT WINAPI
385 CFileSourceFilterImpl_fnQueryInterface(IFileSourceFilter* iface,REFIID riid,void** ppobj)
386 {
387         ICOM_THIS(CFileSourceFilterImpl,iface);
388
389         TRACE("(%p)->()\n",This);
390
391         return IUnknown_QueryInterface(This->punkControl,riid,ppobj);
392 }
393
394 static ULONG WINAPI
395 CFileSourceFilterImpl_fnAddRef(IFileSourceFilter* iface)
396 {
397         ICOM_THIS(CFileSourceFilterImpl,iface);
398
399         TRACE("(%p)->()\n",This);
400
401         return IUnknown_AddRef(This->punkControl);
402 }
403
404 static ULONG WINAPI
405 CFileSourceFilterImpl_fnRelease(IFileSourceFilter* iface)
406 {
407         ICOM_THIS(CFileSourceFilterImpl,iface);
408
409         TRACE("(%p)->()\n",This);
410
411         return IUnknown_Release(This->punkControl);
412 }
413
414 static HRESULT WINAPI
415 CFileSourceFilterImpl_fnLoad(IFileSourceFilter* iface,LPCOLESTR pFileName,const AM_MEDIA_TYPE* pmt)
416 {
417         ICOM_THIS(CFileSourceFilterImpl,iface);
418         HRESULT hr;
419
420         TRACE("(%p)->(%s,%p)\n",This,debugstr_w(pFileName),pmt);
421
422         if ( pFileName == NULL )
423                 return E_POINTER;
424
425         if ( This->m_pwszFileName != NULL )
426                 return E_UNEXPECTED;
427
428         This->m_cbFileName = sizeof(WCHAR)*(lstrlenW(pFileName)+1);
429         This->m_pwszFileName = (WCHAR*)QUARTZ_AllocMem( This->m_cbFileName );
430         if ( This->m_pwszFileName == NULL )
431                 return E_OUTOFMEMORY;
432         memcpy( This->m_pwszFileName, pFileName, This->m_cbFileName );
433
434         if ( pmt != NULL )
435         {
436                 hr = QUARTZ_MediaType_Copy( &This->m_mt, pmt );
437                 if ( FAILED(hr) )
438                         goto err;
439         }
440         else
441         {
442                 ZeroMemory( &This->m_mt, sizeof(AM_MEDIA_TYPE) );
443                 memcpy( &This->m_mt.majortype, &MEDIATYPE_Stream, sizeof(GUID) );
444                 memcpy( &This->m_mt.subtype, &MEDIASUBTYPE_NULL, sizeof(GUID) );
445                 This->m_mt.lSampleSize = 1;
446                 memcpy( &This->m_mt.formattype, &FORMAT_None, sizeof(GUID) );
447         }
448
449         hr = This->pSource->m_pHandler->pLoad( This->pSource, pFileName );
450         if ( FAILED(hr) )
451                 goto err;
452
453         return NOERROR;
454 err:;
455         return hr;
456 }
457
458 static HRESULT WINAPI
459 CFileSourceFilterImpl_fnGetCurFile(IFileSourceFilter* iface,LPOLESTR* ppFileName,AM_MEDIA_TYPE* pmt)
460 {
461         ICOM_THIS(CFileSourceFilterImpl,iface);
462         HRESULT hr = E_NOTIMPL;
463
464         TRACE("(%p)->(%p,%p)\n",This,ppFileName,pmt);
465
466         if ( ppFileName == NULL || pmt == NULL )
467                 return E_POINTER;
468
469         if ( This->m_pwszFileName == NULL )
470                 return E_FAIL;
471
472         hr = QUARTZ_MediaType_Copy( pmt, &This->m_mt );
473         if ( FAILED(hr) )
474                 return hr;
475
476         *ppFileName = (WCHAR*)CoTaskMemAlloc( This->m_cbFileName );
477         if ( *ppFileName == NULL )
478         {
479                 QUARTZ_MediaType_Free(pmt);
480                 ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
481                 return E_OUTOFMEMORY;
482         }
483
484         memcpy( *ppFileName, This->m_pwszFileName, This->m_cbFileName );
485
486         return NOERROR;
487 }
488
489 static ICOM_VTABLE(IFileSourceFilter) ifilesource =
490 {
491         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
492         /* IUnknown fields */
493         CFileSourceFilterImpl_fnQueryInterface,
494         CFileSourceFilterImpl_fnAddRef,
495         CFileSourceFilterImpl_fnRelease,
496         /* IFileSourceFilter fields */
497         CFileSourceFilterImpl_fnLoad,
498         CFileSourceFilterImpl_fnGetCurFile,
499 };
500
501 HRESULT CFileSourceFilterImpl_InitIFileSourceFilter(
502         CFileSourceFilterImpl* This, IUnknown* punkControl,
503         CAsyncSourceImpl* pSource,
504         CRITICAL_SECTION* pcsFileSource )
505 {
506         TRACE("(%p,%p)\n",This,punkControl);
507
508         if ( punkControl == NULL )
509         {
510                 ERR( "punkControl must not be NULL\n" );
511                 return E_INVALIDARG;
512         }
513
514         ICOM_VTBL(This) = &ifilesource;
515         This->punkControl = punkControl;
516         This->pSource = pSource;
517         This->pcsFileSource = pcsFileSource;
518         This->m_pwszFileName = NULL;
519         This->m_cbFileName = 0;
520         ZeroMemory( &This->m_mt, sizeof(AM_MEDIA_TYPE) );
521
522         return NOERROR;
523 }
524
525 void CFileSourceFilterImpl_UninitIFileSourceFilter(
526         CFileSourceFilterImpl* This )
527 {
528         TRACE("(%p)\n",This);
529
530         This->pSource->m_pHandler->pCleanup( This->pSource );
531         if ( This->m_pwszFileName != NULL )
532                 QUARTZ_FreeMem( This->m_pwszFileName );
533         QUARTZ_MediaType_Free( &This->m_mt );
534 }
535
536 /***************************************************************************
537  *
538  *      CAsyncSourcePinImpl methods
539  *
540  */
541
542
543 static HRESULT CAsyncSourcePinImpl_OnPreConnect( CPinBaseImpl* pImpl, IPin* pPin )
544 {
545         CAsyncSourcePinImpl_THIS(pImpl,pin);
546
547         This->bAsyncReaderQueried = FALSE;
548
549         return NOERROR;
550 }
551
552 static HRESULT CAsyncSourcePinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin )
553 {
554         CAsyncSourcePinImpl_THIS(pImpl,pin);
555
556         if ( !This->bAsyncReaderQueried )
557                 return E_FAIL;
558
559         return NOERROR;
560 }
561
562 static HRESULT CAsyncSourcePinImpl_OnDisconnect( CPinBaseImpl* pImpl )
563 {
564         CAsyncSourcePinImpl_THIS(pImpl,pin);
565
566         This->bAsyncReaderQueried = FALSE;
567
568         return NOERROR;
569 }
570
571 static HRESULT CAsyncSourcePinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
572 {
573         CAsyncSourcePinImpl_THIS(pImpl,pin);
574
575         TRACE("(%p,%p)\n",This,pmt);
576         if ( pmt == NULL )
577                 return E_POINTER;
578
579         if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Stream ) )
580                 return E_FAIL;
581
582         return NOERROR;
583 }
584
585 static const CBasePinHandlers outputpinhandlers =
586 {
587         CAsyncSourcePinImpl_OnPreConnect, /* pOnPreConnect */
588         CAsyncSourcePinImpl_OnPostConnect, /* pOnPostConnect */
589         CAsyncSourcePinImpl_OnDisconnect, /* pOnDisconnect */
590         CAsyncSourcePinImpl_CheckMediaType, /* pCheckMediaType */
591         NULL, /* pQualityNotify */
592         NULL, /* pReceive */
593         NULL, /* pReceiveCanBlock */
594         NULL, /* pEndOfStream */
595         NULL, /* pBeginFlush */
596         NULL, /* pEndFlush */
597         NULL, /* pNewSegment */
598 };
599
600 /***************************************************************************
601  *
602  *      CAsyncSourceImpl methods
603  *
604  */
605
606 static HRESULT CAsyncSourceImpl_OnActive( CBaseFilterImpl* pImpl )
607 {
608         CAsyncSourceImpl_THIS(pImpl,basefilter);
609         HRESULT hr;
610
611         TRACE( "(%p)\n", This );
612
613         hr = CAsyncReaderImpl_BeginThread(&This->pPin->async);
614         if ( FAILED(hr) )
615                 return hr;
616
617         return NOERROR;
618 }
619
620 static HRESULT CAsyncSourceImpl_OnInactive( CBaseFilterImpl* pImpl )
621 {
622         CAsyncSourceImpl_THIS(pImpl,basefilter);
623
624         TRACE( "(%p)\n", This );
625
626         CAsyncReaderImpl_EndThread(&This->pPin->async);
627
628         return NOERROR;
629 }
630
631 static const CBaseFilterHandlers filterhandlers =
632 {
633         CAsyncSourceImpl_OnActive, /* pOnActive */
634         CAsyncSourceImpl_OnInactive, /* pOnInactive */
635         NULL, /* pOnStop */
636 };
637
638 /***************************************************************************
639  *
640  *      new/delete CAsyncSourceImpl
641  *
642  */
643
644 /* can I use offsetof safely? - FIXME? */
645 static QUARTZ_IFEntry FilterIFEntries[] =
646 {
647   { &IID_IPersist, offsetof(CAsyncSourceImpl,basefilter)-offsetof(CAsyncSourceImpl,unk) },
648   { &IID_IMediaFilter, offsetof(CAsyncSourceImpl,basefilter)-offsetof(CAsyncSourceImpl,unk) },
649   { &IID_IBaseFilter, offsetof(CAsyncSourceImpl,basefilter)-offsetof(CAsyncSourceImpl,unk) },
650   { &IID_IFileSourceFilter, offsetof(CAsyncSourceImpl,filesrc)-offsetof(CAsyncSourceImpl,unk) },
651 };
652
653 static void QUARTZ_DestroyAsyncSource(IUnknown* punk)
654 {
655         CAsyncSourceImpl_THIS(punk,unk);
656
657         TRACE( "(%p)\n", This );
658
659         if ( This->pPin != NULL )
660         {
661                 IUnknown_Release(This->pPin->unk.punkControl);
662                 This->pPin = NULL;
663         }
664
665         This->m_pHandler->pCleanup( This );
666
667         CFileSourceFilterImpl_UninitIFileSourceFilter(&This->filesrc);
668         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
669
670         DeleteCriticalSection( &This->csFilter );
671 }
672
673 HRESULT QUARTZ_CreateAsyncSource(
674         IUnknown* punkOuter,void** ppobj,
675         const CLSID* pclsidAsyncSource,
676         LPCWSTR pwszAsyncSourceName,
677         LPCWSTR pwszOutPinName,
678         const AsyncSourceHandlers* pHandler )
679 {
680         CAsyncSourceImpl*       This = NULL;
681         HRESULT hr;
682
683         TRACE("(%p,%p)\n",punkOuter,ppobj);
684
685         This = (CAsyncSourceImpl*)
686                 QUARTZ_AllocObj( sizeof(CAsyncSourceImpl) );
687         if ( This == NULL )
688                 return E_OUTOFMEMORY;
689
690         This->pPin = NULL;
691         This->m_pHandler = pHandler;
692         This->m_pUserData = NULL;
693
694         QUARTZ_IUnkInit( &This->unk, punkOuter );
695
696         hr = CBaseFilterImpl_InitIBaseFilter(
697                 &This->basefilter,
698                 This->unk.punkControl,
699                 pclsidAsyncSource,
700                 pwszAsyncSourceName,
701                 &filterhandlers );
702         if ( SUCCEEDED(hr) )
703         {
704                 /* construct this class. */
705                 hr = CFileSourceFilterImpl_InitIFileSourceFilter(
706                         &This->filesrc, This->unk.punkControl,
707                         This, &This->csFilter );
708                 if ( FAILED(hr) )
709                 {
710                         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
711                 }
712         }
713
714         if ( FAILED(hr) )
715         {
716                 QUARTZ_FreeObj(This);
717                 return hr;
718         }
719
720         This->unk.pEntries = FilterIFEntries;
721         This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]);
722         This->unk.pOnFinalRelease = QUARTZ_DestroyAsyncSource;
723         InitializeCriticalSection( &This->csFilter );
724
725         /* create the output pin. */
726         hr = S_OK;
727
728         if ( FAILED(hr) )
729         {
730                 IUnknown_Release( This->unk.punkControl );
731                 return hr;
732         }
733
734         *ppobj = (void*)&(This->unk);
735
736         return S_OK;
737 }
738
739 /***************************************************************************
740  *
741  *      new/delete CAsyncSourcePinImpl
742  *
743  */
744
745 /* can I use offsetof safely? - FIXME? */
746 static QUARTZ_IFEntry OutPinIFEntries[] =
747 {
748   { &IID_IPin, offsetof(CAsyncSourcePinImpl,pin)-offsetof(CAsyncSourcePinImpl,unk) },
749   /***{ &IID_IAsyncReader, offsetof(CAsyncSourcePinImpl,async)-offsetof(CAsyncSourcePinImpl,unk) },***/
750 };
751
752 static HRESULT CAsyncSourceImpl_OnQueryInterface(
753         IUnknown* punk, const IID* piid, void** ppobj )
754 {
755         CAsyncSourcePinImpl_THIS(punk,unk);
756
757         if ( IsEqualGUID( &IID_IAsyncReader, piid ) )
758         {
759                 *ppobj = (void*)&This->async;
760                 IUnknown_AddRef(punk);
761                 This->bAsyncReaderQueried = TRUE;
762                 return S_OK;
763         }
764
765         return E_NOINTERFACE;
766 }
767
768 static void QUARTZ_DestroyAsyncSourcePin(IUnknown* punk)
769 {
770         CAsyncSourcePinImpl_THIS(punk,unk);
771
772         TRACE( "(%p)\n", This );
773
774         CAsyncReaderImpl_UninitIAsyncReader( &This->async );
775         CPinBaseImpl_UninitIPin( &This->pin );
776 }
777
778 HRESULT QUARTZ_CreateAsyncSourcePin(
779         CAsyncSourceImpl* pFilter,
780         CRITICAL_SECTION* pcsPin,
781         CAsyncSourcePinImpl** ppPin,
782         LPCWSTR pwszPinName )
783 {
784         CAsyncSourcePinImpl*    This = NULL;
785         HRESULT hr;
786
787         TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
788
789         This = (CAsyncSourcePinImpl*)
790                 QUARTZ_AllocObj( sizeof(CAsyncSourcePinImpl) );
791         if ( This == NULL )
792                 return E_OUTOFMEMORY;
793
794         QUARTZ_IUnkInit( &This->unk, NULL );
795         This->qiext.pNext = NULL;
796         This->qiext.pOnQueryInterface = &CAsyncSourceImpl_OnQueryInterface;
797         QUARTZ_IUnkAddDelegation( &This->unk, &This->qiext );
798
799         This->bAsyncReaderQueried = FALSE;
800         This->pSource = pFilter;
801
802         hr = CPinBaseImpl_InitIPin(
803                 &This->pin,
804                 This->unk.punkControl,
805                 pcsPin,
806                 &pFilter->basefilter,
807                 pwszPinName,
808                 TRUE,
809                 &outputpinhandlers );
810
811         if ( SUCCEEDED(hr) )
812         {
813                 hr = CAsyncReaderImpl_InitIAsyncReader(
814                         &This->async,
815                         This->unk.punkControl,
816                         pFilter,
817                         pcsPin );
818                 if ( FAILED(hr) )
819                 {
820                         CPinBaseImpl_UninitIPin( &This->pin );
821                 }
822         }
823
824         if ( FAILED(hr) )
825         {
826                 QUARTZ_FreeObj(This);
827                 return hr;
828         }
829
830         This->unk.pEntries = OutPinIFEntries;
831         This->unk.dwEntries = sizeof(OutPinIFEntries)/sizeof(OutPinIFEntries[0]);
832         This->unk.pOnFinalRelease = QUARTZ_DestroyAsyncSourcePin;
833
834         *ppPin = This;
835
836         TRACE("returned successfully.\n");
837
838         return S_OK;
839 }
840