Partilhar via


Modelo Básico de Processamento MFT

Este tópico descreve como um cliente usa uma transformação do Media Foundation (MFT) para processar dados. O cliente é qualquer coisa que chame métodos diretamente no MFT. Pode ser a aplicação ou o pipeline do Media Foundation.

Leia este tópico se estiver:

  • Escrever um aplicativo que faz chamadas diretas para uma ou mais MFTs.
  • Estou a escrever uma MFT personalizada e gostaria de compreender o comportamento esperado de uma MFT.

Este tópico descreve um modelo de processamento de síncrono. Neste modelo, todos os métodos de processamento de dados bloqueiam até à sua conclusão. MFTs também podem suportar um modelo assíncrono, que é descrito no tópico MFTs assíncronas.

Modelo Básico de Processamento

Criar o MFT

Há várias maneiras de criar um MFT:

  • Chame a função MFTEnum .
  • Chame a função MFTEnumEx .
  • Se você já conhece o CLSID do MFT, basta chamar CoCreateInstance.

Algumas MFTs podem fornecer outras opções, como uma função de criação especializada.

Obter identificadores de fluxo

Um MFT tem um ou mais fluxos . Os fluxos de entrada recebem dados de entrada e os fluxos de saída geram dados de saída. Os fluxos não são representados como objetos distintos. Em vez disso, vários métodos MFT usam identificadores de fluxo como parâmetros.

Algumas MFTs permitem que o cliente adicione ou remova fluxos de entrada. Durante o streaming, um MFT pode adicionar ou remover fluxos de saída. (O cliente não pode adicionar ou remover fluxos de saída.)

  1. (Opcional.) Ligue IMFTransform::GetStreamLimits para obter o número mínimo e máximo de fluxos que o MFT pode suportar. Se o mínimo e o máximo forem os mesmos, o MFT tem um número fixo de fluxos.
  2. Chame IMFTransform::GetStreamCount para obter o número inicial de fluxos.
  3. Chame IMFTransform::GetStreamIDs para obter os identificadores de fluxo. Se esse método retornar E_NOTIMPL, isso significa que o MFT tem um número fixo de fluxos e os identificadores de fluxo são consecutivos começando de zero.
  4. (Opcional.) Se o MFT não tiver um número fixo de fluxos, chame IMFTransform::AddInputStreams para adicionar mais fluxos de entrada ou IMFTransform::D eleteInputStream para remover fluxos de entrada. (Não é possível adicionar ou remover fluxos de saída.)

Definir tipos de mídia

Antes que uma MFT possa processar dados, o cliente deve definir tipos de mídia para cada um dos fluxos da MFT. Uma MFT pode exigir que o cliente defina os tipos de entrada antes de definir os tipos de saída, ou pode exigir a ordem oposta (tipos de saída primeiro). Algumas MFTs não têm um requisito na ordem.

Uma MFT pode fornecer uma lista de tipos de mídia preferenciais para um fluxo. Além disso, MFTs podem indicar os formatos gerais que eles suportam, adicionando essas informações ao registro.

Para definir os tipos de mídia, faça o seguinte:

  1. (Opcional.) Para cada fluxo de entrada, chame IMFTransform::GetInputAvailableType para obter a lista de tipos preferenciais para esse fluxo.
    • Se esse método retornar MF_E_TRANSFORM_TYPE_NOT_SET, você deve definir os tipos de saída primeiro; pule para a etapa 3.
    • Se o método retornar E_NOTIMPL, o MFT não tem uma lista de tipos de entrada preferenciais; pule para a etapa 2.
  2. Para cada fluxo de entrada, chame IMFTransform::SetInputType para definir o tipo de entrada. Você pode usar um tipo de mídia da etapa 1 ou um tipo que descreva seus dados de entrada. Se algum stream retornar MF_E_TRANSFORM_TYPE_NOT_SET, avance para a etapa 3.
  3. (Opcional.) Para cada fluxo de saída, chame IMFTransform::GetOutputAvailableType para obter uma lista de tipos preferenciais para esse fluxo.
    • Se esse método retornar MF_E_TRANSFORM_TYPE_NOT_SET, você deve definir os tipos de entrada primeiro; Volte ao passo 1.
    • Se qualquer fluxo retornar E_NOTIMPL, o MFT não tem uma lista de tipos de saída preferenciais; pule para a etapa 4.
  4. Para cada fluxo de saída, chame IMFTransform::SetOutputType para definir o tipo de saída. Você pode usar um tipo de mídia da etapa 3 ou um tipo que descreva o formato de saída necessário.
  5. Se algum fluxo de entrada não tiver um tipo de mídia, volte para a etapa 1.

