Communitygithub.com

Lumos12345/extração-de-texto-de-vídeo

Extraia legendas/letras com timestamps de arquivos de vídeo/áudio: transcrição por whisper + OCR para texto embutido (hardsub).

O que é extração-de-texto-de-vídeo?

Esta habilidade permite extrair transcrições temporizadas ou letras de arquivos de mídia locais (como .mp4, .m4s, .mkv, .m4a, .mp3), lidando com cenários comuns onde o vídeo baixado não possui faixas de legendas suaves, mas contém texto embutido na imagem (hardsub), ou quando você só tem o áudio. Ela suporta plataformas como Bilibili/YouTube e é ideal para vídeos de karaokê, AMV ou clipes musicais onde as letras estão renderizadas na cena. A habilidade decide automaticamente a melhor fonte de texto: primeiro verifica se há legendas suaves (extração direta com ffmpeg), depois tenta OCR em frames do vídeo usando Tesseract para textos embutidos (priorizando a ortografia oficial), e por fim recorre à transcrição por whisper para áudio puro. Para resultados ótimos, ela recomenda combinar OCR (para as palavras) com whisper (para o timing), já que o whisper frequentemente erra a grafia de palavras cantadas. O fluxo de trabalho inclui inspeção inicial com ffprobe, extração de áudio em 16 kHz mono, transcrição com parâmetros específicos para evitar perda de vocais, e OCR com técnicas de cropping e deduplicação de linhas. A saída típica é um arquivo .lrc com timestamps, que pode ser usado diretamente por outras habilidades, como a geração de tablaturas para guitarra.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add Lumos12345/video-text-extraction

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Extração de Texto de Vídeo / Áudio

Produza um arquivo de transcrição temporizada ou letras a partir de um arquivo de mídia local (.mp4, .m4s, .mkv, .m4a, .mp3). Lida com o caso comum em que um vídeo baixado não possui faixa de legenda suave, mas tem texto embutido na imagem (hardsub), e com o caso em que você só tem áudio.

Quando usar

  • "Extraia as letras / legendas deste vídeo e marque o horário de início de cada linha."
  • "Transcreva este áudio com timestamps."
  • Arquivos .m4s/.m4a baixados do Bilibili/YouTube; vídeos de karaokê/AMV/clipes musicais onde as letras são renderizadas na imagem.
  • Qualquer solicitação que queira uma saída no estilo .lrc ou .srt.

Passo 0 — Inspecione primeiro, sempre

ffprobe -v quiet -print_format json -show_streams -show_format ARQUIVO | python3 -m json.tool

Coisas importantes a descobrir:

  • Fluxos presentes. .m4s do Bilibili geralmente é só de vídeo (o áudio fica em um .m4s/.m4a separado). Se não houver fluxo de áudio, encontre o arquivo de áudio correspondente na mesma pasta, combinando a duração.
  • Legendas suaves? ffprobe ... -select_streams s — se existir um fluxo de legendas, extraia-o diretamente (ffmpeg -i ARQUIVO -map 0:s:0 out.srt) e pule todo o trabalho de OCR/whisper. Este é o caminho mais rápido.
  • Duração. Use-a para encontrar o arquivo de áudio correto quando o vídeo não tiver áudio.
  • O cartão de título não é a faixa de legenda. O quadro ~0 frequentemente carrega um título grande + sobreposição do artista em uma posição e fonte diferentes das legendas reais. Derivar coordenadas de corte a partir dele resulta em uma faixa que perde todas as letras. Em vez disso, amostre um quadro do meio da música (com uma linha de letra longa visível) — e leia o cartão de título separadamente se precisar do nome da música/artista.
  • Confirme qual música antes de transcrever. Um nome de arquivo e um cartão de título podem discordar do que o usuário chama a faixa. Se o áudio/letras não corresponderem ao nome que você espera, diga isso antes de produzir uma transcrição completa — e se o vídeo for uma música entre várias, diga qual você realmente transcreveu.

Passo 1 — Decida a fonte do texto (ordem de prioridade)

  1. Fluxo de legenda suave → extraia diretamente. Pronto.
  2. Texto embutido na imagem (hardsub) → OCR nos quadros (Passo 3). Isso fornece o texto oficial e com ortografia correta. Prefira este sempre que o vídeo renderizar visivelmente legendas/letras.
  3. Apenas áudio, sem texto na imagem → transcrição com whisper (Passo 2).

Se TANTO o texto na imagem quanto uma transcrição de áudio existirem, use o OCR para as palavras e o whisper para o timing/orientação — o texto do OCR é a ortografia autoritativa, o whisper acerta a grade de tempo mas erra gravemente palavras cantadas (por exemplo, ele ouviu "pedofilos" para "pétalas", "frite certo" para uma vogal cantada). Faça verificação cruzada entre si.

Passo 2 — Transcrição de áudio (whisper)

Instale uma vez (veja references/whisper-setup.md para a correção do espelho HF na China continental):

uv venv /tmp/wvenv
/tmp/wvenv/bin/python -m pip install faster-whisper

Extraia WAV mono 16 kHz, opcionalmente normalizado:

ffmpeg -y -i AUDIO -af "loudnorm=I=-16:TP=-1.5:LRA=11,highpass=f=80" -ar 16000 -ac 1 -c:a pcm_s16le /tmp/song.wav

Transcreva (script em scripts/transcribe.py):

