Apuntes mientras aprendo sobre software y computadoras.

Computación

Guía práctica para la edición audiovisual con ffmpeg

Introducción:

Con esta frase le doy comienzo a la “Guía práctica para la edición audiovisual con ffmpeg”.

Existen muchas opciones disponibles para la edición de audio y video. Algunas de estas opciones son de software libre, otras no. Algunas de estas opciones son gratuitas, otras pueden comprarse y otras solo pueden usarse con un servicio pago de suscripción.

Pero entre todas estas opciones, pocas nos permiten realizar la totalidad del trabajo accediendo directamente a la terminal de nuestro sistema operativo.

No se necesita de una interaz gráfica (Graphical User Interface) para utlizar ffmpeg.

En este sentido, este software se distingue por su versatilidad, su velocidad y la posibilidad que presenta para automatizar tareas. Lo que en otros programas supone incontables pasos, aquí puede resolverse con la ejecución de un solo comando.

En el correr de estos párrafos voy a explicar algunas de las otras ventajas que supone comenzar a usar esta forma de trabajo.

Sin embargo, antes de continuar, creo que es bueno desarrollar tres conceptos administrativos a modo de introducción:

1- La idea central de esta página es el de aprender haciendo. No soy un experto en ffmpeg, simplemente soy una persona intentado aprender un poco de computación.

¿Qué significa esto? Quiere decir que esto no es un tutorial, es la transcripción de mi experiencia investigando sobre el software y haciendo experimentos para comprendelo.

Del mismo modo que siempre, si te interesa estudiar todo esto te invito a que me acompañes mientras investigo cosas nuevas.

Y no es la primera vez que hago una experiencia como esta, también escribí la:

  • Guía mínima para empezar con la termina de Linux
  • Guía inmediata para empezar con Arch Linux

Esto último es un poco de auto promoción desvergonzada.

2- ¿Qué significa automatizar tareas con ffmpeg? ¿Quiere decir que el programa puede editar un video por su cuenta mientras me relajo haciendo otras cosas?

No, no es para tanto. Bueno otra vez, no soy experto en el tema. Esta simplemente es una opinión impensada.

Más aun, ffmpeg parece haber sido creado para conseguir muchas cosas. Es una herramienta integral para trabajar con audiovisuales. Yo intento encarar este proyecto por el lado de la automatización de tareas, pero se podría encarar su aprendizaje desde cualquier otro ángulo.

Voy a intentar explicar esto.

Las opciones en ffmpeg son muchas. Por ejemplo, en teoría se puede usar sus técnicas para unir todos los videos en un directorio. O también se puede utilizar para cortar todos esos videos antes de unirlos, obteniendo el montaje artístico de un nuevo video por resultado.

Le dimos una serie detallada de instrucciones al programa sobre que hacer, y la devolución es el trabajo terminado.

Otras tareas parecen requerir menos decisiones de nuestra parte, por ejemplo la tarea de convertir archivos entre diferentes contenedores. Ejemplo, un video de .avi a .mp4 por decir algo. Eso podría llevar mucho tiempo si buscamos cada video individualmente, cuando con este programa podemos convertirlos rápido y sin dar vueltas.

Pero tener muchas opciones no significa que todas resulten en una idea fácil de poner en práctica. ¿Es posible editar una película de 90 minutos usando solamente ffmpeg? En principio si, pero para algo tan complejo tal vez resulte más fácil directamente utilizar un programa como Blender o Kdenlive.

En resumen, cuanto más repetitiva parezca una tarea, más parece brillar ffmpeg en la resolución del problema.

3- Estoy utilizando todo este software en un sistema operativo Linux. Sin embargo tener Linux no es indispensable, se puede usar ffmpeg en otros sistemas. Ejemplo, en Windows.

¿Importa todo eso para la lectura de este texto? La principal diferencia va a estar en que alguno de los comandos si van a ser específicos para Linux. Pero solamente los comandos directamente involucrados con el sistema, por ejemplo los de la terminal bash.

