|  | /* | 
|  | * Implements IBaseFilter. (internal) | 
|  | * | 
|  | * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp> | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "wingdi.h" | 
|  | #include "winuser.h" | 
|  | #include "winerror.h" | 
|  | #include "strmif.h" | 
|  | #include "vfwmsgs.h" | 
|  |  | 
|  | #include "wine/debug.h" | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(quartz); | 
|  |  | 
|  | #include "quartz_private.h" | 
|  | #include "basefilt.h" | 
|  | #include "enumunk.h" | 
|  |  | 
|  |  | 
|  | /*************************************************************************** | 
|  | * | 
|  | *	CBaseFilterImpl::IBaseFilter | 
|  | * | 
|  | */ | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | CBaseFilterImpl_fnQueryInterface(IBaseFilter* iface,REFIID riid,void** ppobj) | 
|  | { | 
|  | ICOM_THIS(CBaseFilterImpl,iface); | 
|  |  | 
|  | TRACE("(%p)->()\n",This); | 
|  |  | 
|  | return IUnknown_QueryInterface(This->punkControl,riid,ppobj); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI | 
|  | CBaseFilterImpl_fnAddRef(IBaseFilter* iface) | 
|  | { | 
|  | ICOM_THIS(CBaseFilterImpl,iface); | 
|  |  | 
|  | TRACE("(%p)->()\n",This); | 
|  |  | 
|  | return IUnknown_AddRef(This->punkControl); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI | 
|  | CBaseFilterImpl_fnRelease(IBaseFilter* iface) | 
|  | { | 
|  | ICOM_THIS(CBaseFilterImpl,iface); | 
|  |  | 
|  | TRACE("(%p)->()\n",This); | 
|  |  | 
|  | return IUnknown_Release(This->punkControl); | 
|  | } | 
|  |  | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | CBaseFilterImpl_fnGetClassID(IBaseFilter* iface,CLSID* pclsid) | 
|  | { | 
|  | ICOM_THIS(CBaseFilterImpl,iface); | 
|  |  | 
|  | TRACE("(%p)->()\n",This); | 
|  |  | 
|  | if ( pclsid == NULL ) | 
|  | return E_POINTER; | 
|  |  | 
|  | memcpy( pclsid, This->pclsidFilter, sizeof(CLSID) ); | 
|  |  | 
|  | return NOERROR; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | CBaseFilterImpl_fnStop(IBaseFilter* iface) | 
|  | { | 
|  | ICOM_THIS(CBaseFilterImpl,iface); | 
|  | HRESULT hr; | 
|  |  | 
|  | TRACE("(%p)->()\n",This); | 
|  |  | 
|  | hr = NOERROR; | 
|  |  | 
|  | EnterCriticalSection( &This->csFilter ); | 
|  | if ( This->bIntermediateState ) | 
|  | { | 
|  | LeaveCriticalSection( &This->csFilter ); | 
|  | return VFW_S_STATE_INTERMEDIATE; /* FIXME? */ | 
|  | } | 
|  | TRACE("(%p) state = %d\n",This,This->fstate); | 
|  |  | 
|  | if ( This->fstate == State_Running ) | 
|  | { | 
|  | 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; | 
|  | } | 
|  |  | 
|  | LeaveCriticalSection( &This->csFilter ); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | CBaseFilterImpl_fnPause(IBaseFilter* iface) | 
|  | { | 
|  | ICOM_THIS(CBaseFilterImpl,iface); | 
|  | HRESULT hr; | 
|  |  | 
|  | TRACE("(%p)->()\n",This); | 
|  |  | 
|  | hr = NOERROR; | 
|  |  | 
|  | EnterCriticalSection( &This->csFilter ); | 
|  | if ( This->bIntermediateState ) | 
|  | { | 
|  | LeaveCriticalSection( &This->csFilter ); | 
|  | return VFW_E_WRONG_STATE; /* FIXME? */ | 
|  | } | 
|  | TRACE("(%p) state = %d\n",This,This->fstate); | 
|  |  | 
|  | if ( This->fstate != State_Paused ) | 
|  | { | 
|  | if ( This->pHandlers->pOnInactive != NULL ) | 
|  | hr = This->pHandlers->pOnInactive( This ); | 
|  | if ( SUCCEEDED(hr) ) | 
|  | This->fstate = State_Paused; | 
|  | } | 
|  | LeaveCriticalSection( &This->csFilter ); | 
|  |  | 
|  | TRACE("hr = %08lx\n",hr); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | CBaseFilterImpl_fnRun(IBaseFilter* iface,REFERENCE_TIME rtStart) | 
|  | { | 
|  | ICOM_THIS(CBaseFilterImpl,iface); | 
|  | HRESULT hr; | 
|  |  | 
|  | TRACE("(%p)->()\n",This); | 
|  |  | 
|  | hr = NOERROR; | 
|  |  | 
|  | EnterCriticalSection( &This->csFilter ); | 
|  | if ( This->bIntermediateState ) | 
|  | { | 
|  | LeaveCriticalSection( &This->csFilter ); | 
|  | return VFW_E_WRONG_STATE; /* FIXME? */ | 
|  | } | 
|  | TRACE("(%p) state = %d\n",This,This->fstate); | 
|  |  | 
|  | This->rtStart = rtStart; | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | LeaveCriticalSection( &This->csFilter ); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | CBaseFilterImpl_fnGetState(IBaseFilter* iface,DWORD dw,FILTER_STATE* pState) | 
|  | { | 
|  | ICOM_THIS(CBaseFilterImpl,iface); | 
|  | HRESULT hr = S_OK; | 
|  |  | 
|  | TRACE("(%p)->(%p)\n",This,pState); | 
|  |  | 
|  | if ( pState == NULL ) | 
|  | return E_POINTER; | 
|  |  | 
|  | EnterCriticalSection( &This->csFilter ); | 
|  | TRACE("(%p) state = %d\n",This,This->fstate); | 
|  | *pState = This->fstate; | 
|  | if ( This->bIntermediateState ) | 
|  | hr = VFW_S_STATE_INTERMEDIATE; | 
|  | LeaveCriticalSection( &This->csFilter ); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | CBaseFilterImpl_fnSetSyncSource(IBaseFilter* iface,IReferenceClock* pobjClock) | 
|  | { | 
|  | ICOM_THIS(CBaseFilterImpl,iface); | 
|  |  | 
|  | TRACE("(%p)->(%p)\n",This,pobjClock); | 
|  |  | 
|  | EnterCriticalSection( &This->csFilter ); | 
|  |  | 
|  | if ( This->pClock != NULL ) | 
|  | { | 
|  | IReferenceClock_Release( This->pClock ); | 
|  | This->pClock = NULL; | 
|  | } | 
|  |  | 
|  | This->pClock = pobjClock; | 
|  | if ( pobjClock != NULL ) | 
|  | IReferenceClock_AddRef( pobjClock ); | 
|  |  | 
|  | LeaveCriticalSection( &This->csFilter ); | 
|  |  | 
|  | return NOERROR; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | CBaseFilterImpl_fnGetSyncSource(IBaseFilter* iface,IReferenceClock** ppobjClock) | 
|  | { | 
|  | ICOM_THIS(CBaseFilterImpl,iface); | 
|  | HRESULT hr = VFW_E_NO_CLOCK; | 
|  |  | 
|  | TRACE("(%p)->(%p)\n",This,ppobjClock); | 
|  |  | 
|  | if ( ppobjClock == NULL ) | 
|  | return E_POINTER; | 
|  |  | 
|  | EnterCriticalSection( &This->csFilter ); | 
|  |  | 
|  | *ppobjClock = This->pClock; | 
|  | if ( This->pClock != NULL ) | 
|  | { | 
|  | hr = NOERROR; | 
|  | IReferenceClock_AddRef( This->pClock ); | 
|  | } | 
|  |  | 
|  | LeaveCriticalSection( &This->csFilter ); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | CBaseFilterImpl_fnEnumPins(IBaseFilter* iface,IEnumPins** ppenum) | 
|  | { | 
|  | ICOM_THIS(CBaseFilterImpl,iface); | 
|  | HRESULT	hr = E_FAIL; | 
|  | QUARTZ_CompList*	pListPins; | 
|  | QUARTZ_CompListItem*	pItem; | 
|  | IUnknown*	punkPin; | 
|  |  | 
|  | TRACE("(%p)->(%p)\n",This,ppenum); | 
|  |  | 
|  | if ( ppenum == NULL ) | 
|  | return E_POINTER; | 
|  | *ppenum = NULL; | 
|  |  | 
|  | pListPins = QUARTZ_CompList_Alloc(); | 
|  | if ( pListPins == NULL ) | 
|  | return E_OUTOFMEMORY; | 
|  |  | 
|  | QUARTZ_CompList_Lock( This->pInPins ); | 
|  | QUARTZ_CompList_Lock( This->pOutPins ); | 
|  |  | 
|  | pItem = QUARTZ_CompList_GetFirst( This->pInPins ); | 
|  | while ( pItem != NULL ) | 
|  | { | 
|  | punkPin = QUARTZ_CompList_GetItemPtr( pItem ); | 
|  | hr = QUARTZ_CompList_AddComp( pListPins, punkPin, NULL, 0 ); | 
|  | if ( FAILED(hr) ) | 
|  | goto err; | 
|  | pItem = QUARTZ_CompList_GetNext( This->pInPins, pItem ); | 
|  | } | 
|  |  | 
|  | pItem = QUARTZ_CompList_GetFirst( This->pOutPins ); | 
|  | while ( pItem != NULL ) | 
|  | { | 
|  | punkPin = QUARTZ_CompList_GetItemPtr( pItem ); | 
|  | hr = QUARTZ_CompList_AddComp( pListPins, punkPin, NULL, 0 ); | 
|  | if ( FAILED(hr) ) | 
|  | goto err; | 
|  | pItem = QUARTZ_CompList_GetNext( This->pOutPins, pItem ); | 
|  | } | 
|  |  | 
|  | hr = QUARTZ_CreateEnumUnknown( | 
|  | &IID_IEnumPins, (void**)ppenum, pListPins ); | 
|  | err: | 
|  | QUARTZ_CompList_Unlock( This->pInPins ); | 
|  | QUARTZ_CompList_Unlock( This->pOutPins ); | 
|  |  | 
|  | QUARTZ_CompList_Free( pListPins ); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | CBaseFilterImpl_fnFindPin(IBaseFilter* iface,LPCWSTR lpwszId,IPin** ppobj) | 
|  | { | 
|  | ICOM_THIS(CBaseFilterImpl,iface); | 
|  |  | 
|  | FIXME("(%p)->(%s,%p) stub!\n",This,debugstr_w(lpwszId),ppobj); | 
|  |  | 
|  | if ( ppobj == NULL ) | 
|  | return E_POINTER; | 
|  |  | 
|  |  | 
|  |  | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | CBaseFilterImpl_fnQueryFilterInfo(IBaseFilter* iface,FILTER_INFO* pfi) | 
|  | { | 
|  | ICOM_THIS(CBaseFilterImpl,iface); | 
|  |  | 
|  | TRACE("(%p)->(%p)\n",This,pfi); | 
|  |  | 
|  | if ( pfi == NULL ) | 
|  | return E_POINTER; | 
|  |  | 
|  | EnterCriticalSection( &This->csFilter ); | 
|  |  | 
|  | if ( This->cbNameGraph <= sizeof(WCHAR)*MAX_FILTER_NAME ) | 
|  | { | 
|  | memcpy( pfi->achName, This->pwszNameGraph, This->cbNameGraph ); | 
|  | } | 
|  | else | 
|  | { | 
|  | memcpy( pfi->achName, This->pwszNameGraph, | 
|  | sizeof(WCHAR)*MAX_FILTER_NAME ); | 
|  | pfi->achName[MAX_FILTER_NAME-1] = (WCHAR)0; | 
|  | } | 
|  |  | 
|  | pfi->pGraph = This->pfg; | 
|  | if ( pfi->pGraph != NULL ) | 
|  | IFilterGraph_AddRef(pfi->pGraph); | 
|  |  | 
|  | LeaveCriticalSection( &This->csFilter ); | 
|  |  | 
|  | return NOERROR; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | CBaseFilterImpl_fnJoinFilterGraph(IBaseFilter* iface,IFilterGraph* pfg,LPCWSTR lpwszName) | 
|  | { | 
|  | ICOM_THIS(CBaseFilterImpl,iface); | 
|  | HRESULT	hr; | 
|  |  | 
|  | TRACE("(%p)->(%p,%s)\n",This,pfg,debugstr_w(lpwszName)); | 
|  |  | 
|  | EnterCriticalSection( &This->csFilter ); | 
|  |  | 
|  | if ( This->pwszNameGraph != NULL ) | 
|  | { | 
|  | QUARTZ_FreeMem( This->pwszNameGraph ); | 
|  | This->pwszNameGraph = NULL; | 
|  | This->cbNameGraph = 0; | 
|  | } | 
|  |  | 
|  | This->pfg = pfg; | 
|  | This->cbNameGraph = sizeof(WCHAR) * (lstrlenW(lpwszName)+1); | 
|  | This->pwszNameGraph = (WCHAR*)QUARTZ_AllocMem( This->cbNameGraph ); | 
|  | if ( This->pwszNameGraph == NULL ) | 
|  | { | 
|  | hr = E_OUTOFMEMORY; | 
|  | goto err; | 
|  | } | 
|  | memcpy( This->pwszNameGraph, lpwszName, This->cbNameGraph ); | 
|  |  | 
|  | hr = NOERROR; | 
|  | err: | 
|  | LeaveCriticalSection( &This->csFilter ); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI | 
|  | CBaseFilterImpl_fnQueryVendorInfo(IBaseFilter* iface,LPWSTR* lpwszVendor) | 
|  | { | 
|  | ICOM_THIS(CBaseFilterImpl,iface); | 
|  |  | 
|  | TRACE("(%p)->(%p)\n",This,lpwszVendor); | 
|  |  | 
|  | /* E_NOTIMPL means 'no vender information'. */ | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*************************************************************************** | 
|  | * | 
|  | *	construct/destruct CBaseFilterImpl | 
|  | * | 
|  | */ | 
|  |  | 
|  | static ICOM_VTABLE(IBaseFilter) ibasefilter = | 
|  | { | 
|  | ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE | 
|  | /* IUnknown fields */ | 
|  | CBaseFilterImpl_fnQueryInterface, | 
|  | CBaseFilterImpl_fnAddRef, | 
|  | CBaseFilterImpl_fnRelease, | 
|  | /* IPersist fields */ | 
|  | CBaseFilterImpl_fnGetClassID, | 
|  | /* IMediaFilter fields */ | 
|  | CBaseFilterImpl_fnStop, | 
|  | CBaseFilterImpl_fnPause, | 
|  | CBaseFilterImpl_fnRun, | 
|  | CBaseFilterImpl_fnGetState, | 
|  | CBaseFilterImpl_fnSetSyncSource, | 
|  | CBaseFilterImpl_fnGetSyncSource, | 
|  | /* IBaseFilter fields */ | 
|  | CBaseFilterImpl_fnEnumPins, | 
|  | CBaseFilterImpl_fnFindPin, | 
|  | CBaseFilterImpl_fnQueryFilterInfo, | 
|  | CBaseFilterImpl_fnJoinFilterGraph, | 
|  | CBaseFilterImpl_fnQueryVendorInfo, | 
|  | }; | 
|  |  | 
|  |  | 
|  | HRESULT CBaseFilterImpl_InitIBaseFilter( | 
|  | CBaseFilterImpl* This, IUnknown* punkControl, | 
|  | const CLSID* pclsidFilter, LPCWSTR lpwszNameGraph, | 
|  | const CBaseFilterHandlers* pHandlers ) | 
|  | { | 
|  | TRACE("(%p,%p)\n",This,punkControl); | 
|  |  | 
|  | if ( punkControl == NULL ) | 
|  | { | 
|  | ERR( "punkControl must not be NULL\n" ); | 
|  | return E_INVALIDARG; | 
|  | } | 
|  |  | 
|  | ICOM_VTBL(This) = &ibasefilter; | 
|  | This->punkControl = punkControl; | 
|  | This->pHandlers = pHandlers; | 
|  | This->pclsidFilter = pclsidFilter; | 
|  | This->pInPins = NULL; | 
|  | This->pOutPins = NULL; | 
|  | This->pfg = NULL; | 
|  | This->cbNameGraph = 0; | 
|  | This->pwszNameGraph = NULL; | 
|  | This->pClock = NULL; | 
|  | This->rtStart = 0; | 
|  | This->fstate = State_Stopped; | 
|  | This->bIntermediateState = FALSE; | 
|  |  | 
|  | This->cbNameGraph = sizeof(WCHAR) * (lstrlenW(lpwszNameGraph)+1); | 
|  | This->pwszNameGraph = (WCHAR*)QUARTZ_AllocMem( This->cbNameGraph ); | 
|  | if ( This->pwszNameGraph == NULL ) | 
|  | return E_OUTOFMEMORY; | 
|  | memcpy( This->pwszNameGraph, lpwszNameGraph, This->cbNameGraph ); | 
|  |  | 
|  | This->pInPins = QUARTZ_CompList_Alloc(); | 
|  | This->pOutPins = QUARTZ_CompList_Alloc(); | 
|  | if ( This->pInPins == NULL || This->pOutPins == NULL ) | 
|  | { | 
|  | if ( This->pInPins != NULL ) | 
|  | QUARTZ_CompList_Free(This->pInPins); | 
|  | if ( This->pOutPins != NULL ) | 
|  | QUARTZ_CompList_Free(This->pOutPins); | 
|  | QUARTZ_FreeMem(This->pwszNameGraph); | 
|  | return E_OUTOFMEMORY; | 
|  | } | 
|  |  | 
|  | InitializeCriticalSection( &This->csFilter ); | 
|  |  | 
|  | return NOERROR; | 
|  | } | 
|  |  | 
|  | void CBaseFilterImpl_UninitIBaseFilter( CBaseFilterImpl* This ) | 
|  | { | 
|  | QUARTZ_CompListItem*	pListItem; | 
|  | IPin*	pPin; | 
|  |  | 
|  | TRACE("(%p)\n",This); | 
|  |  | 
|  | if ( This->pInPins != NULL ) | 
|  | { | 
|  | while ( 1 ) | 
|  | { | 
|  | pListItem = QUARTZ_CompList_GetFirst( This->pInPins ); | 
|  | if ( pListItem == NULL ) | 
|  | break; | 
|  | pPin = (IPin*)QUARTZ_CompList_GetItemPtr( pListItem ); | 
|  | QUARTZ_CompList_RemoveComp( This->pInPins, (IUnknown*)pPin ); | 
|  | } | 
|  |  | 
|  | QUARTZ_CompList_Free( This->pInPins ); | 
|  | This->pInPins = NULL; | 
|  | } | 
|  | if ( This->pOutPins != NULL ) | 
|  | { | 
|  | while ( 1 ) | 
|  | { | 
|  | pListItem = QUARTZ_CompList_GetFirst( This->pOutPins ); | 
|  | if ( pListItem == NULL ) | 
|  | break; | 
|  | pPin = (IPin*)QUARTZ_CompList_GetItemPtr( pListItem ); | 
|  | QUARTZ_CompList_RemoveComp( This->pOutPins, (IUnknown*)pPin ); | 
|  | } | 
|  |  | 
|  | QUARTZ_CompList_Free( This->pOutPins ); | 
|  | This->pOutPins = NULL; | 
|  | } | 
|  |  | 
|  | if ( This->pwszNameGraph != NULL ) | 
|  | { | 
|  | QUARTZ_FreeMem( This->pwszNameGraph ); | 
|  | This->pwszNameGraph = NULL; | 
|  | } | 
|  |  | 
|  | if ( This->pClock != NULL ) | 
|  | { | 
|  | IReferenceClock_Release( This->pClock ); | 
|  | This->pClock = NULL; | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  |