MFTs assíncronas
Este tópico descreve o processamento assíncrono de dados para transformações do Media Foundation (MFTs).
Observação
Este tópico aplica-se ao Windows 7 ou posterior.
- Sobre MFTs assíncronas
- Requisitos Gerais
- Eventos
- ProcessInput
- ProcessOutput
- Drenagem
- Flushing
- Marcadores
- Alterações de formato
- Atributos
- Desbloqueio de MFTs assíncronas
- Desligando o MFT
- Registo e Enumeração
- Tópicos relacionados
Sobre MFTs assíncronas
Quando MFTs foram introduzidas no Windows Vista, a API foi projetada para síncrono processamento de dados. Nesse modelo, o MFT está sempre esperando para obter entrada, ou esperando para produzir 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, blocos de ProcessOutput enquanto o MFT decodifica o quadro. Caso contrário, ProcessOutput retorna MF_E_TRANSFORM_NEED_MORE_INPUT, indicando que o cliente deve chamar IMFTransform::P rocessInput.
Este modelo funciona bem se o descodificador executar todas as suas operações de descodificação num thread. Mas suponha que o decodificador usa vários threads para decodificar quadros em paralelo. Para obter o melhor desempenho, o decodificador deve receber novas entradas sempre que um thread de decodificação ficar ocioso. Mas a taxa na qual os threads concluem as 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 introduz o processamento de assíncrono controlado por eventos para MFTs. Neste modelo, sempre que o MFT precisa de entrada ou tem saída, ele envia um evento para o cliente.
Requisitos gerais
Este tópico descreve como as MFTs assíncronas diferem das MFTs síncronas. Exceto onde observado neste tópico, os dois modelos de processamento são os mesmos. (Em particular, a negociação de formato é a mesma.)
Uma MFT assíncrona deve implementar as seguintes interfaces:
- IMFTransform
- IMFMediaEventGenerator
- FMIhutdown
Publicações
Uma MFT assíncrona 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 para fora da banda. É importante entender a diferença entre eventos in-band e out-of-band no contexto de um MFT.
O design original do MFT suporta eventos de 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étodoProcessOutput. (Especificamente, os eventos são transmitidos no pEvents membro da estrutura MFT_OUTPUT_DATA_BUFFER.)
Um MFT envia eventos fora de banda através da interfaceIMFMediaEventGeneratorda seguinte maneira:
- O MFT implementa o interface de IMFMediaEventGenerator, conforme descrito em Media Event Generators.
- O cliente chama IUnknown::QueryInterface no MFT para o interface de IMFMediaEventGenerator. Uma MFT assíncrona deve expor essa interface. MFTs síncronas não devem expor essa interface.
- 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 forma:
- Quando o streaming é iniciado, o cliente envia a mensagem MFT_MESSAGE_NOTIFY_START_OF_STREAM.
- Durante o streaming, o MFT solicita dados enviando um evento METransformNeedInput. Os dados do evento são o identificador de fluxo.
- Para cada evento METransformNeedInput, o cliente chama ProcessInput para o fluxo especificado.
- No final do streaming, o cliente pode chamar ProcessMessage com a mensagem MFT_MESSAGE_NOTIFY_END_OF_STREAM.
Notas de execução:
- O MFT não deve enviar nenhum eventos de METransformNeedInput até receber a mensagem MFT_MESSAGE_NOTIFY_START_OF_STREAM.
- Durante o streaming, o MFT pode enviar eventos de METransformNeedInput a qualquer momento.
- O MFT deve manter uma contagem de pendentes METransformNeedInput eventos. Qualquer chamada para ProcessInput que não corresponda a um evento METransformNeedInput deve retornar MF_E_NOTACCEPTING.
- Quando o MFT recebe a mensagem de MFT_MESSAGE_NOTIFY_END_OF_STREAM, ele redefine a contagem de pendentes de eventos de METransformNeedInput para zero.
- O MFT não deve enviar nenhum eventos de METransformNeedInput depois de receber a mensagem MFT_MESSAGE_NOTIFY_END_OF_STREAM.
- Se ProcessInput for chamado antes MFT_MESSAGE_NOTIFY_START_OF_STREAM ou depois MFT_MESSAGE_NOTIFY_END_OF_STREAM, o método deverá retornar MF_E_NOTACCEPTING.
ProcessOutput
O método IMFTransform::P rocessOutput é modificado da seguinte forma:
- Sempre que o MFT tem saída, ele envia um METransformHaveOutput evento.
- Para cada evento METransformHaveOutput, o cliente chama ProcessOutput.
Notas de execução:
- Se o cliente chamar ProcessOutput em qualquer outro momento, o método retornará E_UNEXPECTED.
- Uma MFT assíncrona 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
Drenar uma MFT faz com que a MFT produza o máximo de saída possível a partir de quaisquer dados de entrada que já tenham sido enviados. A drenagem de uma MFT assíncrona funciona da seguinte forma:
- O cliente envia a mensagem MFT_MESSAGE_COMMAND_DRAIN.
- O MFT continua a enviar eventos METransformHaveOutput até que não tenha mais dados para processar. Ele não envia eventos de METransformNeedInput durante esse período.
- Depois que o MFT envia o último evento METransformHaveOutput, ele envia um evento METransformDrainComplete evento.
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.
Rubor
O cliente pode liberar o MFT enviando a mensagem MFT_MESSAGE_COMMAND_FLUSH. O MFT deixa cair todas as amostras de entrada e saída que está armazenando.
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 forma:
- O MFT gera o maior número possível de amostras de saída a partir dos dados de entrada existentes, enviando um evento METransformHaveOutput para cada amostra de saída.
- Depois que toda a saída é gerada, o MFT envia um METransformMarker evento. 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 amostra de saída), seguido por um evento METransformMarker.
A mensagem do marcador é semelhante à mensagem de drenagem. No entanto, um dreno é considerado uma rutura no córrego, enquanto um marcador não é. A drenagem e os marcadores têm as seguintes diferenças.
Drenagem:
- Durante a drenagem, o MFT não envia eventos de METransformNeedInput.
- O MFT descarta quaisquer dados de entrada que não possam ser usados para criar uma amostra de saída.
- Algumas 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. Uma MFT que gera uma cauda deve fazê-lo no final de uma operação de drenagem.
- Depois que o MFT terminar de drenar, ele marca a próxima amostra de saída com o atributo MFSampleExtension_Discontinuity, para indicar uma descontinuidade no fluxo.
Marcador:
- O MFT continua a enviar eventos de METransformNeedInput antes de enviar o evento de marcador.
- O MFT não descarta nenhum dado de entrada. Se existirem dados parciais, estes devem ser tratados após o marcador.
- O MFT não produz uma cauda no ponto de marcação.
- O MFT não define o sinalizador de descontinuidade após o ponto de marcador.
Alterações de formato
Uma MFT assíncrona deve suportar alterações de formato dinâmico, conforme descrito em Manipulando alterações de fluxo.
Atributos
Uma MFT assíncrona deve implementar o método IMFTransform::GetAttributes para retornar um repositório de atributos válido. Os seguintes atributos se aplicam a MFTs assíncronas:
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íncronas
MFTs assíncronas não são compatíveis com o modelo de processamento de dados MFT original. Para evitar que MFTs assíncronas interrompam aplicativos existentes, o seguinte mecanismo é definido:
- O cliente chama IMFTransform::GetAttributes no MFT.
O cliente consulta o para este atributo MF_TRANSFORM_ASYNC. Para uma MFT assíncrona, 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:
- IMFTransform::GetAttributes (todas as MFTs assíncronas)
- IMFTransform::GetInputAvailableType (todas as MFTs assíncronas)
- IMFTransform::GetOutputCurrentType (somente codificadores)
- IMFTransform::SetOutputType (somente codificadores)
- IMFTransform::GetStreamCount (todas as MFTs assíncronas)
- IMFTransform::GetStreamIDs (todas as MFTs assíncronas)
O código a seguir mostra como desbloquear uma MFT assíncrona:
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
MFTs assíncronas devem implementar o interface IMFShutdown.
- Shutdown: O MFT deve encerrar 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 Shutdown.
- GetShutdownStatus: Depois que Shutdown tiver sido chamado, o MFT deve retornar o valor MFSHUTDOWN_COMPLETED no parâmetro pStatus. Ele não deve retornar o valor MFSHUTDOWN_INITIATED.
Registo e Enumeração
Para registrar uma MFT assíncrona, chame a funçãoMFTRegistere defina o sinalizador MFT_ENUM_FLAG_ASYNCMFT no parâmetro Flags. (Anteriormente, esta bandeira era reservada.)
Para enumerar MFTs assíncronas, chame a função MFTEnumEx e defina o sinalizador de MFT_ENUM_FLAG_ASYNCMFT no parâmetro Flags. Para compatibilidade com versões anteriores, a função MFTEnum não enumera MFTs assíncronas. Caso contrário, a instalação de uma MFT assíncrona no computador do usuário pode interromper os aplicativos existentes.
Tópicos relacionados