ManzDev
Perfil de Manz Dashboard de actividad
HTML5 Etiquetas HTML
CSS CSS vanilla
PostCSS Transformador CSS
Javascript Javascript ES2020+
NPM Node Package Manager
WebComponents Componentes web
Terminal Terminal de GNU/Linux
VueJS Framework VueJS 3
Automatizadores Empaquetadores Javascript
Youtube Canal de Youtube
Twitch Canal de Twitch
Telegram Canal de Telegram
Discord Servidor de Discord

Tutorial de ffmpeg

Una de mis herramientas preferidas para conversión multimedia es ffmpeg. Se trata de una herramienta de línea de comandos que permite realizar multitud de tareas relacionadas con video, audio o incluso imágenes.

Cómo editar video con ffmpeg

Aunque su uso no es excesivamente complejo, la gran cantidad de parámetros, combinaciones y el inmenso abanico de formatos y sus características, hacen que el uso de ffmpeg sea poco intuitivo cuando empezamos a utilizarlo (o incluso más tarde, si no lo tenemos bien claro).

En este artículo vamos a explicar como utilizar esta herramienta de forma sencilla, dando un repaso a las tareas de edición de video más comunes y prácticas, viendo ejemplos prácticos para aplicar.

Instalación de ffmpeg

La herramienta ffmpeg es multiplataforma, por lo que puede instalarse en cualquier sistema, ya sea GNU/Linux, Windows o Mac. En nuestro caso, que es GNU/Linux (o Windows bajo WSL), puedes utilizar el siguiente comando:

$ sudo apt-get install ffmpeg

Si quieres comprobar si todo ha ido bien y ya tienes disponible el comando, puedes escribir which ffmpeg, el cuál debería devolverte algo similar a /usr/bin/ffmpeg. Eso significa que ya está instalado.

Obtener información de un video

Una vez instalado, podemos ver información sobre nuestros videos de la siguiente forma:

$ ffmpeg -i video.mp4

El parámetro -i indica que se va a especificar un archivo de entrada (en nuestro caso, el video) y a continuación, dicho archivo. Veremos que ffmpeg nos devuelve gran cantidad de información, sin embargo no te asustes, solo tendremos que fijarnos en algunos detalles:

$ ffmpeg -i video.mp4
ffmpeg version 4.1.6-1~deb10u1 Copyright (c) 2000-2020 the FFmpeg developers
  built with gcc 8 (Debian 8.3.0-6)
  configuration: --prefix=/usr --extra-version='1~deb10u1' --toolchain=hardened
   --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64
   --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample
   --enable-avisynth --enable-gnutls --enable-ladspa --enable-libaom --enable-libass
   --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio
   --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-libfreetype
   --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame
   --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus
   --enable-libpulse --enable-librsvg --enable-librubberband --enable-libshine
   --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh
   --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis
   --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2
   --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx
   --enable-openal --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm
   --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared
  libavutil      56. 22.100 / 56. 22.100
  libavcodec     58. 35.100 / 58. 35.100
  libavformat    58. 20.100 / 58. 20.100
  libavdevice    58.  5.100 / 58.  5.100
  libavfilter     7. 40.101 /  7. 40.101
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  3.100 /  5.  3.100
  libswresample   3.  3.100 /  3.  3.100
  libpostproc    55.  3.100 / 55.  3.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'video.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf55.43.100
  Duration: 02:42:45.01, start: 0.000000, bitrate: 6180 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 1920x1080 [SAR 1:1 DAR 16:9], 6003 kb/s, 60 fps, 60 tbr, 90k tbn, 120 tbc (default)
    Metadata:
      handler_name    : VideoHandler
    Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 160 kb/s (default)
    Metadata:
      handler_name    : SoundHandler
At least one output file must be specified

