Compartir a través de


Modelo de procesamiento de MFT básico

En este tema se describe cómo un cliente usa una transformación de Media Foundation (MFT) para procesar datos. El cliente es cualquier cosa que llame directamente a métodos en el MFT. Puede ser la aplicación o la canalización de Media Foundation.

Lea este tema si es:

  • Escritura de una aplicación que realiza llamadas directas a una o varias MFP.
  • Escribir un MFT personalizado y querer comprender el comportamiento esperado de un MFT.

En este tema se describe un modelo de procesamiento sincrónico . En este modelo, todos los métodos de procesamiento de datos se bloquean hasta que se completan. Las MFT también pueden admitir un modelo asincrónico , que se describe en el tema MFP asincrónicas.

Modelo de procesamiento básico

Creación del MFT

Hay varias maneras de crear una MFT:

  • Llame a la función MFTEnum .
  • Llame a la función MFTEnumEx .
  • Si ya conoce el CLSID del MFT, simplemente llame a CoCreateInstance.

Algunas MFP pueden proporcionar otras opciones, como una función de creación especializada.

Obtención de identificadores de flujo

Un MFT tiene una o varias secuencias. Los flujos de entrada reciben datos de entrada y los flujos de salida generan datos de salida. Las secuencias no se representan como objetos distintos. En su lugar, varios métodos MFT toman identificadores de flujo como parámetros.

Algunas MFP permiten al cliente agregar o quitar flujos de entrada. Durante el streaming, un MFT puede agregar o quitar flujos de salida. (El cliente no puede agregar ni quitar flujos de salida).

  1. (Opcional). Llame a IMFTransform::GetStreamLimits para obtener el número mínimo y máximo de secuencias que el MFT puede admitir. Si el mínimo y el máximo son los mismos, MFT tiene un número fijo de secuencias.
  2. Llame a IMFTransform::GetStreamCount para obtener el número inicial de secuencias.
  3. Llame a IMFTransform::GetStreamIDs para obtener los identificadores de flujo. Si este método devuelve E_NOTIMPL, significa que MFT tiene un número fijo de secuencias y los identificadores de flujo comienzan de cero.
  4. (Opcional). Si el MFT no tiene un número fijo de secuencias, llame a IMFTransform::AddInputStreams para agregar más flujos de entrada o IMFTransform::D eleteInputStream para quitar flujos de entrada. (No se pueden agregar ni quitar flujos de salida).

Establecer tipos de medios

Para que un MFT pueda procesar datos, el cliente debe establecer un tipo de medio para cada una de las secuencias de MFT. Un MFT puede requerir que el cliente establezca los tipos de entrada antes de establecer los tipos de salida, o podría requerir el orden opuesto (primero los tipos de salida). Algunos TMF no tienen un requisito en el pedido.

Un MFT puede proporcionar una lista de los tipos de medios preferidos para una secuencia. Además, las MFT pueden indicar los formatos generales que admiten agregando esta información al registro.

Para establecer los tipos de medios, haga lo siguiente:

  1. (Opcional). Para cada flujo de entrada, llame a IMFTransform::GetInputAvailableType para obtener la lista de tipos preferidos para esa secuencia.
    • Si este método devuelve MF_E_TRANSFORM_TYPE_NOT_SET, primero debe establecer los tipos de salida; vaya al paso 3.
    • Si el método devuelve E_NOTIMPL, el MFT no tiene una lista de tipos de entrada preferidos; vaya al paso 2.
  2. Para cada flujo de entrada, llame a IMFTransform::SetInputType para establecer el tipo de entrada. Puede usar un tipo de medio del paso 1 o un tipo que describa los datos de entrada. Si alguna secuencia devuelve MF_E_TRANSFORM_TYPE_NOT_SET, vaya al paso 3.
  3. (Opcional). Para cada flujo de salida, llame a IMFTransform::GetOutputAvailableType para obtener una lista de los tipos preferidos para esa secuencia.
    • Si este método devuelve MF_E_TRANSFORM_TYPE_NOT_SET, primero debe establecer los tipos de entrada; vuelva al paso 1.
    • Si alguna secuencia devuelve E_NOTIMPL, el MFT no tiene una lista de tipos de salida preferidos; vaya al paso 4.
  4. Para cada flujo de salida, llame a IMFTransform::SetOutputType para establecer el tipo de salida. Puede usar un tipo de medio del paso 3 o un tipo que describa el formato de salida necesario.
  5. Si alguna secuencia de entrada no tiene un tipo de medio, vuelva al paso 1.

