Criando grafos com o Construtor de Grafos de Captura

[O recurso associado a esta página, DirectShow, é um recurso herdado. Ele foi substituído por MediaPlayer, IMFMediaEngine e Captura de Áudio/Vídeo na Media Foundation. Esses recursos foram otimizados para Windows 10 e Windows 11. A Microsoft recomenda fortemente que o novo código use MediaPlayer, IMFMediaEngine e Captura de Áudio/Vídeo no Media Foundation em vez de DirectShow, quando possível. A Microsoft sugere que o código existente que usa as APIs herdadas seja reescrito para usar as novas APIs, se possível.]

Apesar de seu nome, o Capture Graph Builder é útil para criar muitos tipos de grafos de filtro personalizados, não apenas capturar grafos. Este artigo fornece uma breve visão geral de como usar esse objeto.

O Capture Graph Builder expõe a interface ICaptureGraphBuilder2 . Comece chamando CoCreateInstance para criar o Capture Graph Builder e o Filter Graph Manager. Em seguida, inicialize o Construtor de Grafo de Captura chamando ICaptureGraphBuilder2::SetFiltergraph com um ponteiro para o Gerenciador de Grafo de Filtro, da seguinte maneira:

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);
    }
};

Conectando filtros

O método ICaptureGraphBuilder2::RenderStream conecta dois ou três filtros em uma cadeia. Geralmente, o método funciona melhor quando cada filtro não tem mais de um pino de entrada ou pino de saída do mesmo tipo. Essa discussão começa ignorando os dois primeiros parâmetros do RenderStream e focando nos últimos três parâmetros. O terceiro parâmetro é um ponteiro IUnknown , que pode especificar um filtro (como um ponteiro de interface IBaseFilter ) ou um pino de saída (como um ponteiro de interface IPin ). O quarto e o quinto parâmetros especificam ponteiros IBaseFilter . O método RenderStream conecta todos os três filtros em uma cadeia. Por exemplo, suponha que A, B e C sejam filtros. Suponha, por enquanto, que cada filtro tenha exatamente um pino de entrada e um pino de saída. A chamada a seguir conecta A a B e, em seguida, B a C:

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

Todas as conexões são "inteligentes", o que significa que filtros adicionais são adicionados ao grafo conforme necessário. Para obter detalhes, confira Conexão Inteligente. Para conectar apenas dois filtros, defina o valor do meio como NULL. Por exemplo, essa chamada conecta A a C:

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

Você pode criar cadeias mais longas chamando o método duas vezes:

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

Se o último parâmetro for NULL, o método localizará automaticamente um renderizador padrão. Ele usa o Renderizador de Vídeo para vídeo e o Renderizador DirectSound para áudio. Assim:

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

é equivalente a

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

em que R é o renderizador apropriado. Para conectar o filtro Renderizador de Combinação de Vídeo em vez do Renderizador de Vídeo, no entanto, você deve especificá-lo explicitamente.

Se você especificar um filtro no terceiro parâmetro, em vez de um pino, talvez seja necessário indicar qual pino de saída deve ser usado para a conexão. Essa é a finalidade dos dois primeiros parâmetros do método. O primeiro parâmetro se aplica somente aos filtros de captura. Ele especifica um GUID que indica uma categoria de pino. Para obter uma lista completa de categorias, consulte Fixar Conjunto de Propriedades. Duas das categorias são válidas para todos os filtros de captura:

  • PIN_CATEGORY_CAPTURE
  • PIN_CATEGORY_PREVIEW

Se um filtro de captura não fornecer pinos separados para captura e visualização, o método RenderStream inserirá um filtro Smart Tee , que divide o fluxo em um fluxo de captura e em um fluxo de visualização. Do ponto de vista do aplicativo, você pode simplesmente tratar todos os filtros de captura como tendo pinos separados e ignorar a topologia subjacente do grafo.

Para captura de arquivo, conecte o pino de captura a um filtro mux. Para visualização ao vivo, conecte o pino de visualização a um renderizador. Se você alternar as duas categorias, o grafo poderá descartar um número excessivo de quadros durante a captura de arquivo; mas, se o grafo estiver conectado corretamente, ele removerá os quadros de visualização conforme necessário para manter a taxa de transferência no fluxo de captura.

O exemplo a seguir mostra como conectar os dois fluxos:

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

Alguns filtros de captura também dão suporte a legendas fechadas, indicadas por PIN_CATEGORY_VBI. Para capturar as legendas fechadas em um arquivo, renderize essa categoria para o filtro mux. Para exibir as legendas fechadas na janela de visualização, conecte-se ao renderizador:

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

O segundo parâmetro para RenderStream identifica o tipo de mídia e normalmente é um dos seguintes:

  • Mediatype_audio
  • MEDIATYPE_Video
  • MEDIATYPE_Interleaved (DV)

Você pode usar esse parâmetro sempre que os pinos de saída do filtro derem suporte à enumeração de tipos de mídia preferenciais. Para fontes de arquivo, o Capture Graph Builder adiciona automaticamente um filtro de analisador, se necessário, e consulta os tipos de mídia no analisador. (Para obter um exemplo, consulte Recompactando um arquivo AVI.) Além disso, se o último filtro na cadeia tiver vários pinos de entrada, o método tentará enumerar seus tipos de mídia. No entanto, nem todos os filtros dão suporte a essa funcionalidade.

Localizando interfaces em filtros e pinos

Depois de criar um grafo, você normalmente precisará localizar várias interfaces expostas por filtros e pinos no grafo. Por exemplo, um filtro de captura pode expor a interface IAMDroppedFrames , enquanto os pinos de saída do filtro podem expor a interface IAMStreamConfig .

A maneira mais simples de encontrar uma interface é usar o método ICaptureGraphBuilder2::FindInterface . Esse método orienta o grafo (filtros e pinos) até localizar a interface desejada. Você pode especificar o ponto de partida para a pesquisa e pode limitar a pesquisa a filtros upstream ou downstream do ponto de partida.

O exemplo a seguir pesquisa a interface IAMStreamConfig em um pin de visualização de vídeo:

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

Observação

O tópico Localizar uma interface em um filtro ou pin mostra uma abordagem alternativa que usa a interface IGraphBuilder em vez de ICaptureGraphBuilder2. Qual abordagem usar depende do aplicativo. Se seu aplicativo já usa ICaptureGraphBuilder2 para criar o grafo, ICaptureGraphBuilder2::FindInterface é uma boa abordagem. Caso contrário, considere usar os métodos IGraphBuilder .

 

Localizando pinos

Com menos frequência, talvez seja necessário localizar um pino individual em um filtro, embora, na maioria dos casos, os métodos RenderStream e FindInterface salvem o problema. Se você precisar encontrar um determinado pino em um filtro, o método auxiliar ICaptureGraphBuilder2::FindPin será útil. Especifique a categoria, o tipo de mídia (vídeo ou áudio), a direção e se o pino deve ser desconectado.

Por exemplo, o código a seguir pesquisa um pin de visualização de vídeo não conectado em um filtro de captura:

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();
}

Captura de vídeo