diff --git a/dlls/quartz/Makefile.in b/dlls/quartz/Makefile.in index dd9a5d429a9..20756447b05 100644 --- a/dlls/quartz/Makefile.in +++ b/dlls/quartz/Makefile.in @@ -10,6 +10,7 @@ SYMBOLFILE = $(MODULE).tmp.o C_SRCS = \ amundoc.c \ + asyncsrc.c \ audren.c \ basefilt.c \ basepin.c \ @@ -34,10 +35,13 @@ C_SRCS = \ main.c \ memalloc.c \ mtype.c \ + parser.c \ regsvr.c \ sample.c \ seekpass.c \ - sysclock.c + sysclock.c \ + vidren.c \ + wavparse.c @MAKE_DLL_RULES@ diff --git a/dlls/quartz/asyncsrc.c b/dlls/quartz/asyncsrc.c new file mode 100644 index 00000000000..a5cd0d0d6a1 --- /dev/null +++ b/dlls/quartz/asyncsrc.c @@ -0,0 +1,840 @@ +/* + * Implements Asynchronous File/URL Source. + * + * FIXME - not work yet. + * + * hidenori@a2.ctktv.ne.jp + */ + +#include "config.h" + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winerror.h" +#include "wine/obj_base.h" +#include "strmif.h" +#include "vfwmsgs.h" +#include "uuids.h" + +#include "debugtools.h" +DEFAULT_DEBUG_CHANNEL(quartz); + +#include "quartz_private.h" +#include "asyncsrc.h" +#include "memalloc.h" + + +/*************************************************************************** + * + * CAsyncReaderImpl internal methods + * + */ + +static DWORD WINAPI +CAsyncReaderImpl_ThreadEntry( LPVOID pv ) +{ + CAsyncReaderImpl* This = (CAsyncReaderImpl*)pv; + HANDLE hWaitEvents[2]; + HANDLE hReadEvents[2]; + DWORD dwRes; + + SetEvent( This->m_hEventInit ); + + hWaitEvents[0] = This->m_hEventReqQueued; + hWaitEvents[1] = This->m_hEventAbort; + + hReadEvents[0] = This->m_hEventSampQueued; + hReadEvents[1] = This->m_hEventAbort; + + while ( 1 ) + { + dwRes = WaitForMultipleObjects(2,hWaitEvents,FALSE,INFINITE); + if ( dwRes != WAIT_OBJECT_0 ) + break; + + /* FIXME - process a queued request */ + + dwRes = WaitForMultipleObjects(2,hReadEvents,FALSE,INFINITE); + if ( dwRes != WAIT_OBJECT_0 ) + break; + } + + return 0; +} + +static HRESULT +CAsyncReaderImpl_BeginThread( CAsyncReaderImpl* This ) +{ + DWORD dwRes; + DWORD dwThreadId; + HANDLE hEvents[2]; + + if ( This->m_hEventInit != (HANDLE)NULL || + This->m_hEventAbort != (HANDLE)NULL || + This->m_hEventReqQueued != (HANDLE)NULL || + This->m_hEventSampQueued != (HANDLE)NULL || + This->m_hEventCompletion != (HANDLE)NULL || + This->m_hThread != (HANDLE)NULL ) + return E_UNEXPECTED; + + This->m_hEventInit = CreateEventA(NULL,TRUE,FALSE,NULL); + if ( This->m_hEventInit == (HANDLE)NULL ) + return E_OUTOFMEMORY; + This->m_hEventAbort = CreateEventA(NULL,TRUE,FALSE,NULL); + if ( This->m_hEventAbort == (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; + This->m_hEventCompletion = CreateEventA(NULL,TRUE,FALSE,NULL); + if ( This->m_hEventCompletion == (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 ) + { + SetEvent( This->m_hEventAbort ); + + WaitForSingleObject( This->m_hThread, INFINITE ); + 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_hEventAbort != (HANDLE)NULL ) + { + CloseHandle( This->m_hEventAbort ); + This->m_hEventAbort = (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; + } + if ( This->m_hEventCompletion != (HANDLE)NULL ) + { + CloseHandle( This->m_hEventCompletion ); + This->m_hEventCompletion = (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); + + FIXME("(%p)->() stub!\n",This); + + EnterCriticalSection( This->pcsReader ); + LeaveCriticalSection( This->pcsReader ); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +CAsyncReaderImpl_fnWaitForNext(IAsyncReader* iface,DWORD dwTimeout,IMediaSample** pSample,DWORD_PTR* pdwContext) +{ + ICOM_THIS(CAsyncReaderImpl,iface); + + FIXME("(%p)->() stub!\n",This); + + EnterCriticalSection( This->pcsReader ); + LeaveCriticalSection( This->pcsReader ); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +CAsyncReaderImpl_fnSyncReadAligned(IAsyncReader* iface,IMediaSample* pSample) +{ + ICOM_THIS(CAsyncReaderImpl,iface); + + FIXME("(%p)->() stub!\n",This); + + EnterCriticalSection( This->pcsReader ); + LeaveCriticalSection( This->pcsReader ); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +CAsyncReaderImpl_fnSyncRead(IAsyncReader* iface,LONGLONG llPosStart,LONG lLength,BYTE* pbBuf) +{ + ICOM_THIS(CAsyncReaderImpl,iface); + + FIXME("(%p)->() stub!\n",This); + + EnterCriticalSection( This->pcsReader ); + LeaveCriticalSection( This->pcsReader ); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +CAsyncReaderImpl_fnLength(IAsyncReader* iface,LONGLONG* pllTotal,LONGLONG* pllAvailable) +{ + ICOM_THIS(CAsyncReaderImpl,iface); + HRESULT hr; + + TRACE("(%p)->()\n",This); + + EnterCriticalSection( This->pcsReader ); + hr = This->pSource->m_pHandler->pGetLength( This->pSource, pllTotal, pllAvailable ); + LeaveCriticalSection( This->pcsReader ); + + return hr; +} + +static HRESULT WINAPI +CAsyncReaderImpl_fnBeginFlush(IAsyncReader* iface) +{ + ICOM_THIS(CAsyncReaderImpl,iface); + + FIXME("(%p)->() stub!\n",This); + + EnterCriticalSection( This->pcsReader ); + LeaveCriticalSection( This->pcsReader ); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +CAsyncReaderImpl_fnEndFlush(IAsyncReader* iface) +{ + ICOM_THIS(CAsyncReaderImpl,iface); + + FIXME("(%p)->() stub!\n",This); + + EnterCriticalSection( This->pcsReader ); + LeaveCriticalSection( This->pcsReader ); + + return E_NOTIMPL; +} + + +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, + CRITICAL_SECTION* pcsReader ) +{ + 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->pcsReader = pcsReader; + This->m_hEventInit = (HANDLE)NULL; + This->m_hEventAbort = (HANDLE)NULL; + This->m_hEventReqQueued = (HANDLE)NULL; + This->m_hEventSampQueued = (HANDLE)NULL; + This->m_hEventCompletion = (HANDLE)NULL; + This->m_hThread = (HANDLE)NULL; + + return NOERROR; +} + +void CAsyncReaderImpl_UninitIAsyncReader( + CAsyncReaderImpl* This ) +{ + TRACE("(%p)\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; + + 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); + + This->bAsyncReaderQueried = FALSE; + + return NOERROR; +} + +static HRESULT CAsyncSourcePinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin ) +{ + CAsyncSourcePinImpl_THIS(pImpl,pin); + + if ( !This->bAsyncReaderQueried ) + return E_FAIL; + + return NOERROR; +} + +static HRESULT CAsyncSourcePinImpl_OnDisconnect( CPinBaseImpl* pImpl ) +{ + CAsyncSourcePinImpl_THIS(pImpl,pin); + + 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 = S_OK; + + 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 ) ) + { + *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, + &pFilter->basefilter, + pwszPinName, + TRUE, + &outputpinhandlers ); + + if ( SUCCEEDED(hr) ) + { + hr = CAsyncReaderImpl_InitIAsyncReader( + &This->async, + This->unk.punkControl, + pFilter, + pcsPin ); + 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; +} + diff --git a/dlls/quartz/asyncsrc.h b/dlls/quartz/asyncsrc.h new file mode 100644 index 00000000000..57e769d5ffe --- /dev/null +++ b/dlls/quartz/asyncsrc.h @@ -0,0 +1,115 @@ +/* + * Implements Asynchronous File/URL Source. + * + * hidenori@a2.ctktv.ne.jp + */ + +#ifndef WINE_DSHOW_ASYNCSRC_H +#define WINE_DSHOW_ASYNCSRC_H + +#include "iunk.h" +#include "basefilt.h" + +typedef struct CAsyncSourceImpl CAsyncSourceImpl; +typedef struct CAsyncSourcePinImpl CAsyncSourcePinImpl; +typedef struct AsyncSourceHandlers AsyncSourceHandlers; + +typedef struct CAsyncReaderImpl +{ + ICOM_VFIELD(IAsyncReader); + + /* IUnknown fields */ + IUnknown* punkControl; + /* IAsyncReader fields */ + CAsyncSourceImpl* pSource; + + CRITICAL_SECTION* pcsReader; + HANDLE m_hEventInit; + HANDLE m_hEventAbort; + HANDLE m_hEventReqQueued; + HANDLE m_hEventSampQueued; + HANDLE m_hEventCompletion; + HANDLE m_hThread; +} CAsyncReaderImpl; + +typedef struct CFileSourceFilterImpl +{ + ICOM_VFIELD(IFileSourceFilter); + + /* IUnknown fields */ + IUnknown* punkControl; + /* IFileSourceFilter fields */ + CAsyncSourceImpl* pSource; + + CRITICAL_SECTION* pcsFileSource; + WCHAR* m_pwszFileName; + DWORD m_cbFileName; + AM_MEDIA_TYPE m_mt; +} CFileSourceFilterImpl; + +struct CAsyncSourceImpl +{ + QUARTZ_IUnkImpl unk; + CBaseFilterImpl basefilter; + CFileSourceFilterImpl filesrc; + + CRITICAL_SECTION csFilter; + CAsyncSourcePinImpl* pPin; + const AsyncSourceHandlers* m_pHandler; + void* m_pUserData; +}; + +struct CAsyncSourcePinImpl +{ + QUARTZ_IUnkImpl unk; + CPinBaseImpl pin; + CAsyncReaderImpl async; + QUARTZ_IFDelegation qiext; + + BOOL bAsyncReaderQueried; + CAsyncSourceImpl* pSource; +}; + +struct AsyncSourceHandlers +{ + /* all handlers MUST be implemented. */ + HRESULT (*pLoad)( CAsyncSourceImpl* pImpl, LPCWSTR lpwszSourceName ); + HRESULT (*pCleanup)( CAsyncSourceImpl* pImpl ); + HRESULT (*pGetLength)( CAsyncSourceImpl* pImpl, LONGLONG* pllTotal, LONGLONG* pllAvailable ); + HRESULT (*pReadAsync)( CAsyncSourceImpl* pImpl, LONGLONG llOfsStart, LONG lLength, BYTE* pBuf, HANDLE hEventCompletion ); + HRESULT (*pGetResult)( CAsyncSourceImpl* pImpl, LONG* plReturned ); + HRESULT (*pCancelAsync)( CAsyncSourceImpl* pImpl ); +}; + +#define CAsyncSourceImpl_THIS(iface,member) CAsyncSourceImpl* This = ((CAsyncSourceImpl*)(((char*)iface)-offsetof(CAsyncSourceImpl,member))) +#define CAsyncSourcePinImpl_THIS(iface,member) CAsyncSourcePinImpl* This = ((CAsyncSourcePinImpl*)(((char*)iface)-offsetof(CAsyncSourcePinImpl,member))) + + +HRESULT CAsyncReaderImpl_InitIAsyncReader( + CAsyncReaderImpl* This, IUnknown* punkControl, + CAsyncSourceImpl* pSource, + CRITICAL_SECTION* pcsReader ); +void CAsyncReaderImpl_UninitIAsyncReader( + CAsyncReaderImpl* This ); +HRESULT CFileSourceFilterImpl_InitIFileSourceFilter( + CFileSourceFilterImpl* This, IUnknown* punkControl, + CAsyncSourceImpl* pSource, + CRITICAL_SECTION* pcsFileSource ); +void CFileSourceFilterImpl_UninitIFileSourceFilter( + CFileSourceFilterImpl* This ); + + +HRESULT QUARTZ_CreateAsyncSource( + IUnknown* punkOuter,void** ppobj, + const CLSID* pclsidAsyncSource, + LPCWSTR pwszAsyncSourceName, + LPCWSTR pwszOutPinName, + const AsyncSourceHandlers* pHandler ); +HRESULT QUARTZ_CreateAsyncSourcePin( + CAsyncSourceImpl* pFilter, + CRITICAL_SECTION* pcsPin, + CAsyncSourcePinImpl** ppPin, + LPCWSTR pwszPinName ); + + +#endif /* WINE_DSHOW_ASYNCSRC_H */ diff --git a/dlls/quartz/audren.c b/dlls/quartz/audren.c index 0a1810377a2..50e613ea5b3 100644 --- a/dlls/quartz/audren.c +++ b/dlls/quartz/audren.c @@ -22,6 +22,7 @@ #include "control.h" #include "vfwmsgs.h" #include "uuids.h" +#include "evcode.h" #include "debugtools.h" DEFAULT_DEBUG_CHANNEL(quartz); @@ -365,6 +366,7 @@ static const CBaseFilterHandlers filterhandlers = { CAudioRendererImpl_OnActive, /* pOnActive */ CAudioRendererImpl_OnInactive, /* pOnInactive */ + NULL, /* pOnStop */ }; /*************************************************************************** @@ -378,7 +380,7 @@ static HRESULT CAudioRendererPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const CAudioRendererPinImpl_THIS(pImpl,pin); const WAVEFORMATEX* pwfx; - TRACE( "(%p,%p)\n",This,pmt ); + TRACE("(%p,%p)\n",This,pmt); if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Audio ) ) return E_FAIL; @@ -463,9 +465,11 @@ static HRESULT CAudioRendererPinImpl_EndOfStream( CPinBaseImpl* pImpl ) FIXME( "(%p)\n", This ); This->pRender->m_fInFlush = FALSE; - /* IMediaEventSink::Notify(EC_COMPLETE) */ - return NOERROR; + /* FIXME - don't notify twice until stopped or seeked. */ + return CBaseFilterImpl_MediaEventNotify( + &This->pRender->basefilter, EC_COMPLETE, + (LONG_PTR)S_OK, (LONG_PTR)(IBaseFilter*)(This->pRender) ); } static HRESULT CAudioRendererPinImpl_BeginFlush( CPinBaseImpl* pImpl ) @@ -497,11 +501,16 @@ static HRESULT CAudioRendererPinImpl_NewSegment( CPinBaseImpl* pImpl, REFERENCE_ FIXME( "(%p)\n", This ); + This->pRender->m_fInFlush = FALSE; + return NOERROR; } static const CBasePinHandlers pinhandlers = { + NULL, /* pOnPreConnect */ + NULL, /* pOnPostConnect */ + NULL, /* pOnDisconnect */ CAudioRendererPinImpl_CheckMediaType, /* pCheckMediaType */ NULL, /* pQualityNotify */ CAudioRendererPinImpl_Receive, /* pReceive */ diff --git a/dlls/quartz/basefilt.c b/dlls/quartz/basefilt.c index ef1d57ee5e1..c2db042325b 100644 --- a/dlls/quartz/basefilt.c +++ b/dlls/quartz/basefilt.c @@ -23,6 +23,13 @@ DEFAULT_DEBUG_CHANNEL(quartz); #include "basefilt.h" #include "enumunk.h" + +/*************************************************************************** + * + * CBaseFilterImpl::IBaseFilter + * + */ + static HRESULT WINAPI CBaseFilterImpl_fnQueryInterface(IBaseFilter* iface,REFIID riid,void** ppobj) { @@ -85,10 +92,17 @@ CBaseFilterImpl_fnStop(IBaseFilter* iface) { if ( This->pHandlers->pOnInactive != NULL ) hr = This->pHandlers->pOnInactive( This ); + if ( SUCCEEDED(hr) ) + This->fstate = State_Paused; + } + if ( This->fstate == State_Paused ) + { + if ( This->pHandlers->pOnStop != NULL ) + hr = This->pHandlers->pOnStop( This ); + if ( SUCCEEDED(hr) ) + This->fstate = State_Stopped; } - if ( SUCCEEDED(hr) ) - This->fstate = State_Stopped; LeaveCriticalSection( &This->csFilter ); return hr; @@ -105,16 +119,13 @@ CBaseFilterImpl_fnPause(IBaseFilter* iface) hr = NOERROR; EnterCriticalSection( &This->csFilter ); - - if ( This->fstate == State_Running ) + if ( This->fstate != State_Paused ) { if ( This->pHandlers->pOnInactive != NULL ) hr = This->pHandlers->pOnInactive( This ); + if ( SUCCEEDED(hr) ) + This->fstate = State_Paused; } - - if ( SUCCEEDED(hr) ) - This->fstate = State_Paused; - LeaveCriticalSection( &This->csFilter ); TRACE("hr = %08lx\n",hr); @@ -136,15 +147,21 @@ CBaseFilterImpl_fnRun(IBaseFilter* iface,REFERENCE_TIME rtStart) This->rtStart = rtStart; - if ( This->fstate != State_Running ) + if ( This->fstate == State_Stopped ) + { + if ( This->pHandlers->pOnInactive != NULL ) + hr = This->pHandlers->pOnInactive( This ); + if ( SUCCEEDED(hr) ) + This->fstate = State_Paused; + } + if ( This->fstate == State_Paused ) { if ( This->pHandlers->pOnActive != NULL ) hr = This->pHandlers->pOnActive( This ); + if ( SUCCEEDED(hr) ) + This->fstate = State_Running; } - if ( SUCCEEDED(hr) ) - This->fstate = State_Running; - LeaveCriticalSection( &This->csFilter ); return hr; @@ -366,6 +383,11 @@ CBaseFilterImpl_fnQueryVendorInfo(IBaseFilter* iface,LPWSTR* lpwszVendor) } +/*************************************************************************** + * + * construct/destruct CBaseFilterImpl + * + */ static ICOM_VTABLE(IBaseFilter) ibasefilter = { @@ -491,3 +513,41 @@ void CBaseFilterImpl_UninitIBaseFilter( CBaseFilterImpl* This ) DeleteCriticalSection( &This->csFilter ); } + +/*************************************************************************** + * + * CBaseFilterImpl methods + * + */ + +HRESULT CBaseFilterImpl_MediaEventNotify( + CBaseFilterImpl* This, long lEvent,LONG_PTR lParam1,LONG_PTR lParam2) +{ + IMediaEventSink* pSink = NULL; + HRESULT hr = E_NOTIMPL; + + EnterCriticalSection( &This->csFilter ); + + if ( This->pfg == NULL ) + { + hr = E_UNEXPECTED; + goto err; + } + + hr = IFilterGraph_QueryInterface( This->pfg, &IID_IMediaEventSink, (void**)&pSink ); + if ( FAILED(hr) ) + goto err; + if ( pSink == NULL ) + { + hr = E_FAIL; + goto err; + } + + hr = IMediaEventSink_Notify(pSink,lEvent,lParam1,lParam2); + IMediaEventSink_Release(pSink); +err: + LeaveCriticalSection( &This->csFilter ); + + return hr; +} + diff --git a/dlls/quartz/basefilt.h b/dlls/quartz/basefilt.h index fe41a98f602..cee374287a7 100644 --- a/dlls/quartz/basefilt.h +++ b/dlls/quartz/basefilt.h @@ -44,6 +44,7 @@ struct CBaseFilterHandlers { HRESULT (*pOnActive)( CBaseFilterImpl* pImpl ); HRESULT (*pOnInactive)( CBaseFilterImpl* pImpl ); + HRESULT (*pOnStop)( CBaseFilterImpl* pImpl ); }; @@ -54,12 +55,18 @@ HRESULT CBaseFilterImpl_InitIBaseFilter( void CBaseFilterImpl_UninitIBaseFilter( CBaseFilterImpl* This ); +HRESULT CBaseFilterImpl_MediaEventNotify( + CBaseFilterImpl* This, long lEvent,LONG_PTR lParam1,LONG_PTR lParam2); + + /* * Implements IPin, IMemInputPin, and IQualityControl. (internal) * * a base class for implementing IPin. */ +typedef struct OutputPinAsyncImpl OutputPinAsyncImpl; + typedef struct CPinBaseImpl { /* IPin */ @@ -80,7 +87,9 @@ typedef struct CPinBaseImpl CRITICAL_SECTION* pcsPin; CBaseFilterImpl* pFilter; IPin* pPinConnectedTo; + IMemInputPin* pMemInputPinConnectedTo; AM_MEDIA_TYPE* pmtConn; + OutputPinAsyncImpl* pAsyncOut; /* for asynchronous output */ } CPinBaseImpl; typedef struct CMemInputPinBaseImpl @@ -111,6 +120,9 @@ typedef struct CQualityControlPassThruImpl struct CBasePinHandlers { + HRESULT (*pOnPreConnect)( CPinBaseImpl* pImpl, IPin* pPin ); + HRESULT (*pOnPostConnect)( CPinBaseImpl* pImpl, IPin* pPin ); + HRESULT (*pOnDisconnect)( CPinBaseImpl* pImpl ); HRESULT (*pCheckMediaType)( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt ); HRESULT (*pQualityNotify)( CPinBaseImpl* pImpl, IBaseFilter* pFilter, Quality q ); HRESULT (*pReceive)( CPinBaseImpl* pImpl, IMediaSample* pSample ); @@ -146,5 +158,41 @@ void CQualityControlPassThruImpl_UninitIQualityControl( CQualityControlPassThruImpl* This ); +HRESULT CPinBaseImpl_SendSample( CPinBaseImpl* This, IMediaSample* pSample ); +HRESULT CPinBaseImpl_SendEndOfStream( CPinBaseImpl* This ); +HRESULT CPinBaseImpl_SendBeginFlush( CPinBaseImpl* This ); +HRESULT CPinBaseImpl_SendEndFlush( CPinBaseImpl* This ); +HRESULT CPinBaseImpl_SendNewSegment( CPinBaseImpl* This, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate ); + + +/*************************************************************************** + * + * handlers for output pins. + * + */ + +HRESULT OutputPinSync_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample ); +HRESULT OutputPinSync_ReceiveCanBlock( CPinBaseImpl* pImpl ); +HRESULT OutputPinSync_EndOfStream( CPinBaseImpl* pImpl ); +HRESULT OutputPinSync_BeginFlush( CPinBaseImpl* pImpl ); +HRESULT OutputPinSync_EndFlush( CPinBaseImpl* pImpl ); +HRESULT OutputPinSync_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate ); + +/*************************************************************************** + * + * handlers for output pins (async). + * + */ + +HRESULT OutputPinAsync_OnActive( CPinBaseImpl* pImpl ); +HRESULT OutputPinAsync_OnInactive( CPinBaseImpl* pImpl ); +HRESULT OutputPinAsync_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample ); +HRESULT OutputPinAsync_ReceiveCanBlock( CPinBaseImpl* pImpl ); +HRESULT OutputPinAsync_EndOfStream( CPinBaseImpl* pImpl ); +HRESULT OutputPinAsync_BeginFlush( CPinBaseImpl* pImpl ); +HRESULT OutputPinAsync_EndFlush( CPinBaseImpl* pImpl ); +HRESULT OutputPinAsync_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate ); + + #endif /* WINE_DSHOW_BASEFILT_H */ diff --git a/dlls/quartz/basepin.c b/dlls/quartz/basepin.c index 25711353453..1f809b7b3e3 100644 --- a/dlls/quartz/basepin.c +++ b/dlls/quartz/basepin.c @@ -71,9 +71,11 @@ CPinBaseImpl_fnConnect(IPin* iface,IPin* pPin,const AM_MEDIA_TYPE* pmt) if ( !This->bOutput ) return E_UNEXPECTED; - if ( pPin == NULL || pmt == NULL ) + if ( pPin == NULL ) return E_POINTER; + TRACE("try to connect to %p\n",pPin); + EnterCriticalSection( This->pcsPin ); if ( This->pPinConnectedTo != NULL ) @@ -84,6 +86,13 @@ CPinBaseImpl_fnConnect(IPin* iface,IPin* pPin,const AM_MEDIA_TYPE* pmt) /* FIXME - return fail if running */ + if ( This->pHandlers->pOnPreConnect != NULL ) + { + hr = This->pHandlers->pOnPreConnect(This,pPin); + if ( FAILED(hr) ) + goto err; + } + if ( pmt != NULL ) { hr = IPin_QueryAccept(iface,pmt); @@ -113,9 +122,6 @@ CPinBaseImpl_fnConnect(IPin* iface,IPin* pPin,const AM_MEDIA_TYPE* pmt) goto err; } - if ( FAILED(hr) ) - goto err; - connected:; This->pmtConn = QUARTZ_MediaType_Duplicate( pmt ); if ( This->pmtConn == NULL ) @@ -124,11 +130,32 @@ connected:; IPin_Disconnect(pPin); goto err; } - hr = S_OK; This->pPinConnectedTo = pPin; IPin_AddRef(pPin); + hr = IPin_QueryInterface(pPin,&IID_IMemInputPin,(void**)&This->pMemInputPinConnectedTo); + if ( FAILED(hr) ) + { + IPin_Disconnect(pPin); + goto err; + } + + if ( This->pHandlers->pOnPostConnect != NULL ) + { + hr = This->pHandlers->pOnPostConnect(This,pPin); + if ( FAILED(hr) ) + { + IPin_Disconnect(pPin); + goto err; + } + } + + hr = S_OK; err: + if ( FAILED(hr) ) + { + IPin_Disconnect(iface); + } LeaveCriticalSection( This->pcsPin ); return hr; @@ -157,6 +184,12 @@ CPinBaseImpl_fnReceiveConnection(IPin* iface,IPin* pPin,const AM_MEDIA_TYPE* pmt /* FIXME - return fail if running */ + if ( This->pHandlers->pOnPreConnect != NULL ) + { + hr = This->pHandlers->pOnPreConnect(This,pPin); + if ( FAILED(hr) ) + goto err; + } hr = IPin_QueryAccept(iface,pmt); if ( FAILED(hr) ) @@ -168,10 +201,20 @@ CPinBaseImpl_fnReceiveConnection(IPin* iface,IPin* pPin,const AM_MEDIA_TYPE* pmt hr = E_OUTOFMEMORY; goto err; } - hr = S_OK; + if ( This->pHandlers->pOnPostConnect != NULL ) + { + hr = This->pHandlers->pOnPostConnect(This,pPin); + if ( FAILED(hr) ) + goto err; + } + + hr = S_OK; This->pPinConnectedTo = pPin; IPin_AddRef(pPin); + err: + if ( FAILED(hr) ) + IPin_Disconnect(iface); LeaveCriticalSection( This->pcsPin ); return hr; @@ -189,16 +232,23 @@ CPinBaseImpl_fnDisconnect(IPin* iface) /* FIXME - return fail if running */ + if ( This->pHandlers->pOnDisconnect != NULL ) + hr = This->pHandlers->pOnDisconnect(This); + + if ( This->pmtConn != NULL ) + { + QUARTZ_MediaType_Destroy( This->pmtConn ); + This->pmtConn = NULL; + } + if ( This->pMemInputPinConnectedTo != NULL ) + { + IMemInputPin_Release(This->pMemInputPinConnectedTo); + This->pMemInputPinConnectedTo = NULL; + } if ( This->pPinConnectedTo != NULL ) { /* FIXME - cleanup */ - if ( This->pmtConn != NULL ) - { - QUARTZ_MediaType_Destroy( This->pmtConn ); - This->pmtConn = NULL; - } - IPin_Release(This->pPinConnectedTo); This->pPinConnectedTo = NULL; hr = NOERROR; @@ -517,7 +567,9 @@ HRESULT CPinBaseImpl_InitIPin( This->pcsPin = pcsPin; This->pFilter = pFilter; This->pPinConnectedTo = NULL; + This->pMemInputPinConnectedTo = NULL; This->pmtConn = NULL; + This->pAsyncOut = NULL; This->pwszId = (WCHAR*)QUARTZ_AllocMem( This->cbIdLen ); if ( This->pwszId == NULL ) @@ -877,3 +929,463 @@ void CQualityControlPassThruImpl_UninitIQualityControl( { } +/*************************************************************************** + * + * helper methods for output pins. + * + */ + +HRESULT CPinBaseImpl_SendSample( CPinBaseImpl* This, IMediaSample* pSample ) +{ + if ( This->pHandlers->pReceive == NULL ) + return E_NOTIMPL; + + return This->pHandlers->pReceive( This, pSample ); +} + +HRESULT CPinBaseImpl_SendEndOfStream( CPinBaseImpl* This ) +{ + if ( This->pHandlers->pEndOfStream == NULL ) + return E_NOTIMPL; + + return This->pHandlers->pEndOfStream( This ); +} + +HRESULT CPinBaseImpl_SendBeginFlush( CPinBaseImpl* This ) +{ + if ( This->pHandlers->pBeginFlush == NULL ) + return E_NOTIMPL; + + return This->pHandlers->pBeginFlush( This ); +} + +HRESULT CPinBaseImpl_SendEndFlush( CPinBaseImpl* This ) +{ + if ( This->pHandlers->pEndFlush == NULL ) + return E_NOTIMPL; + + return This->pHandlers->pEndFlush( This ); +} + +HRESULT CPinBaseImpl_SendNewSegment( CPinBaseImpl* This, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate ) +{ + if ( This->pHandlers->pNewSegment == NULL ) + return E_NOTIMPL; + + return This->pHandlers->pNewSegment( This, rtStart, rtStop, rate ); +} + + + +/*************************************************************************** + * + * handlers for output pins. + * + */ + +HRESULT OutputPinSync_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample ) +{ + if ( pImpl->pMemInputPinConnectedTo == NULL ) + return E_UNEXPECTED; + + return IMemInputPin_Receive(pImpl->pMemInputPinConnectedTo,pSample); +} + +HRESULT OutputPinSync_ReceiveCanBlock( CPinBaseImpl* pImpl ) +{ + if ( pImpl->pMemInputPinConnectedTo == NULL ) + return S_FALSE; + + return IMemInputPin_ReceiveCanBlock(pImpl->pMemInputPinConnectedTo); +} + +HRESULT OutputPinSync_EndOfStream( CPinBaseImpl* pImpl ) +{ + if ( pImpl->pPinConnectedTo == NULL ) + return NOERROR; + + return IPin_EndOfStream(pImpl->pPinConnectedTo); +} + +HRESULT OutputPinSync_BeginFlush( CPinBaseImpl* pImpl ) +{ + if ( pImpl->pPinConnectedTo == NULL ) + return NOERROR; + + return IPin_BeginFlush(pImpl->pPinConnectedTo); +} + +HRESULT OutputPinSync_EndFlush( CPinBaseImpl* pImpl ) +{ + if ( pImpl->pPinConnectedTo == NULL ) + return NOERROR; + + return IPin_EndFlush(pImpl->pPinConnectedTo); +} + +HRESULT OutputPinSync_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate ) +{ + if ( pImpl->pPinConnectedTo == NULL ) + return NOERROR; + + return IPin_NewSegment(pImpl->pPinConnectedTo,rtStart,rtStop,rate); +} + +/*************************************************************************** + * + * handlers for output pins (async). + * + */ + +typedef struct OutputPinTask OutputPinTask; + +enum OutputPinTaskType +{ + OutTask_ExitThread, + OutTask_Receive, + OutTask_EndOfStream, + OutTask_BeginFlush, + OutTask_EndFlush, + OutTask_NewSegment, +}; + +struct OutputPinTask +{ + OutputPinTask* pNext; + enum OutputPinTaskType tasktype; + IMediaSample* pSample; + REFERENCE_TIME rtStart; + REFERENCE_TIME rtStop; + double rate; +}; + +struct OutputPinAsyncImpl +{ + HANDLE m_hTaskThread; + HANDLE m_hTaskEvent; + IPin* m_pPin; /* connected pin */ + IMemInputPin* m_pMemInputPin; /* connected pin */ + CRITICAL_SECTION m_csTasks; + OutputPinTask* m_pFirst; + OutputPinTask* m_pLast; + OutputPinTask* m_pTaskExitThread; +}; + +static OutputPinTask* OutputPinAsync_AllocTask( enum OutputPinTaskType tasktype ) +{ + OutputPinTask* pTask; + + pTask = (OutputPinTask*)QUARTZ_AllocMem( sizeof(OutputPinTask) ); + pTask->pNext = NULL; + pTask->tasktype = tasktype; + pTask->pSample = NULL; + + return pTask; +} + +static void OutputPinAsync_FreeTask( OutputPinTask* pTask ) +{ + if ( pTask->pSample != NULL ) + IMediaSample_Release( pTask->pSample ); + QUARTZ_FreeMem( pTask ); +} + +static void OutputPinAsync_AddTask( OutputPinAsyncImpl* This, OutputPinTask* pTask, BOOL bFirst ) +{ + EnterCriticalSection( &This->m_csTasks ); + + if ( bFirst ) + { + pTask->pNext = This->m_pFirst; + This->m_pFirst = pTask; + if ( This->m_pLast == NULL ) + This->m_pLast = pTask; + } + else + { + if ( This->m_pLast != NULL ) + This->m_pLast->pNext = pTask; + else + This->m_pFirst = pTask; + This->m_pLast = pTask; + } + + LeaveCriticalSection( &This->m_csTasks ); + + SetEvent( This->m_hTaskEvent ); +} + +static OutputPinTask* OutputPinAsync_GetNextTask( OutputPinAsyncImpl* This ) +{ + OutputPinTask* pTask; + + EnterCriticalSection( &This->m_csTasks ); + pTask = This->m_pFirst; + if ( pTask != NULL ) + { + This->m_pFirst = pTask->pNext; + if ( This->m_pFirst == NULL ) + This->m_pLast = NULL; + else + SetEvent( This->m_hTaskEvent ); + } + + LeaveCriticalSection( &This->m_csTasks ); + + return pTask; +} + +static DWORD WINAPI OutputPinAsync_ThreadEntry( LPVOID pv ) +{ + OutputPinAsyncImpl* This = ((CPinBaseImpl*)pv)->pAsyncOut; + OutputPinTask* pTask; + BOOL bLoop = TRUE; + BOOL bInFlush = FALSE; + HRESULT hr; + + while ( bLoop ) + { + WaitForSingleObject( This->m_hTaskEvent, INFINITE ); + ResetEvent( This->m_hTaskEvent ); + + pTask = OutputPinAsync_GetNextTask( This ); + if ( pTask == NULL ) + continue; + + hr = S_OK; + switch ( pTask->tasktype ) + { + case OutTask_ExitThread: + bLoop = FALSE; + break; + case OutTask_Receive: + if ( !bInFlush ) + hr = IMemInputPin_Receive( This->m_pMemInputPin, pTask->pSample ); + break; + case OutTask_EndOfStream: + hr = IPin_EndOfStream( This->m_pPin ); + break; + case OutTask_BeginFlush: + bInFlush = TRUE; + hr = IPin_BeginFlush( This->m_pPin ); + break; + case OutTask_EndFlush: + bInFlush = FALSE; + hr = IPin_EndFlush( This->m_pPin ); + break; + case OutTask_NewSegment: + hr = IPin_NewSegment( This->m_pPin, pTask->rtStart, pTask->rtStop, pTask->rate ); + break; + default: + ERR( "unexpected task type %d.\n", pTask->tasktype ); + bLoop = FALSE; + break; + } + + OutputPinAsync_FreeTask( pTask ); + + if ( FAILED(hr) ) + { + ERR( "hresult %08lx\n", hr ); + bLoop = FALSE; + } + } + + return 0; +} + +HRESULT OutputPinAsync_OnActive( CPinBaseImpl* pImpl ) +{ + HRESULT hr; + DWORD dwThreadId; + + FIXME("(%p)\n",pImpl); + + if ( pImpl->pMemInputPinConnectedTo == NULL ) + return NOERROR; + + pImpl->pAsyncOut = (OutputPinAsyncImpl*) + QUARTZ_AllocMem( sizeof( OutputPinAsyncImpl ) ); + if ( pImpl->pAsyncOut == NULL ) + return E_OUTOFMEMORY; + + InitializeCriticalSection( &pImpl->pAsyncOut->m_csTasks ); + pImpl->pAsyncOut->m_hTaskThread = (HANDLE)NULL; + pImpl->pAsyncOut->m_hTaskEvent = (HANDLE)NULL; + pImpl->pAsyncOut->m_pFirst = NULL; + pImpl->pAsyncOut->m_pLast = NULL; + pImpl->pAsyncOut->m_pTaskExitThread = NULL; + pImpl->pAsyncOut->m_pPin = pImpl->pPinConnectedTo; + pImpl->pAsyncOut->m_pMemInputPin = pImpl->pMemInputPinConnectedTo; + + pImpl->pAsyncOut->m_hTaskEvent = + CreateEventA( NULL, TRUE, FALSE, NULL ); + if ( pImpl->pAsyncOut->m_hTaskEvent == (HANDLE)NULL ) + { + hr = E_FAIL; + goto err; + } + + pImpl->pAsyncOut->m_pTaskExitThread = + OutputPinAsync_AllocTask( OutTask_ExitThread ); + if ( pImpl->pAsyncOut->m_pTaskExitThread == NULL ) + { + hr = E_OUTOFMEMORY; + goto err; + } + + pImpl->pAsyncOut->m_hTaskThread = CreateThread( + NULL, 0, OutputPinAsync_ThreadEntry, pImpl, + 0, &dwThreadId ); + if ( pImpl->pAsyncOut->m_hTaskThread == (HANDLE)NULL ) + { + hr = E_FAIL; + goto err; + } + + return NOERROR; +err: + OutputPinAsync_OnInactive( pImpl ); + return hr; +} + +HRESULT OutputPinAsync_OnInactive( CPinBaseImpl* pImpl ) +{ + OutputPinTask* pTask; + + FIXME("(%p)\n",pImpl); + + if ( pImpl->pAsyncOut == NULL ) + return NOERROR; + + if ( pImpl->pAsyncOut->m_pTaskExitThread != NULL ) + { + OutputPinAsync_AddTask( pImpl->pAsyncOut, pImpl->pAsyncOut->m_pTaskExitThread, TRUE ); + pImpl->pAsyncOut->m_pTaskExitThread = NULL; + } + + if ( pImpl->pAsyncOut->m_hTaskThread != (HANDLE)NULL ) + { + WaitForSingleObject( pImpl->pAsyncOut->m_hTaskThread, INFINITE ); + CloseHandle( pImpl->pAsyncOut->m_hTaskThread ); + } + if ( pImpl->pAsyncOut->m_hTaskEvent != (HANDLE)NULL ) + CloseHandle( pImpl->pAsyncOut->m_hTaskEvent ); + + /* release all tasks. */ + while ( 1 ) + { + pTask = OutputPinAsync_GetNextTask( pImpl->pAsyncOut ); + if ( pTask == NULL ) + break; + OutputPinAsync_FreeTask( pTask ); + } + + DeleteCriticalSection( &pImpl->pAsyncOut->m_csTasks ); + + QUARTZ_FreeMem( pImpl->pAsyncOut ); + pImpl->pAsyncOut = NULL; + + return NOERROR; +} + +HRESULT OutputPinAsync_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample ) +{ + OutputPinAsyncImpl* This = pImpl->pAsyncOut; + OutputPinTask* pTask; + + TRACE("(%p,%p)\n",pImpl,pSample); + + if ( This == NULL ) + return NOERROR; + + pTask = OutputPinAsync_AllocTask( OutTask_Receive ); + if ( pTask == NULL ) + return E_OUTOFMEMORY; + pTask->pSample = pSample; IMediaSample_AddRef( pSample ); + OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE ); + + return NOERROR; +} + +HRESULT OutputPinAsync_ReceiveCanBlock( CPinBaseImpl* pImpl ) +{ + return S_FALSE; +} + +HRESULT OutputPinAsync_EndOfStream( CPinBaseImpl* pImpl ) +{ + OutputPinAsyncImpl* This = pImpl->pAsyncOut; + OutputPinTask* pTask; + + TRACE("(%p)\n",pImpl); + + if ( This == NULL ) + return NOERROR; + + pTask = OutputPinAsync_AllocTask( OutTask_EndOfStream ); + if ( pTask == NULL ) + return E_OUTOFMEMORY; + OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE ); + + return NOERROR; +} + +HRESULT OutputPinAsync_BeginFlush( CPinBaseImpl* pImpl ) +{ + OutputPinAsyncImpl* This = pImpl->pAsyncOut; + OutputPinTask* pTask; + + TRACE("(%p)\n",pImpl); + + if ( This == NULL ) + return NOERROR; + + pTask = OutputPinAsync_AllocTask( OutTask_BeginFlush ); + if ( pTask == NULL ) + return E_OUTOFMEMORY; + OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, TRUE ); + + return NOERROR; +} + +HRESULT OutputPinAsync_EndFlush( CPinBaseImpl* pImpl ) +{ + OutputPinAsyncImpl* This = pImpl->pAsyncOut; + OutputPinTask* pTask; + + TRACE("(%p)\n",pImpl); + + if ( This == NULL ) + return NOERROR; + + pTask = OutputPinAsync_AllocTask( OutTask_EndFlush ); + if ( pTask == NULL ) + return E_OUTOFMEMORY; + OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE ); + + return NOERROR; +} + +HRESULT OutputPinAsync_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate ) +{ + OutputPinAsyncImpl* This = pImpl->pAsyncOut; + OutputPinTask* pTask; + + TRACE("(%p)\n",pImpl); + + if ( This == NULL ) + return NOERROR; + + pTask = OutputPinAsync_AllocTask( OutTask_NewSegment ); + if ( pTask == NULL ) + return E_OUTOFMEMORY; + pTask->rtStart = rtStart; + pTask->rtStop = rtStop; + pTask->rate = rate; + OutputPinAsync_AddTask( pImpl->pAsyncOut, pTask, FALSE ); + + return NOERROR; +} + + diff --git a/dlls/quartz/igconfig.c b/dlls/quartz/igconfig.c index 4f7465db7de..4ab9b089c34 100644 --- a/dlls/quartz/igconfig.c +++ b/dlls/quartz/igconfig.c @@ -73,10 +73,19 @@ static HRESULT WINAPI IGraphConfig_fnReconfigure(IGraphConfig* iface,IGraphConfigCallback* pCallback,PVOID pvParam,DWORD dwFlags,HANDLE hAbort) { CFilterGraph_THIS(iface,grphconf); + HRESULT hr; - FIXME("(%p)->() stub!\n",This); + FIXME("(%p)->(%p,%p,%08lx,%08x) stub!\n",This,pCallback,pvParam,dwFlags,hAbort); - return E_NOTIMPL; + QUARTZ_CompList_Lock( This->m_pFilterList ); + EnterCriticalSection( &This->m_csGraphState ); + + hr = IGraphConfigCallback_Reconfigure(pCallback,pvParam,dwFlags); + + LeaveCriticalSection( &This->m_csGraphState ); + QUARTZ_CompList_Unlock( This->m_pFilterList ); + + return hr; } static HRESULT WINAPI diff --git a/dlls/quartz/main.c b/dlls/quartz/main.c index 9b73116f7de..fb8421c2719 100644 --- a/dlls/quartz/main.c +++ b/dlls/quartz/main.c @@ -32,7 +32,8 @@ DEFAULT_DEBUG_CHANNEL(quartz); #include "fmap2.h" #include "seekpass.h" #include "audren.h" - +#include "vidren.h" +#include "parser.h" typedef struct QUARTZ_CLASSENTRY { @@ -77,6 +78,8 @@ static const QUARTZ_CLASSENTRY QUARTZ_ClassList[] = { &CLSID_FilterMapper2, &QUARTZ_CreateFilterMapper2 }, { &CLSID_SeekingPassThru, &QUARTZ_CreateSeekingPassThru }, { &CLSID_AudioRender, &QUARTZ_CreateAudioRenderer }, + { &CLSID_VideoRenderer, &QUARTZ_CreateVideoRenderer }, + { &CLSID_quartzWaveParser, &QUARTZ_CreateWaveParser }, { NULL, NULL }, }; diff --git a/dlls/quartz/memalloc.c b/dlls/quartz/memalloc.c index 59a9c508e47..31e0e6b9152 100644 --- a/dlls/quartz/memalloc.c +++ b/dlls/quartz/memalloc.c @@ -318,6 +318,8 @@ IMemAllocator_fnGetBuffer(IMemAllocator* iface,IMediaSample** ppSample,REFERENCE EnterCriticalSection( &This->csMem ); + TRACE("(%p) enter critical section\n",This); + hr = NOERROR; if ( This->pData == NULL || This->ppSamples == NULL || @@ -353,6 +355,7 @@ IMemAllocator_fnGetBuffer(IMemAllocator* iface,IMediaSample** ppSample,REFERENCE end: LeaveCriticalSection( &This->csMem ); + TRACE("(%p) leave critical section\n",This); return hr; } @@ -418,3 +421,4 @@ void CMemoryAllocator_UninitIMemAllocator( CMemoryAllocator* pma ) if ( pma->hEventSample != (HANDLE)NULL ) CloseHandle( pma->hEventSample ); } + diff --git a/dlls/quartz/mtype.c b/dlls/quartz/mtype.c index e356218a6c8..0510fdfc1ff 100644 --- a/dlls/quartz/mtype.c +++ b/dlls/quartz/mtype.c @@ -14,6 +14,7 @@ #include "wine/obj_base.h" #include "strmif.h" #include "vfwmsgs.h" +#include "uuids.h" #include "debugtools.h" DEFAULT_DEBUG_CHANNEL(quartz); @@ -101,6 +102,22 @@ void QUARTZ_MediaType_Destroy( CoTaskMemFree( pmt ); } +void QUARTZ_MediaSubType_FromFourCC( + GUID* psubtype, DWORD dwFourCC ) +{ + memcpy( psubtype, &MEDIASUBTYPE_PCM, sizeof(GUID) ); + psubtype->Data1 = dwFourCC; +} + +BOOL QUARTZ_MediaSubType_IsFourCC( + const GUID* psubtype ) +{ + GUID guidTemp; + + QUARTZ_MediaSubType_FromFourCC( + &guidTemp, psubtype->Data1 ); + return IsEqualGUID( psubtype, &guidTemp ); +} /****************************************************************************/ diff --git a/dlls/quartz/mtype.h b/dlls/quartz/mtype.h index 502b593bfdc..9332f3ec5f7 100644 --- a/dlls/quartz/mtype.h +++ b/dlls/quartz/mtype.h @@ -17,6 +17,10 @@ AM_MEDIA_TYPE* QUARTZ_MediaType_Duplicate( void QUARTZ_MediaType_Destroy( AM_MEDIA_TYPE* pmt ); +void QUARTZ_MediaSubType_FromFourCC( + GUID* psubtype, DWORD dwFourCC ); +BOOL QUARTZ_MediaSubType_IsFourCC( + const GUID* psubtype ); HRESULT QUARTZ_CreateEnumMediaTypes( IEnumMediaTypes** ppobj, diff --git a/dlls/quartz/parser.c b/dlls/quartz/parser.c new file mode 100644 index 00000000000..897b31a1f23 --- /dev/null +++ b/dlls/quartz/parser.c @@ -0,0 +1,999 @@ +/* + * Implements IBaseFilter for parsers. (internal) + * + * hidenori@a2.ctktv.ne.jp + */ + +#include "config.h" + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "mmsystem.h" +#include "winerror.h" +#include "wine/obj_base.h" +#include "strmif.h" +#include "vfwmsgs.h" +#include "uuids.h" + +#include "debugtools.h" +DEFAULT_DEBUG_CHANNEL(quartz); + +#include "quartz_private.h" +#include "parser.h" +#include "mtype.h" +#include "memalloc.h" + +#define QUARTZ_MSG_BEGINFLUSH (WM_APP+1) +#define QUARTZ_MSG_ENDFLUSH (WM_APP+2) +#define QUARTZ_MSG_EXITTHREAD (WM_APP+3) +#define QUARTZ_MSG_SEEK (WM_APP+0) + +/*************************************************************************** + * + * CParserImpl internal methods + * + */ + +static +void CParserImpl_SetAsyncReader( CParserImpl* This, IAsyncReader* pReader ) +{ + if ( This->m_pReader != NULL ) + { + IAsyncReader_Release( This->m_pReader ); + This->m_pReader = NULL; + } + if ( pReader != NULL ) + { + This->m_pReader = pReader; + IAsyncReader_AddRef(This->m_pReader); + } +} + +static +void CParserImpl_ReleaseOutPins( CParserImpl* This ) +{ + ULONG nIndex; + + if ( This->m_ppOutPins != NULL ) + { + for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ ) + { + if ( This->m_ppOutPins[nIndex] != NULL ) + { + IUnknown_Release(This->m_ppOutPins[nIndex]->unk.punkControl); + This->m_ppOutPins[nIndex] = NULL; + } + } + QUARTZ_FreeMem(This->m_ppOutPins); + This->m_ppOutPins = NULL; + } + This->m_cOutStreams = 0; +} + +static +void CParserImpl_ClearAllRequests( CParserImpl* This ) +{ + ULONG nIndex; + + for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ ) + This->m_ppOutPins[nIndex]->m_bReqUsed = FALSE; +} + + +static +HRESULT CParserImpl_ReleaseAllPendingSamples( CParserImpl* This ) +{ + HRESULT hr; + IMediaSample* pSample; + DWORD_PTR dwContext; + + IAsyncReader_BeginFlush(This->m_pReader); + while ( 1 ) + { + hr = IAsyncReader_WaitForNext(This->m_pReader,0,&pSample,&dwContext); + if ( hr != S_OK ) + break; + IMediaSample_Release(pSample); + } + IAsyncReader_EndFlush(This->m_pReader); + + if ( hr == VFW_E_TIMEOUT ) + hr = NOERROR; + + return hr; +} + +static +HRESULT CParserImpl_ProcessNextSample( CParserImpl* This ) +{ + IMediaSample* pSample; + DWORD_PTR dwContext; + ULONG nIndex; + HRESULT hr; + CParserOutPinImpl* pOutPin; + MSG msg; + + while ( 1 ) + { + if ( PeekMessageA( &msg, (HWND)NULL, 0, 0, PM_REMOVE ) ) + { + hr = NOERROR; + switch ( msg.message ) + { + case QUARTZ_MSG_BEGINFLUSH: + FIXME("BeginFlush\n"); + hr = IAsyncReader_BeginFlush(This->m_pReader); + /* send to all output pins */ + break; + case QUARTZ_MSG_ENDFLUSH: + FIXME("EndFlush\n"); + hr = IAsyncReader_EndFlush(This->m_pReader); + /* send to all output pins */ + break; + case QUARTZ_MSG_EXITTHREAD: + FIXME("EndThread\n"); + CParserImpl_ReleaseAllPendingSamples(This); + CParserImpl_ClearAllRequests(This); + return S_FALSE; + case QUARTZ_MSG_SEEK: + FIXME("Seek\n"); + break; + default: + FIXME( "invalid message %04u\n", (unsigned)msg.message ); + /* Notify (ABORT) */ + hr = E_FAIL; + } + + return hr; + } + + hr = IAsyncReader_WaitForNext(This->m_pReader,PARSER_POLL_INTERVAL,&pSample,&dwContext); + nIndex = (ULONG)dwContext; + if ( hr != VFW_E_TIMEOUT ) + break; + } + if ( FAILED(hr) ) + return hr; + + pOutPin = This->m_ppOutPins[nIndex]; + if ( pOutPin != NULL && pOutPin->m_bReqUsed ) + { + if ( This->m_pHandler->pProcessSample != NULL ) + hr = This->m_pHandler->pProcessSample(This,nIndex,pOutPin->m_llReqStart,pOutPin->m_lReqLength,pSample); + + if ( FAILED(hr) ) + { + /* Notify (ABORT) */ + } + else + { + /* FIXME - if pin has its own allocator, sample must be copied */ + hr = CPinBaseImpl_SendSample(&pOutPin->pin,pSample); + } + pOutPin->m_bReqUsed = FALSE; + } + + if ( SUCCEEDED(hr) ) + hr = NOERROR; + + IMediaSample_Release(pSample); + return hr; +} + +static +DWORD WINAPI CParserImpl_ThreadEntry( LPVOID pv ) +{ + CParserImpl* This = (CParserImpl*)pv; + BOOL bReqNext; + ULONG nIndex = 0; + HRESULT hr; + REFERENCE_TIME rtSampleTimeStart, rtSampleTimeEnd; + LONGLONG llReqStart; + LONG lReqLength; + REFERENCE_TIME rtReqStart, rtReqStop; + IMediaSample* pSample; + MSG msg; + + /* initialize the message queue. */ + PeekMessageA( &msg, (HWND)NULL, 0, 0, PM_NOREMOVE ); + + CParserImpl_ClearAllRequests(This); + + /* resume the owner thread. */ + SetEvent( This->m_hEventInit ); + + TRACE( "Enter message loop.\n" ); + + bReqNext = TRUE; + while ( 1 ) + { + if ( bReqNext ) + { + /* Get the next request. */ + hr = This->m_pHandler->pGetNextRequest( This, &nIndex, &llReqStart, &lReqLength, &rtReqStart, &rtReqStop ); + if ( FAILED(hr) ) + { + /* Notify (ABORT) */ + break; + } + if ( hr != S_OK ) + { + /* Flush */ + /* Notify (COMPLETE) */ + + /* Waiting... */ + hr = CParserImpl_ProcessNextSample(This); + if ( hr != S_OK ) + { + /* notification is already sent */ + break; + } + continue; + } + rtSampleTimeStart = llReqStart * QUARTZ_TIMEUNITS; + rtSampleTimeEnd = (llReqStart + lReqLength) * QUARTZ_TIMEUNITS; + bReqNext = FALSE; + } + + if ( !This->m_ppOutPins[nIndex]->m_bReqUsed ) + { + hr = IMemAllocator_GetBuffer( This->m_pAllocator, &pSample, NULL, NULL, 0 ); + if ( FAILED(hr) ) + { + /* Notify (ABORT) */ + break; + } + hr = IMediaSample_SetTime(pSample,&rtSampleTimeStart,&rtSampleTimeEnd); + if ( SUCCEEDED(hr) ) + hr = IAsyncReader_Request(This->m_pReader,pSample,nIndex); + if ( FAILED(hr) ) + { + /* Notify (ABORT) */ + break; + } + + This->m_ppOutPins[nIndex]->m_bReqUsed = TRUE; + This->m_ppOutPins[nIndex]->m_llReqStart = llReqStart; + This->m_ppOutPins[nIndex]->m_lReqLength = lReqLength; + This->m_ppOutPins[nIndex]->m_rtReqStart = rtSampleTimeStart; + This->m_ppOutPins[nIndex]->m_rtReqStop = rtSampleTimeEnd; + bReqNext = TRUE; + continue; + } + + hr = CParserImpl_ProcessNextSample(This); + if ( hr != S_OK ) + { + /* notification is already sent */ + break; + } + } + + return 0; +} + +static +HRESULT CParserImpl_BeginThread( CParserImpl* This ) +{ + DWORD dwRes; + HANDLE hEvents[2]; + + if ( This->m_hEventInit != (HANDLE)NULL || + This->m_hThread != (HANDLE)NULL ) + return E_UNEXPECTED; + + This->m_hEventInit = CreateEventA(NULL,TRUE,FALSE,NULL); + if ( This->m_hEventInit == (HANDLE)NULL ) + return E_OUTOFMEMORY; + + /* create the processing thread. */ + This->m_hThread = CreateThread( + NULL, 0, + CParserImpl_ThreadEntry, + (LPVOID)This, + 0, &This->m_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 CParserImpl_EndThread( CParserImpl* This ) +{ + if ( This->m_hThread != (HANDLE)NULL ) + { + if ( PostThreadMessageA( + This->m_dwThreadId, QUARTZ_MSG_EXITTHREAD, 0, 0 ) ) + { + WaitForSingleObject( This->m_hThread, INFINITE ); + } + CloseHandle( This->m_hThread ); + This->m_hThread = (HANDLE)NULL; + This->m_dwThreadId = 0; + } + if ( This->m_hEventInit != (HANDLE)NULL ) + { + CloseHandle( This->m_hEventInit ); + This->m_hEventInit = (HANDLE)NULL; + } +} + +static +HRESULT CParserImpl_MemCommit( CParserImpl* This ) +{ + HRESULT hr; + ULONG nIndex; + IMemAllocator* pAlloc; + + if ( This->m_pAllocator == NULL ) + return E_UNEXPECTED; + + hr = IMemAllocator_Commit( This->m_pAllocator ); + if ( FAILED(hr) ) + return hr; + + if ( This->m_ppOutPins != NULL && This->m_cOutStreams > 0 ) + { + for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ ) + { + pAlloc = This->m_ppOutPins[nIndex]->m_pOutPinAllocator; + if ( pAlloc != NULL && pAlloc != This->m_pAllocator ) + { + hr = IMemAllocator_Commit( pAlloc ); + if ( FAILED(hr) ) + return hr; + } + } + } + + return NOERROR; +} + +static +void CParserImpl_MemDecommit( CParserImpl* This ) +{ + ULONG nIndex; + IMemAllocator* pAlloc; + + if ( This->m_pAllocator != NULL ) + IMemAllocator_Decommit( This->m_pAllocator ); + + if ( This->m_ppOutPins != NULL && This->m_cOutStreams > 0 ) + { + for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ ) + { + pAlloc = This->m_ppOutPins[nIndex]->m_pOutPinAllocator; + if ( pAlloc != NULL ) + IMemAllocator_Decommit( pAlloc ); + } + } +} + + + +/*************************************************************************** + * + * CParserImpl methods + * + */ + +static HRESULT CParserImpl_OnActive( CBaseFilterImpl* pImpl ) +{ + CParserImpl_THIS(pImpl,basefilter); + HRESULT hr; + + TRACE( "(%p)\n", This ); + + hr = CParserImpl_MemCommit(This); + if ( FAILED(hr) ) + return hr; + hr = CParserImpl_BeginThread(This); + if ( FAILED(hr) ) + return hr; + + return NOERROR; +} + +static HRESULT CParserImpl_OnInactive( CBaseFilterImpl* pImpl ) +{ + CParserImpl_THIS(pImpl,basefilter); + + TRACE( "(%p)\n", This ); + + CParserImpl_EndThread(This); + CParserImpl_MemDecommit(This); + + return NOERROR; +} + +static HRESULT CParserImpl_OnStop( CBaseFilterImpl* pImpl ) +{ + CParserImpl_THIS(pImpl,basefilter); + + FIXME( "(%p)\n", This ); + + /* FIXME - reset streams. */ + + return NOERROR; +} + + +static const CBaseFilterHandlers filterhandlers = +{ + CParserImpl_OnActive, /* pOnActive */ + CParserImpl_OnInactive, /* pOnInactive */ + CParserImpl_OnStop, /* pOnStop */ +}; + + +/*************************************************************************** + * + * CParserInPinImpl methods + * + */ + +static HRESULT CParserInPinImpl_OnPreConnect( CPinBaseImpl* pImpl, IPin* pPin ) +{ + CParserInPinImpl_THIS(pImpl,pin); + HRESULT hr; + ULONG nIndex; + IUnknown* punk; + IAsyncReader* pReader = NULL; + LPCWSTR pwszOutPinName; + IMemAllocator* pAllocActual; + AM_MEDIA_TYPE* pmt; + + TRACE("(%p,%p)\n",This,pPin); + + if ( This->pParser->m_pHandler->pInitParser == NULL || + This->pParser->m_pHandler->pUninitParser == NULL || + This->pParser->m_pHandler->pGetOutPinName == NULL || + This->pParser->m_pHandler->pGetStreamType == NULL || + This->pParser->m_pHandler->pCheckStreamType == NULL || + This->pParser->m_pHandler->pGetAllocProp == NULL || + This->pParser->m_pHandler->pGetNextRequest == NULL ) + { + FIXME("this parser is not implemented.\n"); + return E_NOTIMPL; + } + + CParserImpl_SetAsyncReader( This->pParser, NULL ); + hr = IPin_QueryInterface( pPin, &IID_IAsyncReader, (void**)&pReader ); + if ( FAILED(hr) ) + return hr; + CParserImpl_SetAsyncReader( This->pParser, pReader ); + IAsyncReader_Release(pReader); + + /* initialize parser. */ + hr = This->pParser->m_pHandler->pInitParser(This->pParser,&This->pParser->m_cOutStreams); + if ( FAILED(hr) ) + return hr; + This->pParser->m_ppOutPins = (CParserOutPinImpl**)QUARTZ_AllocMem( + sizeof(CParserOutPinImpl*) * This->pParser->m_cOutStreams ); + if ( This->pParser->m_ppOutPins == NULL ) + return E_OUTOFMEMORY; + for ( nIndex = 0; nIndex < This->pParser->m_cOutStreams; nIndex++ ) + This->pParser->m_ppOutPins[nIndex] = NULL; + + /* create and initialize an allocator. */ + hr = This->pParser->m_pHandler->pGetAllocProp(This->pParser,&This->pParser->m_propAlloc); + if ( FAILED(hr) ) + return hr; + if ( This->pParser->m_pAllocator == NULL ) + { + hr = QUARTZ_CreateMemoryAllocator(NULL,(void**)&punk); + if ( FAILED(hr) ) + return hr; + hr = IUnknown_QueryInterface( punk, &IID_IMemAllocator, (void**)&This->pParser->m_pAllocator ); + IUnknown_Release(punk); + if ( FAILED(hr) ) + return hr; + } + pAllocActual = NULL; + hr = IAsyncReader_RequestAllocator(pReader,This->pParser->m_pAllocator,&This->pParser->m_propAlloc,&pAllocActual); + if ( FAILED(hr) ) + return hr; + IMemAllocator_Release(This->pParser->m_pAllocator); + This->pParser->m_pAllocator = pAllocActual; + + /* create output pins. */ + for ( nIndex = 0; nIndex < This->pParser->m_cOutStreams; nIndex++ ) + { + pwszOutPinName = This->pParser->m_pHandler->pGetOutPinName(This->pParser,nIndex); + if ( pwszOutPinName == NULL ) + return E_FAIL; + hr = QUARTZ_CreateParserOutPin( + This->pParser, + &This->pParser->m_csParser, + &This->pParser->m_ppOutPins[nIndex], + nIndex, pwszOutPinName ); + if ( SUCCEEDED(hr) ) + hr = QUARTZ_CompList_AddComp( + This->pParser->basefilter.pOutPins, + (IUnknown*)&(This->pParser->m_ppOutPins[nIndex]->pin), + NULL, 0 ); + if ( FAILED(hr) ) + return hr; + pmt = &This->pParser->m_ppOutPins[nIndex]->m_mtOut; + QUARTZ_MediaType_Free( pmt ); + ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) ); + hr = This->pParser->m_pHandler->pGetStreamType(This->pParser,nIndex,pmt); + if ( FAILED(hr) ) + { + ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) ); + return hr; + } + This->pParser->m_ppOutPins[nIndex]->pin.cAcceptTypes = 1; + This->pParser->m_ppOutPins[nIndex]->pin.pmtAcceptTypes = pmt; + } + + return NOERROR; +} + +static HRESULT CParserInPinImpl_OnDisconnect( CPinBaseImpl* pImpl ) +{ + CParserInPinImpl_THIS(pImpl,pin); + + CParserImpl_OnInactive(&This->pParser->basefilter); + CParserImpl_OnStop(&This->pParser->basefilter); + if ( This->pParser->m_pHandler->pUninitParser != NULL ) + This->pParser->m_pHandler->pUninitParser(This->pParser); + CParserImpl_SetAsyncReader( This->pParser, NULL ); + if ( This->pParser->m_pAllocator != NULL ) + { + IMemAllocator_Release(This->pParser->m_pAllocator); + This->pParser->m_pAllocator = NULL; + } + + return NOERROR; +} + +static HRESULT CParserInPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt ) +{ + CParserInPinImpl_THIS(pImpl,pin); + + TRACE("(%p,%p)\n",This,pmt); + + if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Stream ) ) + return E_FAIL; + + return NOERROR; +} + +static const CBasePinHandlers inputpinhandlers = +{ + CParserInPinImpl_OnPreConnect, /* pOnPreConnect */ + NULL, /* pOnPostConnect */ + CParserInPinImpl_OnDisconnect, /* pOnDisconnect */ + CParserInPinImpl_CheckMediaType, /* pCheckMediaType */ + NULL, /* pQualityNotify */ + NULL, /* pReceive */ + NULL, /* pReceiveCanBlock */ + NULL, /* pEndOfStream */ + NULL, /* pBeginFlush */ + NULL, /* pEndFlush */ + NULL, /* pNewSegment */ +}; + +/*************************************************************************** + * + * CParserOutPinImpl methods + * + */ + +static HRESULT CParserOutPinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin ) +{ + CParserOutPinImpl_THIS(pImpl,pin); + ALLOCATOR_PROPERTIES propReq; + IMemAllocator* pAllocator; + HRESULT hr; + BOOL bNewAllocator = FALSE; + + TRACE("(%p,%p)\n",This,pPin); + + if ( This->pin.pMemInputPinConnectedTo == NULL ) + return E_UNEXPECTED; + + if ( This->m_pOutPinAllocator != NULL ) + { + IMemAllocator_Release(This->m_pOutPinAllocator); + This->m_pOutPinAllocator = NULL; + } + + /* try to use This->pParser->m_pAllocator. */ + ZeroMemory( &propReq, sizeof(ALLOCATOR_PROPERTIES) ); + hr = IMemInputPin_GetAllocatorRequirements( + This->pin.pMemInputPinConnectedTo, &propReq ); + if ( propReq.cbAlign != 0 ) + { + if ( This->pParser->m_propAlloc.cbAlign != ( This->pParser->m_propAlloc.cbAlign / propReq.cbAlign * propReq.cbAlign ) ) + bNewAllocator = TRUE; + } + if ( propReq.cbPrefix != 0 ) + bNewAllocator = TRUE; + if ( !bNewAllocator ) + { + hr = IMemInputPin_NotifyAllocator( + This->pin.pMemInputPinConnectedTo, + This->pParser->m_pAllocator, FALSE ); + if ( hr == NOERROR ) + { + This->m_pOutPinAllocator = This->pParser->m_pAllocator; + IMemAllocator_AddRef(This->m_pOutPinAllocator); + return NOERROR; + } + } + + hr = IMemInputPin_GetAllocator( + This->pin.pMemInputPinConnectedTo, &pAllocator ); + if ( FAILED(hr) ) + return hr; + hr = IMemInputPin_NotifyAllocator( + This->pin.pMemInputPinConnectedTo, pAllocator, FALSE ); + if ( FAILED(hr) ) + { + IMemAllocator_Release(pAllocator); + return hr; + } + + This->m_pOutPinAllocator = pAllocator; + return NOERROR; +} + +static HRESULT CParserOutPinImpl_OnDisconnect( CPinBaseImpl* pImpl ) +{ + CParserOutPinImpl_THIS(pImpl,pin); + + if ( This->m_pOutPinAllocator != NULL ) + { + IMemAllocator_Release(This->m_pOutPinAllocator); + This->m_pOutPinAllocator = NULL; + } + + return NOERROR; +} + +static HRESULT CParserOutPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt ) +{ + CParserOutPinImpl_THIS(pImpl,pin); + HRESULT hr; + + TRACE("(%p,%p)\n",This,pmt); + if ( pmt == NULL ) + return E_POINTER; + + if ( This->pParser->m_pHandler->pCheckStreamType == NULL ) + return E_NOTIMPL; + + hr = This->pParser->m_pHandler->pCheckStreamType( This->pParser, This->nStreamIndex, pmt ); + if ( FAILED(hr) ) + return hr; + + return NOERROR; +} + + +static const CBasePinHandlers outputpinhandlers = +{ + NULL, /* pOnPreConnect */ + CParserOutPinImpl_OnPostConnect, /* pOnPostConnect */ + CParserOutPinImpl_OnDisconnect, /* pOnDisconnect */ + CParserOutPinImpl_CheckMediaType, /* pCheckMediaType */ + NULL, /* pQualityNotify */ + OutputPinSync_Receive, /* pReceive */ + OutputPinSync_ReceiveCanBlock, /* pReceiveCanBlock */ + OutputPinSync_EndOfStream, /* pEndOfStream */ + OutputPinSync_BeginFlush, /* pBeginFlush */ + OutputPinSync_EndFlush, /* pEndFlush */ + OutputPinSync_NewSegment, /* pNewSegment */ +}; + +/*************************************************************************** + * + * new/delete CParserImpl + * + */ + +/* can I use offsetof safely? - FIXME? */ +static QUARTZ_IFEntry FilterIFEntries[] = +{ + { &IID_IPersist, offsetof(CParserImpl,basefilter)-offsetof(CParserImpl,unk) }, + { &IID_IMediaFilter, offsetof(CParserImpl,basefilter)-offsetof(CParserImpl,unk) }, + { &IID_IBaseFilter, offsetof(CParserImpl,basefilter)-offsetof(CParserImpl,unk) }, +}; + +static void QUARTZ_DestroyParser(IUnknown* punk) +{ + CParserImpl_THIS(punk,unk); + + TRACE( "(%p)\n", This ); + + if ( This->m_pInPin != NULL ) + CParserInPinImpl_OnDisconnect(&This->m_pInPin->pin); + + CParserImpl_SetAsyncReader( This, NULL ); + if ( This->m_pAllocator != NULL ) + { + IMemAllocator_Release(This->m_pAllocator); + This->m_pAllocator = NULL; + } + if ( This->m_pInPin != NULL ) + { + IUnknown_Release(This->m_pInPin->unk.punkControl); + This->m_pInPin = NULL; + } + CParserImpl_ReleaseOutPins( This ); + + DeleteCriticalSection( &This->m_csParser ); + + CBaseFilterImpl_UninitIBaseFilter(&This->basefilter); +} + +HRESULT QUARTZ_CreateParser( + IUnknown* punkOuter,void** ppobj, + const CLSID* pclsidParser, + LPCWSTR pwszParserName, + LPCWSTR pwszInPinName, + const ParserHandlers* pHandler ) +{ + CParserImpl* This = NULL; + HRESULT hr; + + TRACE("(%p,%p)\n",punkOuter,ppobj); + + This = (CParserImpl*) + QUARTZ_AllocObj( sizeof(CParserImpl) ); + if ( This == NULL ) + return E_OUTOFMEMORY; + + This->m_pInPin = NULL; + This->m_cOutStreams = 0; + This->m_ppOutPins = NULL; + This->m_pReader = NULL; + This->m_pAllocator = NULL; + ZeroMemory( &This->m_propAlloc, sizeof(ALLOCATOR_PROPERTIES) ); + This->m_hEventInit = (HANDLE)NULL; + This->m_hThread = (HANDLE)NULL; + This->m_dwThreadId = 0; + This->m_pHandler = pHandler; + This->m_pUserData = NULL; + + QUARTZ_IUnkInit( &This->unk, punkOuter ); + + hr = CBaseFilterImpl_InitIBaseFilter( + &This->basefilter, + This->unk.punkControl, + pclsidParser, + pwszParserName, + &filterhandlers ); + if ( SUCCEEDED(hr) ) + { + /* construct this class. */ + hr = S_OK; + + 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_DestroyParser; + InitializeCriticalSection( &This->m_csParser ); + + /* create the input pin. */ + hr = QUARTZ_CreateParserInPin( + This, + &This->m_csParser, + &This->m_pInPin, + pwszInPinName ); + if ( SUCCEEDED(hr) ) + hr = QUARTZ_CompList_AddComp( + This->basefilter.pInPins, + (IUnknown*)&(This->m_pInPin->pin), + NULL, 0 ); + + if ( FAILED(hr) ) + { + IUnknown_Release( This->unk.punkControl ); + return hr; + } + + *ppobj = (void*)&(This->unk); + + return S_OK; +} + +/*************************************************************************** + * + * new/delete CParserInPinImpl + * + */ + +/* can I use offsetof safely? - FIXME? */ +static QUARTZ_IFEntry InPinIFEntries[] = +{ + { &IID_IPin, offsetof(CParserInPinImpl,pin)-offsetof(CParserInPinImpl,unk) }, + { &IID_IMemInputPin, offsetof(CParserInPinImpl,meminput)-offsetof(CParserInPinImpl,unk) }, +}; + +static void QUARTZ_DestroyParserInPin(IUnknown* punk) +{ + CParserInPinImpl_THIS(punk,unk); + + TRACE( "(%p)\n", This ); + + CPinBaseImpl_UninitIPin( &This->pin ); + CMemInputPinBaseImpl_UninitIMemInputPin( &This->meminput ); +} + +HRESULT QUARTZ_CreateParserInPin( + CParserImpl* pFilter, + CRITICAL_SECTION* pcsPin, + CParserInPinImpl** ppPin, + LPCWSTR pwszPinName ) +{ + CParserInPinImpl* This = NULL; + HRESULT hr; + + TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin); + + This = (CParserInPinImpl*) + QUARTZ_AllocObj( sizeof(CParserInPinImpl) ); + if ( This == NULL ) + return E_OUTOFMEMORY; + + QUARTZ_IUnkInit( &This->unk, NULL ); + This->pParser = pFilter; + + hr = CPinBaseImpl_InitIPin( + &This->pin, + This->unk.punkControl, + pcsPin, + &pFilter->basefilter, + pwszPinName, + FALSE, + &inputpinhandlers ); + + if ( SUCCEEDED(hr) ) + { + hr = CMemInputPinBaseImpl_InitIMemInputPin( + &This->meminput, + This->unk.punkControl, + &This->pin ); + if ( FAILED(hr) ) + { + CPinBaseImpl_UninitIPin( &This->pin ); + } + } + + if ( FAILED(hr) ) + { + QUARTZ_FreeObj(This); + return hr; + } + + This->unk.pEntries = InPinIFEntries; + This->unk.dwEntries = sizeof(InPinIFEntries)/sizeof(InPinIFEntries[0]); + This->unk.pOnFinalRelease = QUARTZ_DestroyParserInPin; + + *ppPin = This; + + TRACE("returned successfully.\n"); + + return S_OK; +} + + +/*************************************************************************** + * + * new/delete CParserOutPinImpl + * + */ + +/* can I use offsetof safely? - FIXME? */ +static QUARTZ_IFEntry OutPinIFEntries[] = +{ + { &IID_IPin, offsetof(CParserOutPinImpl,pin)-offsetof(CParserOutPinImpl,unk) }, + { &IID_IQualityControl, offsetof(CParserOutPinImpl,qcontrol)-offsetof(CParserOutPinImpl,unk) }, +}; + +static void QUARTZ_DestroyParserOutPin(IUnknown* punk) +{ + CParserOutPinImpl_THIS(punk,unk); + + TRACE( "(%p)\n", This ); + + QUARTZ_MediaType_Free( &This->m_mtOut ); + if ( This->m_pOutPinAllocator != NULL ) + IMemAllocator_Release(This->m_pOutPinAllocator); + + CPinBaseImpl_UninitIPin( &This->pin ); + CQualityControlPassThruImpl_UninitIQualityControl( &This->qcontrol ); +} + +HRESULT QUARTZ_CreateParserOutPin( + CParserImpl* pFilter, + CRITICAL_SECTION* pcsPin, + CParserOutPinImpl** ppPin, + ULONG nStreamIndex, + LPCWSTR pwszPinName ) +{ + CParserOutPinImpl* This = NULL; + HRESULT hr; + + TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin); + + This = (CParserOutPinImpl*) + QUARTZ_AllocObj( sizeof(CParserOutPinImpl) ); + if ( This == NULL ) + return E_OUTOFMEMORY; + + QUARTZ_IUnkInit( &This->unk, NULL ); + This->pParser = pFilter; + This->nStreamIndex = nStreamIndex; + ZeroMemory( &This->m_mtOut, sizeof(AM_MEDIA_TYPE) ); + This->m_pOutPinAllocator = NULL; + This->m_pUserData = NULL; + This->m_bReqUsed = FALSE; + This->m_llReqStart = 0; + This->m_lReqLength = 0; + This->m_rtReqStart = 0; + This->m_rtReqStop = 0; + + + hr = CPinBaseImpl_InitIPin( + &This->pin, + This->unk.punkControl, + pcsPin, + &pFilter->basefilter, + pwszPinName, + TRUE, + &outputpinhandlers ); + + if ( SUCCEEDED(hr) ) + { + hr = CQualityControlPassThruImpl_InitIQualityControl( + &This->qcontrol, + This->unk.punkControl, + &This->pin ); + 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_DestroyParserOutPin; + + *ppPin = This; + + TRACE("returned successfully.\n"); + + return S_OK; +} + diff --git a/dlls/quartz/parser.h b/dlls/quartz/parser.h new file mode 100644 index 00000000000..1fb997c7cc3 --- /dev/null +++ b/dlls/quartz/parser.h @@ -0,0 +1,162 @@ +/* + * Implements Parser. + * + * hidenori@a2.ctktv.ne.jp + */ + +#ifndef WINE_DSHOW_PARSER_H +#define WINE_DSHOW_PARSER_H + +#include "iunk.h" +#include "basefilt.h" + +typedef struct CParserImpl CParserImpl; +typedef struct CParserInPinImpl CParserInPinImpl; +typedef struct CParserOutPinImpl CParserOutPinImpl; +typedef struct ParserHandlers ParserHandlers; + +/* {D51BD5A1-7548-11CF-A520-0080C77EF58A} */ +DEFINE_GUID(CLSID_quartzWaveParser, +0xD51BD5A1,0x7548,0x11CF,0xA5,0x20,0x00,0x80,0xC7,0x7E,0xF5,0x8A); + +struct CParserImpl +{ + QUARTZ_IUnkImpl unk; + CBaseFilterImpl basefilter; + + CParserInPinImpl* m_pInPin; + ULONG m_cOutStreams; + CParserOutPinImpl** m_ppOutPins; + + CRITICAL_SECTION m_csParser; + IAsyncReader* m_pReader; + IMemAllocator* m_pAllocator; + ALLOCATOR_PROPERTIES m_propAlloc; + HANDLE m_hEventInit; + DWORD m_dwThreadId; + HANDLE m_hThread; + const ParserHandlers* m_pHandler; + + void* m_pUserData; +}; + +struct CParserInPinImpl +{ + QUARTZ_IUnkImpl unk; + CPinBaseImpl pin; + CMemInputPinBaseImpl meminput; + + CParserImpl* pParser; +}; + +struct CParserOutPinImpl +{ + QUARTZ_IUnkImpl unk; + CPinBaseImpl pin; + CQualityControlPassThruImpl qcontrol; + + CParserImpl* pParser; + ULONG nStreamIndex; + + AM_MEDIA_TYPE m_mtOut; + IMemAllocator* m_pOutPinAllocator; + void* m_pUserData; + + /* for parser */ + BOOL m_bReqUsed; + LONGLONG m_llReqStart; + LONG m_lReqLength; + REFERENCE_TIME m_rtReqStart; + REFERENCE_TIME m_rtReqStop; +}; + + + +struct ParserHandlers +{ + HRESULT (*pInitParser)( CParserImpl* pImpl, ULONG* pcStreams ); + HRESULT (*pUninitParser)( CParserImpl* pImpl ); + LPCWSTR (*pGetOutPinName)( CParserImpl* pImpl, ULONG nStreamIndex ); + HRESULT (*pGetStreamType)( CParserImpl* pImpl, ULONG nStreamIndex, AM_MEDIA_TYPE* pmt ); + HRESULT (*pCheckStreamType)( CParserImpl* pImpl, ULONG nStreamIndex, const AM_MEDIA_TYPE* pmt ); + HRESULT (*pGetAllocProp)( CParserImpl* pImpl, ALLOCATOR_PROPERTIES* pReqProp ); + /* S_OK - ok, S_FALSE - end of stream */ + HRESULT (*pGetNextRequest)( CParserImpl* pImpl, ULONG* pnStreamIndex, LONGLONG* pllStart, LONG* plLength, REFERENCE_TIME* prtStart, REFERENCE_TIME* prtStop ); + HRESULT (*pProcessSample)( CParserImpl* pImpl, ULONG nStreamIndex, LONGLONG llStart, LONG lLength, IMediaSample* pSample ); + + /* for IQualityControl */ + HRESULT (*pQualityNotify)( CParserImpl* pImpl, ULONG nStreamIndex, Quality q ); + + /* for seeking */ + HRESULT (*pGetSeekingCaps)( CParserImpl* pImpl, DWORD* pdwCaps ); + HRESULT (*pIsTimeFormatSupported)( CParserImpl* pImpl, const GUID* pTimeFormat ); + HRESULT (*pGetCurPos)( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG* pllPos ); + HRESULT (*pSetCurPos)( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG llPos ); + HRESULT (*pGetDuration)( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG* pllDuration ); + HRESULT (*pSetDuration)( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG llDuration ); + HRESULT (*pGetStopPos)( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG* pllPos ); + HRESULT (*pSetStopPos)( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG llPos ); + HRESULT (*pGetPreroll)( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG* pllPreroll ); + HRESULT (*pSetPreroll)( CParserImpl* pImpl, const GUID* pTimeFormat, DWORD nStreamIndex, LONGLONG llPreroll ); +}; + +#define CParserImpl_THIS(iface,member) CParserImpl* This = ((CParserImpl*)(((char*)iface)-offsetof(CParserImpl,member))) +#define CParserInPinImpl_THIS(iface,member) CParserInPinImpl* This = ((CParserInPinImpl*)(((char*)iface)-offsetof(CParserInPinImpl,member))) +#define CParserOutPinImpl_THIS(iface,member) CParserOutPinImpl* This = ((CParserOutPinImpl*)(((char*)iface)-offsetof(CParserOutPinImpl,member))) + + +HRESULT QUARTZ_CreateParser( + IUnknown* punkOuter,void** ppobj, + const CLSID* pclsidParser, + LPCWSTR pwszParserName, + LPCWSTR pwszInPinName, + const ParserHandlers* pHandler ); +HRESULT QUARTZ_CreateParserInPin( + CParserImpl* pFilter, + CRITICAL_SECTION* pcsPin, + CParserInPinImpl** ppPin, + LPCWSTR pwszPinName ); +HRESULT QUARTZ_CreateParserOutPin( + CParserImpl* pFilter, + CRITICAL_SECTION* pcsPin, + CParserOutPinImpl** ppPin, + ULONG nStreamIndex, + LPCWSTR pwszPinName ); + + +#define QUARTZ_TIMEUNITS ((LONGLONG)10000000) +#define PARSER_POLL_INTERVAL 100 + +#define PARSER_RIFF_OfsFirst 12 +#define PARSER_WAVE mmioFOURCC('W','A','V','E') +#define PARSER_AVI mmioFOURCC('A','V','I',' ') +#define PARSER_AVIX mmioFOURCC('A','V','I','X') + +#define PARSER_fmt mmioFOURCC('f','m','t',' ') +#define PARSER_fact mmioFOURCC('f','a','c','t') +#define PARSER_data mmioFOURCC('d','a','t','a') + +#define PARSER_avih mmioFOURCC('a','v','i','h') +#define PARSER_strl mmioFOURCC('s','t','r','l') +#define PARSER_strh mmioFOURCC('s','t','r','h') +#define PARSER_strf mmioFOURCC('s','t','r','f') +#define PARSER_idx1 mmioFOURCC('i','d','x','1') +#define PARSER_indx mmioFOURCC('i','n','d','x') +#define PARSER_movi mmioFOURCC('m','o','v','i') +#define PARSER_JUNK mmioFOURCC('J','U','N','K') + +#define PARSER_vids mmioFOURCC('v','i','d','s') +#define PARSER_auds mmioFOURCC('a','u','d','s') +#define PARSER_mids mmioFOURCC('m','i','d','s') +#define PARSER_txts mmioFOURCC('t','x','t','s') + +#define PARSER_LE_UINT16(ptr) (((DWORD)(ptr)[0])|((DWORD)(ptr)[1]<<8)) +#define PARSER_LE_UINT32(ptr) (((DWORD)(ptr)[0])|((DWORD)(ptr)[1]<<8)|((DWORD)(ptr)[2]<<16)|((DWORD)(ptr)[3]<<24)) +#define PARSER_BE_UINT16(ptr) (((DWORD)(ptr)[0]<<8)|((DWORD)(ptr)[1])) +#define PARSER_BE_UINT32(ptr) (((DWORD)(ptr)[0]<<24)|((DWORD)(ptr)[1]<<16)|((DWORD)(ptr)[2]<<8)|((DWORD)(ptr)[3])) + +HRESULT QUARTZ_CreateWaveParser(IUnknown* punkOuter,void** ppobj); + + + +#endif /* WINE_DSHOW_PARSER_H */ diff --git a/dlls/quartz/quartz.spec b/dlls/quartz/quartz.spec index 64e49260be8..92aa19d758d 100644 --- a/dlls/quartz/quartz.spec +++ b/dlls/quartz/quartz.spec @@ -6,7 +6,7 @@ import oleaut32.dll import ole32.dll import winmm.dll import user32.dll -#import gdi32.dll +import gdi32.dll import advapi32.dll import kernel32.dll import ntdll.dll diff --git a/dlls/quartz/sample.c b/dlls/quartz/sample.c index 03a8f0e30c3..6b30408cb8c 100644 --- a/dlls/quartz/sample.c +++ b/dlls/quartz/sample.c @@ -23,6 +23,147 @@ DEFAULT_DEBUG_CHANNEL(quartz); #include "mtype.h" +/*************************************************************************** + * + * Helper functions + * + */ + +HRESULT QUARTZ_IMediaSample_GetProperties( + IMediaSample* pSample, + AM_SAMPLE2_PROPERTIES* pProp ) +{ + HRESULT hr; + AM_SAMPLE2_PROPERTIES prop; + IMediaSample2* pSample2 = NULL; + + ZeroMemory( &prop, sizeof(AM_SAMPLE2_PROPERTIES) ); + +#if 0 /* not yet */ + hr = IMediaSample_QueryInterface( pSample, &IID_IMediaSample2, (void**)&pSample2 ); + if ( hr == S_OK ) + { + hr = IMediaSample2_GetProperties(pSample2,sizeof(AM_SAMPLE2_PROPERTIES),&prop); + IMediaSample2_Release(pSample2); + if ( hr == S_OK ) + { + memcpy( pProp, &prop, sizeof(AM_SAMPLE2_PROPERTIES) ); + pProp->pMediaType = + QUARTZ_MediaType_Duplicate( &prop.pMediaType ); + + return NOERROR; + } + } +#endif + + pProp->cbData = sizeof(AM_SAMPLE2_PROPERTIES); + pProp->dwTypeSpecificFlags = 0; + pProp->dwSampleFlags = 0; + if ( IMediaSample_IsSyncPoint(pSample) == S_OK ) + pProp->dwSampleFlags |= AM_SAMPLE_SPLICEPOINT; + if ( IMediaSample_IsPreroll(pSample) == S_OK ) + pProp->dwSampleFlags |= AM_SAMPLE_PREROLL; + if ( IMediaSample_IsDiscontinuity(pSample) == S_OK ) + pProp->dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY; + pProp->lActual = (LONG)IMediaSample_GetActualDataLength(pSample); + if ( IMediaSample_GetTime(pSample,&pProp->tStart,&pProp->tStop) == S_OK ) + pProp->dwSampleFlags |= AM_SAMPLE_TIMEVALID | AM_SAMPLE_STOPVALID; + pProp->dwStreamId = 0; + if ( IMediaSample_GetMediaType(pSample,&(pProp->pMediaType)) == S_OK ) + pProp->dwSampleFlags |= AM_SAMPLE_TYPECHANGED; + IMediaSample_GetPointer(pSample,&(pProp->pbBuffer)); + pProp->cbBuffer = (LONG)IMediaSample_GetSize(pSample); + + return NOERROR; +} + +HRESULT QUARTZ_IMediaSample_SetProperties( + IMediaSample* pSample, + const AM_SAMPLE2_PROPERTIES* pProp ) +{ + HRESULT hr; + AM_SAMPLE2_PROPERTIES prop; + IMediaSample2* pSample2 = NULL; + + memcpy( &prop, pProp, sizeof(AM_SAMPLE2_PROPERTIES) ); + prop.cbData = sizeof(AM_SAMPLE2_PROPERTIES); + prop.pbBuffer = NULL; + prop.cbBuffer = 0; + +#if 0 /* not yet */ + hr = IMediaSample_QueryInterface( pSample, &IID_IMediaSample2, (void**)&pSample2 ); + if ( hr == S_OK ) + { + hr = IMediaSample2_SetProperties(pSample2,sizeof(AM_SAMPLE2_PROPERTIES),&prop); + IMediaSample2_Release(pSample2); + if ( hr == S_OK ) + return NOERROR; + } +#endif + + hr = S_OK; + + if ( SUCCEEDED(hr) ) + hr = IMediaSample_SetSyncPoint(pSample, + (prop.dwSampleFlags & AM_SAMPLE_SPLICEPOINT) ? TRUE : FALSE); + if ( SUCCEEDED(hr) ) + hr = IMediaSample_SetPreroll(pSample, + (prop.dwSampleFlags & AM_SAMPLE_PREROLL) ? TRUE : FALSE); + if ( SUCCEEDED(hr) ) + hr = IMediaSample_SetDiscontinuity(pSample, + (prop.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) ? TRUE : FALSE); + if ( SUCCEEDED(hr) ) + hr = IMediaSample_SetActualDataLength(pSample,prop.lActual); + if ( SUCCEEDED(hr) ) + { + if ( ( prop.dwSampleFlags & AM_SAMPLE_TIMEVALID) && + ( prop.dwSampleFlags & AM_SAMPLE_STOPVALID) ) + hr = IMediaSample_SetTime(pSample,&prop.tStart,&prop.tStop); + else + hr = IMediaSample_SetTime(pSample,NULL,NULL); + } + if ( SUCCEEDED(hr) ) + hr = IMediaSample_SetMediaType(pSample, + (prop.dwSampleFlags & AM_SAMPLE_TYPECHANGED) ? + prop.pMediaType : NULL); + + return hr; +} + +HRESULT QUARTZ_IMediaSample_Copy( + IMediaSample* pDstSample, + IMediaSample* pSrcSample, + BOOL bCopyData ) +{ + HRESULT hr; + AM_SAMPLE2_PROPERTIES prop; + BYTE* pDataSrc = NULL; + BYTE* pDataDst = NULL; + + hr = QUARTZ_IMediaSample_GetProperties( pSrcSample, &prop ); + if ( FAILED(hr) ) + return hr; + hr = QUARTZ_IMediaSample_SetProperties( pDstSample, &prop ); + if ( prop.pMediaType != NULL ) + QUARTZ_MediaType_Destroy( prop.pMediaType ); + + if ( SUCCEEDED(hr) && bCopyData ) + { + hr = IMediaSample_GetPointer(pSrcSample,&pDataSrc); + if ( SUCCEEDED(hr) ) + hr = IMediaSample_GetPointer(pDstSample,&pDataDst); + if ( SUCCEEDED(hr) ) + { + if ( pDataSrc != NULL && pDataDst != NULL ) + memcpy( pDataDst, pDataSrc, prop.lActual ); + else + hr = E_FAIL; + } + } + + return hr; +} + /*************************************************************************** * * CMemMediaSample::IMediaSample2 @@ -69,6 +210,12 @@ IMediaSample2_fnRelease(IMediaSample2* iface) TRACE("(%p)->()\n",This); + if ( This->ref == 0 ) + { + ERR("(%p) - released sample!\n",This); + return 0; + } + ref = InterlockedExchangeAdd(&(This->ref),-1) - 1; if ( ref > 0 ) return (ULONG)ref; @@ -97,6 +244,12 @@ IMediaSample2_fnGetPointer(IMediaSample2* iface,BYTE** ppData) TRACE("(%p)->()\n",This); + if ( This->ref == 0 ) + { + ERR("(%p) - released sample!\n",This); + return E_UNEXPECTED; + } + if ( ppData == NULL ) return E_POINTER; @@ -121,6 +274,12 @@ IMediaSample2_fnGetTime(IMediaSample2* iface,REFERENCE_TIME* prtStart,REFERENCE_ TRACE("(%p)->(%p,%p)\n",This,prtStart,prtEnd); + if ( This->ref == 0 ) + { + ERR("(%p) - released sample!\n",This); + return E_UNEXPECTED; + } + if ( prtStart == NULL || prtEnd == NULL ) return E_POINTER; @@ -226,7 +385,7 @@ IMediaSample2_fnSetActualDataLength(IMediaSample2* iface,long lLength) TRACE("(%p)->(%ld)\n",This,lLength); - if ( This->prop.cbBuffer > lLength ) + if ( This->prop.cbBuffer < lLength ) return E_INVALIDARG; This->prop.lActual = lLength; diff --git a/dlls/quartz/sample.h b/dlls/quartz/sample.h index 834e866710f..bf0c9d543f3 100644 --- a/dlls/quartz/sample.h +++ b/dlls/quartz/sample.h @@ -31,4 +31,18 @@ HRESULT QUARTZ_CreateMemMediaSample( void QUARTZ_DestroyMemMediaSample( CMemMediaSample* pSample ); + +HRESULT QUARTZ_IMediaSample_GetProperties( + IMediaSample* pSample, + AM_SAMPLE2_PROPERTIES* pProp ); +HRESULT QUARTZ_IMediaSample_SetProperties( + IMediaSample* pSample, + const AM_SAMPLE2_PROPERTIES* pProp ); +HRESULT QUARTZ_IMediaSample_Copy( + IMediaSample* pDstSample, + IMediaSample* pSrcSample, + BOOL bCopyData ); + + + #endif /* WINE_DSHOW_SAMPLE_H */ diff --git a/dlls/quartz/vidren.c b/dlls/quartz/vidren.c new file mode 100644 index 00000000000..e30a076f733 --- /dev/null +++ b/dlls/quartz/vidren.c @@ -0,0 +1,1774 @@ +/* + * Implements CLSID_VideoRenderer. + * + * hidenori@a2.ctktv.ne.jp + * + * FIXME - use clock + */ + +#include "config.h" + +#include +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winerror.h" +#include "wine/obj_base.h" +#include "wine/obj_oleaut.h" +#include "mmsystem.h" +#include "strmif.h" +#include "control.h" +#include "vfwmsgs.h" +#include "uuids.h" +#include "amvideo.h" +#include "evcode.h" + +#include "debugtools.h" +DEFAULT_DEBUG_CHANNEL(quartz); + +#include "quartz_private.h" +#include "vidren.h" + + +static const WCHAR QUARTZ_VideoRenderer_Name[] = +{ 'V','i','d','e','o',' ','R','e','n','d','e','r','e','r',0 }; +static const WCHAR QUARTZ_VideoRendererPin_Name[] = +{ 'I','n',0 }; + +#define VIDRENMSG_UPDATE (WM_APP+0) +#define VIDRENMSG_ENDTHREAD (WM_APP+1) + +static const CHAR VIDREN_szWndClass[] = "Wine_VideoRenderer"; +static const CHAR VIDREN_szWndName[] = "Wine Video Renderer"; + + + + +static void VIDREN_OnPaint( CVideoRendererImpl* This, HWND hwnd ) +{ + PAINTSTRUCT ps; + const VIDEOINFOHEADER* pinfo; + const AM_MEDIA_TYPE* pmt; + + TRACE("(%p,%08x)\n",This,hwnd); + + if ( !BeginPaint( hwnd, &ps ) ) + return; + + pmt = This->pPin->pin.pmtConn; + if ( (!This->m_bSampleIsValid) || pmt == NULL ) + goto err; + + pinfo = (const VIDEOINFOHEADER*)pmt->pbFormat; + + StretchDIBits( + ps.hdc, + 0, 0, + abs(pinfo->bmiHeader.biWidth), abs(pinfo->bmiHeader.biHeight), + 0, 0, + abs(pinfo->bmiHeader.biWidth), abs(pinfo->bmiHeader.biHeight), + This->m_pSampleData, (BITMAPINFO*)(&pinfo->bmiHeader), + DIB_RGB_COLORS, SRCCOPY ); + +err: + EndPaint( hwnd, &ps ); +} + +static void VIDREN_OnQueryNewPalette( CVideoRendererImpl* This, HWND hwnd ) +{ + FIXME("(%p,%08x)\n",This,hwnd); +} + +static void VIDREN_OnUpdate( CVideoRendererImpl* This, HWND hwnd ) +{ + MSG msg; + + TRACE("(%p,%08x)\n",This,hwnd); + + InvalidateRect(hwnd,NULL,FALSE); + UpdateWindow(hwnd); + + /* FIXME */ + while ( PeekMessageA(&msg,hwnd, + VIDRENMSG_UPDATE,VIDRENMSG_UPDATE, + PM_REMOVE) != FALSE ) + { + /* discard this message. */ + } +} + + +static LRESULT CALLBACK +VIDREN_WndProc( + HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam ) +{ + CVideoRendererImpl* This = (CVideoRendererImpl*) + GetWindowLongA( hwnd, 0L ); + + TRACE("(%p) - %u/%u/%ld\n",This,message,wParam,lParam); + + if ( message == WM_NCCREATE ) + { + This = (CVideoRendererImpl*)(((CREATESTRUCTA*)lParam)->lpCreateParams); + SetWindowLongA( hwnd, 0L, (LONG)This ); + This->m_hwnd = hwnd; + } + + if ( message == WM_NCDESTROY ) + { + PostQuitMessage(0); + This->m_hwnd = (HWND)NULL; + SetWindowLongA( hwnd, 0L, (LONG)NULL ); + This = NULL; + } + + if ( This != NULL ) + { + switch ( message ) + { + case WM_PAINT: + TRACE("WM_PAINT begin\n"); + EnterCriticalSection( &This->m_csSample ); + VIDREN_OnPaint( This, hwnd ); + LeaveCriticalSection( &This->m_csSample ); + TRACE("WM_PAINT end\n"); + return 0; + case WM_CLOSE: + ShowWindow( hwnd, SW_HIDE ); + return 0; + case WM_PALETTECHANGED: + if ( hwnd == (HWND)wParam ) + break; + /* fall through */ + case WM_QUERYNEWPALETTE: + VIDREN_OnQueryNewPalette( This, hwnd ); + break; + case VIDRENMSG_UPDATE: + VIDREN_OnUpdate( This, hwnd ); + return 0; + case VIDRENMSG_ENDTHREAD: + DestroyWindow(hwnd); + return 0; + default: + break; + } + } + + return DefWindowProcA( hwnd, message, wParam, lParam ); +} + +static BOOL VIDREN_Register( HINSTANCE hInst ) +{ + WNDCLASSA wc; + ATOM atom; + + wc.style = 0; + wc.lpfnWndProc = VIDREN_WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = sizeof(LONG); + wc.hInstance = hInst; + wc.hIcon = LoadIconA((HINSTANCE)NULL,IDI_WINLOGOA); + wc.hCursor = LoadCursorA((HINSTANCE)NULL,IDC_ARROWA); + wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + wc.lpszMenuName = NULL; + wc.lpszClassName = VIDREN_szWndClass; + + atom = RegisterClassA( &wc ); + if ( atom != (ATOM)0 ) + return TRUE; + + /* FIXME */ + return FALSE; +} + +static HWND VIDREN_Create( HWND hwndOwner, CVideoRendererImpl* This ) +{ + HINSTANCE hInst = (HINSTANCE)GetModuleHandleA(NULL); + const VIDEOINFOHEADER* pinfo; + DWORD dwExStyle = 0; + DWORD dwStyle = WS_OVERLAPPED|WS_CAPTION|WS_MINIMIZEBOX|WS_MAXIMIZEBOX; + RECT rcWnd; + + if ( !VIDREN_Register( hInst ) ) + return (HWND)NULL; + + pinfo = (const VIDEOINFOHEADER*)This->pPin->pin.pmtConn->pbFormat; + + TRACE("width %ld, height %ld\n", pinfo->bmiHeader.biWidth, pinfo->bmiHeader.biHeight); + + rcWnd.left = 0; + rcWnd.top = 0; + rcWnd.right = pinfo->bmiHeader.biWidth; + rcWnd.bottom = abs(pinfo->bmiHeader.biHeight); + AdjustWindowRectEx( &rcWnd, dwStyle, FALSE, dwExStyle ); + + TRACE("window width %d,height %d\n", + rcWnd.right-rcWnd.left,rcWnd.bottom-rcWnd.top); + + return CreateWindowExA( + dwExStyle, + VIDREN_szWndClass, VIDREN_szWndName, + dwStyle | WS_VISIBLE, + 100,100, /* FIXME */ + rcWnd.right-rcWnd.left, rcWnd.bottom-rcWnd.top, + hwndOwner, (HMENU)NULL, + hInst, (LPVOID)This ); +} + +static DWORD WINAPI VIDREN_ThreadEntry( LPVOID pv ) +{ + CVideoRendererImpl* This = (CVideoRendererImpl*)pv; + MSG msg; + + TRACE("(%p)\n",This); + if ( !VIDREN_Create( (HWND)NULL, This ) ) + return 0; + TRACE("VIDREN_Create succeeded\n"); + + SetEvent( This->m_hEventInit ); + TRACE("Enter message loop\n"); + + while ( GetMessageA(&msg,(HWND)NULL,0,0) ) + { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + + return 0; +} + +static HRESULT VIDREN_StartThread( CVideoRendererImpl* This ) +{ + DWORD dwRes; + DWORD dwThreadId; + HANDLE hEvents[2]; + + if ( This->m_hEventInit != (HANDLE)NULL || + This->m_hwnd != (HWND)NULL || + This->m_hThread != (HANDLE)NULL || + This->pPin->pin.pmtConn == NULL ) + return E_UNEXPECTED; + + This->m_hEventInit = CreateEventA(NULL,TRUE,FALSE,NULL); + if ( This->m_hEventInit == (HANDLE)NULL ) + return E_OUTOFMEMORY; + + This->m_hThread = CreateThread( + NULL, 0, + VIDREN_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 S_OK; +} + +static void VIDREN_EndThread( CVideoRendererImpl* This ) +{ + if ( This->m_hwnd != (HWND)NULL ) + PostMessageA( This->m_hwnd, VIDRENMSG_ENDTHREAD, 0, 0 ); + + if ( This->m_hThread != (HANDLE)NULL ) + { + WaitForSingleObject( This->m_hThread, INFINITE ); + CloseHandle( This->m_hThread ); + This->m_hThread = (HANDLE)NULL; + } + if ( This->m_hEventInit != (HANDLE)NULL ) + { + CloseHandle( This->m_hEventInit ); + This->m_hEventInit = (HANDLE)NULL; + } +} + + + +/*************************************************************************** + * + * CVideoRendererImpl methods + * + */ + +static HRESULT CVideoRendererImpl_OnActive( CBaseFilterImpl* pImpl ) +{ + CVideoRendererImpl_THIS(pImpl,basefilter); + + FIXME( "(%p)\n", This ); + + This->m_bSampleIsValid = FALSE; + + return NOERROR; +} + +static HRESULT CVideoRendererImpl_OnInactive( CBaseFilterImpl* pImpl ) +{ + CVideoRendererImpl_THIS(pImpl,basefilter); + + FIXME( "(%p)\n", This ); + + EnterCriticalSection( &This->m_csSample ); + This->m_bSampleIsValid = FALSE; + LeaveCriticalSection( &This->m_csSample ); + + return NOERROR; +} + +static const CBaseFilterHandlers filterhandlers = +{ + CVideoRendererImpl_OnActive, /* pOnActive */ + CVideoRendererImpl_OnInactive, /* pOnInactive */ + NULL, /* pOnStop */ +}; + +/*************************************************************************** + * + * CVideoRendererPinImpl methods + * + */ + +static HRESULT CVideoRendererPinImpl_OnPreConnect( CPinBaseImpl* pImpl, IPin* pPin ) +{ + CVideoRendererPinImpl_THIS(pImpl,pin); + + TRACE("(%p,%p)\n",This,pPin); + + return NOERROR; +} + +static HRESULT CVideoRendererPinImpl_OnPostConnect( CPinBaseImpl* pImpl, IPin* pPin ) +{ + CVideoRendererPinImpl_THIS(pImpl,pin); + const VIDEOINFOHEADER* pinfo; + HRESULT hr; + + TRACE("(%p,%p)\n",This,pPin); + + if ( This->pRender->m_pSampleData != NULL ) + { + QUARTZ_FreeMem(This->pRender->m_pSampleData); + This->pRender->m_pSampleData = NULL; + } + This->pRender->m_cbSampleData = 0; + This->pRender->m_bSampleIsValid = FALSE; + + pinfo = (const VIDEOINFOHEADER*)This->pin.pmtConn->pbFormat; + if ( pinfo == NULL ) + return E_FAIL; + + This->pRender->m_bSampleIsValid = FALSE; + This->pRender->m_cbSampleData = DIBSIZE(pinfo->bmiHeader); + This->pRender->m_pSampleData = (BYTE*)QUARTZ_AllocMem(This->pRender->m_cbSampleData); + if ( This->pRender->m_pSampleData == NULL ) + return E_OUTOFMEMORY; + + hr = VIDREN_StartThread(This->pRender); + if ( FAILED(hr) ) + return hr; + + return NOERROR; +} + +static HRESULT CVideoRendererPinImpl_OnDisconnect( CPinBaseImpl* pImpl ) +{ + CVideoRendererPinImpl_THIS(pImpl,pin); + + TRACE("(%p)\n",This); + + VIDREN_EndThread(This->pRender); + + if ( This->pRender->m_pSampleData != NULL ) + { + QUARTZ_FreeMem(This->pRender->m_pSampleData); + This->pRender->m_pSampleData = NULL; + } + This->pRender->m_cbSampleData = 0; + This->pRender->m_bSampleIsValid = FALSE; + + return NOERROR; +} + +static HRESULT CVideoRendererPinImpl_CheckMediaType( CPinBaseImpl* pImpl, const AM_MEDIA_TYPE* pmt ) +{ + CVideoRendererPinImpl_THIS(pImpl,pin); + const VIDEOINFOHEADER* pinfo; + + TRACE("(%p,%p)\n",This,pmt); + + if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Video ) ) + return E_FAIL; + if ( !IsEqualGUID( &pmt->formattype, &FORMAT_VideoInfo ) ) + return E_FAIL; + /* + * check subtype. + */ + if ( !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_RGB555 ) && + !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_RGB565 ) && + !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_RGB24 ) && + !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_RGB32 ) ) + return E_FAIL; + + /**** + * + * + if ( !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_RGB8 ) && + !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_RGB555 ) && + !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_RGB565 ) && + !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_RGB24 ) && + !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_RGB32 ) ) + return E_FAIL; + * + ****/ + + pinfo = (const VIDEOINFOHEADER*)pmt->pbFormat; + if ( pinfo == NULL || + pinfo->bmiHeader.biSize < sizeof(BITMAPINFOHEADER) || + pinfo->bmiHeader.biWidth <= 0 || + pinfo->bmiHeader.biHeight == 0 || + pinfo->bmiHeader.biPlanes != 1 || + pinfo->bmiHeader.biCompression != 0 ) + return E_FAIL; + + return NOERROR; +} + +static HRESULT CVideoRendererPinImpl_Receive( CPinBaseImpl* pImpl, IMediaSample* pSample ) +{ + CVideoRendererPinImpl_THIS(pImpl,pin); + HWND hwnd; + BYTE* pData = NULL; + LONG lLength; + HRESULT hr; + + TRACE( "(%p,%p)\n",This,pSample ); + + hwnd = This->pRender->m_hwnd; + if ( hwnd == (HWND)NULL || + This->pRender->m_hThread == (HWND)NULL ) + return E_UNEXPECTED; + if ( This->pRender->m_fInFlush ) + return S_FALSE; + if ( pSample == NULL ) + return E_POINTER; + + /* FIXME - wait/skip/qualitycontrol */ + + + /* duplicate this sample. */ + hr = IMediaSample_GetPointer(pSample,&pData); + if ( FAILED(hr) ) + return hr; + lLength = (LONG)IMediaSample_GetActualDataLength(pSample); + if ( lLength <= 0 || (lLength < (LONG)This->pRender->m_cbSampleData) ) + { + ERR( "invalid length: %ld\n", lLength ); + return NOERROR; + } + + EnterCriticalSection( &This->pRender->m_csSample ); + memcpy(This->pRender->m_pSampleData,pData,lLength); + This->pRender->m_bSampleIsValid = TRUE; + PostMessageA( hwnd, VIDRENMSG_UPDATE, 0, 0 ); + LeaveCriticalSection( &This->pRender->m_csSample ); + + return NOERROR; +} + +static HRESULT CVideoRendererPinImpl_ReceiveCanBlock( CPinBaseImpl* pImpl ) +{ + CVideoRendererPinImpl_THIS(pImpl,pin); + + TRACE( "(%p)\n", This ); + + /* might block. */ + return S_OK; +} + +static HRESULT CVideoRendererPinImpl_EndOfStream( CPinBaseImpl* pImpl ) +{ + CVideoRendererPinImpl_THIS(pImpl,pin); + + FIXME( "(%p)\n", This ); + + This->pRender->m_fInFlush = FALSE; + + /* FIXME - don't notify twice until stopped or seeked. */ + return CBaseFilterImpl_MediaEventNotify( + &This->pRender->basefilter, EC_COMPLETE, + (LONG_PTR)S_OK, (LONG_PTR)(IBaseFilter*)(This->pRender) ); +} + +static HRESULT CVideoRendererPinImpl_BeginFlush( CPinBaseImpl* pImpl ) +{ + CVideoRendererPinImpl_THIS(pImpl,pin); + + FIXME( "(%p)\n", This ); + + This->pRender->m_fInFlush = TRUE; + EnterCriticalSection( &This->pRender->m_csSample ); + This->pRender->m_bSampleIsValid = FALSE; + LeaveCriticalSection( &This->pRender->m_csSample ); + + return NOERROR; +} + +static HRESULT CVideoRendererPinImpl_EndFlush( CPinBaseImpl* pImpl ) +{ + CVideoRendererPinImpl_THIS(pImpl,pin); + + FIXME( "(%p)\n", This ); + + This->pRender->m_fInFlush = FALSE; + + return NOERROR; +} + +static HRESULT CVideoRendererPinImpl_NewSegment( CPinBaseImpl* pImpl, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double rate ) +{ + CVideoRendererPinImpl_THIS(pImpl,pin); + + FIXME( "(%p)\n", This ); + + This->pRender->m_fInFlush = FALSE; + + return NOERROR; +} + + + + +static const CBasePinHandlers pinhandlers = +{ + CVideoRendererPinImpl_OnPreConnect, /* pOnPreConnect */ + CVideoRendererPinImpl_OnPostConnect, /* pOnPostConnect */ + CVideoRendererPinImpl_OnDisconnect, /* pOnDisconnect */ + CVideoRendererPinImpl_CheckMediaType, /* pCheckMediaType */ + NULL, /* pQualityNotify */ + CVideoRendererPinImpl_Receive, /* pReceive */ + CVideoRendererPinImpl_ReceiveCanBlock, /* pReceiveCanBlock */ + CVideoRendererPinImpl_EndOfStream, /* pEndOfStream */ + CVideoRendererPinImpl_BeginFlush, /* pBeginFlush */ + CVideoRendererPinImpl_EndFlush, /* pEndFlush */ + CVideoRendererPinImpl_NewSegment, /* pNewSegment */ +}; + + +/*************************************************************************** + * + * new/delete CVideoRendererImpl + * + */ + +/* can I use offsetof safely? - FIXME? */ +static QUARTZ_IFEntry FilterIFEntries[] = +{ + { &IID_IPersist, offsetof(CVideoRendererImpl,basefilter)-offsetof(CVideoRendererImpl,unk) }, + { &IID_IMediaFilter, offsetof(CVideoRendererImpl,basefilter)-offsetof(CVideoRendererImpl,unk) }, + { &IID_IBaseFilter, offsetof(CVideoRendererImpl,basefilter)-offsetof(CVideoRendererImpl,unk) }, + { &IID_IBasicVideo, offsetof(CVideoRendererImpl,basvid)-offsetof(CVideoRendererImpl,unk) }, + { &IID_IBasicVideo2, offsetof(CVideoRendererImpl,basvid)-offsetof(CVideoRendererImpl,unk) }, + { &IID_IVideoWindow, offsetof(CVideoRendererImpl,vidwin)-offsetof(CVideoRendererImpl,unk) }, +}; + +static void QUARTZ_DestroyVideoRenderer(IUnknown* punk) +{ + CVideoRendererImpl_THIS(punk,unk); + + TRACE( "(%p)\n", This ); + CVideoRendererImpl_OnInactive(&This->basefilter); + VIDREN_EndThread(This); + + if ( This->pPin != NULL ) + { + IUnknown_Release(This->pPin->unk.punkControl); + This->pPin = NULL; + } + + CVideoRendererImpl_UninitIBasicVideo2(This); + CVideoRendererImpl_UninitIVideoWindow(This); + CBaseFilterImpl_UninitIBaseFilter(&This->basefilter); + + DeleteCriticalSection( &This->m_csSample ); +} + +HRESULT QUARTZ_CreateVideoRenderer(IUnknown* punkOuter,void** ppobj) +{ + CVideoRendererImpl* This = NULL; + HRESULT hr; + + TRACE("(%p,%p)\n",punkOuter,ppobj); + + This = (CVideoRendererImpl*) + QUARTZ_AllocObj( sizeof(CVideoRendererImpl) ); + if ( This == NULL ) + return E_OUTOFMEMORY; + This->pPin = NULL; + This->m_fInFlush = FALSE; + + This->m_hEventInit = (HANDLE)NULL; + This->m_hThread = (HANDLE)NULL; + This->m_hwnd = (HWND)NULL; + This->m_bSampleIsValid = FALSE; + This->m_pSampleData = NULL; + This->m_cbSampleData = 0; + + QUARTZ_IUnkInit( &This->unk, punkOuter ); + + hr = CBaseFilterImpl_InitIBaseFilter( + &This->basefilter, + This->unk.punkControl, + &CLSID_VideoRenderer, + QUARTZ_VideoRenderer_Name, + &filterhandlers ); + if ( SUCCEEDED(hr) ) + { + hr = CVideoRendererImpl_InitIBasicVideo2(This); + if ( SUCCEEDED(hr) ) + { + hr = CVideoRendererImpl_InitIVideoWindow(This); + if ( FAILED(hr) ) + { + CVideoRendererImpl_UninitIBasicVideo2(This); + } + } + 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_DestroyVideoRenderer; + + hr = QUARTZ_CreateVideoRendererPin( + This, + &This->basefilter.csFilter, + &This->pPin ); + if ( SUCCEEDED(hr) ) + hr = QUARTZ_CompList_AddComp( + This->basefilter.pInPins, + (IUnknown*)&This->pPin->pin, + NULL, 0 ); + if ( FAILED(hr) ) + { + IUnknown_Release( This->unk.punkControl ); + return hr; + } + + InitializeCriticalSection( &This->m_csSample ); + + *ppobj = (void*)&(This->unk); + + return S_OK; +} + +/*************************************************************************** + * + * new/delete CVideoRendererPinImpl + * + */ + +/* can I use offsetof safely? - FIXME? */ +static QUARTZ_IFEntry PinIFEntries[] = +{ + { &IID_IPin, offsetof(CVideoRendererPinImpl,pin)-offsetof(CVideoRendererPinImpl,unk) }, + { &IID_IMemInputPin, offsetof(CVideoRendererPinImpl,meminput)-offsetof(CVideoRendererPinImpl,unk) }, +}; + +static void QUARTZ_DestroyVideoRendererPin(IUnknown* punk) +{ + CVideoRendererPinImpl_THIS(punk,unk); + + TRACE( "(%p)\n", This ); + + CPinBaseImpl_UninitIPin( &This->pin ); + CMemInputPinBaseImpl_UninitIMemInputPin( &This->meminput ); +} + +HRESULT QUARTZ_CreateVideoRendererPin( + CVideoRendererImpl* pFilter, + CRITICAL_SECTION* pcsPin, + CVideoRendererPinImpl** ppPin) +{ + CVideoRendererPinImpl* This = NULL; + HRESULT hr; + + TRACE("(%p,%p,%p)\n",pFilter,pcsPin,ppPin); + + This = (CVideoRendererPinImpl*) + QUARTZ_AllocObj( sizeof(CVideoRendererPinImpl) ); + if ( This == NULL ) + return E_OUTOFMEMORY; + + QUARTZ_IUnkInit( &This->unk, NULL ); + This->pRender = pFilter; + + hr = CPinBaseImpl_InitIPin( + &This->pin, + This->unk.punkControl, + pcsPin, + &pFilter->basefilter, + QUARTZ_VideoRendererPin_Name, + FALSE, + &pinhandlers ); + + if ( SUCCEEDED(hr) ) + { + hr = CMemInputPinBaseImpl_InitIMemInputPin( + &This->meminput, + This->unk.punkControl, + &This->pin ); + if ( FAILED(hr) ) + { + CPinBaseImpl_UninitIPin( &This->pin ); + } + } + + if ( FAILED(hr) ) + { + QUARTZ_FreeObj(This); + return hr; + } + + This->unk.pEntries = PinIFEntries; + This->unk.dwEntries = sizeof(PinIFEntries)/sizeof(PinIFEntries[0]); + This->unk.pOnFinalRelease = QUARTZ_DestroyVideoRendererPin; + + *ppPin = This; + + TRACE("returned successfully.\n"); + + return S_OK; +} + +/*************************************************************************** + * + * CVideoRendererImpl::IBasicVideo2 + * + */ + + +static HRESULT WINAPI +IBasicVideo2_fnQueryInterface(IBasicVideo2* iface,REFIID riid,void** ppobj) +{ + CVideoRendererImpl_THIS(iface,basvid); + + TRACE("(%p)->()\n",This); + + return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj); +} + +static ULONG WINAPI +IBasicVideo2_fnAddRef(IBasicVideo2* iface) +{ + CVideoRendererImpl_THIS(iface,basvid); + + TRACE("(%p)->()\n",This); + + return IUnknown_AddRef(This->unk.punkControl); +} + +static ULONG WINAPI +IBasicVideo2_fnRelease(IBasicVideo2* iface) +{ + CVideoRendererImpl_THIS(iface,basvid); + + TRACE("(%p)->()\n",This); + + return IUnknown_Release(This->unk.punkControl); +} + +static HRESULT WINAPI +IBasicVideo2_fnGetTypeInfoCount(IBasicVideo2* iface,UINT* pcTypeInfo) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnGetTypeInfo(IBasicVideo2* iface,UINT iTypeInfo, LCID lcid, ITypeInfo** ppobj) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnGetIDsOfNames(IBasicVideo2* iface,REFIID riid, LPOLESTR* ppwszName, UINT cNames, LCID lcid, DISPID* pDispId) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnInvoke(IBasicVideo2* iface,DISPID DispId, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarRes, EXCEPINFO* pExcepInfo, UINT* puArgErr) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + + +static HRESULT WINAPI +IBasicVideo2_fnget_AvgTimePerFrame(IBasicVideo2* iface,REFTIME* prefTime) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnget_BitRate(IBasicVideo2* iface,long* plRate) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnget_BitErrorRate(IBasicVideo2* iface,long* plRate) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnget_VideoWidth(IBasicVideo2* iface,long* plWidth) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnget_VideoHeight(IBasicVideo2* iface,long* plHeight) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnput_SourceLeft(IBasicVideo2* iface,long lLeft) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnget_SourceLeft(IBasicVideo2* iface,long* plLeft) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnput_SourceWidth(IBasicVideo2* iface,long lWidth) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnget_SourceWidth(IBasicVideo2* iface,long* plWidth) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnput_SourceTop(IBasicVideo2* iface,long lTop) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnget_SourceTop(IBasicVideo2* iface,long* plTop) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnput_SourceHeight(IBasicVideo2* iface,long lHeight) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnget_SourceHeight(IBasicVideo2* iface,long* plHeight) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnput_DestinationLeft(IBasicVideo2* iface,long lLeft) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnget_DestinationLeft(IBasicVideo2* iface,long* plLeft) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnput_DestinationWidth(IBasicVideo2* iface,long lWidth) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnget_DestinationWidth(IBasicVideo2* iface,long* plWidth) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnput_DestinationTop(IBasicVideo2* iface,long lTop) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnget_DestinationTop(IBasicVideo2* iface,long* plTop) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnput_DestinationHeight(IBasicVideo2* iface,long lHeight) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnget_DestinationHeight(IBasicVideo2* iface,long* plHeight) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnSetSourcePosition(IBasicVideo2* iface,long lLeft,long lTop,long lWidth,long lHeight) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnGetSourcePosition(IBasicVideo2* iface,long* plLeft,long* plTop,long* plWidth,long* plHeight) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnSetDefaultSourcePosition(IBasicVideo2* iface) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnSetDestinationPosition(IBasicVideo2* iface,long lLeft,long lTop,long lWidth,long lHeight) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnGetDestinationPosition(IBasicVideo2* iface,long* plLeft,long* plTop,long* plWidth,long* plHeight) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnSetDefaultDestinationPosition(IBasicVideo2* iface) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnGetVideoSize(IBasicVideo2* iface,long* plWidth,long* plHeight) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnGetVideoPaletteEntries(IBasicVideo2* iface,long lStart,long lCount,long* plRet,long* plPaletteEntry) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnGetCurrentImage(IBasicVideo2* iface,long* plBufferSize,long* plDIBBuffer) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnIsUsingDefaultSource(IBasicVideo2* iface) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnIsUsingDefaultDestination(IBasicVideo2* iface) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IBasicVideo2_fnGetPreferredAspectRatio(IBasicVideo2* iface,long* plRateX,long* plRateY) +{ + CVideoRendererImpl_THIS(iface,basvid); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + + + + +static ICOM_VTABLE(IBasicVideo2) ibasicvideo = +{ + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + /* IUnknown fields */ + IBasicVideo2_fnQueryInterface, + IBasicVideo2_fnAddRef, + IBasicVideo2_fnRelease, + /* IDispatch fields */ + IBasicVideo2_fnGetTypeInfoCount, + IBasicVideo2_fnGetTypeInfo, + IBasicVideo2_fnGetIDsOfNames, + IBasicVideo2_fnInvoke, + /* IBasicVideo fields */ + IBasicVideo2_fnget_AvgTimePerFrame, + IBasicVideo2_fnget_BitRate, + IBasicVideo2_fnget_BitErrorRate, + IBasicVideo2_fnget_VideoWidth, + IBasicVideo2_fnget_VideoHeight, + IBasicVideo2_fnput_SourceLeft, + IBasicVideo2_fnget_SourceLeft, + IBasicVideo2_fnput_SourceWidth, + IBasicVideo2_fnget_SourceWidth, + IBasicVideo2_fnput_SourceTop, + IBasicVideo2_fnget_SourceTop, + IBasicVideo2_fnput_SourceHeight, + IBasicVideo2_fnget_SourceHeight, + IBasicVideo2_fnput_DestinationLeft, + IBasicVideo2_fnget_DestinationLeft, + IBasicVideo2_fnput_DestinationWidth, + IBasicVideo2_fnget_DestinationWidth, + IBasicVideo2_fnput_DestinationTop, + IBasicVideo2_fnget_DestinationTop, + IBasicVideo2_fnput_DestinationHeight, + IBasicVideo2_fnget_DestinationHeight, + IBasicVideo2_fnSetSourcePosition, + IBasicVideo2_fnGetSourcePosition, + IBasicVideo2_fnSetDefaultSourcePosition, + IBasicVideo2_fnSetDestinationPosition, + IBasicVideo2_fnGetDestinationPosition, + IBasicVideo2_fnSetDefaultDestinationPosition, + IBasicVideo2_fnGetVideoSize, + IBasicVideo2_fnGetVideoPaletteEntries, + IBasicVideo2_fnGetCurrentImage, + IBasicVideo2_fnIsUsingDefaultSource, + IBasicVideo2_fnIsUsingDefaultDestination, + /* IBasicVideo2 fields */ + IBasicVideo2_fnGetPreferredAspectRatio, +}; + + +HRESULT CVideoRendererImpl_InitIBasicVideo2( CVideoRendererImpl* This ) +{ + TRACE("(%p)\n",This); + ICOM_VTBL(&This->basvid) = &ibasicvideo; + + return NOERROR; +} + +void CVideoRendererImpl_UninitIBasicVideo2( CVideoRendererImpl* This ) +{ + TRACE("(%p)\n",This); +} + +/*************************************************************************** + * + * CVideoRendererImpl::IVideoWindow + * + */ + + +static HRESULT WINAPI +IVideoWindow_fnQueryInterface(IVideoWindow* iface,REFIID riid,void** ppobj) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + TRACE("(%p)->()\n",This); + + return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj); +} + +static ULONG WINAPI +IVideoWindow_fnAddRef(IVideoWindow* iface) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + TRACE("(%p)->()\n",This); + + return IUnknown_AddRef(This->unk.punkControl); +} + +static ULONG WINAPI +IVideoWindow_fnRelease(IVideoWindow* iface) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + TRACE("(%p)->()\n",This); + + return IUnknown_Release(This->unk.punkControl); +} + +static HRESULT WINAPI +IVideoWindow_fnGetTypeInfoCount(IVideoWindow* iface,UINT* pcTypeInfo) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnGetTypeInfo(IVideoWindow* iface,UINT iTypeInfo, LCID lcid, ITypeInfo** ppobj) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnGetIDsOfNames(IVideoWindow* iface,REFIID riid, LPOLESTR* ppwszName, UINT cNames, LCID lcid, DISPID* pDispId) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnInvoke(IVideoWindow* iface,DISPID DispId, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarRes, EXCEPINFO* pExcepInfo, UINT* puArgErr) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + + + +static HRESULT WINAPI +IVideoWindow_fnput_Caption(IVideoWindow* iface,BSTR strCaption) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnget_Caption(IVideoWindow* iface,BSTR* pstrCaption) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnput_WindowStyle(IVideoWindow* iface,long lStyle) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnget_WindowStyle(IVideoWindow* iface,long* plStyle) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnput_WindowStyleEx(IVideoWindow* iface,long lExStyle) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnget_WindowStyleEx(IVideoWindow* iface,long* plExStyle) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnput_AutoShow(IVideoWindow* iface,long lAutoShow) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnget_AutoShow(IVideoWindow* iface,long* plAutoShow) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnput_WindowState(IVideoWindow* iface,long lState) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnget_WindowState(IVideoWindow* iface,long* plState) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnput_BackgroundPalette(IVideoWindow* iface,long lBackPal) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnget_BackgroundPalette(IVideoWindow* iface,long* plBackPal) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnput_Visible(IVideoWindow* iface,long lVisible) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnget_Visible(IVideoWindow* iface,long* plVisible) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnput_Left(IVideoWindow* iface,long lLeft) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnget_Left(IVideoWindow* iface,long* plLeft) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnput_Width(IVideoWindow* iface,long lWidth) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnget_Width(IVideoWindow* iface,long* plWidth) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnput_Top(IVideoWindow* iface,long lTop) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnget_Top(IVideoWindow* iface,long* plTop) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnput_Height(IVideoWindow* iface,long lHeight) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnget_Height(IVideoWindow* iface,long* plHeight) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnput_Owner(IVideoWindow* iface,OAHWND hwnd) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnget_Owner(IVideoWindow* iface,OAHWND* phwnd) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnput_MessageDrain(IVideoWindow* iface,OAHWND hwnd) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnget_MessageDrain(IVideoWindow* iface,OAHWND* phwnd) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnget_BorderColor(IVideoWindow* iface,long* plColor) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnput_BorderColor(IVideoWindow* iface,long lColor) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnget_FullScreenMode(IVideoWindow* iface,long* plMode) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnput_FullScreenMode(IVideoWindow* iface,long lMode) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnSetWindowForeground(IVideoWindow* iface,long lFocus) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnNotifyOwnerMessage(IVideoWindow* iface,OAHWND hwnd,long message,LONG_PTR wParam,LONG_PTR lParam) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnSetWindowPosition(IVideoWindow* iface,long lLeft,long lTop,long lWidth,long lHeight) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnGetWindowPosition(IVideoWindow* iface,long* plLeft,long* plTop,long* plWidth,long* plHeight) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnGetMinIdealImageSize(IVideoWindow* iface,long* plWidth,long* plHeight) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnGetMaxIdealImageSize(IVideoWindow* iface,long* plWidth,long* plHeight) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnGetRestorePosition(IVideoWindow* iface,long* plLeft,long* plTop,long* plWidth,long* plHeight) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnHideCursor(IVideoWindow* iface,long lHide) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI +IVideoWindow_fnIsCursorHidden(IVideoWindow* iface,long* plHide) +{ + CVideoRendererImpl_THIS(iface,vidwin); + + FIXME("(%p)->()\n",This); + + return E_NOTIMPL; +} + + + + +static ICOM_VTABLE(IVideoWindow) ivideowindow = +{ + ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE + /* IUnknown fields */ + IVideoWindow_fnQueryInterface, + IVideoWindow_fnAddRef, + IVideoWindow_fnRelease, + /* IDispatch fields */ + IVideoWindow_fnGetTypeInfoCount, + IVideoWindow_fnGetTypeInfo, + IVideoWindow_fnGetIDsOfNames, + IVideoWindow_fnInvoke, + /* IVideoWindow fields */ + IVideoWindow_fnput_Caption, + IVideoWindow_fnget_Caption, + IVideoWindow_fnput_WindowStyle, + IVideoWindow_fnget_WindowStyle, + IVideoWindow_fnput_WindowStyleEx, + IVideoWindow_fnget_WindowStyleEx, + IVideoWindow_fnput_AutoShow, + IVideoWindow_fnget_AutoShow, + IVideoWindow_fnput_WindowState, + IVideoWindow_fnget_WindowState, + IVideoWindow_fnput_BackgroundPalette, + IVideoWindow_fnget_BackgroundPalette, + IVideoWindow_fnput_Visible, + IVideoWindow_fnget_Visible, + IVideoWindow_fnput_Left, + IVideoWindow_fnget_Left, + IVideoWindow_fnput_Width, + IVideoWindow_fnget_Width, + IVideoWindow_fnput_Top, + IVideoWindow_fnget_Top, + IVideoWindow_fnput_Height, + IVideoWindow_fnget_Height, + IVideoWindow_fnput_Owner, + IVideoWindow_fnget_Owner, + IVideoWindow_fnput_MessageDrain, + IVideoWindow_fnget_MessageDrain, + IVideoWindow_fnget_BorderColor, + IVideoWindow_fnput_BorderColor, + IVideoWindow_fnget_FullScreenMode, + IVideoWindow_fnput_FullScreenMode, + IVideoWindow_fnSetWindowForeground, + IVideoWindow_fnNotifyOwnerMessage, + IVideoWindow_fnSetWindowPosition, + IVideoWindow_fnGetWindowPosition, + IVideoWindow_fnGetMinIdealImageSize, + IVideoWindow_fnGetMaxIdealImageSize, + IVideoWindow_fnGetRestorePosition, + IVideoWindow_fnHideCursor, + IVideoWindow_fnIsCursorHidden, + +}; + + +HRESULT CVideoRendererImpl_InitIVideoWindow( CVideoRendererImpl* This ) +{ + TRACE("(%p)\n",This); + ICOM_VTBL(&This->vidwin) = &ivideowindow; + + return NOERROR; +} + +void CVideoRendererImpl_UninitIVideoWindow( CVideoRendererImpl* This ) +{ + TRACE("(%p)\n",This); +} + diff --git a/dlls/quartz/vidren.h b/dlls/quartz/vidren.h new file mode 100644 index 00000000000..f3b6123e843 --- /dev/null +++ b/dlls/quartz/vidren.h @@ -0,0 +1,74 @@ +/* + * Implements CLSID_VideoRenderer. + * + * hidenori@a2.ctktv.ne.jp + */ + +#ifndef WINE_DSHOW_VIDREN_H +#define WINE_DSHOW_VIDREN_H + +#include "iunk.h" +#include "basefilt.h" + +typedef struct CVideoRendererImpl CVideoRendererImpl; +typedef struct CVideoRendererPinImpl CVideoRendererPinImpl; + + +typedef struct VidRen_IBasicVideo +{ + ICOM_VFIELD(IBasicVideo2); +} VidRen_IBasicVideo; + +typedef struct VidRen_IVideoWindow +{ + ICOM_VFIELD(IVideoWindow); +} VidRen_IVideoWindow; + +struct CVideoRendererImpl +{ + QUARTZ_IUnkImpl unk; + CBaseFilterImpl basefilter; + VidRen_IBasicVideo basvid; + VidRen_IVideoWindow vidwin; + + CVideoRendererPinImpl* pPin; + + BOOL m_fInFlush; + + /* for rendering */ + HANDLE m_hEventInit; + HANDLE m_hThread; + HWND m_hwnd; + CRITICAL_SECTION m_csSample; + BOOL m_bSampleIsValid; + BYTE* m_pSampleData; + DWORD m_cbSampleData; +}; + +struct CVideoRendererPinImpl +{ + QUARTZ_IUnkImpl unk; + CPinBaseImpl pin; + CMemInputPinBaseImpl meminput; + + CVideoRendererImpl* pRender; +}; + + + +#define CVideoRendererImpl_THIS(iface,member) CVideoRendererImpl* This = ((CVideoRendererImpl*)(((char*)iface)-offsetof(CVideoRendererImpl,member))) +#define CVideoRendererPinImpl_THIS(iface,member) CVideoRendererPinImpl* This = ((CVideoRendererPinImpl*)(((char*)iface)-offsetof(CVideoRendererPinImpl,member))) + +HRESULT CVideoRendererImpl_InitIBasicVideo2( CVideoRendererImpl* This ); +void CVideoRendererImpl_UninitIBasicVideo2( CVideoRendererImpl* This ); +HRESULT CVideoRendererImpl_InitIVideoWindow( CVideoRendererImpl* This ); +void CVideoRendererImpl_UninitIVideoWindow( CVideoRendererImpl* This ); + +HRESULT QUARTZ_CreateVideoRenderer(IUnknown* punkOuter,void** ppobj); +HRESULT QUARTZ_CreateVideoRendererPin( + CVideoRendererImpl* pFilter, + CRITICAL_SECTION* pcsPin, + CVideoRendererPinImpl** ppPin); + + +#endif /* WINE_DSHOW_VIDREN_H */ diff --git a/dlls/quartz/wavparse.c b/dlls/quartz/wavparse.c new file mode 100644 index 00000000000..6514e99c5af --- /dev/null +++ b/dlls/quartz/wavparse.c @@ -0,0 +1,473 @@ +/* + * Implements WAVE/AU/AIFF Parser. + * + * hidenori@a2.ctktv.ne.jp + */ + +#include "config.h" + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "mmsystem.h" +#include "winerror.h" +#include "wine/obj_base.h" +#include "strmif.h" +#include "vfwmsgs.h" +#include "uuids.h" + +#include "debugtools.h" +DEFAULT_DEBUG_CHANNEL(quartz); + +#include "quartz_private.h" + +/* for CLSID_quartzWaveParser. */ +#include "initguid.h" +#include "parser.h" + + +static const WCHAR QUARTZ_WaveParser_Name[] = +{ 'W','a','v','e',' ','P','a','r','s','e','r',0 }; +static const WCHAR QUARTZ_WaveParserInPin_Name[] = +{ 'I','n',0 }; +static const WCHAR QUARTZ_WaveParserOutPin_Name[] = +{ 'O','u','t',0 }; + + +/****************************************************************************/ + +/* S_OK = found, S_FALSE = not found */ +HRESULT RIFF_GetNext( + CParserImpl* pImpl, LONGLONG llOfs, + DWORD* pdwCode, DWORD* pdwLength ) +{ + BYTE bTemp[8]; + HRESULT hr; + + hr = IAsyncReader_SyncRead( pImpl->m_pReader, llOfs, 8, bTemp ); + if ( hr == S_OK ) + { + *pdwCode = mmioFOURCC(bTemp[0],bTemp[1],bTemp[2],bTemp[3]); + *pdwLength = PARSER_LE_UINT32(&bTemp[4]); + } + else + { + *pdwCode = 0; + *pdwLength = 0; + } + + return hr; +} + +/* S_OK = found, S_FALSE = not found */ +HRESULT RIFF_SearchChunk( + CParserImpl* pImpl, + LONGLONG llOfs, DWORD dwChunk, + LONGLONG* pllOfs, DWORD* pdwChunkLength ) +{ + HRESULT hr; + DWORD dwCurCode; + DWORD dwCurLen; + + while ( 1 ) + { + hr = RIFF_GetNext( pImpl, llOfs, &dwCurCode, &dwCurLen ); + if ( hr != S_OK ) + break; + if ( dwChunk == dwCurCode ) + break; + llOfs += 8 + (LONGLONG)((dwCurLen+1)&(~1)); + } + + *pllOfs = llOfs; + *pdwChunkLength = dwCurLen; + + return hr; +} + + + + +/**************************************************************************** + * + * CWavParseImpl + */ + +typedef enum WavParseFmtType +{ + WaveParse_Native, + WaveParse_Signed8, + WaveParse_Signed16BE, + WaveParse_Unsigned16LE, + WaveParse_Unsigned16BE, +} WavParseFmtType; + +typedef struct CWavParseImpl +{ + DWORD cbFmt; + WAVEFORMATEX* pFmt; + DWORD dwBlockSize; + LONGLONG llDataStart; + LONGLONG llBytesTotal; + LONGLONG llBytesProcessed; + WavParseFmtType iFmtType; +} CWavParseImpl; + + +static HRESULT CWavParseImpl_InitWAV( CParserImpl* pImpl, CWavParseImpl* This ) +{ + HRESULT hr; + LONGLONG llOfs; + DWORD dwChunkLength; + + hr = RIFF_SearchChunk( + pImpl, PARSER_RIFF_OfsFirst, + PARSER_fmt, &llOfs, &dwChunkLength ); + if ( FAILED(hr) ) + return hr; + if ( hr != S_OK || ( dwChunkLength < (sizeof(WAVEFORMATEX)-2) ) ) + return E_FAIL; + llOfs += 8; + + This->cbFmt = dwChunkLength; + if ( dwChunkLength < sizeof(WAVEFORMATEX) ) + This->cbFmt = sizeof(WAVEFORMATEX); + This->pFmt = (WAVEFORMATEX*)QUARTZ_AllocMem( dwChunkLength ); + if ( This->pFmt == NULL ) + return E_OUTOFMEMORY; + ZeroMemory( This->pFmt, This->cbFmt ); + + hr = IAsyncReader_SyncRead( + pImpl->m_pReader, llOfs, dwChunkLength, (BYTE*)This->pFmt ); + if ( hr != S_OK ) + { + if ( SUCCEEDED(hr) ) + hr = E_FAIL; + return hr; + } + + + hr = RIFF_SearchChunk( + pImpl, PARSER_RIFF_OfsFirst, + PARSER_data, &llOfs, &dwChunkLength ); + if ( FAILED(hr) ) + return hr; + if ( hr != S_OK || dwChunkLength == 0 ) + return E_FAIL; + + This->llDataStart = llOfs; + This->llBytesTotal = (LONGLONG)dwChunkLength; + + return NOERROR; +} + +static HRESULT CWavParseImpl_InitAU( CParserImpl* pImpl, CWavParseImpl* This ) +{ + BYTE au_hdr[24]; + DWORD dataofs; + DWORD datalen; + DWORD datafmt; + DWORD datarate; + DWORD datachannels; + HRESULT hr; + WAVEFORMATEX wfx; + + hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 24, au_hdr ); + if ( FAILED(hr) ) + return hr; + + dataofs = PARSER_BE_UINT32(&au_hdr[4]); + datalen = PARSER_BE_UINT32(&au_hdr[8]); + datafmt = PARSER_BE_UINT32(&au_hdr[12]); + datarate = PARSER_BE_UINT32(&au_hdr[16]); + datachannels = PARSER_BE_UINT32(&au_hdr[20]); + + if ( dataofs < 24U || datalen == 0U ) + return E_FAIL; + if ( datachannels != 1 && datachannels != 2 ) + return E_FAIL; + + ZeroMemory( &wfx, sizeof(WAVEFORMATEX) ); + wfx.nChannels = datachannels; + wfx.nSamplesPerSec = datarate; + + switch ( datafmt ) + { + case 1: + wfx.wFormatTag = 7; + wfx.nBlockAlign = datachannels; + wfx.wBitsPerSample = 8; + break; + case 2: + wfx.wFormatTag = 1; + wfx.nBlockAlign = datachannels; + wfx.wBitsPerSample = 8; + This->iFmtType = WaveParse_Signed8; + break; + case 3: + wfx.wFormatTag = 1; + wfx.nBlockAlign = datachannels; + wfx.wBitsPerSample = 16; + This->iFmtType = WaveParse_Signed16BE; + break; + default: + FIXME("audio/basic - unknown format %lu\n", datafmt ); + return E_FAIL; + } + wfx.nAvgBytesPerSec = (datarate * datachannels * (DWORD)wfx.wBitsPerSample) >> 3; + + This->cbFmt = sizeof(WAVEFORMATEX); + This->pFmt = (WAVEFORMATEX*)QUARTZ_AllocMem( sizeof(WAVEFORMATEX) ); + if ( This->pFmt == NULL ) + return E_OUTOFMEMORY; + memcpy( This->pFmt, &wfx, sizeof(WAVEFORMATEX) ); + + This->llDataStart = dataofs; + This->llBytesTotal = datalen; + + return NOERROR; +} + +static HRESULT CWavParseImpl_InitAIFF( CParserImpl* pImpl, CWavParseImpl* This ) +{ + FIXME( "AIFF is not supported now.\n" ); + return E_FAIL; +} + +static HRESULT CWavParseImpl_InitParser( CParserImpl* pImpl, ULONG* pcStreams ) +{ + CWavParseImpl* This = NULL; + HRESULT hr; + BYTE header[12]; + + TRACE("(%p,%p)\n",pImpl,pcStreams); + + if ( pImpl->m_pReader == NULL ) + return E_UNEXPECTED; + + This = (CWavParseImpl*)QUARTZ_AllocMem( sizeof(CWavParseImpl) ); + if ( This == NULL ) + return E_OUTOFMEMORY; + pImpl->m_pUserData = This; + + /* construct */ + This->cbFmt = 0; + This->pFmt = NULL; + This->dwBlockSize = 0; + This->llDataStart = 0; + This->llBytesTotal = 0; + This->llBytesProcessed = 0; + This->iFmtType = WaveParse_Native; + + hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 12, header ); + if ( FAILED(hr) ) + return hr; + if ( hr != S_OK ) + return E_FAIL; + + if ( !memcmp( &header[0], "RIFF", 4 ) && + !memcmp( &header[8], "WAVE", 4 ) ) + { + TRACE( "(%p) - it's audio/wav.\n", pImpl ); + hr = CWavParseImpl_InitWAV( pImpl, This ); + } + else + if ( !memcmp( &header[0], ".snd", 4 ) ) + { + TRACE( "(%p) - it's audio/basic.\n", pImpl ); + hr = CWavParseImpl_InitAU( pImpl, This ); + } + else + if ( !memcmp( &header[0], "FORM", 4 ) && + !memcmp( &header[8], "AIFF", 4 ) ) + { + TRACE( "(%p) - it's audio/aiff.\n", pImpl ); + hr = CWavParseImpl_InitAIFF( pImpl, This ); + } + else + { + FIXME( "(%p) - unknown format.\n", pImpl ); + hr = E_FAIL; + } + + if ( FAILED(hr) ) + { + return hr; + } + + /* initialized successfully. */ + *pcStreams = 1; + + This->dwBlockSize = (This->pFmt->nAvgBytesPerSec + (DWORD)This->pFmt->nBlockAlign - 1U) / (DWORD)This->pFmt->nBlockAlign; + + TRACE( "(%p) returned successfully.\n", pImpl ); + + return NOERROR; +} + +static HRESULT CWavParseImpl_UninitParser( CParserImpl* pImpl ) +{ + CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData; + + TRACE("(%p)\n",This); + + if ( This == NULL ) + return NOERROR; + + /* destruct */ + if ( This->pFmt != NULL ) QUARTZ_FreeMem(This->pFmt); + + QUARTZ_FreeMem( This ); + pImpl->m_pUserData = NULL; + + return NOERROR; +} + +static LPCWSTR CWavParseImpl_GetOutPinName( CParserImpl* pImpl, ULONG nStreamIndex ) +{ + CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData; + + TRACE("(%p)\n",This); + + return QUARTZ_WaveParserOutPin_Name; +} + +static HRESULT CWavParseImpl_GetStreamType( CParserImpl* pImpl, ULONG nStreamIndex, AM_MEDIA_TYPE* pmt ) +{ + CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData; + + TRACE("(%p)\n",This); + + if ( This == NULL || This->pFmt == NULL ) + return E_UNEXPECTED; + + ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) ); + memcpy( &pmt->majortype, &MEDIATYPE_Audio, sizeof(GUID) ); + QUARTZ_MediaSubType_FromFourCC( &pmt->subtype, (DWORD)This->pFmt->wFormatTag ); + pmt->bFixedSizeSamples = 1; + pmt->bTemporalCompression = 0; + pmt->lSampleSize = This->pFmt->nBlockAlign; + memcpy( &pmt->formattype, &FORMAT_WaveFormatEx, sizeof(GUID) ); + pmt->pUnk = NULL; + + pmt->pbFormat = (BYTE*)CoTaskMemAlloc( This->cbFmt ); + if ( pmt->pbFormat == NULL ) + return E_OUTOFMEMORY; + pmt->cbFormat = This->cbFmt; + memcpy( pmt->pbFormat, This->pFmt, This->cbFmt ); + + return NOERROR; +} + +static HRESULT CWavParseImpl_CheckStreamType( CParserImpl* pImpl, ULONG nStreamIndex, const AM_MEDIA_TYPE* pmt ) +{ + if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Audio ) || + !IsEqualGUID( &pmt->formattype, &FORMAT_WaveFormatEx ) ) + return E_FAIL; + if ( pmt->pbFormat == NULL || pmt->cbFormat < sizeof(WAVEFORMATEX) ) + return E_FAIL; + + return NOERROR; +} + +static HRESULT CWavParseImpl_GetAllocProp( CParserImpl* pImpl, ALLOCATOR_PROPERTIES* pReqProp ) +{ + CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData; + + TRACE("(%p)\n",This); + + if ( This == NULL || This->pFmt == NULL ) + return E_UNEXPECTED; + + ZeroMemory( pReqProp, sizeof(ALLOCATOR_PROPERTIES) ); + pReqProp->cBuffers = 1; + pReqProp->cbBuffer = This->dwBlockSize; + + return NOERROR; +} + +static HRESULT CWavParseImpl_GetNextRequest( CParserImpl* pImpl, ULONG* pnStreamIndex, LONGLONG* pllStart, LONG* plLength, REFERENCE_TIME* prtStart, REFERENCE_TIME* prtStop ) +{ + CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData; + LONGLONG llAvail; + LONGLONG llStart; + LONGLONG llEnd; + + TRACE("(%p)\n",This); + + if ( This == NULL || This->pFmt == NULL ) + return E_UNEXPECTED; + + llAvail = This->llBytesTotal - This->llBytesProcessed; + if ( llAvail > (LONGLONG)This->dwBlockSize ) + llAvail = (LONGLONG)This->dwBlockSize; + llStart = This->llBytesProcessed; + llEnd = llStart + llAvail; + This->llBytesProcessed = llEnd; + + *pllStart = This->llBytesProcessed; + *plLength = (LONG)llAvail; + *prtStart = llStart * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec; + *prtStop = llEnd * QUARTZ_TIMEUNITS / (LONGLONG)This->pFmt->nAvgBytesPerSec; + + return NOERROR; +} + +static HRESULT CWavParseImpl_ProcessSample( CParserImpl* pImpl, ULONG nStreamIndex, LONGLONG llStart, LONG lLength, IMediaSample* pSample ) +{ + CWavParseImpl* This = (CWavParseImpl*)pImpl->m_pUserData; + + TRACE("(%p)\n",This); + + switch ( This->iFmtType ) + { + case WaveParse_Native: + break; + default: + FIXME("(%p) - %d not implemented\n", This, This->iFmtType ); + return E_FAIL; + } + + return NOERROR; +} + + +static const struct ParserHandlers CWavParseImpl_Handlers = +{ + CWavParseImpl_InitParser, + CWavParseImpl_UninitParser, + CWavParseImpl_GetOutPinName, + CWavParseImpl_GetStreamType, + CWavParseImpl_CheckStreamType, + CWavParseImpl_GetAllocProp, + CWavParseImpl_GetNextRequest, + CWavParseImpl_ProcessSample, + + /* for IQualityControl */ + NULL, /* pQualityNotify */ + + /* for seeking */ + NULL, /* pGetSeekingCaps */ + NULL, /* pIsTimeFormatSupported */ + NULL, /* pGetCurPos */ + NULL, /* pSetCurPos */ + NULL, /* pGetDuration */ + NULL, /* pSetDuration */ + NULL, /* pGetStopPos */ + NULL, /* pSetStopPos */ + NULL, /* pGetPreroll */ + NULL, /* pSetPreroll */ +}; + +HRESULT QUARTZ_CreateWaveParser(IUnknown* punkOuter,void** ppobj) +{ + return QUARTZ_CreateParser( + punkOuter,ppobj, + &CLSID_quartzWaveParser, + QUARTZ_WaveParser_Name, + QUARTZ_WaveParserInPin_Name, + &CWavParseImpl_Handlers ); +} + + diff --git a/include/amvideo.h b/include/amvideo.h index 20fd693ba83..19dabb6f607 100644 --- a/include/amvideo.h +++ b/include/amvideo.h @@ -4,12 +4,76 @@ #include "ole2.h" #include "ddraw.h" + typedef struct IBaseVideoMixer IBaseVideoMixer; typedef struct IDirectDrawVideo IDirectDrawVideo; typedef struct IFullScreenVideo IFullScreenVideo; typedef struct IFullScreenVideoEx IFullScreenVideoEx; typedef struct IQualProp IQualProp; + +#define iEGA_COLORS 16 +#define iPALETTE_COLORS 256 +#define iMASK_COLORS 3 +#define iRED 0 +#define iGREEN 1 +#define iBLUE 2 + +#define WIDTHBYTES(bits) ((DWORD)((((DWORD)(bits)+31U)&(~31U))>>3)) +#define DIBWIDTHBYTES(bi) ((DWORD)WIDTHBYTES((bi).biWidth*(bi).biBitCount)) +#define DIBSIZE(bi) (DIBWIDTHBYTES(bi)*(DWORD)abs((bi).biHeight)) + + +typedef struct +{ + DWORD dwBitMasks[iMASK_COLORS]; + RGBQUAD bmiColors[iPALETTE_COLORS]; +} TRUECOLORINFO; + +typedef struct +{ + RECT rcSource; + RECT rcTarget; + DWORD dwBitRate; + DWORD dwBitErrorRate; + REFERENCE_TIME AvgTimePerFrame; + BITMAPINFOHEADER bmiHeader; +} VIDEOINFOHEADER; + +typedef struct +{ + RECT rcSource; + RECT rcTarget; + DWORD dwBitRate; + DWORD dwBitErrorRate; + REFERENCE_TIME AvgTimePerFrame; + BITMAPINFOHEADER bmiHeader; + + union { + RGBQUAD bmiColors[iPALETTE_COLORS]; + DWORD dwBitMasks[iMASK_COLORS]; + TRUECOLORINFO TrueColorInfo; + } DUMMYUNIONNAME; +} VIDEOINFO; + +typedef struct +{ + VIDEOINFOHEADER hdr; + DWORD dwStartTimeCode; + DWORD cbSequenceHeader; + BYTE bSequenceHeader[1]; +} MPEG1VIDEOINFO; + +typedef struct +{ + RECT rcSource; + RECT rcTarget; + DWORD dwActiveWidth; + DWORD dwActiveHeight; + REFERENCE_TIME AvgTimePerFrame; +} ANALOGVIDEOINFO; + + /************************************************************************** * * IBaseVideoMixer interface diff --git a/winedefault.reg b/winedefault.reg index 9dd68f3c337..5cacfe238ac 100644 --- a/winedefault.reg +++ b/winedefault.reg @@ -328,6 +328,88 @@ "CLSID"="{e30629d1-27e5-11ce-875d-00608cb78066}" "FriendlyName"="Waveout audio renderer" +# CLSID_VideoRenderer + +[HKEY_CLASSES_ROOT\CLSID\{70e102b0-5556-11ce-97c0-00aa0055595a}\InprocServer32] +@="quartz.dll" +"ThreadingModel"="Both" + +[HKEY_CLASSES_ROOT\CLSID\{083863F1-70DE-11D0-BD40-00A0C911CE86}\Instance\{70e102b0-5556-11ce-97c0-00aa0055595a}] +"CLSID"="{70e102b0-5556-11ce-97c0-00aa0055595a}" +"FriendlyName"="Video Renderer" + +# Wave Parser + +[HKEY_CLASSES_ROOT\CLSID\{D51BD5A1-7548-11CF-A520-0080C77EF58A}\InprocServer32] +@="quartz.dll" +"ThreadingModel"="Both" + +[HKEY_CLASSES_ROOT\CLSID\{083863F1-70DE-11D0-BD40-00A0C911CE86}\Instance\{D51BD5A1-7548-11CF-A520-0080C77EF58A}] +"CLSID"="{D51BD5A1-7548-11CF-A520-0080C77EF58A}" +"FriendlyName"="Wave Parser" + +# CLSID_AVIDec(AVI Decompressor) (not implemented yet) + +[HKEY_CLASSES_ROOT\CLSID\{CF49D4E0-1115-11CE-B03A-0020AF0BA770}\InprocServer32] +@="quartz.dll" +"ThreadingModel"="Both" + +[HKEY_CLASSES_ROOT\CLSID\{083863F1-70DE-11D0-BD40-00A0C911CE86}\Instance\{CF49D4E0-1115-11CE-B03A-0020AF0BA770}] +"CLSID"="{CF49D4E0-1115-11CE-B03A-0020AF0BA770}" +"FriendlyName"="AVI Decompressor" + +# CLSID_AsyncReader (not implemented yet) + +[HKEY_CLASSES_ROOT\CLSID\{E436EBB5-524F-11CE-9F53-0020AF0BA770}\InprocServer32] +@="quartz.dll" +"ThreadingModel"="Both" + +[HKEY_CLASSES_ROOT\CLSID\{083863F1-70DE-11D0-BD40-00A0C911CE86}\Instance\{E436EBB5-524F-11CE-9F53-0020AF0BA770}] +"CLSID"="{E436EBB5-524F-11CE-9F53-0020AF0BA770}" +"FriendlyName"="Async Reader" + +# CLSID_URLReader (not implemented yet) + +[HKEY_CLASSES_ROOT\CLSID\{E436EBB6-524F-11CE-9F53-0020AF0BA770}\InprocServer32] +@="quartz.dll" +"ThreadingModel"="Both" + +[HKEY_CLASSES_ROOT\CLSID\{083863F1-70DE-11D0-BD40-00A0C911CE86}\Instance\{E436EBB6-524F-11CE-9F53-0020AF0BA770}] +"CLSID"="{E436EBB6-524F-11CE-9F53-0020AF0BA770}" +"FriendlyName"="URL Reader" + +# CLSID_AviSplitter (not implemented yet) + +[HKEY_CLASSES_ROOT\CLSID\{1B544C20-FD0B-11CE-8C63-00AA0044B51E}\InprocServer32] +@="quartz.dll" +"ThreadingModel"="Both" + +[HKEY_CLASSES_ROOT\CLSID\{083863F1-70DE-11D0-BD40-00A0C911CE86}\Instance\{1B544C20-FD0B-11CE-8C63-00AA0044B51E}] +"CLSID"="{1B544C20-FD0B-11CE-8C63-00AA0044B51E}" +"FriendlyName"="AVI Splitter" + +# CLSID_QuickTimeParser (not implemented yet) + +[HKEY_CLASSES_ROOT\CLSID\{D51BD5A0-7548-11CF-A520-0080C77EF58A}\InprocServer32] +@="quartz.dll" +"ThreadingModel"="Both" + +[HKEY_CLASSES_ROOT\CLSID\{083863F1-70DE-11D0-BD40-00A0C911CE86}\Instance\{D51BD5A0-7548-11CF-A520-0080C77EF58A}] +"CLSID"="{D51BD5A0-7548-11CF-A520-0080C77EF58A}" +"FriendlyName"="QuickTime Movie Parser" + +# CLSID_Colour(Color space converter) (not implemented yet) + +[HKEY_CLASSES_ROOT\CLSID\{1643E180-90F5-11CE-97D5-00AA0055595A}\InprocServer32] +@="quartz.dll" +"ThreadingModel"="Both" + +[HKEY_CLASSES_ROOT\CLSID\{083863F1-70DE-11D0-BD40-00A0C911CE86}\Instance\{1643E180-90F5-11CE-97D5-00AA0055595A}] +"CLSID"="{1643E180-90F5-11CE-97D5-00AA0055595A}" +"FriendlyName"="Color space converter" + + + # # Entries for Mozilla ActiveX control support