Escritura de un origen multimedia personalizado
En este tema se describe cómo implementar un origen multimedia personalizado en Microsoft Media Foundation. Contiene las secciones siguientes:
- Creación del descriptor de presentación
- Iniciar el origen multimedia
- Pausar el origen multimedia
- Generación de datos de origen
- Apagar el origen multimedia
- Orígenes activos
- Temas relacionados
Creación del descriptor de presentación
El método IMFMediaSource::CreatePresentationDescriptor devuelve una copia del descriptor de presentación del origen. Para crear el descriptor de presentación, debe conocer el número de secuencias en el contenido de origen y los posibles formatos de cada secuencia. Para cada secuencia, cree un descriptor de secuencia de la siguiente manera:
- Cree una matriz de tipos de medios. Cada tipo de medio de la matriz representa un formato posible para la secuencia. Para obtener más información sobre cómo crear tipos de medios, vea Tipos de medios.
- Llame a MFCreateStreamDescriptor para crear el descriptor de secuencia. Pase la matriz de tipos de medios. La función devuelve un puntero IMFStreamDescriptor .
- Llame a IMFStreamDescriptor::GetMediaTypeHandler para obtener el controlador de tipos multimedia del descriptor de secuencia.
- Llame a IMFMediaTypeHandler::SetCurrentMediaType para establecer el formato de secuencia predeterminado. Use uno de los tipos de medios que creó en el paso 1. Por lo general, debe usar el formato con la máxima calidad.
- Opcionalmente, establezca atributos en el descriptor de secuencia. Para obtener una lista de atributos que se aplican a los descriptores de flujo, consulte Atributos de descriptor de secuencia.
Ahora cree el descriptor de presentación:
- Llame a MFCreatePresentationDescriptor y pase la matriz de descriptores de secuencia. La función devuelve un puntero IMFPresentationDescriptor .
- Elija la selección de secuencia predeterminada llamando a IMFPresentationDescriptor::SelectStream para seleccionar una o varias secuencias. Debe seleccionarse al menos una secuencia en la configuración predeterminada.
- Opcionalmente, establezca atributos en el descriptor de presentación. Para obtener una lista de atributos que se aplican a los descriptores de flujo, vea Atributos de descriptor de presentación.
Debe crear el descriptor de presentación una vez, ya sea al inicio o después de que el origen haya analizado lo suficiente de los datos de origen para determinar el contenido. El método CreatePresentationDescriptor debe devolver una copia del descriptor de presentación. Para crear la copia, llame a IMFPresentationDescriptor::Clone. Devolver una copia impide que el cliente modifique el estado del descriptor de presentación original, como los atributos o la selección de secuencias. Sin embargo, tenga en cuenta que Clone crea una copia superficial, por lo que el cliente puede modificar potencialmente los descriptores de secuencia subyacentes.
Iniciar el origen multimedia
El método IMFMediaSource::Start inicia la fuente de medios o busca una nueva posición. Una llamada a Start provoca una búsqueda cuando el estado anterior estaba en pausa o en ejecución, y se especifica una nueva hora de inicio. De lo contrario, el método Start provoca un inicio. Cuando finalice la operación Start , envíe los siguientes eventos.
- Envíe un evento MENewStream para cada nueva secuencia, es decir, cada secuencia que se deseleccionó anteriormente y ahora está seleccionada. Los datos del evento son un puntero a la secuencia.
- Envíe un evento MEUpdatedStream para cada secuencia que se seleccionó anteriormente y todavía está seleccionada. Los datos del evento son un puntero a la secuencia. (No envíe un evento para secuencias deseleccionada).
- Si el origen está buscando, envíe un evento MESourceSeeked . De lo contrario, envíe un evento MESourceStarted . Los datos del evento son la hora de inicio especificada en el método Start . Para el evento MESourceStarted, si la hora de inicio es VT_EMPTY, establezca el atributo MF_EVENT_SOURCE_ACTUAL_START en el evento. El valor del atributo es la hora de inicio real.
- Para cada secuencia, si el origen está buscando, envíe un evento MEStreamSeeked . De lo contrario, envíe un evento MEStreamStarted . Los datos del evento son la hora de inicio. (El origen multimedia puede poner en cola un evento en la secuencia mediante una llamada al método IMFMediaEventGenerator::QueueEvent de la secuencia).
Cuando se deseleccione una secuencia, apague la secuencia. La secuencia no debe poner en cola más eventos en ese momento.
El formato de hora del método Start se da en el parámetro pguidTimeFormat . El formato de hora estándar, indicado por GUID_NULL, es de 100 nanosegundos. Un origen multimedia debe admitir este formato de hora.
Buscando
Al buscar, es posible que la posición inicial solicitada no se coloque en un límite de ejemplo exacto. Además, para el contenido comprimido, la posición inicial podría estar entre fotogramas clave. Una secuencia debe entregar muestras desde el punto más antiguo necesario para generar una muestra sin comprimir en la posición inicial solicitada. En el caso del vídeo, esto significa comenzar desde el fotograma clave anterior. La canalización es responsable de quitar los fotogramas adicionales del descodificador, de modo que la reproducción se inicie en el momento solicitado.
La hora de inicio dada en los eventos de origen (MESourceStarted, MESourceSeeked, MEStreamStarted y MEStreamSeeked) es la hora de inicio solicitada (el valor especificado en el método Start ), independientemente de la posición de inicio real.
Por ejemplo, supongamos que los primeros fotogramas de una secuencia de vídeo tienen las siguientes características:
Ejemplo | 1 | 2 | 3 | 4 |
---|---|---|---|---|
Time | 33 msec | 66 msec | 100 msec | 133 msec |
¿Fotograma clave? | Sí | No | No | Sí |
Si se llama al método Start con un valor de 100 milisegundos, el origen debe generar vídeo a partir del fotograma 1, el primer fotograma clave antes de esta vez. El evento de inicio seguirá indicando 100 milisegundos en los datos del evento.
Pausar el origen multimedia
El método IMFMediaSource::P ause pausa la fuente multimedia.
Mientras el origen está en pausa, una secuencia puede crear nuevos ejemplos y almacenarlos en una cola, pero la secuencia no entrega los ejemplos. Estas son algunas excepciones a esta regla:
- Los orígenes activos deben quitar los datos mientras están en pausa.
- Si el origen obtiene datos de una red, podría pausar el servidor.
Si el cliente llama a IMFMediaStream::RequestSample mientras el origen está en pausa, la solicitud también se pone en cola hasta que se vuelve a iniciar el origen. No se deben quitar las solicitudes.
La pausa solo se permite desde el estado iniciado. De lo contrario, Pause debe devolver MF_E_INVALID_STATE_TRANSITION.
Generación de datos de origen
Media Foundation usa un modelo de extracción, lo que significa que los flujos generan y entregan muestras en respuesta a las solicitudes de la canalización. Una secuencia puede entregar ejemplos cuando se ejecuta el origen multimedia y se selecciona la secuencia. Un flujo solo entrega datos cuando el cliente solicita un nuevo ejemplo.
Solicitudes de ejemplo
El cliente solicita un nuevo ejemplo llamando a IMFMediaStream::RequestSample. Esta es la secuencia de operaciones:
El cliente llama a IMFMediaStream::RequestSample. El argumento es un puntero a un objeto de token opcional que el cliente usa para realizar el seguimiento de la solicitud. El cliente implementa el token. Los tokens deben exponer la interfaz IUnknown . El cliente también puede pasar un puntero NULL en lugar de un token.
Si el cliente proporcionó un token, la secuencia multimedia llama a AddRef en el token y coloca el token en una primera cola de entrada y salida. El método devuelve y los pasos restantes se producen de forma asincrónica.
Cuando hay más datos disponibles, el flujo multimedia crea un nuevo ejemplo. (Este paso se describe con más detalle en la sección siguiente).
La secuencia multimedia extrae el primer token de la cola.
Si el token no es NULL, la secuencia de medios establece el atributo MFSampleExtension_Token en el ejemplo multimedia. El valor del atributo es un puntero al token.
La secuencia multimedia envía un evento MEMediaSample . Los datos del evento son un puntero a la interfaz IMFSample de la muestra.
Si el cliente proporcionó un token, la secuencia multimedia llama a Release en el objeto token.
Si el flujo multimedia no puede cumplir la solicitud RequestSample del cliente, extrae el token de la cola y llama a Release en el token, pero no envía un evento MEMediaSample .
El cliente puede usar el token para realizar un seguimiento del estado de la solicitud. Cuando el cliente recibe el evento MEMediaSample , puede obtener el token del ejemplo y hacer coincidirlo con la solicitud original. El cliente también puede usar el token para detectar si el origen multimedia quitó la solicitud. Si el recuento de referencias del token cae en cero y la secuencia multimedia no envía un evento MEMediaSample, significa que se quitó la solicitud.
En los pasos que se enumeran aquí se da por hecho que el método RequestSample se implementa como una operación asincrónica. Si el método es sincrónico, no es necesario colocar el token de solicitud en una cola. Sin embargo, si la generación de datos tarda mucho tiempo, se recomienda un enfoque asincrónico, por ejemplo, si el origen lee los datos de una secuencia de bytes.
La secuencia es responsable de almacenar en búfer los datos que se acumulan entre las llamadas a RequestSample.
Cuando la secuencia multimedia llega al final de la secuencia, envía un evento MEEndOfStream después del último ejemplo. Una vez finalizada cada secuencia, el origen multimedia envía un evento MEEndOfPresentation . Una vez que una secuencia multimedia envía el evento MEEndOfStream, el método RequestSample devuelve MF_E_END_OF_STREAM hasta que se reinicia el origen.
Asignar ejemplos
Cuando la secuencia está lista para rellenar una solicitud de ejemplo pendiente, crea un nuevo ejemplo y agrega uno o varios búferes multimedia al ejemplo. Para obtener más información sobre cómo crear búferes multimedia, consulte Búferes multimedia.
La secuencia debe establecer la marca de tiempo y la duración, si se conoce. La marca de tiempo es relativa al origen. En la mayoría de los casos, el inicio del contenido corresponde a una marca de tiempo de cero. Por ejemplo, si el origen lee desde un archivo multimedia, el inicio del archivo tendría una marca de tiempo de cero.
La marca de tiempo del ejemplo no es necesariamente igual al tiempo de presentación. La sesión multimedia se traduce de la hora de origen a la hora de presentación. Para los datos comprimidos, el flujo debe generar datos a partir del fotograma clave más cercano antes de la hora de inicio. Esto permite al descodificador entregar el marco que aparece en la hora de inicio solicitada. (De lo contrario, el descodificador tendría que esperar hasta el siguiente fotograma clave).
Si la velocidad de reproducción es más rápida o más lenta que 1,0, la canalización ajusta la velocidad del reloj de presentación. El origen no ajusta las marcas de tiempo en muestras.
El origen puede establecer información adicional sobre el ejemplo estableciendo atributos. Para obtener una lista de atributos de ejemplo, vea Atributos de ejemplo.
Huecos en la secuencia
Si una secuencia contiene un intervalo de longitud significativa, se recomienda que la secuencia envíe un evento MEStreamTick . Este evento notifica al cliente que falta un ejemplo. Los datos del evento son la marca de tiempo de la muestra que falta, en unidades de 100 nanosegundos (VT_I8). Este evento puede guardar los componentes de nivel inferior en espera de ejemplos que no lleguen. La secuencia puede enviar tantos eventos MEStreamTick como sea necesario para abarcar la brecha en la secuencia.
Apagar el origen multimedia
Cuando el cliente haya terminado de usar el origen multimedia, llama a IMFMediaSource::Shutdown. Dentro de este método, el origen del medio debe interrumpir los recuentos de referencia circulares. Normalmente, habrá referencias circulares entre el origen multimedia y las secuencias multimedia.
Si usa la cola de eventos para implementar IMFMediaEventGenerator, llame a IMFMediaEventQueue::Shutdown en la cola de eventos. Este método apaga la cola de eventos y señala a cualquier llamador que esté esperando un evento.
Después del apagado, todos los métodos del origen devuelven MF_E_SHUTDOWN, a excepción de los métodos IUnknown .
Orígenes activos
A partir de Windows 7, Media Foundation admite automáticamente dispositivos de captura de audio y vídeo. En el caso del vídeo, el dispositivo debe proporcionar un minidriver de streaming de kernel (KS) en la categoría de captura de vídeo. Media Foundation usa la ruta de acceso de PnP para enumerar el dispositivo. En el caso del audio, Media Foundation usa la API de dispositivo multimedia de Windows (MMDevice) para enumerar los dispositivos de punto de conexión de audio. Si el dispositivo cumple estos criterios, no es necesario implementar un origen multimedia personalizado.
Sin embargo, es posible que quiera implementar un origen multimedia personalizado para algún otro tipo de dispositivo u otro origen de datos activo. Solo hay algunas diferencias entre un origen en directo y otros orígenes multimedia:
- En el método IMFMediaSource::GetCharacteristics , devuelva la marca MFMEDIASOURCE_IS_LIVE .
- La primera muestra debe tener una marca de tiempo de cero.
- Los eventos y los estados de streaming se controlan igual que los orígenes multimedia, a excepción del estado en pausa.
- Mientras está en pausa, no ponga en cola ejemplos. Quite los datos que se generan mientras se pausan.
- Normalmente, los orígenes dinámicos no admiten la búsqueda, el juego inverso o el control de velocidad.
Temas relacionados