Confío en que el resto de los comandos, los que involucran directamente a ffmpeg, van a poder replicarse sin problemas en cualquier computadora. O bueno, solo para cubrirme, en casi cualquier computadora. En algunos casos vas a necesitar encontrar algún comando equivalente.

Ya no quiero extender más la introducción. Por eso, voy a empezar primero averiguando…

¿Cómo instalar ffmpeg?

Bueno, una vez más… eso depende del sistema operativo.

En Linux, por ejemplo de la vertiente Debian (o distribuciones que usen el comando apt para manejar paquetes), se puede hacer la instalación con:

sudo apt install ffmpeg

De ese modo es como yo lo instalé en Linux Mint.

De necesitar otras opciones, en este link oficial del sitio de ffmpeg se pueden encontrar los archivos ejecutables para descargar.

¿Qué es ffmpeg?

Bueno, tal vez el mejor lugar para empezar este camino sea averiguando qué es ffmpeg. E incluso si ya conocemos del software, siempre podemos aprender algo más de su funcionamiento prestando atención a la documentación.

A partir de ahora voy a leer del manual de ffmpeg, la versión en Inglés. Voy a citar las partes que me parezcan más interesantes, acompañadas de mi propia traducción hogareña.

Accedo al manual en Linux con el comando:

man ffmpeg

Y lo primero que encuentro es:

NAME
ffmpeg – ffmpeg video converter

Manual de ffmpeg

Bueno, bien, esto es: ffmpeg convertidor de video. La especialidad de este software es la de convertir video.

Luego sigue:

ffmpeg is a very fast video and audio converter that can also grab from a live audio/video source. It can also convert between arbitrary sample rates and resize video on the fly with a high quality polyphase filter.

manual de ffmpeg

De esto creo que lo más importante es:

  • Si, ffmpeg es un software para convertir audio y video.
  • Puede trabajar también con audio y video de una fuente “en vivo”. Por ejemplo, se puede hacer live streaming de video usando ffmpeg.
  • Se puede convertir (re-codificar) los archivos determinando diferentes sample rates (tasas de muestro) y dimensiones de video.

Pero lo que sigue a continuación es muy importante. El manual comienza a decir en qué forma tenemos que construir la sintaxis de los comandos:

ffmpeg reads from an arbitrary number of input «files» (which can be regular files, pipes, network streams, grabbing devices, etc.), specified by the «-i» option, and writes to an arbitrary number of output «files», which are specified by a plain output url. Anything found on the command line which cannot be interpreted as an option is considered to be an output url.

manual de ffmpeg

Y de esto entiendo lo siguiente:

  • ffmpeg entiende de “archivos de entrada” (input) y “archivos de salida” (output). Yo le doy uno o más inputs y me devuelve uno o más outputs.
  • Estos archivos pueden responder a múltiples fuentes. Ejemplo, archivos regulares o de video en directo.
  • Los archivos de entrada se especifican primero, acompañados de la opción “-i” al escribir el comando.
  • Los archivos de salida solamente se especifican por el nombre que vamos a darles
  • Cualquier cosa que no pueda ser interpretada como una opción, va a ser considerada como un nombre de salida.

Luego el manual continua entregando información sobre lo anterior:

Each input or output url can, in principle, contain any number of streams of different types (video/audio/subtitle/attachment/data). The allowed number and/or types of streams may be limited by the container format. Selecting which streams from which inputs will go into which output is either done automatically or with the «-map» option.

manual de ffmpeg

De esto entiendo que:

  • En principio cada entrada o salida puede venir de múltiples fuentes (video, audio, subtítulos, documentos adjuntos o datos).
  • El número o el tipo de esas fuentes puede estar limitado por el formato del contenedor.
  • La selección de que entrada va hacia que salida se hace automáticamente. Aunque es posible dar nuevas direcciones agregando “-map” al momento de ejecutar el comando.

Ahora el siguiente párrafo me dice que los archivos de entrada son numerados por un sistema de índice:

To refer to input files in options, you must use their indices (0-based). E.g. the first input file is 0, the second is 1, etc. (…)

manual de gimp