La parte clave es la que resalto a continuación:

  • El comando que hemos escrito: Se trata del comando que escribimos en la terminal de texto para lanzar ffmpeg y realizar alguna acción. En este caso, obtener información del video.
  • La fila Duration y bitrate: Características del archivo en general (duración y bitrate del video+audio, por ejemplo).
  • Stream #0:0: Información sobre el canal de video: codec, resolución, proporción de aspecto, calidad de video, fps, etc...
  • Stream #0:1: Información sobre el canal de audio: codec, frecuencia de muestreo, calidad de audio, etc...

Con esto puedes obtener información sobre un archivo de video y sus características. En la siguiente tabla puedes ver algunos parámetros interesantes, que explicaremos poco a poco más adelante:

Parámetro Descripción
-i fichero.ext Muestra información de ese archivo (audio o video).
-i origen.ext destino.ext Convierte un archivo de un formato a otro.
-formats Muestra todos los formatos soportados por ffmpeg.
-codecs Muestra todos los codecs soportados por ffmpeg.
-decoders Muestra todos los codecs de entrada soportados.
-encoders Muestra todos los codecs de salida soportados.

Conversión entre formatos de video

Uno de los puntos fuertes de ffmpeg es que permite realizar practicamente cualquier tipo de conversión entre los diferentes formatos de video y audio (que no son pocos). Es requisito recomendable tener una idea general de los diferentes formatos y codecs de video y formatos y codecs de audio que existen antes de comenzar a utilizar ffmpeg.

Podemos realizar conversiones aprovechándonos de las extensiones comunes de ciertos formatos de video, ya que ffmpeg los detecta automaticamente. Por ejemplo:

$ ffmpeg -i video_original.avi video_destino.mp4

En este ejemplo, le indicamos a ffmpeg que el formato de entrada es video_original.avi (mediante el parámetro -i) y que lo convierta a un archivo de destino al cuál le hemos indicado la extensión .mp4. De esta forma, ffmpeg busca los codecs de video y de audio apropiados para este formato (automáticamente selecciona h264 para video y aac para audio).

Si realizaramos otra conversión desde un fichero .mp4 a otro .mkv, podremos fijarnos en estas líneas, las cuales nos indican que tipo de conversión se está realizando:

[...]
Stream mapping:
  Stream #0:0 -> #0:0 (mpeg4 (native) -> h264 (libx264))
  Stream #0:1 -> #0:1 (aac (native) -> vorbis (libvorbis))
[...]

No obstante, podemos ser más específicos y personalizar los formatos que queremos utilizar. Por ejemplo, especificando el codec de video y el codec de audio que queremos en el archivo de destino:

$ ffmpeg -i video_original.mp4 -vcodec libx264 video_264.mkv
$ ffmpeg -i video_original.mp4 -vcodec libx265 video_265.mkv

En ambos ejemplos anteriores estamos creando un archivo de video Matroska (MKV), con canal de audio vorbis en ambos casos. Sin embargo, en el primer ejemplo, estamos utilizando el codec de video h264 (mediante la librería libx264), mientras que en el segundo ejemplo utilizamos el codec de video h265 (mediante la librería libx265), aún en desarrollo y futuro sucesor de H264.

Los resultados son bastante interesantes, puesto que el primer archivo resultante ocupa 120MB, mientras que el segundo 69MB. Ambos a 1080p (HD) y con la misma aparente calidad (eso sí, el segundo tarda más en comprimir y crearse).

También podemos hacer lo mismo con los canales de audio:

$ ffmpeg -i video.mp4 -vcodec copy -acodec mp3 h264_mp3.mkv
$ ffmpeg -i video.mp4 -vcodec copy -acodec aac h264_aac.mkv
$ ffmpeg -i video.mp4 -vcodec copy -acodec libvorbis h264_vorbis.mkv

Observa que en estos casos, hemos especificado copy en el codec de video, lo que obliga a ffmpeg a no hacer conversión de formatos de video, sino utilizar el que ya tiene (ahorrando mucho tiempo porque no hay que recomprimir el video), mientras que le especificamos el codec de audio mediante acodec.

