ffmpeg 自动拼接成片 · Auto-assemble with ffmpeg
storyboard.json → 配音(edge-tts)→ 每镜 Ken Burns / 视频裁切 → xfade 转场 → ASS 字幕花字 → BGM 闪避混音 → 两遍 loudnorm(-14 LUFS)→ out/video.mp4 + .srt。
Parte de ecommerce-video-skills · Los scripts están en el directorio
scripts/:assemble.py(programa principal) ·tts_edge.py·make_subs.py·make_bgm.py(síntesis de BGM libre de derechos) ·make_cards.py(tarjetas de producto/final con PIL)
Entradas Inputs
storyboard.json(puede ser generado porselling-point-storyboard), las rutas de los recursos son relativas a este archivo- Entorno: Python 3.9+,
pip install pillow numpy edge-tts, ffmpeg (con libass), fuente CJK
Inicio rápido Quick start
pip install pillow numpy edge-tts
python scripts/assemble.py examples/aura-bottle/storyboard.json -o out/aura.mp4 # Ejemplo incluido en el repositorio, renderiza en ~30 segundos
python scripts/assemble.py storyboard.json --tts none -o out/preview.mp4 # Vista previa sin conexión (sin locución, estima duración por número de caracteres)
python scripts/assemble.py storyboard.json --size 1080x1080 -o out/main-1x1.mp4 # Video de imagen principal 1:1
python scripts/assemble.py storyboard.json --bgm music.mp3 # Usar música con derechos de autor
Campos de storyboard Fields
| Campo | Descripción |
|---|---|
voice / rate / pitch (nivel superior) | Voz edge-tts, velocidad (ej. +10%), tono |
bgm (nivel superior) | "auto" (síntesis integrada, libre de derechos) / ruta de archivo de música / null |
tag (nivel superior) | Etiqueta en la esquina superior izquierda durante todo el video (marca/modelo/"demostración") |
image o video (+start) | Recurso; el video se recorta desde el segundo start hasta la duración del plano |
line | Texto de la locución; la duración del plano = locución + 0.15s de introducción + pad |
sub | Subtítulo (por defecto igual que line); "" significa que no se muestra subtítulo en este plano; **resaltado**, ` |
title / cta | Texto estilizado / Botón de llamada a la acción |
motion | zoom_in zoom_out pan_left pan_right pan_up pan_down punch static |
fit | auto (si la relación de aspecto es similar, recorta; de lo contrario, relleno borroso) / cover / blur |
transition | Nombre del xfade para la transición al siguiente plano: fade slideleft slideup smoothleft circleopen wipeleft … |
min / duration / pad | Duración mínima / Duración fija / Pausa después de la frase (segundos) |
Pasos Steps
- Verificar que todos los recursos existan y tengan una resolución adecuada (imagen del producto ≥ 1000px); si falta la tarjeta final, generarla con
make_cards.py:python scripts/make_cards.py --image main.png --name "Nombre del producto" --points "Punto de venta 1|Punto de venta 2|Punto de venta 3" -o assets/end-card.png - Ejecutar primero con
--tts nonepara revisar el ritmo visual, luego renderizar la versión final. - Después del renderizado, extraer un fotograma para verificar:
ffmpeg -ss 3 -i out/video.mp4 -frames:v 1 check.png - Entregar a
platform-spec-exportpara exportar versiones para cada plataforma; usarcover-title-abpara la miniatura.
Detalles del pipeline How it works
- Ken Burns:
scale(eval=frame)+cropcuadro por cuadro, menos tembloroso quezoompan;punch= acercamiento rápido de 0.35 segundos (para enganche). - Transiciones: Cada plano renderiza media longitud de transición extra, xfade centrado en el límite del plano, el punto de inicio de la locución no se pierde en la transición.
- Mezcla de audio: La locución se coloca en el inicio de cada plano; el BGM por defecto a -20 dB, se reduce 10 dB adicionales cuando hay voz (ducking suave); se comprime/limita y luego se normaliza con loudnorm dos veces hasta aproximadamente -14 LUFS, TP -1.5 dB.
- Subtítulos: Se genera
build/timing.jsoncon la duración real de la locución →make_subs.py→ libass para quemar subtítulos, exportando también.srt.
Lista de verificación Checklist
- La duración, resolución y tasa de fotogramas del video final son correctas (
ffprobe out/video.mp4) - Revisar 3 fotogramas: los subtítulos no tapan el producto ni invaden la zona inferior de la interfaz
- Escuchar una vez: la locución es clara, el BGM no la opaca, no hay estallidos al inicio
- El BGM tiene licencia comercial (la música sintetizada con
autose puede usar con confianza) - Los recursos (imágenes/videos/fuentes) tienen licencia de uso
Problemas comunes y soluciones Failure fixes
| Problema | Solución |
|---|---|
ffmpeg failed | Mirar el final del stderr impreso por el script; comúnmente es un error de ruta o que ffmpeg carece de libass/libx264 |
| Los bordes del video se ven borrosos | La resolución del recurso es demasiado baja; usar imágenes de ≥1080px o reducir la amplitud del movimiento (motion a static) |
| El producto se corta | En ese plano, establecer "fit": "blur" |
| El sonido se corta en la transición | No ocurre (la locución se alinea con el inicio del plano); si se personalizó duration y es demasiado corta, alargarla |
| Renderizado lento | La configuración por defecto ya usa archivos intermedios veryfast; en la codificación final se puede cambiar -preset medium a fast |
| Se desea 1:1 / 16:9 | --size 1080x1080 / --size 1920x1080, el tamaño de la fuente se ajusta automáticamente según la proporción |
Referencias y agradecimientos: La idea se inspira en el pipeline "guion → locución → subtítulos → ensamblaje" de MoneyPrinterTurbo (MIT), esta implementación es una versión independiente y pura de ffmpeg, sin copiar su código.