Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchHow do you generate subtitles from a video with Python and FFmpeg, create an SRT file automatically, and burn subtitles into an MP4? This guide builds a local pipeline that validates an input video, runs FFmpeg’s Whisper speech-recognition filter, writes an editable SRT sidecar, and optionally produces a new video with captions rendered into the picture. Keeping the SRT as an intermediate file lets you correct wording and timing before encoding.
What you will build
The program orchestrates FFmpeg rather than implementing speech recognition itself. FFmpeg reads the media, sends its audio through the Whisper filter, and writes subtitle data. The filter requires a whisper.cpp model file and supports text, srt, and json destinations, along with language, queue, maximum-segment-length, and optional voice-activity-detection settings.
| # | Preview | Product | Price | |
|---|---|---|---|---|
| 1 |
|
The AI Income Generator: Subtitle: From GPT to Midjourney: Learn the Prompts, Tools, and Workflows | $0.99 | Buy on Amazon |
| 2 |
|
Intermediate Python | $41.63 | Buy on Amazon |
Your pipeline will have these stages:
- Validate the source path, model path, and output directory.
- Run FFmpeg with an argument list (not a shell command string).
- Write a temporary SRT and atomically rename it when FFmpeg succeeds.
- Review or edit the SRT.
- Either keep it as a sidecar, mux it as a selectable subtitle stream, or burn it into a new video.
FFmpeg describes its Whisper filter as running automatic speech recognition using OpenAI’s Whisper model. The exact filter option spelling can differ between FFmpeg builds, so verify the syntax supported by the build you deploy.
Prerequisites and model setup
Install FFmpeg
Install an FFmpeg build that includes the Whisper filter. Confirm that the executable is discoverable:
#1 Best Overall
ffmpeg -version
If the command is not on PATH, configure your application with an explicit executable path such as /opt/ffmpeg/bin/ffmpeg (or the equivalent Windows path).
Obtain a whisper.cpp model
Download a compatible whisper.cpp model file and keep its path in configuration. The model option is mandatory for the filter. Model choice, language, audio quality, and segmentation settings affect the resulting captions; there is no universal accuracy, speed, or cost figure that applies to every video and machine.
Choose an output directory
Use a directory where the process can create a temporary file and rename it to the final SRT. Do not overwrite the source media.
Generate an SRT file with Python
Python’s subprocess.run() is the recommended interface for commands that it can handle. Passing a list keeps filenames as separate arguments and leaves shell=False, the safer default.
from pathlib import Path
import os
import subprocess
import tempfile
def generate_srt(
video: Path,
model: Path,
srt: Path,
language: str = "en",
ffmpeg: str = "ffmpeg",
) -> None:
video = video.expanduser()
model = model.expanduser()
srt = srt.expanduser()
if not video.is_file():
raise FileNotFoundError(f"Input video does not exist: {video}")
if not model.is_file():
raise FileNotFoundError(f"Whisper model does not exist: {model}")
srt.parent.mkdir(parents=True, exist_ok=True)
if not os.access(srt.parent, os.W_OK):
raise PermissionError(f"Output directory is not writable: {srt.parent}")
# Keep the temporary file beside the destination so os.replace is atomic
# on the same filesystem.
fd, temporary_name = tempfile.mkstemp(
prefix=f".{srt.stem}-", suffix=".srt.tmp", dir=srt.parent
)
os.close(fd)
temporary = Path(temporary_name)
command = [
ffmpeg,
"-y",
"-i", str(video),
"-vn",
"-af",
(
f"whisper=model={model}:language={language}:"
f"destination={temporary}:format=srt"
),
"-f", "null",
"-",
]
try:
subprocess.run(
command,
check=True,
capture_output=True,
text=True,
timeout=3600,
)
os.replace(temporary, srt)
except FileNotFoundError as error:
raise RuntimeError(
f"FFmpeg executable was not found: {ffmpeg}"
) from error
except subprocess.CalledProcessError as error:
diagnostics = (error.stderr or error.stdout or "").strip()
raise RuntimeError(
f"FFmpeg failed with exit code {error.returncode}: {diagnostics}"
) from error
except subprocess.TimeoutExpired as error:
raise TimeoutError("FFmpeg exceeded the 3600-second timeout") from error
finally:
temporary.unlink(missing_ok=True)
if __name__ == "__main__":
generate_srt(
Path("input.mp4"),
Path("models/ggml-base.en.bin"),
Path("captions.srt"),
language="en",
)
Why these subprocess options matter
check=Trueconverts a non-zero FFmpeg exit intoCalledProcessError, so a failed transcription cannot be mistaken for success.capture_output=Trueretains FFmpeg diagnostics for logs and troubleshooting. In shared logs, redact sensitive paths before publishing them.text=Truedecodes standard output and standard error as text.timeout=3600prevents an unattended process from running forever; handleTimeoutExpiredwhen you need a different limit.- The temporary SRT is renamed only after success, preventing a partial caption file from appearing under the final name.
Paths containing spaces and special characters
Argument lists safely preserve spaces in input and output filenames. The filter itself is a single argument, however, and FFmpeg builds may require escaping characters such as colons, backslashes, or quotes inside a model or destination path. Test representative paths on the operating systems you support, and expose the model path as configuration rather than embedding it in source code. Never concatenate untrusted filenames into a shell string or switch to shell=True merely to make quoting appear easier.
Inspect and edit the SRT
An SRT file is plain text with numbered cues, start and end timestamps, and caption text:
1
00:00:01,200 --> 00:00:03,900
Example caption.
2
00:00:04,100 --> 00:00:06,700
The next caption.
Open the generated file in a subtitle editor or text editor. Correct names, punctuation, line breaks, and cue boundaries before producing a final video. Keep the SRT as a versioned intermediate artifact so you can re-render different video encodes without transcribing again.
Choose a subtitle output
| Output | How it works | Best use | Trade-off |
|---|---|---|---|
| SRT sidecar | Store captions.srt beside the video. |
Editing, archival, and players that load external captions. | Playback software must be told to load the file. |
| WebVTT sidecar | Convert or generate a WebVTT track. | Web video players and browser-oriented workflows. | Player support and cue-feature differences vary. |
| ASS/SSA | Use a styled subtitle format. | Positioning, fonts, colors, and karaoke-style effects. | More complex styling and renderer dependencies. |
| Muxed subtitle stream | Put the subtitle track inside a new media container. | Selectable captions in a single downloadable file. | The player must support the subtitle codec and stream mapping. |
| Burn-in | Render subtitle glyphs into the video frames. | Social platforms or playback environments that ignore subtitle tracks. | Text cannot be turned off and video must be re-encoded. |
FFmpeg’s format documentation lists SubRip (SRT), WebVTT, and SSA/ASS for relevant subtitle operations. Start with SRT unless your delivery target specifically requires another format.
Burn subtitles into a new MP4
After reviewing the SRT, use FFmpeg’s subtitles video filter:
ffmpeg -i input.mp4 -vf "subtitles=captions.srt" -c:a copy output-burned.mp4
This filter reads the subtitle file and draws the captions onto video frames. The FFmpeg build must be configured with libass; detect that requirement early and report a clear installation error if the filter is unavailable. Because the video frames change, FFmpeg normally re-encodes the video. Copying the audio stream with -c:a copy avoids an unnecessary audio encode when the output container and source codec permit it.
Write to a new filename. A burned-in file cannot expose or remove the text later, while the original video and editable SRT remain intact.
Rank #2
Mux selectable subtitles instead of burning them
Use explicit stream mapping when you want viewers to turn captions on or off. A typical MP4 workflow is:
Free tools Windows power users keep installed
One-click scans. No signup required.
ffmpeg -i input.mp4 -i captions.srt -map 0:v:0 -map 0:a? -map 1:0 -c:v copy -c:a copy -c:s mov_text -metadata:s:s:0 language=eng output-selectable.mp4
The subtitle codec and container must be compatible; mov_text is commonly used for an MP4 subtitle track. The optional audio map keeps the command usable for a source without an audio stream. Check the resulting streams with:
ffprobe -hide_banner output-selectable.mp4
Unlike burn-in, this approach preserves a selectable subtitle track, but player support and stream-selection behavior still vary.
Local transcription versus a hosted service
A local FFmpeg/Whisper pipeline keeps media in your environment and does not require an API key. You are responsible for downloading models, installing a compatible FFmpeg build, allocating CPU or GPU resources, and maintaining the process.
A hosted transcription service can reduce model-management work, but adds network transfer, account, pricing, privacy, and regional-availability decisions. For example, AWS Transcribe documents SRT and WebVTT subtitle output; verify the service’s current terms and supported features before adopting it. Do not compare accuracy, speed, or cost without naming the model, language, hardware, media sample, and date of the measurement.
Reliability and security checklist
- Validate that the input and model files exist before invoking FFmpeg.
- Confirm that the executable is discoverable or accept an explicit executable path.
- Ensure the destination directory is writable and use a same-directory temporary file for atomic replacement.
- Keep
shell=Falseand pass an argument list; do not interpolate untrusted filenames into shell syntax. - Set a timeout and handle both FFmpeg failures and timeouts.
- Preserve useful stderr diagnostics while redacting sensitive paths in shared logs.
- Keep the original media untouched and write every rendered result to a new path.
- Record the FFmpeg version, model identifier, language, and relevant filter settings so a caption run can be reproduced.
- Test model and destination paths containing spaces and platform-specific special characters.
Troubleshoot common failures
“ffmpeg” is not found
Install FFmpeg or pass its absolute path through the ffmpeg parameter. The Python exception to catch is FileNotFoundError.
The Whisper filter is unknown
Your build may not include the Whisper integration or may use different filter options. Run ffmpeg -filters, inspect the build documentation, and install a build that supports the required filter and whisper.cpp model format.
FFmpeg exits with an error about the model or filter arguments
Check that the model file is readable and that its path is escaped correctly for the build and operating system. Confirm the language code and destination syntax against that build’s filter reference.
Burn-in reports that the subtitles filter is unavailable
Install an FFmpeg build configured with libass, then retry the -vf subtitles=... command. You can still retain or mux the SRT while resolving the rendering dependency.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →The SRT exists but is incomplete
Do not treat a file left by an interrupted run as valid output. The example writes to a temporary name and renames only after a successful exit; inspect stderr, verify the timeout, and rerun with the same recorded model and settings.
The Bottom Line
Use Python to validate inputs and supervise FFmpeg, generate an editable SRT with the Whisper filter, then choose sidecar, muxed, or burned-in delivery according to whether captions must remain editable and selectable.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

