Создание графов с помощью построителя графов захвата

[Функция, связанная с этой страницей DirectShow, является устаревшей функцией. Он был заменен MediaPlayer, IMFMediaEngine, и аудио/ видео захвата в Media Foundation. Эти функции оптимизированы для Windows 10 и Windows 11. Корпорация Майкрософт настоятельно рекомендует использовать в новом коде MediaPlayer, IMFMediaEngine и аудио/видеозахват в Media Foundation вместо DirectShow, когда это возможно. Корпорация Майкрософт предлагает переписать существующий код, в котором используются устаревшие API, чтобы по возможности использовать новые API.]

Несмотря на свое название, Конструктор графов захвата полезен для создания многих видов настраиваемых графов фильтров, а не только графов захвата. В этой статье представлен краткий обзор использования этого объекта.

Построитель графов захвата предоставляет интерфейс ICaptureGraphBuilder2 . Начните с вызова CoCreateInstance для создания построителя захвата графов и диспетчера фильтров графов. Затем инициализируйте построитель графов захвата, вызвав ICaptureGraphBuilder2::SetFiltergraph с указателем на диспетчер фильтров графов, как показано ниже.

IGraphBuilder *pGraph = NULL;
ICaptureGraphBuilder2 *pBuilder = NULL;

// Create the Filter Graph Manager.
HRESULT hr =  CoCreateInstance(CLSID_FilterGraph, NULL,
    CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph);

if (SUCCEEDED(hr))
{
    // Create the Capture Graph Builder.
    hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,
        CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, 
        (void **)&pBuilder);
    if (SUCCEEDED(hr))
    {
        pBuilder->SetFiltergraph(pGraph);
    }
};

Подключение фильтров

Метод ICaptureGraphBuilder2::RenderStream соединяет два или три фильтра в цепочку. Как правило, метод лучше всего работает, если каждый фильтр имеет не более одного входного или выходного контакта одного типа. Это обсуждение начинается с игнорирования первых двух параметров RenderStream и сосредоточения внимания на последних трех параметрах. Третий параметр — указатель IUnknown , который может указывать фильтр (в виде указателя интерфейса IBaseFilter ) или выходной контакт (в качестве указателя интерфейса IPin ). Четвертый и пятый параметры указывают указатели IBaseFilter . Метод RenderStream соединяет все три фильтра в цепочку. Например, предположим, что A, B и C являются фильтрами. Предположим, что на данный момент каждый фильтр имеет только один входной и выходной контакт. Следующий вызов подключает A к B, а затем B к C:

RenderStream(NULL, NULL, A, B, C)'

Все подключения являются "интеллектуальными", что означает, что дополнительные фильтры добавляются в граф по мере необходимости. Дополнительные сведения см. в разделе Intelligent Connect. Чтобы подключить только два фильтра, задайте для среднего значения значение NULL. Например, этот вызов подключает A к C:

RenderStream(NULL, NULL, A, NULL, C)'

Вы можете создать более длинные цепочки, дважды вызвав метод :

RenderStream(NULL, NULL, A, B, C)' 'RenderStream(NULL, NULL, C, D, E)'

Если последний параметр имеет значение NULL, метод автоматически находит отрисовщик по умолчанию. Он использует отрисовщик видео для видео и отрисовщик DirectSound для звука. Таким образом:

RenderStream(NULL, NULL, A, NULL, NULL)'

эквивалентно

RenderStream(NULL, NULL, A, NULL, R)'

где R — соответствующий отрисовщик. Однако для подключения фильтра отрисовщика для микширования видео вместо отрисовщика видео необходимо указать его явным образом.

Если в третьем параметре указан фильтр, а не pin, может потребоваться указать, какой выходной контакт следует использовать для подключения. Это назначение первых двух параметров метода. Первый параметр применяется только к фильтрам записи. Он задает GUID, указывающий категорию закреплений. Полный список категорий см. в разделе Набор свойств пин-кода. Для всех фильтров записи допустимы две категории:

  • PIN_CATEGORY_CAPTURE
  • PIN_CATEGORY_PREVIEW

Если фильтр отслеживания не предоставляет отдельные контакты для записи и предварительного просмотра, метод RenderStream вставляет фильтр Smart Tee , который разделяет поток на поток захвата и поток предварительного просмотра. С точки зрения приложения можно просто рассматривать все фильтры записи как имеющие отдельные контакты и игнорировать базовую топологию графа.

