La superposición de texto FFmpeg agrega valores de sensor a la transmisión de video

Estoy usando una cámara externa con ffmpeg para adquirir transmisión en vivo bajo el agua. Ahora quiero agregar algunos valores dinámicos (superposición de texto) sobre la transmisión de video y volver a transmitirlos a algún proveedor externo como youtube en vivo... Mis valores son de diferentes sensores (temperatura, oxígeno, salinidad, etc.) y esos valores deben estar incrustados en la transmisión de video.

¿Cuál es la forma correcta o "mejor" o "correcta" de hacer esto?

Dado que esto tiene que hacerse en una transmisión en vivo, use varios filtros de texto dibujado que lean archivos de texto individuales (actualizados) con el filtro configurado para recargar esos archivos.
¿Por qué hacerlo de la manera difícil? 'No probé este método todavía', pero puede usar .m3u8archivos continuos, digamos dos imágenes que obligarán ffmpega cargar continuamente estas imágenes, para que pueda cambiar/reemplazar/actualizar este archivo de imágenes y ffpmegse cargará ellos rapido

Respuestas (1)

Esta pregunta es un poco similar a Estoy tratando de agregar tabulaciones de guitarra a un video musical, ¿conoces algún software para hacerlo?

En primer lugar, ¿en qué formato sus datos, qué protocolo utilizan sus sensores? Supongo, ¿hay algún software de código cerrado y protocolo propietario para sus sensores? Obviamente, necesita un software que pueda leer este formato/protocolo de datos. Si está creando su propio sistema con microcontroladores, intente encontrar un protocolo abierto y utilizable para los datos. Es muy difícil encontrar protocolos abiertos con la funcionalidad necesaria.

En este punto, supongo, encontraste algún protocolo apropiado. Por ejemplo, JSON con campos personalizados. Ahora intente encontrar/escribir software, que lo usará.

Una forma posible: escriba una aplicación web, que mostrará la transmisión de video en su navegador, cargará datos de sensores y mostrará una superposición divertida. Luego, simplemente tome un video de su pantalla y transmítalo a YouTube o cualquier otro servicio. Esta es una forma "sucia", pero funcionará.

Otra forma: escriba un filtro personalizado en ffmpeg. Puede usar ass-renderer como referencia sobre cómo agregar texto en la imagen. Simplemente agregue datos de lectura de sus sensores y su tarea completada.


Escribir filtros de video rápidos y sucios

A veces necesitamos filtrar el video de alguna manera, tal vez poner texto o gráfico encima. Escriba una aplicación completa que descomprima el flujo de video, imbuya la imagen con nuevos elementos o cambie la imagen en sí, y luego comprima el flujo de nuevo, algo difícil. Hoy aprenderemos cómo hacer este tipo de aplicaciones de forma rápida y sucia sin saber cómo codificar el video en general.

Para empezar, recuerda que las imágenes están formadas por filas y columnas de puntos, a los que llamamos píxeles. Cada punto consta de 3 o 4 componentes, generalmente señales rojas, verdes y azules, y en ocasiones hay un canal alfa. Por lo tanto, para cambiar 1 punto de la imagen, necesitamos cambiar 3-4 componentes (esto suele ser 3-4 bytes). Entonces, para cambiar la imagen completa, necesitamos cambiar todas las filas y columnas, en cada uno de los 3-4 elementos y modificarlos de alguna manera, guardar de nuevo. Por ejemplo, si tenemos una imagen de 256x192 píxeles en formato RGB24, tendrá 49152 píxeles y 147456 componentes de color (bytes).

Por lo tanto, solo necesitamos leer fragmentos de 147456 bytes, modificarlos de alguna manera y volver a escribirlos. ¡Es todo! ¡No se requieren bibliotecas ni algoritmos complicados! ¿De dónde obtenemos estos bytes? ¡Y podemos obtenerlos con la maravillosa utilidad ffmpeg y su igualmente maravilloso modo rawvideo, cuyo escape le daremos a stdout y recibiremos en stdin su aplicación!

Escribamos la aplicación más simple que cambiará ligeramente la imagen:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

int main () {

// allocate variables and buffer

uint8_t *pixels = malloc (147456);
uint8_t *pix;
int q;

while (1) {

// read frame
if (fread (pixels, 1,147456, stdin) <= 0) {break;}

// process image
pix = pixels;
for (q = 0; q <49152; q ++) {
*pix++ = *pix * 2; // multiple red to 2
*pix++ = *pix + 120; // shift green channel
*pix++ = *pix + q / 10; // lines in blue channel
}

// write frame back
fwrite (pixels, 1,147456, stdout);
}

return EXIT_SUCCESS;
}

