Aprendendo quando ocorre um evento
[O recurso associado a esta página, DirectShow, é um recurso herdado. Foi substituído por MediaPlayer, IMFMediaEngine e Audio/Video Capture in Media Foundation. Esses recursos foram otimizados para Windows 10 e Windows 11. A Microsoft recomenda fortemente que o novo código use MediaPlayer, IMFMediaEngine e Audio/Video Capture in Media Foundation em vez de DirectShow, quando possível. A Microsoft sugere que o código existente que usa as APIs herdadas seja reescrito para usar as novas APIs, se possível.]
Para processar eventos do DirectShow, um aplicativo precisa de uma maneira de descobrir quando os eventos estão aguardando na fila. O Gerenciador de Grafo de Filtro fornece duas maneiras de fazer isso:
- Notificação de janela: O Gerenciador de Grafo de Filtro envia uma mensagem do Windows definida pelo usuário para uma janela do aplicativo sempre que há um novo evento.
- Sinalização de evento: O Gerenciador de Grafo de Filtro sinalizará um evento do Windows se houver eventos directShow na fila e redefinirá o evento se a fila estiver vazia.
Um aplicativo pode usar qualquer técnica. A notificação de janela geralmente é mais simples.
Notificação de Janela
Para configurar a notificação de janela, chame o método IMediaEventEx::SetNotifyWindow e especifique uma mensagem privada. Os aplicativos podem usar números de mensagem no intervalo de WM_APP até 0xBFFF como mensagens privadas. Sempre que o Gerenciador de Grafo de Filtro coloca uma nova notificação de evento na fila, ele posta essa mensagem na janela designada. O aplicativo responde à mensagem de dentro do loop de mensagens da janela.
O exemplo de código a seguir mostra como definir a janela de notificação.
#define WM_GRAPHNOTIFY WM_APP + 1 // Private message.
pEvent->SetNotifyWindow((OAHWND)g_hwnd, WM_GRAPHNOTIFY, 0);
A mensagem é uma mensagem comum do Windows e é postada separadamente da fila de notificação de eventos do DirectShow. A vantagem dessa abordagem é que a maioria dos aplicativos já implementa um loop de mensagem. Portanto, você pode incorporar a manipulação de eventos do DirectShow sem muito trabalho adicional.
O exemplo de código a seguir mostra uma estrutura de tópicos de como responder à mensagem de notificação. Para obter um exemplo completo, consulte Respondendo a eventos.
LRESULT CALLBACK WindowProc( HWND hwnd, UINT msg, UINT wParam, LONG lParam)
{
switch (msg)
{
case WM_GRAPHNOTIFY:
HandleEvent(); // Application-defined function.
break;
// Handle other Windows messages here too.
}
return (DefWindowProc(hwnd, msg, wParam, lParam));
}
Como a notificação de eventos e o loop de mensagem são assíncronos, a fila pode conter mais de um evento quando o aplicativo responder à mensagem. Além disso, os eventos às vezes podem ser limpos da fila se eles se tornarem inválidos. Portanto, no código de tratamento de eventos, chame IAMMediaEvent::GetEvent até que ele retorne um código de falha, indicando que a fila está vazia.
Antes de liberar o ponteiro IMediaEventEx, cancele a notificação de evento chamando SetNotifyWindow com um ponteiro NULL . No código de processamento de eventos, marcar se o ponteiro IMediaEventEx é válido antes de chamar GetEvent. Essas etapas impedem um possível erro, no qual o aplicativo recebe a notificação de evento depois de ter liberado o ponteiro IMediaEventEx .
Sinalização de Evento
O Gerenciador do Gráfico de Filtro mantém um evento de redefinição manual que reflete o estado da fila de eventos. Se a fila contiver notificações de eventos pendentes, o Gerenciador do Gráfico de Filtro sinalizará o evento de redefinição manual. Se a fila estiver vazia, uma chamada para o método IMediaEvent::GetEvent redefinirá o evento. Um aplicativo pode usar esse evento para determinar o estado da fila.
Observação
A terminologia pode ser confusa aqui. O evento de redefinição manual é o tipo de evento criado pela função CreateEvent do Windows; não tem nada a ver com os eventos definidos pelo DirectShow.
Chame o método IMediaEvent::GetEventHandle para obter um identificador para o evento de redefinição manual. Aguarde até que o evento seja sinalizado chamando uma função como WaitForMultipleObjects. Depois que o evento for sinalizado, chame IMediaEvent::GetEvent para obter o evento DirectShow.
O código de exemplo a seguir ilustra essa abordagem. Ele obtém o identificador de evento e aguarda em intervalos de 100 milissegundos para que o evento seja sinalizado. Se o evento for sinalizado, ele chamará GetEvent e imprimirá o código do evento e os parâmetros de evento na janela do console. O loop termina quando o evento EC_COMPLETE ocorre, indicando que a reprodução foi concluída.
HANDLE hEvent;
long evCode, param1, param2;
BOOLEAN bDone = FALSE;
HRESULT hr = S_OK;
hr = pEvent->GetEventHandle((OAEVENT*)&hEvent);
if (FAILED(hr))
{
/* Insert failure-handling code here. */
}
while(!bDone)
{
if (WAIT_OBJECT_0 == WaitForSingleObject(hEvent, 100))
{
while (S_OK == pEvent->GetEvent(&evCode, ¶m1, ¶m2, 0))
{
printf("Event code: %#04x\n Params: %d, %d\n", evCode, param1, param2);
pEvent->FreeEventParams(evCode, param1, param2);
bDone = (EC_COMPLETE == evCode);
}
}
}
Como o grafo de filtro define ou redefine automaticamente o evento quando apropriado, seu aplicativo não deve fazer isso. Além disso, quando você libera o grafo de filtro, o grafo de filtro fecha o identificador de evento, portanto, não use o identificador de evento após esse ponto.