32blogby StudioMitsu

Genera subtítulos automáticos con FFmpeg y Whisper

Combina Whisper de OpenAI con FFmpeg para agregar subtítulos automáticamente a cualquier video. Construye un pipeline que extrae audio, genera SRT y quema los subtítulos.

7 min read
FFmpegWhispersubtitlesautomationAI
Contenido

Agregar subtítulos a un video es un trabajo tedioso. Transcribir el audio, alinear las marcas de tiempo, exportar el archivo — hacerlo a mano cada vez simplemente no escala.

Este artículo te muestra cómo combinar Whisper de OpenAI con FFmpeg para automatizar completamente la generación de subtítulos. Construiremos un pipeline que va desde el video en bruto hasta un archivo con subtítulos incrustados en un solo script: extracción de audio → transcripción → generación de SRT → quemado de subtítulos.

Elimina el cuello de botella de los subtítulos

El verdadero cuello de botella en la creación de subtítulos es la transcripción. Convertir palabras habladas a texto, decidir dónde dividir los segmentos y asignar códigos de tiempo consume el 90% del tiempo total.

Whisper resuelve esto casi por completo. Pásale un archivo de audio y se encarga de la transcripción y los códigos de tiempo automáticamente. Exporta el resultado como SRT y puedes canalizarlo directamente a FFmpeg para quemar los subtítulos en tu video.

Necesitas dos cosas:

  • Python 3.8+ con Whisper instalado
  • FFmpeg ya instalado y disponible en tu PATH

Si necesitas un repaso sobre los conceptos básicos de FFmpeg, consulta primero Primeros pasos con FFmpeg.

Instala Whisper y elige un modelo

Instala Whisper con pip.

bash
pip install openai-whisper

Una vez instalado, elige el tamaño del modelo. Whisper incluye varias variantes con diferentes balances entre velocidad y precisión.

ModeloVRAMVelocidadPrecisión
tiny~1GBMás rápidoBaja
base~1GBRápidoModerada
small~2GBMediaBuena
medium~5GBLentoAlta
large~10GBMás lentoMejor

Extrae el audio con FFmpeg

Whisper puede aceptar un archivo de video directamente, pero extraer el audio primero hace que el pipeline sea más rápido y limpio. Usa FFmpeg para convertir a WAV.

bash
ffmpeg -i input.mp4 -vn -acodec pcm_s16le -ar 16000 -ac 1 audio.wav

Qué hace cada flag:

  • -vn — ignora el stream de video, procesa solo el audio
  • -acodec pcm_s16le — exporta como WAV (PCM lineal de 16 bits)
  • -ar 16000 — establece la tasa de muestreo a 16kHz (la entrada recomendada por Whisper)
  • -ac 1 — mezcla a mono (Whisper es más consistente con audio mono)

El archivo audio.wav resultante es lo que se pasa a Whisper a continuación.

Transcribe el audio y genera SRT con Whisper

Con el archivo de audio listo, pásalo por Whisper. Puedes usar la CLI o la API de Python.

Usando la CLI

bash
whisper audio.wav --model medium --language en --output_format srt --output_dir ./subtitles

Pasar --language explícitamente es más rápido y preciso que dejar que Whisper lo detecte automáticamente. El resultado se guarda en ./subtitles/audio.srt y luce así:

1
00:00:00,000 --> 00:00:03,500
Welcome. Today we're going to look at FFmpeg and Whisper.

2
00:00:03,500 --> 00:00:07,200
Let's start by installing Whisper.

Usando la API de Python

Usa la API cuando necesites más control sobre la salida.

python
import whisper

model = whisper.load_model("medium")
result = model.transcribe("audio.wav", language="en")

def format_timestamp(seconds: float) -> str:
    ms = int((seconds % 1) * 1000)
    s = int(seconds) % 60
    m = int(seconds) // 60 % 60
    h = int(seconds) // 3600
    return f"{h:02d}:{m:02d}:{s:02d},{ms:03d}"

with open("subtitles/audio.srt", "w", encoding="utf-8") as f:
    for i, segment in enumerate(result["segments"], start=1):
        start = format_timestamp(segment["start"])
        end = format_timestamp(segment["end"])
        text = segment["text"].strip()
        f.write(f"{i}\n{start} --> {end}\n{text}\n\n")

print("SRT file written")

Cada elemento en result["segments"] contiene start, end (en segundos) y text. La función auxiliar los formatea en marcas de tiempo SRT.

