Composição de Vídeo — Montagem, Áudio, Codificação, Validação
FFmpeg é a camada de entrega, não uma ferramenta de design. Ele deve receber cenas já projetadas e produzir um master limpo, além das codificações para plataformas.
Leia references/FFMPEG-COOKBOOK.md para comandos prontos para cópia e scripts/validate.sh para uma verificação pré-entrega.
Regra zero: sonde primeiro. Construir um gráfico de filtro baseado em propriedades de stream assumidas é a causa mais comum de saída quebrada.
ffprobe -v error -show_streams -show_format -of json input.mp4
1. Normalizar antes de combinar
Entradas incompatíveis causam tremor, silêncio, desvio de sincronia e halos. Antes de qualquer montagem com múltiplas fontes, faça cada entrada concordar com:
| Propriedade | Alvo |
|---|---|
| Resolução | master do projeto (ex.: 1920×1080) |
| Proporção de pixel | 1:1 |
| Taxa de quadros | FPS do projeto, constante |
| Base de tempo | consistente |
| Formato de pixel | yuv420p para entrega, yuva444p10le/PNG para alfa |
| Espaço de cor / transferência | um padrão; marque-o |
| Áudio | 48 kHz, estéreo, codec 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
Mantenha os intermediários em alta qualidade (CRF 12–16 ou ProRes). Codifique a versão de entrega uma vez.
2. Concatenação
Mesmo codec, tamanho, fps, formato de pixel e layout de áudio → cópia de stream, rápido e sem perdas:
printf "file 'shot_01.mp4'\nfile 'shot_02.mp4'\n" > list.txt
ffmpeg -f concat -safe 0 -i list.txt -c copy final.mp4
Qualquer outra coisa → gráfico de filtro:
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 faça concatenação com cópia de stream de entradas incompatíveis. Isso "funciona" e produz reprodução quebrada.
3. Sobreposição, alfa e picture-in-picture
# elemento transparente sobre um fundo
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, fonte redimensionada e arredondada
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
Regras para alfa:
- H.264/MP4 não pode transportar alfa. Use sequência PNG, ProRes 4444 ou WebM/VP9 com alfa.
- Verifique o alfa sobre um fundo contrastante após cada etapa.
- Cuidado com halos de alfa pré-multiplicado vs. reto em bordas escuras; siga a convenção do renderizador de origem.
4. Áudio
# música de fundo com fade in/out e ducking sob locução
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 loudness e depois 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
Os alvos variam por destino (-14 LUFS para muitas plataformas web, -23/-24 para radiodifusão). Meça, depois escolha. Evite normalizar um arquivo que já está no alvo.
5. Legendas
# queimar (legendas hard)
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
# legendas soft (faixa móvel)
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 com uma fonte com suporte a shaping, Alignment correto e inspeção de quadro renderizado. Mantenha as legendas dentro das áreas seguras e acima da interface da plataforma.
6. Codificações para plataformas
# paisagem YouTube, 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
# vertical redes sociais, 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
# intermediário de alta qualidade para composição adicional
ffmpeg -i master.mov -c:v prores_ks -profile:v 3 -pix_fmt yuv422p10le -c:a pcm_s24le master.mov
Verifique se o codificador existe: ffmpeg -encoders | grep -E "libx264|prores|nvenc". Codificadores de hardware são rápidos, mas geralmente de qualidade inferior por bit; compare antes de enviar.
7. Quadros, folhas de contato, GIF
# stills em momentos
ffmpeg -ss 00:00:03.5 -i in.mp4 -frames:v 1 frame.png
# folha de contato
ffmpeg -i in.mp4 -vf "fps=1,scale=320:-1,tile=4x4" -frames:v 1 sheet.jpg
# GIF de alta qualidade (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. Validação (não pule)
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
Verificações automatizadas:
# segmentos pretos (quadros pretos acidentais)
ffmpeg -i final.mp4 -vf "blackdetect=d=0.1:pix_th=0.05" -an -f null - 2>&1 | grep blackdetect || true
# segmentos congelados (pausa estática muito longa)
ffmpeg -i final.mp4 -vf "freezedetect=n=0.003:d=2" -an -f null - 2>&1 | grep freeze || true
# presença de áudio e nível de pico
ffmpeg -i final.mp4 -af volumedetect -f null - 2>&1 | grep -E "mean_volume|max_volume"
Em seguida, inspecione o primeiro quadro, o último quadro, cada transição e quadros com muito texto. Números provam que o arquivo está bem formado; eles não provam que está correto visualmente.
9. Armadilhas de precisão de quadro
- Fontes VFR (gravações de tela, celulares) desviam em relação a uma linha do tempo CFR. Normalize com
fps=30e verifique a duração. - Off-by-one: N quadros a 30 fps é exatamente N/30 segundos; uma renderização de 300 quadros é 10,0 s. Se a duração for 9,97 s, um quadro foi descartado.
- Áudio truncado mais curto que o vídeo → silêncio no final; preencha ou corte deliberadamente.
- Vídeo de celular girado carrega uma matriz de exibição; use
-noautorotateapenas se realmente quiser. - Mudança de cor após a codificação: verifique as tags
color_primaries/transfer; uma prévia no navegador não é uma referência de cor confiável. - Codificações repetidas degradam a qualidade; mantenha um master de alta qualidade e codifique a partir dele.
10. Pacote de entrega
output/
final_1080p.mp4 # principal
final_vertical.mp4 # variante de plataforma, se solicitado
final_master.mov # ProRes/H.264 CRF 14, mantido para futuras codificações
thumbnail.png # 1280x720 ou 1080x1920
contact-sheet.jpg
captions.srt
project-report.md # versões de ferramentas, configurações, verificações realizadas
Informe as propriedades exatas do ffprobe; nunca as adivinhe.