Jul 16, 2011

FFmpeg + QtMultimedia + Pipes

Resulta que una semana mas o menos después de realizar el tutorial Grabando Audio desde el micrófono con FFmpeg + QtMultimedia, tocaron actualizaciones en ArchLinux, y entre una de esas actualizaciones se encontraba FFmpeg, y como era de esperarse, la API de FFmpeg no es en lo absoluto estable, siempre está en constante cambio, y con cada nueva versión de FFmpeg siempre hay que hacer nuevas correcciones a nuestro programa si usamos su API, lo que se vuelve un dolor de cabeza terrible mantener un programa basado en su API.
Esto yo ya lo sabía de antemano, pues he investigado mucho este tema, incluso en la misma web de FFmpeg recomiendan que se incluya el código fuente del snapshot que se basará el programa para funcionar, esto es para evitar justamente estos problemas. Y yo por cabeza-dura pasé por alto ésta advertencia :(
Pero justamente por ser tan cabeza-dura, y porque realmente lo necesito para un programa que estoy desarrollando ;) , fue que logre encontrar una muy buena alternativa a este problema, y lo comparto con ustedes :)

El truco consiste en pasar los frames de audio a FFmpeg através de tuberías.
Según Wikipedia:

Tubería (informática)


En informática, una tubería (pipe o '|') consiste en una cadena de procesos conectados de forma tal que la salida de cada elemento de la cadena es la entrada del próximo. Es común el uso de buffer de datos entre elementos consecutivos.
Las tuberías (pipes) están implementadas en forma muy eficiente en los sistemas operativos multitarea, iniciando todos los procesos al mismo tiempo, y atendiendo automáticamente los requerimientos de lectura de datos para cada proceso cuando los datos son escritos por el proceso anterior. De esta manera el planificador de corto plazo va a dar el uso de la CPU a cada proceso a medida que pueda ejecutarse minimizando los tiempos muertos.
Para mejorar el rendimiento, la mayoría de los sistemas operativos implementan las tuberías usando buffers, lo que permite al proceso proveedor generar más datos que lo que el proceso consumidor puede atender inmediatamente.
En nuestro caso usaremos las llamadas "Named Pipes", se traduciría como "Tuberías nombradas", personalmente no me gusta para nada esta traducción, me suena muy extraño este nombre :P . Según Wikipedia:

Tubería nombrada


En ingeniería de software, una tubería nombrada (named pipe en inglés), también llamada FIFO por su comportamiento, es una extensión del concepto tradicional de tuberías utilizado en los Sistemas operativos POSIX, y es uno de los métodos de Comunicación entre procesos (IPC). Este concepto también se encuentra en Windows, si bien implementado con otra semántica.
Una tubería (pipe) tradicional no tiene "nombre" porque existe anónimamente mientras se está ejecutando el proceso. Una named Pipe es creada explícitamente por un comando del sistema operativo y persiste a posteriori de la finalización del proceso y debe ser borrada una vez que no va a seguir siendo utilizada.
En resumen, al menos en sistemas tipo Unix, una Named Pipe se crea y se utiliza como un archivo común y corriente, pero con algunas excepciones:
  • Los datos que se envían a un archivo tradicional son almacenados de forma permanente en algún medio físico (pej. el disco duro, un pendrive, etc.), por el contrario, una tubería funciona como un puente para transportar datos de un programa a otro, una vez finalizado el transporte de datos, absolutamente ninguno de estos datos quedará almacenado en ningún medio físico, por lo tanto esta tubería no consumirá espacio en el disco duro ni en ningún otro medio.
  • Dado que una Named Pipe está pensada para pasar datos de un programa a otro, El programa que abra dicha tubería para escritura (Emisor) quedará esperando hasta que otro programa abra esa tubería para lectura (Receptor). El programa Emisor quedará bloqueado hasta que el programa Receptor lea un paquete de datos, El programa Receptor quedará bloqueado hasta que el programa Emisor envíe un paquete de datos, en ambos casos, la comunicación finalizará cuando cualquiera de los dos cierre la tubería
  • La comunicación con una tubería es asíncrona, lo que quiere decir que es imposible realizar operaciones de retroceso o avance (seek) sobre una tubería
Finalmente en el blog de Ian Baldwin podemos encontrar la solución al problema, en el ejemplo original, Ian envía frames de video através de la tubería, pero podemos aplicar el mismo proceso para enviar frames de audio, sería mas o menos así:
# ...
# Inicializar dispositivo de audio.
# ...

mkfifo video_pipe.tmp

ffmpeg -y \
       -f s16le -ac 2 -ar 8000 -i video_pipe.tmp \
       -acodec libvorbis \
       -f ogg output.ogg

# ...
# Abrir la tubería, comenzar captura de audio y enviar frames a la tubería.
# ...
Algunas de las ventajas con las que podemos encontrarnos en este nuevo esquema son:
  • Nuestro programa será independiente de la versión de FFmpeg estemos usando.
  • El programa ocupará mucho menos espacio en disco que si lo distribuyéramos con nuestra propia versión de FFmpeg.
  • Dividimos el trabajo de mantenimiento, Nosotros nos ocupamos solo de nuestro programa, mientras que el equipo de FFmpeg se ocupa del suyo.

Código fuente


Y finalmente el código fuente completo del ejemplo:

Qt Audio Recorder 2

Enlaces de referencia


No comments:

Post a Comment