When including 'wine/port.h', include it first.
[wine] / dlls / quartz / asyncsrc.c
1 /*
2  * Implements Asynchronous File/URL Source.
3  *
4  * FIXME - URL source is not implemented 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 "strmif.h"
17 #include "vfwmsgs.h"
18 #include "uuids.h"
19
20 #include "debugtools.h"
21 DEFAULT_DEBUG_CHANNEL(quartz);
22
23 #include "quartz_private.h"
24 #include "asyncsrc.h"
25 #include "memalloc.h"
26
27
28
29 const WCHAR QUARTZ_wszAsyncFileSourceName[] =
30 {'F','i','l','e',' ','S','o','u','r','c','e',' ','(','A','s','y','n','c','.',')',0};
31 const WCHAR QUARTZ_wszAsyncFileSourcePinName[] =
32 {'O','u','t',0};
33 const WCHAR QUARTZ_wszAsyncURLSourceName[] =
34 {'F','i','l','e',' ','S','o','u','r','c','e',' ','(','U','R','L',')',0};
35 const WCHAR QUARTZ_wszAsyncURLSourcePinName[] =
36 {'O','u','t',0};
37
38
39
40 /***************************************************************************
41  *
42  *      CAsyncReaderImpl internal methods
43  *
44  */
45
46 static
47 AsyncSourceRequest* CAsyncReaderImpl_AllocRequest( CAsyncReaderImpl* This )
48 {
49         AsyncSourceRequest* pReq;
50
51         EnterCriticalSection( &This->m_csFree );
52         pReq = This->m_pFreeFirst;
53         if ( pReq != NULL )
54                 This->m_pFreeFirst = pReq->pNext;
55         LeaveCriticalSection( &This->m_csFree );
56
57         if ( pReq == NULL )
58         {
59                 pReq = (AsyncSourceRequest*)QUARTZ_AllocMem(
60                         sizeof(AsyncSourceRequest) );
61                 if ( pReq == NULL )
62                         return NULL;
63         }
64
65         pReq->pNext = NULL;
66         pReq->llStart = 0;
67         pReq->lLength = 0;
68         pReq->lActual = 0;
69         pReq->pBuf = NULL;
70         pReq->pSample = NULL;
71         pReq->dwContext = 0;
72
73         return pReq;
74 }
75
76 static
77 void CAsyncReaderImpl_FreeRequest( CAsyncReaderImpl* This, AsyncSourceRequest* pReq, BOOL bReleaseMem )
78 {
79         if ( !bReleaseMem )
80         {
81                 EnterCriticalSection( &This->m_csFree );
82                 pReq->pNext = This->m_pFreeFirst;
83                 This->m_pFreeFirst = pReq;
84                 LeaveCriticalSection( &This->m_csFree );
85         }
86         else
87         {
88                 QUARTZ_FreeMem( pReq );
89         }
90 }
91
92 static
93 AsyncSourceRequest* CAsyncReaderImpl_GetRequest( CAsyncReaderImpl* This )
94 {
95         AsyncSourceRequest*     pReq;
96
97         EnterCriticalSection( &This->m_csRequest );
98         pReq = This->m_pRequestFirst;
99         if ( pReq != NULL )
100                 This->m_pRequestFirst = pReq->pNext;
101         LeaveCriticalSection( &This->m_csRequest );
102
103         return pReq;
104 }
105
106 static
107 AsyncSourceRequest* CAsyncReaderImpl_GetReply( CAsyncReaderImpl* This )
108 {
109         AsyncSourceRequest*     pReq;
110
111         EnterCriticalSection( &This->m_csReply );
112         pReq = This->m_pReplyFirst;
113         if ( pReq != NULL )
114                 This->m_pReplyFirst = pReq->pNext;
115         LeaveCriticalSection( &This->m_csReply );
116
117         return pReq;
118 }
119
120 static
121 void CAsyncReaderImpl_PostRequest( CAsyncReaderImpl* This, AsyncSourceRequest* pReq )
122 {
123         /* FIXME - add to tail */
124         EnterCriticalSection( &This->m_csRequest );
125         pReq->pNext = This->m_pRequestFirst;
126         This->m_pRequestFirst = pReq;
127         if ( This->m_hEventReqQueued != (HANDLE)NULL )
128                 SetEvent( This->m_hEventReqQueued );
129         LeaveCriticalSection( &This->m_csRequest );
130 }
131
132 static
133 void CAsyncReaderImpl_PostReply( CAsyncReaderImpl* This, AsyncSourceRequest* pReq )
134 {
135         /* FIXME - add to tail */
136         EnterCriticalSection( &This->m_csReply );
137         pReq->pNext = This->m_pReplyFirst;
138         This->m_pReplyFirst = pReq;
139         if ( This->m_hEventSampQueued != (HANDLE)NULL )
140                 SetEvent( This->m_hEventSampQueued );
141         LeaveCriticalSection( &This->m_csReply );
142 }
143
144 static
145 void CAsyncReaderImpl_ReleaseReqList( CAsyncReaderImpl* This, AsyncSourceRequest* pReq, BOOL bReleaseMem )
146 {
147         AsyncSourceRequest* pReqNext;
148
149         while ( pReq != NULL )
150         {
151                 pReqNext = pReq->pNext;
152                 CAsyncReaderImpl_FreeRequest(This,pReq,bReleaseMem);
153                 pReq = pReqNext;
154         }
155 }
156
157 static DWORD WINAPI
158 CAsyncReaderImpl_ThreadEntry( LPVOID pv )
159 {
160         CAsyncReaderImpl*       This = (CAsyncReaderImpl*)pv;
161         HANDLE hWaitEvents[2];
162         HRESULT hr;
163         DWORD   dwRes;
164         AsyncSourceRequest*     pReq = NULL;
165
166         SetEvent( This->m_hEventInit );
167
168         hWaitEvents[0] = This->m_hEventReqQueued;
169         hWaitEvents[1] = This->m_hEventCancel;
170
171         TRACE("enter message loop.\n");
172
173         while ( 1 )
174         {
175                 ResetEvent( This->m_hEventReqQueued );
176                 pReq = CAsyncReaderImpl_GetRequest(This);
177                 if ( pReq == NULL )
178                 {
179                         dwRes = WaitForMultipleObjects(2,hWaitEvents,FALSE,INFINITE);
180                         if ( dwRes != WAIT_OBJECT_0 )
181                         {
182                                 if ( This->m_bAbortThread )
183                                         break;
184                         }
185                         continue;
186                 }
187
188                 /* process a queued request */
189                 EnterCriticalSection( &This->m_csReader );
190                 hr = This->pSource->m_pHandler->pRead( This->pSource, pReq->llStart, pReq->lLength, pReq->pBuf, &pReq->lActual, This->m_hEventCancel );
191                 LeaveCriticalSection( &This->m_csReader );
192
193                 if ( FAILED(hr) )
194                 {
195                         /* Notify(ABORT) */
196                         break;
197                 }
198                 if ( hr != S_OK )
199                 {
200                         if ( This->m_bAbortThread )
201                                 break;
202                         ResetEvent( This->m_hEventCancel );
203                 }
204
205                 CAsyncReaderImpl_PostReply( This, pReq );
206                 SetEvent( This->m_hEventSampQueued );
207                 pReq = NULL;
208         }
209
210         if ( pReq != NULL )
211                 CAsyncReaderImpl_PostRequest( This, pReq );
212
213         SetEvent( This->m_hEventSampQueued );
214         return 0;
215 }
216
217 static HRESULT
218 CAsyncReaderImpl_BeginThread( CAsyncReaderImpl* This )
219 {
220         DWORD dwRes;
221         DWORD dwThreadId;
222         HANDLE hEvents[2];
223
224         if ( This->m_hEventInit != (HANDLE)NULL ||
225                  This->m_hEventCancel != (HANDLE)NULL ||
226                  This->m_hEventReqQueued != (HANDLE)NULL ||
227                  This->m_hEventSampQueued != (HANDLE)NULL ||
228                  This->m_hThread != (HANDLE)NULL )
229                 return E_UNEXPECTED;
230         This->m_bAbortThread = FALSE;
231
232         This->m_hEventInit = CreateEventA(NULL,TRUE,FALSE,NULL);
233         if ( This->m_hEventInit == (HANDLE)NULL )
234                 return E_OUTOFMEMORY;
235         This->m_hEventCancel = CreateEventA(NULL,TRUE,FALSE,NULL);
236         if ( This->m_hEventCancel == (HANDLE)NULL )
237                 return E_OUTOFMEMORY;
238         This->m_hEventReqQueued = CreateEventA(NULL,TRUE,FALSE,NULL);
239         if ( This->m_hEventReqQueued == (HANDLE)NULL )
240                 return E_OUTOFMEMORY;
241         This->m_hEventSampQueued = CreateEventA(NULL,TRUE,FALSE,NULL);
242         if ( This->m_hEventSampQueued == (HANDLE)NULL )
243                 return E_OUTOFMEMORY;
244
245         /* create the processing thread. */
246         This->m_hThread = CreateThread(
247                 NULL, 0,
248                 CAsyncReaderImpl_ThreadEntry,
249                 (LPVOID)This,
250                 0, &dwThreadId );
251         if ( This->m_hThread == (HANDLE)NULL )
252                 return E_FAIL;
253
254         hEvents[0] = This->m_hEventInit;
255         hEvents[1] = This->m_hThread;
256
257         dwRes = WaitForMultipleObjects(2,hEvents,FALSE,INFINITE);
258         if ( dwRes != WAIT_OBJECT_0 )
259                 return E_FAIL;
260
261         return NOERROR;
262 }
263
264 static void
265 CAsyncReaderImpl_EndThread( CAsyncReaderImpl* This )
266 {
267         if ( This->m_hThread != (HANDLE)NULL )
268         {
269                 while ( 1 )
270                 {
271                         This->m_bAbortThread = TRUE;
272                         SetEvent( This->m_hEventCancel );
273                         if ( WaitForSingleObject( This->m_hThread, 100 ) == WAIT_OBJECT_0 )
274                                 break;
275                 }
276                 CloseHandle( This->m_hThread );
277                 This->m_hThread = (HANDLE)NULL;
278         }
279         if ( This->m_hEventInit != (HANDLE)NULL )
280         {
281                 CloseHandle( This->m_hEventInit );
282                 This->m_hEventInit = (HANDLE)NULL;
283         }
284         if ( This->m_hEventCancel != (HANDLE)NULL )
285         {
286                 CloseHandle( This->m_hEventCancel );
287                 This->m_hEventCancel = (HANDLE)NULL;
288         }
289         if ( This->m_hEventReqQueued != (HANDLE)NULL )
290         {
291                 CloseHandle( This->m_hEventReqQueued );
292                 This->m_hEventReqQueued = (HANDLE)NULL;
293         }
294         if ( This->m_hEventSampQueued != (HANDLE)NULL )
295         {
296                 CloseHandle( This->m_hEventSampQueued );
297                 This->m_hEventSampQueued = (HANDLE)NULL;
298         }
299 }
300
301 /***************************************************************************
302  *
303  *      CAsyncReaderImpl methods
304  *
305  */
306
307 static HRESULT WINAPI
308 CAsyncReaderImpl_fnQueryInterface(IAsyncReader* iface,REFIID riid,void** ppobj)
309 {
310         ICOM_THIS(CAsyncReaderImpl,iface);
311
312         TRACE("(%p)->()\n",This);
313
314         return IUnknown_QueryInterface(This->punkControl,riid,ppobj);
315 }
316
317 static ULONG WINAPI
318 CAsyncReaderImpl_fnAddRef(IAsyncReader* iface)
319 {
320         ICOM_THIS(CAsyncReaderImpl,iface);
321
322         TRACE("(%p)->()\n",This);
323
324         return IUnknown_AddRef(This->punkControl);
325 }
326
327 static ULONG WINAPI
328 CAsyncReaderImpl_fnRelease(IAsyncReader* iface)
329 {
330         ICOM_THIS(CAsyncReaderImpl,iface);
331
332         TRACE("(%p)->()\n",This);
333
334         return IUnknown_Release(This->punkControl);
335 }
336
337 static HRESULT WINAPI
338 CAsyncReaderImpl_fnRequestAllocator(IAsyncReader* iface,IMemAllocator* pAlloc,ALLOCATOR_PROPERTIES* pProp,IMemAllocator** ppAllocActual)
339 {
340         ICOM_THIS(CAsyncReaderImpl,iface);
341         HRESULT hr;
342         ALLOCATOR_PROPERTIES    propActual;
343         IUnknown* punk = NULL;
344
345         TRACE("(%p)->(%p,%p,%p)\n",This,pAlloc,pProp,ppAllocActual);
346
347         if ( pAlloc == NULL || pProp == NULL || ppAllocActual == NULL )
348                 return E_POINTER;
349
350         IMemAllocator_AddRef(pAlloc);
351         hr = IMemAllocator_SetProperties( pAlloc, pProp, &propActual );
352         if ( SUCCEEDED(hr) )
353         {
354                 *ppAllocActual = pAlloc;
355                 return S_OK;
356         }
357         IMemAllocator_Release(pAlloc);
358
359         hr = QUARTZ_CreateMemoryAllocator(NULL,(void**)&punk);
360         if ( FAILED(hr) )
361                 return hr;
362         hr = IUnknown_QueryInterface( punk, &IID_IMemAllocator, (void**)&pAlloc );
363         IUnknown_Release(punk);
364         if ( FAILED(hr) )
365                 return hr;
366
367         hr = IMemAllocator_SetProperties( pAlloc, pProp, &propActual );
368         if ( SUCCEEDED(hr) )
369         {
370                 *ppAllocActual = pAlloc;
371                 return S_OK;
372         }
373         IMemAllocator_Release(pAlloc);
374
375         return hr;
376 }
377
378 static HRESULT WINAPI
379 CAsyncReaderImpl_fnRequest(IAsyncReader* iface,IMediaSample* pSample,DWORD_PTR dwContext)
380 {
381         ICOM_THIS(CAsyncReaderImpl,iface);
382         HRESULT hr = NOERROR;
383         REFERENCE_TIME  rtStart;
384         REFERENCE_TIME  rtEnd;
385         AsyncSourceRequest*     pReq;
386         BYTE*   pData = NULL;
387
388         TRACE("(%p)->(%p,%u)\n",This,pSample,dwContext);
389
390         hr = IMediaSample_GetPointer(pSample,&pData);
391         if ( SUCCEEDED(hr) )
392                 hr = IMediaSample_GetTime(pSample,&rtStart,&rtEnd);
393         if ( FAILED(hr) )
394                 return hr;
395
396         pReq = CAsyncReaderImpl_AllocRequest(This);
397         if ( pReq == NULL )
398                 return E_OUTOFMEMORY;
399
400         pReq->llStart = rtStart / QUARTZ_TIMEUNITS;
401         pReq->lLength = (LONG)(rtEnd / QUARTZ_TIMEUNITS - rtStart / QUARTZ_TIMEUNITS);
402         pReq->lActual = 0;
403         pReq->pBuf = pData;
404         pReq->pSample = pSample;
405         pReq->dwContext = dwContext;
406         CAsyncReaderImpl_PostRequest( This, pReq );
407
408         return NOERROR;
409 }
410
411 static HRESULT WINAPI
412 CAsyncReaderImpl_fnWaitForNext(IAsyncReader* iface,DWORD dwTimeout,IMediaSample** ppSample,DWORD_PTR* pdwContext)
413 {
414         ICOM_THIS(CAsyncReaderImpl,iface);
415         HRESULT hr = NOERROR;
416         DWORD dwRes;
417         AsyncSourceRequest*     pReq;
418         REFERENCE_TIME  rtStart;
419         REFERENCE_TIME  rtEnd;
420
421         TRACE("(%p)->(%lu,%p,%p)\n",This,dwTimeout,ppSample,pdwContext);
422
423         EnterCriticalSection( &This->m_csRequest );
424         if ( This->m_bInFlushing )
425                 hr = VFW_E_TIMEOUT;
426         LeaveCriticalSection( &This->m_csRequest );
427
428         if ( hr == NOERROR )
429         {
430                 ResetEvent( This->m_hEventSampQueued );
431                 pReq = CAsyncReaderImpl_GetReply(This);
432                 if ( pReq == NULL )
433                 {
434                         dwRes = WaitForSingleObject( This->m_hEventSampQueued, dwTimeout );
435                         if ( dwRes == WAIT_OBJECT_0 )
436                                 pReq = CAsyncReaderImpl_GetReply(This);
437                 }
438                 if ( pReq != NULL )
439                 {
440                         hr = IMediaSample_SetActualDataLength(pReq->pSample,pReq->lActual);
441                         if ( hr == S_OK )
442                         {
443                                 rtStart = pReq->llStart * QUARTZ_TIMEUNITS;
444                                 rtEnd = (pReq->llStart + pReq->lActual) * QUARTZ_TIMEUNITS;
445                                 hr = IMediaSample_SetTime(pReq->pSample,&rtStart,&rtEnd);
446                         }
447                         *ppSample = pReq->pSample;
448                         *pdwContext = pReq->dwContext;
449                         if ( hr == S_OK && pReq->lActual != pReq->lLength )
450                                 hr = S_FALSE;
451                 }
452                 else
453                 {
454                         hr = VFW_E_TIMEOUT;
455                 }
456         }
457
458         return hr;
459 }
460
461 static HRESULT WINAPI
462 CAsyncReaderImpl_fnSyncReadAligned(IAsyncReader* iface,IMediaSample* pSample)
463 {
464         ICOM_THIS(CAsyncReaderImpl,iface);
465         HRESULT hr;
466         REFERENCE_TIME  rtStart;
467         REFERENCE_TIME  rtEnd;
468         BYTE*   pData = NULL;
469         LONGLONG        llStart;
470         LONG    lLength;
471         LONG    lActual;
472
473         TRACE("(%p)->(%p)\n",This,pSample);
474
475         hr = IMediaSample_GetPointer(pSample,&pData);
476         if ( SUCCEEDED(hr) )
477                 hr = IMediaSample_GetTime(pSample,&rtStart,&rtEnd);
478         if ( FAILED(hr) )
479                 return hr;
480
481         llStart = rtStart / QUARTZ_TIMEUNITS;
482         lLength = (LONG)(rtEnd / QUARTZ_TIMEUNITS - rtStart / QUARTZ_TIMEUNITS);
483         lActual = 0;
484
485         EnterCriticalSection( &This->m_csReader );
486         hr = This->pSource->m_pHandler->pRead( This->pSource, llStart, lLength, pData, &lActual, (HANDLE)NULL );
487         LeaveCriticalSection( &This->m_csReader );
488
489         if ( hr == NOERROR )
490         {
491                 hr = IMediaSample_SetActualDataLength(pSample,lActual);
492                 if ( hr == S_OK )
493                 {
494                         rtStart = llStart * QUARTZ_TIMEUNITS;
495                         rtEnd = (llStart + lActual) * QUARTZ_TIMEUNITS;
496                         hr = IMediaSample_SetTime(pSample,&rtStart,&rtEnd);
497                 }
498                 if ( hr == S_OK && lActual != lLength )
499                         hr = S_FALSE;
500         }
501
502         return hr;
503 }
504
505 static HRESULT WINAPI
506 CAsyncReaderImpl_fnSyncRead(IAsyncReader* iface,LONGLONG llPosStart,LONG lLength,BYTE* pbBuf)
507 {
508         ICOM_THIS(CAsyncReaderImpl,iface);
509         HRESULT hr;
510         LONG lActual;
511
512         TRACE("(%p)->()\n",This);
513
514         EnterCriticalSection( &This->m_csReader );
515         hr = This->pSource->m_pHandler->pRead( This->pSource, llPosStart, lLength, pbBuf, &lActual, (HANDLE)NULL );
516         LeaveCriticalSection( &This->m_csReader );
517
518         if ( hr == S_OK && lLength != lActual )
519                 hr = S_FALSE;
520
521         return hr;
522 }
523
524 static HRESULT WINAPI
525 CAsyncReaderImpl_fnLength(IAsyncReader* iface,LONGLONG* pllTotal,LONGLONG* pllAvailable)
526 {
527         ICOM_THIS(CAsyncReaderImpl,iface);
528         HRESULT hr;
529
530         TRACE("(%p)->()\n",This);
531
532         hr = This->pSource->m_pHandler->pGetLength( This->pSource, pllTotal, pllAvailable );
533
534         return hr;
535 }
536
537 static HRESULT WINAPI
538 CAsyncReaderImpl_fnBeginFlush(IAsyncReader* iface)
539 {
540         ICOM_THIS(CAsyncReaderImpl,iface);
541
542         TRACE("(%p)->()\n",This);
543
544         EnterCriticalSection( &This->m_csRequest );
545         This->m_bInFlushing = TRUE;
546         SetEvent( This->m_hEventCancel );
547         CAsyncReaderImpl_ReleaseReqList(This,This->m_pRequestFirst,FALSE);
548         LeaveCriticalSection( &This->m_csRequest );
549
550         return NOERROR;
551 }
552
553 static HRESULT WINAPI
554 CAsyncReaderImpl_fnEndFlush(IAsyncReader* iface)
555 {
556         ICOM_THIS(CAsyncReaderImpl,iface);
557
558         TRACE("(%p)->()\n",This);
559
560         EnterCriticalSection( &This->m_csRequest );
561         This->m_bInFlushing = FALSE;
562         ResetEvent( This->m_hEventCancel );
563         LeaveCriticalSection( &This->m_csRequest );
564
565         return NOERROR;
566 }
567
568
569 static ICOM_VTABLE(IAsyncReader) iasyncreader =
570 {
571         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
572         /* IUnknown fields */
573         CAsyncReaderImpl_fnQueryInterface,
574         CAsyncReaderImpl_fnAddRef,
575         CAsyncReaderImpl_fnRelease,
576
577         /* IAsyncReader fields */
578         CAsyncReaderImpl_fnRequestAllocator,
579         CAsyncReaderImpl_fnRequest,
580         CAsyncReaderImpl_fnWaitForNext,
581         CAsyncReaderImpl_fnSyncReadAligned,
582         CAsyncReaderImpl_fnSyncRead,
583         CAsyncReaderImpl_fnLength,
584         CAsyncReaderImpl_fnBeginFlush,
585         CAsyncReaderImpl_fnEndFlush,
586 };
587
588 HRESULT CAsyncReaderImpl_InitIAsyncReader(
589         CAsyncReaderImpl* This, IUnknown* punkControl,
590         CAsyncSourceImpl* pSource )
591 {
592         TRACE("(%p,%p)\n",This,punkControl);
593
594         if ( punkControl == NULL )
595         {
596                 ERR( "punkControl must not be NULL\n" );
597                 return E_INVALIDARG;
598         }
599
600         ICOM_VTBL(This) = &iasyncreader;
601         This->punkControl = punkControl;
602         This->pSource = pSource;
603         This->m_bInFlushing = FALSE;
604         This->m_bAbortThread = FALSE;
605         This->m_hEventInit = (HANDLE)NULL;
606         This->m_hEventCancel = (HANDLE)NULL;
607         This->m_hEventReqQueued = (HANDLE)NULL;
608         This->m_hEventSampQueued = (HANDLE)NULL;
609         This->m_hThread = (HANDLE)NULL;
610         This->m_pRequestFirst = NULL;
611         This->m_pReplyFirst = NULL;
612         This->m_pFreeFirst = NULL;
613
614         InitializeCriticalSection( &This->m_csReader );
615         InitializeCriticalSection( &This->m_csRequest );
616         InitializeCriticalSection( &This->m_csReply );
617         InitializeCriticalSection( &This->m_csFree );
618
619         return NOERROR;
620 }
621
622 void CAsyncReaderImpl_UninitIAsyncReader(
623         CAsyncReaderImpl* This )
624 {
625         TRACE("(%p)\n",This);
626
627         CAsyncReaderImpl_ReleaseReqList(This,This->m_pRequestFirst,TRUE);
628         CAsyncReaderImpl_ReleaseReqList(This,This->m_pReplyFirst,TRUE);
629         CAsyncReaderImpl_ReleaseReqList(This,This->m_pFreeFirst,TRUE);
630
631         DeleteCriticalSection( &This->m_csReader );
632         DeleteCriticalSection( &This->m_csRequest );
633         DeleteCriticalSection( &This->m_csReply );
634         DeleteCriticalSection( &This->m_csFree );
635 }
636
637 /***************************************************************************
638  *
639  *      CFileSourceFilterImpl
640  *
641  */
642
643 static HRESULT WINAPI
644 CFileSourceFilterImpl_fnQueryInterface(IFileSourceFilter* iface,REFIID riid,void** ppobj)
645 {
646         ICOM_THIS(CFileSourceFilterImpl,iface);
647
648         TRACE("(%p)->()\n",This);
649
650         return IUnknown_QueryInterface(This->punkControl,riid,ppobj);
651 }
652
653 static ULONG WINAPI
654 CFileSourceFilterImpl_fnAddRef(IFileSourceFilter* iface)
655 {
656         ICOM_THIS(CFileSourceFilterImpl,iface);
657
658         TRACE("(%p)->()\n",This);
659
660         return IUnknown_AddRef(This->punkControl);
661 }
662
663 static ULONG WINAPI
664 CFileSourceFilterImpl_fnRelease(IFileSourceFilter* iface)
665 {
666         ICOM_THIS(CFileSourceFilterImpl,iface);
667
668         TRACE("(%p)->()\n",This);
669
670         return IUnknown_Release(This->punkControl);
671 }
672
673 static HRESULT WINAPI
674 CFileSourceFilterImpl_fnLoad(IFileSourceFilter* iface,LPCOLESTR pFileName,const AM_MEDIA_TYPE* pmt)
675 {
676         ICOM_THIS(CFileSourceFilterImpl,iface);
677         HRESULT hr;
678
679         TRACE("(%p)->(%s,%p)\n",This,debugstr_w(pFileName),pmt);
680
681         if ( pFileName == NULL )
682                 return E_POINTER;
683
684         if ( This->m_pwszFileName != NULL )
685                 return E_UNEXPECTED;
686
687         This->m_cbFileName = sizeof(WCHAR)*(lstrlenW(pFileName)+1);
688         This->m_pwszFileName = (WCHAR*)QUARTZ_AllocMem( This->m_cbFileName );
689         if ( This->m_pwszFileName == NULL )
690                 return E_OUTOFMEMORY;
691         memcpy( This->m_pwszFileName, pFileName, This->m_cbFileName );
692
693         if ( pmt != NULL )
694         {
695                 hr = QUARTZ_MediaType_Copy( &This->m_mt, pmt );
696                 if ( FAILED(hr) )
697                         goto err;
698         }
699         else
700         {
701                 ZeroMemory( &This->m_mt, sizeof(AM_MEDIA_TYPE) );
702                 memcpy( &This->m_mt.majortype, &MEDIATYPE_Stream, sizeof(GUID) );
703                 memcpy( &This->m_mt.subtype, &MEDIASUBTYPE_NULL, sizeof(GUID) );
704                 This->m_mt.lSampleSize = 1;
705                 memcpy( &This->m_mt.formattype, &FORMAT_None, sizeof(GUID) );
706         }
707
708         hr = This->pSource->m_pHandler->pLoad( This->pSource, pFileName );
709         if ( FAILED(hr) )
710                 goto err;
711
712         This->pSource->pPin->pin.pmtAcceptTypes = &This->m_mt;
713         This->pSource->pPin->pin.cAcceptTypes = 1;
714
715         return NOERROR;
716 err:;
717         return hr;
718 }
719
720 static HRESULT WINAPI
721 CFileSourceFilterImpl_fnGetCurFile(IFileSourceFilter* iface,LPOLESTR* ppFileName,AM_MEDIA_TYPE* pmt)
722 {
723         ICOM_THIS(CFileSourceFilterImpl,iface);
724         HRESULT hr = E_NOTIMPL;
725
726         TRACE("(%p)->(%p,%p)\n",This,ppFileName,pmt);
727
728         if ( ppFileName == NULL || pmt == NULL )
729                 return E_POINTER;
730
731         if ( This->m_pwszFileName == NULL )
732                 return E_FAIL;
733
734         hr = QUARTZ_MediaType_Copy( pmt, &This->m_mt );
735         if ( FAILED(hr) )
736                 return hr;
737
738         *ppFileName = (WCHAR*)CoTaskMemAlloc( This->m_cbFileName );
739         if ( *ppFileName == NULL )
740         {
741                 QUARTZ_MediaType_Free(pmt);
742                 ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
743                 return E_OUTOFMEMORY;
744         }
745
746         memcpy( *ppFileName, This->m_pwszFileName, This->m_cbFileName );
747
748         return NOERROR;
749 }
750
751 static ICOM_VTABLE(IFileSourceFilter) ifilesource =
752 {
753         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
754         /* IUnknown fields */
755         CFileSourceFilterImpl_fnQueryInterface,
756         CFileSourceFilterImpl_fnAddRef,
757         CFileSourceFilterImpl_fnRelease,
758         /* IFileSourceFilter fields */
759         CFileSourceFilterImpl_fnLoad,
760         CFileSourceFilterImpl_fnGetCurFile,
761 };
762
763 HRESULT CFileSourceFilterImpl_InitIFileSourceFilter(
764         CFileSourceFilterImpl* This, IUnknown* punkControl,
765         CAsyncSourceImpl* pSource,
766         CRITICAL_SECTION* pcsFileSource )
767 {
768         TRACE("(%p,%p)\n",This,punkControl);
769
770         if ( punkControl == NULL )
771         {
772                 ERR( "punkControl must not be NULL\n" );
773                 return E_INVALIDARG;
774         }
775
776         ICOM_VTBL(This) = &ifilesource;
777         This->punkControl = punkControl;
778         This->pSource = pSource;
779         This->pcsFileSource = pcsFileSource;
780         This->m_pwszFileName = NULL;
781         This->m_cbFileName = 0;
782         ZeroMemory( &This->m_mt, sizeof(AM_MEDIA_TYPE) );
783
784         return NOERROR;
785 }
786
787 void CFileSourceFilterImpl_UninitIFileSourceFilter(
788         CFileSourceFilterImpl* This )
789 {
790         TRACE("(%p)\n",This);
791
792         This->pSource->m_pHandler->pCleanup( This->pSource );
793         if ( This->m_pwszFileName != NULL )
794                 QUARTZ_FreeMem( This->m_pwszFileName );
795         QUARTZ_MediaType_Free( &This->m_mt );
796 }
797
798 /***************************************************************************
799  *
800  *      CAsyncSourcePinImpl methods
801  *
802  */
803
804
805 static HRESULT CAsyncSourcePinImpl_OnPreConnect( CPinBaseImpl* pImpl, IPin* pPin )
806 {
807         CAsyncSourcePinImpl_THIS(pImpl,pin);
808
809         TRACE("(%p,%p)\n",This,pPin);
810
811         This->bAsyncReaderQueried = FALSE;
812
813         return NOERROR;
814 }
815
816 static HRESULT CAsyncSourcePinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin )
817 {
818         CAsyncSourcePinImpl_THIS(pImpl,pin);
819
820         TRACE("(%p,%p)\n",This,pPin);
821
822         if ( !This->bAsyncReaderQueried )
823                 return E_FAIL;
824
825         return NOERROR;
826 }
827
828 static HRESULT CAsyncSourcePinImpl_OnDisconnect( CPinBaseImpl* pImpl )
829 {
830         CAsyncSourcePinImpl_THIS(pImpl,pin);
831
832         TRACE("(%p)\n",This);
833
834         This->bAsyncReaderQueried = FALSE;
835
836         return NOERROR;
837 }
838
839 static HRESULT CAsyncSourcePinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
840 {
841         CAsyncSourcePinImpl_THIS(pImpl,pin);
842
843         TRACE("(%p,%p)\n",This,pmt);
844         if ( pmt == NULL )
845                 return E_POINTER;
846
847         if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Stream ) )
848                 return E_FAIL;
849
850         return NOERROR;
851 }
852
853 static const CBasePinHandlers outputpinhandlers =
854 {
855         CAsyncSourcePinImpl_OnPreConnect, /* pOnPreConnect */
856         CAsyncSourcePinImpl_OnPostConnect, /* pOnPostConnect */
857         CAsyncSourcePinImpl_OnDisconnect, /* pOnDisconnect */
858         CAsyncSourcePinImpl_CheckMediaType, /* pCheckMediaType */
859         NULL, /* pQualityNotify */
860         NULL, /* pReceive */
861         NULL, /* pReceiveCanBlock */
862         NULL, /* pEndOfStream */
863         NULL, /* pBeginFlush */
864         NULL, /* pEndFlush */
865         NULL, /* pNewSegment */
866 };
867
868 /***************************************************************************
869  *
870  *      CAsyncSourceImpl methods
871  *
872  */
873
874 static HRESULT CAsyncSourceImpl_OnActive( CBaseFilterImpl* pImpl )
875 {
876         CAsyncSourceImpl_THIS(pImpl,basefilter);
877         HRESULT hr;
878
879         TRACE( "(%p)\n", This );
880
881         hr = CAsyncReaderImpl_BeginThread(&This->pPin->async);
882         if ( FAILED(hr) )
883                 return hr;
884
885         return NOERROR;
886 }
887
888 static HRESULT CAsyncSourceImpl_OnInactive( CBaseFilterImpl* pImpl )
889 {
890         CAsyncSourceImpl_THIS(pImpl,basefilter);
891
892         TRACE( "(%p)\n", This );
893
894         CAsyncReaderImpl_EndThread(&This->pPin->async);
895
896         return NOERROR;
897 }
898
899 static const CBaseFilterHandlers filterhandlers =
900 {
901         CAsyncSourceImpl_OnActive, /* pOnActive */
902         CAsyncSourceImpl_OnInactive, /* pOnInactive */
903         NULL, /* pOnStop */
904 };
905
906 /***************************************************************************
907  *
908  *      new/delete CAsyncSourceImpl
909  *
910  */
911
912 /* can I use offsetof safely? - FIXME? */
913 static QUARTZ_IFEntry FilterIFEntries[] =
914 {
915   { &IID_IPersist, offsetof(CAsyncSourceImpl,basefilter)-offsetof(CAsyncSourceImpl,unk) },
916   { &IID_IMediaFilter, offsetof(CAsyncSourceImpl,basefilter)-offsetof(CAsyncSourceImpl,unk) },
917   { &IID_IBaseFilter, offsetof(CAsyncSourceImpl,basefilter)-offsetof(CAsyncSourceImpl,unk) },
918   { &IID_IFileSourceFilter, offsetof(CAsyncSourceImpl,filesrc)-offsetof(CAsyncSourceImpl,unk) },
919 };
920
921 static void QUARTZ_DestroyAsyncSource(IUnknown* punk)
922 {
923         CAsyncSourceImpl_THIS(punk,unk);
924
925         TRACE( "(%p)\n", This );
926
927         if ( This->pPin != NULL )
928         {
929                 IUnknown_Release(This->pPin->unk.punkControl);
930                 This->pPin = NULL;
931         }
932
933         This->m_pHandler->pCleanup( This );
934
935         CFileSourceFilterImpl_UninitIFileSourceFilter(&This->filesrc);
936         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
937
938         DeleteCriticalSection( &This->csFilter );
939 }
940
941 HRESULT QUARTZ_CreateAsyncSource(
942         IUnknown* punkOuter,void** ppobj,
943         const CLSID* pclsidAsyncSource,
944         LPCWSTR pwszAsyncSourceName,
945         LPCWSTR pwszOutPinName,
946         const AsyncSourceHandlers* pHandler )
947 {
948         CAsyncSourceImpl*       This = NULL;
949         HRESULT hr;
950
951         TRACE("(%p,%p)\n",punkOuter,ppobj);
952
953         This = (CAsyncSourceImpl*)
954                 QUARTZ_AllocObj( sizeof(CAsyncSourceImpl) );
955         if ( This == NULL )
956                 return E_OUTOFMEMORY;
957
958         This->pPin = NULL;
959         This->m_pHandler = pHandler;
960         This->m_pUserData = NULL;
961
962         QUARTZ_IUnkInit( &This->unk, punkOuter );
963
964         hr = CBaseFilterImpl_InitIBaseFilter(
965                 &This->basefilter,
966                 This->unk.punkControl,
967                 pclsidAsyncSource,
968                 pwszAsyncSourceName,
969                 &filterhandlers );
970         if ( SUCCEEDED(hr) )
971         {
972                 /* construct this class. */
973                 hr = CFileSourceFilterImpl_InitIFileSourceFilter(
974                         &This->filesrc, This->unk.punkControl,
975                         This, &This->csFilter );
976                 if ( FAILED(hr) )
977                 {
978                         CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
979                 }
980         }
981
982         if ( FAILED(hr) )
983         {
984                 QUARTZ_FreeObj(This);
985                 return hr;
986         }
987
988         This->unk.pEntries = FilterIFEntries;
989         This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]);
990         This->unk.pOnFinalRelease = QUARTZ_DestroyAsyncSource;
991         InitializeCriticalSection( &This->csFilter );
992
993         /* create the output pin. */
994         hr = QUARTZ_CreateAsyncSourcePin(
995                 This, &This->csFilter,
996                 &This->pPin, pwszOutPinName );
997         if ( SUCCEEDED(hr) )
998                 hr = QUARTZ_CompList_AddComp(
999                         This->basefilter.pOutPins,
1000                         (IUnknown*)&(This->pPin->pin),
1001                         NULL, 0 );
1002
1003         if ( FAILED(hr) )
1004         {
1005                 IUnknown_Release( This->unk.punkControl );
1006                 return hr;
1007         }
1008
1009         *ppobj = (void*)&(This->unk);
1010
1011         return S_OK;
1012 }
1013
1014 /***************************************************************************
1015  *
1016  *      new/delete CAsyncSourcePinImpl
1017  *
1018  */
1019
1020 /* can I use offsetof safely? - FIXME? */
1021 static QUARTZ_IFEntry OutPinIFEntries[] =
1022 {
1023   { &IID_IPin, offsetof(CAsyncSourcePinImpl,pin)-offsetof(CAsyncSourcePinImpl,unk) },
1024   /***{ &IID_IAsyncReader, offsetof(CAsyncSourcePinImpl,async)-offsetof(CAsyncSourcePinImpl,unk) },***/
1025 };
1026
1027 static HRESULT CAsyncSourceImpl_OnQueryInterface(
1028         IUnknown* punk, const IID* piid, void** ppobj )
1029 {
1030         CAsyncSourcePinImpl_THIS(punk,unk);
1031
1032         if ( IsEqualGUID( &IID_IAsyncReader, piid ) )
1033         {
1034                 TRACE("IAsyncReader has been queried.\n");
1035                 *ppobj = (void*)&This->async;
1036                 IUnknown_AddRef(punk);
1037                 This->bAsyncReaderQueried = TRUE;
1038                 return S_OK;
1039         }
1040
1041         return E_NOINTERFACE;
1042 }
1043
1044 static void QUARTZ_DestroyAsyncSourcePin(IUnknown* punk)
1045 {
1046         CAsyncSourcePinImpl_THIS(punk,unk);
1047
1048         TRACE( "(%p)\n", This );
1049
1050         CAsyncReaderImpl_UninitIAsyncReader( &This->async );
1051         CPinBaseImpl_UninitIPin( &This->pin );
1052 }
1053
1054 HRESULT QUARTZ_CreateAsyncSourcePin(
1055         CAsyncSourceImpl* pFilter,
1056         CRITICAL_SECTION* pcsPin,
1057         CAsyncSourcePinImpl** ppPin,
1058         LPCWSTR pwszPinName )
1059 {
1060         CAsyncSourcePinImpl*    This = NULL;
1061         HRESULT hr;
1062
1063         TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
1064
1065         This = (CAsyncSourcePinImpl*)
1066                 QUARTZ_AllocObj( sizeof(CAsyncSourcePinImpl) );
1067         if ( This == NULL )
1068                 return E_OUTOFMEMORY;
1069
1070         QUARTZ_IUnkInit( &This->unk, NULL );
1071         This->qiext.pNext = NULL;
1072         This->qiext.pOnQueryInterface = &CAsyncSourceImpl_OnQueryInterface;
1073         QUARTZ_IUnkAddDelegation( &This->unk, &This->qiext );
1074
1075         This->bAsyncReaderQueried = FALSE;
1076         This->pSource = pFilter;
1077
1078         hr = CPinBaseImpl_InitIPin(
1079                 &This->pin,
1080                 This->unk.punkControl,
1081                 pcsPin,
1082                 &pFilter->basefilter,
1083                 pwszPinName,
1084                 TRUE,
1085                 &outputpinhandlers );
1086
1087         if ( SUCCEEDED(hr) )
1088         {
1089                 hr = CAsyncReaderImpl_InitIAsyncReader(
1090                         &This->async,
1091                         This->unk.punkControl,
1092                         pFilter );
1093                 if ( FAILED(hr) )
1094                 {
1095                         CPinBaseImpl_UninitIPin( &This->pin );
1096                 }
1097         }
1098
1099         if ( FAILED(hr) )
1100         {
1101                 QUARTZ_FreeObj(This);
1102                 return hr;
1103         }
1104
1105         This->unk.pEntries = OutPinIFEntries;
1106         This->unk.dwEntries = sizeof(OutPinIFEntries)/sizeof(OutPinIFEntries[0]);
1107         This->unk.pOnFinalRelease = QUARTZ_DestroyAsyncSourcePin;
1108
1109         *ppPin = This;
1110
1111         TRACE("returned successfully.\n");
1112
1113         return S_OK;
1114 }
1115
1116
1117
1118 /***************************************************************************
1119  *
1120  *      Implements File Source.
1121  *
1122  */
1123
1124 typedef struct AsyncSourceFileImpl
1125 {
1126         HANDLE  hFile;
1127         LONGLONG        llTotal;
1128 } AsyncSourceFileImpl;
1129
1130
1131 static HRESULT AsyncSourceFileImpl_Load( CAsyncSourceImpl* pImpl, LPCWSTR lpwszSourceName )
1132 {
1133         AsyncSourceFileImpl*    This = (AsyncSourceFileImpl*)pImpl->m_pUserData;
1134         DWORD   dwLow;
1135         DWORD   dwHigh;
1136
1137         if ( This != NULL )
1138                 return E_UNEXPECTED;
1139         This = (AsyncSourceFileImpl*)QUARTZ_AllocMem( sizeof(AsyncSourceFileImpl) );
1140         pImpl->m_pUserData = (void*)This;
1141         if ( This == NULL )
1142                 return E_OUTOFMEMORY;
1143         This->hFile = INVALID_HANDLE_VALUE;
1144         This->llTotal = 0;
1145
1146         This->hFile = CreateFileW( lpwszSourceName,
1147                 GENERIC_READ, FILE_SHARE_READ,
1148                 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL );
1149         if ( This->hFile == INVALID_HANDLE_VALUE )
1150                 return E_FAIL;
1151
1152         SetLastError(NO_ERROR);
1153         dwLow = GetFileSize( This->hFile, &dwHigh );
1154         if ( dwLow == 0xffffffff && GetLastError() != NO_ERROR )
1155                 return E_FAIL;
1156
1157         This->llTotal = (LONGLONG)dwLow | ((LONGLONG)dwHigh << 32);
1158
1159         return NOERROR;
1160 }
1161
1162 static HRESULT AsyncSourceFileImpl_Cleanup( CAsyncSourceImpl* pImpl )
1163 {
1164         AsyncSourceFileImpl*    This = (AsyncSourceFileImpl*)pImpl->m_pUserData;
1165
1166         if ( This == NULL )
1167                 return NOERROR;
1168
1169         if ( This->hFile != INVALID_HANDLE_VALUE )
1170                 CloseHandle(This->hFile);
1171
1172         QUARTZ_FreeMem(This);
1173         pImpl->m_pUserData = NULL;
1174
1175         return NOERROR;
1176 }
1177
1178 static HRESULT AsyncSourceFileImpl_GetLength( CAsyncSourceImpl* pImpl, LONGLONG* pllTotal, LONGLONG* pllAvailable )
1179 {
1180         AsyncSourceFileImpl*    This = (AsyncSourceFileImpl*)pImpl->m_pUserData;
1181
1182         if ( This == NULL )
1183                 return E_UNEXPECTED;
1184
1185         *pllTotal = This->llTotal;
1186         *pllAvailable = This->llTotal;
1187
1188         return NOERROR;
1189 }
1190
1191 static HRESULT AsyncSourceFileImpl_Read( CAsyncSourceImpl* pImpl, LONGLONG llOfsStart, LONG lLength, BYTE* pBuf, LONG* plReturned, HANDLE hEventCancel )
1192 {
1193         AsyncSourceFileImpl*    This = (AsyncSourceFileImpl*)pImpl->m_pUserData;
1194         LONG    lReturned;
1195         LONG    lBlock;
1196         LONG    lOfsLow;
1197         LONG    lOfsHigh;
1198         DWORD   dw;
1199         HRESULT hr = S_OK;
1200
1201         if ( This == NULL || This->hFile == INVALID_HANDLE_VALUE )
1202                 return E_UNEXPECTED;
1203
1204         lReturned = 0;
1205
1206         lOfsLow = (LONG)(llOfsStart & 0xffffffff);
1207         lOfsHigh = (LONG)(llOfsStart >> 32);
1208         SetLastError(NO_ERROR);
1209         lOfsLow = SetFilePointer( This->hFile, lOfsLow, &lOfsHigh, FILE_BEGIN );
1210         if ( lOfsLow == (LONG)0xffffffff && GetLastError() != NO_ERROR )
1211                 return E_FAIL;
1212
1213         while ( lLength > 0 )
1214         {
1215                 if ( WaitForSingleObject( hEventCancel, 0 ) == WAIT_OBJECT_0 )
1216                 {
1217                         hr = S_FALSE;
1218                         break;
1219                 }
1220
1221                 lBlock = ( lLength > ASYNCSRC_FILE_BLOCKSIZE ) ?
1222                         ASYNCSRC_FILE_BLOCKSIZE : lLength;
1223
1224                 if ( !ReadFile(This->hFile,pBuf,(DWORD)lBlock,&dw,NULL) )
1225                 {
1226                         hr = E_FAIL;
1227                         break;
1228                 }
1229                 pBuf += dw;
1230                 lReturned += (LONG)dw;
1231                 lLength -= (LONG)dw;
1232                 if ( lBlock > (LONG)dw )
1233                         break;
1234         }
1235
1236         *plReturned = lReturned;
1237
1238         return hr;
1239 }
1240
1241 static const struct AsyncSourceHandlers asyncsrc_file =
1242 {
1243         AsyncSourceFileImpl_Load,
1244         AsyncSourceFileImpl_Cleanup,
1245         AsyncSourceFileImpl_GetLength,
1246         AsyncSourceFileImpl_Read,
1247 };
1248
1249 HRESULT QUARTZ_CreateAsyncReader(IUnknown* punkOuter,void** ppobj)
1250 {
1251         return QUARTZ_CreateAsyncSource(
1252                 punkOuter, ppobj,
1253                 &CLSID_AsyncReader,
1254                 QUARTZ_wszAsyncFileSourceName,
1255                 QUARTZ_wszAsyncFileSourcePinName,
1256                 &asyncsrc_file );
1257 }
1258
1259 /***************************************************************************
1260  *
1261  *      Implements URL Source.
1262  *
1263  */
1264
1265 typedef struct AsyncSourceURLImpl
1266 {
1267         DWORD dwDummy;
1268 } AsyncSourceURLImpl;
1269
1270
1271 static HRESULT AsyncSourceURLImpl_Load( CAsyncSourceImpl* pImpl, LPCWSTR lpwszSourceName )
1272 {
1273         AsyncSourceURLImpl*     This = (AsyncSourceURLImpl*)pImpl->m_pUserData;
1274
1275         FIXME("(%p,%p) stub!\n", pImpl, lpwszSourceName);
1276
1277         if ( This != NULL )
1278                 return E_UNEXPECTED;
1279         This = (AsyncSourceURLImpl*)QUARTZ_AllocMem( sizeof(AsyncSourceURLImpl) );
1280         pImpl->m_pUserData = (void*)This;
1281         if ( This == NULL )
1282                 return E_OUTOFMEMORY;
1283
1284         return E_NOTIMPL;
1285 }
1286
1287 static HRESULT AsyncSourceURLImpl_Cleanup( CAsyncSourceImpl* pImpl )
1288 {
1289         AsyncSourceURLImpl*     This = (AsyncSourceURLImpl*)pImpl->m_pUserData;
1290
1291         FIXME("(%p) stub!\n", This);
1292
1293         if ( This == NULL )
1294                 return NOERROR;
1295
1296         QUARTZ_FreeMem(This);
1297         pImpl->m_pUserData = NULL;
1298
1299         return NOERROR;
1300 }
1301
1302 static HRESULT AsyncSourceURLImpl_GetLength( CAsyncSourceImpl* pImpl, LONGLONG* pllTotal, LONGLONG* pllAvailable )
1303 {
1304         AsyncSourceURLImpl*     This = (AsyncSourceURLImpl*)pImpl->m_pUserData;
1305
1306         FIXME("(%p,%p,%p) stub!\n", This, pllTotal, pllAvailable);
1307
1308         if ( This == NULL )
1309                 return E_UNEXPECTED;
1310
1311         return E_NOTIMPL;
1312 }
1313
1314 static HRESULT AsyncSourceURLImpl_Read( CAsyncSourceImpl* pImpl, LONGLONG llOfsStart, LONG lLength, BYTE* pBuf, LONG* plReturned, HANDLE hEventCancel )
1315 {
1316         AsyncSourceURLImpl*     This = (AsyncSourceURLImpl*)pImpl->m_pUserData;
1317
1318         FIXME("(%p) stub!\n", This);
1319
1320         if ( This == NULL )
1321                 return E_UNEXPECTED;
1322
1323         return E_NOTIMPL;
1324 }
1325
1326 static const struct AsyncSourceHandlers asyncsrc_url =
1327 {
1328         AsyncSourceURLImpl_Load,
1329         AsyncSourceURLImpl_Cleanup,
1330         AsyncSourceURLImpl_GetLength,
1331         AsyncSourceURLImpl_Read,
1332 };
1333
1334
1335 HRESULT QUARTZ_CreateURLReader(IUnknown* punkOuter,void** ppobj)
1336 {
1337         return QUARTZ_CreateAsyncSource(
1338                 punkOuter, ppobj,
1339                 &CLSID_URLReader,
1340                 QUARTZ_wszAsyncURLSourceName,
1341                 QUARTZ_wszAsyncURLSourcePinName,
1342                 &asyncsrc_url );
1343 }