Partilhar via


Responder a eventos

[O recurso associado a esta página, DirectShow, é um recurso herdado. Foi substituído por MediaPlayer, IMFMediaEnginee Audio/Video Capture in Media Foundation. Esses recursos foram otimizados para Windows 10 e Windows 11. A Microsoft recomenda vivamente que o novo código utilize MediaPlayer, IMFMediaEngine e Captura de Áudio/Vídeo no 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 gráfico de filtro.

Como funciona a notificação de eventos

Enquanto um aplicativo DirectShow está em execução, eventos podem ocorrer dentro do gráfico de filtro. Por exemplo, um filtro pode encontrar um erro de streaming. Os filtros alertam o Gerenciador de Gráficos de Filtros enviando eventos, que consistem em um código de evento e dois parâmetros de evento. O código do evento indica o tipo de evento e os parâmetros do 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 evento.

Alguns eventos são tratados silenciosamente pelo Filter Graph Manager, 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 você pode precisar manipular. Este artigo concentra-se em três eventos que são 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 enviam esse evento se o usuário fechar a janela de vídeo.
  • O evento EC_ERRORABORT indica que um erro fez com que a reprodução fosse interrompida.

Usando a notificação de evento

Um aplicativo pode instruir o Gerenciador de Gráficos de Filtro para 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 mensagens no intervalo de WM_APP a 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);

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

WM_GRAPHNOTIFY é uma mensagem comum do Windows. Sempre que o Filter Graph Manager 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 enviar dados da instância com a mensagem. O parâmetro wParam da mensagem da janela é sempre zero.

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

case WM_GRAPHNOTIFY:
    HandleGraphEvent();
    break;

Na função manipulador de eventos, chame o IMediaEvent::GetEvent método 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 de espera por 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 mensagens são assíncronos, portanto, a fila pode conter mais de um evento no momento em que seu aplicativo responde à mensagem. Além disso, o Filter Graph Manager pode 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_USERABORTe EC_ERRORABORT invocando a função CleanUp definida pelo aplicativo, que faz com que o aplicativo saia normalmente. O exemplo ignora os dois parâmetros de evento. Depois de recuperar um evento, chame IMediaEvent::FreeEventParams para libertar quaisquer recursos associados aos parâmetros do evento.

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

Antes de liberar o ponteiro do 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, verifique o ponteiro IMediaEventEx antes de chamar GetEvent:

if (g_pEvent == NULL) return;

Isso evita 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 evento no DirectShow