/* * Implements IBaseFilter for parsers. (internal) * * hidenori@a2.ctktv.ne.jp * * FIXME - save the array of pSample and handle errors/flushing correctly. */ #include "config.h" #include "windef.h" #include "winbase.h" #include "wingdi.h" #include "winuser.h" #include "mmsystem.h" #include "winerror.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); TRACE("return %08lx\n",hr); 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; } if ( This->m_ppOutPins[nIndex]->pin.pPinConnectedTo == NULL ) 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; }