Suporte à decodificação de vídeo Direct3D 11 no Media Foundation
Este tópico descreve como dar suporte ao Microsoft Direct3D 11 em um decodificador do Microsoft Media Foundation. Especificamente, descreve a comunicação entre o decodificador e o renderizador de vídeo. Este tópico não descreve como implementar as operações de decodificação.
- Visão geral
- Abrir um identificador de dispositivo
- Localizar uma configuração de decodificador
- Fallback para decodificação por software
- Alocar buffers descompactados
- Decodificação
- Tópicos relacionados
Visão geral
No restante deste tópico, os seguintes termos são usados:
- Software decodificador. O software decodificador é a MFT (transformação do Media Foundation) que recebe amostras de vídeos compactados e gera quadros de vídeo descompactados.
- Dispositivo decodificador. O dispositivo decodificador é o acelerador de vídeo e é implementado pelo driver gráfico. Ele é responsável por realizar operações de decodificação aceleradas.
- Pipeline. O pipeline hospeda o software decodificador e fornece buffers do e para o software decodificador. Dependendo do aplicativo, o pipeline pode ser a Sessão de Mídia, o Leitor de Origem ou o código do aplicativo que chama diretamente a MFT.
Para realizar a decodificação usando o Direct3D 11, é essencial que o decodificador por software tenha um ponteiro para um dispositivo Direct3D 11. O dispositivo Direct3D 11 é criado externamente ao software decodificador. Em um cenário de Sessão de Mídia, o renderizador de vídeo cria o dispositivo Direct3D 11. Em um cenário de Leitor de Origem, normalmente o aplicativo cria o dispositivo Direct3D 11.
O Gerenciador de Dispositivos DXGI é usado para compartilhar o Direct3D 11 entre os componentes. O Gerenciador de Dispositivos expõe a interface IMFDXGIDeviceManager. O pipeline define o ponteiro IMFDXGIDeviceManager no software decodificador enviando a mensagem MFT_MESSAGE_SET_D3D_MANAGER.
O diagrama a seguir ilustra a relação entre o software decodificador, o Direct3D 11 e o pipeline.
Estas são as etapas básicas que um software decodificador deve realizar para dar suporte ao Direct3D 11 no Media Foundation:
- Abrir um identificador para o dispositivo Direct3D 11.
- Encontrar uma configuração de decodificador.
- Alocar buffers descompactados.
- Decodificar quadros.
Essas etapas são descritas com mais detalhes no restante deste tópico.
Abrir um identificador de dispositivo
O decodificador MFT usa o gerenciador de dispositivos DXGI para obter um identificador para o dispositivo Direct3D 11. Para abrir o identificador do dispositivo, siga as etapas a seguir:
- O decodificador MFT deve expor o atributo MF_SA_D3D11_AWARE com o valor TRUE.
- O Carregador de Topologia consulta esse atributo chamando IMFTransform::GetAttributes. O valor TRUE indica que a MFT dá suporte ao Direct3D 11.
- O Carregador de Topologia chama IMFTransform::ProcessMessage com a mensagem MFT_MESSAGE_SET_D3D_MANAGER. O parâmetro ulParam é um ponteiro IUnknown para o gerenciador de dispositivos DXGI. Consulte este ponteiro para a interface ponteiro IMFDXGIDeviceManager.
- Chame IMFDXGIDeviceManager::OpenDeviceHandle para obter um identificador para o dispositivo Direct3D 11.
- Para obter um ponteiro para o dispositivo Direct3D 11, chame IMFDXGIDeviceManager::GetVideoService. Passe o identificador do dispositivo e o valor IID_ID3D11Device. O método retorna um ponteiro para a interface ID3D11Device.
- Para obter um ponteiro para o acelerador de vídeo, chame IMFDXGIDeviceManager::GetVideoService novamente. Desta vez, passe o identificador de dispositivo e o valor IID_ID3D11VideoDevice. O método retorna um ponteiro para a interface ID3D11VideoDevice.
- Chame ID3D11Device::GetImmediateContext para obter um ponteiro ID3D11DeviceContext.
- Chame QueryInterface no ID3D11DeviceContext para obter um ponteiro ID3D11VideoContext.
- É recomendável que você use a proteção multithread no contexto do dispositivo para evitar problemas de deadlock que às vezes podem acontecer ao chamar ID3D11VideoContext::GetDecoderBuffer ou ID3D11VideoContext::ReleaseDecoderBuffer. Para definir a proteção multithread, primeiro chame QueryInterface no ID3D11Device para obter um ponteiro ID3D10Multithread. Em seguida, chame ID3D10Multithread::SetMultithreadProtected, passandotrue para bMTProtect.
Encontrar uma configuração de decodificador
Para realizar uma decodificação, o software decodificador deve encontrar uma configuração compatível com o dispositivo decodificador, incluindo um formato de destino de renderização. Essa etapa ocorre dentro do método IMFTransform::SetInputType, da seguinte maneira.
- Valide o tipo de mídia de entrada. Se o tipo for rejeitado,pule as etapas restantes e retorne um código de erro.
- Chame ID3D11VideoDevice::GetVideoDecoderProfileCount para obter o número de perfis com suporte.
- Chame ID3D11VideoDevice::GetVideoDecoderProfile para enumerar os perfis e obter os GUIDs dos perfis.
- Procure por um GUID de perfil que corresponda ao formato de vídeo e aos recursos do software decodificador. Por exemplo, um decodificador MPEG-2 procuraria D3D11_DECODER_PROFILE_MPEG2_MOCOMP,D3D11_DECODER_PROFILE_MPEG2_IDCT e D3D11_DECODER_PROFILE_MPEG2_VLD.
- Se encontrar um GUID de decodificador adequado, verifique o formato de saída chamando o método ID3D11VideoDevice::CheckVideoDecoderFormat. Passe o GUID do decodificador e um valor DXGI_FORMAT que especifique o formato de destino de renderização.
- Em seguida, encontre uma configuração adequada para o decodificador.
- Chame ID3D11VideoDevice::GetVideoDecoderConfigCount para obter o número de configurações do decodificador. Passe o mesmo GUID do dispositivo decodificador, juntamente com uma estrutura D3D11_VIDEO_DECODER_DESC que descreve o formato de destino de renderização proposto.
- Chame ID3D11VideoDevice::GetVideoDecoderConfig para enumerar as configurações do decodificador.
No método IMFTransform::GetOutputAvailableType, retorne um formato de vídeo descompactado com base no formato de destino de renderização proposto.
No método IMFTransform::SetOutputType, verifique o tipo de mídia no formato de destino de renderização.
Fallback para decodificação por software
Talvez a MFT consiga localizar uma configuração. Por exemplo, pode ser que o driver gráfico não seja compatível com os recursos corretos. Nesse caso, a MFT deve voltar à decodificação por software, da seguinte maneira.
- Os métodos SetInputType e SetOutputType devem retornar MF_E_UNSUPPORTED_D3D_TYPE.
- Em resposta, o Carregador de Topologia enviará a mensagem MFT_MESSAGE_SET_D3D_MANAGER com o valor NULL para o parâmetro ulParam.
- A MFT libera o ponteiro para a interface IMFDXGIDeviceManager.
- O Carregador de Topologia renegocia o tipo de mídia.
Neste ponto, a MFT pode usar a decodificação por software.
Alocar buffers descompactados
O decodificador é responsável por alocar texturas do Direct3D 11 para usar como buffers de vídeo descompactados. O atributo MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT nos atributos do fluxo de saída (confiraIMFTransform::GetOutputStreamAttributes) é usado para determinar quantas superfícies o decodificador deve alocar para o renderizador de vídeo usar a fim de realizar o desentrelaçamento. Um decodificador deve usar esse valor limitando-o para alguns limites superiores e inferiores razoáveis, por exemplo, 3–32. Para obter conteúdo progressivo, veja MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT_PROGRESSIVE.
No método IMFTransform::GetOutputStreamInfo , defina o sinalizador MFT_OUTPUT_STREAM_PROVIDES_SAMPLES na estrutura MFT_OUTPUT_STREAM_INFO. Esse sinalizador notifica a Sessão de Mídia de que a MFT aloca suas próprias amostras de saída. Para alocar as amostras de saída, a MFT executa as seguintes etapas:
Crie uma matriz de texturas 2D chamando ID3D11Device::CreateTexture2D. Na estrutura D3D11_TEXTURE2D_DESC , defina ArraySize igual ao número de superfícies que o decodificador precisa. Isso inclui:
- Superfícies para quadros de referência.
- Superfícies para desentrelaçamento (três superfícies).
- Superfícies que o decodificador precisa para armazenar em buffer.
Os sinalizadores de associação (BindFlags) devem incluir o sinalizador D3D11_BIND_DECODER e todos os sinalizadores de associação definidos por meio do atributo MF_SA_D3D11_BINDFLAGS nos atributos do fluxo de saída.
Para cada superfície na matriz de texturas, chame ID3D11VideoDevice::CreateVideoDecoderOutputView para criar uma visualização de saída do decodificador de vídeo. Durante a decodificação, essas visualizações de saída serão passadas para o método ID3D11VideoContext::DecoderBeginFrame.
Para cada superfície na matriz de texturas, crie uma amostra de mídia da seguinte maneira:
- Crie um buffer de mídia DXGI chamando a função MFCreateDXGISurfaceBuffer. Passe o ponteiro ID3D11Texture2D e o deslocamento para cada elemento na matriz de texturas. A função retorna um ponteiro IMFMediaBuffer.
- Crie uma amostra de mídia vazia chamando a função MFCreateVideoSampleFromSurface. Defina o parâmetro pUnkSurface como NULL. A função retorna um ponteiro IMFSample.
- Chame IMFSample::AddBuffer para adicionar o buffer de mídia à amostra.
Você deve destruir todas as texturas criadas ao mesmo tempo, em vez de destruir apenas algumas e continuar usando o restante.
Decodificação
Para criar o dispositivo decodificador, chame ID3D11VideoDevice::CreateVideoDecoder. O método retorna um ponteiro para a interface ID3D11VideoDecoder. A decodificação deve ocorrer dentro do método IMFTransform::ProcessOutput. Em cada quadro, chame IMFDXGIDeviceManager::TestDevice para testar a disponibilidade do DXGI. Se o dispositivo foi alterado, o software decodificador deverá recriar o dispositivo decodificador, da seguinte maneira:
- Feche o identificador do dispositivo chamando IMFDXGIDeviceManager::CloseDeviceHandle.
- Libere todos os recursos associados ao dispositivo Direct3D 11 anterior, incluindo as interfaces ID3D11VideoDecoder, ID3D11VideoContext,ID3D11Texture2D e ID3D11VideoDecoderOutputView.
- Abra um novo identificador de dispositivo.
- Negocie uma nova configuração de decodificador, conforme descrito anteriormente em Localizar uma Configuração do Decodificador. Essa etapa é necessária porque os recursos do dispositivo podem ter sido alterados.
- Crie um novo dispositivo decodificador.
Supondo que o identificador do dispositivo seja válido, o processo de decodificação funciona da seguinte maneira:
- Obtenha uma superfície disponível que não esteja em uso no momento. Inicialmente, todas as superfícies estão disponíveis.
- Consulte a amostra de mídia para a interface IMFTrackedSample.
- Chame IMFTrackedSample::SetAllocatore forneça um ponteiro para a interface IMFAsyncCallback. (O software decodificador deve implementar essa interface). Quando o renderizador de vídeo liberar a amostra, o retorno de chamada será invocado. Use esse retorno de chamada para acompanhar quais amostras estão disponíveis no momento e quais estão em uso.
- Chame ID3D11VideoContext::DecoderBeginFrame. Passe os ponteiros para a interface ID3D11VideoDecoder para o dispositivo decodificador e a interface ID3D11VideoDecoderOutputView para a visualização de saída.
- Faça o seguinte uma ou mais vezes:
- Chame ID3D11VideoContext::GetDecoderBuffer para obter um buffer.
- Preencha o buffer.
- Chame ID3D11VideoContext::ReleaseDecoderBuffer.
- Chame ID3D11VideoContext::SubmitDecoderBuffer. Esse método instrui o dispositivo decodificador a executar as operações de decodificação no quadro.
- Chame ID3D11VideoContext::DecoderEndFrame para sinalizar o fim da decodificação para o quadro atual.
O Direct3D 11 usa as mesmas estruturas de dados que o DXVA 2.0 para operações de decodificação. Para o conjunto original de perfis DXVA (para H.261, H.263 e MPEG-2), essas estruturas de dados são descritas na especificação DXVA 1.0.
Em cada par de chamadas DecoderBeginFrame e SubmitDecoderBuffer, você pode chamar GetDecoderBuffer várias vezes, mas apenas uma vez para cada tipo de buffer. Se você usar o mesmo tipo de buffer duas vezes sem chamar SubmitDecoderBuffer, substituirá os dados no buffer.
Tópicos relacionados