Legendas de Vídeo de Dança MMD: Fluxo End-to-End
0. Princípio de uma Frase
Após escrever/renderizar, é obrigatório extrair um quadro e verificar: ffprobe duração correta ≠ legenda realmente apareceu; erro no timestamp ASS ou no formato de cor do Style pode levar a "renderização bem-sucedida, mas sem texto".
Este projeto já teve várias lições de "pensei que estava corrigido, mas na verdade não foi embutido"; a aceitação sempre se baseia na extração de quadros.
1. Ativos e Caminhos (neste workspace)
| Item | Caminho |
|---|---|
| Projeto de legenda | D:\yingyong2\论项目\字幕\ |
| Letra LRC | 字幕\[by维尔日记].txt — KISS OF LIFE《Who is she (Japanese Ver.)》,36 frases |
| Vídeo MMD antigo | 字幕\0001-4956 - 副本.mkv (2560×1080 / 30fps; arquivo incompleto, nominal 165s mas só decodifica ~137s) |
| Vídeo MMD novo | D:\mmd.mp4\0002-4956.mkv (2560×1080 / 30fps / 165.166s, completo) |
| Fontes | 字幕\build\fonts\ (Anton, ArchivoBlack, BebasNeue, Bungee, Monoton, PermanentMarker, RubikGlitch, Silkscreen, PirataOne, UnifrakturCook) + sistema Georgia / Microsoft YaHei |
| Scripts de geração | 字幕\build\*.py |
| Saída de vídeos finais | 字幕\输出\<nome-da-tarefa>\ (uma pasta por tarefa, nome de entrega com nome legível em chinês) |
| ffmpeg | C:\Users\35530\AppData\Local\Microsoft\WinGet\Packages\Gyan.FFmpeg_Microsoft.Winget.Source_8wekyb3d8bbwe\ffmpeg-9.0-full_build\bin\ffmpeg.exe |
| python | C:\Users\35530\.dsh\dsh-runtimes\dsh-primary-runtime\dependencies\python\python.exe (PIL 12.3 / numpy 2.3, sem cv2) |
2. Fluxo Principal em Sete Etapas
① Sondar material ffprobe resolução/fps/duração/cor; teste de decodificação para verificar se o arquivo é truncado
② Selecionar segmento trecho da música vs movimento de dança; amostra 5s / 30s / peça completa
③ Mapear letras Tempo absoluto LRC → subtrair início do segmento = tempo relativo ASS
④ Definir estilo Referência S1–S6 (ver style-frames-compare); primeiro saída de quadros estáticos, depois dinâmicos
⑤ Escrever ASS Gerado com Python; obedecer regras rígidas de formato do ass-render-playbook
⑥ Renderizar ffmpeg embutir (ou camada transparente); primeiro saída de verificação 5–10s, depois segmento completo
⑦ Verificar Extrair quadros (pelo menos 1 quadro por frase) + montar tabela de quadros-chave; verificar composição, sem chinês, sem obstrução facial, fade out final
① Sondar Material
$ff='...\ffmpeg.exe'; $fp='...\ffprobe.exe'
& $fp -v error -select_streams v:0 -show_entries stream=width,height,r_frame_rate,nb_frames,pix_fmt,color_space -show_entries format=duration -of default=nw=1 $v
& $ff -v error -i $v -map 0:v:0 -c copy -f null NUL # "File ended prematurely" = truncado
- Os materiais deste projeto são todos 2560×1080 / 30fps / h264 yuv420p / bt709, ultra-wide 64:27.
- Vídeo de 165s ≈ 4956 quadros; vídeo de 30s = 900 quadros.
② Selecionar Segmento
- Primeira parte do refrão LRC:
36.892 / 40.366 / 44.003 / 47.577 / 51.179 / 54.698 / 58.309 / 61.926, terminando ~66s. - Amostra de 5s comum:
0:58.2–1:03.2; amostra de 30s comum:0:36.5–1:06.5; peça completa: 0–154.6s (arquivo antigo só vai até 137s). - Recorte:
-ss 36.5 -t 30 -i src -vf "eq=brightness=-0.05:contrast=1.04:saturation=1.02" -c:v libx264 -crf 16 -pix_fmt yuv420p(escurecimento leve para dar contraste a letras brancas/creme; correção de cor completa está em subject-color-grade)
③ Mapear Letras
LRC é tempo absoluto; ASS usa tempo relativo ao início do segmento. Exemplo: segmento começa em 36.5s, então 36.892 → 0.392s.
Uma pista por frase; dentro da frase, dividir em múltiplos eventos por palavra (ver abaixo). Os eventos finais devem terminar 0.14–0.4s antes, para evitar sobreposição entre frases.
④ Definir Estilo
- Primeiro, ler a skill
style-frames-compare, escolher S1–S6 de acordo com o estilo desejado, gerar quadros estáticos para mostrar ao usuário. - Restrição importante: quando o usuário disser "sem chinês", manter apenas o inglês/japonês da letra original; pessoa no centro, letras grandes nas laterais e nos cantos superior/inferior.
- Geradores reutilizáveis disponíveis:
styles_anim.py(animação 5s S2/S4/S6),flare_wide.py(explosão),neon_wide.py(néon),avoid_side2.py(desvio completo),kpop_styles.py(rascunho estático),art_frames.py(rascunho estático de arte).
⑤ Escrever ASS
- Usar Python para gerar (mais estável que manual): definir classe
Ass+ auxiliaresword()/rect(), depoiswrite(). - Regras rígidas, modelos e armadilhas em
ass-render-playbook(formato de tempoH:MM:SS.cc, valor de cor Style sem&final,fontsdircaminho relativo, etc.).
⑥ Renderizar
- Diretório de trabalho = diretório de saída; ASS usar nome de arquivo ASCII; diretório de fontes relativo:
cd "字幕\输出\S4S6_30s"
& $ff -v error -y -i _base_30s.mp4 -vf "ass=_s4.ass:fontsdir=fonts" `
-c:v libx264 -preset medium -crf 16 -pix_fmt yuv420p -movflags +faststart S4_30s.mp4
- Camada transparente (para pós-produção):
-f lavfi -i "[email protected]:s=2560x1080:r=30,format=rgba" -vf "ass=x.ass:alpha=1"+ VP9yuva420p(detalhes em ass-render-playbook).
⑦ Lista de Verificação
-
ffprobeduração corresponde ao design (5.000 / 30.000 / 154.6) - Extrair quadros: pelo menos 1 quadro por frase, confirmar que o texto realmente aparece, posição correta, sem caracteres ilegíveis
- Usuário pediu sem chinês → extrair 2–3 quadros para confirmar apenas inglês/japonês
- Rosto/corpo da pessoa não obstruído (especialmente em close-up ou zoom)
- Última frase desaparece antes do final (ex: antes de 29.86s), sem texto residual
- Montar
quadro-chave.jpg(2×2 ou 2×3, cada célula 1280×540, com etiquetas) para facilitar visualização - Nome de arquivo legível + arquivo md de explicação entregues juntos
3. Tipos de Tarefa → Entregáveis
| Tarefa | Entrega |
|---|---|
| Proposta de quadro estático | N imagens 2560×1080 jpg + visao-geral.jpg + md de explicação |
| Amostra 5s | 1–3 vídeos 5s mp4 + vídeo de comparação + tabela de quadros-chave |
| Amostra 30s | 1–2 vídeos 30s mp4 (900 quadros) + versão de comparação + tabela de quadros-chave + md de explicação |
| Entrega em par (comum) | Para cada estilo, 2 vídeos: X_com_fundo_30s.mp4 (H.264 embutido) + X_legenda_pura_transparente_30s.webm (VP9 alpha); N estilos × 2 vídeos, acompanhado de preview_transparente.jpg (preview de composição xadrez) |
| Peça completa | Legenda ASS + mp4 embutido / webm transparente + explicação |
| Correção de cor | mp4 corrigido + quadros de comparação + parâmetros / LUT |
Renderização transparente (mesmo ASS da versão com fundo, quadro a quadro consistente):
& $ff -v error -y -f lavfi -i "[email protected]:s=2560x1080:r=30,format=rgba" ` -vf "ass=_s4.ass:alpha=1:fontsdir=fonts" -t 30 -c:v libvpx-vp9 -pix_fmt yuva420p ` -b:v 0 -crf 30 -row-mt 1 -auto-alt-ref 0 -metadata:s:v:0 alpha_mode=1 OUT.webmVerificar alpha:
ffmpeg -c:v libvpx-vp9 -ss 12.4 -i OUT.webm -frames:v 1 -pix_fmt rgba f.png, PIL verificar alpha min=0 / max=255, cobertura>0; extração de quadros deve usar explicitamente-c:v libvpx-vp9, caso contrário perde alpha e fica tudo 255.
4. Paralelização (Acordo de Subagentes)
Fluxo padrão quando o usuário disser "subagentes separados":
- Agente principal prepara base compartilhada (recortada, escurecida uniformemente) e cópia de
fonts/, ficha de pistas (tabela de tempos relativos); - Cada estilo um subagente, prompt fixo: caminho de entrada, nome de arquivo de saída (
S4_30s.mp4etc.), regras rígidas ASS, tabela de linha do tempo, requisitos de verificação; - Subagentes cada um escreve apenas seu próprio arquivo de prefixo, sem sobreposição;
- Agente principal coleta tudo, faz vídeo de comparação/tabela de quadros-chave/explicação e verifica extração de quadros. Prática: um estilo de 30s (2560×1080, 8 frases, cerca de 40–60 diálogos) leva de 10–20 minutos do design ao vídeo final; dois subagentes paralelos ≈ tempo do mais lento.