To process DirectShow events, an application needs a way to find out when events are waiting in the queue. The Filter Graph Manager provides two ways to do this:
· Window notification: The Filter Graph Manager sends a user-defined Windows message to an application window whenever there is a new event.
· Event signaling: The Filter Graph Manager signals a Windows event if there are DirectShow events in the queue, and reset the event if the queue is empty.
An application can use either technique. Window notification is usually simpler.
为了处理 DirectShow 事件,应用程序需要一种方法发现什么时候事件等待在队列中。 Filter Graph Manager 提供两种方式:
· Window notification: 每当有新的事件的时候, Filter Graph Manager 就发送一个用户自定义的 Windows 消息给应用程序窗口。
· Event signaling: 如果队列中有 DirectShow 事件, Filter Graph Manager 就激发一个 windows 事件,并在队列为空的时候使事件为非激发状态。。
To set up window notification, call the IMediaEventEx::SetNotifyWindow method and specify a private message. Applications can use message numbers in the range from WM_APP through 0xBFFF as private messages. Whenever the Filter Graph Manager places a new event notification in the queue, it posts this message to the designated window. The application responds to the message from within the window's message loop.
调用 ImediaEventEx::SetNotifyWindow 方法并指定私有消息来建立 window notification 。应用程序可以使用 WM_APP 到 0XBFFF 之间的消息值作为私有消息。只要 Filter Graph Manager 把一个新的事件通知放到队列中,它就发送这个消息到指定的窗口。应用程序在窗口消息循环中响应。
The following code example shows how to set the notification window.
下面代码显示如何设置通知窗口。
#define WM_GRAPHNOTIFY WM_APP + 1 // Private message.
pEvent->SetNotifyWindow((OAHWND)g_hwnd, WM_GRAPHNOTIFY, 0);
The message is an ordinary Windows message, and is posted separately from the DirectShow event notification queue. The advantage of this approach is that most applications already implement a message loop. Therefore, you can incorporate DirectShow event handling without much additional work.
消息是普通的 windows 消息。这种方法的好处就是大部分的应用程序早已实现了消息循环。因此,不需要附加太多的工作就能包含 DirectShow 的事件处理。
The following code example shows an outline of how to respond to the notification message
接下来的代码显示了如何响应通知消息。
LRESULT CALLBACK WindowProc( HWND hwnd, UINT msg, UINT wParam, LONG lParam)
{
switch (msg)
{
case WM_GRAPHNOTIFY:
HandleEvent(); // Application-defined function.
break;
// Handle other Windows messages here too.
}
return (DefWindowProc(hwnd, msg, wParam, lParam));
}
Because event notification and the message loop are both asynchronous, the queue might contain more than one event by the time your application responds to the message. Also, events can sometimes be cleared from the queue if they become invalid. Therefore, in your event handling code, call GetEvent until it returns a failure code, indicating that the queue is empty.
因为事件通知和消息循环是异步的,所以在应用程序响应消息的时候,队列中可能包含不止一个事件。如果事件变的无效,那可能会从队列中清除。因此,在事件处理代码中,一直调用 GetEvent 直到这个函数返回失败代码为止,这表明队列为空了。
Before you release the IMediaEventEx pointer, cancel event notification by calling SetNotifyWindow with a NULL pointer. In your event processing code, check whether your IMediaEventEx pointer is valid before calling GetEvent . These steps prevent a possible error, in which the application receives the event notification after it has released the IMediaEventEx pointer.
在释放 IMediaEventEx 指针之前,调用 SetNotifyWindow 函数,传递一个 NULL 指针取消事件通知。在事件处理代码中,调用 GetEvent 之前判断 IMediaEventEx 指针是否有效。这些步骤尽可能的避免了当 IMediaEventEx 指针被释放以后应用程序接到通知事件的错误。
The Filter Graph Manager keeps a manual-reset event that reflects the state of the event queue. If the queue contains pending event notifications, the Filter Graph Manager signals the manual-reset event. If the queue is empty, a call to the IMediaEvent::GetEvent method resets the event. An application can use this event to determine the state of the queue.
Filter Graph Manager 保存一个手动复位的事件,这个事件反映事件队列的状态。如果队列中包含未处理的事件通知,, Filter Graph Manager 激发这个手动复位的事件。如果队列为空,调用 IMediaEvent::GetEvent 方法复位事件。应用程序可以使用这个事件决定队列的状态。
Call the IMediaEvent::GetEventHandle method to retrieve a handle to the manual-reset event. Wait for the event to be signaled by calling a function such as WaitForMultipleObjects . Once the event is signaled, call IMediaEvent::GetEvent to retrieve the DirectShow event.
调用 IMediaEvent::GetEventHandle 方法获得手动复位事件的句柄。调用类似 WaitForMultipleObjects 的函数等待事件被激发。一旦事件被激发,立刻调用 IMediaEvent::GetEvent 获得 DirectShow 事件。
The following code example illustrates this approach. It retrieves the event handle, then waits in 100-millisecond intervals for the event to be signaled. If the event is signaled, it calls GetEvent and prints the event code and event parameters to the console window. The loop terminates when the EC_COMPLETE event occurs, indicating that playback has completed.
接下来的代码说明了这个方法。他获得一个事件句柄,然后在 100 毫秒的时间间隔内等待事件被激发。如果事件被激发,就调用 GetEvent 并通过控制台窗口打印出事件代码和参数。当发生 EC_COMPLETE 事件时循环结束,表明回放完成。
HANDLE hEvent;
long evCode, param1, param2;
BOOLEAN bDone = FALSE;
HRESULT hr = S_OK;
hr = pEvent->GetEventHandle((OAEVENT*)&hEvent);
if (FAILED(hr)
{
/* Insert failure-handling code here. */
}
while(!bDone)
{
if (WAIT_OBJECT_0 == WaitForSingleObject(hEvent, 100))
{
while (hr = pEvent->GetEvent(&evCode, ¶m1, ¶m2, 0), SUCCEEDED(hr))
{
printf("Event code: %#04x/n Params: %d, %d/n", evCode, param1, param2);
pEvent->FreeEventParams(evCode, param1, param2);
bDone = (EC_COMPLETE == evCode);
}
}
}
Because the filter graph automatically sets or resets the event when appropriate, your application should not do so. Also, when you release the filter graph, the filter graph closes the event handle, so do not use the event handle after that point.
因为 filter graph 会在适当的时候自动激发或复位事件,所以应用程序不用关心。当应用程序释放 filter graph 之后, filter graph 会关闭事件句柄,在这之后不要再使用事件句柄做任何事。