Compartilhar via


Respondendo a eventos

[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.]

Este artigo descreve como responder a eventos que ocorrem em um grafo de filtro.

Como funciona a notificação de eventos

Enquanto um aplicativo DirectShow está em execução, eventos podem ocorrer dentro do grafo de filtro. Por exemplo, um filtro pode encontrar um erro de streaming. Os filtros alertam o Gerenciador de Grafo de Filtro enviando eventos, que consistem em um código de evento e dois parâmetros de evento. O código de evento indica o tipo de evento e os parâmetros de evento fornecem informações adicionais. O significado dos parâmetros depende do código do evento. Para obter uma lista completa de códigos de evento, consulte Códigos de notificação de eventos.

Alguns eventos são tratados silenciosamente pelo Gerenciador de Grafo de Filtro, sem que o aplicativo seja notificado. Outros eventos são colocados em uma fila para o aplicativo. Dependendo do aplicativo, há vários eventos que talvez você precise manipular. Este artigo se concentra em três eventos muito comuns:

  • O evento EC_COMPLETE indica que a reprodução foi concluída normalmente.
  • O evento EC_USERABORT indica que o usuário interrompeu a reprodução. Os renderizadores de vídeo enviarão esse evento se o usuário fechar a janela de vídeo.
  • O evento EC_ERRORABORT indica que um erro causou a interrupção da reprodução.

Usando a notificação de evento

Um aplicativo pode instruir o Gerenciador de Grafo de Filtro a enviar uma mensagem do Windows para uma janela designada sempre que ocorrer um novo evento. Isso permite que o aplicativo responda dentro do loop de mensagens da janela. Primeiro, defina a mensagem que será enviada para a janela do aplicativo. Os aplicativos podem usar números de mensagem no intervalo de WM_APP até 0xBFFF como mensagens privadas:

#define WM_GRAPHNOTIFY  WM_APP + 1

Em seguida, consulte o Filter Graph Manager para a interface IMediaEventEx e chame o método IMediaEventEx::SetNotifyWindow :

IMediaEventEx *g_pEvent = NULL;
g_pGraph->QueryInterface(IID_IMediaEventEx, (void **)&g_pEvent);
g_pEvent->SetNotifyWindow((OAHWND)g_hwnd, WM_GRAPHNOTIFY, 0);

Esse método designa a janela especificada (g_hwnd) como o destinatário da mensagem. Chame o método depois de criar o grafo de filtro, mas antes de executar o grafo.

WM_GRAPHNOTIFY é uma mensagem comum do Windows. Sempre que o Gerenciador de Grafo de Filtro coloca um novo evento na fila de eventos, ele posta uma mensagem WM_GRAPHNOTIFY na janela do aplicativo designado. O parâmetro lParam da mensagem é igual ao terceiro parâmetro em SetNotifyWindow. Esse parâmetro permite que você envie dados de instância com a mensagem. O parâmetro wParam da mensagem de janela é sempre zero.

Na função WindowProc do aplicativo, adicione uma instrução case para a mensagem WM_GRAPHNOTIFY:

case WM_GRAPHNOTIFY:
    HandleGraphEvent();
    break;

Na função de manipulador de eventos, chame o método IMediaEvent::GetEvent para recuperar eventos da fila:

void HandleGraphEvent()
{
    // Disregard if we don't have an IMediaEventEx pointer.
    if (g_pEvent == NULL)
    {
        return;
    }
    // Get all the events
    long evCode;
    LONG_PTR param1, param2;
    HRESULT hr;
    while (SUCCEEDED(g_pEvent->GetEvent(&evCode, &param1, &param2, 0)))
    {
        g_pEvent->FreeEventParams(evCode, param1, param2);
        switch (evCode)
        {
        case EC_COMPLETE:  // Fall through.
        case EC_USERABORT: // Fall through.
        case EC_ERRORABORT:
            CleanUp();
            PostQuitMessage(0);
            return;
        }
    } 
}

O método GetEvent recupera o código do evento e os dois parâmetros de evento. O quarto parâmetro GetEvent especifica o período de tempo para aguardar um evento, em milissegundos. Como o aplicativo chama esse método em resposta a uma mensagem WM_GRAPHNOTIFY, o evento já está na fila. Portanto, definimos o valor de tempo limite como zero.

A notificação de eventos e o loop de mensagem são assíncronos, portanto, a fila pode conter mais de um evento quando o aplicativo responder à mensagem. Além disso, o Gerenciador de Grafo de Filtro poderá remover determinados eventos da fila, se eles se tornarem inválidos. Portanto, você deve chamar GetEvent até que ele retorne um código de falha, indicando que a fila está vazia.

Neste exemplo, o aplicativo responde a EC_COMPLETE, EC_USERABORT e EC_ERRORABORT invocando a função CleanUp definida pelo aplicativo, o que faz com que o aplicativo seja encerrado normalmente. O exemplo ignora os dois parâmetros de evento. Depois de recuperar um evento, chame IMediaEvent::FreeEventParams para todos os recursos gratuitos associados aos parâmetros de evento.

Observe que um evento de EC_COMPLETE não faz com que o grafo de filtro pare. O aplicativo pode parar ou pausar o grafo. Se você parar o grafo, os filtros liberarão todos os recursos que eles estão mantendo. Se você pausar o grafo, os filtros continuarão a conter recursos. Além disso, quando um renderizador de vídeo é pausado, ele exibe uma imagem estática do quadro mais recente.

Antes de liberar o ponteiro IMediaEventEx, cancele a notificação de evento chamando SetNotifyWindow com um identificador de janela NULL :

// Disable event notification before releasing the graph.
g_pEvent->SetNotifyWindow(NULL, 0, 0);
g_pEvent->Release();
g_pEvent = NULL;

No manipulador de mensagens WM_GRAPHNOTIFY, marcar o ponteiro IMediaEventEx antes de chamar GetEvent:

if (g_pEvent == NULL) return;

Isso impede um possível erro que pode ocorrer se o aplicativo receber a notificação de evento depois de liberar o ponteiro.

Tarefas básicas do DirectShow

Notificação de eventos no DirectShow