[DirectShow] 035 - Responding to Events

How Event Notification Works

While a DirectShow application is running, events can occur within the filter graph. For example, a filter might encounter a streaming error. Filters alert the Filter Graph Manager by sending events, which consist of an event code and two event parameters. The event code indicates the type of event, and the event parameters supply additional information. The meaning of the parameters depends on the event code. For a complete list of event codes, see Event Notification Codes .

DirectShow 应用程序运行期间, filter graph 内部会产生事件。例如, filter 会遇到一个流错误。 filter 通过由一个事件码和两个事件参数组成的事件警告 Filter Graph Manager 。事件码定义了事件的类型,事件参数提供附加信息。意思是说参数依赖于事件码。

Some events are handled silently by the Filter Graph Manager, without the application being notified. Other events are placed on a queue for the application. Depending on the application, there are various events that you might need to handle. This article focuses on three events that are very common:

一些事件由 Filter Graph Manager 处理,并不通知应用程序。另外一些事件会被放进应用程序的队列中。一些事件必须依赖应用程序来处理。这篇文章焦点在三个最通用时间:

·         The EC_COMPLETE event indicates that playback has completed normally.

·         EC_COMPLETE 事件标志回放完成。

·         The EC_USERABORT event indicates that the user has interrupted playback. Video renderers send this event if the user closes the video window.

·         EC_USERABORT 事件标志用户中断回放。如果用户关闭视频窗口,视频 renderer 发送这个事件。

·         The EC_ERRORABORT event indicates that an error has caused playback to halt.

·         EC_ERRORABORT 标志回放产生错误而停止。

Using Event Notification

An application can instruct the Filter Graph Manager to send a Windows message to a designated window whenever a new event occurs. This enables the application to respond inside the window's message loop. First, define the message that will be sent to the application window. Applications can use message numbers in the range from WM_APP through 0xBFFF as private messages:

一旦新的事件产生的时候,应用程序可以命令 Filter Graph Manager 发送一个 windows 消息到指定的窗口。这可以使应用程序在 windows 消息循环里面响应。第一,定义将要发送到应用程序窗口的消息。应用程序可以使用 WM_APP 0xBFFF 之间的值作为私有消息。

#define WM_GRAPHNOTIFY  WM_APP + 1

Next, query the Filter Graph Manager for the IMediaEventEx interface and call the IMediaEventEx::SetNotifyWindow method: 

接下来,向 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);

This method designates the specified window (g_hwnd) as the recipient of the message. Call the method after you create the filter graph, but before running the graph.

这个函数指派一个指定的窗口作为消息的接受者。在创建 filter graph 之后运行 graph 之前调用这个函数。

WM_GRAPHNOTIFY is an ordinary Windows message. Whenever the Filter Graph Manager puts a new event on the event queue, it posts a WM_GRAPHNOTIFY message to the designated application window. The message's lParam parameter is equal to the third parameter in SetNotifyWindow . This parameter enables you to send instance data with the message. The window message's wParam parameter is always zero.

WM_GRAPHNOTIFY 是一个普通的 windows 消息。当 Filter Graph Manager 把一个新的事件放到队列中去的时候,它会发送 WM_GRAPHNOTIFY 消息给指定的应用程序窗口。消息的 lParam 参数等于 SetNotifyWindow 的第三个参数。这个参数能使你和消息一起发送实例数据。 windows 消息的 wParam 参数始终是 0.

In your application's WindowProc function, add a case statement for the WM_GRAPHNOTIFY message:

在应用程序的消息处理函数中,添加一个 case 语句:

case WM_GRAPHNOTIFY:

    HandleGraphEvent();

    break;

In the event handler function, call the IMediaEvent::GetEvent method to retrieve events from the queue:

在事件处理函数中,调用 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, &param1, &param2, 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;

        }

    }

}

The GetEvent method retrieves the event code and the two event parameters. The fourth GetEvent parameter specifies the length of time to wait for an event, in milliseconds. Because the application calls this method in response to a WM_GRAPHNOTIFY message, the event is already queued. Therefore, we set the time-out value to zero.

GetEvent 函数获得事件码和两个事件参数。 GetEvent 函数的第四个参数指定等待事件的时长,单位是毫秒。因为应用程序对 WM_GRAPHNOTIFY 消息作出反应的时候调用这个方法,事件已经在队列中。所以,可以设置超时时间为 0.

Event notification and the message loop are both asynchronous, so the queue might hold more than one event by the time your application responds to the message. Also, the Filter Graph Manager can remove certain events from the queue, if they become invalid. Therefore, you should call GetEvent until it returns a failure code, indicating the queue is empty.

事件通知和消息循环都是异步的,所以,在应用程序响应消息的时候队列中可能会有多个事件。 Filter Graph Manager 也会移除无效的事件。因此,你应该调用 GetEvent 直到返回失败码,标志队列是空的。

In this example, the application responds to EC_COMPLETE, EC_USERABORT, and EC_ERRORABORT by invoking the application-defined CleanUp function, which causes the application to quit gracefully. The example ignores the two event parameters. After you retrieve an event, call IMediaEvent::FreeEventParams to any free resources associated with the event parameters.

在这个例子中,应用程序通过引用程序定义的 CleanUp 函数来响应 EC_COMPLETE EC_USERABORT EC_ERRORABORT ,将使程序温柔的退出。这个例子忽略了事件的两个参数。获得事件以后,调用 IMediaEvent::FreeEventParams 函数释放与事件参数相关的资源。

Note that an EC_COMPLETE event does not cause the filter graph to stop. The application can either stop or pause the graph. If you stop the graph, filters release any resources they are holding. If you pause the graph, filters continue to hold resources. Also, when a video renderer pauses, it displays a static image of the most recent frame.

EC_COMPLETE 事件不会导致 filter graph 停止。应用程序可以停止或者暂停 graph 。如果停止 graph filter 释放一些他的资源。如果是暂停, filter 将不释放这些资源。当视频 renderer 暂停的时候,它显示最近的一张静态图片。

Before you release the IMediaEventEx pointer, cancel event notification by calling SetNotifyWindow with a NULL window handle:

释放 IMediaEventEx 指针之前,先调用 SetNotifyWindow 取消事件通知,参数是 NULL 窗口句柄。

// Disable event notification before releasing the graph.

g_pEvent->SetNotifyWindow(NULL, 0, 0);

g_pEvent->Release();

g_pEvent = NULL;

In the WM_GRAPHNOTIFY message handler, check the IMediaEventEx pointer before calling GetEvent :

WM_GRAPHNOTIFY 消息处理中,调用 GetEvent 之前检查 IMediaEventEx 指针。

if (g_pEvent == NULL) return;

This prevents a possible error that can occur if the application receives the event notification after releasing the pointer.

如果应用程序获得事件通知之后释放了这个指针,那么这样做就可以尽可能的防止错误发生。

 

你可能感兴趣的:(manager,filter,application,Graph,events,playback)