Esto también lo encontré estudiando lenguajes de programación, por ejemplo Python,

De este modo, el primer input tiene el indice 0, el segundo input tiene el indice 1 y asi sucesivamente. Lo más importante para recordar: el indice comienza desde 0.

Luego sigue:

As a general rule, options are applied to the next specified file. Therefore, order is important, and you can have the same option on the command line multiple times. Each occurrence is then applied to the next input or output file. Exceptions from this rule are the global options (e.g. verbosity level), which should be specified first.

Manual de gimp

Este párrafo vuelve a mencionar la importancia en el orden en el que presentamos primero los archivos de entrada, luego los de salida.

A mi entender, lo que tengo que sacar como información valiosa es lo siguiente:

  • El orden es importante porque las opciones se aplican al siguiente archivo especificado. Primero va la opción, luego va el nombre del archivo de entrada o de salida al que se aplica esa opción.
  • Siendo que la sintaxis es de esta forma, puedo poner la misma opción múltiples veces dentro de un mismo comando. Cada opción va a afectar a un archivo diferente.
  • La excepción a lo anterior son las opciones globales, que afectan a todos los archivos, y tienen que ir al principio del comando.

El párrafo siguiente termina de aclarar estos conceptos:

Do not mix input and output files — first specify all input files, then all output files. Also do not mix options which belong to different files. All options apply ONLY to the next input or output file and are reset between files.

manual de gimp

Y lo importante es:

  • No mezclar los archivos de entrada y de salida. Primero van todos los inputs, luego los outputs.
  • Cada opción solo aplica al siguiente archivo que lo acompaña. El orden es: opción + entrada o salida.
  • Las opciones se reinician en cada entrada/salida que acompañan. Por eso puedo usar la misma opción múltiples veces para archivos distintos.

Luego el manual da algunos ejemplos de como escribir los comandos. Es bastante explicativo, y contiene mucha información valiosa.

Por lo general no me gusta copiar fragmentos enteros de la documentación, pero en este caso creo que ayuda mucho a comprender en que forma funciona el programa.

De todos modos, siendo que la mayoría de las veces la mejor forma de aprender algo es haciendo algo, voy a continuar con…

Cómo convertir archivos en ffmpeg

Para empezar, voy a dedicarme a transformar algunos archivos en ffmpeg. Es cierto, tal vez no es lo más divertido… pero sin dudas es interesante.

Y además, es un tema bastante complejo.

Muchas veces al editar proyectos es importante que los documentos coincidan en su formato. Por ejemplo, si queremos unir dos videos distintos, a veces el proceso no va funcionar bien si los dos videos son de distinto tipo o resolución.

Por otra parte, convertir los archivos entre formatos puede llevar a extraños errores y glitchs de video interesantes. Arte improvisado. Puede también ahorrarnos bastante tiempo cuando algún archivo se niega a funcionar en un equipo determinado.

Pero antes de transformar un documento, necesito conocer sus propias características.

Cómo conocer la información de un video en ffmpeg

En este momento, la terminal se encuentra trabajando en el mismo directorio donde tengo los videos. Por lo tanto, los resultados obtenidos van a guardarse dentro de la misma carpeta.

Según entiendo por mi lectura de la documentación, ffmpeg entiende de archivos de entrada y archivos de salida. Utilizo la opción “-i” para indicar cuales son los archivos de entrada, los archivos que voy a intervenir, transformar o lo que sea.

Y como archivo de salida (output) se cuenta cualquier otra cosa que no se encuentre acompañada de opciones.

Por esto el orden en el que se escribe el comando es muy importante, porque de eso depende el resultado. Indico cuales son los archivos de entrada (input), luego el resto de las opciones que voy a aplicar y al final señalo los archivos de salida (output) que voy a obtener.

Puedo entender todo esto con un primer comando, que me va a servir para conocer la información de un archivo. Voy a usar de ejemplo un video en mi directorio, un video que se llama “nubes.mp4” y de este modo podré conocer su duración, el bitrate y muchas cosas más.

El comando es:

ffmpeg -i nubes.avi

