事件通知原理
当DirectShow应用程序正在运行时,事件可能发生在过滤器图形中。 例如,一个过滤器可能会遇到流式传输错误。 过滤器通过发送事件来提醒Filter Graph Manager,事件由事件代码和两个事件参数组成。 事件代码指示事件的类型,事件参数提供附加信息。 参数的含义取决于事件代码。
某些事件由Filter Graph Manager静默处理,无需通知应用程序。 其他事件放置在应用程序的队列中。 根据应用程序的不同,您可能需要处理各种事件。 本文侧重于三个非常通用的事件:
·EC_COMPLETE事件表示播放已正常完成。
·EC_USERABORT事件表明用户已经中断播放。 视频渲染器在用户关闭视频窗口时发送此事件。
·EC_ERRORABORT事件表示错误导致播放暂停。
事件通知应用
应用程序可以指示Filter Graph Manager在发生新事件时将Windows消息发送到指定的窗口。 这使应用程序能够在窗口的消息循环内作出响应。 首先,定义将发送到应用程序窗口的消息。 应用程序可以使用WM_APP到0xBFFF范围内的消息号作为私人消息:
#define WM_GRAPHNOTIFY WM_APP + 1
接下来,查询Filter Graph Manager以获取IMediaEventEx接口并调用IMediaEventEx :: SetNotifyWindow方法:
IMediaEventEx *g_pEvent = NULL;
g_pGraph->QueryInterface(IID_IMediaEventEx, (void **)&g_pEvent);
g_pEvent->SetNotifyWindow((OAHWND)g_hwnd, WM_GRAPHNOTIFY, 0);
该方法将指定的窗口(g_hwnd)指定为消息的接收者。 在创建过滤器图之后调用方法,但在运行图之前调用该方法。 WM_GRAPHNOTIFY是一个普通的Windows消息。 每当Filter Graph Manager在事件队列中放置一个新事件时,它都会将WM_GRAPHNOTIFY消息发布到指定的应用程序窗口。 消息的lParam参数等于SetNotifyWindow中的第三个参数。 该参数使您能够通过消息发送实例数据。 窗口消息的wParam参数始终为零。
在应用程序的WindowProc函数中,为WM_GRAPHNOTIFY消息添加一个case语句:
case WM_GRAPHNOTIFY:
HandleGraphEvent();
break;
在事件处理函数中,调用IMediaEvent :: GetEvent方法从队列中检索事件:
void HandleGraphEvent()
{
// Disregard if we don't have an IMediaEventEx pointer.
if (g_pEvent == NULL)
{
return;
}
// Get all the events
long evCode;
LONG_PTR param1, param2;
HRESULT hr;
while (SUCCEEDED(g_pEvent->GetEvent(&evCode, ¶m1, ¶m2, 0)))
{
g_pEvent->FreeEventParams(evCode, param1, param2);
switch (evCode)
{
case EC_COMPLETE: // Fall through.
case EC_USERABORT: // Fall through.
case EC_ERRORABORT:
CleanUp();
PostQuitMessage(0);
return;
}
}
}
在释放IMediaEventEx指针之前,通过使用NULL窗口句柄调用SetNotifyWindow来取消事件通知:
// Disable event notification before releasing the graph.
g_pEvent->SetNotifyWindow(NULL, 0, 0);
g_pEvent->Release();
g_pEvent = NULL;
在WM_GRAPHNOTIFY消息处理程序中,在调用GetEvent之前检查IMediaEventEx指针:
if (g_pEvent == NULL) return;
参考:
https://www.yuque.com/docs/share/9a27ded3-4298-46a8-bba3-14696e82b654