Casos de uso y soluciones

Crear videos de producto automáticamente con ffmpeg: fotos, locución con IA y subtítulos en 9:16

6 pasos 16 min de lectura 16 vistas 0
Contenido

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.

Use solo fotos, música y fuentes sobre las que tenga derechos de uso. Etiquete la voz generada por IA según las normas de cada plataforma; TikTok, YouTube y otras exigen declarar el contenido sintético realista.

Paso 1: Preparar el servidor

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

Paso 2: Preparar una carpeta por producto

/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

Paso 3: Crear el script de video

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.

Paso 4: Crear el primer video

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.

Paso 5: Producir un catálogo completo

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.

Paso 6: Revisar antes de publicar

  1. Vea cada video una vez: las pronunciaciones incorrectas, las erratas en los subtítulos y las fotos mal recortadas son fáciles de detectar.
  2. Compruebe que la música no tape la voz; si es necesario, reduzca volume=0.15 en el script.
  3. Antes de subir los videos, consulte los requisitos vigentes de cada plataforma sobre duración, subtítulos y etiqueta de contenido generado por IA.

Preguntas frecuentes

¿Puedo usar clips de video cortos en lugar de fotos?

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.

¿Cómo hago el mismo video en otros idiomas?

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.

Los subtítulos en chino muestran recuadros vacíos

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.

¿Fue útil la respuesta?

Tutoriales relacionados