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

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.

a diagram that shows the software decoder and the dxgi device manager.

Estas são as etapas básicas que um software decodificador deve realizar para dar suporte ao Direct3D 11 no Media Foundation:

  1. Abrir um identificador para o dispositivo Direct3D 11.
  2. Encontrar uma configuração de decodificador.
  3. Alocar buffers descompactados.
  4. 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:

  1. O decodificador MFT deve expor o atributo MF_SA_D3D11_AWARE com o valor TRUE.
  2. O Carregador de Topologia consulta esse atributo chamando IMFTransform::GetAttributes. O valor TRUE indica que a MFT dá suporte ao Direct3D 11.
  3. 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.
  4. Chame IMFDXGIDeviceManager::OpenDeviceHandle para obter um identificador para o dispositivo Direct3D 11.
  5. 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.
  6. 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.
  7. Chame ID3D11Device::GetImmediateContext para obter um ponteiro ID3D11DeviceContext.
  8. Chame QueryInterface no ID3D11DeviceContext para obter um ponteiro ID3D11VideoContext.
  9. É 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.

  1. Valide o tipo de mídia de entrada. Se o tipo for rejeitado,pule as etapas restantes e retorne um código de erro.
  2. Chame ID3D11VideoDevice::GetVideoDecoderProfileCount para obter o número de perfis com suporte.
  3. Chame ID3D11VideoDevice::GetVideoDecoderProfile para enumerar os perfis e obter os GUIDs dos perfis.
  4. 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.
  5. 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.
  6. Em seguida, encontre uma configuração adequada para o decodificador.
    1. 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.
    2. 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.

  1. Os métodos SetInputType e SetOutputType devem retornar MF_E_UNSUPPORTED_D3D_TYPE.
  2. Em resposta, o Carregador de Topologia enviará a mensagem MFT_MESSAGE_SET_D3D_MANAGER com o valor NULL para o parâmetro ulParam.
  3. A MFT libera o ponteiro para a interface IMFDXGIDeviceManager.
  4. 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:

  1. 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.

  2. 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.

  3. Para cada superfície na matriz de texturas, crie uma amostra de mídia da seguinte maneira:

    1. 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.
    2. 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.
    3. 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:

  1. Feche o identificador do dispositivo chamando IMFDXGIDeviceManager::CloseDeviceHandle.
  2. Libere todos os recursos associados ao dispositivo Direct3D 11 anterior, incluindo as interfaces ID3D11VideoDecoder, ID3D11VideoContext,ID3D11Texture2D e ID3D11VideoDecoderOutputView.
  3. Abra um novo identificador de dispositivo.
  4. 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.
  5. Crie um novo dispositivo decodificador.

Supondo que o identificador do dispositivo seja válido, o processo de decodificação funciona da seguinte maneira:

  1. Obtenha uma superfície disponível que não esteja em uso no momento. Inicialmente, todas as superfícies estão disponíveis.
  2. Consulte a amostra de mídia para a interface IMFTrackedSample.
  3. 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.
  4. 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.
  5. Faça o seguinte uma ou mais vezes:
    1. Chame ID3D11VideoContext::GetDecoderBuffer para obter um buffer.
    2. Preencha o buffer.
    3. Chame ID3D11VideoContext::ReleaseDecoderBuffer.
    4. Chame ID3D11VideoContext::SubmitDecoderBuffer. Esse método instrui o dispositivo decodificador a executar as operações de decodificação no quadro.
  6. 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.

APIs de vídeo do Direct3D 11

Aceleração de vídeo DirectX 2.0