天天看點

IMediaEventEx 轉帖

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.

如果應用程式獲得事件通知之後釋放 了這個指針,那麼這樣做就可以盡可能的防止錯誤發生。

繼續閱讀