Los videos cortos de producto venden en TikTok Shop, Shopee Video, Instagram Reels y YouTube Shorts, pero editar a mano un video por producto no es viable para todo un catálogo. Esta guía convierte una carpeta con fotos de producto y un guion de narración breve en un video vertical 9:16 terminado, con locución con IA, subtítulos incrustados y música de fondo opcional, mediante un pequeño script de Python y ffmpeg en su servidor, y después genera videos para cientos de productos en un solo lote.
Esta guía se basa en locución con IA con Kokoro: primero configure /opt/tts y tts.py como se describe allí. Después instale las fuentes para los subtítulos en chino y japonés:
apt install -y ffmpeg fonts-noto-cjk
fc-list | grep -i "Noto Sans CJK" | head -3
/data/videos/LS-01/
├── 01.jpg # photos, shown in name order
├── 02.jpg
├── 03.jpg
├── script.txt # narration, one subtitle line per line
└── music.mp3 # optional background music
cat > /opt/tts/makevideo.py <<'EOF2'
import os, subprocess, sys
import soundfile as sf
W, H, FPS = 1080, 1920, 30
FONT = os.environ.get("SUB_FONT", "Noto Sans CJK SC")
os.chdir(sys.argv[1])
images = sorted(f for f in os.listdir(".") if f.lower().endswith((".jpg", ".jpeg", ".png", ".webp")))
if not images:
sys.exit("No photos found in " + os.getcwd())
per = sf.info("script.wav").duration / len(images) # each photo stays on screen for an equal share
def ffmpeg(*args):
subprocess.run(["ffmpeg", "-y", "-loglevel", "error", *args], check=True)
with open("clips.txt", "w") as lst:
for i, img in enumerate(images):
clip = f"clip{i:03d}.mp4" # photo centred on a blurred copy of itself, 9:16
ffmpeg("-loop", "1", "-t", f"{per:.3f}", "-i", img, "-filter_complex",
f"[0:v]split[a][b];[a]scale={W}:{H}:force_original_aspect_ratio=increase,crop={W}:{H},boxblur=20[bg];"
f"[b]scale={W}:{H}:force_original_aspect_ratio=decrease[fg];[bg][fg]overlay=(W-w)/2:(H-h)/2,format=yuv420p",
"-r", str(FPS), "-c:v", "libx264", "-preset", "veryfast", "-crf", "20", clip)
lst.write(f"file '{clip}'\n")
style = f"FontName={FONT},FontSize=11,Bold=1,Outline=2,Shadow=0,Alignment=2,MarginV=50"
inputs = ["-f", "concat", "-safe", "0", "-i", "clips.txt", "-i", "script.wav"]
if os.path.exists("music.mp3"): # optional background music, quietly under the voice
inputs += ["-stream_loop", "-1", "-i", "music.mp3"]
audio = "[2:a]volume=0.15[m];[1:a][m]amix=inputs=2:duration=first,loudnorm=I=-14:TP=-1.5[a]"
else:
audio = "[1:a]loudnorm=I=-14:TP=-1.5[a]"
ffmpeg(*inputs, "-filter_complex", f"[0:v]subtitles=script.srt:force_style='{style}'[v];{audio}",
"-map", "[v]", "-map", "[a]", "-c:v", "libx264", "-preset", "veryfast", "-crf", "20",
"-pix_fmt", "yuv420p", "-c:a", "aac", "-b:a", "160k", "-ar", "48000", "-ac", "2", "-shortest", "-movflags", "+faststart", "video.mp4")
for f in ["clips.txt"] + [f"clip{i:03d}.mp4" for i in range(len(images))]:
os.remove(f)
print("done:", os.path.abspath("video.mp4"))
EOF2
Cada foto permanece en pantalla durante una parte igual de la locución. Se centra sobre una copia desenfocada de sí misma a pantalla completa, de modo que tanto las fotos horizontales como las verticales llenan el encuadre vertical. A continuación, el script une los clips, añade la voz y, si existe, la música a bajo volumen, incrusta los subtítulos, normaliza la sonoridad a unos -14 LUFS y genera video.mp4.
cd /data/videos/LS-01
TTS_LANG=z TTS_VOICE=zf_xiaobei /opt/tts/bin/python /opt/tts/tts.py script.txt
/opt/tts/bin/python /opt/tts/makevideo.py /data/videos/LS-01
El resultado es un video H.264 de 1080x1920 a 30 fps con audio AAC, el formato que aceptan todas las grandes plataformas de videos cortos. Los subtítulos quedan por encima del borde inferior del encuadre, sin que los tapen los botones de la mayoría de las plataformas. Para subtítulos en japonés, ejecute el segundo comando con SUB_FONT="Noto Sans CJK JP". Para cambiar el tamaño o la posición de los subtítulos, ajuste FontSize y MarginV en la línea style del script.
for d in /data/videos/*/; do
[ -f "$d/video.mp4" ] && continue # skip products that are already done
TTS_LANG=z TTS_VOICE=zf_xiaobei /opt/tts/bin/python /opt/tts/tts.py "$d/script.txt" &&
/opt/tts/bin/python /opt/tts/makevideo.py "$d" || echo "FAILED: $d"
done
Ejecute los lotes largos con nohup o dentro de screen para que continúen después de cerrar la sesión. En nuestra prueba, un video de 16 segundos tardó unos cinco segundos en renderizarse; la mayor parte del tiempo se dedica a codificar el video, así que una CPU multinúcleo ayuda.
volume=0.15 en el script.Sí, pero hay que recortar los clips a la duración adecuada y escalarlos de la misma forma, lo que requiere modificar el script. Una opción más sencilla es generar la voz y el SRT con la guía de locución y combinarlos con sus clips en un editor de video.
Traduzca script.txt y ejecute ambos comandos con una voz de ese idioma. Para videos que ya existen, consulte doblar videos a otro idioma con IA.
Falta la fuente. Instale fonts-noto-cjk como en el paso 1 y compruebe que fc-list muestra "Noto Sans CJK SC".
¿Sigue sin resolverlo después de seguir estos pasos? Abra un ticket de soporte y el equipo técnico de IMIDC, disponible 24/7, le ayudará. Incluya la IP del servidor, la versión del sistema operativo, la estructura de carpetas y la salida completa del error para que podamos localizar el problema más rápido.