Solo necesito eso, utilizar la opción “-i” para indicar el input que ffmpeg va leer. Pero como no estoy indicando la creación de un archivo de salida, voy a ver la información de respuesta reflejada en la terminal.

Y esto me da mucha información del video. Parte de la información es la siguiente:

Input #0, avi, from 'nubes.avi':
Metadata:
encoder : Lavf52.64.2
Duration: 00:00:25.01, start: 0.000000, bitrate: 2356 kb/s
Stream #0:0: Video: h264 (High) (avc1 / 0x31637661), yuv420p(progressive), 1920x1080, 2299 kb/s, 30 fps, 30 tbr, 30 tbn, 60 tbc
Stream #0:1: Audio: mp2 (P[0][0][0] / 0x0050), 44100 Hz, stereo, s16p, 64 kb/s
At least one output file must be specified

Voy a intentar hacer una revisión más o menos rápida de algunas partes de esos datos. O al menos las que entiendo en este momento:

  • Input #0, avi, from ‘nubes.avi’: Si recuerdo de antes, cada input sigue un índice que comienza desde cero. Siendo que en este caso estoy presentando un único archivo, su lugar en el índice es el 0.
  • Metadata: incluye información particular del archivo, que responde preguntas sobre su origen. Ejemplo, el año en que fue creado
  • Duration: 00:00:25.01, start: 0.000000: Si, eso mismo, la duración del video.
  • bitrate: 2356 kb/s : tasa de datos por segundo. Básicamente la cantidad de información del video, cuanto mayor el número mayor la calidad.
  • Video: h264 (High): el codec (codificador-decodificador) del video. Aunque el contenedor del video es “.avi”, el codec es h264. Es lo que especifica la forma en que se comprime la información.
  • 1920×1080: la resolución en pixeles del video.
  • 30 fps: la cantidad de cuadros por segundo (frames per second) del video. Un segundo del video contiene 30 fotogramas individuales. En teoría, cuantos más fotogramas más fluido se ve el movimiento de las imágenes.
  • Audio: mp2 (P[0][0][0] / 0x0050), 44100 Hz, stereo, s16p, 64 kb/s: Algunos detalles del audio.

Con todo, para no detenerme demasiado en esto, quiero repasar especialmente un detalle muy importante.

Canales y más canales:

Voy a detenerme en la siguiente pieza de datos:

Stream #0:0: Video: h264 (High) (avc1 / 0x31637661), yuv420p(progressive), 1920x1080, 2299 kb/s, 30 fps, 30 tbr, 30 tbn, 60 tbc
Stream #0:1: Audio: mp2 (P[0][0][0] / 0x0050), 44100 Hz, stereo, s16p, 64 kb/s

Aquí encuentro:

Stream #0:0: Video:
Stream #0:1: Audio:

