Usage

At its core, ffsubsync takes a reference (something correctly timed) and an input subtitle (something mistimed), and writes a new subtitle shifted to match the reference. ffs, subsync, and ffsubsync are interchangeable entry points.

Sync against a video

The most common case: you have a video and an out-of-sync subtitle.

$ ffs video.mp4 -i unsynchronized.srt -o synchronized.srt

ffsubsync extracts the video’s audio, runs voice-activity detection to work out when someone is speaking, and finds the offset that best lines the subtitle’s “on” intervals up with the detected speech.

Sync against another subtitle

Sometimes you have a subtitle that is already correctly synced — perhaps in a language you don’t read — plus an out-of-sync subtitle in your own language. You can use the correct subtitle directly as the reference:

$ ffs reference.srt -i unsynchronized.srt -o synchronized.srt

ffsubsync decides what to do based on the reference’s file extension: a subtitle extension (.srt, .ass, .ssa, .sub) skips audio extraction entirely and derives the speech signal directly from the reference’s subtitle timings. Because there is no audio to decode, this runs in under a second. See Reference types for the full list of things that can serve as a reference.

Let ffsubsync find the input for you

If you omit -i, ffsubsync looks for subtitle files sitting next to the reference that share its name, and syncs each of them:

$ ffs video.mp4

For a reference named video.mp4 this picks up siblings like video.srt and video.en.srt from the same directory, and writes the synced result for each to a <name>.synced.srt alongside it (e.g. video.synced.srt), leaving the originals untouched. Previously-produced *.synced.srt files are skipped, so re-running is safe. Pass --overwrite-input to rewrite the detected files in place instead of producing .synced.srt copies.

Sibling auto-detection is local-only: it is skipped when subtitles are piped in on stdin, and for remote references (below).

Reading and writing standard streams

-i defaults to stdin and -o defaults to stdout, so ffsubsync composes cleanly in a pipeline:

$ cat unsynchronized.srt | ffs video.mp4 > synchronized.srt

Progress and log messages are written to stderr, so they won’t corrupt piped subtitle output.

Remote references

The reference can be a remote URL instead of a local file. Anything ffmpeg can read works as a video/audio reference, and remote subtitle files work too:

$ ffs "https://example.com/video.mp4" -i unsynchronized.srt -o synchronized.srt
$ ffs "https://example.com/reference.srt" -i unsynchronized.srt -o synchronized.srt

Supported protocols are http(s)://, rtmp://, rtsp://, and ftp://. Processing streams the reference over the network, so reliability depends on the connection. For large or flaky sources there are several options — --max-duration-seconds, --extract-audio-first, and --multi-segment-sync — described under Long and remote references.

What you get back

On success, ffsubsync writes the shifted subtitle and reports the offset (and framerate scale factor, if it corrected one) on stderr. If you’d rather drive ffsubsync from Python and inspect these values programmatically, see Using ffsubsync as a library.