DirectShow


Index


メディアファイルを再生する4つのステップ

1.フィルタグラフ管理のインスタンスを作成する
2.フィルタグラフを作成するためフィルタグラフ管理を使用する
3.フィルタグラフを実施するためフィルタグラフ管理を使用する
4.再生が完了するのを待つ


Microsoft DirectX 8.1 (C++)

Responding to Events

This article describes how to respond to events that occur in a MicrosoftR DirectShowR application. It presents a sample program that builds on the sample given in Setting the Video Window. This article does not repeat all the code from that sample; rather, it describes what you need to add, which comes to about 25 lines of new code.

この記事はどのようにDirectShowアプリケーションで発生するイベントに応じるかを説明します。

How Event Notification Works

イベント通知はどう働いているか。

At various times while a DirectShow application is running, the status of a filter might change. For example, it might go from paused to running, encounter an error in the stream, or request that the video window be repainted. To alert the filter graph manager of a change, the filter sends an event notification, which consists of an event code that indicates the type of event, and two parameters that supply additional information. The meaning of the parameters depends on the event code. For a complete list of event codes and their parameters, see Event Notification Codes.

いろいろな時にDirectShowアプリケーションが走行である間、フィルタの状態は変化するかもしれません。例えば、それは止まるのから走行まで行くか、流れでエラーに遭遇するか、またはビデオウィンドが再描画されるのを要求するかもしれません。変化のフィルタグラフマネージャを警告するために、フィルタはイベント通知を送ります。(それは、イベントの型を示す1つのエラーコード含んでいます。また追加情報を供給する2つのパラメタを含んでいます。パラメタの意味はイベントコードに依存します。イベントコードとそれらのパラメタの全リストに関しては、Event Notification Codesを参照してください。

The filter graph manager handles some events without notifying the application, such as a request to repaint the video window. It places other events into a queue, from which the application retrieves and processes them in order. DirectShow event notification is similar in this respect to MicrosoftR WindowsR message queuing. In fact, you can have the filter graph manager send a Windows message to a designated window when a new event occurs. That way, the application can handle the events from within the window's message loop.

ビデオウィンドウを再描画する要求などのアプリケーションに通知しないで、フィルタグラフマネージャはいくつかのイベントを扱います。それは他のイベントを待ち行列に置きます。(アプリケーションは、それから整然とした状態でそれらを検索して、処理します)。DirectShowイベント通知はこの点でMicrosoftR WindowsRメッセージ待ち行列と同様です。事実上、新たなイベントが起こると、あなたはフィルタグラフマネージャにWindowsメッセージを指定されたウィンドウに送らせることができます。そのように、アプリケーションはウィンドウのメッセージループからのイベントを処理することができます。

An application might need to handle a number of event codes, depending on the purpose of the application. This article focuses on two, EC_COMPLETE and EC_USERABORT.

アプリケーションの目的によって、アプリケーションは、多くのイベントコードを扱う必要があるかもしれません。この記事は2、EC_COMPLETE、およびEC_USERABORTに焦点を合わせます。

Using Event Notification

イベント通知を使用

The sample application handles events from within the main window message loop. It works by having the filter graph manager post a message when a new event occurs. The application responds by retrieving the event and taking the appropriate action.

サンプルアプリケーションはメインウィンドウメッセージループからのイベントを処理します。新たなイベントが起こるとフィルタグラフマネージャにメッセージを掲示させることによって、それは働いています。アプリケーションは、イベントを検索して、適切な行動を取ることによって、反応します。

To handle events from the main window message loop, define the message that will be sent to the application window when a new event occurs. Applications can use message numbers in the range from WM_APP through 0xBFFF as private messages, as shown in the following example:

メインウィンドウメッセージループからのイベントを扱うには、新たなイベントが起こるときアプリケーションウィンドウに送られるメッセージを定義してください。アプリケーションは個人的なメッセージとして範囲でWM_APPから0xBFFFまでメッセージ番号を使用することができます。以下の例に示されるように:

#define WM_GRAPHNOTIFY  WM_APP + 1

Next, set the filter graph manager to deliver this message to the application's main window:

次に、フィルタグラフマネージャにこのメッセージをアプリケーションのメインウィンドウに渡すように設定してください:

pEvent->SetNotifyWindow((OAHWND)g_hwnd, WM_GRAPHNOTIFY, 0);

The IMediaEventEx::SetNotifyWindow method designates the specified window (g_hwnd) as the recipient of the message. Call this method after you create the filter graph and specify the owner window, but before running the graph. For details, see the sample code at the end of this article. The IMediaEventEx interface is exposed by the filter graph manager.

IMediaEventEx: : SetNotifyWindowメソッドはメッセージの受取人として指定されたウィンドウ(g_hwnd)を指定します。あなたがフィルタグラフを作成して、所有者ウィンドウを指定した後にもかかわらず、グラフを走らせる前に、このメソッドを呼び出してください。詳細に関しては、この記事の終わりのサンプルコードを見てください。IMediaEventExインタフェースはフィルタグラフマネージャによって現れます。

When the application receives the WM_GRAPHNOTIFY message, the message's lParam parameter is equal to the third parameter passed to SetNotifyWindow. This parameter enables you to send instance data with the message. The sample code does not use this data, so it passes a value of zero. The message's wParam parameter is always zero.

アプリケーションがWM_GRAPHNOTIFYメッセージを受け取るとき、メッセージのlParamパラメタはSetNotifyWindowに渡された3番目のパラメタと等しいです。このパラメタは、あなたがメッセージがあるインスタンスデータを送るのを可能にします。サンプルコードがこのデータを使用しないので、それはゼロの値を通過します。いつもメッセージのwParamパラメタはゼロです。

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

ウィンドウのWindowProc機能では、WM_GRAPHNOTIFYメッセージのためにケース文を加えてください:

case WM_GRAPHNOTIFY:
    HandleEvent();
    break;

WM_GRAPHNOTIFY is an ordinary Windows message, and is posted separately from the DirectShow event notification queue. The sequence of events is as follows:

WM_GRAPHNOTIFYは普通のWindowsメッセージであり、別々にDirectShowイベント通知待ち行列から掲示されます。イベントの順序は以下の通りです:

  1. A filter sends an event notification to the filter graph manager.
    フィルタはイベント通知をフィルタグラフマネージャに送ります。
  2. If the filter graph manager does not handle the event, it places the event in the event queue.
    フィルタグラフマネージャがイベントを扱わないならば、それはイベントをイベントキューに置きます。
  3. The filter graph manager posts a WM_GRAPHNOTIFY message to the application window.
    フィルタグラフマネージャはアプリケーションウィンドウにWM_GRAPHNOTIFYメッセージを掲示します。
  4. The application responds to the message from within the window's message loop.
    アプリケーションはウィンドウのメッセージループ内からのメッセージに反応します。
  5. The application retrieves the event notification from the queue.
    アプリケーションはキューからイベント通知を検索します。

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

In the event handler function, call the IMediaEvent::GetEvent method to retrieve events from the queue:
イベントハンドラ機能では、キューからのイベントを検索するIMediaEventGetEventメソッドを呼び出してください:

long evCode, param1, param2;
HRESULT hr;
if (pEvent == NULL)
    return;
while (hr = pEvent->GetEvent(&evCode, &param1, &param2, 0), SUCCEEDED(hr))
{
    hr = pEvent->FreeEventParams(evCode, param1, param2);
    if ((EC_COMPLETE == evCode) || (EC_USERABORT == evCode))
    { 
        CleanUp();
        break;
    } 
}

The GetEvent method retrieves the event code and the two event parameters. The last parameter to GetEvent specifies how long the method will wait for an event. Because the application calls this method in response to a WM_GRAPHNOTIFY message, the event is already queued, so use a time-out value of zero.

GetEventメソッドはイベントコードと2つのイベントパラメタを検索します。GetEventへの最後のパラメタは、メソッドがどれくらい長い間イベントを待つかを指定します。なぜならWM_GRAPHNOTIFYメッセージへの応答でアプリケーションはこのメソッドを呼び出します。イベントはすでに行列にあり、タイムアウトの値に"0"を使用します。

Because event notification and the message loop are both asynchronous, the queue might hold more than one event by the time your application responds to the message. Also, the filter graph manager can clear events from the queue, if they become invalid. Therefore, call GetEvent until it returns a failure code, indicating that the queue is empty.

イベント通知とメッセージループがともに非同期であるので、あなたのアプリケーションがメッセージに反応する時までに待ち行列は1回以上のイベントを保持するかもしれません。また、無効になるならば、フィルタグラフマネージャはキューからのイベントをクリアすることができます。したがって、キューが空であることを示して、失敗コードを返すまで、GetEventを呼び出してください。

If the sample program receives an EC_COMPLETE or EC_USERABORT event, it invokes the application-defined CleanUp function, which causes the application to quit gracefully. It ignores the two event parameters (param1 and param2). After you retrieve an event, call IMediaEvent::FreeEventParams to free resources associated with the event parameters. For example, the parameter may be a BSTR, whose memory was allocated by the filter graph manager.

When an EC_COMPLETE event occurs, the filter graph does not automatically switch to a stopped state. The application must stop or pause the graph. When the graph stops, filters release any resources they hold. When it pauses, they continue to hold resources. Also, when a video renderer pauses, it displays a static image of the most recent frame. The sample program stops the graph.

Clean Up

Before the application releases the IMediaEventEx pointer, it cancels event notification by calling SetNotifyWindow with a NULL pointer:

// Disable event notification before releasing the graph.
pEvent->SetNotifyWindow(NULL, 0, 0);
pEvent->Release();
pEvent = NULL;

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

if (pEvent == NULL) return;

These steps prevent a possible error, in which the application receives the event notification after it has released the pointer.

Sample Code

The following code does not include the functions WinMain or WindowProc. See the sample code in Setting the Video Window for these functions.

#include <windows.h>
#include <dshow.h>

#define WM_GRAPHNOTIFY  WM_APP + 1
#define CLASSNAME "EventNotify"

IGraphBuilder   *pGraph = NULL;
IMediaControl   *pMediaControl = NULL;
IMediaEventEx   *pEvent = NULL;
IVideoWindow    *pVidWin = NULL;
HWND            g_hwnd;

void PlayFile(void)
{
    // Create the filter graph manager and render the file.
    CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,
                     IID_IGraphBuilder, (void **)&pGraph);
    pGraph->RenderFile(L"C:\\Media\\Boys.avi", NULL);

    // Specify the owner window.
    pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVidWin);
    pVidWin->put_Owner((OAHWND)g_hwnd);
    pVidWin->put_WindowStyle( WS_CHILD | WS_CLIPSIBLINGS);

    // Set the owner window to receive event notices.
    pGraph->QueryInterface(IID_IMediaEventEx, (void **)&pEvent);
    pEvent->SetNotifyWindow((OAHWND)g_hwnd, WM_GRAPHNOTIFY, 0);

    // Run the graph.
    pGraph->QueryInterface(IID_IMediaControl, (void **)&pMediaControl);
    pMediaControl->Run();
}

void CleanUp(void)
{
    pVidWin->put_Visible(OAFALSE);
    pVidWin->put_Owner(NULL);

    // Disable event notification before releasing the graph.
    pEvent->SetNotifyWindow(NULL, 0, 0);
    pEvent->Release();
    pEvent = NULL;

    // Stop the graph.
    pMediaControl->Stop();

    pMediaControl->Release();
    pVidWin->Release();
    pGraph->Release();
    PostQuitMessage(0);
}

void HandleEvent() 
{
    long evCode, param1, param2;
    HRESULT hr;

    if (pEvent == NULL) // This avoids a possible race condition when
                           shutting down the graph.
        return;

    while (hr = pEvent->GetEvent(&evCode, &param1, &param2, 0), SUCCEEDED(hr))
    { 
        hr = pEvent->FreeEventParams(evCode, param1, param2);
        if ((EC_COMPLETE == evCode) || (EC_USERABORT == evCode))
        { 
            CleanUp();
            break;
        } 
    } 
}

/* WindowProc goes here. Add the following case statement:
        case WM_GRAPHNOTIFY:
            HandleEvent();
            break;
*/

// WinMain goes here.