/* * Implementation of IMediaFilter for FilterGraph. * * FIXME - stub. * * hidenori@a2.ctktv.ne.jp */ #include "config.h" #include "windef.h" #include "winbase.h" #include "wingdi.h" #include "winuser.h" #include "winerror.h" #include "strmif.h" #include "control.h" #include "uuids.h" #include "vfwmsgs.h" #include "evcode.h" #include "debugtools.h" DEFAULT_DEBUG_CHANNEL(quartz); #include "quartz_private.h" #include "fgraph.h" #define WINE_QUARTZ_POLL_INTERVAL 10 /*****************************************************************************/ static HRESULT CFilterGraph_PollGraphState( CFilterGraph* This, FILTER_STATE* pState) { HRESULT hr; QUARTZ_CompListItem* pItem; IBaseFilter* pFilter; hr = S_OK; *pState = State_Stopped; EnterCriticalSection( &This->m_csGraphState ); QUARTZ_CompList_Lock( This->m_pFilterList ); pItem = QUARTZ_CompList_GetFirst( This->m_pFilterList ); while ( pItem != NULL ) { pFilter = (IBaseFilter*)QUARTZ_CompList_GetItemPtr( pItem ); hr = IBaseFilter_GetState( pFilter, (DWORD)0, pState ); if ( hr != S_OK ) break; pItem = QUARTZ_CompList_GetNext( This->m_pFilterList, pItem ); } QUARTZ_CompList_Unlock( This->m_pFilterList ); LeaveCriticalSection( &This->m_csGraphState ); TRACE( "returns %08lx, state %d\n", hr, *pState ); return hr; } /*****************************************************************************/ static HRESULT WINAPI IMediaFilter_fnQueryInterface(IMediaFilter* iface,REFIID riid,void** ppobj) { CFilterGraph_THIS(iface,mediafilter); TRACE("(%p)->()\n",This); return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj); } static ULONG WINAPI IMediaFilter_fnAddRef(IMediaFilter* iface) { CFilterGraph_THIS(iface,mediafilter); TRACE("(%p)->()\n",This); return IUnknown_AddRef(This->unk.punkControl); } static ULONG WINAPI IMediaFilter_fnRelease(IMediaFilter* iface) { CFilterGraph_THIS(iface,mediafilter); TRACE("(%p)->()\n",This); return IUnknown_Release(This->unk.punkControl); } static HRESULT WINAPI IMediaFilter_fnGetClassID(IMediaFilter* iface,CLSID* pclsid) { CFilterGraph_THIS(iface,mediafilter); TRACE("(%p)->()\n",This); return IPersist_GetClassID( CFilterGraph_IPersist(This),pclsid); } static HRESULT WINAPI IMediaFilter_fnStop(IMediaFilter* iface) { CFilterGraph_THIS(iface,mediafilter); HRESULT hr; HRESULT hrFilter; QUARTZ_CompListItem* pItem; IBaseFilter* pFilter; TRACE("(%p)->()\n",This); hr = S_OK; EnterCriticalSection( &This->m_csGraphState ); if ( This->m_stateGraph != State_Stopped ) { /* IDistributorNotify_Stop() */ QUARTZ_CompList_Lock( This->m_pFilterList ); pItem = QUARTZ_CompList_GetFirst( This->m_pFilterList ); while ( pItem != NULL ) { pFilter = (IBaseFilter*)QUARTZ_CompList_GetItemPtr( pItem ); hrFilter = IBaseFilter_Stop( pFilter ); if ( hrFilter != S_OK ) { if ( SUCCEEDED(hr) ) hr = hrFilter; } pItem = QUARTZ_CompList_GetNext( This->m_pFilterList, pItem ); } QUARTZ_CompList_Unlock( This->m_pFilterList ); This->m_stateGraph = State_Stopped; } LeaveCriticalSection( &This->m_csGraphState ); return hr; } static HRESULT WINAPI IMediaFilter_fnPause(IMediaFilter* iface) { CFilterGraph_THIS(iface,mediafilter); HRESULT hr; HRESULT hrFilter; QUARTZ_CompListItem* pItem; IBaseFilter* pFilter; TRACE("(%p)->()\n",This); hr = S_OK; EnterCriticalSection( &This->m_csGraphState ); if ( This->m_stateGraph != State_Paused ) { /* IDistributorNotify_Pause() */ QUARTZ_CompList_Lock( This->m_pFilterList ); pItem = QUARTZ_CompList_GetFirst( This->m_pFilterList ); while ( pItem != NULL ) { pFilter = (IBaseFilter*)QUARTZ_CompList_GetItemPtr( pItem ); hrFilter = IBaseFilter_Pause( pFilter ); if ( hrFilter != S_OK ) { if ( SUCCEEDED(hr) ) hr = hrFilter; } pItem = QUARTZ_CompList_GetNext( This->m_pFilterList, pItem ); } QUARTZ_CompList_Unlock( This->m_pFilterList ); This->m_stateGraph = State_Paused; } LeaveCriticalSection( &This->m_csGraphState ); return hr; } static HRESULT WINAPI IMediaFilter_fnRun(IMediaFilter* iface,REFERENCE_TIME rtStart) { CFilterGraph_THIS(iface,mediafilter); HRESULT hr; HRESULT hrFilter; QUARTZ_CompListItem* pItem; IBaseFilter* pFilter; IReferenceClock* pClock; TRACE("(%p)->()\n",This); EnterCriticalSection( &This->m_csGraphState ); if ( This->m_stateGraph == State_Stopped ) { hr = IMediaFilter_Pause(iface); if ( FAILED(hr) ) goto end; } /* handle the special time. */ if ( rtStart == (REFERENCE_TIME)0 ) { hr = IMediaFilter_GetSyncSource(iface,&pClock); if ( hr == S_OK && pClock != NULL ) { IReferenceClock_GetTime(pClock,&rtStart); IReferenceClock_Release(pClock); } } hr = NOERROR; if ( This->m_stateGraph != State_Running ) { /* IDistributorNotify_Run() */ QUARTZ_CompList_Lock( This->m_pFilterList ); pItem = QUARTZ_CompList_GetFirst( This->m_pFilterList ); while ( pItem != NULL ) { pFilter = (IBaseFilter*)QUARTZ_CompList_GetItemPtr( pItem ); hrFilter = IBaseFilter_Run( pFilter, rtStart ); if ( hrFilter != S_OK ) { if ( SUCCEEDED(hr) ) hr = hrFilter; } pItem = QUARTZ_CompList_GetNext( This->m_pFilterList, pItem ); } QUARTZ_CompList_Unlock( This->m_pFilterList ); This->m_stateGraph = State_Running; } end: LeaveCriticalSection( &This->m_csGraphState ); return hr; } static HRESULT WINAPI IMediaFilter_fnGetState(IMediaFilter* iface,DWORD dwTimeOut,FILTER_STATE* pState) { CFilterGraph_THIS(iface,mediafilter); HRESULT hr; DWORD dwTickStart; DWORD dwTickUsed; TRACE("(%p)->(%p)\n",This,pState); if ( pState == NULL ) return E_POINTER; dwTickStart = GetTickCount(); while ( 1 ) { hr = CFilterGraph_PollGraphState( This, pState ); if ( hr != VFW_S_STATE_INTERMEDIATE ) break; if ( dwTimeOut == 0 ) break; Sleep( (dwTimeOut >= WINE_QUARTZ_POLL_INTERVAL) ? WINE_QUARTZ_POLL_INTERVAL : dwTimeOut ); dwTickUsed = GetTickCount() - dwTickStart; dwTickStart += dwTickUsed; if ( dwTimeOut <= dwTickUsed ) dwTimeOut = 0; else dwTimeOut -= dwTickUsed; } EnterCriticalSection( &This->m_csGraphState ); *pState = This->m_stateGraph; LeaveCriticalSection( &This->m_csGraphState ); return hr; } static HRESULT WINAPI IMediaFilter_fnSetSyncSource(IMediaFilter* iface,IReferenceClock* pobjClock) { CFilterGraph_THIS(iface,mediafilter); QUARTZ_CompListItem* pItem; IBaseFilter* pFilter; HRESULT hr = NOERROR; HRESULT hrCur; TRACE("(%p)->(%p)\n",This,pobjClock); /* IDistributorNotify_SetSyncSource() */ EnterCriticalSection( &This->m_csClock ); QUARTZ_CompList_Lock( This->m_pFilterList ); if ( This->m_pClock != NULL ) { IReferenceClock_Release(This->m_pClock); This->m_pClock = NULL; } This->m_pClock = pobjClock; if ( pobjClock != NULL ) IReferenceClock_AddRef( pobjClock ); pItem = QUARTZ_CompList_GetFirst( This->m_pFilterList ); while ( pItem != NULL ) { pFilter = (IBaseFilter*)QUARTZ_CompList_GetItemPtr( pItem ); hrCur = IBaseFilter_SetSyncSource(pFilter,pobjClock); if ( FAILED(hrCur) ) hr = hrCur; pItem = QUARTZ_CompList_GetNext( This->m_pFilterList, pItem ); } QUARTZ_CompList_Unlock( This->m_pFilterList ); IMediaEventSink_Notify(CFilterGraph_IMediaEventSink(This), EC_CLOCK_CHANGED, 0, 0); LeaveCriticalSection( &This->m_csClock ); TRACE( "hr = %08lx\n", hr ); return hr; } static HRESULT WINAPI IMediaFilter_fnGetSyncSource(IMediaFilter* iface,IReferenceClock** ppobjClock) { CFilterGraph_THIS(iface,mediafilter); HRESULT hr = VFW_E_NO_CLOCK; TRACE("(%p)->(%p)\n",This,ppobjClock); if ( ppobjClock == NULL ) return E_POINTER; EnterCriticalSection( &This->m_csClock ); *ppobjClock = This->m_pClock; if ( This->m_pClock != NULL ) { hr = NOERROR; IReferenceClock_AddRef( This->m_pClock ); } LeaveCriticalSection( &This->m_csClock ); TRACE( "hr = %08lx\n", hr ); return hr; } static ICOM_VTABLE(IMediaFilter) imediafilter = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE /* IUnknown fields */ IMediaFilter_fnQueryInterface, IMediaFilter_fnAddRef, IMediaFilter_fnRelease, /* IPersist fields */ IMediaFilter_fnGetClassID, /* IMediaFilter fields */ IMediaFilter_fnStop, IMediaFilter_fnPause, IMediaFilter_fnRun, IMediaFilter_fnGetState, IMediaFilter_fnSetSyncSource, IMediaFilter_fnGetSyncSource, }; HRESULT CFilterGraph_InitIMediaFilter( CFilterGraph* pfg ) { TRACE("(%p)\n",pfg); ICOM_VTBL(&pfg->mediafilter) = &imediafilter; InitializeCriticalSection( &pfg->m_csGraphState ); InitializeCriticalSection( &pfg->m_csClock ); pfg->m_stateGraph = State_Stopped; pfg->m_pClock = NULL; return NOERROR; } void CFilterGraph_UninitIMediaFilter( CFilterGraph* pfg ) { TRACE("(%p)\n",pfg); if ( pfg->m_pClock != NULL ) { IReferenceClock_Release( pfg->m_pClock ); pfg->m_pClock = NULL; } DeleteCriticalSection( &pfg->m_csGraphState ); DeleteCriticalSection( &pfg->m_csClock ); }