Tengo que prestar atención que un mismo archivo “nubes.avi” (en este caso de índice #0) tengo dos streams separados. Como si fueran dos canales que se bifurcan de una misma fuente.

Esto es, dentro de “nubes.avi” tengo una primera canal de video que también tiene un índice #0. Por eso esta denominada con “#0:0:”.

Y luego tengo un segundo canal de audio, que tiene un índice #1. Esta viene denominada con el código “#0:1:”.

El manual dice:

(…) streams within a file are referred to by their indices. E.g. «2:3» refers to the fourth stream in the third input file (…)

manual de ffmpeg

Esto es, los streams dentro de un archivo tienen sus propios índices. Por ejemplo si encuentro el dato “2:3”, esto se refiere se refiere al cuarto stream (índice #3) en el tercer input (de índice #2).

Para intentar reducir mi propia confusión, voy a traducir el termino “streams” por la palabra “canales”.

Si estuviera usando un editor gráfico como Adobe Premiere o Kdenlive para estudiar “nubes.avi”, podría ver en la linea de tiempo del editor dos canales distintos: uno para el video y otro para el audio. Esto es básicamente lo mismo, son canales o pistas de información dentro de un archivo.

Volviendo al ejemplo original, podría agregar un tercer canal a mi input “nubes.avi”. Digamos que es un nuevo canal de audio. El indice de este tercer canal va a ser “0:2”.

¿Por qué importa todo esto? Bueno, esto es solo una suposición. Pero creo que si escribo un comando lo bastante complejo, voy a poder intervenir distintos canales de una sola pasada.

Por ejemplo, podría subir el volumen de un canal de audio y bajar el de otro al mismo tiempo refiriéndome a cada uno por su propio índice.

Cómo convertir formatos de video en ffmpeg

En el ejemplo del comando anterior, al final de la devolución de la consola, el texto me dice:

At least one output file must be specified

Esto quiere decir: Al menos un archivo de salida tiene que ser especificado.

Siendo que ffmpeg no encuentra un archivo de salida para “resolver” la entrada, en este caso me devuelve los datos directamente en la terminal.

Para empezar a resolver esto, voy a agregar un nombre de salida. Mi objetivo es convertir un video, cambiando de alguna forma alguna de sus características.

Cambiar formato de video con mismo codec en ffmpeg:

En este caso, mi objetivo es convertir un video en formato “.avi” a otro en formato “.mp4” usando solamente la terminal.

Para no confundirme, voy a empezar a usar los comando sin opciones y luego voy a agregar nuevas variables gradualmente.

Entonces, tengo mi archivo original “nubes.avi” (aunque me pregunto si alguien realmente sigue usando ese tipo de formato… no importa, sirve para el ejemplo).

Voy a simplemente escribir el nombre del archivo de entrada, acompañado de la opcion “-i”, seguido del nombre del nuevo archivo de salida: “nuevas_nubes.mp4”.

No recuerdo si lo mencioné antes, pero la “i” de la opcion “-i” se refiere a “input” o en inglés la palabra “entrada”. Es por eso que es la opción que acompaña al nombre del archivo de entrada para señalarlo.

Como es de esperar, mi objetivo es tener un nuevo video, pero ahora con .mp4 por formato contenedor.

Me pregunto que puedo ocurrir…

ffmpeg -i nubes.avi nuevas_nubes.mp4

Bueno, para empezar la terminal se queda trabajando unos minutos en resolver el pedido. A la vez, nos dice cuanto va a llevar el asunto, la cantidad de frames que repasa y otros datos del tema.

El resultado es que ahora tengo dos archivos en mi directorio. Uno de ellos es el original “nubes.avi” y el otro es “nuevas_nubes.mp4”.

Voy a revisar la información de cada uno individualmente, copiando la parte que considero importante:

ffmpeg -i nubes.avi
Input #0, avi, from 'nubes.avi':
encoder : Lavf52.64.2

Stream #0:0: Video: h264 (High) (avc1 / 0x31637661), yuv420p(progressive), 1920x1080, 2299 kb/s, 30 fps, 30 tbr, 30 tbn, 60 tbc
Stream #0:1: Audio: mp2 (P[0][0][0] / 0x0050), 44100 Hz, stereo, s16p, 64 kb/s

Y el nuevo archivo:

ffmpeg -i nuevas_nubes.mp4
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'nuevas_nubes.mp4':
encoder : Lavf58.29.100

Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1920x1080, 3761 kb/s, 30 fps, 30 tbr, 15360 tbn, 60 tbc (default)
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default)

Bueno, puedo comprender que el contenedor efectivamente es distinto. Ahora es parte de la familia de los .mp4 en el nuevo caso.

Pero si reviso lado a lado la información del codec, cantidad de cuadros por segundo y resolusion parecen ser compartir muchos detalles:

Video original:

Video: h264 (High) (avc1 / 0x31637661), yuv420p(progressive), 1920x1080, 2299 kb/s, 30 fps, 30 tbr, 30 tbn, 60 tbc

Video convertido:

Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1920x1080, 3761 kb/s, 30 fps, 30 tbr, 15360 tbn, 60 tbc (default)

Así que creo todo esto es muy bueno para empezar. Ya conseguí empezar a usar ffmpeg, y pude convertir un archivo de entrada en un archivo de salida con un contenedor diferente.

Pero me gustaría empezar con algunas cosas más arriesgadas… ¿Qué más puedo hacer con ffmpeg?

Cómo cortar un fragmento de un video en ffmpeg

Hasta ahora estuve trabajando con un video de dimensiones 1920×1080. Por otra parte, la duración del video es de más de un minuto y su peso en el disco es de 14 megabytes.

La conversión a .mp4 hizo que el video pasara a ocupar 21 mb. La duración y sus dimensiones se mantuvieron iguales, ya que no agregué ninguna opción para modificarlas.

Es verdad, puedo admitirlo, hoy por hoy que un archivo de video ocupe este espacio es prácticamente nada en relación a la capacidad de los discos. Y un proyecto audiovisual puede llegar a ocupar cientos de gigas de memoria… unos simples 20 megas difícilmente vayan a significar algún tipo de problema.

Sin embargo, me gustaría que mi computadora pudiera resolver estos ejemplos más rápido. Para empezar tiene que convertir bastantes cuadros: 30 cuadros por segundo en 60 segundos me dan 1800 frames individuales.

Por otra parte, mi máquina no tiene placa de video externa. Todo depende de su procesador, y cualquier ayuda que pueda darle al momento de trabajar con video me lo va a agradecer.

En este momento se me aparecen varias opciones. Y una de esas opciones es cortar un fragmento de video. Digamos, un fragmento de diez segundos. Con eso voy a poder probar todas estas experiencias mucho más rápido.

Más todavía, este tema es muy importante porque va a a abrir el camino para editar proyectos más complejos. En resumidas cuentas, la tarea de editar un trabajo audiovisual se ocupa de tomar múltiples fragmentos pequeños para crear una obra más grande.

Para hacer esto, lo principal es conocer que momento del video quiero. Y eso lo expreso con el timecode o “código de tiempo”, básicamente el momento exacto expresado en horas, minutos, segundos y centésimas de segundo.

Quiero quedarme con los primeros diez segundos del video. Esto siguiendo el time code significa ir desde el segundo cero (00:00:00.000) hasta el segundo diez (00:00:10.000). Siendo que solamente necesito diez segundos, no tengo que agregar nada en los minutos o las horas.

El comando queda entonces de este modo:

ffmpeg -ss 00:00:00.000 -t 00:00:10.000 -i nuevas_nubes.mp4 -c copy corte_nubes.mp4

El inicio lo señalo con la opción “-ss” (start time), que significa literalmente “momento de comienzo”. Esta opción tiene que ir antes del -i, y por tanto antes del nombre del archivo de entrada.

La opción “-t” (duration) marca la duración del video.

En mi caso, la duración del corte es de diez segundos empezando desde el segundo cero. Pero digamos, puedo cortar empezando en el segundo 26 y hacer que el corte dure 14segundos.

Ahora el comando queda de este modo:

ffmpeg -ss 00:00:26.000 -t 00:00:14.000 -i nuevas_nubes.mp4 -c copy corte_nubes.mp4

Y el resultado es un corte de 8 segundos de video. Eso es, tengo un plano que va entre el segundo 20 y el segundo 40 del video original.

Tengo que recordar que si uso un nombre para un archivo de salida que es igual al nombre de un archivo ya existente en el directorio, ffmpeg me va a preguntar si quiero sobre escribirlo.

Por último tengo la opción “-c” que signfica copy o copia. Según el manual de instrucciones de ffmpeg, esta opción quiere decir:

special value «copy» (output only) to indicate that the stream is not to be re-encoded.

manual de ffmpeg

Esto es que, el valor especial copy indica que los canales no tienen que ser re codificados.

La idea es que de este modo ffmpeg copia los canales del archivo, en este caso un canal de audio y otro de video y los retiene en el archivo de salida sin volver a codificarlos.

El resultado es un nuevo archivo, un corte del video original con sus nuevas características que ya puedo usar para otras cosas.

(Entrada en proceso de escritura, volvé más tarde para ver como sigue)

Dejar una respuesta