[QUARTZ] Implementation of IMediaEventSink and IMediaEventEx interfaces
Christian Costa
titan.costa at wanadoo.fr
Fri Mar 5 10:47:54 CST 2004
Hi,
Changelog :
Implemented IMediaEventSink and IMediaEventEx interfaces.
Christian Costa titan.costa at wanadoo.fr
-------------- next part --------------
Index: filtergraph.c
===================================================================
RCS file: /home/wine/wine/dlls/quartz/filtergraph.c,v
retrieving revision 1.9
diff -u -r1.9 filtergraph.c
--- filtergraph.c 4 Mar 2004 06:07:30 -0000 1.9
+++ filtergraph.c 5 Mar 2004 15:42:33 -0000
@@ -1,6 +1,7 @@
/* DirectShow FilterGraph object (QUARTZ.DLL)
*
* Copyright 2002 Lionel Ulmer
+ * Copyright 2004 Christian Costa
*
* This file contains the (internal) driver registration functions,
* driver enumeration APIs and DirectDraw creation functions.
@@ -29,12 +30,110 @@
#include "wine/debug.h"
#include "strmif.h"
#include "vfwmsgs.h"
+#include "evcode.h"
#include "wine/unicode.h"
#include "quartz_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(quartz);
+typedef struct {
+ HWND hWnd; /* Target window */
+ long msg; /* User window message */
+ long instance; /* User data */
+ int disabled; /* Disabled messages posting */
+} WndNotify;
+
+typedef struct {
+ long lEventCode; /* Event code */
+ LONG_PTR lParam1; /* Param1 */
+ LONG_PTR lParam2; /* Param2 */
+} Event;
+
+/* messages ring implementation for queuing events (taken from winmm) */
+#define EVENTS_RING_BUFFER_INCREMENT 64
+typedef struct {
+ Event* messages;
+ int ring_buffer_size;
+ int msg_tosave;
+ int msg_toget;
+ CRITICAL_SECTION msg_crst;
+ HANDLE msg_event; /* Signaled for no empty queue */
+} EventsQueue;
+
+static int EventsQueue_Init(EventsQueue* omr)
+{
+ omr->msg_toget = 0;
+ omr->msg_tosave = 0;
+ omr->msg_event = CreateEventW(NULL, TRUE, FALSE, NULL);
+ omr->ring_buffer_size = EVENTS_RING_BUFFER_INCREMENT;
+ omr->messages = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,omr->ring_buffer_size * sizeof(Event));
+
+ InitializeCriticalSection(&omr->msg_crst);
+ return TRUE;
+}
+
+static int EventsQueue_Destroy(EventsQueue* omr)
+{
+ CloseHandle(omr->msg_event);
+ HeapFree(GetProcessHeap(),0,omr->messages);
+ DeleteCriticalSection(&omr->msg_crst);
+ return TRUE;
+}
+
+static int EventsQueue_PutEvent(EventsQueue* omr, Event* evt)
+{
+ EnterCriticalSection(&omr->msg_crst);
+ if ((omr->msg_toget == ((omr->msg_tosave + 1) % omr->ring_buffer_size)))
+ {
+ int old_ring_buffer_size = omr->ring_buffer_size;
+ omr->ring_buffer_size += EVENTS_RING_BUFFER_INCREMENT;
+ TRACE("omr->ring_buffer_size=%d\n",omr->ring_buffer_size);
+ omr->messages = HeapReAlloc(GetProcessHeap(),0,omr->messages, omr->ring_buffer_size * sizeof(Event));
+ /* Now we need to rearrange the ring buffer so that the new
+ buffers just allocated are in between omr->msg_tosave and
+ omr->msg_toget.
+ */
+ if (omr->msg_tosave < omr->msg_toget)
+ {
+ memmove(&(omr->messages[omr->msg_toget + EVENTS_RING_BUFFER_INCREMENT]),
+ &(omr->messages[omr->msg_toget]),
+ sizeof(Event)*(old_ring_buffer_size - omr->msg_toget)
+ );
+ omr->msg_toget += EVENTS_RING_BUFFER_INCREMENT;
+ }
+ }
+ omr->messages[omr->msg_tosave] = *evt;
+ SetEvent(omr->msg_event);
+ omr->msg_tosave = (omr->msg_tosave + 1) % omr->ring_buffer_size;
+ LeaveCriticalSection(&omr->msg_crst);
+ return TRUE;
+}
+
+static int EventsQueue_GetEvent(EventsQueue* omr, Event* evt, long msTimeOut)
+{
+ if (WaitForSingleObject(omr->msg_event, msTimeOut) != WAIT_OBJECT_0)
+ return FALSE;
+
+ EnterCriticalSection(&omr->msg_crst);
+
+ if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */
+ {
+ LeaveCriticalSection(&omr->msg_crst);
+ return FALSE;
+ }
+
+ *evt = omr->messages[omr->msg_toget];
+ omr->msg_toget = (omr->msg_toget + 1) % omr->ring_buffer_size;
+
+ /* Mark the buffer as empty if needed */
+ if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */
+ ResetEvent(omr->msg_event);
+
+ LeaveCriticalSection(&omr->msg_crst);
+ return TRUE;
+}
+
typedef struct _IFilterGraphImpl {
ICOM_VTABLE(IGraphBuilder) *IGraphBuilder_vtbl;
ICOM_VTABLE(IMediaControl) *IMediaControl_vtbl;
@@ -44,6 +143,7 @@
ICOM_VTABLE(IVideoWindow) *IVideoWindow_vtbl;
ICOM_VTABLE(IMediaEventEx) *IMediaEventEx_vtbl;
ICOM_VTABLE(IMediaFilter) *IMediaFilter_vtbl;
+ ICOM_VTABLE(IMediaEventSink) *IMediaEventSink_vtbl;
/* IAMGraphStreams */
/* IAMStats */
/* IBasicVideo2 */
@@ -52,7 +152,6 @@
/* IFilterMapper2 */
/* IGraphConfig */
/* IGraphVersion */
- /* IMediaEventSink */
/* IMediaPosition */
/* IQueueCommand */
/* IRegisterServiceProvider */
@@ -66,6 +165,14 @@
int nFilters;
int filterCapacity;
long nameIndex;
+ EventsQueue evqueue;
+ HANDLE hEventCompletion;
+ int CompletionStatus;
+ WndNotify notif;
+ int nRenderers;
+ int EcCompleteCount;
+ int HandleEcComplete;
+ int HandleEcRepaint;
} IFilterGraphImpl;
@@ -101,6 +208,9 @@
IsEqualGUID(&IID_IPersist, riid)) {
*ppvObj = &(This->IMediaFilter_vtbl);
TRACE(" returning IMediaFilter interface (%p)\n", *ppvObj);
+ } else if (IsEqualGUID(&IID_IMediaEventSink, riid)) {
+ *ppvObj = &(This->IMediaEventSink_vtbl);
+ TRACE(" returning IMediaEventSink interface (%p)\n", *ppvObj);
} else {
*ppvObj = NULL;
FIXME("unknown interface %s\n", debugstr_guid(riid));
@@ -124,8 +234,10 @@
ref = --This->ref;
if (ref == 0) {
- HeapFree(GetProcessHeap(), 0, This->ppFiltersInGraph);
- HeapFree(GetProcessHeap(), 0, This->pFilterNames);
+ CloseHandle(This->hEventCompletion);
+ EventsQueue_Destroy(&This->evqueue);
+ HeapFree(GetProcessHeap(), 0, This->ppFiltersInGraph);
+ HeapFree(GetProcessHeap(), 0, This->pFilterNames);
HeapFree(GetProcessHeap(), 0, This);
}
return ref;
@@ -289,7 +401,7 @@
ICOM_THIS_MULTI(IFilterGraphImpl, IGraphBuilder_vtbl, iface);
TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
-
+
return IEnumFiltersImpl_Construct(This->ppFiltersInGraph, This->nFilters, ppEnum);
}
@@ -543,6 +655,8 @@
TRACE("(%p/%p)->(): stub !!!\n", This, iface);
+ ResetEvent(This->hEventCompletion);
+
return S_OK;
}
@@ -1988,7 +2102,9 @@
OAEVENT *hEvent) {
ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
- TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, hEvent);
+ TRACE("(%p/%p)->(%p)\n", This, iface, hEvent);
+
+ *hEvent = (OAEVENT)This->evqueue.msg_event;
return S_OK;
}
@@ -1999,10 +2115,20 @@
LONG_PTR *lParam2,
long msTimeout) {
ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
+ Event evt;
- TRACE("(%p/%p)->(%p, %p, %p, %ld): stub !!!\n", This, iface, lEventCode, lParam1, lParam2, msTimeout);
+ TRACE("(%p/%p)->(%p, %p, %p, %ld)\n", This, iface, lEventCode, lParam1, lParam2, msTimeout);
- return S_OK;
+ if (EventsQueue_GetEvent(&This->evqueue, &evt, msTimeout))
+ {
+ *lEventCode = evt.lEventCode;
+ *lParam1 = evt.lParam1;
+ *lParam2 = evt.lParam2;
+ return S_OK;
+ }
+
+ *lEventCode = 0;
+ return E_ABORT;
}
static HRESULT WINAPI Mediaevent_WaitForCompletion(IMediaEventEx *iface,
@@ -2010,16 +2136,30 @@
long *pEvCode) {
ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
- TRACE("(%p/%p)->(%ld, %p): stub !!!\n", This, iface, msTimeout, pEvCode);
+ TRACE("(%p/%p)->(%ld, %p)\n", This, iface, msTimeout, pEvCode);
- return S_OK;
+ if (WaitForSingleObject(This->hEventCompletion, msTimeout) == WAIT_OBJECT_0)
+ {
+ *pEvCode = This->CompletionStatus;
+ return S_OK;
+ }
+
+ *pEvCode = 0;
+ return E_ABORT;
}
static HRESULT WINAPI Mediaevent_CancelDefaultHandling(IMediaEventEx *iface,
long lEvCode) {
ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
- TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, lEvCode);
+ TRACE("(%p/%p)->(%ld)\n", This, iface, lEvCode);
+
+ if (lEvCode == EC_COMPLETE)
+ This->HandleEcComplete = FALSE;
+ else if (lEvCode == EC_REPAINT)
+ This->HandleEcRepaint = FALSE;
+ else
+ return S_FALSE;
return S_OK;
}
@@ -2028,7 +2168,14 @@
long lEvCode) {
ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
- TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, lEvCode);
+ TRACE("(%p/%p)->(%ld)\n", This, iface, lEvCode);
+
+ if (lEvCode == EC_COMPLETE)
+ This->HandleEcComplete = TRUE;
+ else if (lEvCode == EC_REPAINT)
+ This->HandleEcRepaint = TRUE;
+ else
+ return S_FALSE;
return S_OK;
}
@@ -2051,7 +2198,11 @@
LONG_PTR lInstanceData) {
ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
- TRACE("(%p/%p)->(%08lx, %ld, %08lx): stub !!!\n", This, iface, (DWORD) hwnd, lMsg, lInstanceData);
+ TRACE("(%p/%p)->(%08lx, %ld, %08lx)\n", This, iface, (DWORD) hwnd, lMsg, lInstanceData);
+
+ This->notif.hWnd = (HWND)hwnd;
+ This->notif.msg = lMsg;
+ This->notif.instance = (long) lInstanceData;
return S_OK;
}
@@ -2060,7 +2211,12 @@
long lNoNotifyFlags) {
ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
- TRACE("(%p/%p)->(%ld): stub !!!\n", This, iface, lNoNotifyFlags);
+ TRACE("(%p/%p)->(%ld)\n", This, iface, lNoNotifyFlags);
+
+ if ((lNoNotifyFlags != 0) || (lNoNotifyFlags != 1))
+ return E_INVALIDARG;
+
+ This->notif.disabled = lNoNotifyFlags;
return S_OK;
}
@@ -2069,7 +2225,12 @@
long *lplNoNotifyFlags) {
ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventEx_vtbl, iface);
- TRACE("(%p/%p)->(%p): stub !!!\n", This, iface, lplNoNotifyFlags);
+ TRACE("(%p/%p)->(%p)\n", This, iface, lplNoNotifyFlags);
+
+ if (!lplNoNotifyFlags)
+ return E_POINTER;
+
+ *lplNoNotifyFlags = This->notif.disabled;
return S_OK;
}
@@ -2182,6 +2343,78 @@
MediaFilter_GetSyncSource
};
+static HRESULT WINAPI MediaEventSink_QueryInterface(IMediaEventSink *iface, REFIID riid, LPVOID *ppv)
+{
+ ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
+
+ return Filtergraph_QueryInterface(This, riid, ppv);
+}
+
+static ULONG WINAPI MediaEventSink_AddRef(IMediaEventSink *iface)
+{
+ ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
+
+ return Filtergraph_AddRef(This);
+}
+
+static ULONG WINAPI MediaEventSink_Release(IMediaEventSink *iface)
+{
+ ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
+
+ return Filtergraph_Release(This);
+}
+
+static HRESULT WINAPI MediaEventSink_Notify(IMediaEventSink *iface, long EventCode, LONG_PTR EventParam1, LONG_PTR EventParam2)
+{
+ ICOM_THIS_MULTI(IFilterGraphImpl, IMediaEventSink_vtbl, iface);
+ Event evt;
+
+ TRACE("(%p/%p)->(%ld, %ld, %ld)\n", This, iface, EventCode, EventParam1, EventParam2);
+
+ /* We need thread safety here, let's use the events queue's one */
+ EnterCriticalSection(&This->evqueue.msg_crst);
+
+ if ((EventCode == EC_COMPLETE) && This->HandleEcComplete)
+ {
+ if (++This->EcCompleteCount == This->nRenderers)
+ {
+ evt.lEventCode = EC_COMPLETE;
+ evt.lParam1 = S_OK;
+ evt.lParam2 = 0;
+ EventsQueue_PutEvent(&This->evqueue, &evt);
+ if (!This->notif.disabled && This->notif.hWnd)
+ PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
+ This->CompletionStatus = EC_COMPLETE;
+ SetEvent(This->hEventCompletion);
+ }
+ }
+ else if ((EventCode == EC_REPAINT) && This->HandleEcRepaint)
+ {
+ /* FIXME: Not handled yet */
+ }
+ else
+ {
+ evt.lEventCode = EventCode;
+ evt.lParam1 = EventParam1;
+ evt.lParam2 = EventParam2;
+ EventsQueue_PutEvent(&This->evqueue, &evt);
+ if (!This->notif.disabled && This->notif.hWnd)
+ PostMessageW(This->notif.hWnd, This->notif.msg, 0, This->notif.instance);
+ }
+
+ EnterCriticalSection(&This->evqueue.msg_crst);
+ return S_OK;
+}
+
+static ICOM_VTABLE(IMediaEventSink) IMediaEventSink_VTable =
+{
+ ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+ MediaEventSink_QueryInterface,
+ MediaEventSink_AddRef,
+ MediaEventSink_Release,
+ MediaEventSink_Notify
+};
+
/* This is the only function that actually creates a FilterGraph class... */
HRESULT FILTERGRAPH_create(IUnknown *pUnkOuter, LPVOID *ppObj) {
IFilterGraphImpl *fimpl;
@@ -2197,12 +2430,21 @@
fimpl->IVideoWindow_vtbl = &IVideoWindow_VTable;
fimpl->IMediaEventEx_vtbl = &IMediaEventEx_VTable;
fimpl->IMediaFilter_vtbl = &IMediaFilter_VTable;
+ fimpl->IMediaEventSink_vtbl = &IMediaEventSink_VTable;
fimpl->ref = 1;
fimpl->ppFiltersInGraph = NULL;
fimpl->pFilterNames = NULL;
fimpl->nFilters = 0;
fimpl->filterCapacity = 0;
fimpl->nameIndex = 1;
+ fimpl->hEventCompletion = CreateEventW(0, TRUE, FALSE,0);
+ fimpl->HandleEcComplete = TRUE;
+ fimpl->HandleEcRepaint = TRUE;
+ fimpl->notif.hWnd = 0;
+ fimpl->notif.disabled = TRUE;
+ fimpl->nRenderers = 0;
+ fimpl->EcCompleteCount = 0;
+ EventsQueue_Init(&fimpl->evqueue);
*ppObj = fimpl;
return S_OK;
More information about the wine-patches
mailing list