Freigeben über


Suchen eines Filterpeers

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

Bei einem Filter können Sie das Diagramm durchlaufen, indem Sie die Filter suchen, mit denen es verbunden ist. Beginnen Sie mit dem Aufzählen der Pins des Filters. Überprüfen Sie für jeden Pin, ob dieser Pin mit einem anderen Pin verbunden ist. Wenn dies der Fall ist, fragen Sie den anderen Pin nach dem eigenen Filter ab. Sie können den Graphen in der Upstream Richtung durchlaufen, indem Sie die Eingabestifte des Filters auflisten, oder in der Downstreamrichtung, indem Sie die Ausgabepins auflisten.

Die folgende Funktion sucht Upstream oder nach einem verbundenen Filter. Er gibt den ersten übereinstimmenden Filter zurück, den er findet:

// Get the first upstream or downstream filter
HRESULT GetNextFilter(
    IBaseFilter *pFilter, // Pointer to the starting filter
    PIN_DIRECTION Dir,    // Direction to search (upstream or downstream)
    IBaseFilter **ppNext) // Receives a pointer to the next filter.
{
    if (!pFilter || !ppNext) return E_POINTER;

    IEnumPins *pEnum = 0;
    IPin *pPin = 0;
    HRESULT hr = pFilter->EnumPins(&pEnum);
    if (FAILED(hr)) return hr;
    while (S_OK == pEnum->Next(1, &pPin, 0))
    {
        // See if this pin matches the specified direction.
        PIN_DIRECTION ThisPinDir;
        hr = pPin->QueryDirection(&ThisPinDir);
        if (FAILED(hr))
        {
            // Something strange happened.
            hr = E_UNEXPECTED;
            pPin->Release();
            break;
        }
        if (ThisPinDir == Dir)
        {
            // Check if the pin is connected to another pin.
            IPin *pPinNext = 0;
            hr = pPin->ConnectedTo(&pPinNext);
            if (SUCCEEDED(hr))
            {
                // Get the filter that owns that pin.
                PIN_INFO PinInfo;
                hr = pPinNext->QueryPinInfo(&PinInfo);
                pPinNext->Release();
                pPin->Release();
                pEnum->Release();
                if (FAILED(hr) || (PinInfo.pFilter == NULL))
                {
                    // Something strange happened.
                    return E_UNEXPECTED;
                }
                // This is the filter we're looking for.
                *ppNext = PinInfo.pFilter; // Client must release.
                return S_OK;
            }
        }
        pPin->Release();
    }
    pEnum->Release();
    // Did not find a matching filter.
    return E_FAIL;
}

Die Funktion ruft IBaseFilter::EnumPins auf, um die Pins des ersten Filters aufzulisten. Für jeden Pin wird IPin::QueryDirection aufgerufen, um zu überprüfen, ob die Pin mit der angegebenen Richtung (Eingabe oder Ausgabe) übereinstimmt. Wenn ja, bestimmt die Funktion, ob dieser Pin mit einem anderen Pin verbunden ist, indem die IPin::ConnectedTo-Methode aufgerufen wird. Schließlich wird IPin::QueryPinInfo auf dem verbundenen Pin aufgerufen. Diese Methode gibt eine Struktur zurück, die unter anderem einen Zeiger auf den eigenen Filter dieser Pin enthält. Dieser Zeiger wird an den Aufrufer im ppNext-Parameter zurückgegeben. Der Aufrufer muss den Zeiger freigeben.

Der folgende Code zeigt, wie Diese Funktion aufgerufen wird:

IBaseFilter *pF; // Pointer to some filter.
IBaseFilter *pUpstream = NULL;
if (SUCCEEDED(GetNextFilter(pF, PINDIR_INPUT, &pUpstream)))
{
    // Use pUpstream ...
    pUpstream->Release();
}

Ein Filter kann mit zwei oder mehr Filtern in beide Richtungen verbunden sein. Es kann sich z. B. um einen Splitterfilter mit mehreren nachgeschalteten Filtern sein. Oder es kann sich um einen Muxfilter mit mehreren Filtern Upstream. Aus diesem Grund können Sie alle in einer Liste sammeln.

