Script bash para rotar un vídeo MJPEG sin pérdida

Publicado por el miércoles 16 de julio de 2014 en Amigos, bash, Blogs, lossless, Scripts, Software, Software libre, Útil | 2 comentarios


Esta mañana a Estefanía se le ocurrió pedirme un favor. Ayer me estuvo resolviendo unas dudas sobre mi próximo viaje a Londres y se ve que a raíz de eso se acordó de mi condición de geek/nerd o comúnmente llamado friki en España. Quería que le rotase un vídeo filmado con móvil, que no había forma de insertarlo correctamente. Y aquí empieza la historieta porque una vez más entró en acción mi obsesión afición por la edición lossless o sin pérdida.

Esta manía mía también tiene su explicación en que a la vez que desarrollo esta solución aprendo muchas cosas que me serán útiles en el futuro. Tampoco encontré una solución gratuita ya hecha que funcionase, así que ya tienes a tu disposición esta 🙂

¿Qué es la edición lossless?

Tiene su porqué en el hecho de que a principios de los 90 (y aun hoy) la velocidad de acceso a Internet y los medios de almacenamiento de información (ópticos, discos duros…) eran limitados y se tienen que aplicar técnicas de compresión que se aprovechan de la repetición de patrones y de defectos en la visión y audición humana para eliminar información, de las imágenes en nuestro caso.

Pero muchas veces, para que el ahorro en tiempo y espacio sea aun mayor se aplica un nivel de compresión (es seleccionable) más allá del límite que un perfeccionista puede tolerar.

El trabajo que he hecho viene a ser una operación de conservación o restauración de lienzos digital. ¿Tendrá que ver con que soy socio de RetroMallorca?

La solución óptima

Y un caso en el que se suele perder calidad es en la edición o conversión de unos formatos a otros, como hubiera pasado de haber usado otros sistemas con el vídeo de mi amiga. Me he tirado un buen rato creando el script que pego más abajo, y es una solución específica para el formato en que se encontraba el vídeo de Estefanía, el MJPEG (con contenedor MOV del Apple QuickTime), un formato diría ya en desuso que almacena el vídeo con cada fotograma mismamente como un fichero JPG, como el de una fotografía. Formatos más modernos como MPEG con todas sus versiones y WebM tienen en cuenta los fotogramas anteriores para almacenar solo la parte de la imagen que ha cambiado.

Esa técnica para ahorrar espacio es la causa, por cierto, de los errores que seguro que alguna vez has visto en el que objetos toman colores extraños y la imagen se ve defectuosa en general. He visto últimamente usar estos errores como recurso artístico en vídeos musicales, ya no saben qué inventar xD

El caso es que, debido a que en el formato MJPEG los fotogramas se almacenan enteros, he podido “clonarlos” en otro fichero rotados con una utilidad especial, todo ello de manera que la imagen original y la resultante no se diferencian ni en un solo píxel, salvo por el hecho de que está rotada.

El script

En definitiva mi script (programita) de bash (sirve para Unix/Linux, Mac OS X y Windows con una utilidad especial) lo que hace es:

  1. Extraer uno a uno los fotogramas JPG en una carpeta con ffmpeg.
  2. Rotarlos con jpegtran, que es una utilidad de optimización de tamaño (limpieza de metadatos de la cabecera, etc.), pero que también es capaz de operaciones sin pérdida, incluso recortado (!)
  3. Volver a ensamblar el vídeo, cogiendo el audio original, también con ffmpeg.

En mi caso también arreglé un problema de sincronización (al final resultó que involuntariamente, simplemente volviéndolo a ensamblar, parece que el formato en que grababa ese móvil no estaba muy bien hecho) y otro de ruido del audio mediante Audacity.

Para usarlo

  1. Instalar la utilidad de tratamiento de vídeo por línea de comandos FFMPEG. En Debian y derivados (Ubuntu p.e.): sudo apt-get install ffmpeg.
  2. Instalar jpegtran: sudo apt-get install libjpeg-progs.
  3. Pegar el script en un editor de texto.
  4. Grabarlo y darle permisos de ejecución (chmod +x fichero).
  5. Pasarle el vídeo como parámetro: rotarmjpeg video.avi

Aquí el retoño:

#!/bin/bash
# Rota un MJPEG sin pérdida de calidad
sinextension="${1/.*/}"
avi="$sinextension (corregido).avi"
mkdir extraido
mkdir rotado
ffmpeg -i "$1" -vcodec copy "extraido/temp_%04d.jpg"
cd extraido
for a in *.jpg; do
	jpegtran -rotate 90 "$a" > "../rotado/$a"
done
cd ..
avconv -y -i "$1" -i rotado/temp_%04d.jpg -c:v copy -r 15 -acodec copy -map 0:a:0 -map 1:v:0 -shortest "$avi"
# -r es la tasa de fotogramas
# -start_number 10 Empieza desde esa imagen/fotograma
# -f image2 Fuerza tipo de entrada
vlc "$avi"

# Esta fue la orden concreta para incluir el audio editado con Audacity
# avconv -y -i editado.wav -i rotado/Stefi_%04d.jpg -c:v copy -r 15 -acodec copy -map 0:a:0 -map 1:v:0 -shortest corregido.avi

2 comentarios

  1. De no haber sido por tu ayuda no hubiera podido publicarlo, así que muchísimas gracias. Eres un fenómeno, aunque eso ya te lo he dicho muchas veces 🙂

    Contestar
    • Es simplemente fruto de la afición, pero gracias. Tengo la esperanza de sacarle provecho a estas cosas realmente algún día xD

      Contestar

Publica un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *