Cómo comprimir video con FFmpeg
Para reducir el tamaño de un archivo de video para la web, empieza con video H.264 y audio AAC en un
contenedor MP4. Este comando crea output.mp4 a partir de un archivo local
input.mp4, mediante codificación basada en la calidad:
if [ -e "./output.mp4" ] || [ -L "./output.mp4" ]; then
printf '%s\n' 'Choose a new filename: ./output.mp4 already exists.' >&2
false
else
ffmpeg -n -nostdin -xerror -i "./input.mp4" \
-map 0:V:0 -map '0:a:0?' \
-c:v libx264 -crf 23 -preset medium -pix_fmt yuv420p \
-c:a aac -b:a 128k -ac 2 -movflags +faststart "./output.mp4"
fi
La compresión con pérdida descarta detalles. El resultado puede ser más pequeño, pero una fuente que ya es eficiente puede aumentar de tamaño al volver a codificarla. Conserva el original y compara el resultado antes de elegir ajustes para otros videos. CRF controla la calidad; no garantiza un tamaño de archivo específico.
El comando selecciona el primer flujo de video que no sea una carátula y la primera pista de audio,
si existe. Produce audio AAC estéreo cuando hay audio y un video sin sonido en caso contrario. Se
omiten las demás pistas de audio, los flujos de subtítulos y los flujos de datos. La asignación
opcional de audio y la negativa a sobrescribir de -n se documentan en la
referencia de comandos de FFmpeg.
-nostdin desactiva la entrada interactiva y -xerror
detiene el proceso ante errores que FFmpeg detecte. Un error puede dejar un archivo de salida
incompleto; no lo publiques ni interpretes su pequeño tamaño como una compresión exitosa.
Verifica los requisitos previos
Usa Bash en Linux con ffmpeg y ffprobe en tu PATH.
Estos ejemplos se probaron con FFmpeg 6.1.1 en Ubuntu 24.04 y FFmpeg 9.0.1 en Linux. Requieren el
codificador de video libx264, el codificador de audio nativo
aac y el multiplexor MP4. Verifica tu compilación:
ffmpeg -version &&
ffprobe -version &&
ffmpeg -hide_banner -h encoder=libx264 &&
ffmpeg -hide_banner -h encoder=aac
La salida de ayuda debe describir ambos codificadores; un mensaje como «unknown» o «not recognized» significa que la compilación no es adecuada, aunque el comando de ayuda finalice correctamente. Si necesitas FFmpeg, su página de descargas enlaza a paquetes para Linux y compilaciones para macOS y Windows. Los ejemplos de shell de esta página son para Linux.
Usa un clip progresivo de rango dinámico estándar (SDR), con píxeles cuadrados y ancho y alto pares.
Estos comandos no cambian las dimensiones del video ni realizan mapeo de tonos HDR.
yuv420p selecciona video 4:2:0 de 8 bits; no convierte los colores HDR en
colores SDR correctos. Mantén los nombres de archivo entre comillas, incluido el prefijo
./ para nombres que comiencen con un guion. Cada codificación se niega a
reemplazar un MP4 existente, así que elige un destino nuevo al comparar ajustes. La comprobación en
el shell también devuelve un estado de error si el destino ya existe: la propia negativa a
sobrescribir de FFmpeg puede finalizar con un estado de éxito en algunas versiones.
Elige CRF y el ajuste preestablecido por separado
Para libx264, empieza con CRF 23. Prueba 20 si el texto pequeño o los detalles
finos se ven deteriorados, o 26 si reducir los bytes es más importante. Los valores de CRF más bajos
conservan más detalles y suelen producir archivos más grandes; los más altos sacrifican más
detalles para reducir los bytes. Vuelve a codificar desde el original en cada comparación.
El ajuste preestablecido controla cuánto trabajo de codificación realiza x264.
medium es un punto de partida razonable; slow
dedica más tiempo a buscar formas eficientes de codificar el video. Puede mejorar la eficiencia de
compresión, pero no promete un porcentaje fijo de ahorro ni una calidad idéntica con el mismo CRF.
Consulta las opciones del codificador x264 para conocer los
controles independientes de calidad y ajuste preestablecido.
Los valores de CRF y los nombres de los ajustes preestablecidos son propios de cada codificador.
CRF 23 en x264 no equivale a la misma calidad en x265, VP9 o AV1, y
slow no es una escala de calidad compartida entre codificadores. Si la
resolución de la fuente supera la que muestras, reducir sus dimensiones puede ayudar más que
seguir aumentando CRF, pero revisa el texto pequeño y otros detalles al tamaño de visualización
previsto antes de descartar píxeles.
Comparación de calidad y tamaño de archivo
Inspecciona la fuente y el resultado con ffprobe. Esto muestra las propiedades de los flujos, la duración en segundos y el tamaño del archivo en bytes:
ffprobe -v error -show_format -show_streams -of json "./input.mp4" &&
ffprobe -v error -show_format -show_streams -of json "./output.mp4"
Busca codec_name: "h264" y pix_fmt: "yuv420p" en el flujo de video. Si la
fuente no tiene metadatos de rotación, el ancho y el alto deben coincidir con los de la fuente. Si
la entrada tenía audio, un flujo de audio debe indicar aac con dos
canales. Compara format.size y format.duration con la fuente. Las
pequeñas diferencias por relleno de audio son normales; perder segundos de contenido no lo es.
Decodifica el resultado completo para detectar errores que no se reflejen en sus metadatos:
ffmpeg -v error -nostdin -xerror -i "./output.mp4" \
-map 0:V:0 -map '0:a:0?' -f null -
Una decodificación exitosa no produce mensajes de error aquí. No mide la calidad visual. Reproduce ambos archivos al tamaño de visualización previsto y revisa el movimiento, los degradados, el texto pequeño y la sincronización del audio. Un archivo más pequeño solo es útil si su imagen y sonido siguen siendo aceptables para tu página.
Usa dos pasadas para un tamaño objetivo
Cuando tengas un límite de subida, elige una tasa de bits promedio en lugar de CRF. Un cálculo
inicial es video bits/s = (target bytes × 8 ÷ duration seconds) − audio bits/s. Reserva parte del tamaño total para el contenedor y la
variación de la tasa de bits; luego mide el archivo terminado. La codificación en dos pasadas busca
alcanzar una tasa de bits de video promedio; no establece un límite exacto de bytes.
Por ejemplo, un clip de 60 segundos de menos de 10 MB (10.000.000 bytes) dispone de unos
1.333 kbit/s en total. Reservar un 5 % y asignar 128 kbit/s al audio deja unos 1.139 kbit/s para el
video. Redondea hacia abajo a 1100k para un primer intento. Usa la duración
real de tu fuente indicada por ffprobe y vuelve a calcular si el límite es distinto. Si no hay
audio, este ejemplo deja sin usar la parte asignada al audio.
Ejecuta este bloque completo en Bash. Crea target.mp4 independientemente del
resultado anterior con CRF:
(
if [ -e "./target.mp4" ] || [ -L "./target.mp4" ]; then
printf '%s\n' 'Choose a new filename: ./target.mp4 already exists.' >&2
exit 1
fi
pass_dir=$(mktemp -d) || exit 1
trap 'rm -rf -- "$pass_dir"' EXIT
ffmpeg -y -nostdin -xerror -i "./input.mp4" \
-map 0:V:0 -c:v libx264 -b:v 1100k -preset medium -pix_fmt yuv420p \
-pass 1 -passlogfile "$pass_dir/stats" -an -f null /dev/null &&
ffmpeg -n -nostdin -xerror -i "./input.mp4" \
-map 0:V:0 -map '0:a:0?' \
-c:v libx264 -b:v 1100k -preset medium -pix_fmt yuv420p \
-pass 2 -passlogfile "$pass_dir/stats" \
-c:a aac -b:a 128k -ac 2 -movflags +faststart "./target.mp4"
)
La primera pasada recopila estadísticas; && impide que se ejecute la
segunda si la primera falla. El directorio temporal mantiene separados los
registros de las pasadas entre ejecuciones y se elimina cuando
finaliza el bloque. -y de la primera pasada solo se aplica a la salida
descartada en /dev/null; la segunda pasada usa -n
para proteger target.mp4. Mantén la misma entrada, tasa de bits, ajuste
preestablecido y filtros de video en ambas pasadas.
Repite los comandos de inspección y decodificación con target.mp4 en lugar de
output.mp4. Si el archivo supera tu límite, reduce la tasa de bits de video y
vuelve a ejecutar ambas pasadas con un nombre de archivo de salida nuevo. Si la imagen deja de ser
aceptable antes de alcanzar el tamaño requerido, reconsidera la duración o la resolución. Cambiar
únicamente los códecs no garantiza un resultado aceptable dentro de cualquier tamaño objetivo.
Compatibilidad con navegadores
H.264 es el códec de video; MP4 es el contenedor que aloja ese video y su audio AAC. Es una combinación inicial práctica para una amplia compatibilidad de reproducción web, pero la compatibilidad también depende del navegador, el sistema operativo, el perfil y nivel del códec, la resolución y el decodificador del dispositivo. Por ejemplo, Firefox puede depender de los códecs del sistema operativo para H.264. Consulta la guía de códecs de video de MDN y prueba el archivo real en los navegadores y dispositivos de tu audiencia. HEVC, VP9 y AV1 son alternativas que puedes evaluar para esa audiencia, no reemplazos universalmente mejores o compatibles.
-movflags +faststart coloca el índice MP4 antes de los datos multimedia, lo que permite
que un reproductor compatible inicie la reproducción sin descargar primero el final del archivo.
No reduce el tamaño del video codificado ni crea variantes de streaming adaptativo. La
documentación del multiplexor MP4 explica este paso adicional de
indexación. Incluso tras una decodificación local exitosa, es necesario comprobar la reproducción
a través de tu servidor web y reproductor reales antes de publicar.
Reutiliza los ajustes con cuidado
Prueba los ajustes elegidos en clips representativos antes de codificar una colección. Una grabación de pantalla con texto pequeño y un clip grabado con una cámara en mano pueden necesitar valores de CRF distintos. Mantén un destino separado para cada fuente y comprueba el estado de cada comando antes de inspeccionar o publicar su resultado. Después de una codificación fallida, elige un nombre de salida nuevo o elimina únicamente el archivo incompleto que acabas de crear; la negativa a sobrescribir también se aplica a los archivos parciales de ejecuciones anteriores.
