Sweden-Number/dlls/quartz/basefilt.c

587 lines
13 KiB
C

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