Share via


Risposta agli eventi

[La funzionalità associata a questa pagina, DirectShow, è una funzionalità legacy. È stata sostituita da MediaPlayer, IMFMediaEngine e Audio/Video Capture in Media Foundation. Queste funzionalità sono state ottimizzate per Windows 10 e Windows 11. Microsoft consiglia vivamente che il nuovo codice usi MediaPlayer, IMFMediaEngine e Audio/Video Capture in Media Foundation invece di DirectShow, quando possibile. Microsoft suggerisce che il codice esistente che usa le API legacy venga riscritto per usare le nuove API, se possibile.

Questo articolo descrive come rispondere agli eventi che si verificano in un grafico di filtro.

Funzionamento della notifica degli eventi

Durante l'esecuzione di un'applicazione DirectShow, gli eventi possono verificarsi all'interno del grafico del filtro. Ad esempio, un filtro potrebbe riscontrare un errore di streaming. I filtri avvisano Filter Graph Manager inviando eventi, costituiti da un codice evento e da due parametri di evento. Il codice evento indica il tipo di evento e i parametri dell'evento forniscono informazioni aggiuntive. Il significato dei parametri dipende dal codice dell'evento. Per un elenco completo dei codici evento, vedere Codici di notifica degli eventi.

Alcuni eventi vengono gestiti automaticamente da Filter Graph Manager, senza che l'applicazione venga notificata. Altri eventi vengono inseriti in una coda per l'applicazione. A seconda dell'applicazione, potrebbero essere necessari vari eventi. Questo articolo è incentrato su tre eventi molto comuni:

  • L'evento EC_COMPLETE indica che la riproduzione è stata completata normalmente.
  • L'evento EC_USERABORT indica che l'utente ha interrotto la riproduzione. I renderer video inviano questo evento se l'utente chiude la finestra del video.
  • L'evento EC_ERRORABORT indica che un errore ha causato l'interruzione della riproduzione.

Uso della notifica degli eventi

Un'applicazione può indicare a Filter Graph Manager di inviare un messaggio di Windows a una finestra designata ogni volta che si verifica un nuovo evento. Ciò consente all'applicazione di rispondere all'interno del ciclo di messaggi della finestra. Definire prima di tutto il messaggio che verrà inviato alla finestra dell'applicazione. Le applicazioni possono usare numeri di messaggio nell'intervallo compreso tra WM_APP e 0xBFFF come messaggi privati:

#define WM_GRAPHNOTIFY  WM_APP + 1

Eseguire quindi una query su Filter Graph Manager per l'interfaccia IMediaEventEx e chiamare il metodo IMediaEventEx::SetNotifyWindow :

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

Questo metodo definisce la finestra specificata (g_hwnd) come destinatario del messaggio. Chiamare il metodo dopo aver creato il grafico del filtro, ma prima di eseguire il grafico.

WM_GRAPHNOTIFY è un normale messaggio di Windows. Ogni volta che Filter Graph Manager inserisce un nuovo evento nella coda di eventi, invia un messaggio di WM_GRAPHNOTIFY alla finestra dell'applicazione designata. Il parametro lParam del messaggio è uguale al terzo parametro in SetNotifyWindow. Questo parametro consente di inviare i dati dell'istanza con il messaggio. Il parametro wParam del messaggio della finestra è sempre zero.

Nella funzione WindowProc dell'applicazione aggiungere un'istruzione case per il messaggio WM_GRAPHNOTIFY:

case WM_GRAPHNOTIFY:
    HandleGraphEvent();
    break;

Nella funzione del gestore eventi chiamare il metodo IMediaEvent::GetEvent per recuperare gli eventi dalla coda:

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;
        }
    } 
}

Il metodo GetEvent recupera il codice evento e i due parametri dell'evento. Il quarto parametro GetEvent specifica il tempo di attesa di un evento, espresso in millisecondi. Poiché l'applicazione chiama questo metodo in risposta a un messaggio di WM_GRAPHNOTIFY, l'evento è già in coda. Pertanto, il valore di timeout viene impostato su zero.

La notifica degli eventi e il ciclo di messaggi sono entrambi asincroni, pertanto la coda potrebbe contenere più di un evento al momento in cui l'applicazione risponde al messaggio. Inoltre, Filter Graph Manager può rimuovere determinati eventi dalla coda, se diventano non validi. Pertanto, è necessario chiamare GetEvent finché non restituisce un codice di errore, a indicare che la coda è vuota.

In questo esempio, l'applicazione risponde a EC_COMPLETE, EC_USERABORT e EC_ERRORABORT richiamando la funzione CleanUp definita dall'applicazione, che causa la chiusura normale dell'applicazione. Nell'esempio vengono ignorati i due parametri dell'evento. Dopo aver recuperato un evento, chiamare IMediaEvent::FreeEventParams per tutte le risorse gratuite associate ai parametri dell'evento.

Si noti che un evento EC_COMPLETE non causa l'arresto del grafico del filtro. L'applicazione può arrestare o sospendere il grafico. Se si arresta il grafico, i filtri rilasciano tutte le risorse che contengono. Se si sospende il grafico, i filtri continuano a contenere le risorse. Inoltre, quando un renderer video viene sospeso, viene visualizzata un'immagine statica del fotogramma più recente.

Prima di rilasciare il puntatore IMediaEventEx , annullare la notifica degli eventi chiamando SetNotifyWindow con un handle di finestra NULL :

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

Nel gestore dei messaggi WM_GRAPHNOTIFY controllare il puntatore IMediaEventEx prima di chiamare GetEvent:

if (g_pEvent == NULL) return;

Ciò impedisce un possibile errore che può verificarsi se l'applicazione riceve la notifica degli eventi dopo il rilascio del puntatore.

Attività DirectShow di base

Notifica degli eventi in DirectShow