Vídeo com IA: Claude Code, Codex e ElevenLabs · Capítulo 4 de 25 · 27 min
Cortar, juntar, mixar e exportar vídeo com FFmpeg sem abrir editor
Domine os sete comandos FFmpeg que todo agente escreve e confira cada saída com ffprobe até entregar o vídeo vertical com legenda e som no volume certo.
Este capítulo faz parte do curso gratuito Vídeo com IA: Claude Code, Codex e ElevenLabs.
O FFmpeg é a ferramenta que o resto do curso chama por baixo. O Remotion e o HyperFrames codificam o vídeo final com ele, a transcrição recebe o áudio que ele extrai e o Claude só consegue avaliar um vídeo porque o FFmpeg quebra o arquivo em quadros JPEG. Quando um agente escreve um script de edição, quase sempre o que sai é uma sequência de comandos FFmpeg.
Sem ler esses comandos, você aceita o que o agente entregar: um corte que recomprimiu o arquivo inteiro sem necessidade, uma legenda que escorrega porque o vídeo estava em 29,97 quadros por segundo, uma trilha que cobre a voz. Cada erro desses custa uma nova rodada de render e, a partir da Parte 3, tokens do agente tentando adivinhar a causa.
Nesta aula você não usa agente nenhum. Digita sete comandos, confere cada saída com o ffprobe e só no fim entrega um prompt para o Claude Code repetir o que você já entendeu. A diferença entre copiar e recomprimir decide o custo e a qualidade de tudo o que vem depois.
Ler o arquivo antes de cortar
Em 12/10/2026, a página oficial de downloads lista o FFmpeg 9.0.2, de 18/09/2026, como versão estável mais recente; a linha 8.1 segue com a 8.1.3, lançada em 21/09/2026. Qualquer 8.x ou 9.x serve para esta aula. Se ffmpeg -version responder command not found, o problema é o PATH, resolvido em montar a bancada de vídeo com IA; quem ainda estranha o terminal encontra no curso de Claude Code por que trocar o clique pelo comando.
Dois termos aparecem em todo comando. Codec é o formato de compressão, como o idioma em que o arquivo foi escrito: H.264 para imagem, AAC para som. Contêiner (MP4, MOV, WebM) é o envelope que carrega as faixas; trocar o envelope não muda o idioma da carta. Antes de cortar, rode da raiz video-ia o comando ffprobe -v error -show_streams -of json midia/raw/bruto.mp4, o raio X que mostra codec, resolução, duração e quadros por segundo de cada faixa.
De todos os campos, r_frame_rate é o que mais derruba pipeline. Se vier 30/1, o vídeo tem 30 quadros por segundo; se vier 30000/1001, são 29,97. Tratar 29,97 como 30 desloca a legenda cerca de 0,06 segundo por minuto, e no minuto oito ela já está meio segundo fora da fala. O padrão de entrega do curso é H.264, yuv420p, 30 fps, -crf 20, AAC 192k e -movflags +faststart, em 1920x1080 (16:9) ou 1080x1920 (9:16), com 10% de área segura nas bordas.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
Colocar -ss e -to antes do -i faz o programa pular direto para o trecho, sem decodificar o começo do arquivo. A quarta caixa é a decisão cara. Reencodar, ou seja, recomprimir, é como fotocopiar uma fotocópia: cada passagem perde um pouco e demora. Com -c copy o FFmpeg copia os pacotes sem recomprimir, em segundos e sem perda; o preço é que o corte começa no quadro completo (o I-frame, que o codec grava inteiro de tempos em tempos) anterior ao instante pedido, e o trecho entre esse quadro e o -ss vai junto para o arquivo. No MP4, o FFmpeg marca esse trecho para o player pular, então o ffprobe mostra a duração pedida; ao juntar as partes com concat, porém, ele reaparece. O tamanho da sobra depende do intervalo entre quadros completos do seu arquivo: o libx264 no padrão grava um a cada até 250 quadros, cerca de 8 segundos a 30 fps. O comando ffprobe -v error -select_streams v -skip_frame nokey -show_entries frame=pts_time -of csv=p=0 midia/raw/bruto.mp4 lista os instantes de cada quadro completo.
Os sete comandos da tabela cobrem quase tudo o que um agente escreve num pipeline de vídeo. Os quatro primeiros estão no primeiro script; os outros três, no script de entrega.
Os sete comandos que o pipeline reutiliza
| Comando | Para que serve | Recomprime? |
|---|---|---|
| ffprobe -show_streams | Ler codec, resolução, fps e duração | Não, só lê |
| -ss -to -c copy | Cortar um trecho sem perda | Não |
| -f concat -c copy | Juntar partes com mesmo codec e fps | Não |
| -vn -ac 1 -ar 16000 | Extrair áudio leve para transcrição | Só o áudio |
| -vf fps=0.5,scale=960:-2 | Tirar quadros para revisão visual | Gera JPEG |
| amix e loudnorm | Mixar voz e trilha no volume certo | Só o áudio |
| crop, scale e subtitles | Reenquadrar 9:16 e queimar legenda | Sim, a imagem |
Padrão de entrega do curso: H.264, yuv420p, 30 fps, crf 20, AAC 192k e +faststart.
#!/usr/bin/env bash
# scripts/aula04_cortes.sh: lê o bruto, corta sem recomprimir, junta as partes
# e extrai o áudio leve (transcrição) e os quadros (revisão visual).
# Uso: bash scripts/aula04_cortes.sh (na raiz video-ia; o bruto fica em midia/raw/ e só é lido)
set -euo pipefail # para no primeiro erro, variável vazia ou pipe quebrado
BRUTO="midia/raw/bruto.mp4"
# 1) Raio X do arquivo em JSON: codec, resolução, fps e duração de cada faixa
ffprobe -v error -show_streams -of json "$BRUTO" > logs/ffprobe-bruto.json
echo "fps declarado:"
grep -m1 '"r_frame_rate"' logs/ffprobe-bruto.json # "30/1" = 30 fps; "30000/1001" = 29,97 fps
# 2) Dois cortes SEM recomprimir
# -nostdin não espera teclado (essencial em script e em agente)
# -v error só mostra erro de verdade
# -y sobrescreve a saída sem perguntar
# -ss/-to antes do -i: pula direto para o trecho, sem decodificar o começo
# -c copy copia os pacotes; o corte começa no quadro completo ANTERIOR ao -ss
ffmpeg -nostdin -v error -y -ss 00:01:10 -to 00:02:10 -i "$BRUTO" -c copy renders/corte01.mp4
ffmpeg -nostdin -v error -y -ss 00:04:30 -to 00:05:00 -i "$BRUTO" -c copy renders/corte02.mp4
# 3) Juntar: o demuxer concat lê uma lista de arquivos (caminhos relativos à pasta da lista).
# Com -c copy só funciona se codec, resolução e fps forem iguais (aqui são: vêm do mesmo bruto)
printf "file '../renders/corte01.mp4'\nfile '../renders/corte02.mp4'\n" > edicao/partes.txt
ffmpeg -nostdin -v error -y -f concat -safe 0 -i edicao/partes.txt -c copy renders/junto.mp4
ffprobe -v error -show_entries format=duration -of csv=p=0 renders/junto.mp4 # esperado: perto de 90, ou alguns segundos a mais
# (cada parte traz o trecho desde o quadro completo anterior ao -ss; para a soma exata, recomprima os cortes)
# 4) Áudio leve para o Scribe v2 (Aula 17): sem vídeo (-vn), mono (-ac 1),
# 16 kHz (-ar 16000), MP3 a 64 kbps. Arquivo pequeno, sobe rápido, mesma transcrição.
ffmpeg -nostdin -v error -y -i renders/junto.mp4 -vn -ac 1 -ar 16000 -b:a 64k audio/junto.mp3
# 5) Quadros para o Claude revisar (Aula 11): 1 quadro a cada 2 s (fps=0.5),
# 960 px de largura com altura par automática (scale=960:-2). A API aceita JPEG, PNG, GIF e WebP.
mkdir -p qa/frames/junto
ffmpeg -nostdin -v error -y -i renders/junto.mp4 -vf "fps=0.5,scale=960:-2" qa/frames/junto/q_%03d.jpg
ls qa/frames/junto | wc -l # 90 s de vídeo dão cerca de 45 quadrosO áudio mono de 16 kHz a 64 kbps é o formato que a transcrição recebe: arquivo pequeno, envio rápido e o mesmo texto de volta; o uso dele com o Scribe v2 está em transcrever com Scribe e cortar por palavra. Os quadros a cada 2 segundos, com 960 px de largura, são o material da revisão visual pelo Claude, e o custo deles em tokens fica em QA visual com a visão do Claude.
Transcrição e opções novas do FFmpeg 8 e 9
fileText Transcrever com o filtro whisper
O FFmpeg também transcreve sozinho. Desde a 8.0 existe o filtro de áudio whisper, que roda o whisper.cpp na sua máquina, sem chamar API nenhuma. Os pacotes de apt, brew e winget costumam vir sem ele; ffmpeg -filters | grep whisper responde se o seu build tem. No manual do 9.0, a opção format aceita text, srt e json e max_len quebra as linhas, mas o filtro não grava o instante de cada palavra: para legenda palavra a palavra, use o Scribe ou o transcribe do HyperFrames, como mostra a Aula 22.

Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
terminal Trocar -vsync por -fps_mode no FFmpeg 9
Desde 04/08/2026, com o FFmpeg 9.0, a opção -vsync não existe mais; saíram junto -top, -qphist, -filter_complex_script e -adrift_threshold. Os scripts desta aula não usam nenhuma delas, mas os agentes aprenderam com exemplos antigos e ainda escrevem -vsync vfr ao extrair quadros. O sintoma é imediato: o comando para com Unrecognized option 'vsync' e nenhum JPEG sai. Entre 07/09 e 25/09/2026, cinco relatos públicos em três projetos abertos registraram a mesma quebra.
Troque -vsync vfr por -fps_mode vfr, -vsync 0 por -fps_mode passthrough e -vsync 1 por -fps_mode cfr. A opção nova existe desde o FFmpeg 5.0, então o comando corrigido roda no 8.x e no 9.x. O cuidado fica com quem ainda atende máquinas com o FFmpeg 4.4 do Ubuntu 22.04: ali -fps_mode não existe, e o script precisa ler a versão antes de escolher a opção, como no trecho abaixo. Está certo quando o mesmo script extrai os quadros no 9.0.2 e na máquina mais antiga da equipe sem mudar uma linha.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
# Rode na raiz video-ia. FFmpeg 5.0 ou superior: -fps_mode. FFmpeg 4.x: -vsync (removido no 9.0).
# Build de desenvolvimento ("ffmpeg version N-...") não tem número: o teste falha e fica o -fps_mode.
MAIOR=$(ffmpeg -version | head -1 | sed -E 's/^ffmpeg version n?([0-9]+).*/\1/')
if [ "$MAIOR" -lt 5 ] 2>/dev/null; then MODO=(-vsync vfr); else MODO=(-fps_mode vfr); fi
# select guarda só os quadros com troca de cena acima de 30%;
# o modo vfr impede o FFmpeg de duplicar quadros para preencher o tempo entre eles.
mkdir -p qa/frames/cenas
ffmpeg -nostdin -v error -y -i renders/junto.mp4 \
-vf "select='gt(scene,0.3)',scale=960:-2" "${MODO[@]}" qa/frames/cenas/c_%03d.jpg
ls qa/frames/cenas | wc -l # um JPEG por troca de cenaO 9.0 trouxe outra mudança que pega quem lê mídia pela rede: o FFmpeg passou a verificar o certificado TLS por padrão. Se o bruto vem por HTTPS de um servidor interno com certificado próprio e o comando passa a recusar a conexão, instale um certificado válido no servidor; desligar a verificação com -tls_verify 0 só serve para um teste pontual numa rede que você controla.
Mixar, reenquadrar, legendar e normalizar a entrega
O segundo script transforma o corte 16:9 em vertical pronto para publicar. No som, entra o loudness, o volume percebido ao longo do tempo, medido em LUFS: é a média da conversa, e não o grito mais alto. O filtro loudnorm ajusta o arquivo a um alvo. A regra do curso é -16 LUFS para o YouTube longo e -14 LUFS para Reels e TikTok, com pico máximo de -1,5 dB. A trilha fica 20 dB abaixo da voz, e o amix leva normalize=0 para não rebaixar a narração pela metade. Quando a peça inteira nasce no HyperFrames, a mesma meta pode ser aplicada lá dentro, com a normalização com ducking (02/10/2026) e o limitador true-peak (11/10/2026); o FFmpeg continua sendo o caminho quando a voz chega de fora do render.
Na imagem, o recorte 9:16 é geométrico: uma janela com a altura inteira, centralizada. Ele serve quando o assunto está parado no centro. Não existe auto-reframe no FFmpeg 8.x nem no 9.0; seguir o rosto exige detectar a pessoa quadro a quadro, o que fica para editar por transcrição e reenquadrar. A legenda queimada com MarginV=180 fica acima da interface do Reels, mas não sai mais do vídeo: guarde o SRT separado para publicar como faixa também.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
#!/usr/bin/env bash
# scripts/aula04_entrega_9x16.sh: do corte 16:9 com voz e trilha separadas até o MP4 vertical pronto.
# Uso: bash scripts/aula04_entrega_9x16.sh (na raiz video-ia)
set -euo pipefail
VIDEO="renders/junto.mp4" # imagem 16:9; o áudio original fica de fora
VOZ="audio/narracao.mp3" # narração (ElevenLabs, Aula 15)
TRILHA="audio/trilha.mp3" # trilha instrumental (Eleven Music, Aula 18)
SRT="legendas/narracao.srt" # legenda (Scribe v2, Aula 17); caminho sem acento nem dois-pontos
# Etapa A: mix de som.
# [2:a]volume=-20dB trilha 20 dB abaixo da voz
# amix=inputs=2:duration=first soma voz e trilha e para quando a voz (primeira entrada) acaba
# normalize=0 impede o amix de baixar o volume de cada entrada pela metade
# loudnorm=I=-14:TP=-1.5:LRA=11 -14 LUFS para Reels e TikTok (use I=-16 no YouTube longo)
# -ar 48000 o loudnorm sobe o áudio para 192 kHz; o -ar 48000 traz a saída de volta a 48 kHz
# -map 0:v -map "[a]" imagem do arquivo 0, som do grafo
# -c:v copy a imagem ainda não muda, então não recomprime
ffmpeg -nostdin -v error -y -i "$VIDEO" -i "$VOZ" -i "$TRILHA" \
-filter_complex "[2:a]volume=-20dB[m];[1:a][m]amix=inputs=2:duration=first:normalize=0[mix];[mix]loudnorm=I=-14:TP=-1.5:LRA=11[a]" \
-map 0:v -map "[a]" -c:v copy -c:a aac -b:a 192k -ar 48000 -shortest renders/mix_16x9.mp4
# Etapa B: imagem vertical.
# crop=ih*9/16:ih:(iw-ih*9/16)/2:0 janela 9:16 com a altura inteira, centralizada na horizontal
# scale=1080:1920:flags=lanczos escala para o tamanho de entrega com um filtro nítido
# setsar=1 pixel quadrado (sem isso alguns players esticam a imagem)
# subtitles=...:force_style=... queima a legenda; MarginV=180 a afasta da interface do Reels
# -crf 20 -preset medium qualidade alta com velocidade razoável
# -pix_fmt yuv420p formato de cor que todo celular toca
# -r 30 30 fps de entrega
# -movflags +faststart índice no começo: o vídeo começa a tocar antes de baixar inteiro
ffmpeg -nostdin -v error -y -i renders/mix_16x9.mp4 \
-vf "crop=ih*9/16:ih:(iw-ih*9/16)/2:0,scale=1080:1920:flags=lanczos,setsar=1,subtitles=$SRT:force_style='FontName=Inter,FontSize=14,Outline=2,Alignment=2,MarginV=180'" \
-c:v libx264 -preset medium -crf 20 -pix_fmt yuv420p -r 30 \
-c:a copy -movflags +faststart renders/saida_9x16.mp4
# Etapa C: conferir o que saiu
ffprobe -v error -show_entries stream=codec_name,width,height,r_frame_rate,pix_fmt \
-show_entries format=duration -of default=nw=1 renders/saida_9x16.mp4
# Etapa D: medir o loudness final (input_i deve ficar perto de -14)
ffmpeg -nostdin -hide_banner -i renders/saida_9x16.mp4 -af loudnorm=print_format=json -f null - 2>&1 | grep -E 'input_(i|tp)'Com os dois scripts lidos, faça o caminho inteiro no seu bruto, um passo por vez, conferindo a saída antes de seguir. Deixe na árvore do projeto um MP4 de 1 a 10 minutos em midia/raw/bruto.mp4, uma narração em audio/narracao.mp3, uma trilha em audio/trilha.mp3 e um SRT qualquer em legendas/narracao.srt.
Levar o bruto ao vertical aprovado em oito passos
Rode cada passo na raiz video-ia e só avance quando o sinal de acerto aparecer.
Passo 1: Confira a instalação com ffmpeg -version e ffprobe -version
Deu certo quando: A primeira linha mostra ffmpeg version 9.0.2, 8.1.3 ou outra 8.x.
Erro comum: Command not found no Windows por falta do PATH; reabra o terminal depois de instalar.
Passo 2: Leia o bruto com ffprobe e guarde o JSON
ffprobe -v error -show_streams -of json midia/raw/bruto.mp4 > logs/ffprobe-bruto.json
Deu certo quando: codec_name traz h264 e aac, e width, height e r_frame_rate estão preenchidos.
Erro comum: r_frame_rate em 30000/1001 anotado como 30 fps; a legenda escorrega minutos depois.
Passo 3: Corte sem recomprimir com -ss, -to e -c copy
Deu certo quando: O comando termina em poucos segundos e o ffprobe mostra uma duração perto da pedida.
Erro comum: Esquecer o -c copy e recomprimir o arquivo inteiro, com minutos de espera e perda de qualidade.
Passo 4: Junte os cortes com o demuxer concat
Deu certo quando: A duração final fica perto da soma das partes, sem quadro congelado na emenda; alguns segundos a mais vêm do trecho anterior a cada -ss.
Erro comum: Partes com fps ou resolução diferentes; a emenda engasga. Recomprima tudo de uma vez com trim e concat no -filter_complex.
Passo 5: Misture voz e trilha com amix e loudnorm
Deu certo quando: A trilha aparece só nas pausas da fala e a medição final mostra input_i perto de -14.
Erro comum: Trilha mais longa que a voz sem -shortest, deixando 40 segundos de música no final.
Passo 6: Reenquadre para 9:16 com crop central e scale
Deu certo quando: O ffprobe mostra 1080x1920 e o rosto continua inteiro no quadro.
Erro comum: Pessoa no terço esquerdo do 16:9; o recorte central corta metade do rosto. Ajuste o x do crop.
Passo 7: Queime a legenda com MarginV=180
Deu certo quando: O texto fica acima de 180 px da borda inferior e dentro dos 10% de área segura nas laterais.
Erro comum: Caminho do SRT com dois-pontos ou acento quebra o filtro; use legendas/narracao.srt e rode o comando da raiz video-ia.
Passo 8: Rode scripts/verificar_entrega.py em renders/saida_9x16.mp4
Deu certo quando: O script imprime OK nos seis critérios e sai com código 0.
Erro comum: pix_fmt diferente de yuv420p; alguns players do Instagram mostram tela preta. Mantenha -pix_fmt yuv420p.
No fim você tem: Um MP4 1080x1920, 30 fps, H.264 e AAC, com legenda legível e trilha abaixo da voz, aprovado pelo verificador.
"""scripts/verificar_entrega.py: confere um MP4 contra o padrão de entrega do curso.
Uso (na raiz video-ia):
python scripts/verificar_entrega.py renders/saida_9x16.mp4 audio/narracao.mp3 9:16
Saída: uma linha OK ou FALHA por critério; código de saída 0 só se tudo passar.
Critérios: H.264 e AAC, yuv420p, 30 fps, 1080x1920 (9:16) ou 1920x1080 (16:9)
e duração do vídeo a no máximo 0,5 s do áudio de referência.
Depende só do ffprobe no PATH (vem junto com o FFmpeg).
"""
import json
import subprocess
import sys
def probe(caminho: str) -> dict:
"""Roda o ffprobe e devolve faixas e formato como dicionário."""
saida = subprocess.run(
["ffprobe", "-v", "error", "-show_streams", "-show_format", "-of", "json", caminho],
capture_output=True, text=True, check=True,
).stdout
return json.loads(saida)
arquivo, audio_ref, formato = sys.argv[1], sys.argv[2], sys.argv[3]
alvo = {"9:16": (1080, 1920), "16:9": (1920, 1080)}[formato]
info = probe(arquivo)
video = next(s for s in info["streams"] if s["codec_type"] == "video")
audio = next((s for s in info["streams"] if s["codec_type"] == "audio"), None)
num, den = map(int, video["r_frame_rate"].split("/")) # "30/1" ou "30000/1001"
fps = num / den
dur_video = float(info["format"]["duration"])
dur_audio = float(probe(audio_ref)["format"]["duration"])
criterios = {
"codec de vídeo h264": video["codec_name"] == "h264",
"codec de áudio aac": audio is not None and audio["codec_name"] == "aac",
"pix_fmt yuv420p": video.get("pix_fmt") == "yuv420p",
"fps = 30": abs(fps - 30) < 0.01, # 29,97 (30000/1001) reprova de propósito
f"dimensões {alvo[0]}x{alvo[1]}": (video["width"], video["height"]) == alvo,
"duração a até 0,5 s do áudio": abs(dur_video - dur_audio) <= 0.5,
}
for nome, ok in criterios.items():
print(("OK " if ok else "FALHA ") + nome)
sys.exit(0 if all(criterios.values()) else 1)O verificador reprova 29,97 fps de propósito: o padrão de entrega é 30. Se o bruto chegou em 29,97, exporte o vídeo longo em 29,97 e só os cortes 9:16 em 30, com -r 30 depois do crop, e gere a legenda a partir do arquivo final, nunca do bruto. Se o corte precisa começar no quadro exato de uma fala, recomprima só aquele trecho com -c:v libx264 -crf 20; se é só separar blocos, fique no -c copy e aceite o trecho extra desde o quadro completo anterior. Se a pessoa anda pela cena, o recorte central não basta: grave já pensando no 9:16 ou use o reenquadramento por rosto da Aula 22.
Na Cozinha da Rafa, o vídeo longo da semana é o bolo de rolo, 8 minutos em 16:9 e 30 fps, gravado com a câmera fixa no balcão. Do bruto saem os dois cortes 9:16 de 60 segundos da semana, a massa e o enrolar. O script corta os trechos sem recomprimir, mistura a narração da Rafa com a trilha a -20 dB, normaliza em -14 LUFS, recorta o centro, onde ela fica atrás do balcão, e queima a legenda. O verificador reprova a primeira versão porque o -r 30 tinha ficado de fora e o arquivo saiu em 29,97; com a correção, os dois cortes passam. Custo de API: zero.
Existem atalhos. Para tirar silêncios numa linha, o auto-editor corta pelo volume do áudio; versão, instalação e comando estão em editar por transcrição e reenquadrar. Em Python, o MoviePy 2.2.1 e o PyAV 19.0.1 (que exige Python 3.12 ou superior) embrulham o mesmo FFmpeg. O curso usa o FFmpeg direto porque é o que os agentes escrevem melhor e o que você lê sem camada no meio. O raciocínio de cortar curto e medir cada etapa também aparece no curso de podcasts, em cortar clipes e medir o resultado no funil.
Cinco hábitos que evitam render perdido
Leia o arquivo com ffprobe antes e depois de todo comando que o altera.
- Use -nostdin -v error -y em todo ffmpeg de script ou de agente
- Separe blocos com -c copy e recomprima só o trecho que pede precisão
- Confira r_frame_rate: 30000/1001 não é 30
- Entregue com -pix_fmt yuv420p e +faststart e guarde o SRT separado
- No FFmpeg 9, troque -vsync por -fps_mode (vfr, passthrough ou cfr)
O teste: O hábito pegou quando o scripts/verificar_entrega.py passa na primeira tentativa.
alexandrecaramaschi.com/educacao/frontends-com-vibecoding
Glossário rápido
FFmpeg
Programa de linha de comando que lê, corta, mistura e codifica áudio e vídeo; o motor que o Remotion e o HyperFrames chamam por baixo.
ffprobe
Ferramenta que acompanha o FFmpeg e lê codec, resolução, fps e duração de um arquivo, como um raio X antes da cirurgia.
codec
Formato de compressão de uma faixa (H.264 para imagem, AAC para som), como o idioma em que o arquivo foi escrito.
contêiner
Envelope que carrega as faixas de áudio e vídeo (MP4, MOV, WebM); trocar o envelope não muda o idioma da carta.
reencodar
Recomprimir o vídeo; como fotocopiar uma fotocópia, cada passagem perde um pouco e demora. O oposto é copiar com -c copy.
quadro completo (I-frame)
Quadro que o codec grava inteiro de tempos em tempos; o corte com -c copy começa no último deles antes do ponto pedido.
grafo de filtros
Cadeia de filtros do FFmpeg (-vf, -af, -filter_complex) em que a saída de um alimenta o próximo, como estações de uma linha de montagem.
loudness (LUFS)
Volume percebido ao longo do tempo, medido em LUFS; a média da conversa, e não o grito mais alto.
área segura
Margem de 10% nas bordas do quadro onde texto não entra, para não ficar sob a interface do Reels, do TikTok ou do YouTube.
Com a mecânica na mão, delegar fica seguro: você sabe o que pedir e sabe ler o que voltar. O prompt abaixo faz o caminho inteiro da aula num projeto real; no Codex, a mesma tarefa vira uma skill chamada pelo nome, montada em configurar o Codex com GPT-6 Astra. Para servir o vertical num site, o tamanho e o formato do arquivo seguem o capítulo de preparar imagens, ícones e vídeo para a web.
Guia prático: FFmpeg como inspetor que devolve evidência
Os sete comandos da aula produzem o vídeo; este guia usa o mesmo FFmpeg para inspecionar o resultado antes de qualquer revisão humana ou da visão do Claude. Quatro filtros detectores (tela preta, imagem congelada, silêncio e loudness, o volume percebido) varrem o MP4 inteiro e anotam o instante de cada problema num log que o agente lê. Você sai com scripts/qa_detectores.sh e com as novidades do FFmpeg 9 que importam para quem automatiza.
Funções, casos de uso e aplicações
Funções
Detectores e novidades do FFmpeg que entram no pipeline
| Função ou recurso | O que faz | Quando usar | Desde |
|---|---|---|---|
| blackdetect | Marca trechos pretos com início, fim e duração | Emenda de concat que deixou um buraco | Em todo 8.x e 9.x |
| freezedetect | Acusa imagem parada além da tolerância de ruído | B-roll que acabou antes da narração | Em todo 8.x e 9.x |
| silencedetect | Marca silêncio abaixo de um nível em dB por um tempo mínimo | Voz que começou atrasada ou faixa de áudio vazia | Em todo 8.x e 9.x |
| ebur128 com peak=true | Mede o loudness integrado e o pico verdadeiro; framelog=quiet esconde o log quadro a quadro | Conferir os -14 LUFS do Reels sem recomprimir nada | Em todo 8.x e 9.x |
| -progress pipe:1 | Escreve o andamento em linhas chave=valor, como out_time e progress=end | Agente que acompanha um render longo sem ler a barra do terminal | Em todo 8.x e 9.x |
| Decodificador de WebP animado | Lê WebP animado de forma nativa, com demuxer próprio | Figurinha ou animação de marca em WebP que entra no vídeo | 04/08/2026 (FFmpeg 9.0) |
| Backend ONNX Runtime nos filtros DNN | Roda modelos ONNX dentro do grafo de filtros, com CUDA ou DirectML | Tirar fundo ou reduzir ruído sem sair do FFmpeg, quando o build tiver o backend | 04/08/2026 (FFmpeg 9.0) |
Os detectores só leem o arquivo; o FFmpeg 9.0.2, de 18/09/2026, é a versão estável mais recente da linha 9.
Casos de uso
Editora de vídeo de uma faculdade de ensino a distância em Campinas, responsável pelas videoaulas de vários cursos
Educação, ensino a distância
Dor
Alunos reclamavam de segundos de tela preta entre blocos das videoaulas, e o defeito só aparecia depois da publicação.
Solução
Ela pôs o qa_detectores.sh logo depois de cada montagem. O render com trecho preto volta para a etapa de montagem com o instante exato anotado no log.
Resultado
Acompanhar, mês a mês, se as reclamações de tela preta somem dos comentários e quantos renders o detector devolve por semana.
Cenário construído para fins didáticos. Números não correspondem a cliente específico.
Social media de uma loja de cosméticos em Manaus que publica Reels diários com trilha e locução
Marketing digital, varejo de beleza
Dor
Alguns Reels saíam baixos demais e outros estouravam no fone, e a revisão de áudio era feita só de ouvido.
Solução
O agente passou a rodar o detector depois da entrega e a anexar os valores de I e Peak ao parecer de QA; o vídeo fora da faixa volta para a etapa de mixagem.
Resultado
Observar se os Reels da semana ficam com I perto de -14 LUFS e se cai o número de vídeos devolvidos na revisão de áudio.
Cenário construído para fins didáticos. Números não correspondem a cliente específico.
Na prática
Salve como scripts/qa_detectores.sh e rode da raiz video-ia sobre a entrega da aula. O script só lê o MP4: decodifica o arquivo inteiro com -f null - (a saída nula, que descarta a imagem depois de analisada), grava o log completo e um resumo curto em logs/ e sai com código 2 quando acha tela preta ou imagem congelada; esse código é o que um orquestrador lê para devolver o vídeo à montagem. Em render longo, acrescente -progress pipe:1 -nostats ao comando de exportação: o FFmpeg passa a escrever out_time= e, no fim, progress=end, linhas que o agente lê sem interpretar a barra de andamento.
#!/usr/bin/env bash
# scripts/qa_detectores.sh: procura tela preta, imagem congelada e silêncio e mede o loudness.
# Uso: bash scripts/qa_detectores.sh renders/saida_9x16.mp4 (na raiz video-ia; só LÊ o vídeo)
set -euo pipefail
ARQ="${1:-renders/saida_9x16.mp4}"
NOME=$(basename "$ARQ" .mp4)
mkdir -p logs
# -f null - decodifica o arquivo inteiro e descarta a imagem: os detectores escrevem no log.
# blackdetect trecho preto de 0,5 s ou mais (pix_th: quão escuro conta como preto)
# freezedetect imagem parada por 1 s ou mais (n: tolerância a ruído; tela preta também conta)
# silencedetect áudio abaixo de -50 dB por 0,5 s ou mais
# ebur128 loudness integrado (I) e pico verdadeiro (Peak), sem o log quadro a quadro
ffmpeg -nostdin -hide_banner -i "$ARQ" \
-vf "blackdetect=d=0.5:pix_th=0.1,freezedetect=n=0.003:d=1" \
-af "silencedetect=n=-50dB:d=0.5,ebur128=peak=true:framelog=quiet" \
-f null - 2> "logs/qa-$NOME-completo.txt"
# Resumo legível: uma linha por achado, sem o prefixo [Parsed_...]
grep -E "black_start|freeze_start|freeze_duration|silence_start|silence_duration|^ +I:|^ +Peak:" \
"logs/qa-$NOME-completo.txt" | sed -E 's/^\[[^]]*\] //; s/^ +//' > "logs/qa-$NOME.txt" || true
cat "logs/qa-$NOME.txt"
PRETAS=$(grep -c "black_start" "logs/qa-$NOME.txt" || true)
PARADAS=$(grep -c "freeze_start" "logs/qa-$NOME.txt" || true)
if [ "$PRETAS" -gt 0 ] || [ "$PARADAS" -gt 0 ]; then
echo "REVISAR: $PRETAS trecho(s) preto(s) e $PARADAS imagem(ns) parada(s). Abra os instantes acima."
exit 2
fi
echo "OK: nenhum trecho preto ou congelado; confira I perto de -14 LUFS e Peak abaixo de -1,5."Inspecionar a entrega antes da revisão
Cinco passos na raiz video-ia, sem recomprimir nada.
Passo 1: Rode o detector na entrega 9:16
bash scripts/qa_detectores.sh renders/saida_9x16.mp4
Deu certo quando: O resumo mostra I e Peak, e a última linha diz OK.
Erro comum: Rodar sobre o bruto de midia/raw/ e confundir problema da câmera com problema da montagem.
Passo 2: Leia o instante de cada achado
black_start e freeze_start dizem o segundo; extraia o quadro com ffmpeg -ss <segundo> -i renders/saida_9x16.mp4 -frames:v 1 qa/frames/achado.jpg.
Deu certo quando: O quadro extraído mostra o defeito que o log apontou.
Erro comum: Corrigir sem olhar: o mesmo trecho preto aparece também como imagem congelada.
Passo 3: Ajuste a tolerância ao seu material
Receita com câmera fixa tem planos quase parados; suba o d do freezedetect para dois ou três segundos.
Deu certo quando: Os achados que sobram são defeitos de verdade.
Erro comum: Desligar o detector porque ele acusou um plano parado de propósito.
Passo 4: Compare o loudness com a meta
Deu certo quando: I perto de -14 LUFS no Reels e de -16 no YouTube longo, com Peak abaixo de -1,5.
Erro comum: Medir um arquivo com segundos de silêncio no começo e culpar o loudnorm pelo número baixo.
Passo 5: Entregue só o resumo ao agente
Deu certo quando: O parecer de QA cita logs/qa-*.txt no lugar da saída inteira do terminal.
Erro comum: Colar no chat o log completo, com milhares de linhas.
No fim você tem: Uma entrega varrida por quatro detectores, com cada problema anotado pelo segundo em que acontece.
Armadilhas
Inspecionar com FFmpeg sem se enganar
Evite
Coluna a evitar
- Usar ebur128 sem framelog=quiet e afogar o log
- Tratar todo silêncio no começo como defeito
- Reaproveitar scripts com -vsync do FFmpeg 4.x
- Passar -t negativo e esperar que o FFmpeg ignore
- Supor que o build tem ONNX Runtime ou o filtro whisper
Faça assim
Coluna recomendada
- framelog=quiet e leitura só do resumo
- Respiro curto e registrado no briefing
- -fps_mode, que existe desde o 5.0, como na aula
- Calcular a duração antes: desde o 9.0.2, -t negativo é recusado
- Rodar ffmpeg -filters e ffmpeg -h filter=<nome> antes
Rode os três scripts no seu próprio bruto, troque o alvo de loudness para -16 e gere também a versão 16:9 do vídeo longo. Está pronto quando o verificador devolve OK nos seis critérios para o corte 9:16, o MP4 toca no celular com a legenda acima da interface e a trilha só aparece nas pausas da fala. A próxima aula, montar vídeo em React com Remotion, usa este mesmo verificador no MP4 que o Remotion gerar.
Seu caderno neste capítulo
Abrir o caderno completoSelecione um trecho do capítulo para destacar ou anotar. Nos vídeos e áudios, use Anotar este momento. No teclado, selecione com Shift e as setas e use Alt+Shift+D para destacar ou Alt+Shift+N para anotar.
Salvo neste navegador. Entre na sua conta para levar o caderno a outros aparelhos.
Entre na sua conta para compartilhar o que aprendeu e convidar alguém para estudar com você.
Conexões deste capítulo
Veja o que estudar antes e para onde seguir depois, explore os conceitos e compare abordagens em outros cursos. Sugestões marcadas como “sugerido pelo grafo” vêm dos assuntos em comum, não do índice do curso.
Estude antes
- CursoClaude Code CLI: Programação com IA
- CursoAstra profundosugerido pelo grafoA quinta parte do Astra planeja o vídeo e edita o material bruto com o modelo dirigindo a ferramenta. O curso de vídeo com IA aprofunda esse trabalho com Claude Code, Codex e ElevenLabs, do roteiro à publicação. O grafo já sugeria esta ordem pela regra de entrada da trilha; com a ordem anterior curada, ela passa a ser declarada (Etapa 4, wave 3).
- CursoSetup Completo: do zero ao Claude Codesugerido pelo grafo7 capítulos de “Vídeo com IA: Claude Code, Codex e ElevenLabs” usam conceitos apresentados em “Setup Completo: do zero ao Claude Code”.
Depois, siga para
- CursoFrontends com Vibecodingsugerido pelo grafo21 capítulos de “Frontends com Vibecoding” usam conceitos apresentados em “Vídeo com IA: Claude Code, Codex e ElevenLabs”.
- CursoDo Agile ao Agentic Operating Modelsugerido pelo grafo5 capítulos de “Do Agile ao Agentic Operating Model” usam conceitos apresentados em “Vídeo com IA: Claude Code, Codex e ElevenLabs”.
- CursoAgentes de IA Autônomos: Do Conceito à Produçãosugerido pelo grafo7 capítulos de “Agentes de IA Autônomos: Do Conceito à Produção” usam conceitos apresentados em “Vídeo com IA: Claude Code, Codex e ElevenLabs”.
- CursoLLM FinOps: o custo da IA para quem assina o orçamentosugerido pelo grafo4 capítulos de “LLM FinOps: o custo da IA para quem assina o orçamento” usam conceitos apresentados em “Vídeo com IA: Claude Code, Codex e ElevenLabs”.
O mesmo assunto em outros cursos
- Frontends com VibecodingConstruir profundidade e dirigir a montagem de vídeoExaminar conexões de Construir profundidade e dirigir a montagem de vídeo
- Astra profundoMontar um filme a partir do material disponívelExaminar conexões de Montar um filme a partir do material disponível
- Claude Code CLI: Programação com IAManter modelo e custo sob controle com os comandos de barraExaminar conexões de Manter modelo e custo sob controle com os comandos de barra
Voltar ao capítulo anterior: Montar a bancada de vídeo com IA mesmo sem nunca ter usado o terminal
Leve uma ideia para a prática
Escolha uma atividade no painel e volte a este curso quando quiser.
Atividades e evolução ficam reunidas no painel da sua conta.
Laboratórios ao vivo deste curso
Cada laboratório monta a biblioteca real dentro da aula, com controles para você mexer e o código do exemplo para copiar. O texto de reserva descreve a demonstração para quem lê sem JavaScript. O link abre o capítulo já no ponto do laboratório.
MediaRecorder, Canvas 2D e Long Animation Frames (plataforma)
Grave a cena em tempo real e veja os quadros que se perdem
Suba as partículas, force um bloqueio de 300 ms e grave seis segundos; compare com o render quadro a quadro desta aula.
Pacote
Abrir no capítuloMontar vídeo em HTML com HyperFrames e escolher entre ele e o Remotionsem pacoteMotion
Ver agentes em paralelo trocando mensagens numa linha do tempo
Reproduza a cena, percorra o tempo pelo controle e compare o tempo de parede com a soma das barras de cada agente.
Pacote
Abrir no capítuloParalelizar cenas com subagentes sem estourar o limite das APIsmotionReact (sem dependência extra), com as APIs do Veo e do fal.ai
Prompt de vídeo em cinco camadas, pronto para a API
Escolha plano, câmera, luz, ação e áudio e copie o prompt e o JSON para o Veo ou para o fal.ai.
Pacote
Abrir no capítuloEscrever prompt de vídeo em cinco camadas e manter o personagem consistentereactReact (sem dependência extra), com o comando para o FFmpeg
Corte o vídeo apagando palavras da transcrição
Aperte as palavras para removê-las, ligue a remoção de pausas e copie o comando FFmpeg e a legenda SRT gerados.
Pacote
Abrir no capítuloRemover pausas e reenquadrar o vídeo de 16:9 para 9:16 com legenda por palavrareactReact (sem dependência extra)
Quanto custa cada etapa do seu pipeline de vídeo
Troque a ferramenta de cada etapa e o percentual de b-roll e veja qual etapa pesa no custo por minuto e por vídeo.
Pacote
Abrir no capítuloOrquestrar o pipeline com etapas idempotentes e teto de gastoreact
Capítulos vizinhos em Vídeo com IA: Claude Code, Codex e ElevenLabs
- 02Desenhar o pipeline de vídeo do briefing à publicação
- 03Montar a bancada de vídeo com IA mesmo sem nunca ter usado o terminal
- 04Cortar, juntar, mixar e exportar vídeo com FFmpeg sem abrir editor
- 05Montar vídeo em React com Remotion e renderizar na sua máquina ou na AWS
- 06Montar vídeo em HTML com HyperFrames e escolher entre ele e o Remotion