Tanto con -vcodec como con -acodec tenemos que especificar la librería de codec a utilizar. En el caso de especificar solo la extensión en el archivo (por ejemplo, .mp3), el ffmpeg se encarga de seleccionar la librería más apropiada (libmp3lame, en este caso).

Podemos ver las librerías de codecs y formatos que soporta ffmpeg escribiendo en una terminal las lineas de comandos ffmpeg -formats o ffmpeg -codecs.

Parámetro Descripción
-vcodec Fuerza a usar un codec de video de salida.
-acodec Fuerza a usar un codec de audio de salida.

Reducir calidad de video/audio

Por defecto, ffmpeg se encarga de detectar la calidad (bitrate) del video y audio del archivo original y le asigna uno equivalente al archivo de destino. Sin embargo, esto depende mucho del archivo en cuestión y puede que ffmpeg reduzca demasiado la calidad (y se vea con mala calidad el archivo resultante) o mantenga una calidad demasiado alta (y ocupe demasiado el archivo final).

Reducir calidad de video (bitrate) con ffmpeg

Generalmente, ffmpeg hace un gran trabajo en este aspecto. Pero si queremos personalizar la calidad, utilizaremos el parámetro -b:v para el bitrate de video y -b:a para el bitrate de audio. Por ejemplo:

$ ffmpeg -i video.avi -b:v 2500k -b:a 192k video_final.mp4

Esto conseguiría que el archivo MP4 final tenga un video con un bitrate de 2500kb/s y un audio con un bitrate de 192kb/s.

Parámetro Descripción
-b:v Establece el bitrate de video de salida (no olvides la k!).
-b:a Establece el bitrate de audio de salida.

Extraer audio de un video

Otra operación muy común es querer extraer el audio de un video, para pasarlo a un archivo MP3, por ejemplo. Esto es muy sencillo de hacer con ffmpeg:

$ ffmpeg -i video.mp4 -vn audio.mp3

En algunos casos, como el caso anterior, ffmpeg detectará que el archivo de destino es un archivo de audio y hará la conversión automáticamente sin necesidad de indicar parámetros como -vn. Sin embargo, será necesario si queremos hacerlo en un formato final mkv sin canal de video.

Parámetro Descripción
-vn Elimina el canal de video.
-an Elimina el canal de audio.

Silenciar (eliminar) el audio de un video

De la misma forma análoga al ejemplo anterior (donde eliminabamos el canal de video en un archivo de video), podemos eliminar el canal de audio de un archivo de video:

$ ffmpeg -i video.mp4 -an video_mute.mp4

Subir el volumen de un video (o audio)

Muchas veces tenemos un video que tiene un audio muy bajo. Podemos subirle el volumen del canal de audio con el parámetro -vol, indicándole un valor numérico donde 256 es el volumen original, pudiendo subirlo o bajarlo:

$ ffmpeg -i video.mp4 -vol 512 video_final.mp4
$ ffmpeg -i video.mp4 -af volume=2

En el segundo ejemplo vemos una forma alternativa utilizando filtros de audio, en el que subimos el volumen al doble de su volumen original.

Parámetro Descripción
-vol Cambia el volumen de audio (256 normal, 512 doble, 128 mitad)
-af [filtro] Establece un filtro avanzado de audio.
-vf [filtro] Establece un filtro avanzado de video.

Rotar o girar un video

También es muy común tener la necesidad de rotar un video, ya sea porque nos interesa tenerlo así o porque alguien tuvo la osadía de hacer un maldito vídeo vertical. Para solucionarlo, podemos rotar el video haciendo lo siguiente:

$ ffmpeg -i video.mp4 -vf transpose=clock video_rotado_90.mp4
$ ffmpeg -i video.mp4 -vf transpose=clock,transpose=clock video_rotado_180.mp4
$ ffmpeg -i video.mp4 -vf hflip video_invertido_horizontalmente.mp4
$ ffmpeg -i video.mp4 -vf vflip video_invertido_verticalmente.mp4

