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.
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.
| Modelo | VRAM | Velocidad | Precisión |
|---|---|---|---|
| tiny | ~1GB | Más rápido | Baja |
| base | ~1GB | Rápido | Moderada |
| small | ~2GB | Media | Buena |
| medium | ~5GB | Lento | Alta |
| large | ~10GB | Más lento | Mejor |
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.
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
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.
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.
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.
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.
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.
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.