MFTs assíncronos

Este tópico descreve o processamento de dados assíncrono para MFTs (transformações do Media Foundation).

Observação

Este tópico se aplica ao Windows 7 ou posterior.

 

Sobre MFTs assíncronos

Quando os MFTs foram introduzidos no Windows Vista, a API foi projetada para processamento de dados síncronos . Nesse modelo, o MFT está sempre aguardando para obter entrada ou aguardando para produzir a saída.

Considere um decodificador de vídeo típico. Para obter um quadro decodificado, o cliente chama IMFTransform::P rocessOutput. Se o decodificador tiver dados suficientes para decodificar um quadro, ProcessOutput bloqueará enquanto o MFT decodificará o quadro. Caso contrário, ProcessOutput retornará MF_E_TRANSFORM_NEED_MORE_INPUT, indicando que o cliente deve chamar IMFTransform::P rocessInput.

Esse modelo funcionará bem se o decodificador executar todas as operações de decodificação em um thread. Mas suponha que o decodificador use vários threads para decodificar quadros em paralelo. Para obter o melhor desempenho, o decodificador deve receber uma nova entrada sempre que um thread de decodificação ficar ocioso. Mas a taxa na qual os threads concluem operações de decodificação não se alinhará exatamente com as chamadas do cliente para ProcessInput e ProcessOutput, resultando em threads aguardando trabalho.

O Windows 7 apresenta o processamento assíncrono controlado por eventos para MFTs. Nesse modelo, sempre que o MFT precisar de entrada ou de saída, ele enviará um evento para o cliente.

Requisitos gerais

Este tópico descreve como os MFTs assíncronos diferem do MFT síncrono. Exceto quando observado neste tópico, os dois modelos de processamento são os mesmos. (Em particular, a negociação de formato é a mesma.)

Um MFT assíncrono deve implementar as seguintes interfaces:

Eventos

Um MFT assíncrono usa os seguintes eventos para sinalizar seu status de processamento de dados:

Evento Descrição
METransformNeedInput Enviado quando o MFT pode aceitar mais entradas.
METransformHaveOutput Enviado quando o MFT tem saída.
METransformDrainComplete Enviado quando uma operação de drenagem é concluída. Veja Drenando.
METransformMarker Enviado quando um marcador é processado. Consulte Marcadores.

 

Esses eventos são enviados fora de banda. É importante entender a diferença entre eventos fora de banda e fora de banda no contexto de um MFT.

O design original do MFT dá suporte a eventos em banda . Um evento em banda contém informações sobre o fluxo de dados, como informações sobre uma alteração de formato. O cliente envia eventos em banda para o MFT chamando IMFTransform::P rocessEvent. O MFT pode enviar eventos em banda de volta para o cliente no método ProcessOutput . (Especificamente, os eventos são transmitidos no membro pEvents da estrutura MFT_OUTPUT_DATA_BUFFER .)

Um MFT envia eventos fora de banda por meio da interface IMFMediaEventGenerator da seguinte maneira:

  1. O MFT implementa a interface IMFMediaEventGenerator , conforme descrito em Geradores de Eventos de Mídia.
  2. O cliente chama IUnknown::QueryInterface no MFT para a interface IMFMediaEventGenerator . Um MFT assíncrono deve expor essa interface. MFTs síncronos não devem expor essa interface.
  3. O cliente chama IMFMediaEventGenerator::BeginGetEvent e IMFMediaEventGenerator::EndGetEvent para receber eventos fora de banda do MFT.

ProcessInput

O método IMFTransform::P rocessInput é modificado da seguinte maneira:

  1. Quando o streaming é iniciado, o cliente envia a mensagem MFT_MESSAGE_NOTIFY_START_OF_STREAM .
  2. Durante o streaming, o MFT solicita dados enviando um evento METransformNeedInput . Os dados do evento são o identificador de fluxo.
  3. Para cada evento METransformNeedInput , o cliente chama ProcessInput para o fluxo especificado.
  4. No final do streaming, o cliente pode chamar ProcessMessage com a mensagem MFT_MESSAGE_NOTIFY_END_OF_STREAM .

Notas de implementação:

Processoutput

O método IMFTransform::P rocessOutput é modificado da seguinte maneira:

  1. Sempre que o MFT tem saída, ele envia um evento METransformHaveOutput .
  2. Para cada evento METransformHaveOutput , o cliente chama ProcessOutput.

Notas de implementação:

  • Se o cliente chamar ProcessOutput em qualquer outro momento, o método retornará E_UNEXPECTED.
  • Um MFT assíncrono nunca deve retornar MF_E_TRANSFORM_NEED_MORE_INPUT do método ProcessOutput . Se o MFT exigir mais entrada, ele enviará um evento METransformNeedInput .

Drenagem

A drenagem de um MFT faz com que o MFT produza o máximo de saída possível de qualquer dado de entrada que já tenha sido enviado. A drenagem de um MFT assíncrono funciona da seguinte maneira:

  1. O cliente envia a mensagem de MFT_MESSAGE_COMMAND_DRAIN .
  2. O MFT continua a enviar eventos METransformHaveOutput até que não tenha mais dados para processar. Ele não envia eventos METransformNeedInput durante esse tempo.
  3. Depois que o MFT envia o último evento METransformHaveOutput , ele envia um evento METransformDrainComplete .

Após a conclusão da drenagem, o MFT não envia outro evento METransformNeedInput até receber uma mensagem MFT_MESSAGE_NOTIFY_START_OF_STREAM do cliente.

Liberando

