Subtítulos para Videos de Baile MMD: Flujo de Extremo a Extremo
0. Principio de una Sola Frase
Después de escribir/renderizar, debes extraer fotogramas y verificar: ffprobe con duración correcta no significa que los subtítulos realmente aparezcan; un error en la marca de tiempo de ASS o en el formato de color de Style puede resultar en "renderizado exitoso pero sin texto".
Este proyecto ha tenido múltiples lecciones de "creí que estaba bien, pero en realidad no se grabó", la verificación siempre se basa en capturas de fotogramas.
1. Activos y Rutas (Este workspace)
| Elemento | Ruta |
|---|---|
| Proyecto de subtítulos | D:\yingyong2\论项目\字幕\ |
| Letra LRC | 字幕\[by维尔日记].txt — KISS OF LIFE《Who is she (Japanese Ver.)》, 36 líneas |
| Video MMD antiguo | 字幕\0001-4956 - 副本.mkv (2560×1080 / 30fps; archivo incompleto, duración nominal 165s pero solo se puede decodificar hasta ~137s) |
| Video MMD nuevo | D:\mmd.mp4\0002-4956.mkv (2560×1080 / 30fps / 165.166s, completo) |
| Fuentes | 字幕\build\fonts\ (Anton, ArchivoBlack, BebasNeue, Bungee, Monoton, PermanentMarker, RubikGlitch, Silkscreen, PirataOne, UnifrakturCook) + sistema Georgia / Microsoft YaHei |
| Scripts de generación | 字幕\build\*.py |
| Salida de videos | 字幕\输出\<nombre-tarea>\ (una carpeta por tarea, nombres de entrega legibles en chino) |
| 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, sin cv2) |
2. Flujo Principal en Siete Pasos
① Sondear material ffprobe resolución/fps/duración/color; prueba de decodificación para detectar archivos truncados
② Seleccionar segmento Canción vs movimiento de baile; muestra de 5s / 30s / video completo
③ Alinear letras Tiempo absoluto LRC → restar inicio del segmento = tiempo relativo ASS
④ Elegir estilo Referencia S1–S6 (ver style-frames-compare); primero fotogramas estáticos, luego dinámicos
⑤ Escribir ASS Generar con Python; cumplir reglas estrictas de formato del ass-render-playbook
⑥ Renderizar ffmpeg graba (o capa transparente); primero probar 5–10s, luego segmento completo
⑦ Verificar Extraer fotogramas (al menos 1 por línea) + ensamblar tabla de fotogramas clave; revisar composición, sin chino, sin cubrir rostro, fundido al final
① Sondear 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 # Mensaje "File ended prematurely" = truncado
- Todos los materiales de este proyecto son 2560×1080 / 30fps / h264 yuv420p / bt709, ultra ancho 64:27.
- Video de 165s ≈ 4956 fotogramas; video de 30s = 900 fotogramas.
② Seleccionar segmento
- Primera parte del estribillo LRC:
36.892 / 40.366 / 44.003 / 47.577 / 51.179 / 54.698 / 58.309 / 61.926, termina ~66s. - Muestra de 5s común:
0:58.2–1:03.2; muestra de 30s común:0:36.5–1:06.5; video completo: 0–154.6s (el archivo antiguo solo llega a 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(oscurecer ligeramente para dar contraste a letras blancas/crema; la corrección de color completa está en subject-color-grade)
③ Alinear letras
LRC usa tiempo absoluto; ASS usa tiempo relativo al inicio del segmento. Ejemplo: segmento comienza en 36.5s, entonces 36.892 → 0.392s.
Un cue por línea; dentro de la línea, dividir por palabra en múltiples eventos (ver abajo). Los eventos finales deben terminar 0.14–0.4s antes para evitar superposición entre líneas.
④ Elegir estilo
- Primero leer la habilidad
style-frames-compare, seleccionar S1–S6 según el tono deseado, generar fotogramas estáticos para que el usuario los vea. - Restricción importante: Cuando el usuario diga explícitamente "sin chino", mantener solo el inglés/japonés de la letra original; el personaje en el centro, letras grandes en los márgenes laterales y las esquinas superior e inferior.
- Generadores reutilizables existentes:
styles_anim.py(animación 5s para S2/S4/S6),flare_wide.py(explosión),neon_wide.py(neón),avoid_side2.py(evitación completa),kpop_styles.py(fotogramas estáticos),art_frames.py(fotogramas estáticos de arte).
⑤ Escribir ASS
- Generar con Python (más estable que manual): definir clase
Ass+ helpersword()/rect(), finalmentewrite(). - Reglas estrictas, plantillas y errores comunes en
ass-render-playbook(formato de tiempoH:MM:SS.cc, colores Style sin&final,fontsdircon ruta relativa, etc.).
⑥ Renderizar
- Directorio de trabajo = directorio de salida; ASS con nombre de archivo ASCII; directorio de fuentes 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
- Capa transparente (para postproducción):
-f lavfi -i "[email protected]:s=2560x1080:r=30,format=rgba" -vf "ass=x.ass:alpha=1"+ VP9yuva420p(detalles en ass-render-playbook).
⑦ Lista de verificación
- La duración de
ffprobecoincide con el diseño (5.000 / 30.000 / 154.6) - Extraer fotogramas: al menos 1 por línea, confirmar que el texto realmente aparece, posición correcta, sin caracteres ilegibles
- El usuario solicita sin chino → extraer 2–3 fotogramas para confirmar solo inglés/japonés
- El rostro/cuerpo del personaje no está oculto (especialmente en planos cercanos/primeros planos)
- La última línea se desvanece antes de que termine (ej. antes de 29.86s), sin texto residual
- Ensamblar
关键帧.jpg(2×2 o 2×3, cada celda 1280×540, con etiquetas) para que el usuario lo vea fácilmente - Nombres de archivo legibles + archivo md de explicación entregados juntos
3. Tipos de Tarea → Entregables
| Tarea | Entregable |
|---|---|
| Propuesta de fotograma estático | N jpg de 2560×1080 + 总览.jpg + md de explicación |
| Muestra de 5s | 1–3 mp4 de 5s + video de comparación + tabla de fotogramas clave |
| Muestra de 30s | 1–2 mp4 de 30s (900 fotogramas) + versión de comparación + tabla de fotogramas clave + md de explicación |
| Entrega en pares (común) | Por estilo, 2 videos: X_有背景_30s.mp4 (H.264 grabado) + X_纯字幕_透明_30s.webm (VP9 alpha); N estilos × 2 videos, además de 纯字幕_透明预览.jpg (vista previa de composición con patrón de ajedrez) |
| Video completo | ASS de subtítulos + mp4 grabado / webm transparente + explicación |
| Corrección de color | mp4 corregido + fotogramas de comparación + explicación de parámetros / LUT |
Renderizado de versión transparente (mismo ASS que la versión con fondo, fotograma a fotograma 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; Al extraer fotogramas, usar explícitamente-c:v libvpx-vp9, de lo contrario se pierde alpha y todo se vuelve 255.
4. Paralelización (Convención de Sub-Agentes)
Juego estándar cuando el usuario dice "hazlo con sub-agentes separados":
- El agente principal primero prepara el material base compartido (recortado, oscurecido uniformemente), una copia de
fonts/, y la hoja de pistas (tabla de tiempos relativos); - Un sub-agente por estilo, con indicaciones fijas: ruta de entrada, nombre de archivo de salida (
S4_30s.mp4, etc.), reglas estrictas de ASS, tabla de línea de tiempo, requisitos de verificación; - Cada sub-agente escribe solo su propio archivo de prefijo, sin sobrescribir a otros;
- El agente principal recoge todo y hace el video de comparación, tabla de fotogramas clave, explicación, y verifica la extracción de fotogramas. Realidad: un solo estilo de 30s (2560×1080, 8 líneas, aproximadamente 40–60 Diálogos) desde el diseño hasta el video final toma alrededor de 10–20 minutos; dos sub-agentes en paralelo ≈ tiempo del más lento.