Transmisión de memoria
Como se describió anteriormente, el objeto roMediaStreamer proporciona un medio para especificar una única canalización flexible de procesamiento multimedia. Sin embargo, la canalización está limitada a tener una sola entrada y una sola salida. La función transmisión de memoria agrega un medio para bifurcar el flujo de datos de modo que se puedan crear múltiples salidas y realizar más de un hilo de procesamiento.
Tenga en cuenta que el memory streaming es especialmente importante al servir medios codificados en vivo, como HDMI® Input. El memory streaming garantiza que solo se necesite un único codificador para distribuir un flujo codificado en vivo a múltiples clientes.
HTTP unicast múltiple
Para transmitir un flujo fuente mediante unicast a múltiples clientes, envíe la fuente (en este caso, HDMI Input codificada) a un flujo de memoria:
m = CreateObject("roMediaStreamer")
m.SetPipeline("hdmi:, encoder:, mem:/livehdmi")
m.Start()Ahora, una gran cantidad de clientes puede recibir el mismo flujo denominado "livehdmi" (el nombre es arbitrario, pero no debe entrar en conflicto con ningún otro flujo de memoria).
Cuando un cliente accede a la siguiente URL, el código del servidor multimedia HTTP crea una instancia independiente de roMediaServer que lee desde la fuente mem:/livehdmi/stream.ts y la reenvía al socket HTTP:
http://IP_address:port/mem:/livehdmi/stream.ts
Tenga en cuenta que /stream.ts debe agregarse al nombre del flujo de memoria para indicar que se debe utilizar el flujo completo.
En la instancia anterior, el código del media streamer creará realmente el componente fuente memsimple:/livehdmi/stream.ts porque utiliza menos recursos y es más eficiente.
Una vez que se ha creado el flujo de memoria, también puede transmitirse simultáneamente mediante multicast utilizando otra instancia de Media Streamer:
m1 = CreateObject("roMediaStreamer")
m1.SetPipeline("memsimple:/livehdmi/stream.ts,rtpsimple://239.192.0.0:5004/")
m1.Start()mem: y memsimple:
Al igual que con ciertos otros componentes, existe una versión "simple" y una "no simple" del memory streaming. La versión simple (memsimple:) solo puede utilizarse en una canalización con otros componentes simples, aunque los flujos de memoria simples pueden leer de flujos de memoria no simples mem: (como se muestra arriba, donde el componente memsimple:/livehdmi lee del componente mem:/livehdmi). Sin embargo, lo contrario no es posible: el componente fuente mem: no puede utilizarse para leer desde un flujo de memoria que se creó con el componente de destino memsimple: .
Debido a que los flujos de memoria simples no están indexados, no pueden admitir operaciones de transmisión HLS downstream (otros componentes no recibirán información sobre los segmentos HLS).
Como ocurre con otros componentes "simple", los flujos de memoria simples deben utilizarse siempre que sea posible porque consumen menos recursos.
HLS unicast múltiple
El unicast múltiple HLS funciona de manera similar al ejemplo de multicast HTTP proporcionado anteriormente, pero con una excepción: los filtros de indexación de flujo solo funcionan en flujos leídos en el procesador de flujos de transporte, no en flujos leídos en el codificador (ambos manejados por el componente mem:). Como resultado, los flujos codificados como HDMI Input deben pasarse al componente mem: dos veces antes de que puedan transmitirse mediante multicast. Esto se logra fácilmente utilizando dos llamadas a SetPipeline() :
m = CreateObject("roMediaStreamer")
m1 = CreateObject("roMediaStreamer")
m.SetPipeline("hdmi:,encoder:,mem:/hdmi_unindexed?size=5")
m1.SetPipeline("mem:/hdmi_unindexed/stream.ts ,mem:/hdmi_indexed?size=30&duration=5")
m.Start()
m1.Start()Tenga en cuenta que debe especificarse un búfer de memoria más grande (30 MB en esta instancia) para el segundo componente mem: porque debe contener al menos cinco segmentos completos de 5 segundos en todo momento. Los clientes generalmente requieren 5 segmentos completos en todo momento para los flujos HLS, por lo que a menudo necesitarán esperar al menos 25 segundos antes de que el flujo pueda reproducirse correctamente.
Los clientes pueden acceder a los flujos HLS utilizando la siguiente URL:
http://IP_address:port/mem:/hdmi_indexed/index.m3u8
Al igual que el multicast HTTP, el media streamer generará instancias adicionales de roMediaStreamer para cada cliente que se conecte. Además de los clientes HLS, los clientes HTTP y RTSP también pueden conectarse al flujo indexado utilizando las siguientes URL:
HTTP
http://IP_address:port/mem:/hdmi_indexed/stream.ts
RTSP
rtsp://IP_address:port/mem:/hdmi_indexed/stream.ts
El flujo indexado también puede transmitirse mediante multicast por otra instancia de roMediaStreamer .
Acceder a un flujo de memoria indexado
Como se muestra en ejemplos anteriores, agregar stream.ts al identificador del flujo de memoria denota el búfer completo, mientras que agregar index.m3u8 a un flujo indexado (HLS) denota el archivo de índice completo. De forma similar, agregar el nombre de un segmento listado en el archivo de índice accederá a ese segmento durante el tiempo de vida de dicho segmento en el búfer del flujo de memoria. Por ejemplo, si el archivo de índice lista un segmento llamado 000179.ts como disponible en el componente mem:/componente de transmisión en vivo, entonces el siguiente componente de origen puede utilizarse para recuperar ese segmento:
mem:/livestream/000179.ts
El componente memsimple: también puede utilizarse para recuperar el segmento.
Ritmo del flujo de memoria
El flujo de datos hacia el flujo de memoria siempre se sincroniza en tiempo real para dar tiempo a los clientes de lectura a mantenerse al día. Una instancia de roMediaStreamer que está escribiendo nunca esperará a ninguno de los clientes de lectura; si algún cliente se queda demasiado atrás (lo cual se detecta cuando el extremo de escritura del FIFO sobrepasa el extremo de lectura del cliente), el cliente abortará y emitirá un mensaje EVENT_EOS_ERROR.
Debido a esta limitación, es importante tener en cuenta lo siguiente: si un flujo de memoria se utiliza para solucionar el hecho de que los datos no pueden pasarse directamente de un codificador a un decodificador (como en el siguiente ejemplo), entonces el procesamiento no puede realizarse más rápido que en tiempo real.
Ejemplo
m1 = CreateObject("roMediaStreamer")
m2 = CreateObject("roMediaStreamer")
m1.SetPipeline("hdmi:,encoder:,mem:/hdmi")
m2.SetPipeline("mem:/hdmi/stream.ts,decoder:,file:///file.ts")
m1.Start()
m2.Start()Estados del flujo de memoria
Un flujo de memoria solo se crea cuando el Media Streamer que lo nombra como destino está al menos en el estado CONNECTED. Esto significa que es posible conectar el pipeline (usando Connect()) que crea el flujo de memoria pero no iniciarlo. Se puede crear cualquier cantidad de Media Streamers que lean desde un flujo de memoria (e incluso iniciarlos) antes de que el Media Streamer original se inicie, comenzando el flujo de datos hacia el flujo de memoria.
Consulte Máquina de estados de Media StreamerMedia Streamer State Machine para obtener más información sobre los estados de roMediaStreamer .
Cifrado y protección contra copia
En términos generales, una instancia de roMediaStreamer que lee desde un flujo de memoria adoptará el mismo cifrado/protección contra copia que la instancia asociada de roMediaStreamer que está escribiendo en él. Las reglas específicas son las siguientes:
- Escritor simple: Un destino memsimple: no puede marcarse como que requiere protección (ni puede recibir dicho flujo).
- Lector simple: Un origen memsimple: solo leerá desde un flujo de memoria que se marcó como no cifrado (sin requerir protección) cuando se creó.
- Escritor no simple: Un destino mem: se marcará como que requiere protección cuando se cree de acuerdo con el origen del pipeline. Si un flujo pasa a estar protegido más adelante, continuará funcionando si inicialmente se marcó como que requiere protección (opcionalmente con el parámetro cifrar ), de lo contrario se detendrá.
- Lector no simple: Un origen mem: hereda el estado de protección de su escritor asociado y, por lo tanto, su salida finalmente requerirá protección HDCP o DTCP si el origen se marcó de manera similar.