2 * CLSID_FilterGraph event handling.
4 * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
37 #include "quartz_private.h"
40 #define EVENTQUEUE_BLOCKSIZE 2
41 #define EVENTQUEUE_MAX 1024
43 struct FilterGraph_MEDIAEVENT
51 static HRESULT FGEVENT_KeepEvent(
53 long lEventCode, LONG_PTR lParam1, LONG_PTR lParam2 )
65 case EC_STREAM_ERROR_STOPPED:
67 case EC_STREAM_ERROR_STILLPLAYING:
69 case EC_ERROR_STILLPLAYING:
71 case EC_PALETTE_CHANGED:
73 case EC_VIDEO_SIZE_CHANGED:
75 case EC_QUALITY_CHANGE:
77 /*case EC_SHUTTING_DOWN:*/
78 case EC_CLOCK_CHANGED:
85 case EC_BUFFERING_DATA:
87 case EC_FULLSCREEN_LOST:
90 if ( ((IBaseFilter*)lParam2) != NULL )
91 IBaseFilter_AddRef( (IBaseFilter*)lParam2 );
95 if ( ((IBaseFilter*)lParam2) != NULL )
96 IBaseFilter_Release( (IBaseFilter*)lParam2 );
100 /*case EC_NEED_RESTART:*/
101 /*case EC_WINDOW_DESTROYED:*/
102 /*case EC_DISPLAY_CHANGED:*/
103 /*case EC_STARVATION:*/
104 /*case EC_OLE_EVENT:*/
105 /*case EC_NOTIFY_WINDOW:*/
106 /*case EC_STREAM_CONTROL_STOPPED:*/
107 /*case EC_STREAM_CONTROL_STARTED:*/
108 /*case EC_END_OF_SEGMENT:*/
109 /*case EC_SEGMENT_STARTED:*/
110 case EC_LENGTH_CHANGED:
115 if ( ((IUnknown*)lParam1) != NULL )
116 IUnknown_AddRef( (IUnknown*)lParam1 );
120 if ( ((IUnknown*)lParam1) != NULL )
121 IUnknown_Release( (IUnknown*)lParam1 );
125 case EC_STEP_COMPLETE:
130 /*case EC_TIMECODE_AVAILABLE:*/
131 /*case EC_EXTDEVICE_MODE_CHANGE:*/
133 case EC_GRAPH_CHANGED:
139 if ( lEventCode < EC_USER )
141 FIXME( "unknown system event %08lx\n", lEventCode );
144 TRACE( "user event %08lx\n", lEventCode );
151 /***************************************************************************
153 * CLSID_FilterGraph::IMediaEvent[Ex]
157 static HRESULT WINAPI
158 IMediaEventEx_fnQueryInterface(IMediaEventEx* iface,REFIID riid,void** ppobj)
160 CFilterGraph_THIS(iface,mediaevent);
162 TRACE("(%p)->()\n",This);
164 return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
168 IMediaEventEx_fnAddRef(IMediaEventEx* iface)
170 CFilterGraph_THIS(iface,mediaevent);
172 TRACE("(%p)->()\n",This);
174 return IUnknown_AddRef(This->unk.punkControl);
178 IMediaEventEx_fnRelease(IMediaEventEx* iface)
180 CFilterGraph_THIS(iface,mediaevent);
182 TRACE("(%p)->()\n",This);
184 return IUnknown_Release(This->unk.punkControl);
187 static HRESULT WINAPI
188 IMediaEventEx_fnGetTypeInfoCount(IMediaEventEx* iface,UINT* pcTypeInfo)
190 CFilterGraph_THIS(iface,mediaevent);
192 FIXME("(%p)->()\n",This);
197 static HRESULT WINAPI
198 IMediaEventEx_fnGetTypeInfo(IMediaEventEx* iface,UINT iTypeInfo, LCID lcid, ITypeInfo** ppobj)
200 CFilterGraph_THIS(iface,mediaevent);
202 FIXME("(%p)->()\n",This);
207 static HRESULT WINAPI
208 IMediaEventEx_fnGetIDsOfNames(IMediaEventEx* iface,REFIID riid, LPOLESTR* ppwszName, UINT cNames, LCID lcid, DISPID* pDispId)
210 CFilterGraph_THIS(iface,mediaevent);
212 FIXME("(%p)->()\n",This);
217 static HRESULT WINAPI
218 IMediaEventEx_fnInvoke(IMediaEventEx* iface,DISPID DispId, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarRes, EXCEPINFO* pExcepInfo, UINT* puArgErr)
220 CFilterGraph_THIS(iface,mediaevent);
222 FIXME("(%p)->()\n",This);
228 static HRESULT WINAPI
229 IMediaEventEx_fnGetEventHandle(IMediaEventEx* iface,OAEVENT* hEvent)
231 CFilterGraph_THIS(iface,mediaevent);
233 TRACE("(%p)->()\n",This);
235 *hEvent = (OAEVENT)This->m_hMediaEvent;
240 static HRESULT WINAPI
241 IMediaEventEx_fnGetEvent(IMediaEventEx* iface,long* plEventCode,LONG_PTR* plParam1,LONG_PTR* plParam2,long lTimeOut)
243 CFilterGraph_THIS(iface,mediaevent);
248 FilterGraph_MEDIAEVENT* pEvent;
250 TRACE("(%p)->(%p,%p,%p,%ld)\n",This,plEventCode,
251 plParam1,plParam2,lTimeOut);
253 if ( plEventCode == NULL || plParam1 == NULL || plParam2 == NULL )
258 dwStart = GetTickCount();
259 dw = WaitForSingleObject( This->m_hMediaEvent, lTimeOut );
260 if ( dw == WAIT_TIMEOUT )
261 return VFW_E_TIMEOUT;
262 if ( dw != WAIT_OBJECT_0 )
265 EnterCriticalSection( &This->m_csMediaEvents );
267 if ( This->m_cbMediaEventsMax > 0 )
270 (This->m_cbMediaEventsMax +
271 This->m_cbMediaEventsPut - This->m_cbMediaEventsGet) %
272 This->m_cbMediaEventsMax;
275 pEvent = &This->m_pMediaEvents[This->m_cbMediaEventsGet];
276 *plEventCode = pEvent->lEventCode;
277 *plParam1 = pEvent->lParam1;
278 *plParam2 = pEvent->lParam2;
279 This->m_cbMediaEventsGet = (This->m_cbMediaEventsGet + 1) %
280 This->m_cbMediaEventsMax;
283 if ( This->m_cbMediaEventsPut == This->m_cbMediaEventsGet )
284 ResetEvent( This->m_hMediaEvent );
287 LeaveCriticalSection( &This->m_csMediaEvents );
291 if ( lTimeOut != INFINITE )
293 lTimeOut -= GetTickCount() - dwStart;
295 return VFW_E_TIMEOUT;
300 static HRESULT WINAPI
301 IMediaEventEx_fnWaitForCompletion(IMediaEventEx* iface,long lTimeOut,long* plEventCode)
303 CFilterGraph_THIS(iface,mediaevent);
311 TRACE("(%p)->(%ld,%p)\n",This,lTimeOut,plEventCode);
313 if ( plEventCode == NULL )
317 dwTimePrev = GetTickCount();
321 hr = IMediaEventEx_GetEvent(
322 CFilterGraph_IMediaEventEx(This),
323 &lEventCode,&lParam1,&lParam2,lTimeOut);
324 if ( hr == VFW_E_TIMEOUT )
328 IMediaEventEx_FreeEventParams(
329 CFilterGraph_IMediaEventEx(This),
330 lEventCode,lParam1,lParam2);
332 if ( lEventCode == EC_COMPLETE ||
333 lEventCode == EC_ERRORABORT ||
334 lEventCode == EC_USERABORT )
336 *plEventCode = lEventCode;
340 if ( lTimeOut != INFINITE )
342 dwTimeCur = GetTickCount();
343 lTimeOut -= dwTimeCur - dwTimePrev;
344 dwTimePrev = dwTimeCur;
351 static HRESULT WINAPI
352 IMediaEventEx_fnCancelDefaultHandling(IMediaEventEx* iface,long lEventCode)
354 CFilterGraph_THIS(iface,mediaevent);
356 FIXME("(%p)->() stub!\n",This);
361 static HRESULT WINAPI
362 IMediaEventEx_fnRestoreDefaultHandling(IMediaEventEx* iface,long lEventCode)
364 CFilterGraph_THIS(iface,mediaevent);
366 FIXME("(%p)->() stub!\n",This);
371 static HRESULT WINAPI
372 IMediaEventEx_fnFreeEventParams(IMediaEventEx* iface,long lEventCode,LONG_PTR lParam1,LONG_PTR lParam2)
374 CFilterGraph_THIS(iface,mediaevent);
376 TRACE("(%p)->(%08lx,%08x,%08x)\n",This,lEventCode,lParam1,lParam2);
378 return FGEVENT_KeepEvent( FALSE, lEventCode, lParam1, lParam2 );
381 static HRESULT WINAPI
382 IMediaEventEx_fnSetNotifyWindow(IMediaEventEx* iface,OAHWND hwnd,long message,LONG_PTR lParam)
384 CFilterGraph_THIS(iface,mediaevent);
386 TRACE("(%p)->(%08x,%08lx,%08x)\n",This,hwnd,message,lParam);
388 EnterCriticalSection( &This->m_csMediaEvents );
389 This->m_hwndEventNotify = (HWND)hwnd;
390 This->m_lEventNotifyMsg = message;
391 This->m_lEventNotifyParam = lParam;
392 LeaveCriticalSection( &This->m_csMediaEvents );
397 static HRESULT WINAPI
398 IMediaEventEx_fnSetNotifyFlags(IMediaEventEx* iface,long lNotifyFlags)
400 CFilterGraph_THIS(iface,mediaevent);
402 TRACE("(%p)->(%ld)\n",This,lNotifyFlags);
404 if ( lNotifyFlags != 0 && lNotifyFlags != 1 )
407 EnterCriticalSection( &This->m_csMediaEvents );
408 This->m_lEventNotifyFlags = lNotifyFlags;
409 LeaveCriticalSection( &This->m_csMediaEvents );
414 static HRESULT WINAPI
415 IMediaEventEx_fnGetNotifyFlags(IMediaEventEx* iface,long* plNotifyFlags)
417 CFilterGraph_THIS(iface,mediaevent);
419 TRACE("(%p)->(%p)\n",This,plNotifyFlags);
421 if ( plNotifyFlags == NULL )
424 EnterCriticalSection( &This->m_csMediaEvents );
425 *plNotifyFlags = This->m_lEventNotifyFlags;
426 LeaveCriticalSection( &This->m_csMediaEvents );
433 static ICOM_VTABLE(IMediaEventEx) imediaevent =
435 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
436 /* IUnknown fields */
437 IMediaEventEx_fnQueryInterface,
438 IMediaEventEx_fnAddRef,
439 IMediaEventEx_fnRelease,
440 /* IDispatch fields */
441 IMediaEventEx_fnGetTypeInfoCount,
442 IMediaEventEx_fnGetTypeInfo,
443 IMediaEventEx_fnGetIDsOfNames,
444 IMediaEventEx_fnInvoke,
445 /* IMediaEvent fields */
446 IMediaEventEx_fnGetEventHandle,
447 IMediaEventEx_fnGetEvent,
448 IMediaEventEx_fnWaitForCompletion,
449 IMediaEventEx_fnCancelDefaultHandling,
450 IMediaEventEx_fnRestoreDefaultHandling,
451 IMediaEventEx_fnFreeEventParams,
452 /* IMediaEventEx fields */
453 IMediaEventEx_fnSetNotifyWindow,
454 IMediaEventEx_fnSetNotifyFlags,
455 IMediaEventEx_fnGetNotifyFlags,
459 HRESULT CFilterGraph_InitIMediaEventEx( CFilterGraph* pfg )
462 ICOM_VTBL(&pfg->mediaevent) = &imediaevent;
464 pfg->m_hMediaEvent = CreateEventA( NULL, TRUE, FALSE, NULL );
465 if ( pfg->m_hMediaEvent == (HANDLE)NULL )
466 return E_OUTOFMEMORY;
468 InitializeCriticalSection( &pfg->m_csMediaEvents );
469 pfg->m_pMediaEvents = NULL;
470 pfg->m_cbMediaEventsPut = 0;
471 pfg->m_cbMediaEventsGet = 0;
472 pfg->m_cbMediaEventsMax = 0;
473 pfg->m_hwndEventNotify = (HWND)NULL;
474 pfg->m_lEventNotifyMsg = 0;
475 pfg->m_lEventNotifyParam = 0;
476 pfg->m_lEventNotifyFlags = 0;
481 void CFilterGraph_UninitIMediaEventEx( CFilterGraph* pfg )
492 hr = IMediaEventEx_GetEvent(
493 CFilterGraph_IMediaEventEx(pfg),
494 &lEventCode,&lParam1,&lParam2,0);
497 IMediaEventEx_FreeEventParams(
498 CFilterGraph_IMediaEventEx(pfg),
499 lEventCode,lParam1,lParam2);
502 if ( pfg->m_pMediaEvents != NULL )
504 QUARTZ_FreeMem( pfg->m_pMediaEvents );
505 pfg->m_pMediaEvents = NULL;
508 DeleteCriticalSection( &pfg->m_csMediaEvents );
509 CloseHandle( pfg->m_hMediaEvent );
512 /***************************************************************************
514 * CLSID_FilterGraph::IMediaEventSink
518 static HRESULT WINAPI
519 IMediaEventSink_fnQueryInterface(IMediaEventSink* iface,REFIID riid,void** ppobj)
521 CFilterGraph_THIS(iface,mediaeventsink);
523 TRACE("(%p)->()\n",This);
525 return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
529 IMediaEventSink_fnAddRef(IMediaEventSink* iface)
531 CFilterGraph_THIS(iface,mediaeventsink);
533 TRACE("(%p)->()\n",This);
535 return IUnknown_AddRef(This->unk.punkControl);
539 IMediaEventSink_fnRelease(IMediaEventSink* iface)
541 CFilterGraph_THIS(iface,mediaeventsink);
543 TRACE("(%p)->()\n",This);
545 return IUnknown_Release(This->unk.punkControl);
548 static HRESULT WINAPI
549 IMediaEventSink_fnNotify(IMediaEventSink* iface,long lEventCode,LONG_PTR lParam1,LONG_PTR lParam2)
551 CFilterGraph_THIS(iface,mediaeventsink);
552 HRESULT hr = NOERROR;
555 FilterGraph_MEDIAEVENT* pEvent;
557 TRACE("(%p)->(%08lx,%08x,%08x) stub!\n",This,lEventCode,lParam1,lParam2);
559 EnterCriticalSection( &This->m_csMediaEvents );
561 /* allocate a new entry. */
562 if ( This->m_cbMediaEventsMax == 0 )
566 (This->m_cbMediaEventsMax +
567 This->m_cbMediaEventsPut - This->m_cbMediaEventsGet) %
568 This->m_cbMediaEventsMax;
570 if ( (cQueued + 1) >= This->m_cbMediaEventsMax )
572 if ( This->m_cbMediaEventsMax >= EVENTQUEUE_MAX )
577 pEvent = (FilterGraph_MEDIAEVENT*)
578 QUARTZ_AllocMem( sizeof(FilterGraph_MEDIAEVENT) *
579 (This->m_cbMediaEventsMax+EVENTQUEUE_BLOCKSIZE) );
580 if ( pEvent == NULL )
587 if ( (This->m_cbMediaEventsGet + cQueued) >=
588 This->m_cbMediaEventsMax )
590 cTemp = This->m_cbMediaEventsMax - This->m_cbMediaEventsGet;
593 &This->m_pMediaEvents[This->m_cbMediaEventsGet],
594 sizeof(FilterGraph_MEDIAEVENT) * cTemp );
597 &This->m_pMediaEvents[0],
598 sizeof(FilterGraph_MEDIAEVENT) * (cQueued - cTemp) );
604 &This->m_pMediaEvents[This->m_cbMediaEventsGet],
605 sizeof(FilterGraph_MEDIAEVENT) * cQueued );
607 QUARTZ_FreeMem( This->m_pMediaEvents );
609 This->m_pMediaEvents = pEvent;
610 This->m_cbMediaEventsMax += EVENTQUEUE_BLOCKSIZE;
611 This->m_cbMediaEventsPut = cQueued;
612 This->m_cbMediaEventsGet = 0;
615 /* duplicate params if necessary. */
616 hr = FGEVENT_KeepEvent( TRUE, lEventCode, lParam1, lParam2 );
620 /* add to the queue. */
621 pEvent = &This->m_pMediaEvents[This->m_cbMediaEventsPut];
622 pEvent->lEventCode = lEventCode;
623 pEvent->lParam1 = lParam1;
624 pEvent->lParam2 = lParam2;
625 This->m_cbMediaEventsPut =
626 (This->m_cbMediaEventsPut + 1) % This->m_cbMediaEventsMax;
628 SetEvent( This->m_hMediaEvent );
629 if ( This->m_hwndEventNotify != (HWND)NULL &&
630 This->m_lEventNotifyFlags == 0 )
633 This->m_hwndEventNotify,
634 This->m_lEventNotifyMsg,
636 (LPARAM)This->m_lEventNotifyParam );
641 LeaveCriticalSection( &This->m_csMediaEvents );
647 static ICOM_VTABLE(IMediaEventSink) imediaeventsink =
649 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
650 /* IUnknown fields */
651 IMediaEventSink_fnQueryInterface,
652 IMediaEventSink_fnAddRef,
653 IMediaEventSink_fnRelease,
654 /* IMediaEventSink fields */
655 IMediaEventSink_fnNotify,
660 HRESULT CFilterGraph_InitIMediaEventSink( CFilterGraph* pfg )
663 ICOM_VTBL(&pfg->mediaeventsink) = &imediaeventsink;
668 void CFilterGraph_UninitIMediaEventSink( CFilterGraph* pfg )