步骤 6:处理图形事件

[与此页面关联的功能 DirectShow 是旧版功能。 它已被 MediaPlayerIMFMediaEngineMedia Foundation 中的音频/视频捕获所取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能在 Media Foundation 中使用 MediaPlayerIMFMediaEngine音频/视频捕获 ,而不是 DirectShow。 如果可能,Microsoft 建议重写使用旧 API 的现有代码以使用新 API。]

本主题是 DirectShow 中音频/视频播放教程的步骤 6。 主题 DirectShow 播放示例中显示了完整的代码。

当应用程序创建 Filter Graph Manager 的新实例时,应用程序将调用 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 中的事件通知

响应事件