查找筛选器对等
[与此页面关联的功能 DirectShow 是旧版功能。 它已被 MediaPlayer、 IMFMediaEngine 和 Media Foundation 中的音频/视频捕获所取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能在 Media Foundation 中使用 MediaPlayer、 IMFMediaEngine 和 音频/视频捕获 ,而不是 DirectShow。 如果可能,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();
}
筛选器可以在任一方向连接到两个或更多个筛选器。 例如,它可能是一个拆分器筛选器,其下游有多个筛选器。 或者,它可能是复用筛选器,其中上游多个筛选器。 因此,你可能希望将它们全部收集到一个列表中。
以下代码演示了实现此类函数的一种可能方法。 它使用 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 的规则,两个接口指针仅当且仅当它们返回相同的 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();
}
}
相关主题