步驟 6:處理圖形事件

[與此頁面 相關的功能 DirectShow是舊版功能。 它已被 MediaPlayerIMFMediaEngineMedia Foundation 中的音訊/視訊擷取取代。 這些功能已針對Windows 10和Windows 11進行優化。 Microsoft 強烈建議新程式碼盡可能使用 MediaPlayerIMFMediaEngine音訊/視訊擷取 ,而不是 DirectShow。 Microsoft 建議盡可能重寫使用舊版 API 的現有程式碼,以使用新的 API。]

本主題是 DirectShow 中音訊/視訊播放教學課程的步驟 6。 完整的程式碼會顯示在 DirectShow 播放範例主題中。

當應用程式建立 Filter Graph 管理員的新實例時,應用程式會呼叫 IMediaEventEx::SetNotifyWindow。 這個方法會登錄應用程式視窗,以從篩選圖形接收事件。

    hr = m_pGraph->QueryInterface(IID_PPV_ARGS(&m_pEvent));
    if (FAILED(hr))
    {
        goto done;
    }

    // Set up event notification.
    hr = m_pEvent->SetNotifyWindow((OAHWND)m_hwnd, WM_GRAPH_EVENT, NULL);
    if (FAILED(hr))
    {
        goto done;
    }

此值 WM_GRAPH_EVENT 是私人視窗訊息。 每當應用程式收到此訊息時,就會呼叫 DShowPlayer::HandleGraphEvent 方法。

    case WM_GRAPH_EVENT:
       g_pPlayer->HandleGraphEvent(OnGraphEvent);
       return 0;

DShowPlayer::HandleGraphEvent 方法會執行下列動作:

  1. 在迴圈中呼叫 IMediaEvent::GetEvent ,以取得所有已排入佇列的事件。
  2. (pfnOnGraphEvent) 叫用回呼函式。
  3. 呼叫 IMediaEvent::FreeEventParams 以釋放與每個事件相關聯的資料。
// Respond to a graph event.
//
// The owning window should call this method when it receives the window
// message that the application specified when it called SetEventWindow.
//
// Caution: Do not tear down the graph from inside the callback.

HRESULT DShowPlayer::HandleGraphEvent(GraphEventFN pfnOnGraphEvent)
{
    if (!m_pEvent)
    {
        return E_UNEXPECTED;
    }

    long evCode = 0;
    LONG_PTR param1 = 0, param2 = 0;

    HRESULT hr = S_OK;

    // Get the events from the queue.
    while (SUCCEEDED(m_pEvent->GetEvent(&evCode, &param1, &param2, 0)))
    {
        // Invoke the callback.
        pfnOnGraphEvent(m_hwnd, evCode, param1, param2);

        // Free the event data.
        hr = m_pEvent->FreeEventParams(evCode, param1, param2);
        if (FAILED(hr))
        {
            break;
        }
    }
    return hr;
}

下列程式碼顯示傳遞至 DShowPlayer::HandleGraphEvent 的回呼函式。 函式會處理圖形事件數目下限 , (EC_COMPLETEEC_ERRORABORTEC_USERABORT) ;您可以展開 函式來處理其他事件。

void CALLBACK OnGraphEvent(HWND hwnd, long evCode, LONG_PTR param1, LONG_PTR param2)
{
    switch (evCode)
    {
    case EC_COMPLETE:
    case EC_USERABORT:
        g_pPlayer->Stop();
        break;

    case EC_ERRORABORT:
        NotifyError(hwnd, L"Playback error.");
        g_pPlayer->Stop();
        break;
    }
}

DirectShow 中的音訊/視訊播放

DirectShow 播放範例

DirectShow 中的事件通知

回應事件