Partilhar via


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, &param1, &param2, 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.