HF_HUB_DISABLE_XET=1 HF_ENDPOINT=https://hf-mirror.com \
  /tmp/wvenv/bin/python scripts/transcribe.py /tmp/song.wav medium
  • O modelo medium é o ponto ideal; large-v3 é mais preciso, mas lento na CPU.
  • medium na CPU (int8) transcreve uma música de ~2,5 min em alguns minutos; o processo fica com RSS baixo durante o carregamento do modelo, depois salta para ~1,4 GB RSS enquanto transcreve — não mate em pânico durante a fase de carregamento, verifique /proc/<pid>/status VmRSS.
  • NÃO use filtragem VAD para canto. vad_filter=True remove linhas vocais suaves/ reverberadas e pode reduzir uma música de 3 minutos a um punhado de segmentos. Transcreva a faixa inteira.
  • Ajuste "canto" funcional (sem VAD): beam_size=5, condition_on_previous_text=True, fallback de temperatura [0.0,0.2,0.4,0.6,0.8,1.0], no_speech_threshold=0.8, log_prob_threshold=-1.5, compression_ratio_threshold=2.8, word_timestamps=True, hallucination_silence_threshold=1.5. (Os padrões descartam frases inteiras e emitem alucinações de silêncio em lacunas instrumentais.)

Passo 3 — OCR de texto embutido (o caminho de alto valor)

Manual completo: references/hardsub-ocr.md. Resumo:

  1. Instale o tesseract sem sudo extraindo .deb para um prefixo (detalhes na referência). Correções de symlink para liblept.so.5 e libarchive.so.13 estão documentadas lá.
  2. Encontre a região de texto: leia um quadro com vision_analyze e peça as coordenadas de pixel da faixa de legenda. Legendas geralmente ficam no canto inferior esquerdo em videoclipes — NÃO adivinhe.
  3. Extraia quadros densamente: ffmpeg -i SRC -vf fps=2 /tmp/frames/f_%04d.png (2 fps → resolução de ~0,5 s; quadro N está em t = N/2 s).
  4. Corte a faixa, aumente a escala 2–3x, tons de cinza, OCR de cada quadro (--psm 6 ou --psm 7).
  5. Deduplicação: quadros consecutivos repetindo uma linha = uma linha de letra; a primeira leitura limpa dá seu tempo de início.
  6. Texto de baixo contraste: recorra a vision_analyze. O Tesseract falha em textos serifados claros sobre fundo claro/fotográfico. O modelo de visão o lê de forma confiável — use-o para os quadros em que o tesseract retorna lixo. Este híbrido (tesseract em massa + preenchimento pontual com visão) é o padrão de produção.

Saída

Produza um .lrc quando o usuário pedir letras + timestamps ([mm:ss.xx]linha), caso contrário, MM:SS texto simples. Salve no caminho que o usuário nomear (comumente a Área de Trabalho do Windows quando no WSL, por exemplo /mnt/c/Users/<usuário>/Desktop/).

Entrega: o .lrc que você produz aqui é exatamente a entrada que a habilidade guitar-tabs deseja para seu gráfico de acordes sincronizado com LRC / alinhamento de acordes por linha. Quando uma solicitação de letras seguidas de tablatura vier como uma única tarefa, mantenha o .lrc por perto e alimente-o diretamente em guitar-tabs (seu scripts/chord_analyze.py recebe <áudio> <letras.lrc> e imprime um acorde por linha de letra). As duas habilidades se encadeiam: video-text-extraction → letras temporizadas → guitar-tabs → 弹唱谱.

Armadilhas

  • .m4s geralmente é só de vídeo. Não presuma que tem áudio. Corresponda o áudio companheiro pela duração.
  • Não confie na grafia do whisper para vocais cantados. Verifique com o texto na imagem quando disponível.
  • VAD mata vocais suaves — veja o Passo 2.
  • O Tesseract precisa de um corte exato. Uma faixa deslocada em ~100px verticalmente retorna ruído. Obtenha coordenadas da visão primeiro.
  • As dependências de bibliotecas compartilhadas do Tesseract vêm uma a uma. Cada execução morre com um error while loading shared libraries: X diferente — liblept.so.5, depois libarchive.so.13, depois libgif.so.7, e assim por diante. Não desista e não instale um por comando: baixe a lista inteira de uma vez (veja a referência), extraia, depois ldd … | grep "not found" para ver tudo ainda faltando em uma única passagem. Duas pegadinhas extras: libarchive13 não tem candidato no Ubuntu mais novo (use libarchive13t64), e liblept5 é o pacote que carrega o liblept.so.5.0.4 real — o pacote -dev só fornece symlinks soltos.
  • Uma leitura curta/confusa do OCR geralmente é um problema de corte, não de OCR. Antes de ajustar --psm ou limites, faça vision_analyze da própria faixa cortada. Se a visão também não vir texto, o corte está errado. Esta única verificação economiza muito ajuste de filtro inútil.
  • Comandos de terminal com export / pipes podem exigir aprovação. Agrupe variáveis de ambiente do tesseract em um script .sh e execute bash script.sh em vez de export ...; tesseract ... inline.
  • HuggingFace é lento/bloqueado na China continental. Sempre defina HF_ENDPOINT=https://hf-mirror.com E HF_HUB_DISABLE_XET=1 (o backend xet retorna 401 contra o espelho).
  • Verifique se o download do modelo está realmente progredindo. Uma execução do faster-whisper que fica parada em ~5 MB RSS e 0 jiffies de CPU está presa buscando o modelo; uma execução real sobe para ~1,4 GB RSS. Inspecione /proc/<pid>/status (VmRSS) em vez de matá-lo ou esperar cegamente.

Habilidades Relacionadas