フィルター ピアを検索する
[このページに関連付けられている機能 DirectShow は、従来の機能です。 MediaPlayer、IMFMediaEngine、および Media Foundation のオーディオ/ビデオ キャプチャに置き換わりました。 これらの機能は、Windows 10とWindows 11用に最適化されています。 新しいコードでは、可能であれば、DirectShow ではなく Media Foundation で MediaPlayer、IMFMediaEngine、Audio/Video Capture を使用することを強くお勧めします。 Microsoft は、従来の 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();
}
フィルターは、どちらの方向でも 2 つ以上のフィルターに接続されている場合があります。 たとえば、スプリッター フィルターであり、そこからいくつかのフィルターがダウンストリームに配置されている場合があります。 または、複数のフィルターが上流にある多重化フィルターである場合もあります。 したがって、それらのすべてを一覧に収集する必要がある場合があります。
次のコードは、このような関数を実装する方法の 1 つを示しています。 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);
}
問題を複雑にするために、フィルターは同じフィルターに複数のピン接続を持つことができます。 重複がリストに含まれないようにするには、IUnknown の各 IBaseFilter ポインターに対してクエリを実行し、IUnknown ポインターを比較します。 COM の規則により、2 つのインターフェイス ポインターは、同じ 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();
}
}
関連トピック