Legenda automática palavra por palavra no vídeo
A legenda que mostra uma palavra de cada vez, no ritmo da fala, e destaca em amarelo o que importa. Dois scripts, um que transcreve e outro que cola a legenda no vídeo, e o pedido pronto para o Claude Code.
Você já viu: o vídeo mostra uma palavra de cada vez, grande, no centro da tela, e a que carrega o sentido aparece em amarelo. É o estilo mais usado em Reels, TikTok e Shorts.
Fazer isso à mão exige marcar o tempo de cada palavra. Fazer por script exige duas coisas: saber quando cada palavra é dita e desenhar cada uma no vídeo. Este guia resolve as duas, com código que eu testei num vídeo vertical em português.
O que você vai ter no final
Cada palavra aparece só enquanto é falada, em letras brancas com contorno preto. Números e palavras de impacto saem em amarelo.
O que você precisa
- ffmpeg, que junta imagem, legenda e áudio. No Mac:
brew install ffmpeg. - Python 3 e três bibliotecas:
pip install faster-whisper pillow numpy. - Um vídeo em que alguém fala. A transcrição funciona melhor com voz clara e sem música alta por cima.
Na primeira vez, o faster-whisper baixa o modelo de transcrição, algumas centenas de MB. Depois disso ele roda no seu computador, sem enviar o vídeo para lugar nenhum.
Passo 1: descubra o tempo de cada palavra
Salve como palavras.py:
#!/usr/bin/env python3
"""Transcreve um vídeo com o tempo de cada palavra. Uso: python3 palavras.py video.mp4"""
import json, subprocess, sys
import numpy as np
from faster_whisper import WhisperModel
# o ffmpeg entrega o áudio pronto (16 kHz, mono), sem depender de outra biblioteca de leitura
pcm = subprocess.run(["ffmpeg", "-v", "error", "-i", sys.argv[1], "-f", "f32le", "-ac", "1", "-ar", "16000", "-"],
capture_output=True, check=True).stdout
audio = np.frombuffer(pcm, dtype=np.float32)
modelo = WhisperModel("small", compute_type="int8")
segmentos, _ = modelo.transcribe(audio, language="pt", word_timestamps=True)
palavras = [{"palavra": p.word.strip(), "inicio": round(p.start, 2), "fim": round(p.end, 2)}
for s in segmentos for p in s.words]
print(json.dumps(palavras, ensure_ascii=False, indent=1))
Rode e guarde o resultado:
python3 palavras.py gravacao.mp4 > palavras.json
O arquivo palavras.json fica assim (no vídeo de teste):
[
{ "palavra": "Fala", "inicio": 0.0, "fim": 0.24 },
{ "palavra": "pessoal,", "inicio": 0.24, "fim": 0.58 },
{ "palavra": "hoje", "inicio": 1.0, "fim": 1.14 }
]
Abra o arquivo e leia antes de seguir. O modelo erra nomes próprios, siglas e palavras em inglês, e o que estiver errado aqui vai aparecer na tela. Corrigir é só editar o texto de palavra.
Passo 2: cole a legenda no vídeo
Salve como legendar.py. Ele desenha cada palavra como uma imagem com fundo transparente e a sobrepõe ao vídeo só no tempo em que ela é falada. Esse caminho funciona em qualquer instalação do ffmpeg, sem depender de suporte a fontes ou a arquivos de legenda:
#!/usr/bin/env python3
"""Coloca legenda palavra por palavra no vídeo.
Uso: python3 legendar.py video.mp4 palavras.json saida.mp4 [fonte.ttf]
Cada palavra vira uma imagem com fundo transparente e é sobreposta só no tempo em que é falada."""
import json, os, re, subprocess, sys, tempfile
from PIL import Image, ImageDraw, ImageFont
video, arquivo_palavras, saida = sys.argv[1:4]
fonte = sys.argv[4] if len(sys.argv) > 4 else "/System/Library/Fonts/Supplemental/Arial Bold.ttf"
BRANCO, AMARELO = (255, 255, 255, 255), (255, 225, 77, 255)
DESTAQUE = {"ia", "vídeo", "video", "editar", "grátis", "agora", "nunca", "sempre"} # palavras de impacto (ajuste à vontade)
larg, alt = map(int, subprocess.run(
["ffprobe", "-v", "error", "-select_streams", "v", "-show_entries", "stream=width,height", "-of", "csv=p=0:s=x", video],
capture_output=True, text=True, check=True).stdout.strip().split("x"))
tamanho = round(larg * 0.11)
fnt = ImageFont.truetype(fonte, tamanho)
palavras = json.load(open(arquivo_palavras, encoding="utf-8"))
pasta = tempfile.mkdtemp()
entradas, filtros, anterior = [], [], "0:v"
for i, p in enumerate(palavras):
texto = p["palavra"].strip(".,;:!?…").upper()
if not texto:
continue
cor = AMARELO if (re.search(r"\d", texto) or texto.lower() in DESTAQUE) else BRANCO
img = Image.new("RGBA", (larg, round(tamanho * 1.8)), (0, 0, 0, 0))
d = ImageDraw.Draw(img)
x = (larg - d.textlength(texto, font=fnt)) / 2
d.text((x, tamanho * 0.3), texto, font=fnt, fill=cor, stroke_width=max(3, tamanho // 14), stroke_fill=(0, 0, 0, 255))
caminho = os.path.join(pasta, f"p{i:03d}.png")
img.save(caminho)
entradas += ["-i", caminho]
n = len(entradas) // 2
saida_rotulo = f"v{n}"
ini, fim = p["inicio"], max(p["fim"], p["inicio"] + 0.15)
filtros.append(f"[{anterior}][{n}:v]overlay=0:{round(alt * 0.62)}:enable='between(t,{ini},{fim})'[{saida_rotulo}]")
anterior = saida_rotulo
subprocess.run(["ffmpeg", "-y", "-hide_banner", "-loglevel", "error", "-i", video, *entradas,
"-filter_complex", ";".join(filtros), "-map", f"[{anterior}]", "-map", "0:a?",
"-c:v", "libx264", "-crf", "20", "-c:a", "copy", saida], check=True)
print("Pronto:", saida)
Rode:
python3 legendar.py gravacao.mp4 palavras.json gravacao-legendado.mp4
No Windows, informe uma fonte instalada como último argumento, por exemplo C:/Windows/Fonts/arialbd.ttf.
Como ajustar o estilo
| O que mudar | Onde | Dica |
|---|---|---|
| Palavras em amarelo | DESTAQUE |
Coloque as palavras-chave do seu assunto. Números já saem em amarelo automaticamente. |
| Cor do destaque | AMARELO |
Troque pelos valores RGB da cor da sua marca. |
| Tamanho | larg * 0.11 |
Aumente para 0,13 se o vídeo for assistido em tela pequena. |
| Altura | alt * 0.62 |
0,62 deixa a legenda abaixo do rosto e acima da zona onde Reels e Stories colocam botões e textos da plataforma. Suba ou desça conforme o enquadramento. |
Limites que valem saber
- Vídeos curtos. O script usa uma imagem por palavra. Em vídeos de poucos minutos tudo bem. Em vídeos longos fica pesado, e o melhor é gerar por trechos.
- Uma palavra por vez. É o estilo que o título promete. Para legenda em frases, é outro desenho.
- A transcrição precisa de revisão. Sempre confira o
palavras.json.
O jeito mais curto: pedir ao Claude Code
Com o Claude Code, você não copia os dois arquivos. Abra a pasta do vídeo e peça:
Coloque legenda palavra por palavra no vídeo gravacao.mp4, no centro da tela, em letras brancas com contorno preto. Destaque em amarelo os números e as palavras de impacto. Antes de colar no vídeo, me mostre a transcrição pra eu conferir. Salve como gravacao-legendado.mp4 e não altere o original.
Ele transcreve, mostra o texto, espera a sua aprovação e só então gera o vídeo. Veja a instalação e o primeiro pedido em Como editar vídeo com Claude Code. Para tirar as pausas antes de legendar, use o guia de como cortar pausas do vídeo automaticamente: as palavras ficam mais próximas e a legenda corre no ritmo certo.
Perguntas frequentes
A transcrição funciona em português do Brasil?
Sim. O script informa language="pt" e o modelo entende bem português falado com voz clara. Ele erra mais em nomes próprios, gírias e termos em inglês, por isso a revisão do passo 1.
Preciso pagar por alguma coisa?
O ffmpeg e o faster-whisper são gratuitos e rodam no seu computador. Se você pedir ao Claude Code, o custo é o da sua conta do Claude.
Dá pra usar a legenda em vídeo horizontal?
Dá. O tamanho e a altura são calculados pelas dimensões do vídeo. Num vídeo horizontal, reduza o 0.11 do tamanho, porque a largura é maior.
E se eu quiser editar a legenda depois?
Edite o palavras.json e rode o legendar.py de novo. O vídeo original continua intacto, e você gera quantas versões quiser.