Obtener requisitos de búfer

Una vez que el cliente establece los tipos de medios, debe obtener los requisitos de búfer para cada secuencia:

Procesar datos

Un MFT está diseñado para ser una máquina de estado confiable. No realiza ninguna llamada al cliente.

  1. Llame a IMFTransform::P rocessMessage con el mensaje MFT_MESSAGE_NOTIFY_BEGIN_STREAMING . Este mensaje solicita al MFT que asigne los recursos que necesita durante el streaming.
  2. Llame a IMFTransform::P rocessInput en al menos un flujo de entrada para entregar una muestra de entrada al MFT.
  3. (Opcional). Llame a IMFTransform::GetOutputStatus para consultar si el MFT puede generar una muestra de salida. Si el método devuelve S_OK, compruebe el parámetro pdwFlags . Si pdwFlags contiene la marca MFT_OUTPUT_STATUS_SAMPLE_READY , vaya al paso 4. Si pdwFlags es cero, vuelva al paso 2. Si el método devuelve E_NOTIMPL, vaya al paso 4.
  4. Llame a IMFTransform::P rocessOutput para obtener datos de salida.
    • Si el método devuelve MF_E_TRANSFORM_NEED_MORE_INPUT, significa que el MFT requiere más datos de entrada; vuelva al paso 2.
    • Si el método devuelve MF_E_TRANSFORM_STREAM_CHANGE, significa que el número de secuencias de salida ha cambiado o el formato de salida ha cambiado. Es posible que el cliente tenga que consultar nuevos identificadores de flujo o establecer nuevos tipos de medios. Para obtener más información, consulte la documentación de ProcessOutput.
  5. Si todavía hay datos de entrada que procesar, vaya al paso 2. Si MFT ha consumido todos los datos de entrada disponibles, continúe con el paso 6.
  6. Llame a ProcessMessage con el mensaje MFT_MESSAGE_NOTIFY_END_OF_STREAM .
  7. Llame a ProcessMessage con el mensaje MFT_MESSAGE_COMMAND_DRAIN .
  8. Llame a ProcessOutput para obtener el resultado restante. Repita este paso hasta que el método devuelva MF_E_TRANSFORM_NEED_MORE_INPUT. Este valor devuelto indica que toda la salida se ha purgado del MFT. (No lo trate como una condición de error).

La secuencia que se describe aquí mantiene los datos lo más pequeños posible en MFT. Después de cada llamada a ProcessInput, el cliente intenta obtener la salida. Es posible que se necesiten varias muestras de entrada para generar una muestra de salida o una única muestra de entrada podría generar varias muestras de salida. El comportamiento óptimo para el cliente es extraer muestras de salida de MFT hasta que MFT requiera más entrada.

Sin embargo, MFT debe ser capaz de controlar un orden diferente de llamadas de método por parte del cliente. Por ejemplo, el cliente podría simplemente alternar entre llamadas a ProcessInput y ProcessOutput. El MFT debe restringir la cantidad de entrada que obtiene devolviendo MF_E_NOTACCEPTING de ProcessInput siempre que tenga alguna salida para generar.

El orden de las llamadas de método que se describen aquí no es la única secuencia válida de eventos. Por ejemplo, los pasos 3 y 4 suponen que el cliente comienza con los tipos de entrada y, a continuación, intenta los tipos de salida. El cliente también puede invertir este orden y empezar con los tipos de salida. En cualquier caso, si el MFT requiere el orden opuesto, debe devolver el código de error MF_E_TRANSFORM_TYPE_NOT_SET.

El cliente puede llamar a métodos informativos, como GetInputCurrentType y GetOutputStreamInfo, en cualquier momento durante el streaming. El cliente también puede intentar cambiar los tipos de medios en cualquier momento. El MFT debe devolver un código de error si no es una operación válida. En resumen, las MFT deben suponer muy poco sobre el orden de las operaciones, aparte de lo que se documenta en las propias llamadas.

En el diagrama siguiente se muestra un gráfico de flujo de los procedimientos descritos en este tema.

diagrama de flujo que conduce desde obtención de identificadores de flujo a través de bucles que establecen tipos de entrada, obtención de entrada y salida de proceso

