| /* |
| * 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 ); |
| } |