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:
- 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.
- O filtro downstream chama IPin::QueryAccept no pino de saída upstream (consulte ilustração, etapa A).
- 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). - O filtro upstream chama GetBuffer para obter um novo exemplo (C) e IMediaSample::GetMediaType para obter o tipo de mídia (D).
- 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.
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);
}
}