Extensiones al modelo básico

Opcionalmente, un MFT puede admitir algunas extensiones para el modelo de streaming básico.

  • Secuencias de lectura diferida. Si el método IMFTransform::GetOutputStreamInfo devuelve la marca MFT_OUTPUT_STREAM_LAZY_READ para un flujo de salida, el cliente no tiene que recopilar datos de ese flujo de salida. El MFT sigue aceptando la entrada y, en algún momento, MFT descartará los datos de salida de esa secuencia. Si todos los flujos de salida tienen esta marca, el MFT nunca no aceptará la entrada. Un ejemplo podría ser una transformación de visualización, donde el cliente obtiene la salida solo cuando tiene ciclos de CPU de reserva para dibujar la visualización.
  • Secuencias descartables. Si el método GetOutputStreamInfo devuelve la marca MFT_OUTPUT_STREAM_DISCARDABLE para un flujo de salida, el cliente puede solicitar al MFT que descarte la salida, pero el MFT no descartará ninguna salida a menos que se solicite. Cuando el MFT alcanza su búfer de entrada máximo, el cliente debe recopilar algunos datos de salida o solicitar al MFT que descarte la salida.
  • Secuencias opcionales. Si el método GetOutputStreamInfo devuelve la marca MFT_OUTPUT_STREAM_OPTIONAL de un flujo de salida o el método IMFTransform::GetInputStreamInfo devuelve la marca MFT_INPUT_STREAM_OPTIONAL para un flujo de entrada, esa secuencia es opcional. El cliente no tiene que establecer un tipo de medio en la secuencia. Si el cliente no establece el tipo, se deselecciona la secuencia. Un flujo de salida deseleccionada no genera muestras y el cliente no proporciona un búfer para la secuencia cuando llama a ProcessOutput. Un flujo de entrada deseleccionada no acepta datos de entrada. Un MFT puede marcar todos sus flujos de entrada y salida como opcionales. Sin embargo, se espera que al menos una entrada y una salida se deba seleccionar para que el MFT funcione.
  • Procesamiento asincrónico. El modelo de procesamiento asincrónico se introdujo en Windows 7. Se describe en el tema MFP asincrónicas.

IMF2DBuffer

Si un MFT procesa datos de vídeo sin comprimir, debe usar la interfaz IMF2DBuffer para manipular los búferes de muestra. Para obtener esta interfaz, consulte la interfaz IMFMediaBuffer en cualquier búfer de entrada o salida. Si no se usa esta interfaz, es posible que se realicen copias de búfer adicionales. Para hacer un uso adecuado de esta interfaz, la transformación no debe bloquear el búfer mediante la interfaz IMFMediaBuffer cuando IMF2DBuffer está disponible.

Para obtener más información sobre el procesamiento de datos de vídeo, vea Búferes de vídeo sin comprimir.

Vaciado de un MFT

El vaciado de un MFT hace que MFT descarte todos sus datos de entrada. Esto puede provocar una interrupción en el flujo de salida. Normalmente, un cliente vaciaría un MFT antes de buscar un nuevo punto en el flujo de entrada o cambiar a un nuevo flujo de entrada, cuando el cliente no se preocupa por perder datos.

Para vaciar un MFT, llame a IMFTransform::P rocessMessage con el mensaje MFT_MESSAGE_COMMAND_FLUSH .

Purgar un MFT

La purga de un MFT hace que el MFT genere tanto salida como pueda de cualquier dato de entrada que ya se haya enviado. Si el MFT no puede generar una muestra de salida completa a partir de la entrada disponible, quitará los datos de entrada. Normalmente, un cliente purgaría un MFT cuando llegó al final de la secuencia de origen o inmediatamente antes de un cambio de formato en la secuencia de origen. Para purgar un MFT, haga lo siguiente:

  1. Llame a ProcessMessage con el mensaje MFT_MESSAGE_COMMAND_DRAIN . Este mensaje notifica al MFT que debe entregar tantos datos de salida como pueda de los datos de entrada que ya se han enviado.
  2. Llame a ProcessOutput para obtener datos de salida, hasta que el método devuelva MF_E_TRANSFORM_NEED_MORE_INPUT.

Aunque el MFT se está purgando, no aceptará más entradas.

Atributos de ejemplo

