Partilhar via


QueryAccept (Upstream)

[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.]

Esse mecanismo permite que um pino de entrada proponha uma alteração de formato para seu par upstream. O filtro downstream deve anexar um tipo de mídia ao exemplo que o filtro upstream obterá em sua próxima chamada para IMemAllocator::GetBuffer. No entanto, para fazer isso, o filtro downstream deve fornecer um alocador personalizado para a conexão. Esse alocador deve implementar um método privado que o filtro downstream pode usar para definir o tipo de mídia no próximo exemplo.

As seguintes etapas ocorrem:

  1. O filtro downstream verifica se a conexão de pino usa o alocador personalizado do filtro. Se o filtro upstream possuir o alocador, o filtro downstream não poderá alterar o formato.
  2. O filtro downstream chama IPin::QueryAccept no pino de saída upstream (consulte ilustração, etapa A).
  3. Se QueryAccept retornar S_OK, o filtro downstream chamará o método privado em seu alocador para definir o tipo de mídia. Dentro desse método privado, o alocador chama IMediaSample::SetMediaType no próximo exemplo disponível (B).
  4. O filtro upstream chama GetBuffer para obter um novo exemplo (C) e IMediaSample::GetMediaType para obter o tipo de mídia (D).
  5. Quando o filtro upstream entregar o exemplo, ele deverá deixar o tipo de mídia anexado a esse exemplo. Dessa forma, o filtro downstream pode confirmar se o tipo de mídia foi alterado (E).

Se o filtro upstream aceitar a alteração de formato, ele também deverá ser capaz de voltar para o tipo de mídia original, conforme mostrado no diagrama a seguir.

queryaccept (upstream)

Os exemplos main desse tipo de alteração de formato envolvem os renderizadores de vídeo directShow.

  • O filtro original do Renderizador de Vídeo pode alternar entre os tipos RGB e YUV durante o streaming. Quando o filtro se conecta, ele requer um formato RGB que corresponda às configurações de exibição atuais. Isso garante que ele possa fazer fallback no GDI, se necessário. Após o início do streaming, se o DirectDraw estiver disponível, o Renderizador de Vídeo solicitará uma alteração de formato para um tipo YUV. Posteriormente, ele poderá voltar para RGB se perder a superfície do DirectDraw por qualquer motivo.
  • O filtro VMR (Renderizador de Combinação de Vídeo) mais recente se conectará a qualquer formato compatível com o hardware gráfico, incluindo tipos YUV. No entanto, o hardware gráfico pode alterar o passo da superfície subjacente do DirectDraw para otimizar o desempenho. O filtro VMR usa QueryAccept para relatar o novo passo, que é especificado no membro biWidth da estrutura BITMAPINFOHEADER . Os retângulos de origem e destino na estrutura VIDEOINFOHEADER ou VIDEOINFOHEADER2 identificam a região em que o vídeo deve ser decodificado.

Nota de implementação

É improvável que você escreva um filtro que precise solicitar upstream alterações de formato, pois esse é principalmente um recurso de renderizadores de vídeo. No entanto, se você escrever um filtro de transformação de vídeo ou um decodificador de vídeo, o filtro deverá responder corretamente às solicitações do renderizador de vídeo.

Um filtro trans-in-loco que fica entre o renderizador de vídeo e o decodificador deve passar todas as QueryAccept chamadas upstream. Armazene as novas informações de formato quando elas chegarem.

Um filtro de transformação de cópia (ou seja, um filtro não trans-in-loco) deve implementar um dos seguintes comportamentos:

  • Passe as alterações de formato upstream e armazene as novas informações de formato quando elas chegarem. O filtro deve usar um alocador personalizado para que ele possa anexar o formato ao exemplo de upstream.
  • Execute a conversão de formato dentro do filtro. Isso provavelmente é mais fácil do que passar a alteração de formato upstream. No entanto, pode ser menos eficiente do que deixar o filtro de decodificador decodificar no formato correto.
  • Como último recurso, basta rejeitar a alteração de formato. (Para obter mais informações, consulte o código-fonte do método CTransInPlaceOutputPin::CheckMediaType na biblioteca de classes base do DirectShow.) Rejeitar uma alteração de formato pode reduzir o desempenho, no entanto, porque impede que o renderizador de vídeo use o formato mais eficiente.

O pseudocódigo a seguir mostra como você pode implementar um filtro de transformação de cópia (derivado de CTransformFilter) que pode alternar entre tipos de saída YUV e RGB. Este exemplo pressupõe que o filtro faça a conversão em si, em vez de passar a alteração de formato upstream.

HRESULT CMyTransform::CheckInputType(const CMediaType *pmt)
{
    if (pmt is a YUV type that you support) {
        return S_OK;
    }
    else {
        return VFW_E_TYPE_NOT_ACCEPTED;
    }
}

HRESULT CMyTransform::CheckTransform(
    const CMediaType *mtIn, const CMediaType *mtOut)
{
    if (mtOut is a YUV or RGB type that you support)
    {
        if ((mtIn has the same video dimensions as mtOut) &&
            (you support the mtIn-to-mtOut transform))
        {
            return S_OK;
        }
    }
    // otherwise
    return VFW_E_TYPE_NOT_ACCEPTED;
}

// GetMediaType: Return a preferred output type.
HRESULT CMyTransform::GetMediaType(int iPosition, CMediaType *pMediaType)
{
    if (iPosition < 0) {
        return E_INVALIDARG;
    }
    switch (iPosition)
    {
    case 0:
        Copy the input type (YUV) to pMediaType
        return S_OK;
    case 1:
        Construct an RGB type that matches the input type.
        return S_OK;
    default:
        return VFW_S_NO_MORE_ITEMS;
    }
}

// SetMediaType: Override from CTransformFilter. 
HRESULT CMyTransform::SetMediaType(
    PIN_DIRECTION direction, const CMediaType *pmt)
{
    // Capture this information...
    if (direction == PINDIR_OUTPUT)
    {
       m_bYuv = (pmt->subtype == MEDIASUBTYPE_UYVY);
    }
    return S_OK;
}

HRESULT CMyTransform::Transform(
    IMediaSample *pSource, IMediaSample *pDest)
{
    // Look for format changes from downstream.
    CMediaType *pMT = NULL;
    HRESULT hr = pDest->GetMediaType((AM_MEDIA_TYPE**)&pMT);
    if (hr == S_OK)
    {
        hr = m_pOutput->CheckMediaType(pMT);
        if(FAILED(hr))
        {
            DeleteMediaType(pMT);
            return E_FAIL;
        }
        // Notify our own output pin about the new type.
        m_pOutput->SetMediaType(pMT);
        DeleteMediaType(pMT);
    }
    // Process the buffers
    if (m_bYuv) {
        return ProcessFrameYUV(pSource, pDest);
    }
    else {
        return ProcessFrameRGB(pSource, pDest);
    }
}