1364 lines
32 KiB
C
1364 lines
32 KiB
C
/*
|
|
* Implements Asynchronous File/URL Source.
|
|
*
|
|
* FIXME - URL source is not implemented yet.
|
|
*
|
|
* Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "wingdi.h"
|
|
#include "winuser.h"
|
|
#include "winerror.h"
|
|
#include "strmif.h"
|
|
#include "vfwmsgs.h"
|
|
#include "uuids.h"
|
|
|
|
#include "wine/debug.h"
|
|
WINE_DEFAULT_DEBUG_CHANNEL(quartz);
|
|
|
|
#include "quartz_private.h"
|
|
#include "asyncsrc.h"
|
|
#include "memalloc.h"
|
|
|
|
|
|
|
|
const WCHAR QUARTZ_wszAsyncFileSourceName[] =
|
|
{'F','i','l','e',' ','S','o','u','r','c','e',' ','(','A','s','y','n','c','.',')',0};
|
|
const WCHAR QUARTZ_wszAsyncFileSourcePinName[] =
|
|
{'O','u','t',0};
|
|
const WCHAR QUARTZ_wszAsyncURLSourceName[] =
|
|
{'F','i','l','e',' ','S','o','u','r','c','e',' ','(','U','R','L',')',0};
|
|
const WCHAR QUARTZ_wszAsyncURLSourcePinName[] =
|
|
{'O','u','t',0};
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* CAsyncReaderImpl internal methods
|
|
*
|
|
*/
|
|
|
|
static
|
|
AsyncSourceRequest* CAsyncReaderImpl_AllocRequest( CAsyncReaderImpl* This )
|
|
{
|
|
AsyncSourceRequest* pReq;
|
|
|
|
EnterCriticalSection( &This->m_csFree );
|
|
pReq = This->m_pFreeFirst;
|
|
if ( pReq != NULL )
|
|
This->m_pFreeFirst = pReq->pNext;
|
|
LeaveCriticalSection( &This->m_csFree );
|
|
|
|
if ( pReq == NULL )
|
|
{
|
|
pReq = (AsyncSourceRequest*)QUARTZ_AllocMem(
|
|
sizeof(AsyncSourceRequest) );
|
|
if ( pReq == NULL )
|
|
return NULL;
|
|
}
|
|
|
|
pReq->pNext = NULL;
|
|
pReq->llStart = 0;
|
|
pReq->lLength = 0;
|
|
pReq->lActual = 0;
|
|
pReq->pBuf = NULL;
|
|
pReq->pSample = NULL;
|
|
pReq->dwContext = 0;
|
|
|
|
return pReq;
|
|
}
|
|
|
|
static
|
|
void CAsyncReaderImpl_FreeRequest( CAsyncReaderImpl* This, AsyncSourceRequest* pReq, BOOL bReleaseMem )
|
|
{
|
|
if ( !bReleaseMem )
|
|
{
|
|
EnterCriticalSection( &This->m_csFree );
|
|
pReq->pNext = This->m_pFreeFirst;
|
|
This->m_pFreeFirst = pReq;
|
|
LeaveCriticalSection( &This->m_csFree );
|
|
}
|
|
else
|
|
{
|
|
QUARTZ_FreeMem( pReq );
|
|
}
|
|
}
|
|
|
|
static
|
|
AsyncSourceRequest* CAsyncReaderImpl_GetRequest( CAsyncReaderImpl* This )
|
|
{
|
|
AsyncSourceRequest* pReq;
|
|
|
|
EnterCriticalSection( &This->m_csRequest );
|
|
pReq = This->m_pRequestFirst;
|
|
if ( pReq != NULL )
|
|
This->m_pRequestFirst = pReq->pNext;
|
|
LeaveCriticalSection( &This->m_csRequest );
|
|
|
|
return pReq;
|
|
}
|
|
|
|
static
|
|
AsyncSourceRequest* CAsyncReaderImpl_GetReply( CAsyncReaderImpl* This )
|
|
{
|
|
AsyncSourceRequest* pReq;
|
|
|
|
EnterCriticalSection( &This->m_csReply );
|
|
pReq = This->m_pReplyFirst;
|
|
if ( pReq != NULL )
|
|
This->m_pReplyFirst = pReq->pNext;
|
|
LeaveCriticalSection( &This->m_csReply );
|
|
|
|
return pReq;
|
|
}
|
|
|
|
static
|
|
void CAsyncReaderImpl_PostRequest( CAsyncReaderImpl* This, AsyncSourceRequest* pReq )
|
|
{
|
|
/* FIXME - add to tail */
|
|
EnterCriticalSection( &This->m_csRequest );
|
|
pReq->pNext = This->m_pRequestFirst;
|
|
This->m_pRequestFirst = pReq;
|
|
if ( This->m_hEventReqQueued != (HANDLE)NULL )
|
|
SetEvent( This->m_hEventReqQueued );
|
|
LeaveCriticalSection( &This->m_csRequest );
|
|
}
|
|
|
|
static
|
|
void CAsyncReaderImpl_PostReply( CAsyncReaderImpl* This, AsyncSourceRequest* pReq )
|
|
{
|
|
/* FIXME - add to tail */
|
|
EnterCriticalSection( &This->m_csReply );
|
|
pReq->pNext = This->m_pReplyFirst;
|
|
This->m_pReplyFirst = pReq;
|
|
if ( This->m_hEventSampQueued != (HANDLE)NULL )
|
|
SetEvent( This->m_hEventSampQueued );
|
|
LeaveCriticalSection( &This->m_csReply );
|
|
}
|
|
|
|
static
|
|
void CAsyncReaderImpl_ReleaseReqList( CAsyncReaderImpl* This, AsyncSourceRequest** ppReq, BOOL bReleaseMem )
|
|
{
|
|
AsyncSourceRequest* pReq;
|
|
AsyncSourceRequest* pReqNext;
|
|
|
|
TRACE("(%p,%p,%d)\n",This,*ppReq,bReleaseMem);
|
|
pReq = *ppReq; *ppReq = NULL;
|
|
while ( pReq != NULL )
|
|
{
|
|
pReqNext = pReq->pNext;
|
|
CAsyncReaderImpl_FreeRequest(This,pReq,bReleaseMem);
|
|
pReq = pReqNext;
|
|
}
|
|
}
|
|
|
|
static DWORD WINAPI
|
|
CAsyncReaderImpl_ThreadEntry( LPVOID pv )
|
|
{
|
|
CAsyncReaderImpl* This = (CAsyncReaderImpl*)pv;
|
|
HANDLE hWaitEvents[2];
|
|
HRESULT hr;
|
|
DWORD dwRes;
|
|
AsyncSourceRequest* pReq = NULL;
|
|
|
|
SetEvent( This->m_hEventInit );
|
|
|
|
hWaitEvents[0] = This->m_hEventReqQueued;
|
|
hWaitEvents[1] = This->m_hEventCancel;
|
|
|
|
TRACE("enter message loop.\n");
|
|
|
|
while ( 1 )
|
|
{
|
|
ResetEvent( This->m_hEventReqQueued );
|
|
pReq = CAsyncReaderImpl_GetRequest(This);
|
|
if ( pReq == NULL )
|
|
{
|
|
dwRes = WaitForMultipleObjects(2,hWaitEvents,FALSE,INFINITE);
|
|
if ( dwRes != WAIT_OBJECT_0 )
|
|
{
|
|
if ( This->m_bAbortThread )
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/* process a queued request */
|
|
EnterCriticalSection( &This->m_csReader );
|
|
hr = This->pSource->m_pHandler->pRead( This->pSource, pReq->llStart, pReq->lLength, pReq->pBuf, &pReq->lActual, This->m_hEventCancel );
|
|
LeaveCriticalSection( &This->m_csReader );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
/* Notify(ABORT) */
|
|
break;
|
|
}
|
|
if ( hr != S_OK )
|
|
{
|
|
if ( This->m_bAbortThread )
|
|
break;
|
|
ResetEvent( This->m_hEventCancel );
|
|
}
|
|
|
|
CAsyncReaderImpl_PostReply( This, pReq );
|
|
SetEvent( This->m_hEventSampQueued );
|
|
pReq = NULL;
|
|
}
|
|
|
|
if ( pReq != NULL )
|
|
CAsyncReaderImpl_PostRequest( This, pReq );
|
|
|
|
SetEvent( This->m_hEventSampQueued );
|
|
return 0;
|
|
}
|
|
|
|
static HRESULT
|
|
CAsyncReaderImpl_BeginThread( CAsyncReaderImpl* This )
|
|
{
|
|
DWORD dwRes;
|
|
DWORD dwThreadId;
|
|
HANDLE hEvents[2];
|
|
|
|
if ( This->m_hEventInit != (HANDLE)NULL ||
|
|
This->m_hEventCancel != (HANDLE)NULL ||
|
|
This->m_hEventReqQueued != (HANDLE)NULL ||
|
|
This->m_hEventSampQueued != (HANDLE)NULL ||
|
|
This->m_hThread != (HANDLE)NULL )
|
|
return E_UNEXPECTED;
|
|
This->m_bAbortThread = FALSE;
|
|
|
|
This->m_hEventInit = CreateEventA(NULL,TRUE,FALSE,NULL);
|
|
if ( This->m_hEventInit == (HANDLE)NULL )
|
|
return E_OUTOFMEMORY;
|
|
This->m_hEventCancel = CreateEventA(NULL,TRUE,FALSE,NULL);
|
|
if ( This->m_hEventCancel == (HANDLE)NULL )
|
|
return E_OUTOFMEMORY;
|
|
This->m_hEventReqQueued = CreateEventA(NULL,TRUE,FALSE,NULL);
|
|
if ( This->m_hEventReqQueued == (HANDLE)NULL )
|
|
return E_OUTOFMEMORY;
|
|
This->m_hEventSampQueued = CreateEventA(NULL,TRUE,FALSE,NULL);
|
|
if ( This->m_hEventSampQueued == (HANDLE)NULL )
|
|
return E_OUTOFMEMORY;
|
|
|
|
/* create the processing thread. */
|
|
This->m_hThread = CreateThread(
|
|
NULL, 0,
|
|
CAsyncReaderImpl_ThreadEntry,
|
|
(LPVOID)This,
|
|
0, &dwThreadId );
|
|
if ( This->m_hThread == (HANDLE)NULL )
|
|
return E_FAIL;
|
|
|
|
hEvents[0] = This->m_hEventInit;
|
|
hEvents[1] = This->m_hThread;
|
|
|
|
dwRes = WaitForMultipleObjects(2,hEvents,FALSE,INFINITE);
|
|
if ( dwRes != WAIT_OBJECT_0 )
|
|
return E_FAIL;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static void
|
|
CAsyncReaderImpl_EndThread( CAsyncReaderImpl* This )
|
|
{
|
|
if ( This->m_hThread != (HANDLE)NULL )
|
|
{
|
|
while ( 1 )
|
|
{
|
|
This->m_bAbortThread = TRUE;
|
|
SetEvent( This->m_hEventCancel );
|
|
if ( WaitForSingleObject( This->m_hThread, 100 ) == WAIT_OBJECT_0 )
|
|
break;
|
|
}
|
|
CloseHandle( This->m_hThread );
|
|
This->m_hThread = (HANDLE)NULL;
|
|
}
|
|
if ( This->m_hEventInit != (HANDLE)NULL )
|
|
{
|
|
CloseHandle( This->m_hEventInit );
|
|
This->m_hEventInit = (HANDLE)NULL;
|
|
}
|
|
if ( This->m_hEventCancel != (HANDLE)NULL )
|
|
{
|
|
CloseHandle( This->m_hEventCancel );
|
|
This->m_hEventCancel = (HANDLE)NULL;
|
|
}
|
|
if ( This->m_hEventReqQueued != (HANDLE)NULL )
|
|
{
|
|
CloseHandle( This->m_hEventReqQueued );
|
|
This->m_hEventReqQueued = (HANDLE)NULL;
|
|
}
|
|
if ( This->m_hEventSampQueued != (HANDLE)NULL )
|
|
{
|
|
CloseHandle( This->m_hEventSampQueued );
|
|
This->m_hEventSampQueued = (HANDLE)NULL;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
* CAsyncReaderImpl methods
|
|
*
|
|
*/
|
|
|
|
static HRESULT WINAPI
|
|
CAsyncReaderImpl_fnQueryInterface(IAsyncReader* iface,REFIID riid,void** ppobj)
|
|
{
|
|
ICOM_THIS(CAsyncReaderImpl,iface);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
return IUnknown_QueryInterface(This->punkControl,riid,ppobj);
|
|
}
|
|
|
|
static ULONG WINAPI
|
|
CAsyncReaderImpl_fnAddRef(IAsyncReader* iface)
|
|
{
|
|
ICOM_THIS(CAsyncReaderImpl,iface);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
return IUnknown_AddRef(This->punkControl);
|
|
}
|
|
|
|
static ULONG WINAPI
|
|
CAsyncReaderImpl_fnRelease(IAsyncReader* iface)
|
|
{
|
|
ICOM_THIS(CAsyncReaderImpl,iface);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
return IUnknown_Release(This->punkControl);
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CAsyncReaderImpl_fnRequestAllocator(IAsyncReader* iface,IMemAllocator* pAlloc,ALLOCATOR_PROPERTIES* pProp,IMemAllocator** ppAllocActual)
|
|
{
|
|
ICOM_THIS(CAsyncReaderImpl,iface);
|
|
HRESULT hr;
|
|
ALLOCATOR_PROPERTIES propActual;
|
|
IUnknown* punk = NULL;
|
|
|
|
TRACE("(%p)->(%p,%p,%p)\n",This,pAlloc,pProp,ppAllocActual);
|
|
|
|
if ( pAlloc == NULL || pProp == NULL || ppAllocActual == NULL )
|
|
return E_POINTER;
|
|
|
|
IMemAllocator_AddRef(pAlloc);
|
|
hr = IMemAllocator_SetProperties( pAlloc, pProp, &propActual );
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
*ppAllocActual = pAlloc;
|
|
return S_OK;
|
|
}
|
|
IMemAllocator_Release(pAlloc);
|
|
|
|
hr = QUARTZ_CreateMemoryAllocator(NULL,(void**)&punk);
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
hr = IUnknown_QueryInterface( punk, &IID_IMemAllocator, (void**)&pAlloc );
|
|
IUnknown_Release(punk);
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
|
|
hr = IMemAllocator_SetProperties( pAlloc, pProp, &propActual );
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
*ppAllocActual = pAlloc;
|
|
return S_OK;
|
|
}
|
|
IMemAllocator_Release(pAlloc);
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CAsyncReaderImpl_fnRequest(IAsyncReader* iface,IMediaSample* pSample,DWORD_PTR dwContext)
|
|
{
|
|
ICOM_THIS(CAsyncReaderImpl,iface);
|
|
HRESULT hr = NOERROR;
|
|
REFERENCE_TIME rtStart;
|
|
REFERENCE_TIME rtEnd;
|
|
AsyncSourceRequest* pReq;
|
|
BYTE* pData = NULL;
|
|
|
|
TRACE("(%p)->(%p,%u)\n",This,pSample,dwContext);
|
|
|
|
hr = IMediaSample_GetPointer(pSample,&pData);
|
|
if ( SUCCEEDED(hr) )
|
|
hr = IMediaSample_GetTime(pSample,&rtStart,&rtEnd);
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
|
|
pReq = CAsyncReaderImpl_AllocRequest(This);
|
|
if ( pReq == NULL )
|
|
return E_OUTOFMEMORY;
|
|
|
|
pReq->llStart = rtStart / QUARTZ_TIMEUNITS;
|
|
pReq->lLength = (LONG)(rtEnd / QUARTZ_TIMEUNITS - rtStart / QUARTZ_TIMEUNITS);
|
|
pReq->lActual = 0;
|
|
pReq->pBuf = pData;
|
|
pReq->pSample = pSample;
|
|
pReq->dwContext = dwContext;
|
|
CAsyncReaderImpl_PostRequest( This, pReq );
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CAsyncReaderImpl_fnWaitForNext(IAsyncReader* iface,DWORD dwTimeout,IMediaSample** ppSample,DWORD_PTR* pdwContext)
|
|
{
|
|
ICOM_THIS(CAsyncReaderImpl,iface);
|
|
HRESULT hr = NOERROR;
|
|
DWORD dwRes;
|
|
AsyncSourceRequest* pReq;
|
|
REFERENCE_TIME rtStart;
|
|
REFERENCE_TIME rtEnd;
|
|
|
|
TRACE("(%p)->(%lu,%p,%p)\n",This,dwTimeout,ppSample,pdwContext);
|
|
|
|
EnterCriticalSection( &This->m_csRequest );
|
|
if ( This->m_bInFlushing )
|
|
hr = VFW_E_TIMEOUT;
|
|
LeaveCriticalSection( &This->m_csRequest );
|
|
|
|
if ( hr == NOERROR )
|
|
{
|
|
ResetEvent( This->m_hEventSampQueued );
|
|
pReq = CAsyncReaderImpl_GetReply(This);
|
|
if ( pReq == NULL )
|
|
{
|
|
dwRes = WaitForSingleObject( This->m_hEventSampQueued, dwTimeout );
|
|
if ( dwRes == WAIT_OBJECT_0 )
|
|
pReq = CAsyncReaderImpl_GetReply(This);
|
|
}
|
|
if ( pReq != NULL )
|
|
{
|
|
hr = IMediaSample_SetActualDataLength(pReq->pSample,pReq->lActual);
|
|
if ( hr == S_OK )
|
|
{
|
|
rtStart = pReq->llStart * QUARTZ_TIMEUNITS;
|
|
rtEnd = (pReq->llStart + pReq->lActual) * QUARTZ_TIMEUNITS;
|
|
hr = IMediaSample_SetTime(pReq->pSample,&rtStart,&rtEnd);
|
|
}
|
|
*ppSample = pReq->pSample;
|
|
*pdwContext = pReq->dwContext;
|
|
if ( hr == S_OK && pReq->lActual != pReq->lLength )
|
|
hr = S_FALSE;
|
|
}
|
|
else
|
|
{
|
|
hr = VFW_E_TIMEOUT;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CAsyncReaderImpl_fnSyncReadAligned(IAsyncReader* iface,IMediaSample* pSample)
|
|
{
|
|
ICOM_THIS(CAsyncReaderImpl,iface);
|
|
HRESULT hr;
|
|
REFERENCE_TIME rtStart;
|
|
REFERENCE_TIME rtEnd;
|
|
BYTE* pData = NULL;
|
|
LONGLONG llStart;
|
|
LONG lLength;
|
|
LONG lActual;
|
|
|
|
TRACE("(%p)->(%p)\n",This,pSample);
|
|
|
|
hr = IMediaSample_GetPointer(pSample,&pData);
|
|
if ( SUCCEEDED(hr) )
|
|
hr = IMediaSample_GetTime(pSample,&rtStart,&rtEnd);
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
|
|
llStart = rtStart / QUARTZ_TIMEUNITS;
|
|
lLength = (LONG)(rtEnd / QUARTZ_TIMEUNITS - rtStart / QUARTZ_TIMEUNITS);
|
|
lActual = 0;
|
|
|
|
EnterCriticalSection( &This->m_csReader );
|
|
hr = This->pSource->m_pHandler->pRead( This->pSource, llStart, lLength, pData, &lActual, (HANDLE)NULL );
|
|
LeaveCriticalSection( &This->m_csReader );
|
|
|
|
if ( hr == NOERROR )
|
|
{
|
|
hr = IMediaSample_SetActualDataLength(pSample,lActual);
|
|
if ( hr == S_OK )
|
|
{
|
|
rtStart = llStart * QUARTZ_TIMEUNITS;
|
|
rtEnd = (llStart + lActual) * QUARTZ_TIMEUNITS;
|
|
hr = IMediaSample_SetTime(pSample,&rtStart,&rtEnd);
|
|
}
|
|
if ( hr == S_OK && lActual != lLength )
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CAsyncReaderImpl_fnSyncRead(IAsyncReader* iface,LONGLONG llPosStart,LONG lLength,BYTE* pbBuf)
|
|
{
|
|
ICOM_THIS(CAsyncReaderImpl,iface);
|
|
HRESULT hr;
|
|
LONG lActual;
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
EnterCriticalSection( &This->m_csReader );
|
|
hr = This->pSource->m_pHandler->pRead( This->pSource, llPosStart, lLength, pbBuf, &lActual, (HANDLE)NULL );
|
|
LeaveCriticalSection( &This->m_csReader );
|
|
|
|
if ( hr == S_OK && lLength != lActual )
|
|
hr = S_FALSE;
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CAsyncReaderImpl_fnLength(IAsyncReader* iface,LONGLONG* pllTotal,LONGLONG* pllAvailable)
|
|
{
|
|
ICOM_THIS(CAsyncReaderImpl,iface);
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
hr = This->pSource->m_pHandler->pGetLength( This->pSource, pllTotal, pllAvailable );
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CAsyncReaderImpl_fnBeginFlush(IAsyncReader* iface)
|
|
{
|
|
ICOM_THIS(CAsyncReaderImpl,iface);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
EnterCriticalSection( &This->m_csRequest );
|
|
This->m_bInFlushing = TRUE;
|
|
SetEvent( This->m_hEventCancel );
|
|
CAsyncReaderImpl_ReleaseReqList(This,&This->m_pRequestFirst,FALSE);
|
|
LeaveCriticalSection( &This->m_csRequest );
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CAsyncReaderImpl_fnEndFlush(IAsyncReader* iface)
|
|
{
|
|
ICOM_THIS(CAsyncReaderImpl,iface);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
EnterCriticalSection( &This->m_csRequest );
|
|
This->m_bInFlushing = FALSE;
|
|
ResetEvent( This->m_hEventCancel );
|
|
LeaveCriticalSection( &This->m_csRequest );
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
static ICOM_VTABLE(IAsyncReader) iasyncreader =
|
|
{
|
|
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
|
|
/* IUnknown fields */
|
|
CAsyncReaderImpl_fnQueryInterface,
|
|
CAsyncReaderImpl_fnAddRef,
|
|
CAsyncReaderImpl_fnRelease,
|
|
|
|
/* IAsyncReader fields */
|
|
CAsyncReaderImpl_fnRequestAllocator,
|
|
CAsyncReaderImpl_fnRequest,
|
|
CAsyncReaderImpl_fnWaitForNext,
|
|
CAsyncReaderImpl_fnSyncReadAligned,
|
|
CAsyncReaderImpl_fnSyncRead,
|
|
CAsyncReaderImpl_fnLength,
|
|
CAsyncReaderImpl_fnBeginFlush,
|
|
CAsyncReaderImpl_fnEndFlush,
|
|
};
|
|
|
|
HRESULT CAsyncReaderImpl_InitIAsyncReader(
|
|
CAsyncReaderImpl* This, IUnknown* punkControl,
|
|
CAsyncSourceImpl* pSource )
|
|
{
|
|
TRACE("(%p,%p)\n",This,punkControl);
|
|
|
|
if ( punkControl == NULL )
|
|
{
|
|
ERR( "punkControl must not be NULL\n" );
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
ICOM_VTBL(This) = &iasyncreader;
|
|
This->punkControl = punkControl;
|
|
This->pSource = pSource;
|
|
This->m_bInFlushing = FALSE;
|
|
This->m_bAbortThread = FALSE;
|
|
This->m_hEventInit = (HANDLE)NULL;
|
|
This->m_hEventCancel = (HANDLE)NULL;
|
|
This->m_hEventReqQueued = (HANDLE)NULL;
|
|
This->m_hEventSampQueued = (HANDLE)NULL;
|
|
This->m_hThread = (HANDLE)NULL;
|
|
This->m_pRequestFirst = NULL;
|
|
This->m_pReplyFirst = NULL;
|
|
This->m_pFreeFirst = NULL;
|
|
|
|
InitializeCriticalSection( &This->m_csReader );
|
|
InitializeCriticalSection( &This->m_csRequest );
|
|
InitializeCriticalSection( &This->m_csReply );
|
|
InitializeCriticalSection( &This->m_csFree );
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
void CAsyncReaderImpl_UninitIAsyncReader(
|
|
CAsyncReaderImpl* This )
|
|
{
|
|
TRACE("(%p) enter\n",This);
|
|
|
|
CAsyncReaderImpl_ReleaseReqList(This,&This->m_pRequestFirst,TRUE);
|
|
CAsyncReaderImpl_ReleaseReqList(This,&This->m_pReplyFirst,TRUE);
|
|
CAsyncReaderImpl_ReleaseReqList(This,&This->m_pFreeFirst,TRUE);
|
|
|
|
DeleteCriticalSection( &This->m_csReader );
|
|
DeleteCriticalSection( &This->m_csRequest );
|
|
DeleteCriticalSection( &This->m_csReply );
|
|
DeleteCriticalSection( &This->m_csFree );
|
|
|
|
TRACE("(%p) leave\n",This);
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
* CFileSourceFilterImpl
|
|
*
|
|
*/
|
|
|
|
static HRESULT WINAPI
|
|
CFileSourceFilterImpl_fnQueryInterface(IFileSourceFilter* iface,REFIID riid,void** ppobj)
|
|
{
|
|
ICOM_THIS(CFileSourceFilterImpl,iface);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
return IUnknown_QueryInterface(This->punkControl,riid,ppobj);
|
|
}
|
|
|
|
static ULONG WINAPI
|
|
CFileSourceFilterImpl_fnAddRef(IFileSourceFilter* iface)
|
|
{
|
|
ICOM_THIS(CFileSourceFilterImpl,iface);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
return IUnknown_AddRef(This->punkControl);
|
|
}
|
|
|
|
static ULONG WINAPI
|
|
CFileSourceFilterImpl_fnRelease(IFileSourceFilter* iface)
|
|
{
|
|
ICOM_THIS(CFileSourceFilterImpl,iface);
|
|
|
|
TRACE("(%p)->()\n",This);
|
|
|
|
return IUnknown_Release(This->punkControl);
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CFileSourceFilterImpl_fnLoad(IFileSourceFilter* iface,LPCOLESTR pFileName,const AM_MEDIA_TYPE* pmt)
|
|
{
|
|
ICOM_THIS(CFileSourceFilterImpl,iface);
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p)->(%s,%p)\n",This,debugstr_w(pFileName),pmt);
|
|
|
|
if ( pFileName == NULL )
|
|
return E_POINTER;
|
|
|
|
if ( This->m_pwszFileName != NULL )
|
|
return E_UNEXPECTED;
|
|
|
|
This->m_cbFileName = sizeof(WCHAR)*(lstrlenW(pFileName)+1);
|
|
This->m_pwszFileName = (WCHAR*)QUARTZ_AllocMem( This->m_cbFileName );
|
|
if ( This->m_pwszFileName == NULL )
|
|
return E_OUTOFMEMORY;
|
|
memcpy( This->m_pwszFileName, pFileName, This->m_cbFileName );
|
|
|
|
if ( pmt != NULL )
|
|
{
|
|
hr = QUARTZ_MediaType_Copy( &This->m_mt, pmt );
|
|
if ( FAILED(hr) )
|
|
goto err;
|
|
}
|
|
else
|
|
{
|
|
ZeroMemory( &This->m_mt, sizeof(AM_MEDIA_TYPE) );
|
|
memcpy( &This->m_mt.majortype, &MEDIATYPE_Stream, sizeof(GUID) );
|
|
memcpy( &This->m_mt.subtype, &MEDIASUBTYPE_NULL, sizeof(GUID) );
|
|
This->m_mt.lSampleSize = 1;
|
|
memcpy( &This->m_mt.formattype, &FORMAT_None, sizeof(GUID) );
|
|
}
|
|
|
|
hr = This->pSource->m_pHandler->pLoad( This->pSource, pFileName );
|
|
if ( FAILED(hr) )
|
|
goto err;
|
|
|
|
This->pSource->pPin->pin.pmtAcceptTypes = &This->m_mt;
|
|
This->pSource->pPin->pin.cAcceptTypes = 1;
|
|
|
|
return NOERROR;
|
|
err:;
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI
|
|
CFileSourceFilterImpl_fnGetCurFile(IFileSourceFilter* iface,LPOLESTR* ppFileName,AM_MEDIA_TYPE* pmt)
|
|
{
|
|
ICOM_THIS(CFileSourceFilterImpl,iface);
|
|
HRESULT hr = E_NOTIMPL;
|
|
|
|
TRACE("(%p)->(%p,%p)\n",This,ppFileName,pmt);
|
|
|
|
if ( ppFileName == NULL || pmt == NULL )
|
|
return E_POINTER;
|
|
|
|
if ( This->m_pwszFileName == NULL )
|
|
return E_FAIL;
|
|
|
|
hr = QUARTZ_MediaType_Copy( pmt, &This->m_mt );
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
|
|
*ppFileName = (WCHAR*)CoTaskMemAlloc( This->m_cbFileName );
|
|
if ( *ppFileName == NULL )
|
|
{
|
|
QUARTZ_MediaType_Free(pmt);
|
|
ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) );
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
memcpy( *ppFileName, This->m_pwszFileName, This->m_cbFileName );
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static ICOM_VTABLE(IFileSourceFilter) ifilesource =
|
|
{
|
|
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
|
|
/* IUnknown fields */
|
|
CFileSourceFilterImpl_fnQueryInterface,
|
|
CFileSourceFilterImpl_fnAddRef,
|
|
CFileSourceFilterImpl_fnRelease,
|
|
/* IFileSourceFilter fields */
|
|
CFileSourceFilterImpl_fnLoad,
|
|
CFileSourceFilterImpl_fnGetCurFile,
|
|
};
|
|
|
|
HRESULT CFileSourceFilterImpl_InitIFileSourceFilter(
|
|
CFileSourceFilterImpl* This, IUnknown* punkControl,
|
|
CAsyncSourceImpl* pSource,
|
|
CRITICAL_SECTION* pcsFileSource )
|
|
{
|
|
TRACE("(%p,%p)\n",This,punkControl);
|
|
|
|
if ( punkControl == NULL )
|
|
{
|
|
ERR( "punkControl must not be NULL\n" );
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
ICOM_VTBL(This) = &ifilesource;
|
|
This->punkControl = punkControl;
|
|
This->pSource = pSource;
|
|
This->pcsFileSource = pcsFileSource;
|
|
This->m_pwszFileName = NULL;
|
|
This->m_cbFileName = 0;
|
|
ZeroMemory( &This->m_mt, sizeof(AM_MEDIA_TYPE) );
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
void CFileSourceFilterImpl_UninitIFileSourceFilter(
|
|
CFileSourceFilterImpl* This )
|
|
{
|
|
TRACE("(%p)\n",This);
|
|
|
|
This->pSource->m_pHandler->pCleanup( This->pSource );
|
|
if ( This->m_pwszFileName != NULL )
|
|
QUARTZ_FreeMem( This->m_pwszFileName );
|
|
QUARTZ_MediaType_Free( &This->m_mt );
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
* CAsyncSourcePinImpl methods
|
|
*
|
|
*/
|
|
|
|
|
|
static HRESULT CAsyncSourcePinImpl_OnPreConnect( CPinBaseImpl* pImpl, IPin* pPin )
|
|
{
|
|
CAsyncSourcePinImpl_THIS(pImpl,pin);
|
|
|
|
TRACE("(%p,%p)\n",This,pPin);
|
|
|
|
This->bAsyncReaderQueried = FALSE;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static HRESULT CAsyncSourcePinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin )
|
|
{
|
|
CAsyncSourcePinImpl_THIS(pImpl,pin);
|
|
|
|
TRACE("(%p,%p)\n",This,pPin);
|
|
|
|
if ( !This->bAsyncReaderQueried )
|
|
return E_FAIL;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static HRESULT CAsyncSourcePinImpl_OnDisconnect( CPinBaseImpl* pImpl )
|
|
{
|
|
CAsyncSourcePinImpl_THIS(pImpl,pin);
|
|
|
|
TRACE("(%p)\n",This);
|
|
|
|
This->bAsyncReaderQueried = FALSE;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static HRESULT CAsyncSourcePinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt )
|
|
{
|
|
CAsyncSourcePinImpl_THIS(pImpl,pin);
|
|
|
|
TRACE("(%p,%p)\n",This,pmt);
|
|
if ( pmt == NULL )
|
|
return E_POINTER;
|
|
|
|
if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Stream ) )
|
|
return E_FAIL;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static const CBasePinHandlers outputpinhandlers =
|
|
{
|
|
CAsyncSourcePinImpl_OnPreConnect, /* pOnPreConnect */
|
|
CAsyncSourcePinImpl_OnPostConnect, /* pOnPostConnect */
|
|
CAsyncSourcePinImpl_OnDisconnect, /* pOnDisconnect */
|
|
CAsyncSourcePinImpl_CheckMediaType, /* pCheckMediaType */
|
|
NULL, /* pQualityNotify */
|
|
NULL, /* pReceive */
|
|
NULL, /* pReceiveCanBlock */
|
|
NULL, /* pEndOfStream */
|
|
NULL, /* pBeginFlush */
|
|
NULL, /* pEndFlush */
|
|
NULL, /* pNewSegment */
|
|
};
|
|
|
|
/***************************************************************************
|
|
*
|
|
* CAsyncSourceImpl methods
|
|
*
|
|
*/
|
|
|
|
static HRESULT CAsyncSourceImpl_OnActive( CBaseFilterImpl* pImpl )
|
|
{
|
|
CAsyncSourceImpl_THIS(pImpl,basefilter);
|
|
HRESULT hr;
|
|
|
|
TRACE( "(%p)\n", This );
|
|
|
|
hr = CAsyncReaderImpl_BeginThread(&This->pPin->async);
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static HRESULT CAsyncSourceImpl_OnInactive( CBaseFilterImpl* pImpl )
|
|
{
|
|
CAsyncSourceImpl_THIS(pImpl,basefilter);
|
|
|
|
TRACE( "(%p)\n", This );
|
|
|
|
CAsyncReaderImpl_EndThread(&This->pPin->async);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static const CBaseFilterHandlers filterhandlers =
|
|
{
|
|
CAsyncSourceImpl_OnActive, /* pOnActive */
|
|
CAsyncSourceImpl_OnInactive, /* pOnInactive */
|
|
NULL, /* pOnStop */
|
|
};
|
|
|
|
/***************************************************************************
|
|
*
|
|
* new/delete CAsyncSourceImpl
|
|
*
|
|
*/
|
|
|
|
/* can I use offsetof safely? - FIXME? */
|
|
static QUARTZ_IFEntry FilterIFEntries[] =
|
|
{
|
|
{ &IID_IPersist, offsetof(CAsyncSourceImpl,basefilter)-offsetof(CAsyncSourceImpl,unk) },
|
|
{ &IID_IMediaFilter, offsetof(CAsyncSourceImpl,basefilter)-offsetof(CAsyncSourceImpl,unk) },
|
|
{ &IID_IBaseFilter, offsetof(CAsyncSourceImpl,basefilter)-offsetof(CAsyncSourceImpl,unk) },
|
|
{ &IID_IFileSourceFilter, offsetof(CAsyncSourceImpl,filesrc)-offsetof(CAsyncSourceImpl,unk) },
|
|
};
|
|
|
|
static void QUARTZ_DestroyAsyncSource(IUnknown* punk)
|
|
{
|
|
CAsyncSourceImpl_THIS(punk,unk);
|
|
|
|
TRACE( "(%p)\n", This );
|
|
|
|
if ( This->pPin != NULL )
|
|
{
|
|
IUnknown_Release(This->pPin->unk.punkControl);
|
|
This->pPin = NULL;
|
|
}
|
|
|
|
This->m_pHandler->pCleanup( This );
|
|
|
|
CFileSourceFilterImpl_UninitIFileSourceFilter(&This->filesrc);
|
|
CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
|
|
|
|
DeleteCriticalSection( &This->csFilter );
|
|
}
|
|
|
|
HRESULT QUARTZ_CreateAsyncSource(
|
|
IUnknown* punkOuter,void** ppobj,
|
|
const CLSID* pclsidAsyncSource,
|
|
LPCWSTR pwszAsyncSourceName,
|
|
LPCWSTR pwszOutPinName,
|
|
const AsyncSourceHandlers* pHandler )
|
|
{
|
|
CAsyncSourceImpl* This = NULL;
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p,%p)\n",punkOuter,ppobj);
|
|
|
|
This = (CAsyncSourceImpl*)
|
|
QUARTZ_AllocObj( sizeof(CAsyncSourceImpl) );
|
|
if ( This == NULL )
|
|
return E_OUTOFMEMORY;
|
|
|
|
This->pPin = NULL;
|
|
This->m_pHandler = pHandler;
|
|
This->m_pUserData = NULL;
|
|
|
|
QUARTZ_IUnkInit( &This->unk, punkOuter );
|
|
|
|
hr = CBaseFilterImpl_InitIBaseFilter(
|
|
&This->basefilter,
|
|
This->unk.punkControl,
|
|
pclsidAsyncSource,
|
|
pwszAsyncSourceName,
|
|
&filterhandlers );
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
/* construct this class. */
|
|
hr = CFileSourceFilterImpl_InitIFileSourceFilter(
|
|
&This->filesrc, This->unk.punkControl,
|
|
This, &This->csFilter );
|
|
if ( FAILED(hr) )
|
|
{
|
|
CBaseFilterImpl_UninitIBaseFilter(&This->basefilter);
|
|
}
|
|
}
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
QUARTZ_FreeObj(This);
|
|
return hr;
|
|
}
|
|
|
|
This->unk.pEntries = FilterIFEntries;
|
|
This->unk.dwEntries = sizeof(FilterIFEntries)/sizeof(FilterIFEntries[0]);
|
|
This->unk.pOnFinalRelease = QUARTZ_DestroyAsyncSource;
|
|
InitializeCriticalSection( &This->csFilter );
|
|
|
|
/* create the output pin. */
|
|
hr = QUARTZ_CreateAsyncSourcePin(
|
|
This, &This->csFilter,
|
|
&This->pPin, pwszOutPinName );
|
|
if ( SUCCEEDED(hr) )
|
|
hr = QUARTZ_CompList_AddComp(
|
|
This->basefilter.pOutPins,
|
|
(IUnknown*)&(This->pPin->pin),
|
|
NULL, 0 );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
IUnknown_Release( This->unk.punkControl );
|
|
return hr;
|
|
}
|
|
|
|
*ppobj = (void*)&(This->unk);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
* new/delete CAsyncSourcePinImpl
|
|
*
|
|
*/
|
|
|
|
/* can I use offsetof safely? - FIXME? */
|
|
static QUARTZ_IFEntry OutPinIFEntries[] =
|
|
{
|
|
{ &IID_IPin, offsetof(CAsyncSourcePinImpl,pin)-offsetof(CAsyncSourcePinImpl,unk) },
|
|
/***{ &IID_IAsyncReader, offsetof(CAsyncSourcePinImpl,async)-offsetof(CAsyncSourcePinImpl,unk) },***/
|
|
};
|
|
|
|
static HRESULT CAsyncSourceImpl_OnQueryInterface(
|
|
IUnknown* punk, const IID* piid, void** ppobj )
|
|
{
|
|
CAsyncSourcePinImpl_THIS(punk,unk);
|
|
|
|
if ( IsEqualGUID( &IID_IAsyncReader, piid ) )
|
|
{
|
|
TRACE("IAsyncReader has been queried.\n");
|
|
*ppobj = (void*)&This->async;
|
|
IUnknown_AddRef(punk);
|
|
This->bAsyncReaderQueried = TRUE;
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static void QUARTZ_DestroyAsyncSourcePin(IUnknown* punk)
|
|
{
|
|
CAsyncSourcePinImpl_THIS(punk,unk);
|
|
|
|
TRACE( "(%p)\n", This );
|
|
|
|
CAsyncReaderImpl_UninitIAsyncReader( &This->async );
|
|
CPinBaseImpl_UninitIPin( &This->pin );
|
|
}
|
|
|
|
HRESULT QUARTZ_CreateAsyncSourcePin(
|
|
CAsyncSourceImpl* pFilter,
|
|
CRITICAL_SECTION* pcsPin,
|
|
CAsyncSourcePinImpl** ppPin,
|
|
LPCWSTR pwszPinName )
|
|
{
|
|
CAsyncSourcePinImpl* This = NULL;
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin);
|
|
|
|
This = (CAsyncSourcePinImpl*)
|
|
QUARTZ_AllocObj( sizeof(CAsyncSourcePinImpl) );
|
|
if ( This == NULL )
|
|
return E_OUTOFMEMORY;
|
|
|
|
QUARTZ_IUnkInit( &This->unk, NULL );
|
|
This->qiext.pNext = NULL;
|
|
This->qiext.pOnQueryInterface = &CAsyncSourceImpl_OnQueryInterface;
|
|
QUARTZ_IUnkAddDelegation( &This->unk, &This->qiext );
|
|
|
|
This->bAsyncReaderQueried = FALSE;
|
|
This->pSource = pFilter;
|
|
|
|
hr = CPinBaseImpl_InitIPin(
|
|
&This->pin,
|
|
This->unk.punkControl,
|
|
pcsPin, NULL,
|
|
&pFilter->basefilter,
|
|
pwszPinName,
|
|
TRUE,
|
|
&outputpinhandlers );
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
hr = CAsyncReaderImpl_InitIAsyncReader(
|
|
&This->async,
|
|
This->unk.punkControl,
|
|
pFilter );
|
|
if ( FAILED(hr) )
|
|
{
|
|
CPinBaseImpl_UninitIPin( &This->pin );
|
|
}
|
|
}
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
QUARTZ_FreeObj(This);
|
|
return hr;
|
|
}
|
|
|
|
This->unk.pEntries = OutPinIFEntries;
|
|
This->unk.dwEntries = sizeof(OutPinIFEntries)/sizeof(OutPinIFEntries[0]);
|
|
This->unk.pOnFinalRelease = QUARTZ_DestroyAsyncSourcePin;
|
|
|
|
*ppPin = This;
|
|
|
|
TRACE("returned successfully.\n");
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* Implements File Source.
|
|
*
|
|
*/
|
|
|
|
typedef struct AsyncSourceFileImpl
|
|
{
|
|
HANDLE hFile;
|
|
LONGLONG llTotal;
|
|
} AsyncSourceFileImpl;
|
|
|
|
|
|
static HRESULT AsyncSourceFileImpl_Load( CAsyncSourceImpl* pImpl, LPCWSTR lpwszSourceName )
|
|
{
|
|
AsyncSourceFileImpl* This = (AsyncSourceFileImpl*)pImpl->m_pUserData;
|
|
DWORD dwLow;
|
|
DWORD dwHigh;
|
|
|
|
if ( This != NULL )
|
|
return E_UNEXPECTED;
|
|
This = (AsyncSourceFileImpl*)QUARTZ_AllocMem( sizeof(AsyncSourceFileImpl) );
|
|
pImpl->m_pUserData = (void*)This;
|
|
if ( This == NULL )
|
|
return E_OUTOFMEMORY;
|
|
This->hFile = INVALID_HANDLE_VALUE;
|
|
This->llTotal = 0;
|
|
|
|
This->hFile = CreateFileW( lpwszSourceName,
|
|
GENERIC_READ, FILE_SHARE_READ,
|
|
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL );
|
|
if ( This->hFile == INVALID_HANDLE_VALUE )
|
|
return E_FAIL;
|
|
|
|
SetLastError(NO_ERROR);
|
|
dwLow = GetFileSize( This->hFile, &dwHigh );
|
|
if ( dwLow == 0xffffffff && GetLastError() != NO_ERROR )
|
|
return E_FAIL;
|
|
|
|
This->llTotal = (LONGLONG)dwLow | ((LONGLONG)dwHigh << 32);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static HRESULT AsyncSourceFileImpl_Cleanup( CAsyncSourceImpl* pImpl )
|
|
{
|
|
AsyncSourceFileImpl* This = (AsyncSourceFileImpl*)pImpl->m_pUserData;
|
|
|
|
if ( This == NULL )
|
|
return NOERROR;
|
|
|
|
if ( This->hFile != INVALID_HANDLE_VALUE )
|
|
CloseHandle(This->hFile);
|
|
|
|
QUARTZ_FreeMem(This);
|
|
pImpl->m_pUserData = NULL;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static HRESULT AsyncSourceFileImpl_GetLength( CAsyncSourceImpl* pImpl, LONGLONG* pllTotal, LONGLONG* pllAvailable )
|
|
{
|
|
AsyncSourceFileImpl* This = (AsyncSourceFileImpl*)pImpl->m_pUserData;
|
|
|
|
if ( This == NULL )
|
|
return E_UNEXPECTED;
|
|
|
|
*pllTotal = This->llTotal;
|
|
*pllAvailable = This->llTotal;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static HRESULT AsyncSourceFileImpl_Read( CAsyncSourceImpl* pImpl, LONGLONG llOfsStart, LONG lLength, BYTE* pBuf, LONG* plReturned, HANDLE hEventCancel )
|
|
{
|
|
AsyncSourceFileImpl* This = (AsyncSourceFileImpl*)pImpl->m_pUserData;
|
|
LONG lReturned;
|
|
LONG lBlock;
|
|
LONG lOfsLow;
|
|
LONG lOfsHigh;
|
|
DWORD dw;
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( This == NULL || This->hFile == INVALID_HANDLE_VALUE )
|
|
return E_UNEXPECTED;
|
|
|
|
lReturned = 0;
|
|
|
|
lOfsLow = (LONG)(llOfsStart & 0xffffffff);
|
|
lOfsHigh = (LONG)(llOfsStart >> 32);
|
|
SetLastError(NO_ERROR);
|
|
lOfsLow = SetFilePointer( This->hFile, lOfsLow, &lOfsHigh, FILE_BEGIN );
|
|
if ( lOfsLow == (LONG)0xffffffff && GetLastError() != NO_ERROR )
|
|
return E_FAIL;
|
|
|
|
while ( lLength > 0 )
|
|
{
|
|
if ( hEventCancel != (HANDLE)NULL &&
|
|
WaitForSingleObject( hEventCancel, 0 ) == WAIT_OBJECT_0 )
|
|
{
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
|
|
lBlock = ( lLength > ASYNCSRC_FILE_BLOCKSIZE ) ?
|
|
ASYNCSRC_FILE_BLOCKSIZE : lLength;
|
|
|
|
if ( !ReadFile(This->hFile,pBuf,(DWORD)lBlock,&dw,NULL) )
|
|
{
|
|
hr = E_FAIL;
|
|
break;
|
|
}
|
|
pBuf += dw;
|
|
lReturned += (LONG)dw;
|
|
lLength -= (LONG)dw;
|
|
if ( lBlock > (LONG)dw )
|
|
break;
|
|
}
|
|
|
|
*plReturned = lReturned;
|
|
|
|
return hr;
|
|
}
|
|
|
|
static const struct AsyncSourceHandlers asyncsrc_file =
|
|
{
|
|
AsyncSourceFileImpl_Load,
|
|
AsyncSourceFileImpl_Cleanup,
|
|
AsyncSourceFileImpl_GetLength,
|
|
AsyncSourceFileImpl_Read,
|
|
};
|
|
|
|
HRESULT QUARTZ_CreateAsyncReader(IUnknown* punkOuter,void** ppobj)
|
|
{
|
|
return QUARTZ_CreateAsyncSource(
|
|
punkOuter, ppobj,
|
|
&CLSID_AsyncReader,
|
|
QUARTZ_wszAsyncFileSourceName,
|
|
QUARTZ_wszAsyncFileSourcePinName,
|
|
&asyncsrc_file );
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
* Implements URL Source.
|
|
*
|
|
*/
|
|
|
|
typedef struct AsyncSourceURLImpl
|
|
{
|
|
DWORD dwDummy;
|
|
} AsyncSourceURLImpl;
|
|
|
|
|
|
static HRESULT AsyncSourceURLImpl_Load( CAsyncSourceImpl* pImpl, LPCWSTR lpwszSourceName )
|
|
{
|
|
AsyncSourceURLImpl* This = (AsyncSourceURLImpl*)pImpl->m_pUserData;
|
|
|
|
FIXME("(%p,%p) stub!\n", pImpl, lpwszSourceName);
|
|
|
|
if ( This != NULL )
|
|
return E_UNEXPECTED;
|
|
This = (AsyncSourceURLImpl*)QUARTZ_AllocMem( sizeof(AsyncSourceURLImpl) );
|
|
pImpl->m_pUserData = (void*)This;
|
|
if ( This == NULL )
|
|
return E_OUTOFMEMORY;
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT AsyncSourceURLImpl_Cleanup( CAsyncSourceImpl* pImpl )
|
|
{
|
|
AsyncSourceURLImpl* This = (AsyncSourceURLImpl*)pImpl->m_pUserData;
|
|
|
|
FIXME("(%p) stub!\n", This);
|
|
|
|
if ( This == NULL )
|
|
return NOERROR;
|
|
|
|
QUARTZ_FreeMem(This);
|
|
pImpl->m_pUserData = NULL;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
static HRESULT AsyncSourceURLImpl_GetLength( CAsyncSourceImpl* pImpl, LONGLONG* pllTotal, LONGLONG* pllAvailable )
|
|
{
|
|
AsyncSourceURLImpl* This = (AsyncSourceURLImpl*)pImpl->m_pUserData;
|
|
|
|
FIXME("(%p,%p,%p) stub!\n", This, pllTotal, pllAvailable);
|
|
|
|
if ( This == NULL )
|
|
return E_UNEXPECTED;
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT AsyncSourceURLImpl_Read( CAsyncSourceImpl* pImpl, LONGLONG llOfsStart, LONG lLength, BYTE* pBuf, LONG* plReturned, HANDLE hEventCancel )
|
|
{
|
|
AsyncSourceURLImpl* This = (AsyncSourceURLImpl*)pImpl->m_pUserData;
|
|
|
|
FIXME("(%p) stub!\n", This);
|
|
|
|
if ( This == NULL )
|
|
return E_UNEXPECTED;
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static const struct AsyncSourceHandlers asyncsrc_url =
|
|
{
|
|
AsyncSourceURLImpl_Load,
|
|
AsyncSourceURLImpl_Cleanup,
|
|
AsyncSourceURLImpl_GetLength,
|
|
AsyncSourceURLImpl_Read,
|
|
};
|
|
|
|
|
|
HRESULT QUARTZ_CreateURLReader(IUnknown* punkOuter,void** ppobj)
|
|
{
|
|
return QUARTZ_CreateAsyncSource(
|
|
punkOuter, ppobj,
|
|
&CLSID_URLReader,
|
|
QUARTZ_wszAsyncURLSourceName,
|
|
QUARTZ_wszAsyncURLSourcePinName,
|
|
&asyncsrc_url );
|
|
}
|