Los ejemplos de entrada pueden tener atributos que se deben copiar en los ejemplos de salida correspondientes.

Para un MFT con una entrada y una salida, puede usar la siguiente regla general:

  • Si cada ejemplo de entrada genera exactamente un ejemplo de salida, puede permitir que el cliente copie los atributos. Deje la propiedad MFPKEY_EXATTRIBUTE_SUPPORTED sin establecer.
  • Si no hay una correspondencia uno a uno entre las muestras de entrada y las muestras de salida, MFT debe determinar los atributos correctos para los ejemplos de salida. Establezca la propiedad MFPKEY_EXATTRIBUTE_SUPPORTEDen VARIANT_TRUE.

Discontinuidades

Una discontinuidad es una interrupción en una secuencia de audio o vídeo. Las discontinuidades pueden deberse a paquetes descartados en una conexión de red, datos de archivos dañados, un cambio de una secuencia de origen a otra o una amplia gama de otras causas. Las discontinuidades se indican estableciendo el atributo MFSampleExtension_Discontinuity en el primer ejemplo después de la discontinuidad. No es posible señalar una discontinuidad en medio de una muestra. Por lo tanto, los datos discontinuos deben enviarse en ejemplos independientes.

Algunas transformaciones, especialmente aquellas que controlan datos sin comprimir, como los efectos de audio y vídeo, deben omitir las discontinuidades cuando procesan los datos de entrada. Por lo general, estas MFP están diseñadas para controlar los datos continuos y deben tratar los datos que reciben como continuos, incluso después de una discontinuidad.

Si un MFT omite una discontinuidad en los datos de entrada, debe establecer la marca de discontinuidad en el ejemplo de salida, si la muestra de salida tiene la misma marca de tiempo que la muestra de entrada. Sin embargo, si el ejemplo de salida tiene una marca de tiempo diferente, MFT no debe propagar la discontinuidad. (Este sería el caso en algunos remuestreos de audio, por ejemplo). Una discontinuidad en el lugar equivocado de la secuencia es peor que ninguna discontinuidad.

La mayoría de los descodificadores no pueden omitir las discontinuidades, ya que una discontinuidad afecta a la interpretación del ejemplo siguiente. Cualquier tecnología de codificación que use compresión entre fotogramas, como MPEG-2, entra en esta categoría. Algunos esquemas de codificación solo usan compresión dentro del marco, como DV y MJPEG. Estos descodificadores pueden omitir de forma segura las discontinuidades.

Las transformaciones que responden a las discontinuidades generalmente deben generar tantos datos antes de la discontinuidad como puedan y descartar el resto. El ejemplo de entrada con la marca de discontinuidad debe procesarse como si fuera el primer ejemplo de la secuencia. (Este comportamiento coincide con lo que se especifica para el mensaje de MFT_MESSAGE_COMMAND_DRAIN ). Sin embargo, los detalles exactos dependerán del formato multimedia.

Si un descodificador no hace nada para mitigar una discontinuidad, debe copiar la marca de discontinuidad en los datos de salida. Los demultiplexadores y otros MFP que funcionan completamente con datos comprimidos deben copiar las discontinuidades en sus flujos de salida. De lo contrario, es posible que los componentes de nivel inferior no puedan descodificar los datos comprimidos correctamente. En general, casi siempre es correcto pasar discontinuidades de bajada, a menos que el MFT contenga código explícito para suavizar las discontinuidades.

Cambios de formato dinámico

Los formatos pueden cambiar durante el streaming. Por ejemplo, la relación de aspecto puede cambiar en medio de una secuencia de vídeo.

Para obtener más información sobre cómo un MFT controla los cambios de flujo, consulte Control de cambios de flujo.

Eventos de transmisión

Para enviar un evento a un MFT, llame a IMFTransform::P rocessEvent. Si el método devuelve MF_S_TRANSFORM_DO_NOT_PROPAGATE_EVENT, el MFT devolverá el evento al autor de la llamada en una llamada posterior a ProcessOutput. Si el método devuelve cualquier otro valor HRESULT , MFT no devolverá el evento al cliente en ProcessOutput. En ese caso, el cliente es responsable de propagar el evento de bajada al siguiente componente de la canalización, si procede. Para obtener más información, vea IMFTransform::P rocessOutput.

Transformaciones de Media Foundation