Obter requisitos de buffer

Depois que o cliente define os tipos de mídia, ele deve obter os requisitos de buffer para cada fluxo:

Processar dados

Uma MFT é projetada para ser uma máquina de estado confiável. Não faz nenhuma chamada de retorno para o cliente.

  1. Ligue IMFTransform::ProcessMessage com a mensagem MFT_MESSAGE_NOTIFY_BEGIN_STREAMING. Esta mensagem solicita que o MFT aloque todos os recursos necessários durante o streaming.
  2. Chame IMFTransform::ProcessInput em pelo menos um dos fluxos de entrada para fornecer uma amostra de entrada ao MFT.
  3. (Opcional.) Chame IMFTransform::GetOutputStatus para consultar se o MFT pode gerar uma amostra de saída. Se o método retornar S_OK, verifique o parâmetro pdwFlags. Se pdwFlags contiver o sinalizador MFT_OUTPUT_STATUS_SAMPLE_READY, vá para a etapa 4. Se pdwFlags é zero, volte para o passo 2. Se o método retornar E_NOTIMPL, vá para a etapa 4.
  4. Chamar IMFTransform::ProcessOutput para obter dados de saída.
    • Se o método retornar MF_E_TRANSFORM_NEED_MORE_INPUT, significa que a MFT requer mais dados de entrada; Volte para a etapa 2.
    • Se o método retornar MF_E_TRANSFORM_STREAM_CHANGE, isso significa que o número de fluxos de saída foi alterado ou o formato de saída foi alterado. O cliente pode precisar consultar novos identificadores de fluxo ou definir novos tipos de mídia. Para obter mais informações, consulte a documentação do ProcessOutput.
  5. Se ainda houver dados de entrada para processar, vá para a etapa 2. Se a MFT tiver consumido todos os dados de entrada disponíveis, avance para o passo 6.
  6. Chame ProcessMessage com a mensagem MFT_MESSAGE_NOTIFY_END_OF_STREAM.
  7. Chame ProcessMessage com a mensagem MFT_MESSAGE_COMMAND_DRAIN.
  8. Chame ProcessOutput para obter a saída restante. Repita esta etapa até que o método retorne MF_E_TRANSFORM_NEED_MORE_INPUT. Esse valor de retorno sinaliza que toda a saída foi drenada do MFT. (Não trate isso como uma condição de erro.)

A sequência aqui descrita mantém o mínimo possível de dados no MFT. Após cada chamada para ProcessInput, o cliente tenta obter resultado. Várias amostras de entrada podem ser necessárias para produzir uma amostra de saída, ou uma única amostra de entrada pode gerar várias amostras de saída. O comportamento ideal para o cliente é extrair amostras de saída do MFT até que o MFT exija mais entrada.

No entanto, o MFT deve ser capaz de lidar com uma ordem diferente de chamadas de método pelo cliente. Por exemplo, o cliente pode simplesmente alternar entre chamadas para ProcessInput e ProcessOutput. O MFT deve restringir a quantidade de entrada que ela recebe retornando MF_E_NOTACCEPTING de ProcessInput sempre que tiver alguma saída para produzir.

A ordem das chamadas de método descrita aqui não é a única sequência válida de eventos. Por exemplo, as etapas 3 e 4 assumem que o cliente começa com os tipos de entrada e, em seguida, tenta os tipos de saída. O cliente também pode inverter essa ordem e começar com os tipos de saída. Em ambos os casos, se o MFT requer a ordem oposta, ele deve retornar o código de erro MF_E_TRANSFORM_TYPE_NOT_SET.

O cliente pode chamar métodos informativos, como GetInputCurrentType e GetOutputStreamInfo, a qualquer momento durante o streaming. O cliente também pode tentar alterar os tipos de mídia a qualquer momento. O MFT deve retornar um código de erro se esta não for uma operação válida. Em suma, as MFTs devem assumir muito pouco sobre a ordem das operações, além do que está documentado nas próprias chamadas.

O diagrama a seguir mostra um fluxograma dos procedimentos descritos neste tópico.

