Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
[Функция, связанная с этой страницей, DirectShow, является устаревшей функцией. Он был заменен MediaPlayer, IMFMediaEngineи аудио и видеозахват в Media Foundation. Эти функции оптимизированы для Windows 10 и Windows 11. Корпорация Майкрософт настоятельно рекомендует использовать новый код MediaPlayer, IMFMediaEngine и аудио-видеозахват в Media Foundation вместо DirectShowпо возможности. Корпорация Майкрософт предлагает, что существующий код, использующий устаревшие 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);
}
Чтобы несколько усложнить ситуацию, фильтр может иметь несколько подключений к одному фильтру. Чтобы избежать дублирования в список, запросите каждый указателя 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();
}
}
Связанные разделы