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