Step 6: Handle Graph Events
[The feature associated with this page, DirectShow, is a legacy feature. It has been superseded by MediaPlayer, IMFMediaEngine, and Audio/Video Capture in Media Foundation. Those features have been optimized for Windows 10 and Windows 11. Microsoft strongly recommends that new code use MediaPlayer, IMFMediaEngine and Audio/Video Capture in Media Foundation instead of DirectShow, when possible. Microsoft suggests that existing code that uses the legacy APIs be rewritten to use the new APIs if possible.]
This topic is step 6 of the tutorial Audio/Video Playback in DirectShow. The complete code is shown in the topic DirectShow Playback Example.
When the application creates a new instance of the Filter Graph Manager, the application calls IMediaEventEx::SetNotifyWindow. This method registers the application window to receive events from the filter graph.
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;
}
The value WM_GRAPH_EVENT
is a private window message. Whenever the application receives this message, it calls the DShowPlayer::HandleGraphEvent
method.
case WM_GRAPH_EVENT:
g_pPlayer->HandleGraphEvent(OnGraphEvent);
return 0;
The DShowPlayer::HandleGraphEvent
method does the following:
- Calls IMediaEvent::GetEvent in a loop to get all of the queued events.
- Invokes a callback function (pfnOnGraphEvent).
- Calls IMediaEvent::FreeEventParams to free the data associated with each event.
// 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, ¶m1, ¶m2, 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;
}
The following code shows the callback function that is passed to DShowPlayer::HandleGraphEvent
. The function handles the minimum number of graph events (EC_COMPLETE, EC_ERRORABORT, and EC_USERABORT); you could expand the function to handle additional events.
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;
}
}
Related topics