Der folgende Code zeigt eine mögliche Möglichkeit zum Implementieren einer solchen Funktion. Es verwendet die DirectShow-Klasse CGenericList . Sie könnten eine entsprechende Funktion mit einer anderen Datenstruktur schreiben.

#include <streams.h>  // Link to the DirectShow base class library
// Define a typedef for a list of filters.
typedef CGenericList<IBaseFilter> CFilterList;

// Forward declaration. Adds a filter to the list unless it's a duplicate.
void AddFilterUnique(CFilterList &FilterList, IBaseFilter *pNew);

// Find all the immediate upstream or downstream peers of a filter.
HRESULT GetPeerFilters(
    IBaseFilter *pFilter, // Pointer to the starting filter
    PIN_DIRECTION Dir,    // Direction to search (upstream or downstream)
    CFilterList &FilterList)  // Collect the results in this list.
{
    if (!pFilter) return E_POINTER;

    IEnumPins *pEnum = 0;
    IPin *pPin = 0;
    HRESULT hr = pFilter->EnumPins(&pEnum);
    if (FAILED(hr)) return hr;
    while (S_OK == pEnum->Next(1, &pPin, 0))
    {
        // See if this pin matches the specified direction.
        PIN_DIRECTION ThisPinDir;
        hr = pPin->QueryDirection(&ThisPinDir);
        if (FAILED(hr))
        {
            // Something strange happened.
            hr = E_UNEXPECTED;
            pPin->Release();
            break;
        }
        if (ThisPinDir == Dir)
        {
            // Check if the pin is connected to another pin.
            IPin *pPinNext = 0;
            hr = pPin->ConnectedTo(&pPinNext);
            if (SUCCEEDED(hr))
            {
                // Get the filter that owns that pin.
                PIN_INFO PinInfo;
                hr = pPinNext->QueryPinInfo(&PinInfo);
                pPinNext->Release();
                if (FAILED(hr) || (PinInfo.pFilter == NULL))
                {
                    // Something strange happened.
                    pPin->Release();
                    pEnum->Release();
                    return E_UNEXPECTED;
                }
                // Insert the filter into the list.
                AddFilterUnique(FilterList, PinInfo.pFilter);
                PinInfo.pFilter->Release();
            }
        }
        pPin->Release();
    }
    pEnum->Release();
    return S_OK;
}
void AddFilterUnique(CFilterList &FilterList, IBaseFilter *pNew)
{
    if (pNew == NULL) return;

    POSITION pos = FilterList.GetHeadPosition();
    while (pos)
    {
        IBaseFilter *pF = FilterList.GetNext(pos);
        if (IsEqualObject(pF, pNew))
        {
            return;
        }
    }
    pNew->AddRef();  // The caller must release everything in the list.
    FilterList.AddTail(pNew);
}

Um die Sache etwas zu erschweren, kann ein Filter mehrere Pinverbindungen mit demselben Filter haben. Um das Einfügen von Duplikaten in die Liste zu vermeiden, fragen Sie jeden IBaseFilter-Zeiger nach IUnknown ab, und vergleichen Sie die IUnknown-Zeiger . Nach den Regeln von COM verweisen zwei Schnittstellenzeiger nur dann auf dasselbe Objekt, wenn sie identische IUnknown-Zeiger zurückgeben. Im vorherigen Beispiel verarbeitet die AddFilterUnique-Funktion diese Details.

Im folgenden Beispiel wird die Verwendung der GetPeerFilters-Funktion veranschaulicht:

IBaseFilter *pF; // Pointer to some filter.
CFilterList FList(NAME("MyList"));  // List to hold the downstream peers.
hr = GetPeerFilters(pF, PINDIR_OUTPUT, FList);
if (SUCCEEDED(hr))
{
    POSITION pos = FList.GetHeadPosition();
    while (pos)
    {
        IBaseFilter *pDownstream = FList.GetNext(pos);
        pDownstream->Release();
    }
}

Allgemeine Graph-Building Techniken