Wiedergeben einer Datei

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

Dieser Artikel soll Ihnen den Geschmack der DirectShow-Programmierung vermitteln. Es stellt eine einfache Konsolenanwendung dar, die eine Audio- oder Videodatei wiedergibt. Das Programm ist nur wenige Zeilen lang, aber es zeigt einige der Möglichkeiten der DirectShow-Programmierung.

Wie im Artikel Einführung in die DirectShow-Anwendungsprogrammierung beschrieben, führt eine DirectShow-Anwendung immer die gleichen grundlegenden Schritte aus:

  1. Erstellen Sie eine instance des Filter Graph-Managers.
  2. Verwenden Sie den Filtergraph-Manager, um ein Filterdiagramm zu erstellen.
  3. Führen Sie das Diagramm aus, sodass Daten durch die Filter verschoben werden.

Um den Code in diesem Thema zu kompilieren und zu verknüpfen, schließen Sie die Headerdatei Dshow.h ein, und verknüpfen Sie die statische Bibliotheksdatei strmiids.lib. Weitere Informationen finden Sie unter Erstellen von DirectShow-Anwendungen.

Rufen Sie zunächst CoInitialize oder CoInitializeEx auf, um die COM-Bibliothek zu initialisieren:

HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
    // Add error-handling code here. (Omitted for clarity.)
}

Um die Dinge einfach zu halten, ignoriert dieses Beispiel den Rückgabewert, aber Sie sollten immer den HRESULT-Wert aus jedem Methodenaufruf überprüfen.

Rufen Sie als Nächstes CoCreateInstance auf, um den Filter Graph-Manager zu erstellen:

IGraphBuilder *pGraph;
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, 
    CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph);

Wie gezeigt, ist der Klassenbezeichner (CLSID) CLSID_FilterGraph. Der Filter Graph-Manager wird von einer prozessinternen DLL bereitgestellt, sodass der Ausführungskontext CLSCTX_INPROC_SERVER wird. DirectShow unterstützt das Free-Threading-Modell, sodass Sie CoInitializeEx auch mit dem flag COINIT_MULTITHREADED aufrufen können.

Der Aufruf von CoCreateInstance gibt die IGraphBuilder-Schnittstelle zurück, die größtenteils Methoden zum Erstellen des Filterdiagramms enthält. Für dieses Beispiel sind zwei weitere Schnittstellen erforderlich:

  • IMediaControl steuert das Streaming. Sie enthält Methoden zum Beenden und Starten des Graphen.
  • IMediaEvent verfügt über Methoden zum Abrufen von Ereignissen aus dem Filter Graph-Manager. In diesem Beispiel wird die -Schnittstelle verwendet, um auf den Abschluss der Wiedergabe zu warten.

Beide Schnittstellen werden vom Filter Graph-Manager verfügbar gemacht. Verwenden Sie den zurückgegebenen IGraphBuilder-Zeiger , um sie abzufragen:

IMediaControl *pControl;
IMediaEvent   *pEvent;
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);

Jetzt können Sie das Filterdiagramm erstellen. Bei der Dateiwiedergabe erfolgt dies durch einen einzelnen Methodenaufruf:

hr = pGraph->RenderFile(L"C:\\Example.avi", NULL);

Die IGraphBuilder::RenderFile-Methode erstellt ein Filterdiagramm, das die angegebene Datei wiedergeben kann. Der erste Parameter ist der Dateiname, der als Breitzeichenzeichenfolge (2-Byte) dargestellt wird. Der zweite Parameter ist reserviert und muss gleich NULL sein.

Diese Methode kann fehlschlagen, wenn die angegebene Datei nicht vorhanden ist oder das Dateiformat nicht erkannt wird. Unter der Annahme, dass die Methode erfolgreich ist, ist das Filterdiagramm jetzt für die Wiedergabe bereit. Rufen Sie zum Ausführen des Graphen die IMediaControl::Run-Methode auf :

hr = pControl->Run();

Wenn das Filterdiagramm ausgeführt wird, durchlaufen die Daten die Filter und werden als Video und Audio gerendert. Die Wiedergabe erfolgt in einem separaten Thread. Sie können warten, bis die Wiedergabe abgeschlossen ist, indem Sie die IMediaEvent::WaitForCompletion-Methode aufrufen:

long evCode = 0;
pEvent->WaitForCompletion(INFINITE, &evCode);

Diese Methode blockiert, bis die Wiedergabe der Datei abgeschlossen ist oder das angegebene Timeoutintervall verstrichen ist. Der Wert INFINITE bedeutet, dass die Anwendung unbegrenzt blockiert wird, bis die Wiedergabe der Datei abgeschlossen ist. Ein realistischeres Beispiel für die Ereignisbehandlung finden Sie unter Reagieren auf Ereignisse.

Wenn die Anwendung abgeschlossen ist, lassen Sie die Schnittstellenzeiger frei, und schließen Sie die COM-Bibliothek:

pControl->Release();
pEvent->Release();
pGraph->Release();
CoUninitialize();

Beispielcode

Hier sehen Sie den vollständigen Code für das in diesem Artikel beschriebene Beispiel:

#include <dshow.h>
void main(void)
{
    IGraphBuilder *pGraph = NULL;
    IMediaControl *pControl = NULL;
    IMediaEvent   *pEvent = NULL;

    // Initialize the COM library.
    HRESULT hr = CoInitialize(NULL);
    if (FAILED(hr))
    {
        printf("ERROR - Could not initialize COM library");
        return;
    }

    // Create the filter graph manager and query for interfaces.
    hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, 
                        IID_IGraphBuilder, (void **)&pGraph);
    if (FAILED(hr))
    {
        printf("ERROR - Could not create the Filter Graph Manager.");
        return;
    }

    hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
    hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);

    // Build the graph. IMPORTANT: Change this string to a file on your system.
    hr = pGraph->RenderFile(L"C:\\Example.avi", NULL);
    if (SUCCEEDED(hr))
    {
        // Run the graph.
        hr = pControl->Run();
        if (SUCCEEDED(hr))
        {
            // Wait for completion.
            long evCode;
            pEvent->WaitForCompletion(INFINITE, &evCode);

            // Note: Do not use INFINITE in a real application, because it
            // can block indefinitely.
        }
    }
    pControl->Release();
    pEvent->Release();
    pGraph->Release();
    CoUninitialize();
}

Grundlegende DirectShow-Aufgaben