필터 피어 찾기
[DirectShow 이 페이지와 연결된 기능은 레거시 기능입니다. MediaPlayer, IMFMediaEngine, Media Foundation 오디오/비디오 캡처대체되었습니다. 이러한 기능은 Windows 10 및 Windows 11에 최적화되었습니다. Microsoft는 가능하면 새로운 코드에서 MediaPlayer, IMFMediaEngine 및 Audio/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();
}
}
관련 항목