Для записи файлов подключите контакт записи к фильтру мультиплексии. Для динамического предварительного просмотра подключите контакт предварительного просмотра к отрисовщику. Если вы переключите две категории, граф может удалить чрезмерное количество кадров во время записи файла; но если граф подключен правильно, он удаляет кадры предварительного просмотра по мере необходимости, чтобы сохранить пропускную способность в потоке захвата.

В следующем примере показано, как подключить оба потока:

// Capture to file:
pBuilder->RenderStream(&PIN_CATEGORY_CAPTURE, NULL, pCapFilter, NULL, pMux);
// Preview:
pBuilder->RenderStream(&PIN_CATEGORY_PREVIEW, NULL, pCapFilter, NULL, NULL);

Некоторые фильтры записи также поддерживают скрытые субтитры, обозначаемые PIN_CATEGORY_VBI. Чтобы записать скрытые субтитры в файл, отрисуйте эту категорию в фильтре мультиплекса. Чтобы просмотреть скрытые субтитры в окне предварительного просмотра, подключитесь к отрисовщику:

// Capture to file:
pBuilder->RenderStream(&PIN_CATEGORY_VBI, NULL, pCapFilter, NULL, pMux);
// Preview on screen:
pBuilder->RenderStream(&PIN_CATEGORY_VBI, NULL, pCapFilter, NULL, NULL);

Второй параметр RenderStream определяет тип носителя и обычно имеет один из следующих значений:

  • MEDIATYPE_Audio
  • MEDIATYPE_Video
  • MEDIATYPE_Interleaved (DV)

Этот параметр можно использовать всякий раз, когда выходные контакты фильтра поддерживают перечисление предпочтительных типов мультимедиа. Для источников файлов построитель графов записи автоматически добавляет фильтр синтаксического анализа, если это необходимо, а затем запрашивает типы мультимедиа в средстве синтаксического анализа. (Пример см. в разделе Recompressing a AVI File.) Кроме того, если последний фильтр в цепочке содержит несколько входных контактов, метод пытается перечислить их типы мультимедиа. Однако не все фильтры поддерживают эту функцию.

Поиск интерфейсов в фильтрах и контактах

После построения графа обычно требуется найти в графе различные интерфейсы, предоставляемые фильтрами и контактами. Например, фильтр записи может предоставлять интерфейс IAMDroppedFrames , а выходные контакты фильтра — интерфейс IAMStreamConfig .

Самый простой способ найти интерфейс — использовать метод ICaptureGraphBuilder2::FindInterface . Этот метод выполняет обход графа (фильтрацию и закрепление), пока не будет обнаружен нужный интерфейс. Вы можете указать начальную точку для поиска и ограничить поиск фильтрами вышестоящий или ниже, начиная с начальной точки.

В следующем примере выполняется поиск интерфейса IAMStreamConfig на пин-коде предварительного просмотра видео:

IAMStreamConfig *pConfig = NULL;
HRESULT hr = pBuild->FindInterface(
    &PIN_CATEGORY_PREVIEW, 
    &MEDIATYPE_Video,
    pVCap, 
    IID_IAMStreamConfig, 
    (void**)&pConfig
);
if (SUCCESSFUL(hr))
{
    /* ... */
    pConfig->Release();
}

Примечание

В статье Поиск интерфейса для фильтра или закрепления показан альтернативный подход, в котором вместо ICaptureGraphBuilder2 используется интерфейс IGraphBuilder. Используемый подход зависит от приложения. Если приложение уже использует ICaptureGraphBuilder2 для построения графа, рекомендуется использовать ICaptureGraphBuilder2::FindInterface . В противном случае рекомендуется использовать методы IGraphBuilder .

 

Поиск контактов

Реже может потребоваться найти отдельный закрепление на фильтре, хотя в большинстве случаев методы RenderStream и FindInterface избавят вас от проблем. Если вам нужно найти определенный контакт на фильтре, полезен вспомогательный метод ICaptureGraphBuilder2::FindPin . Укажите категорию, тип мультимедиа (видео или аудио), направление и необходимость разъединения контакта.

Например, следующий код выполняет поиск несоединенного контакта предварительного просмотра видео в фильтре захвата:

IPin *pPin = NULL;
hr = pBuild->FindPin(
    pCap,                   // Pointer to the filter to search.
    PINDIR_OUTPUT,          // Search for an output pin.
    &PIN_CATEGORY_PREVIEW,  // Search for a preview pin.
    &MEDIATYPE_Video,       // Search for a video pin.
    TRUE,                   // The pin must be unconnected. 
    0,                      // Return the first matching pin (index 0).
    &pPin);                 // This variable receives the IPin pointer.
if (SUCCESSFUL(hr))
{
    /* ... */
    pPin->Release();
}

Захват видео