fluxograma que conduz desde os identificadores de fluxo através de loops que definem os tipos de entrada, obtêm entrada e processam saída

Extensões para o modelo básico

Opcionalmente, um MFT pode suportar algumas extensões para o modelo básico de streaming.

  • Fluxos de leitura preguiçosa. Se o método IMFTransform::GetOutputStreamInfo retornar o sinalizador de MFT_OUTPUT_STREAM_LAZY_READ para um fluxo de saída, o cliente não precisará recolher dados desse fluxo de saída. O MFT continua a aceitar entrada e, em algum momento, o MFT descartará os dados de saída desse fluxo. Se todos os fluxos de saída tiverem esse sinalizador, o MFT nunca deixará de aceitar entrada. Um exemplo pode ser uma transformação de visualização, onde o cliente obtém a saída somente quando tem ciclos de CPU sobressalentes para desenhar a visualização.
  • Fluxos descartáveis. Se o métodoGetOutputStreamInfo daretornar o sinalizador de MFT_OUTPUT_STREAM_DISCARDABLE para um fluxo de saída, o cliente poderá solicitar que a MFT descarte a saída, mas a MFT não descartará nenhuma saída, a menos que seja solicitada. Quando o MFT atinge seu buffer de entrada máximo, o cliente deve coletar alguns dados de saída ou solicitar que o MFT descarte a saída.
  • Fluxos opcionais. Se o método GetOutputStreamInfo retornar o sinalizador MFT_OUTPUT_STREAM_OPTIONAL para um fluxo de saída, ou se o método IMFTransform::GetInputStreamInfo retornar o sinalizador MFT_INPUT_STREAM_OPTIONAL para um fluxo de entrada, esse fluxo será opcional. O cliente não precisa definir um tipo de mídia no fluxo. Se o cliente não especificar o tipo, o fluxo será desativado. Um fluxo de saída desmarcado não produz amostras e o cliente não fornece um buffer para o fluxo quando chama ProcessOutput. Um fluxo de entrada desmarcado não aceita dados de entrada. Um MFT pode marcar todos os seus fluxos de entrada e saída como opcionais. No entanto, espera-se que pelo menos uma entrada e uma saída devem ser selecionadas para que a MFT funcione.
  • Processamento assíncrono. O modelo de processamento assíncrono foi introduzido no Windows 7. É descrito no tópico MFTs assíncronas.

IMF2DBuffer

Se uma MFT processar dados de vídeo não compactados, ela deverá usar a interfaceIMF2DBufferpara manipular os buffers de amostra. Para obter essa interface, consulte o interface IMFMediaBuffer em qualquer buffer de entrada ou saída. Não usar essa interface quando ela estiver disponível pode resultar em cópias de buffer adicionais. Para fazer uso adequado dessa interface, a transformação não deve bloquear o buffer usando a interface IMFMediaBuffer quando IMF2DBuffer estiver disponível.

Para obter mais informações sobre como processar dados de vídeo, consulte Buffers de vídeo não compactados.

Lavagem de uma MFT

Flushing um MFT faz com que o MFT descarte todos os seus dados de entrada. Isso pode causar uma quebra no fluxo de saída. Normalmente, um cliente esvazia uma MFT antes de procurar um novo ponto no fluxo de entrada ou mudar para um novo fluxo de entrada, caso o cliente não se importe em perder dados.

Para liberar uma MFT, chame IMFTransform::ProcessMessage com a mensagem MFT_MESSAGE_COMMAND_FLUSH.

Drenando uma MFT

Esvaziar uma MFT faz com que a MFT gere o máximo de saída possível a partir dos dados de entrada já enviados. Se o MFT não puder produzir uma amostra de saída completa a partir da entrada disponível, ele descartará os dados de entrada. Um cliente normalmente drena um MFT quando ele atinge o final do fluxo de origem, ou imediatamente antes de uma alteração de formato no fluxo de origem. Para drenar uma MFT, siga estas etapas:

  1. Chame ProcessMessage com a mensagem MFT_MESSAGE_COMMAND_DRAIN. Esta mensagem notifica a MFT de que deve fornecer o máximo de dados de saída possível a partir dos dados de entrada que já foram enviados.
  2. Chame ProcessOutput para obter dados de saída, até que o método retorne MF_E_TRANSFORM_NEED_MORE_INPUT.

Enquanto o MFT estiver sendo drenado, ele não aceitará mais entradas.

