DirectShow 事件回应

事件通知原理

    当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指针:

雷同学的源程序在播放视频是有时候会出现5秒闪退,加上下边这句就可以了。

若需要返回值那就return 0;

if (g_pEvent == NULL) return;

附实践相关源码:

LRESULT CplayerGUIDlg::OnGraphNotify(WPARAM inWParam, LPARAM inLParam)
{
	if(pEvent==NULL)
		return 0;
	LONG   eventCode = 0, eventParam1 = 0, eventParam2 = 0;
	while (SUCCEEDED(pEvent->GetEvent(&eventCode, &eventParam1, &eventParam2, 0)))
	{ 
		// Spin through the events
		pEvent->FreeEventParams(eventCode, eventParam1, eventParam2);
		switch (eventCode)
		{
		case EC_COMPLETE:{
			OnBnClickedStop();
			break;
			}
		case EC_USERABORT:
		case EC_ERRORABORT:{
			OnBnClickedStop();
			break;
			}
		default:
			break;
		}
	}
	return 0;
}

 

参考:

https://www.yuque.com/docs/share/9a27ded3-4298-46a8-bba3-14696e82b654

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值