En el primer ejemplo, utilizamos el filtro de video transpose para girar 90 grados en el sentido de las agujas del reloj. En el caso de indicar el valor cclock en lugar de clock, se gira en el sentido contrario de las agujas del reloj. En el segundo ejemplo, aplicamos el filtro dos veces, por lo que conseguimos como resultado un giro de 180 grados. Los dos últimos ejemplos son para invertir un video horizontal o verticalmente.

Existe un parámetro rotate en ffmpeg que es mucho más flexible, pero cuidado, los valores deben expresarse en radianes.

Redimensionar o cambiar tamaño de un video

Otra operación bastante frecuente es la de redimensionar el tamaño de un video. También es una operación muy sencilla de realizar con ffmpeg, aunque hay que tener en cuenta la proporción de aspecto, de modo que al redimensionar no se deforme el mismo. Veamos algunos ejemplos:

$ ffmpeg -i video.mp4 -vf scale=320:240 video_320x240.mp4
$ ffmpeg -i video.mp4 -vf scale=320:-1 video_320x180.mp4
$ ffmpeg -i video.mp4 -vf scale=iw/2:ih/2 video_x.mp4

En el primero de los casos, obligamos a ffmpeg a redimensionar el video a la resolución 320x240, independientemente del tamaño del video original. En la segunda opción, sin embargo, al indicar -1 le decimos a ffmpeg que utilice el alto apropiado para que el video no se deforme, reemplazándolo por su alto equivalente:

Cambiar tamaño de un video con ffmpeg

En el tercer ejemplo, utilizamos las palabras clave iw (input width) y ih (input height). Al dividirlas entre dos, lo que indicamos es que el video resultante tenga la mitad de tamaño tanto de ancho como de alto.

Nota: Hay que tener cuidado con algunos codecs, puesto que no permiten redimensiones a tamaños que no sean múltiplos de 4 o restricciones similares.

Recortar fragmentos de un video

Otra operación interesante que nos puede surgir es la de recortar un fragmento de tiempo de un video más largo. Por ejemplo, obtener el fragmento de video desde los 35seg hasta los 65seg (30seg de duración).

Existe un parámetro con el que podemos realizar estas operaciones:

$ ffmpeg -i video.mp4 -ss 35 -t 30 fragmento.mp4
$ ffmpeg -i video.mp4 -ss 00:35 -to 01:05 fragmento.mp4

En el primer ejemplo, estamos seleccionando el fragmento de video desde los 35seg (como marca de inicio), y a partir de ahí, 30seg hacia adelante. En el segundo ejemplo, estamos seleccionando el fragmento de video desde la marca de tiempo de 35seg hasta 1min 5seg, ambos del video original.

Parámetro Descripción
-ss Establece el momento de inicio de un fragmento de video/audio.
-to Establece el momento de final de un fragmento de video/audio.
-t Establece la duración del fragmento de video/audio.

Añadir o eliminar pistas de audio a un video

La mayoría de formatos de video de la actualidad funcionan como contenedores que son capaces de incluir varios canales de audio (e incluso de otros tipos). Es muy común, por ejemplo, para añadir audio en diferentes idiomas. Con ffmpeg podemos gestionar esas pistas múltiples presentes en un archivo de video.

Un ejemplo de uso podrían ser los siguientes comandos:

$ ffmpeg -i video.mp4 -i audio_es.mp3 -map 0:v -map 0:a -map 1:a -vcodec copy video_final.mp4
$ ffmpeg -i video.mp4 -map 0:0 -map 0:2 solo_canal1_audio.mp4

En el primer ejemplo, obtenemos dos archivos de entrada: video.mp4 (un video en inglés) y audio_es.mp3 (el audio en español). Nuestra intención es añadir este audio en el video, de modo que se pueda seleccionar el idioma. Con -map 0:v y -map 0:a indicamos que utilizaremos el video y audio del primer archivo de entrada (video.mp4) y con -map 1:a indicamos que utilizaremos el audio del segundo archivo de entrada (audio_es.mp3) para incorporarlo al video final.

