Composición de video — Ensamblaje, audio, codificación y validación
FFmpeg es la capa de entrega, no una herramienta de diseño. Debe recibir escenas ya diseñadas y producir un master limpio más las codificaciones para plataformas.
Consulte references/FFMPEG-COOKBOOK.md para comandos listos para copiar y scripts/validate.sh para una comprobación previa a la entrega.
Regla cero: sondear primero. Construir un grafo de filtros asumiendo propiedades de flujo incorrectas es la causa más común de salida rota.
ffprobe -v error -show_streams -show_format -of json input.mp4
1. Normalizar antes de combinar
Entradas incompatibles causan vibración, silencio, desvío y halos. Antes de cualquier ensamblaje con múltiples fuentes, haga que todas las entradas coincidan en:
| Propiedad | Objetivo |
|---|---|
| Resolución | master del proyecto (ej. 1920×1080) |
| Relación de aspecto de píxel | 1:1 |
| Fotogramas por segundo | FPS del proyecto, constante |
| Base de tiempo | consistente |
| Formato de píxel | yuv420p para entrega, yuva444p10le/PNG para alpha |
| Espacio de color / transferencia | un estándar; etiquételo |
| Audio | 48 kHz, estéreo, códec consistente |
ffmpeg -i in.mp4 -vf "scale=1920:1080:flags=lanczos,fps=30,setsar=1" \
-c:v libx264 -crf 14 -preset fast -pix_fmt yuv420p \
-c:a aac -ar 48000 -ac 2 -b:a 256k normalized.mp4
Mantenga los intermedios en alta calidad (CRF 12–16 o ProRes). Codifique la versión de entrega una sola vez.
2. Concatenación
Mismo códec, tamaño, FPS, formato de píxel y diseño de audio → copia de flujo, rápida y sin pérdidas:
printf "file 'shot_01.mp4'\nfile 'shot_02.mp4'\n" > list.txt
ffmpeg -f concat -safe 0 -i list.txt -c copy final.mp4
Cualquier otra cosa → grafo de filtros:
ffmpeg -i a.mp4 -i b.mp4 -filter_complex \
"[0:v]scale=1920:1080,fps=30,setsar=1[v0]; \
[1:v]scale=1920:1080,fps=30,setsar=1[v1]; \
[v0][0:a][v1][1:a]concat=n=2:v=1:a=1[v][a]" \
-map "[v]" -map "[a]" -c:v libx264 -crf 16 -pix_fmt yuv420p -c:a aac final.mp4
Nunca copie flujo para concatenar entradas no coincidentes. "Tiene éxito" y produce reproducción rota.
3. Superposición, alpha y picture-in-picture
# elemento transparente sobre un fondo
ffmpeg -i bg.mp4 -i logo.mov -filter_complex \
"[0:v][1:v]overlay=W-w-48:48:format=auto" -c:v libx264 -crf 16 out.mp4
# picture-in-picture, fuente escalada y redondeada
ffmpeg -i main.mp4 -i insert.mp4 -filter_complex \
"[1:v]scale=640:-2[pip];[0:v][pip]overlay=W-w-40:H-h-40" out.mp4
Reglas de alpha:
- H.264/MP4 no puede transportar alpha. Use secuencia PNG, ProRes 4444 o WebM/VP9 con alpha.
- Verifique el alpha sobre un fondo contrastante después de cada etapa.
- Cuidado con los halos de alpha premultiplicado vs. recto en bordes oscuros; siga la convención del motor de renderizado.
4. Audio
# fondo musical con fundido y ducking bajo voz
ffmpeg -i video.mp4 -i music.mp3 -i voice.wav -filter_complex \
"[1:a]volume=0.35,afade=t=in:st=0:d=1,afade=t=out:st=28:d=2[bed]; \
[2:a]volume=1.0[vo]; \
[bed][vo]sidechaincompress=threshold=0.08:ratio=6:attack=8:release=250[duck]; \
[duck][vo]amix=inputs=2:duration=first:dropout_transition=0[a]" \
-map 0:v -map "[a]" -c:v copy -c:a aac -b:a 192k out.mp4
# medir sonoridad, luego normalizar
ffmpeg -i in.mp4 -af loudnorm=I=-14:TP=-1:LRA=11:print_format=json -f null -
ffmpeg -i in.mp4 -af loudnorm=I=-14:TP=-1:LRA=11 -c:v copy out.mp4
Los objetivos varían según el destino (-14 LUFS para muchas plataformas web, -23/-24 para radiodifusión). Mida, luego elija. Evite normalizar un archivo que ya está en el objetivo.
5. Subtítulos
# incrustar (subtítulos duros)
ffmpeg -i in.mp4 -vf "subtitles=captions.srt:force_style='FontName=Inter,FontSize=22,PrimaryColour=&H00FFFFFF,OutlineColour=&H80000000,BorderStyle=3,Outline=1,Shadow=0'" \
-c:v libx264 -crf 18 -c:a copy out.mp4
# subtítulos suaves (pista transportable)
ffmpeg -i in.mp4 -i captions.srt -c copy -c:s mov_text -metadata:s:s:0 language=eng out.mp4
Verifique RTL: force_style con una fuente que admita shaping, Alignment correcto y una inspección de fotograma renderizado. Mantenga los subtítulos dentro de las áreas seguras y por encima de la interfaz de la plataforma.
6. Codificaciones para plataformas
# YouTube horizontal, 1080p30
ffmpeg -i master.mov -c:v libx264 -preset slow -crf 18 -pix_fmt yuv420p \
-profile:v high -level 4.1 -movflags +faststart \
-c:a aac -b:a 192k -ar 48000 out_1080p.mp4
# red social vertical, 1080x1920
ffmpeg -i master.mov -vf "scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920" \
-c:v libx264 -preset slow -crf 18 -pix_fmt yuv420p -movflags +faststart \
-c:a aac -b:a 192k out_vertical.mp4
# intermedio de alta calidad para composición posterior
ffmpeg -i master.mov -c:v prores_ks -profile:v 3 -pix_fmt yuv422p10le -c:a pcm_s24le master.mov
Verifique que el codificador existe: ffmpeg -encoders | grep -E "libx264|prores|nvenc". Los codificadores hardware son rápidos pero a menudo de menor calidad por bit; compare antes de enviar.
7. Fotogramas, contact sheets, GIF
# fotogramas en momentos específicos
ffmpeg -ss 00:00:03.5 -i in.mp4 -frames:v 1 frame.png
# hoja de contactos
ffmpeg -i in.mp4 -vf "fps=1,scale=320:-1,tile=4x4" -frames:v 1 sheet.jpg
# GIF de alta calidad (palettegen/paletteuse)
ffmpeg -i in.mp4 -vf "fps=15,scale=640:-1:flags=lanczos,palettegen" palette.png
ffmpeg -i in.mp4 -i palette.png -lavfi "fps=15,scale=640:-1:flags=lanczos[x];[x][1:v]paletteuse" out.gif
8. Validación (no la omita)
ffprobe -v error \
-show_entries format=duration,size,bit_rate,format_name \
-show_entries stream=index,codec_type,codec_name,width,height,r_frame_rate,avg_frame_rate,pix_fmt,channels,sample_rate,nb_frames \
-of json final.mp4
Comprobaciones automatizadas:
# segmentos negros (fotogramas negros accidentales)
ffmpeg -i final.mp4 -vf "blackdetect=d=0.1:pix_th=0.05" -an -f null - 2>&1 | grep blackdetect || true
# segmentos congelados (pausa demasiado larga)
ffmpeg -i final.mp4 -vf "freezedetect=n=0.003:d=2" -an -f null - 2>&1 | grep freeze || true
# presencia de audio y nivel pico
ffmpeg -i final.mp4 -af volumedetect -f null - 2>&1 | grep -E "mean_volume|max_volume"
Luego inspeccione el primer fotograma, el último, cada transición y los fotogramas con mucho texto. Los números prueban que el archivo está bien formado; no prueban que luzca correcto.
9. Trampas de precisión de fotogramas
- Fuentes VFR (grabaciones de pantalla, teléfonos) se desvían de una línea de tiempo CFR. Normalice con
fps=30y verifique la duración. - Error de uno: N fotogramas a 30 fps son exactamente N/30 segundos; un render de 300 fotogramas es 10.0 s. Si la duración es 9.97 s, se perdió un fotograma.
- Audio truncado más corto que el video → silencio al final; añada padding o recorte deliberadamente.
- Video de teléfono rotado lleva una matriz de visualización;
-noautorotatesolo si realmente lo necesita. - Cambio de color después de codificar: verifique las etiquetas
color_primaries/transfer; una vista previa del navegador no es una referencia de color confiable. - Codificaciones repetidas degradan la calidad; mantenga un master de alta calidad y codifique a partir de él.
10. Paquete de entrega
output/
final_1080p.mp4 # primario
final_vertical.mp4 # variante de plataforma, si se solicita
final_master.mov # ProRes/H.264 CRF 14, conservado para futuras codificaciones
thumbnail.png # 1280x720 o 1080x1920
contact-sheet.jpg
captions.srt
project-report.md # versiones de herramientas, configuraciones, comprobaciones realizadas
Informe las propiedades exactas desde ffprobe; nunca las adivine.