Quema los subtítulos en el video con FFmpeg

Una vez que el archivo SRT existe, usa el filtro subtitles de FFmpeg para incrustarlos en el video de forma permanente.

bash
ffmpeg -i input.mp4 -vf "subtitles=subtitles/audio.srt" -c:a copy output.mp4

Para personalizar la fuente, tamaño y color, pasa un argumento force_style.

bash
ffmpeg -i input.mp4 \
  -vf "subtitles=subtitles/audio.srt:force_style='FontName=Arial,FontSize=24,PrimaryColour=&Hffffff,OutlineColour=&H000000,Outline=2'" \
  -c:a copy output.mp4

force_style sigue la especificación de estilos ASS/SSA. Los scripts no latinos deben usar una fuente que cubra el conjunto de caracteres requerido para evitar problemas de renderizado.

Combina todo en un solo script

Aquí está el pipeline completo en un solo script de Python. Apúntalo a un archivo de video y genera una versión con subtítulos.

python
import subprocess
import sys
import os
import whisper


def extract_audio(input_video: str, output_audio: str) -> None:
    """Extract audio from a video file."""
    cmd = [
        "ffmpeg", "-i", input_video,
        "-vn", "-acodec", "pcm_s16le",
        "-ar", "16000", "-ac", "1",
        output_audio, "-y"
    ]
    subprocess.run(cmd, check=True, capture_output=True)
    print(f"Audio extracted: {output_audio}")


def transcribe_to_srt(audio_path: str, srt_path: str, model_name: str = "medium") -> None:
    """Transcribe audio with Whisper and write an SRT file."""
    model = whisper.load_model(model_name)
    result = model.transcribe(audio_path, language="en")

    def format_timestamp(seconds: float) -> str:
        ms = int((seconds % 1) * 1000)
        s = int(seconds) % 60
        m = int(seconds) // 60 % 60
        h = int(seconds) // 3600
        return f"{h:02d}:{m:02d}:{s:02d},{ms:03d}"

    with open(srt_path, "w", encoding="utf-8") as f:
        for i, segment in enumerate(result["segments"], start=1):
            start = format_timestamp(segment["start"])
            end = format_timestamp(segment["end"])
            text = segment["text"].strip()
            f.write(f"{i}\n{start} --> {end}\n{text}\n\n")

    print(f"SRT written: {srt_path}")


def burn_subtitles(input_video: str, srt_path: str, output_video: str) -> None:
    """Hard-code subtitles into the video."""
    # Assumes srt_path contains only ASCII characters
    vf = f"subtitles={srt_path}"
    cmd = [
        "ffmpeg", "-i", input_video,
        "-vf", vf,
        "-c:a", "copy",
        output_video, "-y"
    ]
    subprocess.run(cmd, check=True, capture_output=True)
    print(f"Subtitles burned: {output_video}")


def main(input_video: str) -> None:
    base = os.path.splitext(input_video)[0]
    audio_path = f"{base}_audio.wav"
    srt_path = f"{base}_subtitles.srt"
    output_video = f"{base}_subtitled.mp4"

    print("=== Subtitle Auto-Generation Pipeline ===")
    extract_audio(input_video, audio_path)
    transcribe_to_srt(audio_path, srt_path)
    burn_subtitles(input_video, srt_path, output_video)

    # Clean up intermediate files
    os.remove(audio_path)
    print(f"\nDone: {output_video}")


if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("Usage: python subtitle_pipeline.py <input_video>")
        sys.exit(1)
    main(sys.argv[1])

Ejecútalo con un solo comando.

bash
python subtitle_pipeline.py input.mp4

Si quieres procesar una carpeta completa de videos de una vez, el artículo sobre Automatización por lotes con FFmpeg y Python cubre ese patrón en detalle.

Conclusión

Combinar FFmpeg y Whisper automatiza casi todo el flujo de trabajo de subtítulos.

  • El pipeline tiene cuatro pasos: extraer audio, transcribir con Whisper, escribir SRT, quemar con FFmpeg
  • Usa modelos medium o superiores para audio en idiomas distintos al inglés
  • Mantén todas las rutas de archivo solo con caracteres ASCII para evitar errores del filtro subtitles
  • El script de Python envuelve todo en un solo comando: python subtitle_pipeline.py input.mp4

Deja de perder tiempo en transcripción manual. Deja que Whisper se encargue y concéntrate en la edición.