Modelo de processamento MFT básico
Este tópico descreve como um cliente usa uma MFT (transformação do Media Foundation) para processar dados. O cliente é qualquer coisa que chama diretamente métodos no MFT. Esse pode ser o aplicativo ou o pipeline do Media Foundation.
Leia este tópico se você estiver:
- Escrever um aplicativo que faz chamadas diretas para um ou mais MFTs.
- Escrever um MFT personalizado e desejar entender o comportamento esperado de um MFT.
Este tópico descreve um modelo de processamento síncrono . Nesse modelo, todos os métodos de processamento de dados são bloqueados até que sejam concluídos. Os MFTs também podem dar suporte a um modelo assíncrono , que é descrito no tópico MFTs assíncronos.
- Modelo de processamento básico
- Extensões para o modelo básico
- IMF2DBuffer
- Liberando um MFT
- Drenando um MFT
- Atributos de exemplo
- Descontinuidades
- Alterações de formato dinâmico
- Eventos de fluxo
- Tópicos relacionados
Modelo de processamento básico
Criar o MFT
Há várias maneiras de criar um MFT:
- Chame a função MFTEnum .
- Chame a função MFTEnumEx .
- Se você já souber o CLSID do MFT, basta chamar CoCreateInstance.
Alguns 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 assumem identificadores de fluxo como parâmetros.
Alguns 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.)
- (Opcional.) Chame IMFTransform::GetStreamLimits para obter o número mínimo e máximo de fluxos aos quais o MFT pode dar suporte. Se o mínimo e o máximo forem os mesmos, o MFT terá um número fixo de fluxos.
- Chame IMFTransform::GetStreamCount para obter o número inicial de fluxos.
- 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 do zero.
- (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. (Você não pode adicionar ou remover fluxos de saída.)
Definir tipos de mídia
Antes que um MFT possa processar dados, o cliente deve definir um tipo de mídia para cada um dos fluxos do MFT. Um 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). Alguns MFTs não têm um requisito na ordem.
Um MFT pode fornecer uma lista de tipos de mídia preferenciais para um fluxo. Além disso, os MFTs podem indicar os formatos gerais aos quais dão suporte adicionando essas informações ao registro.
Para definir os tipos de mídia, faça o seguinte:
- (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ê deverá definir os tipos de saída primeiro; vá para a etapa 3.
- Se o método retornar E_NOTIMPL, o MFT não terá uma lista de tipos de entrada preferenciais; vá para a etapa 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 fluxo retornar MF_E_TRANSFORM_TYPE_NOT_SET, pule para a etapa 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ê deverá definir os tipos de entrada primeiro; volte para a etapa 1.
- Se algum fluxo retornar E_NOTIMPL, o MFT não terá uma lista de tipos de saída preferenciais; vá para a etapa 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.
- 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 definir os tipos de mídia, ele deverá obter os requisitos de buffer para cada fluxo:
- Para cada fluxo de entrada, chame IMFTransform::GetInputStreamInfo.
- Para cada fluxo de saída, chame IMFTransform::GetOutputStreamInfo.
Processar Dados
Um MFT foi projetado para ser uma máquina de estado confiável. Ele não faz nenhuma chamada de volta para o cliente.
- Chame IMFTransform::P rocessMessage com a mensagem MFT_MESSAGE_NOTIFY_BEGIN_STREAMING . Essa mensagem solicita que o MFT aloque todos os recursos necessários durante o streaming.
- Chame IMFTransform::P rocessInput em pelo menos um fluxo de entrada para fornecer uma amostra de entrada ao MFT.
- (Opcional.) Chame IMFTransform::GetOutputStatus para consultar se o MFT pode gerar um exemplo de saída. Se o método retornar S_OK, marcar o parâmetro pdwFlags. Se pdwFlags contiver o sinalizador MFT_OUTPUT_STATUS_SAMPLE_READY , vá para a etapa 4. Se pdwFlags for zero, volte para a etapa 2. Se o método retornar E_NOTIMPL, vá para a etapa 4.
- Chame IMFTransform::P rocessOutput para obter dados de saída.
- Se o método retornar MF_E_TRANSFORM_NEED_MORE_INPUT, isso significa que o MFT requer mais dados de entrada; volte para a etapa 2.
- Se o método retornar MF_E_TRANSFORM_STREAM_CHANGE, isso significará 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 de ProcessOutput.
- Se ainda houver dados de entrada a serem processados, vá para a etapa 2. Se o MFT tiver consumido todos os dados de entrada disponíveis, vá para a etapa 6.
- Chame ProcessMessage com a mensagem MFT_MESSAGE_NOTIFY_END_OF_STREAM .
- Chame ProcessMessage com a mensagem MFT_MESSAGE_COMMAND_DRAIN .
- Chame ProcessOutput para obter a saída restante. Repita essa etapa até que o método retorne MF_E_TRANSFORM_NEED_MORE_INPUT. Esse valor retornado sinaliza que toda a saída foi drenada do MFT. (Não trate isso como uma condição de erro.)
A sequência descrita aqui mantém o mínimo possível de dados no MFT. Após cada chamada para ProcessInput, o cliente tenta obter a saída. Vários exemplos de entrada podem ser necessários para produzir um exemplo de saída ou um único exemplo de entrada pode gerar vários exemplos de saída. O comportamento ideal para o cliente é efetuar pull de 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 obtém retornando MF_E_NOTACCEPTING de ProcessInput sempre que tiver alguma saída para produzir.
A ordem das chamadas de método descritas aqui não é a única sequência válida de eventos. Por exemplo, as etapas 3 e 4 pressupõem que o cliente comece com os tipos de entrada e tente os tipos de saída. O cliente também pode reverter essa ordem e começar com os tipos de saída. Em ambos os casos, se o MFT exigir a ordem oposta, ele deverá 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 deverá retornar um código de erro se esta não for uma operação válida. Em suma, os 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.
Extensões para o modelo básico
Opcionalmente, um MFT pode dar suporte a algumas extensões para o modelo de streaming básico.
- Fluxos de leitura lenta. Se o método IMFTransform::GetOutputStreamInfo retornar o sinalizador MFT_OUTPUT_STREAM_LAZY_READ para um fluxo de saída, o cliente não precisará coletar dados desse fluxo de saída. O MFT continua a aceitar a 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 a entrada. Um exemplo pode ser uma transformação de visualização, em que 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étodo GetOutputStreamInfo retornar o sinalizador MFT_OUTPUT_STREAM_DISCARDABLE para um fluxo de saída, o cliente poderá solicitar que o MFT descarte a saída, mas o MFT não descartará nenhuma saída, a menos que solicitado. 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 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 definir o tipo, o fluxo será desmarcado. 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 fluxos de entrada e saída como opcionais. No entanto, espera-se que pelo menos uma entrada e uma saída precisem ser selecionadas para que o MFT funcione.
- Processamento assíncrono. O modelo de processamento assíncrono foi introduzido no Windows 7. Ele é descrito no tópico MFTs assíncronos.
IMF2DBuffer
Se um MFT processar dados de vídeo descompactados, ele deverá usar a interface IMF2DBuffer para manipular os buffers de exemplo. Para obter essa interface, consulte a interface IMFMediaBuffer em qualquer buffer de entrada ou saída. Não usar essa interface quando ela está disponível pode resultar em cópias de buffer adicionais. Para fazer o 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 descompactados.
Liberando um MFT
A liberação de um MFT faz com que o MFT descarte todos os seus dados de entrada. Isso pode causar uma interrupção no fluxo de saída. Um cliente normalmente libera um MFT antes de procurar um novo ponto no fluxo de entrada ou alternar para um novo fluxo de entrada, quando o cliente não se importa em perder dados.
Para liberar um MFT, chame IMFTransform::P rocessMessage com a mensagem MFT_MESSAGE_COMMAND_FLUSH .
Drenando um MFT
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. Se o MFT não puder produzir um exemplo de saída completo da entrada disponível, ele removerá os dados de entrada. Um cliente normalmente esvaziaria um MFT quando atingisse o final do fluxo de origem ou imediatamente antes de uma alteração de formato no fluxo de origem. Para esvaziar um MFT, faça o seguinte:
- Chame ProcessMessage com a mensagem MFT_MESSAGE_COMMAND_DRAIN . Esta mensagem notifica o MFT de que ele deve fornecer o máximo de dados de saída possível dos dados de entrada que já foram enviados.
- 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 esvaziado, ele não aceitará mais nenhuma entrada.
Atributos de exemplo
Os exemplos de entrada podem ter atributos que devem ser copiados para os exemplos de saída correspondentes.
- Se o MFT retornar VARIANT_TRUE para a propriedade MFPKEY_EXATTRIBUTE_SUPPORTED , o MFT deverá copiar os atributos.
- Se a propriedade MFPKEY_EXATTRIBUTE_SUPPORTED for VARIANT_FALSE ou não estiver definida, o cliente deverá copiar os atributos.
Para um MFT com uma entrada e uma saída, você pode usar a seguinte regra geral:
- Se cada exemplo de entrada produzir exatamente um exemplo de saída, você poderá permitir que o cliente copie os atributos. Deixe a propriedade MFPKEY_EXATTRIBUTE_SUPPORTED desconjunta.
- Se não houver uma correspondência um-para-um entre amostras de entrada e amostras de saída, o MFT deverá determinar os atributos corretos para exemplos de saída. Defina a propriedade MFPKEY_EXATTRIBUTE_SUPPORTED como VARIANT_TRUE.
Descontinuidades
Uma descontinuidade é uma interrupção em um fluxo de áudio ou vídeo. Descontinuidades podem ser causadas por pacotes descartados em uma conexão de rede, dados de arquivo corrompidos, uma mudança de um fluxo de origem para outro ou uma ampla variedade de outras causas. As descontinuidades são sinalizadas definindo o atributo MFSampleExtension_Discontinuity no primeiro exemplo após a descontinuidade. Não é possível sinalizar uma descontinuidade no meio de uma amostra. Portanto, todos os dados descontinuados devem ser enviados em exemplos separados.
Algumas transformações, especialmente aquelas que lidam com dados descompactados, como efeitos de áudio e vídeo, devem ignorar descontinuidades ao processar dados de entrada. Esses MFTs geralmente são projetados para lidar com dados contínuos e devem tratar todos os dados recebidos como contínuos, mesmo após uma descontinuidade.
Se um MFT ignorar uma descontinuidade nos dados de entrada, ele ainda deverá definir o sinalizador de descontinuidade no exemplo de saída, se o exemplo de saída tiver o mesmo carimbo de data/hora que o exemplo de entrada. No entanto, se o exemplo de saída tiver um carimbo de data/hora diferente, o MFT não deverá propagar a descontinuidade. (Esse seria o caso em alguns resamplers de áudio, por exemplo.) Uma descontinuidade no lugar errado no fluxo é pior do que nenhuma descontinuidade.
A maioria dos decodificadores não pode ignorar descontinuidades, pois uma descontinuidade afeta a interpretação do próximo exemplo. Qualquer tecnologia de codificação que usa compactação entre quadros, como MPEG-2, se enquadra nessa categoria. Alguns esquemas de codificação usam apenas compactação intramoldura, como DV e MJPEG. Esses decodificadores podem ignorar descontinuidades com segurança.
As transformações que respondem a descontinuidades geralmente devem gerar o máximo de dados antes da descontinuidade possível e descartar o restante. O exemplo de entrada com o sinalizador de descontinuidade deve ser processado como se fosse o primeiro exemplo 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 decodificador não fizer nada para atenuar uma descontinuidade, ele deverá copiar o sinalizador de descontinuidade para os dados de saída. Demultiplexers e outros MFTs que funcionam inteiramente com dados compactados devem copiar quaisquer descontinuidades para seus fluxos de saída. Caso contrário, os componentes downstream podem não ser capazes de decodificar os dados compactados corretamente. Em geral, quase sempre é correto passar descontinuidades downstream, a menos que o MFT contenha código explícito para suavizar descontinuidades.
Alterações de formato dinâmico
Os formatos podem ser alterados durante o streaming. Por exemplo, a taxa de proporção pode ser alterada 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.
Eventos de fluxo
Para enviar um evento para um MFT, chame IMFTransform::P rocessEvent. Se o método retornar MF_S_TRANSFORM_DO_NOT_PROPAGATE_EVENT, o MFT retornará o evento para o chamador em uma chamada subsequente para ProcessOutput. Se o método retornar qualquer outro valor HRESULT , o MFT não retornará o evento para o 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::P rocessOutput.
Tópicos relacionados