Atributos de exemplo

As amostras de entrada podem ter atributos que devem ser copiados para as amostras de saída correspondentes.

Para uma MFT com uma entrada e uma saída, você pode usar a seguinte regra geral:

  • Se cada amostra de entrada produzir exatamente uma amostra de saída, você poderá permitir que o cliente copie os atributos. Deixe a propriedade MFPKEY_EXATTRIBUTE_SUPPORTED não definida.
  • Se não houver uma correspondência um-para-um entre amostras de entrada e amostras de saída, a MFT deve determinar os atributos corretos para amostras de saída. Defina a propriedade MFPKEY_EXATTRIBUTE_SUPPORTED como VARIANT_TRUE.

Descontinuidades

Uma descontinuidade é uma quebra em um fluxo de áudio ou vídeo. As descontinuidades podem ser causadas por pacotes descartados em uma conexão de rede, dados de arquivos corrompidos, uma mudança de um fluxo de origem para outro ou uma ampla gama de outras causas. As descontinuidades são sinalizadas definindo o atributo MFSampleExtension_Discontinuity na primeira amostra após a descontinuidade. Não é possível sinalizar uma descontinuidade no meio de uma amostra. Por conseguinte, quaisquer dados descontínuos devem ser enviados em amostras separadas.

Algumas transformações, especialmente aquelas que lidam com dados não compactados, como efeitos de áudio e vídeo, devem ignorar descontinuidades ao processar dados de entrada. Estas MFT são geralmente concebidas para lidar com dados contínuos e devem tratar quaisquer dados que recebam como contínuos, mesmo após uma descontinuidade.

Se uma MFT ignorar uma descontinuidade nos dados de entrada, ela ainda deverá definir o sinalizador de descontinuidade na amostra de saída, se a amostra de saída tiver o mesmo carimbo de data/hora que a amostra de entrada. Se a amostra de saída tiver um timestamp diferente, a MFT, contudo, não deve propagar a descontinuidade. (Esse será o caso em alguns resamplers de áudio, por exemplo.) Uma descontinuidade no lugar errado do fluxo é pior do que qualquer descontinuidade.

A maioria dos descodificadores não pode ignorar descontinuidades, porque uma descontinuidade afeta a interpretação da amostra seguinte. Qualquer tecnologia de codificação que utilize compressão entre quadros, como MPEG-2, enquadra-se nesta categoria. Alguns esquemas de codificação usam apenas compressão intra-frame, como DV e MJPEG. Estes descodificadores podem ignorar com segurança descontinuidades.

As transformações que respondem a descontinuidades geralmente devem produzir o máximo possível de dados antes da descontinuidade e descartar o restante. A amostra de entrada com o sinalizador de descontinuidade deve ser processada como se fosse a primeira amostra no fluxo. (Esse comportamento corresponde ao especificado para a mensagem MFT_MESSAGE_COMMAND_DRAIN.) No entanto, os detalhes exatos dependerão do formato de mídia.

Se um descodificador não fizer nada para atenuar uma descontinuidade, deve copiar o sinalizador de descontinuidade para os dados de saída. Os desmultiplexadores e outros MFTs que funcionam inteiramente com dados compactados devem copiar quaisquer descontinuidades para seus fluxos de saída. Caso contrário, os componentes a jusante poderão não conseguir descodificar corretamente os dados comprimidos. Em geral, é quase sempre correto passar descontinuidades a jusante, a menos que a MFT contenha código explícito para suavizar descontinuidades.

Alterações de formato dinâmico

Os formatos podem mudar durante o streaming. Por exemplo, a proporção pode mudar no meio de um fluxo de vídeo.

Para obter detalhes sobre como as alterações de fluxo são tratadas por um MFT, consulte Manipulando alterações de fluxo.

Transmitir Eventos

Para enviar um evento para uma MFT, ligue IMFTransform::ProcessEvent. Se o método retornar MF_S_TRANSFORM_DO_NOT_PROPAGATE_EVENT, o MFT retornará o evento ao chamador numa chamada subsequente para ProcessOutput. Se o método retornar qualquer outro valor de HRESULT, a MFT não retornará o evento ao cliente em ProcessOutput. Nesse caso, o cliente é responsável por propagar o evento downstream para o próximo componente no pipeline, se aplicável. Para obter mais informações, consulte IMFTransform::ProcessOutput.

Media Foundation transforma