Sweden-Number/dlls/quartz/asyncsrc.c

1369 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;
if ( lLength > IMediaSample_GetSize(pSample) )
{
FIXME("invalid length\n");
return E_FAIL;
}
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 );
}