Freigeben über


Schritt 3: Erstellen des Filterdiagramms

[Das dieser Seite zugeordnete Feature DirectShow ist ein Legacyfeature. Es wurde durch MediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation ersetzt. Diese Features wurden für Windows 10 und Windows 11 optimiert. Microsoft empfiehlt dringend, dass neuer Code nach Möglichkeit MediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation anstelle von DirectShow verwendet. Microsoft schlägt vor, vorhandenen Code, der die Legacy-APIs verwendet, um nach Möglichkeit die neuen APIs zu verwenden.]

Dieses Thema ist Schritt 3 des Tutorials Audio-/Videowiedergabe in DirectShow. Der vollständige Code wird im Thema DirectShow-Wiedergabebeispiel angezeigt.

Der nächste Schritt besteht darin, ein Filterdiagramm zu erstellen, um die Mediendatei wiederzugeben.

Öffnen einer Mediendatei

Die DShowPlayer::OpenFile -Methode öffnet eine Mediendatei für die Wiedergabe. Diese Methode führt Folgendes aus:

  1. Erstellt ein neues (leeres) Filterdiagramm.
  2. Ruft IGraphBuilder::AddSourceFilter auf, um einen Quellfilter für die angegebene Datei hinzuzufügen.
  3. Rendert die Streams im Quellfilter.
HRESULT DShowPlayer::OpenFile(PCWSTR pszFileName)
{
    IBaseFilter *pSource = NULL;

    // Create a new filter graph. (This also closes the old one, if any.)
    HRESULT hr = InitializeGraph();
    if (FAILED(hr))
    {
        goto done;
    }
    
    // Add the source filter to the graph.
    hr = m_pGraph->AddSourceFilter(pszFileName, NULL, &pSource);
    if (FAILED(hr))
    {
        goto done;
    }

    // Try to render the streams.
    hr = RenderStreams(pSource);

done:
    if (FAILED(hr))
    {
        TearDownGraph();
    }
    SafeRelease(&pSource);
    return hr;
}

Erstellen des Filtergraph-Managers

Die DShowPlayer::InitializeGraph -Methode erstellt ein neues Filterdiagramm. Diese Methode führt Folgendes aus:

  1. Ruft CoCreateInstance auf, um eine neue instance des Filter Graph-Managers zu erstellen.
  2. Fragt den Filter Graph-Manager für die Schnittstellen IMediaControl und IMediaEventEx ab.
  3. Ruft IMediaEventEx::SetNotifyWindow auf, um ereignisbenachrichtigungen einzurichten. Weitere Informationen finden Sie unter Ereignisbenachrichtigung in DirectShow.
HRESULT DShowPlayer::InitializeGraph()
{
    TearDownGraph();

    // Create the Filter Graph Manager.
    HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, 
        CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_pGraph));
    if (FAILED(hr))
    {
        goto done;
    }

    hr = m_pGraph->QueryInterface(IID_PPV_ARGS(&m_pControl));
    if (FAILED(hr))
    {
        goto done;
    }

    hr = m_pGraph->QueryInterface(IID_PPV_ARGS(&m_pEvent));
    if (FAILED(hr))
    {
        goto done;
    }

    // Set up event notification.
    hr = m_pEvent->SetNotifyWindow((OAHWND)m_hwnd, WM_GRAPH_EVENT, NULL);
    if (FAILED(hr))
    {
        goto done;
    }

    m_state = STATE_STOPPED;

done:
    return hr;
}

Rendern der Streams

Der nächste Schritt besteht darin, den Quellfilter mit einem oder mehreren Rendererfiltern zu verbinden.

Die DShowPlayer::RenderStreams -Methode führt die folgenden Schritte aus.

  1. Fragt den Filter Graph-Manager nach der IFilterGraph2-Schnittstelle ab.
  2. Fügt dem Filterdiagramm einen Videorendererfilter hinzu.
  3. Fügt dem Filterdiagramm den DirectSound-Rendererfilter hinzu, um die Audiowiedergabe zu unterstützen. Weitere Informationen zum Hinzufügen von Filtern zum Filterdiagramm finden Sie unter Hinzufügen eines Filters by CLSID.
  4. Listet die Ausgabepins für den Quellfilter auf. Weitere Informationen zum Aufzählen von Pins finden Sie unter Aufzählen von Pins.
  5. Ruft für jeden Pin die IFilterGraph2::RenderEx-Methode auf. Diese Methode verbindet den Ausgabepin mit einem Rendererfilter und fügt bei Bedarf Zwischenfilter (z. B. Decoder) hinzu.
  6. Aufrufe CVideoRenderer::FinalizeGraph , um die Initialisierung des Videorenderers abzuschließen.
  7. Entfernt den DirectSound-Renderer-Filter , wenn dieser Filter nicht mit einem anderen Filter verbunden ist. Dies kann auftreten, wenn die Quelldatei keinen Audiodatenstrom enthält.
