Don't return from overlapped ReadFile on EAGAIN and other non-fatal
[wine/gsoc_dplay.git] / dlls / quartz / asyncsrc.c
blobc72b2455e7d754fc7b5a667e1b585f6485b04dd6
1 /*
2 * Implements Asynchronous File/URL Source.
4 * FIXME - URL source is not implemented yet.
6 * hidenori@a2.ctktv.ne.jp
7 */
9 #include "config.h"
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"
20 #include "debugtools.h"
21 DEFAULT_DEBUG_CHANNEL(quartz);
23 #include "quartz_private.h"
24 #include "asyncsrc.h"
25 #include "memalloc.h"
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};
40 /***************************************************************************
42 * CAsyncReaderImpl internal methods
46 static
47 AsyncSourceRequest* CAsyncReaderImpl_AllocRequest( CAsyncReaderImpl* This )
49 AsyncSourceRequest* pReq;
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 );
57 if ( pReq == NULL )
59 pReq = (AsyncSourceRequest*)QUARTZ_AllocMem(
60 sizeof(AsyncSourceRequest) );
61 if ( pReq == NULL )
62 return NULL;
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;
73 return pReq;
76 static
77 void CAsyncReaderImpl_FreeRequest( CAsyncReaderImpl* This, AsyncSourceRequest* pReq, BOOL bReleaseMem )
79 if ( !bReleaseMem )
81 EnterCriticalSection( &This->m_csFree );
82 pReq->pNext = This->m_pFreeFirst;
83 This->m_pFreeFirst = pReq;
84 LeaveCriticalSection( &This->m_csFree );
86 else
88 QUARTZ_FreeMem( pReq );
92 static
93 AsyncSourceRequest* CAsyncReaderImpl_GetRequest( CAsyncReaderImpl* This )
95 AsyncSourceRequest* pReq;
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 );
103 return pReq;
106 static
107 AsyncSourceRequest* CAsyncReaderImpl_GetReply( CAsyncReaderImpl* This )
109 AsyncSourceRequest* pReq;
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 );
117 return pReq;
120 static
121 void CAsyncReaderImpl_PostRequest( CAsyncReaderImpl* This, AsyncSourceRequest* pReq )
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 );
132 static
133 void CAsyncReaderImpl_PostReply( CAsyncReaderImpl* This, AsyncSourceRequest* pReq )
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 );
144 static
145 void CAsyncReaderImpl_ReleaseReqList( CAsyncReaderImpl* This, AsyncSourceRequest** ppReq, BOOL bReleaseMem )
147 AsyncSourceRequest* pReq;
148 AsyncSourceRequest* pReqNext;
150 TRACE("(%p,%p,%d)\n",This,*ppReq,bReleaseMem);
151 pReq = *ppReq; *ppReq = NULL;
152 while ( pReq != NULL )
154 pReqNext = pReq->pNext;
155 CAsyncReaderImpl_FreeRequest(This,pReq,bReleaseMem);
156 pReq = pReqNext;
160 static DWORD WINAPI
161 CAsyncReaderImpl_ThreadEntry( LPVOID pv )
163 CAsyncReaderImpl* This = (CAsyncReaderImpl*)pv;
164 HANDLE hWaitEvents[2];
165 HRESULT hr;
166 DWORD dwRes;
167 AsyncSourceRequest* pReq = NULL;
169 SetEvent( This->m_hEventInit );
171 hWaitEvents[0] = This->m_hEventReqQueued;
172 hWaitEvents[1] = This->m_hEventCancel;
174 TRACE("enter message loop.\n");
176 while ( 1 )
178 ResetEvent( This->m_hEventReqQueued );
179 pReq = CAsyncReaderImpl_GetRequest(This);
180 if ( pReq == NULL )
182 dwRes = WaitForMultipleObjects(2,hWaitEvents,FALSE,INFINITE);
183 if ( dwRes != WAIT_OBJECT_0 )
185 if ( This->m_bAbortThread )
186 break;
188 continue;
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 );
196 if ( FAILED(hr) )
198 /* Notify(ABORT) */
199 break;
201 if ( hr != S_OK )
203 if ( This->m_bAbortThread )
204 break;
205 ResetEvent( This->m_hEventCancel );
208 CAsyncReaderImpl_PostReply( This, pReq );
209 SetEvent( This->m_hEventSampQueued );
210 pReq = NULL;
213 if ( pReq != NULL )
214 CAsyncReaderImpl_PostRequest( This, pReq );
216 SetEvent( This->m_hEventSampQueued );
217 return 0;
220 static HRESULT
221 CAsyncReaderImpl_BeginThread( CAsyncReaderImpl* This )
223 DWORD dwRes;
224 DWORD dwThreadId;
225 HANDLE hEvents[2];
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;
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;
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;
257 hEvents[0] = This->m_hEventInit;
258 hEvents[1] = This->m_hThread;
260 dwRes = WaitForMultipleObjects(2,hEvents,FALSE,INFINITE);
261 if ( dwRes != WAIT_OBJECT_0 )
262 return E_FAIL;
264 return NOERROR;
267 static void
268 CAsyncReaderImpl_EndThread( CAsyncReaderImpl* This )
270 if ( This->m_hThread != (HANDLE)NULL )
272 while ( 1 )
274 This->m_bAbortThread = TRUE;
275 SetEvent( This->m_hEventCancel );
276 if ( WaitForSingleObject( This->m_hThread, 100 ) == WAIT_OBJECT_0 )
277 break;
279 CloseHandle( This->m_hThread );
280 This->m_hThread = (HANDLE)NULL;
282 if ( This->m_hEventInit != (HANDLE)NULL )
284 CloseHandle( This->m_hEventInit );
285 This->m_hEventInit = (HANDLE)NULL;
287 if ( This->m_hEventCancel != (HANDLE)NULL )
289 CloseHandle( This->m_hEventCancel );
290 This->m_hEventCancel = (HANDLE)NULL;
292 if ( This->m_hEventReqQueued != (HANDLE)NULL )
294 CloseHandle( This->m_hEventReqQueued );
295 This->m_hEventReqQueued = (HANDLE)NULL;
297 if ( This->m_hEventSampQueued != (HANDLE)NULL )
299 CloseHandle( This->m_hEventSampQueued );
300 This->m_hEventSampQueued = (HANDLE)NULL;
304 /***************************************************************************
306 * CAsyncReaderImpl methods
310 static HRESULT WINAPI
311 CAsyncReaderImpl_fnQueryInterface(IAsyncReader* iface,REFIID riid,void** ppobj)
313 ICOM_THIS(CAsyncReaderImpl,iface);
315 TRACE("(%p)->()\n",This);
317 return IUnknown_QueryInterface(This->punkControl,riid,ppobj);
320 static ULONG WINAPI
321 CAsyncReaderImpl_fnAddRef(IAsyncReader* iface)
323 ICOM_THIS(CAsyncReaderImpl,iface);
325 TRACE("(%p)->()\n",This);
327 return IUnknown_AddRef(This->punkControl);
330 static ULONG WINAPI
331 CAsyncReaderImpl_fnRelease(IAsyncReader* iface)
333 ICOM_THIS(CAsyncReaderImpl,iface);
335 TRACE("(%p)->()\n",This);
337 return IUnknown_Release(This->punkControl);
340 static HRESULT WINAPI
341 CAsyncReaderImpl_fnRequestAllocator(IAsyncReader* iface,IMemAllocator* pAlloc,ALLOCATOR_PROPERTIES* pProp,IMemAllocator** ppAllocActual)
343 ICOM_THIS(CAsyncReaderImpl,iface);
344 HRESULT hr;
345 ALLOCATOR_PROPERTIES propActual;
346 IUnknown* punk = NULL;
348 TRACE("(%p)->(%p,%p,%p)\n",This,pAlloc,pProp,ppAllocActual);
350 if ( pAlloc == NULL || pProp == NULL || ppAllocActual == NULL )
351 return E_POINTER;
353 IMemAllocator_AddRef(pAlloc);
354 hr = IMemAllocator_SetProperties( pAlloc, pProp, &propActual );
355 if ( SUCCEEDED(hr) )
357 *ppAllocActual = pAlloc;
358 return S_OK;
360 IMemAllocator_Release(pAlloc);
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;
370 hr = IMemAllocator_SetProperties( pAlloc, pProp, &propActual );
371 if ( SUCCEEDED(hr) )
373 *ppAllocActual = pAlloc;
374 return S_OK;
376 IMemAllocator_Release(pAlloc);
378 return hr;
381 static HRESULT WINAPI
382 CAsyncReaderImpl_fnRequest(IAsyncReader* iface,IMediaSample* pSample,DWORD_PTR dwContext)
384 ICOM_THIS(CAsyncReaderImpl,iface);
385 HRESULT hr = NOERROR;
386 REFERENCE_TIME rtStart;
387 REFERENCE_TIME rtEnd;
388 AsyncSourceRequest* pReq;
389 BYTE* pData = NULL;
391 TRACE("(%p)->(%p,%u)\n",This,pSample,dwContext);
393 hr = IMediaSample_GetPointer(pSample,&pData);
394 if ( SUCCEEDED(hr) )
395 hr = IMediaSample_GetTime(pSample,&rtStart,&rtEnd);
396 if ( FAILED(hr) )
397 return hr;
399 pReq = CAsyncReaderImpl_AllocRequest(This);
400 if ( pReq == NULL )
401 return E_OUTOFMEMORY;
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 );
411 return NOERROR;
414 static HRESULT WINAPI
415 CAsyncReaderImpl_fnWaitForNext(IAsyncReader* iface,DWORD dwTimeout,IMediaSample** ppSample,DWORD_PTR* pdwContext)
417 ICOM_THIS(CAsyncReaderImpl,iface);
418 HRESULT hr = NOERROR;
419 DWORD dwRes;
420 AsyncSourceRequest* pReq;
421 REFERENCE_TIME rtStart;
422 REFERENCE_TIME rtEnd;
424 TRACE("(%p)->(%lu,%p,%p)\n",This,dwTimeout,ppSample,pdwContext);
426 EnterCriticalSection( &This->m_csRequest );
427 if ( This->m_bInFlushing )
428 hr = VFW_E_TIMEOUT;
429 LeaveCriticalSection( &This->m_csRequest );
431 if ( hr == NOERROR )
433 ResetEvent( This->m_hEventSampQueued );
434 pReq = CAsyncReaderImpl_GetReply(This);
435 if ( pReq == NULL )
437 dwRes = WaitForSingleObject( This->m_hEventSampQueued, dwTimeout );
438 if ( dwRes == WAIT_OBJECT_0 )
439 pReq = CAsyncReaderImpl_GetReply(This);
441 if ( pReq != NULL )
443 hr = IMediaSample_SetActualDataLength(pReq->pSample,pReq->lActual);
444 if ( hr == S_OK )
446 rtStart = pReq->llStart * QUARTZ_TIMEUNITS;
447 rtEnd = (pReq->llStart + pReq->lActual) * QUARTZ_TIMEUNITS;
448 hr = IMediaSample_SetTime(pReq->pSample,&rtStart,&rtEnd);
450 *ppSample = pReq->pSample;
451 *pdwContext = pReq->dwContext;
452 if ( hr == S_OK && pReq->lActual != pReq->lLength )
453 hr = S_FALSE;
455 else
457 hr = VFW_E_TIMEOUT;
461 return hr;
464 static HRESULT WINAPI
465 CAsyncReaderImpl_fnSyncReadAligned(IAsyncReader* iface,IMediaSample* pSample)
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;
476 TRACE("(%p)->(%p)\n",This,pSample);
478 hr = IMediaSample_GetPointer(pSample,&pData);
479 if ( SUCCEEDED(hr) )
480 hr = IMediaSample_GetTime(pSample,&rtStart,&rtEnd);
481 if ( FAILED(hr) )
482 return hr;
484 llStart = rtStart / QUARTZ_TIMEUNITS;
485 lLength = (LONG)(rtEnd / QUARTZ_TIMEUNITS - rtStart / QUARTZ_TIMEUNITS);
486 lActual = 0;
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 );
492 if ( hr == NOERROR )
494 hr = IMediaSample_SetActualDataLength(pSample,lActual);
495 if ( hr == S_OK )
497 rtStart = llStart * QUARTZ_TIMEUNITS;
498 rtEnd = (llStart + lActual) * QUARTZ_TIMEUNITS;
499 hr = IMediaSample_SetTime(pSample,&rtStart,&rtEnd);
501 if ( hr == S_OK && lActual != lLength )
502 hr = S_FALSE;
505 return hr;
508 static HRESULT WINAPI
509 CAsyncReaderImpl_fnSyncRead(IAsyncReader* iface,LONGLONG llPosStart,LONG lLength,BYTE* pbBuf)
511 ICOM_THIS(CAsyncReaderImpl,iface);
512 HRESULT hr;
513 LONG lActual;
515 TRACE("(%p)->()\n",This);
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 );
521 if ( hr == S_OK && lLength != lActual )
522 hr = S_FALSE;
524 return hr;
527 static HRESULT WINAPI
528 CAsyncReaderImpl_fnLength(IAsyncReader* iface,LONGLONG* pllTotal,LONGLONG* pllAvailable)
530 ICOM_THIS(CAsyncReaderImpl,iface);
531 HRESULT hr;
533 TRACE("(%p)->()\n",This);
535 hr = This->pSource->m_pHandler->pGetLength( This->pSource, pllTotal, pllAvailable );
537 return hr;
540 static HRESULT WINAPI
541 CAsyncReaderImpl_fnBeginFlush(IAsyncReader* iface)
543 ICOM_THIS(CAsyncReaderImpl,iface);
545 TRACE("(%p)->()\n",This);
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 );
553 return NOERROR;
556 static HRESULT WINAPI
557 CAsyncReaderImpl_fnEndFlush(IAsyncReader* iface)
559 ICOM_THIS(CAsyncReaderImpl,iface);
561 TRACE("(%p)->()\n",This);
563 EnterCriticalSection( &This->m_csRequest );
564 This->m_bInFlushing = FALSE;
565 ResetEvent( This->m_hEventCancel );
566 LeaveCriticalSection( &This->m_csRequest );
568 return NOERROR;
572 static ICOM_VTABLE(IAsyncReader) iasyncreader =
574 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
575 /* IUnknown fields */
576 CAsyncReaderImpl_fnQueryInterface,
577 CAsyncReaderImpl_fnAddRef,
578 CAsyncReaderImpl_fnRelease,
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,
591 HRESULT CAsyncReaderImpl_InitIAsyncReader(
592 CAsyncReaderImpl* This, IUnknown* punkControl,
593 CAsyncSourceImpl* pSource )
595 TRACE("(%p,%p)\n",This,punkControl);
597 if ( punkControl == NULL )
599 ERR( "punkControl must not be NULL\n" );
600 return E_INVALIDARG;
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;
617 InitializeCriticalSection( &This->m_csReader );
618 InitializeCriticalSection( &This->m_csRequest );
619 InitializeCriticalSection( &This->m_csReply );
620 InitializeCriticalSection( &This->m_csFree );
622 return NOERROR;
625 void CAsyncReaderImpl_UninitIAsyncReader(
626 CAsyncReaderImpl* This )
628 TRACE("(%p) enter\n",This);
630 CAsyncReaderImpl_ReleaseReqList(This,&This->m_pRequestFirst,TRUE);
631 CAsyncReaderImpl_ReleaseReqList(This,&This->m_pReplyFirst,TRUE);
632 CAsyncReaderImpl_ReleaseReqList(This,&This->m_pFreeFirst,TRUE);
634 DeleteCriticalSection( &This->m_csReader );
635 DeleteCriticalSection( &This->m_csRequest );
636 DeleteCriticalSection( &This->m_csReply );
637 DeleteCriticalSection( &This->m_csFree );
639 TRACE("(%p) leave\n",This);
642 /***************************************************************************
644 * CFileSourceFilterImpl
648 static HRESULT WINAPI
649 CFileSourceFilterImpl_fnQueryInterface(IFileSourceFilter* iface,REFIID riid,void** ppobj)
651 ICOM_THIS(CFileSourceFilterImpl,iface);
653 TRACE("(%p)->()\n",This);
655 return IUnknown_QueryInterface(This->punkControl,riid,ppobj);
658 static ULONG WINAPI
659 CFileSourceFilterImpl_fnAddRef(IFileSourceFilter* iface)
661 ICOM_THIS(CFileSourceFilterImpl,iface);
663 TRACE("(%p)->()\n",This);
665 return IUnknown_AddRef(This->punkControl);
668 static ULONG WINAPI
669 CFileSourceFilterImpl_fnRelease(IFileSourceFilter* iface)
671 ICOM_THIS(CFileSourceFilterImpl,iface);
673 TRACE("(%p)->()\n",This);
675 return IUnknown_Release(This->punkControl);
678 static HRESULT WINAPI
679 CFileSourceFilterImpl_fnLoad(IFileSourceFilter* iface,LPCOLESTR pFileName,const AM_MEDIA_TYPE* pmt)
681 ICOM_THIS(CFileSourceFilterImpl,iface);
682 HRESULT hr;
684 TRACE("(%p)->(%s,%p)\n",This,debugstr_w(pFileName),pmt);
686 if ( pFileName == NULL )
687 return E_POINTER;
689 if ( This->m_pwszFileName != NULL )
690 return E_UNEXPECTED;
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 );
698 if ( pmt != NULL )
700 hr = QUARTZ_MediaType_Copy( &This->m_mt, pmt );
701 if ( FAILED(hr) )
702 goto err;
704 else
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) );
713 hr = This->pSource->m_pHandler->pLoad( This->pSource, pFileName );
714 if ( FAILED(hr) )
715 goto err;
717 This->pSource->pPin->pin.pmtAcceptTypes = &This->m_mt;
718 This->pSource->pPin->pin.cAcceptTypes = 1;
720 return NOERROR;
721 err:;
722 return hr;
725 static HRESULT WINAPI
726 CFileSourceFilterImpl_fnGetCurFile(IFileSourceFilter* iface,LPOLESTR* ppFileName,AM_MEDIA_TYPE* pmt)
728 ICOM_THIS(CFileSourceFilterImpl,iface);
729 HRESULT hr = E_NOTIMPL;
731 TRACE("(%p)->(%p,%p)\n",This,ppFileName,pmt);
733 if ( ppFileName == NULL || pmt == NULL )
734 return E_POINTER;
736 if ( This->m_pwszFileName == NULL )
737 return E_FAIL;
739 hr = QUARTZ_MediaType_Copy( pmt, &This->m_mt );
740 if ( FAILED(hr) )
741 return hr;
743 *ppFileName = (WCHAR*)CoTaskMemAlloc( This->m_cbFileName );
744 if ( *ppFileName == NULL )
746 QUARTZ_MediaType_Free(pmt);
747 ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
748 return E_OUTOFMEMORY;
751 memcpy( *ppFileName, This->m_pwszFileName, This->m_cbFileName );
753 return NOERROR;
756 static ICOM_VTABLE(IFileSourceFilter) ifilesource =
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,
768 HRESULT CFileSourceFilterImpl_InitIFileSourceFilter(
769 CFileSourceFilterImpl* This, IUnknown* punkControl,
770 CAsyncSourceImpl* pSource,
771 CRITICAL_SECTION* pcsFileSource )
773 TRACE("(%p,%p)\n",This,punkControl);
775 if ( punkControl == NULL )
777 ERR( "punkControl must not be NULL\n" );
778 return E_INVALIDARG;
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) );
789 return NOERROR;
792 void CFileSourceFilterImpl_UninitIFileSourceFilter(
793 CFileSourceFilterImpl* This )
795 TRACE("(%p)\n",This);
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 );
803 /***************************************************************************
805 * CAsyncSourcePinImpl methods
810 static HRESULT CAsyncSourcePinImpl_OnPreConnect( CPinBaseImpl* pImpl, IPin* pPin )
812 CAsyncSourcePinImpl_THIS(pImpl,pin);
814 TRACE("(%p,%p)\n",This,pPin);
816 This->bAsyncReaderQueried = FALSE;
818 return NOERROR;
821 static HRESULT CAsyncSourcePinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin )
823 CAsyncSourcePinImpl_THIS(pImpl,pin);
825 TRACE("(%p,%p)\n",This,pPin);
827 if ( !This->bAsyncReaderQueried )
828 return E_FAIL;
830 return NOERROR;
833 static HRESULT CAsyncSourcePinImpl_OnDisconnect( CPinBaseImpl* pImpl )
835 CAsyncSourcePinImpl_THIS(pImpl,pin);
837 TRACE("(%p)\n",This);
839 This->bAsyncReaderQueried = FALSE;
841 return NOERROR;
844 static HRESULT CAsyncSourcePinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
846 CAsyncSourcePinImpl_THIS(pImpl,pin);
848 TRACE("(%p,%p)\n",This,pmt);
849 if ( pmt == NULL )
850 return E_POINTER;
852 if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Stream ) )
853 return E_FAIL;
855 return NOERROR;
858 static const CBasePinHandlers outputpinhandlers =
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 */
873 /***************************************************************************
875 * CAsyncSourceImpl methods
879 static HRESULT CAsyncSourceImpl_OnActive( CBaseFilterImpl* pImpl )
881 CAsyncSourceImpl_THIS(pImpl,basefilter);
882 HRESULT hr;
884 TRACE( "(%p)\n", This );
886 hr = CAsyncReaderImpl_BeginThread(&This->pPin->async);
887 if ( FAILED(hr) )
888 return hr;
890 return NOERROR;
893 static HRESULT CAsyncSourceImpl_OnInactive( CBaseFilterImpl* pImpl )
895 CAsyncSourceImpl_THIS(pImpl,basefilter);
897 TRACE( "(%p)\n", This );
899 CAsyncReaderImpl_EndThread(&This->pPin->async);
901 return NOERROR;
904 static const CBaseFilterHandlers filterhandlers =
906 CAsyncSourceImpl_OnActive, /* pOnActive */
907 CAsyncSourceImpl_OnInactive, /* pOnInactive */
908 NULL, /* pOnStop */
911 /***************************************************************************
913 * new/delete CAsyncSourceImpl
917 /* can I use offsetof safely? - FIXME? */
918 static QUARTZ_IFEntry FilterIFEntries[] =
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) },
926 static void QUARTZ_DestroyAsyncSource(IUnknown* punk)
928 CAsyncSourceImpl_THIS(punk,unk);
930 TRACE( "(%p)\n", This );
932 if ( This->pPin != NULL )
934 IUnknown_Release(This->pPin->unk.punkControl);
935 This->pPin = NULL;
938 This->m_pHandler->pCleanup( This );
940 CFileSourceFilterImpl_UninitIFileSourceFilter(&This->filesrc);
941 CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
943 DeleteCriticalSection( &This->csFilter );
946 HRESULT QUARTZ_CreateAsyncSource(
947 IUnknown* punkOuter,void** ppobj,
948 const CLSID* pclsidAsyncSource,
949 LPCWSTR pwszAsyncSourceName,
950 LPCWSTR pwszOutPinName,
951 const AsyncSourceHandlers* pHandler )
953 CAsyncSourceImpl* This = NULL;
954 HRESULT hr;
956 TRACE("(%p,%p)\n",punkOuter,ppobj);
958 This = (CAsyncSourceImpl*)
959 QUARTZ_AllocObj( sizeof(CAsyncSourceImpl) );
960 if ( This == NULL )
961 return E_OUTOFMEMORY;
963 This->pPin = NULL;
964 This->m_pHandler = pHandler;
965 This->m_pUserData = NULL;
967 QUARTZ_IUnkInit( &This->unk, punkOuter );
969 hr = CBaseFilterImpl_InitIBaseFilter(
970 &This->basefilter,
971 This->unk.punkControl,
972 pclsidAsyncSource,
973 pwszAsyncSourceName,
974 &filterhandlers );
975 if ( SUCCEEDED(hr) )
977 /* construct this class. */
978 hr = CFileSourceFilterImpl_InitIFileSourceFilter(
979 &This->filesrc, This->unk.punkControl,
980 This, &This->csFilter );
981 if ( FAILED(hr) )
983 CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
987 if ( FAILED(hr) )
989 QUARTZ_FreeObj(This);
990 return hr;
993 This->unk.pEntries = FilterIFEntries;
994 This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]);
995 This->unk.pOnFinalRelease = QUARTZ_DestroyAsyncSource;
996 InitializeCriticalSection( &This->csFilter );
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 );
1008 if ( FAILED(hr) )
1010 IUnknown_Release( This->unk.punkControl );
1011 return hr;
1014 *ppobj = (void*)&(This->unk);
1016 return S_OK;
1019 /***************************************************************************
1021 * new/delete CAsyncSourcePinImpl
1025 /* can I use offsetof safely? - FIXME? */
1026 static QUARTZ_IFEntry OutPinIFEntries[] =
1028 { &IID_IPin, offsetof(CAsyncSourcePinImpl,pin)-offsetof(CAsyncSourcePinImpl,unk) },
1029 /***{ &IID_IAsyncReader, offsetof(CAsyncSourcePinImpl,async)-offsetof(CAsyncSourcePinImpl,unk) },***/
1032 static HRESULT CAsyncSourceImpl_OnQueryInterface(
1033 IUnknown* punk, const IID* piid, void** ppobj )
1035 CAsyncSourcePinImpl_THIS(punk,unk);
1037 if ( IsEqualGUID( &IID_IAsyncReader, piid ) )
1039 TRACE("IAsyncReader has been queried.\n");
1040 *ppobj = (void*)&This->async;
1041 IUnknown_AddRef(punk);
1042 This->bAsyncReaderQueried = TRUE;
1043 return S_OK;
1046 return E_NOINTERFACE;
1049 static void QUARTZ_DestroyAsyncSourcePin(IUnknown* punk)
1051 CAsyncSourcePinImpl_THIS(punk,unk);
1053 TRACE( "(%p)\n", This );
1055 CAsyncReaderImpl_UninitIAsyncReader( &This->async );
1056 CPinBaseImpl_UninitIPin( &This->pin );
1059 HRESULT QUARTZ_CreateAsyncSourcePin(
1060 CAsyncSourceImpl* pFilter,
1061 CRITICAL_SECTION* pcsPin,
1062 CAsyncSourcePinImpl** ppPin,
1063 LPCWSTR pwszPinName )
1065 CAsyncSourcePinImpl* This = NULL;
1066 HRESULT hr;
1068 TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
1070 This = (CAsyncSourcePinImpl*)
1071 QUARTZ_AllocObj( sizeof(CAsyncSourcePinImpl) );
1072 if ( This == NULL )
1073 return E_OUTOFMEMORY;
1075 QUARTZ_IUnkInit( &This->unk, NULL );
1076 This->qiext.pNext = NULL;
1077 This->qiext.pOnQueryInterface = &CAsyncSourceImpl_OnQueryInterface;
1078 QUARTZ_IUnkAddDelegation( &This->unk, &This->qiext );
1080 This->bAsyncReaderQueried = FALSE;
1081 This->pSource = pFilter;
1083 hr = CPinBaseImpl_InitIPin(
1084 &This->pin,
1085 This->unk.punkControl,
1086 pcsPin,
1087 &pFilter->basefilter,
1088 pwszPinName,
1089 TRUE,
1090 &outputpinhandlers );
1092 if ( SUCCEEDED(hr) )
1094 hr = CAsyncReaderImpl_InitIAsyncReader(
1095 &This->async,
1096 This->unk.punkControl,
1097 pFilter );
1098 if ( FAILED(hr) )
1100 CPinBaseImpl_UninitIPin( &This->pin );
1104 if ( FAILED(hr) )
1106 QUARTZ_FreeObj(This);
1107 return hr;
1110 This->unk.pEntries = OutPinIFEntries;
1111 This->unk.dwEntries = sizeof(OutPinIFEntries)/sizeof(OutPinIFEntries[0]);
1112 This->unk.pOnFinalRelease = QUARTZ_DestroyAsyncSourcePin;
1114 *ppPin = This;
1116 TRACE("returned successfully.\n");
1118 return S_OK;
1123 /***************************************************************************
1125 * Implements File Source.
1129 typedef struct AsyncSourceFileImpl
1131 HANDLE hFile;
1132 LONGLONG llTotal;
1133 } AsyncSourceFileImpl;
1136 static HRESULT AsyncSourceFileImpl_Load( CAsyncSourceImpl* pImpl, LPCWSTR lpwszSourceName )
1138 AsyncSourceFileImpl* This = (AsyncSourceFileImpl*)pImpl->m_pUserData;
1139 DWORD dwLow;
1140 DWORD dwHigh;
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;
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;
1157 SetLastError(NO_ERROR);
1158 dwLow = GetFileSize( This->hFile, &dwHigh );
1159 if ( dwLow == 0xffffffff && GetLastError() != NO_ERROR )
1160 return E_FAIL;
1162 This->llTotal = (LONGLONG)dwLow | ((LONGLONG)dwHigh << 32);
1164 return NOERROR;
1167 static HRESULT AsyncSourceFileImpl_Cleanup( CAsyncSourceImpl* pImpl )
1169 AsyncSourceFileImpl* This = (AsyncSourceFileImpl*)pImpl->m_pUserData;
1171 if ( This == NULL )
1172 return NOERROR;
1174 if ( This->hFile != INVALID_HANDLE_VALUE )
1175 CloseHandle(This->hFile);
1177 QUARTZ_FreeMem(This);
1178 pImpl->m_pUserData = NULL;
1180 return NOERROR;
1183 static HRESULT AsyncSourceFileImpl_GetLength( CAsyncSourceImpl* pImpl, LONGLONG* pllTotal, LONGLONG* pllAvailable )
1185 AsyncSourceFileImpl* This = (AsyncSourceFileImpl*)pImpl->m_pUserData;
1187 if ( This == NULL )
1188 return E_UNEXPECTED;
1190 *pllTotal = This->llTotal;
1191 *pllAvailable = This->llTotal;
1193 return NOERROR;
1196 static HRESULT AsyncSourceFileImpl_Read( CAsyncSourceImpl* pImpl, LONGLONG llOfsStart, LONG lLength, BYTE* pBuf, LONG* plReturned, HANDLE hEventCancel )
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;
1206 if ( This == NULL || This->hFile == INVALID_HANDLE_VALUE )
1207 return E_UNEXPECTED;
1209 lReturned = 0;
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;
1218 while ( lLength > 0 )
1220 if ( hEventCancel != (HANDLE)NULL &&
1221 WaitForSingleObject( hEventCancel, 0 ) == WAIT_OBJECT_0 )
1223 hr = S_FALSE;
1224 break;
1227 lBlock = ( lLength > ASYNCSRC_FILE_BLOCKSIZE ) ?
1228 ASYNCSRC_FILE_BLOCKSIZE : lLength;
1230 if ( !ReadFile(This->hFile,pBuf,(DWORD)lBlock,&dw,NULL) )
1232 hr = E_FAIL;
1233 break;
1235 pBuf += dw;
1236 lReturned += (LONG)dw;
1237 lLength -= (LONG)dw;
1238 if ( lBlock > (LONG)dw )
1239 break;
1242 *plReturned = lReturned;
1244 return hr;
1247 static const struct AsyncSourceHandlers asyncsrc_file =
1249 AsyncSourceFileImpl_Load,
1250 AsyncSourceFileImpl_Cleanup,
1251 AsyncSourceFileImpl_GetLength,
1252 AsyncSourceFileImpl_Read,
1255 HRESULT QUARTZ_CreateAsyncReader(IUnknown* punkOuter,void** ppobj)
1257 return QUARTZ_CreateAsyncSource(
1258 punkOuter, ppobj,
1259 &CLSID_AsyncReader,
1260 QUARTZ_wszAsyncFileSourceName,
1261 QUARTZ_wszAsyncFileSourcePinName,
1262 &asyncsrc_file );
1265 /***************************************************************************
1267 * Implements URL Source.
1271 typedef struct AsyncSourceURLImpl
1273 DWORD dwDummy;
1274 } AsyncSourceURLImpl;
1277 static HRESULT AsyncSourceURLImpl_Load( CAsyncSourceImpl* pImpl, LPCWSTR lpwszSourceName )
1279 AsyncSourceURLImpl* This = (AsyncSourceURLImpl*)pImpl->m_pUserData;
1281 FIXME("(%p,%p) stub!\n", pImpl, lpwszSourceName);
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;
1290 return E_NOTIMPL;
1293 static HRESULT AsyncSourceURLImpl_Cleanup( CAsyncSourceImpl* pImpl )
1295 AsyncSourceURLImpl* This = (AsyncSourceURLImpl*)pImpl->m_pUserData;
1297 FIXME("(%p) stub!\n", This);
1299 if ( This == NULL )
1300 return NOERROR;
1302 QUARTZ_FreeMem(This);
1303 pImpl->m_pUserData = NULL;
1305 return NOERROR;
1308 static HRESULT AsyncSourceURLImpl_GetLength( CAsyncSourceImpl* pImpl, LONGLONG* pllTotal, LONGLONG* pllAvailable )
1310 AsyncSourceURLImpl* This = (AsyncSourceURLImpl*)pImpl->m_pUserData;
1312 FIXME("(%p,%p,%p) stub!\n", This, pllTotal, pllAvailable);
1314 if ( This == NULL )
1315 return E_UNEXPECTED;
1317 return E_NOTIMPL;
1320 static HRESULT AsyncSourceURLImpl_Read( CAsyncSourceImpl* pImpl, LONGLONG llOfsStart, LONG lLength, BYTE* pBuf, LONG* plReturned, HANDLE hEventCancel )
1322 AsyncSourceURLImpl* This = (AsyncSourceURLImpl*)pImpl->m_pUserData;
1324 FIXME("(%p) stub!\n", This);
1326 if ( This == NULL )
1327 return E_UNEXPECTED;
1329 return E_NOTIMPL;
1332 static const struct AsyncSourceHandlers asyncsrc_url =
1334 AsyncSourceURLImpl_Load,
1335 AsyncSourceURLImpl_Cleanup,
1336 AsyncSourceURLImpl_GetLength,
1337 AsyncSourceURLImpl_Read,
1341 HRESULT QUARTZ_CreateURLReader(IUnknown* punkOuter,void** ppobj)
1343 return QUARTZ_CreateAsyncSource(
1344 punkOuter, ppobj,
1345 &CLSID_URLReader,
1346 QUARTZ_wszAsyncURLSourceName,
1347 QUARTZ_wszAsyncURLSourcePinName,
1348 &asyncsrc_url );