Sweden-Number/dlls/quartz/fgevent.c

673 lines
15 KiB
C

/*
* CLSID_FilterGraph event handling.
*
* 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 "control.h"
#include "evcode.h"
#include "uuids.h"
#include "vfwmsgs.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(quartz);
#include "quartz_private.h"
#include "fgraph.h"
#define EVENTQUEUE_BLOCKSIZE 2
#define EVENTQUEUE_MAX 1024
struct FilterGraph_MEDIAEVENT
{
long lEventCode;
LONG_PTR lParam1;
LONG_PTR lParam2;
};
static HRESULT FGEVENT_KeepEvent(
BOOL bKeep,
long lEventCode, LONG_PTR lParam1, LONG_PTR lParam2 )
{
switch ( lEventCode )
{
/*case EC_COMPLETE:*/
case EC_USERABORT:
break;
case EC_ERRORABORT:
break;
case EC_TIME:
break;
/*case EC_REPAINT:*/
case EC_STREAM_ERROR_STOPPED:
break;
case EC_STREAM_ERROR_STILLPLAYING:
break;
case EC_ERROR_STILLPLAYING:
break;
case EC_PALETTE_CHANGED:
break;
case EC_VIDEO_SIZE_CHANGED:
break;
case EC_QUALITY_CHANGE:
break;
/*case EC_SHUTTING_DOWN:*/
case EC_CLOCK_CHANGED:
break;
case EC_PAUSED:
break;
case EC_OPENING_FILE:
break;
case EC_BUFFERING_DATA:
break;
case EC_FULLSCREEN_LOST:
if ( bKeep )
{
if ( ((IBaseFilter*)lParam2) != NULL )
IBaseFilter_AddRef( (IBaseFilter*)lParam2 );
}
else
{
if ( ((IBaseFilter*)lParam2) != NULL )
IBaseFilter_Release( (IBaseFilter*)lParam2 );
}
break;
/*case EC_ACTIVATE:*/
/*case EC_NEED_RESTART:*/
/*case EC_WINDOW_DESTROYED:*/
/*case EC_DISPLAY_CHANGED:*/
/*case EC_STARVATION:*/
/*case EC_OLE_EVENT:*/
/*case EC_NOTIFY_WINDOW:*/
/*case EC_STREAM_CONTROL_STOPPED:*/
/*case EC_STREAM_CONTROL_STARTED:*/
/*case EC_END_OF_SEGMENT:*/
/*case EC_SEGMENT_STARTED:*/
case EC_LENGTH_CHANGED:
break;
case EC_DEVICE_LOST:
if ( bKeep )
{
if ( ((IUnknown*)lParam1) != NULL )
IUnknown_AddRef( (IUnknown*)lParam1 );
}
else
{
if ( ((IUnknown*)lParam1) != NULL )
IUnknown_Release( (IUnknown*)lParam1 );
}
break;
case EC_STEP_COMPLETE:
break;
case EC_SKIP_FRAMES:
break;
/*case EC_TIMECODE_AVAILABLE:*/
/*case EC_EXTDEVICE_MODE_CHANGE:*/
case EC_GRAPH_CHANGED:
break;
case EC_CLOCK_UNSET:
break;
default:
if ( lEventCode < EC_USER )
{
FIXME( "unknown system event %08lx\n", lEventCode );
return E_INVALIDARG;
}
TRACE( "user event %08lx\n", lEventCode );
break;
}
return NOERROR;
}
/***************************************************************************
*
* CLSID_FilterGraph::IMediaEvent[Ex]
*
*/
static HRESULT WINAPI
IMediaEventEx_fnQueryInterface(IMediaEventEx* iface,REFIID riid,void** ppobj)
{
CFilterGraph_THIS(iface,mediaevent);
TRACE("(%p)->()\n",This);
return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
}
static ULONG WINAPI
IMediaEventEx_fnAddRef(IMediaEventEx* iface)
{
CFilterGraph_THIS(iface,mediaevent);
TRACE("(%p)->()\n",This);
return IUnknown_AddRef(This->unk.punkControl);
}
static ULONG WINAPI
IMediaEventEx_fnRelease(IMediaEventEx* iface)
{
CFilterGraph_THIS(iface,mediaevent);
TRACE("(%p)->()\n",This);
return IUnknown_Release(This->unk.punkControl);
}
static HRESULT WINAPI
IMediaEventEx_fnGetTypeInfoCount(IMediaEventEx* iface,UINT* pcTypeInfo)
{
CFilterGraph_THIS(iface,mediaevent);
FIXME("(%p)->()\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
IMediaEventEx_fnGetTypeInfo(IMediaEventEx* iface,UINT iTypeInfo, LCID lcid, ITypeInfo** ppobj)
{
CFilterGraph_THIS(iface,mediaevent);
FIXME("(%p)->()\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
IMediaEventEx_fnGetIDsOfNames(IMediaEventEx* iface,REFIID riid, LPOLESTR* ppwszName, UINT cNames, LCID lcid, DISPID* pDispId)
{
CFilterGraph_THIS(iface,mediaevent);
FIXME("(%p)->()\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
IMediaEventEx_fnInvoke(IMediaEventEx* iface,DISPID DispId, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarRes, EXCEPINFO* pExcepInfo, UINT* puArgErr)
{
CFilterGraph_THIS(iface,mediaevent);
FIXME("(%p)->()\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
IMediaEventEx_fnGetEventHandle(IMediaEventEx* iface,OAEVENT* hEvent)
{
CFilterGraph_THIS(iface,mediaevent);
TRACE("(%p)->()\n",This);
*hEvent = (OAEVENT)This->m_hMediaEvent;
return NOERROR;
}
static HRESULT WINAPI
IMediaEventEx_fnGetEvent(IMediaEventEx* iface,long* plEventCode,LONG_PTR* plParam1,LONG_PTR* plParam2,long lTimeOut)
{
CFilterGraph_THIS(iface,mediaevent);
ULONG cQueued;
DWORD dw;
DWORD dwStart;
HRESULT hr;
FilterGraph_MEDIAEVENT* pEvent;
TRACE("(%p)->(%p,%p,%p,%ld)\n",This,plEventCode,
plParam1,plParam2,lTimeOut);
if ( plEventCode == NULL || plParam1 == NULL || plParam2 == NULL )
return E_POINTER;
while ( 1 )
{
dwStart = GetTickCount();
dw = WaitForSingleObject( This->m_hMediaEvent, lTimeOut );
if ( dw == WAIT_TIMEOUT )
return VFW_E_TIMEOUT;
if ( dw != WAIT_OBJECT_0 )
return E_FAIL;
EnterCriticalSection( &This->m_csMediaEvents );
hr = S_FALSE;
if ( This->m_cbMediaEventsMax > 0 )
{
cQueued =
(This->m_cbMediaEventsMax +
This->m_cbMediaEventsPut - This->m_cbMediaEventsGet) %
This->m_cbMediaEventsMax;
if ( cQueued > 0 )
{
pEvent = &This->m_pMediaEvents[This->m_cbMediaEventsGet];
*plEventCode = pEvent->lEventCode;
*plParam1 = pEvent->lParam1;
*plParam2 = pEvent->lParam2;
This->m_cbMediaEventsGet = (This->m_cbMediaEventsGet + 1) %
This->m_cbMediaEventsMax;
hr = NOERROR;
if ( This->m_cbMediaEventsPut == This->m_cbMediaEventsGet )
ResetEvent( This->m_hMediaEvent );
}
}
LeaveCriticalSection( &This->m_csMediaEvents );
if ( hr != S_FALSE )
return hr;
if ( lTimeOut != INFINITE )
{
lTimeOut -= GetTickCount() - dwStart;
if ( lTimeOut < 0 )
return VFW_E_TIMEOUT;
}
}
}
static HRESULT WINAPI
IMediaEventEx_fnWaitForCompletion(IMediaEventEx* iface,long lTimeOut,long* plEventCode)
{
CFilterGraph_THIS(iface,mediaevent);
HRESULT hr;
long lEventCode;
LONG_PTR lParam1;
LONG_PTR lParam2;
DWORD dwTimePrev;
DWORD dwTimeCur;
TRACE("(%p)->(%ld,%p)\n",This,lTimeOut,plEventCode);
if ( plEventCode == NULL )
return E_POINTER;
*plEventCode = 0;
dwTimePrev = GetTickCount();
while ( 1 )
{
hr = IMediaEventEx_GetEvent(
CFilterGraph_IMediaEventEx(This),
&lEventCode,&lParam1,&lParam2,lTimeOut);
if ( hr == VFW_E_TIMEOUT )
hr = E_ABORT;
if ( hr != NOERROR )
return hr;
IMediaEventEx_FreeEventParams(
CFilterGraph_IMediaEventEx(This),
lEventCode,lParam1,lParam2);
if ( lEventCode == EC_COMPLETE ||
lEventCode == EC_ERRORABORT ||
lEventCode == EC_USERABORT )
{
*plEventCode = lEventCode;
return NOERROR;
}
if ( lTimeOut != INFINITE )
{
dwTimeCur = GetTickCount();
lTimeOut -= dwTimeCur - dwTimePrev;
dwTimePrev = dwTimeCur;
if ( lTimeOut < 0 )
return E_ABORT;
}
}
}
static HRESULT WINAPI
IMediaEventEx_fnCancelDefaultHandling(IMediaEventEx* iface,long lEventCode)
{
CFilterGraph_THIS(iface,mediaevent);
FIXME("(%p)->() stub!\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
IMediaEventEx_fnRestoreDefaultHandling(IMediaEventEx* iface,long lEventCode)
{
CFilterGraph_THIS(iface,mediaevent);
FIXME("(%p)->() stub!\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI
IMediaEventEx_fnFreeEventParams(IMediaEventEx* iface,long lEventCode,LONG_PTR lParam1,LONG_PTR lParam2)
{
CFilterGraph_THIS(iface,mediaevent);
TRACE("(%p)->(%08lx,%08x,%08x)\n",This,lEventCode,lParam1,lParam2);
return FGEVENT_KeepEvent( FALSE, lEventCode, lParam1, lParam2 );
}
static HRESULT WINAPI
IMediaEventEx_fnSetNotifyWindow(IMediaEventEx* iface,OAHWND hwnd,long message,LONG_PTR lParam)
{
CFilterGraph_THIS(iface,mediaevent);
TRACE("(%p)->(%08x,%08lx,%08x)\n",This,hwnd,message,lParam);
EnterCriticalSection( &This->m_csMediaEvents );
This->m_hwndEventNotify = (HWND)hwnd;
This->m_lEventNotifyMsg = message;
This->m_lEventNotifyParam = lParam;
LeaveCriticalSection( &This->m_csMediaEvents );
return NOERROR;
}
static HRESULT WINAPI
IMediaEventEx_fnSetNotifyFlags(IMediaEventEx* iface,long lNotifyFlags)
{
CFilterGraph_THIS(iface,mediaevent);
TRACE("(%p)->(%ld)\n",This,lNotifyFlags);
if ( lNotifyFlags != 0 && lNotifyFlags != 1 )
return E_INVALIDARG;
EnterCriticalSection( &This->m_csMediaEvents );
This->m_lEventNotifyFlags = lNotifyFlags;
LeaveCriticalSection( &This->m_csMediaEvents );
return NOERROR;
}
static HRESULT WINAPI
IMediaEventEx_fnGetNotifyFlags(IMediaEventEx* iface,long* plNotifyFlags)
{
CFilterGraph_THIS(iface,mediaevent);
TRACE("(%p)->(%p)\n",This,plNotifyFlags);
if ( plNotifyFlags == NULL )
return E_POINTER;
EnterCriticalSection( &This->m_csMediaEvents );
*plNotifyFlags = This->m_lEventNotifyFlags;
LeaveCriticalSection( &This->m_csMediaEvents );
return NOERROR;
}
static ICOM_VTABLE(IMediaEventEx) imediaevent =
{
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
/* IUnknown fields */
IMediaEventEx_fnQueryInterface,
IMediaEventEx_fnAddRef,
IMediaEventEx_fnRelease,
/* IDispatch fields */
IMediaEventEx_fnGetTypeInfoCount,
IMediaEventEx_fnGetTypeInfo,
IMediaEventEx_fnGetIDsOfNames,
IMediaEventEx_fnInvoke,
/* IMediaEvent fields */
IMediaEventEx_fnGetEventHandle,
IMediaEventEx_fnGetEvent,
IMediaEventEx_fnWaitForCompletion,
IMediaEventEx_fnCancelDefaultHandling,
IMediaEventEx_fnRestoreDefaultHandling,
IMediaEventEx_fnFreeEventParams,
/* IMediaEventEx fields */
IMediaEventEx_fnSetNotifyWindow,
IMediaEventEx_fnSetNotifyFlags,
IMediaEventEx_fnGetNotifyFlags,
};
HRESULT CFilterGraph_InitIMediaEventEx( CFilterGraph* pfg )
{
TRACE("(%p)\n",pfg);
ICOM_VTBL(&pfg->mediaevent) = &imediaevent;
pfg->m_hMediaEvent = CreateEventA( NULL, TRUE, FALSE, NULL );
if ( pfg->m_hMediaEvent == (HANDLE)NULL )
return E_OUTOFMEMORY;
InitializeCriticalSection( &pfg->m_csMediaEvents );
pfg->m_pMediaEvents = NULL;
pfg->m_cbMediaEventsPut = 0;
pfg->m_cbMediaEventsGet = 0;
pfg->m_cbMediaEventsMax = 0;
pfg->m_hwndEventNotify = (HWND)NULL;
pfg->m_lEventNotifyMsg = 0;
pfg->m_lEventNotifyParam = 0;
pfg->m_lEventNotifyFlags = 0;
return NOERROR;
}
void CFilterGraph_UninitIMediaEventEx( CFilterGraph* pfg )
{
HRESULT hr;
long lEventCode;
LONG_PTR lParam1;
LONG_PTR lParam2;
TRACE("(%p)\n",pfg);
while ( 1 )
{
hr = IMediaEventEx_GetEvent(
CFilterGraph_IMediaEventEx(pfg),
&lEventCode,&lParam1,&lParam2,0);
if ( hr != NOERROR )
break;
IMediaEventEx_FreeEventParams(
CFilterGraph_IMediaEventEx(pfg),
lEventCode,lParam1,lParam2);
}
if ( pfg->m_pMediaEvents != NULL )
{
QUARTZ_FreeMem( pfg->m_pMediaEvents );
pfg->m_pMediaEvents = NULL;
}
DeleteCriticalSection( &pfg->m_csMediaEvents );
CloseHandle( pfg->m_hMediaEvent );
}
/***************************************************************************
*
* CLSID_FilterGraph::IMediaEventSink
*
*/
static HRESULT WINAPI
IMediaEventSink_fnQueryInterface(IMediaEventSink* iface,REFIID riid,void** ppobj)
{
CFilterGraph_THIS(iface,mediaeventsink);
TRACE("(%p)->()\n",This);
return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
}
static ULONG WINAPI
IMediaEventSink_fnAddRef(IMediaEventSink* iface)
{
CFilterGraph_THIS(iface,mediaeventsink);
TRACE("(%p)->()\n",This);
return IUnknown_AddRef(This->unk.punkControl);
}
static ULONG WINAPI
IMediaEventSink_fnRelease(IMediaEventSink* iface)
{
CFilterGraph_THIS(iface,mediaeventsink);
TRACE("(%p)->()\n",This);
return IUnknown_Release(This->unk.punkControl);
}
static HRESULT WINAPI
IMediaEventSink_fnNotify(IMediaEventSink* iface,long lEventCode,LONG_PTR lParam1,LONG_PTR lParam2)
{
CFilterGraph_THIS(iface,mediaeventsink);
HRESULT hr = NOERROR;
ULONG cQueued;
ULONG cTemp;
FilterGraph_MEDIAEVENT* pEvent;
TRACE("(%p)->(%08lx,%08x,%08x) stub!\n",This,lEventCode,lParam1,lParam2);
EnterCriticalSection( &This->m_csMediaEvents );
/* allocate a new entry. */
if ( This->m_cbMediaEventsMax == 0 )
cQueued = 0;
else
cQueued =
(This->m_cbMediaEventsMax +
This->m_cbMediaEventsPut - This->m_cbMediaEventsGet) %
This->m_cbMediaEventsMax;
if ( (cQueued + 1) >= This->m_cbMediaEventsMax )
{
if ( This->m_cbMediaEventsMax >= EVENTQUEUE_MAX )
{
hr = E_FAIL;
goto end;
}
pEvent = (FilterGraph_MEDIAEVENT*)
QUARTZ_AllocMem( sizeof(FilterGraph_MEDIAEVENT) *
(This->m_cbMediaEventsMax+EVENTQUEUE_BLOCKSIZE) );
if ( pEvent == NULL )
{
hr = E_OUTOFMEMORY;
goto end;
}
if ( cQueued > 0 )
{
if ( (This->m_cbMediaEventsGet + cQueued) >=
This->m_cbMediaEventsMax )
{
cTemp = This->m_cbMediaEventsMax - This->m_cbMediaEventsGet;
memcpy(
pEvent,
&This->m_pMediaEvents[This->m_cbMediaEventsGet],
sizeof(FilterGraph_MEDIAEVENT) * cTemp );
memcpy(
pEvent + cTemp,
&This->m_pMediaEvents[0],
sizeof(FilterGraph_MEDIAEVENT) * (cQueued - cTemp) );
}
else
{
memcpy(
pEvent,
&This->m_pMediaEvents[This->m_cbMediaEventsGet],
sizeof(FilterGraph_MEDIAEVENT) * cQueued );
}
QUARTZ_FreeMem( This->m_pMediaEvents );
}
This->m_pMediaEvents = pEvent;
This->m_cbMediaEventsMax += EVENTQUEUE_BLOCKSIZE;
This->m_cbMediaEventsPut = cQueued;
This->m_cbMediaEventsGet = 0;
}
/* duplicate params if necessary. */
hr = FGEVENT_KeepEvent( TRUE, lEventCode, lParam1, lParam2 );
if ( FAILED(hr) )
goto end;
/* add to the queue. */
pEvent = &This->m_pMediaEvents[This->m_cbMediaEventsPut];
pEvent->lEventCode = lEventCode;
pEvent->lParam1 = lParam1;
pEvent->lParam2 = lParam2;
This->m_cbMediaEventsPut =
(This->m_cbMediaEventsPut + 1) % This->m_cbMediaEventsMax;
SetEvent( This->m_hMediaEvent );
if ( This->m_hwndEventNotify != (HWND)NULL &&
This->m_lEventNotifyFlags == 0 )
{
PostMessageA(
This->m_hwndEventNotify,
This->m_lEventNotifyMsg,
(WPARAM)0,
(LPARAM)This->m_lEventNotifyParam );
}
hr = NOERROR;
end:
LeaveCriticalSection( &This->m_csMediaEvents );
return hr;
}
static ICOM_VTABLE(IMediaEventSink) imediaeventsink =
{
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
/* IUnknown fields */
IMediaEventSink_fnQueryInterface,
IMediaEventSink_fnAddRef,
IMediaEventSink_fnRelease,
/* IMediaEventSink fields */
IMediaEventSink_fnNotify,
};
HRESULT CFilterGraph_InitIMediaEventSink( CFilterGraph* pfg )
{
TRACE("(%p)\n",pfg);
ICOM_VTBL(&pfg->mediaeventsink) = &imediaeventsink;
return NOERROR;
}
void CFilterGraph_UninitIMediaEventSink( CFilterGraph* pfg )
{
TRACE("(%p)\n",pfg);
}