Filtros de driver de classe WDM

[O recurso associado a esta página, DirectShow, é um recurso herdado. Foi substituído por MediaPlayer, IMFMediaEngine e Audio/Video Capture in 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 Audio/Video Capture in 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.]

Se um dispositivo de captura usar um driver WDM (Modelo de Driver do Windows), o grafo poderá exigir determinados filtros upstream do filtro de captura. Esses filtros são chamados de filtros de driver de classe de fluxo ou filtros WDM. Eles dão suporte a funcionalidades adicionais fornecidas pelo hardware. Por exemplo, um sintonizador de TV cartão tem funções para definir o canal. O filtro correspondente é o filtro sintonizador de TV , que expõe a interface IAMTVTuner . Para disponibilizar essa funcionalidade para o aplicativo, você deve conectar o filtro sintonizador de TV ao filtro de captura.

A interface ICaptureGraphBuilder2 fornece a maneira mais fácil de adicionar filtros WDM ao grafo. Em algum momento durante a criação do grafo, chame FindInterface ou RenderStream. Qualquer um desses métodos localizará automaticamente os filtros WDM necessários e os conectará ao filtro de captura. O restante desta seção descreve como adicionar filtros WDM manualmente. No entanto, lembre-se de que a abordagem recomendada é simplesmente chamar um desses métodos ICaptureGraphBuilder2 .

Os pinos em um filtro WDM dão suporte a um ou mais meios. Um meio define um método de comunicação, como um ônibus. Você deve conectar pinos que dão suporte ao mesmo meio. A estrutura REGPINMEDIUM , que é equivalente à estrutura KSPIN_MEDIUM usada para drivers de streaming de kernel, define um meio no DirectShow. O membro clsMedium da estrutura REGPINMEDIUM especifica o CLSID (identificador de classe) para o meio. Para recuperar o meio de um pino, chame o método IKsPin::KsQueryMediums . Esse método retorna um ponteiro para um bloco de memória que contém uma estrutura KSMULTIPLE_ITEM , seguido por zero ou mais estruturas REGPINMEDIUM . Cada estrutura REGPINMEDIUM identifica um meio compatível com o pino.

Não conecte um pino se o meio tiver um CLSID de GUID_NULL ou KSMEDIUMSETID_Standard. Esses são valores padrão que indicam que o pino não dá suporte a meios.

Além disso, não conecte um pino, a menos que o filtro exija exatamente uma instância conectada desse pino. Caso contrário, seu aplicativo pode tentar conectar vários pinos que não devem ter conexões, o que pode fazer com que o programa pare de responder. Para descobrir o número de instâncias necessárias, recupere o conjunto de propriedades KSPROPERTY_PIN_NECESSARYINSTANCES, conforme mostrado no exemplo de código a seguir. (Para fins de brevidade, este exemplo não testa nenhum código de retorno ou libera nenhuma interface. Seu aplicativo deve fazer as duas coisas, é claro.)

// Obtain the pin factory identifier.
IKsPinFactory *pPinFactory;
hr = pPin->QueryInterface(IID_IKsPinFactory, (void **)&pPinFactory);

ULONG ulFactoryId;
hr = pPinFactory->KsPinFactory(&ulFactoryId);

// Get the "instance" property from the filter.
IKsControl *pKsControl;
hr = pFilter->QueryInterface(IID_IKsControl, (void **)&pKsControl);

KSP_PIN ksPin;
ksPin.Property.Set = KSPROPSETID_Pin;
ksPin.Property.Id = KSPROPERTY_PIN_NECESSARYINSTANCES;
ksPin.Property.Flags = KSPROPERTY_TYPE_GET;
ksPin.PinId = ulFactoryId;
ksPin.Reserved = 0; 

KSPROPERTY ksProp;
ULONG ulInstances, bytes;
pKsControl->KsProperty((PKSPROPERTY)&ksPin, sizeof(ksPin), 
    &ulInstances, sizeof(ULONG), &bytes);

if (hr == S_OK && bytes == sizeof(ULONG)) 
{
    if (ulInstances == 1) 
    {
        // Filter requires one instance of this pin.
        // This pin is OK.
    } 
}

O pseudocódigo a seguir é uma estrutura de tópicos extremamente breve mostrando como localizar e conectar os filtros do WDM. Ele omite muitos detalhes e destina-se apenas a mostrar as etapas gerais que seu aplicativo precisaria executar.

Add supporting filters:
{
    foreach input pin:
        skip if (pin is connected)
    
        Get pin medium
        skip if (medium is GUID_NULL or KSMEDIUMSETID_Standard)
    
        Query filter for KSPROPERTY_PIN_NECESSARYINSTANCES property
        skip if (necessary instances != 1)

        Match an existing pin || Find a matching filter
}    

Match an existing pin:
{
    foreach filter in the graph
        foreach unconnected pin
            Get pin medium
            if (mediums match)
                connect the pins    
}

Find a matching filter:
{    
    Query the filter graph manager for IFilterMapper2.
    Find a filter with an output pin that matches the medium.
    Add the filter to the graph.
    Connect the pins.
    Add supporting filters. (Recursive call.)
}

Tópicos avançados de captura