Reagieren auf Ereignisse

[Das dieser Seite zugeordnete Feature DirectShow ist ein Legacyfeature. Es wurde von MediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation abgelöst. Diese Features wurden für Windows 10 und Windows 11 optimiert. Microsoft empfiehlt dringend, dass neuer Code mediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation anstelle von DirectShow verwendet, wenn möglich. Microsoft schlägt vor, dass vorhandener Code, der die Legacy-APIs verwendet, so umgeschrieben wird, dass nach Möglichkeit die neuen APIs verwendet werden.]

In diesem Artikel wird beschrieben, wie Sie auf Ereignisse reagieren, die in einem Filterdiagramm auftreten.

Funktionsweise von Ereignisbenachrichtigungen

Während eine DirectShow-Anwendung ausgeführt wird, können Ereignisse innerhalb des Filterdiagramms auftreten. Beispielsweise kann bei einem Filter ein Streamingfehler auftreten. Filter warnen den Graph-Filter-Manager, indem Ereignisse gesendet werden, die aus einem Ereigniscode und zwei Ereignisparametern bestehen. Der Ereigniscode gibt den Typ des Ereignisses an, und die Ereignisparameter liefern zusätzliche Informationen. Die Bedeutung der Parameter hängt vom Ereigniscode ab. Eine vollständige Liste der Ereigniscodes finden Sie unter Ereignisbenachrichtigungscodes.

Einige Ereignisse werden vom Filter Graph-Manager automatisch behandelt, ohne dass die Anwendung benachrichtigt wird. Andere Ereignisse werden in einer Warteschlange für die Anwendung platziert. Je nach Anwendung gibt es verschiedene Ereignisse, die Sie möglicherweise behandeln müssen. Dieser Artikel konzentriert sich auf drei Ereignisse, die sehr häufig sind:

  • Das ereignis EC_COMPLETE gibt an, dass die Wiedergabe normal abgeschlossen wurde.
  • Das EC_USERABORT-Ereignis gibt an, dass der Benutzer die Wiedergabe unterbrochen hat. Videorenderer senden dieses Ereignis, wenn der Benutzer das Videofenster schließt.
  • Das EC_ERRORABORT-Ereignis gibt an, dass die Wiedergabe aufgrund eines Fehlers angehalten wurde.

Verwenden von Ereignisbenachrichtigungen

Eine Anwendung kann den Filter Graph-Manager anweisen, bei jedem Auftreten eines neuen Ereignisses eine Windows-Nachricht an ein bestimmtes Fenster zu senden. Dadurch kann die Anwendung innerhalb der Meldungsschleife des Fensters reagieren. Definieren Sie zunächst die Nachricht, die an das Anwendungsfenster gesendet wird. Anwendungen können Nachrichtennummern im Bereich von WM_APP bis 0xBFFF als private Nachrichten verwenden:

#define WM_GRAPHNOTIFY  WM_APP + 1

Fragen Sie als Nächstes den Filter Graph-Manager für die IMediaEventEx-Schnittstelle ab, und rufen Sie die IMediaEventEx::SetNotifyWindow-Methode auf :

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

Diese Methode legt das angegebene Fenster (g_hwnd) als Empfänger der Nachricht fest. Rufen Sie die -Methode auf, nachdem Sie das Filterdiagramm erstellt haben, aber vor dem Ausführen des Graphen.

WM_GRAPHNOTIFY ist eine normale Windows-Nachricht. Wenn der Filter Graph-Manager ein neues Ereignis in die Ereigniswarteschlange einfügt, sendet er eine WM_GRAPHNOTIFY Nachricht an das angegebene Anwendungsfenster. Der lParam-Parameter der Nachricht ist gleich dem dritten Parameter in SetNotifyWindow. Mit diesem Parameter können Sie instance Daten mit der Nachricht senden. Der wParam-Parameter der Fensternachricht ist immer null.

Fügen Sie in der WindowProc-Funktion Ihrer Anwendung eine Case-Anweisung für die WM_GRAPHNOTIFY Meldung hinzu:

case WM_GRAPHNOTIFY:
    HandleGraphEvent();
    break;

Rufen Sie in der Ereignishandlerfunktion die IMediaEvent::GetEvent-Methode auf, um Ereignisse aus der Warteschlange abzurufen:

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

Die GetEvent-Methode ruft den Ereigniscode und die beiden Ereignisparameter ab. Der vierte GetEvent-Parameter gibt die Zeitdauer an, in Millisekunden auf ein Ereignis zu warten. Da die Anwendung diese Methode als Reaktion auf eine WM_GRAPHNOTIFY-Nachricht aufruft, befindet sich das Ereignis bereits in der Warteschlange. Daher legen wir den Timeoutwert auf 0 (null) fest.

Die Ereignisbenachrichtigung und die Nachrichtenschleife sind asynchron, sodass die Warteschlange möglicherweise mehr als ein Ereignis enthält, wenn Ihre Anwendung auf die Nachricht antwortet. Außerdem kann der Filter Graph Manager bestimmte Ereignisse aus der Warteschlange entfernen, wenn sie ungültig werden. Daher sollten Sie GetEvent aufrufen, bis ein Fehlercode zurückgegeben wird, der angibt, dass die Warteschlange leer ist.

In diesem Beispiel antwortet die Anwendung auf EC_COMPLETE, EC_USERABORT und EC_ERRORABORT , indem sie die anwendungsdefinierte CleanUp-Funktion aufruft, wodurch die Anwendung ordnungsgemäß beendet wird. Im Beispiel werden die beiden Ereignisparameter ignoriert. Nachdem Sie ein Ereignis abgerufen haben, rufen Sie IMediaEvent::FreeEventParams für alle freien Ressourcen auf, die den Ereignisparametern zugeordnet sind.

Beachten Sie, dass ein EC_COMPLETE-Ereignis nicht bewirkt, dass das Filterdiagramm beendet wird. Die Anwendung kann den Graphen entweder beenden oder anhalten. Wenn Sie das Diagramm beenden, geben Filter alle Darin enthaltenen Ressourcen frei. Wenn Sie das Diagramm anhalten, enthalten Filter weiterhin Ressourcen. Wenn ein Videorenderer anhält, wird außerdem ein statisches Bild des letzten Frames angezeigt.

Bevor Sie den IMediaEventEx-Zeiger freigeben, brechen Sie die Ereignisbenachrichtigung ab, indem Sie SetNotifyWindow mit einem NULL-Fensterhandle aufrufen:

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

Überprüfen Sie im WM_GRAPHNOTIFY-Nachrichtenhandler den IMediaEventEx-Zeiger , bevor Sie GetEvent aufrufen:

if (g_pEvent == NULL) return;

Dadurch wird ein möglicher Fehler verhindert, der auftreten kann, wenn die Anwendung die Ereignisbenachrichtigung nach dem Freigeben des Zeigers empfängt.

Grundlegende DirectShow-Aufgaben

Ereignisbenachrichtigung in DirectShow