O cliente pode liberar o MFT enviando a mensagem MFT_MESSAGE_COMMAND_FLUSH . O MFT descarta todos os exemplos de entrada e saída que está mantendo.

O MFT não envia outro evento METransformNeedInput até receber uma mensagem MFT_MESSAGE_NOTIFY_START_OF_STREAM do cliente.

Marcadores

O cliente pode marcar um ponto no fluxo enviando a mensagem MFT_MESSAGE_COMMAND_MARKER . O MFT responde da seguinte maneira:

  1. O MFT gera o máximo de exemplos de saída que puder dos dados de entrada existentes, enviando um evento METransformHaveOutput para cada exemplo de saída.
  2. Depois que toda a saída é gerada, o MFT envia um evento METransformMarker . Esse evento deve ser enviado após todos os eventos METransformHaveOutput .

Por exemplo, suponha que um decodificador tenha dados de entrada suficientes para produzir quatro amostras de saída. Se o cliente enviar a mensagem MFT_MESSAGE_COMMAND_MARKER , o MFT enfileirará quatro eventos METransformHaveOutput (um por exemplo de saída), seguido por um evento METransformMarker .

A mensagem de marcador é semelhante à mensagem de esvaziamento. No entanto, um dreno é considerado uma quebra no fluxo, enquanto um marcador não é. Esvaziamento e marcadores têm as seguintes diferenças.

Drenagem:

  • Durante a drenagem, o MFT não envia eventos METransformNeedInput .
  • O MFT descarta todos os dados de entrada que não podem ser usados para criar um exemplo de saída.
  • Alguns MFTs produzem uma "cauda" no final dos dados. Por exemplo, efeitos de áudio como reverb ou echo produzem dados extras depois que os dados de entrada são interrompidos. Um MFT que gera uma cauda deve fazer isso no final de uma operação de esvaziamento.
  • Depois que o MFT terminar de esvaziar, ele marcará o próximo exemplo de saída com o atributo MFSampleExtension_Discontinuity , para indicar uma descontinuidade no fluxo.

Marcador:

  • O MFT continua a enviar eventos METransformNeedInput antes de enviar o evento de marcador.
  • O MFT não descarta nenhum dado de entrada. Se houver dados parciais, eles deverão ser processados após o ponto de marcador.
  • O MFT não produz uma cauda no ponto de marcador.
  • O MFT não define o sinalizador de descontinuidade após o ponto de marcador.

Alterações de formato

Um MFT assíncrono deve dar suporte a alterações de formato dinâmico, conforme descrito em Tratamento de Alterações de Fluxo.

Atributos

Um MFT assíncrono deve implementar o método IMFTransform::GetAttributes para retornar um repositório de atributos válido. Os seguintes atributos se aplicam a MFTs assíncronos:

Atributo Descrição
MF_TRANSFORM_ASYNC O MFT deve definir esse atributo como TRUE (1). O cliente pode consultar esse atributo para descobrir se o MFT é assíncrono.
MF_TRANSFORM_ASYNC_UNLOCK
MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE O MFT deve definir esse atributo como TRUE (1). O cliente pode assumir que esse atributo está definido.

 

Desbloqueando MFTs assíncronos

MFTs assíncronos não são compatíveis com o modelo de processamento de dados MFT original. Para evitar que MFTs assíncronos quebrando aplicativos existentes, o seguinte mecanismo é definido:

O cliente chama IMFTransform::GetAttributes no MFT. O cliente consulta o para esse atributo MF_TRANSFORM_ASYNC . Para um MFT assíncrono, o valor desse atributo é **TRUE**. Para desbloquear o MFT, o cliente deve definir o atributo MF_TRANSFORM_ASYNC_UNLOCK como **TRUE**.

Até que o cliente desbloqueie o MFT, todos os métodos IMFTransform devem retornar MF_E_TRANSFORM_ASYNC_LOCKED, com as seguintes exceções:

O código a seguir mostra como desbloquear um MFT assíncrono:

HRESULT UnlockAsyncMFT(IMFTransform *pMFT)
{
    IMFAttributes *pAttributes = NULL;

    HRESULT hr = hr = pMFT->GetAttributes(&pAttributes);

    if (SUCCEEDED(hr))
    {
        hr = pAttributes->SetUINT32(MF_TRANSFORM_ASYNC_UNLOCK, TRUE);
        pAttributes->Release();
    }
    
    return hr;
}

Desligando o MFT

Os MFTs assíncronos devem implementar a interface IMFShutdown .

  • Desligamento: o MFT deve desligar sua fila de eventos. Se estiver usando a fila de eventos padrão, chame IMFMediaEventQueue::Shutdown. Opcionalmente, o MFT pode liberar outros recursos. O cliente não deve usar o MFT depois de chamar Desligamento.
  • GetShutdownStatus: depois que o Desligamento for chamado, o MFT deverá retornar o valor MFSHUTDOWN_COMPLETED no parâmetro pStatus . Ele não deve retornar o valor MFSHUTDOWN_INITIATED.

Registro e enumeração

Para registrar um MFT assíncrono, chame a função MFTRegister e defina o sinalizador MFT_ENUM_FLAG_ASYNCMFT no parâmetro Flags . (Anteriormente, esse sinalizador era reservado.)

Para enumerar MFTs assíncronos, chame a função MFTEnumEx e defina o sinalizador MFT_ENUM_FLAG_ASYNCMFT no parâmetro Flags . Para compatibilidade com versões anteriores, a função MFTEnum não enumera MFTs assíncronos. Caso contrário, instalar um MFT assíncrono no computador do usuário pode interromper os aplicativos existentes.

Transformações do Media Foundation