Whisper is OpenAI’s open-source speech recognition model, and it’s the rare AI tool that works brilliantly with almost no setup: point it at an audio file, get back a transcript with timestamps. In this guide you’ll install it, transcribe a recording, generate properly formatted SRT subtitles — the readable kind, not one giant wall of text — and burn those subtitles into a video. You’ll also meet faster-whisper, the community reimplementation that’s several times quicker.
This is for podcasters, video creators, students sitting on lecture recordings, and developers who need transcription in a pipeline without sending audio to a third party.
Prerequisites
- OS: Linux, macOS, or Windows (via WSL2 for the smoothest ride).
- Python: 3.9–3.12.
- ffmpeg: required — Whisper shells out to it for audio decoding. Install with
apt install ffmpeg,brew install ffmpeg, or from ffmpeg.org on Windows. - Hardware: any modern CPU works; an NVIDIA GPU makes the larger models dramatically faster. A 10-minute audio file takes a few minutes on CPU with the
smallmodel.
Step 1: Install Whisper
pip install -U openai-whisper
whisper --help | head -30
Whisper downloads its model weights on first use (~1 GB for small, ~3 GB for large), cached in ~/.cache/whisper. Available sizes, smallest to largest: tiny, base, small, medium, large-v3, and large-v3-turbo — the turbo variant is nearly as accurate as large-v3 at a fraction of the speed cost, and it’s the best default in 2026.
How to choose: tiny and base are fine for clear, single-speaker audio where speed matters more than polish — think quick voice-memo transcripts. small is the sweet spot for most real work: noticeably fewer errors on accents and terminology, still fast on CPU. medium and above earn their keep on difficult audio — overlapping speakers, heavy accents, technical jargon — or when the transcript is the product (published captions, legal records). When in doubt, transcribe a two-minute sample with small and large-v3-turbo and compare; the right model is the smallest one whose errors you can live with.
Step 2: Transcribe your first file
whisper interview.mp3 --model small --language en --output_dir ./out
This writes interview.txt (plain transcript), interview.srt, interview.vtt, and a few other formats into ./out. Drop --language en and Whisper auto-detects the language — it handles 90+ of them. For translation to English instead of transcription, add --task translate.
Expected output looks like this:
Detecting language using up to the first 30 seconds...
Detected language: English
[00:00.000 --> 00:04.200] So let's start with the project timeline...
Transcribing: 100%|████████| 42/42 [01:12<00:00, 1.72s/it]
Step 3: Generate subtitles people can actually read
Here’s where most people stop too early. Whisper’s default SRT output creates one subtitle per speech segment, which can mean eleven seconds of wall-of-text on screen. Broadcast convention is ~42 characters per line, two lines max, a few seconds per subtitle. Whisper has flags for exactly this — but they only work with word-level timestamps enabled:
whisper video.mp4 --model small --language en \
--output_format srt --output_dir ./out \
--word_timestamps True --max_line_width 42 --max_line_count 2
--word_timestamps True is the key: it tells Whisper to align each word to a time, which is what lets --max_line_width and --max_line_count reflow the text into readable chunks. The result:
1
00:00:00,000 --> 00:00:03,120
So let's start with the
project timeline.
2
00:00:03,120 --> 00:00:06,400
The first milestone is due
in early March.
Step 4: Burn the subtitles into the video
If your player doesn’t support sidecar subtitles, bake them in with ffmpeg:
ffmpeg -i video.mp4 -vf subtitles=out/video.srt final.mp4
The subtitles filter renders the SRT over the video and re-encodes. Keep the original SRT too — platforms like YouTube accept SRT uploads directly and render them more crisply than burned-in text.
Step 5: Go faster with faster-whisper
The original Whisper package is not optimised for speed. faster-whisper (built on CTranslate2) is typically 3–4× faster with the same accuracy, and it quantises the model so large-v3-turbo fits comfortably on modest GPUs:
pip install faster-whisper
python3 - <<'EOF'
from faster_whisper import WhisperModel
model = WhisperModel("large-v3-turbo", device="cuda", compute_type="int8_float16")
segments, info = model.transcribe("interview.mp3", beam_size=5)
print(f"Detected language: {info.language} ({info.language_probability:.0%})")
with open("interview.srt", "w") as f:
for i, seg in enumerate(segments, 1):
f.write(f"{i}\n{seg.start:.3f} --> {seg.end:.3f}\n{seg.text.strip()}\n\n")
print("Wrote interview.srt")
EOF
On CPU-only machines, device="cpu", compute_type="int8" still beats the original package. For batch jobs — a folder of recordings — loop over files and reuse one model instance; loading the model once is half the battle.
Batch-processing a folder of recordings
One file is a demo; a folder is a workflow. This loop transcribes every audio file in a directory with faster-whisper, reusing one loaded model, and writes an SRT next to each source file. It also skips files that already have subtitles, so re-runs are cheap:
pip install faster-whisper
python3 - <<'EOF'
from pathlib import Path
from faster_whisper import WhisperModel
model = WhisperModel("large-v3-turbo", device="cuda", compute_type="int8_float16")
for audio in sorted(Path("recordings").glob("*.mp3")):
srt_path = audio.with_suffix(".srt")
if srt_path.exists():
print(f"Skipping {audio.name} (already done)")
continue
segments, info = model.transcribe(str(audio), beam_size=5)
def ts(t):
h, r = divmod(t, 3600); m, s = divmod(r, 60)
return f"{int(h):02d}:{int(m):02d}:{s:06.3f}".replace(".", ",")
with open(srt_path, "w") as f:
for i, seg in enumerate(segments, 1):
f.write(f"{i}\n{ts(seg.start)} --> {ts(seg.end)}\n{seg.text.strip()}\n\n")
print(f"Wrote {srt_path.name} [{info.language}]")
EOF
A few practical notes: keep the original audio — you’ll re-transcribe when better models arrive, and storage is cheap. Name output files deterministically (same stem, .srt extension) so downstream tools can find them. And if you’re processing interviews, consider a diarization pass (pyannote) to label speakers; Whisper alone won’t tell you who said what.
Where things go wrong
“ffmpeg not found”. Whisper needs ffmpeg on your PATH, not just Python. Install the system package and re-open your terminal.
Transcript has repeated phrases or hallucinates during silence. Whisper invents text over long silences and music. Trim silence first, or raise --no_speech_threshold (default 0.6) to make it stricter about what counts as speech.
Wrong language detected. Short clips confuse the detector. Pass --language explicitly — it also speeds things up by skipping detection.
Out of memory on GPU. Drop a model size, or switch to faster-whisper with compute_type="int8". The large models need ~10 GB VRAM in the original package.
Subtitles drift out of sync. This usually means the audio has a variable frame rate or the file’s container timestamps are odd. Re-encode the audio to a clean WAV first (ffmpeg -i in.mp4 -ar 16000 -ac 1 clean.wav) and transcribe that — Whisper’s timing is far more reliable on plain PCM input.
Wrap-up
You can now turn any recording into a transcript and broadcast-sane subtitles, entirely offline. The pattern generalizes: Whisper handles the audio, and a local LLM can then summarise, translate, or extract action items from the transcript — which is exactly the kind of pipeline our document automation guide builds for text. Pair the two and a folder of meeting recordings becomes searchable knowledge.
Featured image: KyleThayer via Wikimedia Commons (CC0 1.0 Universal)