En el segundo ejemplo, partimos de un archivo video.mp4 que tiene varios canales de audio, y con los parámetros -map 0:0 y -map 0:2 indicamos que queremos generar un archivo con el video (canal 0) y la segunda pista de audio (canal 2), eliminando por tanto la primera pista (canal 1).

Parámetro Descripción
-map #:@ Mapea un canal de audio o video. En # va el número del canal y en @ va una a o una v.
-filter_complex Utiliza un filtro complejo.

Mezclar pistas de audio

Pero en algunas ocasiones no interesa añadir otra pista de audio al video, sino mezclarla con la pista existente. Para ello, podemos utilizar el filtro de audio amerge, como vemos en el siguiente ejemplo:

$ ffmpeg -i audio1.mp3 -i audio2.mp3 -filter_complex amerge audio_mezclado.mp3

Recorta zonas del video

Imagina por un momento que tienes un video, pero sólo te interesa quedarte con una región concreta del mismo. Esto es lo que se llama crop (recortar), y también se puede realizar con ffmpeg, con una línea de comandos como la que vemos a continuación:

$ ffmpeg -i screencast.mp4 -ss 00:30 -to 03:50 -vf crop=640:480:500:250 video_final.mp4

En ella, escogemos un fragmento de video, en el que sólo nos quedamos con una región de tamaño 640x480 desde la posición (500,250) de la pantalla. Esto puede ser muy útil para recortar grabaciones que hemos hecho y queremos extraer sólo una región de la pantalla.

Aplicar un viñeteado al video

Un efecto muy elegante y utilizado es el viñeteado, muy utilizado por los fans de Instagram. Con ffmpeg podemos también aplicar un viñeteado a nuestro video, en todos sus fotogramas, dándole un aspecto más elegante y profesional.

Aplicar filtros de video con ffmpeg

Para aplicarlo, basta con utilizar el filtro de video vignette, junto a un valor que representa el ángulo del mismo en radianes:

$ ffmpeg -i video.mp4 -vf vignette=PI/4 video_vignette.mp4
$ ffmpeg -i video.mp4 -vf vignette='PI/4+random(1)*PI/50':eval=frame

El valor aplicado por defecto al viñeteado es pi/5, sin embargo se pueden hacer cosas un poco más complejas, como el segundo ejemplo, donde se crea un viñeteado que vibra aleatoriamente, simulando un efecto retro de reproducción antigua.

Crear fundidos (fade-out o fade-in)

Otro efecto elegante utilizado a menudo en videos es el de los «fundidos a negro» (fade-out) o su proceso inverso (fade-in). Estos fundidos son muy comunes al inicio o al final de un video, ya que es una forma elegante de terminarlo.

Con ffmpeg se pueden crear de la siguiente forma:

$ ffmpeg -i video.mp4 -vf fade=t=in:st=0:d=5 video-fadein.mp4
$ ffmpeg -i video.mp4 -vf fade=t=in:st=0:d=5,fade=t=out:st=25:d=5 video-fadeout.mp4

Teniendo en cuenta que nuestro video.mp4 tiene una duración de 30 segundos, en el primer ejemplo, creamos un fundido desde negro (fade-in). Los parámetros indicados fade=t=in:st=0:d=5 son para realizar un tipo de fundido de entrada (fade-in), que comience en la marca de tiempo de 0seg y dure 5seg desde que pasa de negro a desvanecerse por completo.

En el segundo ejemplo, añadimos además un fundido a negro (fade-out), que comienza a los 25seg y dura 5seg. También podríamos añadir un párametro c=white para realizar los fundidos al color blanco, en lugar de negro.

Sin embargo, ya que tenemos el fundido a negro visualmente hecho, también podemos utilizar el filtro de audio afade para hacer lo mismo con el sonido:

$ ffmpeg -i true.mp4 -vf fade=t=in:st=0:d=5,fade=t=out:st=25:d=5 -af afade=t=in:ss=0:d=5,afade=t=out:st=25:d=5 truefade.mp4

Extraer fotogramas de un video