// Render the streams from a source filter. 

HRESULT DShowPlayer::RenderStreams(IBaseFilter *pSource)
{
    BOOL bRenderedAnyPin = FALSE;

    IFilterGraph2 *pGraph2 = NULL;
    IEnumPins *pEnum = NULL;
    IBaseFilter *pAudioRenderer = NULL;
    HRESULT hr = m_pGraph->QueryInterface(IID_PPV_ARGS(&pGraph2));
    if (FAILED(hr))
    {
        goto done;
    }

    // Add the video renderer to the graph
    hr = CreateVideoRenderer();
    if (FAILED(hr))
    {
        goto done;
    }

    // Add the DSound Renderer to the graph.
    hr = AddFilterByCLSID(m_pGraph, CLSID_DSoundRender, 
        &pAudioRenderer, L"Audio Renderer");
    if (FAILED(hr))
    {
        goto done;
    }

    // Enumerate the pins on the source filter.
    hr = pSource->EnumPins(&pEnum);
    if (FAILED(hr))
    {
        goto done;
    }

    // Loop through all the pins
    IPin *pPin;
    while (S_OK == pEnum->Next(1, &pPin, NULL))
    {           
        // Try to render this pin. 
        // It's OK if we fail some pins, if at least one pin renders.
        HRESULT hr2 = pGraph2->RenderEx(pPin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL);

        pPin->Release();
        if (SUCCEEDED(hr2))
        {
            bRenderedAnyPin = TRUE;
        }
    }

    hr = m_pVideo->FinalizeGraph(m_pGraph);
    if (FAILED(hr))
    {
        goto done;
    }

    // Remove the audio renderer, if not used.
    BOOL bRemoved;
    hr = RemoveUnconnectedRenderer(m_pGraph, pAudioRenderer, &bRemoved);

done:
    SafeRelease(&pEnum);
    SafeRelease(&pAudioRenderer);
    SafeRelease(&pGraph2);

    // If we succeeded to this point, make sure we rendered at least one 
    // stream.
    if (SUCCEEDED(hr))
    {
        if (!bRenderedAnyPin)
        {
            hr = VFW_E_CANNOT_RENDER;
        }
    }
    return hr;
}

Hier ist der Code für die RemoveUnconnectedRenderer Funktion, die im vorherigen Beispiel verwendet wird.

HRESULT RemoveUnconnectedRenderer(IGraphBuilder *pGraph, IBaseFilter *pRenderer, BOOL *pbRemoved)
{
    IPin *pPin = NULL;

    *pbRemoved = FALSE;

    // Look for a connected input pin on the renderer.

    HRESULT hr = FindConnectedPin(pRenderer, PINDIR_INPUT, &pPin);
    SafeRelease(&pPin);

    // If this function succeeds, the renderer is connected, so we don't remove it.
    // If it fails, it means the renderer is not connected to anything, so
    // we remove it.

    if (FAILED(hr))
    {
        hr = pGraph->RemoveFilter(pRenderer);
        *pbRemoved = TRUE;
    }

    return hr;
}

Freigeben des Filterdiagramms

Wenn die Anwendung beendet wird, muss sie das Filterdiagramm freigeben, wie im folgenden Code gezeigt.

void DShowPlayer::TearDownGraph()
{
    // Stop sending event messages
    if (m_pEvent)
    {
        m_pEvent->SetNotifyWindow((OAHWND)NULL, NULL, NULL);
    }

    SafeRelease(&m_pGraph);
    SafeRelease(&m_pControl);
    SafeRelease(&m_pEvent);

    delete m_pVideo;
    m_pVideo = NULL;

    m_state = STATE_NO_GRAPH;
}

Nächster Schritt 4: Hinzufügen des Videorenderers.

Audio-/Videowiedergabe in DirectShow

DirectShow-Wiedergabebeispiel

Erstellen des Filterdiagramms

Allgemeine Graph-Building Techniken