¡Sí, eso es todo! Por supuesto, aquí todas las constantes están codificadas, ¡nunca lo haga en proyectos reales!

Ahora, ejecuta esto y sube un video aquí:

ffmpeg -i video.mp4 -s 256x192 -f rawvideo -pix_fmt rgb24 - | ./a.out | ffmpeg -s 256x192 -f rawvideo -pix_fmt rgb24 -i - -y out.mp4

Y obtenemos el siguiente resultado:

ingrese la descripción de la imagen aquí 2.gif

Analicemos qué parámetros participaron en esta línea:

ffmpeg -i video.mp4 -s 256x192 -f rawvideo -pix_fmt rgb24 -

Aquí leemos del archivo video.mp4, cambiamos el tamaño de la imagen 256x192(si su video ya tiene un tamaño de 256x192, entonces no puede hacer esto), luego especificamos que debe convertirse al rgb24espacio de color (si aún no está en él, ¿qué para puede gastar bastantes recursos), y el resultado que necesitamos en forma de video sin comprimir rawvideo, el resultado que grabamos en -, es decir, en stdout.

| ./a.out |

Y esta es nuestra aplicación. Los "tubos" verticales significan que tomará datos de la aplicación anterior y los transferirá a la siguiente

ffmpeg -s 256x192 -f rawvideo -pix_fmt rgb24 -i - -y out.mp4

Aquí indicamos que la entrada de este ffmpeg será video sin comprimir en rawvideoformato, tamaño 256x192y rgb24espacio de color. También es posible que deba especificar fps, ya que se pierde con dicha conversión. Escribiremos la salida en out.mp4, e incluso si dicho archivo ya existe, el -yparámetro es responsable de esto.

Aquí hay un ejemplo muy simple de cómo cambiar la imagen, pero puede superponer texto, otras imágenes y cualquier otra cosa. Por supuesto, es mejor escribir una aplicación completa, o al menos parchear el filtro ya existente al estado deseado, esta será una solución más correcta. Pero si necesita una solución que funcione, aunque no quiera escribir mucho código, esta es la solución para usted.

Puedo usar JSON o XML para pasar los datos de mi sensor... o cualquier otro formato. El problema que tengo es solo cómo pasar datos a ffmpeg.
he encontrado aquí el ejemplo: s55ma.radioamater.si/2017/08/04/…
Aquí debes escribir tu texto en archivo cada... cuadro! Sí, esto puede funcionar, pero es bastante sucio para mí. No me gustan esos archivos tmp y desperdiciar CPU. Por lo tanto, sugiero escribir un filtro simple para ello.
Han probado con Java. Hice un proceso de subproceso simple que escribe algunos valores en el archivo. Cuando se cierra el archivo, ejecuto el método Files.move con StandardCopyOption.ATOMIC_MOVE. Sé que está sucio, pero no tengo mucha experiencia en cómo hacer algún complemento (si tiene alguna buena referencia (enlace) por favor ayúdenme... La otra opción es usar OBS Studio pero debo verificar si se puede ejecutar desde la línea de comando (terminal) (sin GUI).
¿Tienes alguna experiencia con C o C++? Puede escribir su propio filtro en las tuberías, como ffmpeg -i _SOURCE_ -f rawvideo -pix_fmt rgb32 - | ./your_app | ffmpeg -f rawvideo -pix_fmt rgb32 -i - rtmp://broadcast.to.server/. Esto pasará marcos a su aplicación a través de stdin, luego puede dibujar en él y pasar mapas de bits a stdout, donde la nueva instancia de ffmpeg lo codificará y guardará en un archivo/transmisión.
Me gustaría intentarlo, pero primero necesito ver algún ejemplo o escribir un blog al respecto. (He hecho algún proyecto también en C/C++ (pasado)).. ;)
Hoy-mañana escribiré uno
¡Gracias! por favor infórmeme para que pueda verificar su código. Por ahora, la única forma que tengo es usar FFmpeg con drawtext del archivo que se actualiza desde Java. O usar OBS studio ( obsproject.com/download ) pero necesito verificar si Puedo ejecutarlo desde la ventana de la terminal (sin interfaz gráfica de usuario).
Creé un ejemplo con C, es muy simple.