Con ffmpeg también podemos realizar tareas con formatos de imágenes. Es posible extraer los fotogramas de un video (o un fragmento de video) y pasarlos a imágenes individuales. Para hacerlo, simplemente escribimos la siguiente línea de comandos:

$ ffmpeg -i video.mp4 image%d.jpg

Teniendo en cuenta que los videos, por lo general, tienen entre 25-30fps (fotogramas por segundo), esto quiere decir que, salvo que se trate de un video muy corto, cada video generará gran cantidad de imágenes.

Extraer fotogramas de un video

Para evitarlo, se puede reducir los fotogramas por segundo a uno, por ejemplo, utilizando el siguiente filtro:

$ ffmpeg -i video.mp4 -vf fps=1 image%d.png

De esta forma, sólo generará una imagen por segundo. También podemos realizar la operación contraria, de modo que teniendo una serie de imágenes, las unamos y convirtamos en un video, algo ideal para técnicas de stop-motion, realizadas con una cámara digital:

$ ffmpeg -f image2 -i image%d.jpg video.mp4

Poner un logo o marca de agua a un video

Quizás, uno de los ejemplos más prácticos puede ser el siguiente. En él, lo que hacemos es insertar una imagen en una posición concreta de la imagen. Esto es ideal para insertar logotipos o marcas de agua en un video. Ten en cuenta, que si utilizas imágenes PNG puedes aprovechar el canal alfa de transparencia del mismo y colocar marcas de aguas que no sean totalmente opacas. El primer ejemplo que se ve a continuación inserta la imagen logo.png en la posición (10,10), comenzando desde la esquina superior izquierda:

$ ffmpeg -i video.mp4 -i logo.png -filter_complex overlay=10:10 final.mp4
$ ffmpeg -i video.mp4 -i logo.png -filter_complex overlay=x=(main_w-overlay_w):y=(main_h-overlay_h) final.mp4

Por otro lado, el segundo ejemplo realiza la misma tarea, pero utilizando variables predefinidas, que equivalen a colocar ese logotipo en la esquina inferior derecha, algo quizás más habitual.

Otros comandos

Añado algunos otros comandos interesantes que he utilizado en alguna ocasión:

# Morphing entre dos imágenes (image1.jpg e image2.jpg)
$ ffmpeg -loop 1 -i image1.jpg -loop 1 -i image2.jpg \
  -filter_complex [1:v][0:v]blend=all_expr='A*(if(gte(T,3),1,T/3))+B*(1-(if(gte(T,3),1,T/3)))' \
  -t 4 final.gif

# Incrementar velocidad de video
$ ffmpeg -i original.mp4 -vf setpts=0.02*PTS destino.mp4

# Zoom IN
$ ffmpeg -loop 1 -i imagen.png -i audio.mp3 \
  -vf "zoompan=z='min(zoom+0.0010,1.5)':d=700:x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':s=1080x1920" video.mp4

# Eliminar escenas con frames duplicados de un video
$ ffmpeg -i input.mp4 -vf mpdecimate,setpts=N/FRAME_RATE/TB output.mp4

# Trim del audio (eliminar silencio antes y después)
$ ffmpeg -i original.mp3 -af silenceremove=1:0:-50dB:1:0:-75dB destino.mp3

# Rotar 270 grados
$ ffmpeg -i video.mp4 -vf transpose=clock,transpose=clock,transpose=clock video_rotado_270.mp4

Esto sólo es una selección práctica con algunos pequeños ejemplos de lo que se puede hacer con ffmpeg. Si te ha resultado útil o conoces algún parámetro interesante que no esté en la lista, por favor, compártelo con nosotros en los comentarios.



Manz
Publicado por Manz

Docente, divulgador informático y Streamer de código. Amante del CSS y de la plataforma web en general. Autor de Emezeta.com tiempo atrás. Ha trabajado como profesor en la Universidad de La Laguna y es director del curso de Programación web FullStack y FrontEnd de EOI en Tenerife. En sus ratos libres, busca GIF de gatos en Internet.