다음을 통해 공유


필터 피어 찾기

[DirectShow 이 페이지와 연결된 기능은 레거시 기능입니다. MediaPlayer, IMFMediaEngine, Media Foundation 오디오/비디오 캡처대체되었습니다. 이러한 기능은 Windows 10 및 Windows 11에 최적화되었습니다. Microsoft는 가능하면 새로운 코드에서 MediaPlayer, IMFMediaEngineAudio/Video Capture를 DirectShow대신 Media Foundation 사용하는 것이 좋습니다. 가능한 경우 레거시 API를 사용하는 기존 코드를 다시 작성하여 새 API를 사용하도록 제안합니다.]

필터가 제공되면 연결된 필터를 찾아 그래프를 트래버스할 수 있습니다. 먼저 필터의 핀을 열거합니다. 각 핀에 대해 해당 핀이 다른 핀에 연결되어 있는지 확인합니다. 그렇다면 소유 필터에 대한 다른 핀을 쿼리합니다. 필터의 입력 핀을 열거하거나 출력 핀을 열거하여 다운스트림 방향으로 그래프를 걸을 수 있습니다.

다음 함수는 업스트림 또는 다운스트림에서 연결된 필터를 검색합니다. 찾은 첫 번째 일치 필터를 반환합니다.

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

이 함수는 IBaseFilter::EnumPins 호출하여 첫 번째 필터의 핀을 열거합니다. 각 핀에 대해 IPin::QueryDirection 호출하여 핀이 지정된 방향(입력 또는 출력)과 일치하는지 확인합니다. 이 경우 함수는 IPin::ConnectedTo 메서드를 호출하여 해당 핀이 다른 핀에 연결되어 있는지 여부를 결정합니다. 마지막으로 연결된 핀에서 IPin::QueryPinInfo 호출합니다. 이 메서드는 무엇보다도 해당 핀의 소유 필터에 대한 포인터를 포함하는 구조를 반환합니다. 이 포인터는 ppNext 매개 변수의 호출자에게 반환됩니다. 호출자는 포인터를 해제해야 합니다.

다음 코드는 이 함수를 호출하는 방법을 보여줍니다.

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

필터는 어느 방향으로든 둘 이상의 필터에 연결될 수 있습니다. 예를 들어 여러 필터를 다운스트림으로 사용하는 분할자 필터일 수 있습니다. 또는 여러 필터가 업스트림된 mux 필터일 수 있습니다. 따라서 모든 항목을 목록으로 수집할 수 있습니다.

다음 코드에서는 이러한 함수를 구현할 수 있는 한 가지 방법을 보여 주세요. DirectShow CGenericList 클래스를 사용합니다. 다른 데이터 구조를 사용하여 동등한 함수를 작성할 수 있습니다.

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

문제를 다소 복잡하게 만들기 위해 필터는 동일한 필터에 여러 핀 연결을 가질 수 있습니다. 목록에 중복 항목을 배치하지 않도록 하려면 각 IBaseFilter 포인터를 쿼리하여 IUnknown IUnknown 포인터를 비교합니다. COM 규칙에 따라 두 인터페이스 포인터는 동일한 IUnknown 포인터를 반환하는 경우에만 동일한 개체를 참조합니다. 이전 예제에서 AddFilterUnique 함수는 이 세부 정보를 처리합니다.

다음 예제에서는 GetPeerFilters 함수를 사용하는 방법을 보여 줍니다.

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

일반 Graph-Building 기술