¿Cómo mostrar una imagen estática si el flujo de entrada termina usando ffmpeg?

Recibo una transmisión a través de la red con el siguiente comando ffmpeg:

ffmpeg -i rtmp://server:port/input.stream -f flv rtmp://server2:port/output.stream

Cuando el flujo de entrada se detiene, quiero mostrar una imagen fija. Cuando el flujo de entrada continúa, quiero seguir mostrando el flujo de entrada. He intentado esto:

ffmpeg -loop 1 -i Error.png -i rtmp://server:port/input.stream -filter_complex "[0:v][1:v] overlay=0:0" -f flv rtmp://server2:port/output.stream

Eso funciona, excepto cuando la transmisión de video de entrada se detiene, sigue mostrando el último cuadro recibido de la transmisión. Quiero que muestre el archivo .png (es decir, la entrada de video se vuelve transparente).

¿Qué sucede cuando cambia su filtro de "[0:v][1:v] overlay=0:0" a "[0:v][1:v] overlay=0:0:repeatlast=0"? repeatlast es una opción para la superposición. ffmpeg.org/ffmpeg-all.html#overlay-1
Una combinación de mkfifo y rtmp podría ser una especie de solución

Respuestas (1)

TL; DR : Nada simple. Ambas soluciones utilizan un relé y no es adecuado para la producción real.


En realidad, solo tienes dos posibilidades, y ambas son feas.

No existe absolutamente ningún software de código abierto capaz de manejar una transmisión no permanente (GStreamer+forks, FFmpeg, VLC, MPlayer). Todos y cada uno de ellos tienen el mismo comportamiento: el último cuadro sigue siendo visible y todo se detiene hasta que vuelven los datos.

Opción 1 — Tunelización + caché

Necesita dos FFmpeg en ejecución y un script que use FFplay.

El primer FFmpeg extrae la transmisión RTMP. La salida es un puerto local y el protocolo debe basarse en MPEG-TS. Es mejor si la entrada está ajustada para la latencia más baja.

Además, debe optimizar cómo se inicia FFmpeg: sin análisis de la transmisión (establezca los fps en la línea de comando), inicio anticipado, etc.

El segundo FFmpeg extrae el flujo MPEG-TS local y transcodifica el flujo a un nuevo RTMP. Debe volver a codificarlo con x264, porque los paquetes de video se romperán en el primer cambio (por lo que necesita una mejor calidad para su transmisión original). Debe aumentar la latencia de entrada: el valor predeterminado es 3 s para FFmpeg, pero necesita algo así como 8 s. Se puede reducir, pero solo después de que realmente entiendas lo que está pasando y dónde está tu margen.

La magia está con FFplay.
Tiene un script en ejecución, donde FFmpeg lee la transmisión RTMP original. Cuando la transmisión no tiene más datos, FFplay envía un error y se detiene. Luego, el script elimina la primera instancia de FFmpeg y lanza una nueva. Ese FFmpeg es la transmisión "fuera de línea". Independientemente de la entrada que desee, debe codificarla en x264 MPEG-TS, en el puerto local. Y con los mismos fps/tamaño que tu transmisión normal.

Durante este tiempo, el segundo FFmpeg sigue reproduciendo su caché de entrada. Entonces, los 4 o 5 segundos para que se inicie el FFmpeg "fuera de línea" no es un problema.

En el bucle real del script, necesita un nuevo FFplay. Cuando su transmisión regresa, elimina el FFmpeg fuera de línea y reinicia el normal.

El caché de entrada hace el trabajo y la recodificación limpia los paquetes de video rotos.

Funciona, pero no es una solución adecuada, como una superposición en FFmpeg, y FFmpeg no se detiene cuando una entrada no responde/falta/vacía.

Opción 2 - Software OpenBroadcaster

Si no tengo un guión completo para publicar aquí, es porque encontré una nueva solución: use OBS en el servidor, capture la transmisión original, coloque su imagen sin conexión detrás y envíe la transmisión a su servidor de distribución.

Pero, hay una trampa, OBS necesita OpenGL 3.1 (2?) y una computadora de escritorio. Entonces, necesita una PC y GPU reales, o virtualizar el escritorio con ESXI (no sé si VirtualBox hace que una GPU virtual sea compatible con OpenGL 3.1).

La lógica es la misma, pero más amigable.

La única buena solución

FFmpeg es capaz de manejar todo en una sola instancia. Si usa superposiciones, puede tener la capa fuera de línea y la transmisión original en la parte superior. FFmpeg incluso sabe cómo reiniciar una transmisión cuando se vuelve a publicar.

Pero, en realidad, FFmpeg detiene todo cuando una entrada está fuera de línea/falta/vacía.

Lo único que falta es una opción para cambiar el comportamiento de FFmpeg en una entrada.

Probé la lista de correo de desarrollo, sin respuesta. Lo mismo para mis predecesores. La "comunidad" de desarrolladores de FFmpeg no es amigable, se basa en herramientas antiguas (¡es mejor que no critiques el uso de una lista de correo!) y es conservadora.

Si alguien tiene una mejor solución, un programa mágico para hacer un conmutador fuera de línea simple, es realmente necesario;)