How to Fix Out-of-Sync Subtitles: Shift, Stretch and Re-Time
Diagnose why subtitles are out of sync and fix them properly: shift all cues by a constant offset, stretch timing to correct frame-rate drift, and re-time individual sections after edits.
- timing
- sync
- srt
Out-of-sync subtitles are one of the most common subtitle problems, and one of the most annoying for viewers. The good news: almost every sync problem falls into one of three patterns, and each has a specific, mechanical fix. The trick is diagnosing which one you have before you start dragging cues around.
Step 1: Diagnose the type of drift
Pick three moments in the video — one near the start, one in the middle and one near the end. At each, note how far the subtitle is from the spoken line. Write it down as a number: “+2.0 s late”, “−0.5 s early”.
Then compare:
| What you measure | Diagnosis | Fix |
|---|---|---|
| Same offset at start, middle and end | Constant offset | Shift all cues |
| Offset grows steadily over time | Linear drift (usually frame rate) | Stretch between two sync points |
| Fine, then suddenly wrong after a point | Edit mismatch (cut or added footage) | Shift only from that point on |
| Random errors throughout | Bad alignment | Re-time cue by cue, or regenerate |
Don’t skip the measurement. Applying a constant shift to a file with linear drift fixes one part of the video and breaks the rest.
Fix 1: Constant offset — shift everything
A constant offset usually happens when subtitles were made for a version of the video with a different intro, a logo sting or a few seconds of black at the start.
The fix is to add or subtract the same amount from every timestamp. If the subtitles appear 2.0 seconds late, shift them by −2.0 s.
Testing the offset in a player
Before changing the file, find the exact value in a player:
- VLC: press
GandHto move the subtitle delay in 50 ms steps while the video plays. The current delay is shown on screen. - mpv: press
zandZ(Shift+z) to adjust subtitle delay in 100 ms steps.
Once it looks right, use that value to fix the file permanently — player settings don’t travel with the file.
Shifting with FFmpeg
FFmpeg can apply an offset while rewriting a subtitle file:
# Subtitles are 2 seconds early: delay them by 2 seconds
ffmpeg -itsoffset 2 -i subs.srt -c copy subs_fixed.srt
A negative -itsoffset moves subtitles earlier, but cues that would end up before zero can be dropped or clamped, so check the beginning of the result.
Shifting with a script
If you prefer to understand exactly what happens, a short Python script does the job:
import re
from datetime import timedelta
OFFSET = timedelta(seconds=-2.0)
pattern = re.compile(r"(\d{2}):(\d{2}):(\d{2}),(\d{3})")
def shift(m):
h, mi, s, ms = map(int, m.groups())
t = timedelta(hours=h, minutes=mi, seconds=s, milliseconds=ms) + OFFSET
t = max(t, timedelta(0))
total_ms = int(t.total_seconds() * 1000)
h, rem = divmod(total_ms, 3_600_000)
mi, rem = divmod(rem, 60_000)
s, ms = divmod(rem, 1000)
return f"{h:02}:{mi:02}:{s:02},{ms:03}"
with open("subs.srt", encoding="utf-8") as f:
text = f.read()
with open("subs_fixed.srt", "w", encoding="utf-8") as f:
f.write(pattern.sub(shift, text))
Fix 2: Linear drift — stretch the timing
If subtitles start in sync but get progressively later (or earlier), the timing needs to be scaled, not just shifted. The classic cause is a frame-rate mismatch: subtitles timed for one version of a video being used with another.
Common ratios:
| Subtitle timed for | Video plays at | Scale factor |
|---|---|---|
| 23.976 fps | 25 fps (PAL speed-up) | 23.976 ÷ 25 ≈ 0.959 |
| 25 fps | 23.976 fps | 25 ÷ 23.976 ≈ 1.043 |
| 24 fps | 23.976 fps | 24 ÷ 23.976 = 1.001 |
PAL speed-up (playing 24 fps film at 25 fps) makes the whole video about 4% shorter, which is why the error becomes obvious within a few minutes. The 24 → 23.976 mismatch is tiny — about 3.6 seconds over an hour — so it may only show up late in long videos.
Two-point synchronisation
You don’t need to know the cause to fix linear drift. You only need two reference points:
- Find a line near the start and note its current subtitle time (
old₁) and the time it is actually spoken (new₁). - Do the same for a line near the end (
old₂,new₂).
Every timestamp t then becomes:
scale = (new₂ − new₁) / (old₂ − old₁)
t_new = new₁ + (t − old₁) × scale
This handles offset and drift at the same time. Pick reference lines that are clearly spoken and far apart — the further apart, the more accurate the result.
Desktop tools such as Subtitle Edit offer this as “point synchronisation”, and it is a core feature of subtitle studios like CutMySub.
Fix 3: Edit mismatch — shift from a point onward
Sometimes subtitles are perfect for the first ten minutes, then jump out of sync and stay that way. That almost always means footage was cut or added at that point: an ad break removed, a scene trimmed, a sponsor segment inserted.
To fix it:
- Find the first cue that is wrong.
- Measure the new offset from that point.
- Shift only that cue and everything after it.
- Check the end of the video. If there’s another jump, repeat for the next segment.
If footage was removed, some cues may now refer to content that no longer exists. Delete those, and check nothing overlaps at the join.
Fix 4: Bad alignment — re-time cue by cue
If errors are random — some cues early, some late, some fine — the problem is the timing itself, not a global offset. This is common with old fan-made files and some auto-generated captions.
Options:
- Regenerate the timing. Some tools can re-align existing text to the audio (“forced alignment”), which keeps your corrected words but recomputes the timestamps.
- Re-time manually on a waveform. Speech shows up clearly as peaks; drag each cue’s start to the beginning of the peak and its end to where the speech stops.
When re-timing by hand, a few guidelines keep things readable:
- Start a cue at the first syllable — a frame or two early is fine.
- Keep at least a short gap between consecutive cues (many style guides use two frames) so viewers notice the change.
- Don’t leave cues on screen across a shot change if you can avoid it.
- Avoid cues shorter than about one second.
Preventing sync problems in the first place
- Generate subtitles from the final cut. Captioning a rough cut guarantees you’ll be fixing sync later.
- Keep the frame rate consistent. Export the video at the same frame rate the subtitles were timed against.
- Start at zero. If your export adds black frames or a bumper at the start, add them before captioning.
- Version your files. Name subtitle files to match the video version they belong to (
episode3_v2_final.srt).
Quick checklist
- Measure the offset at the start, middle and end.
- Same everywhere → shift.
- Growing over time → two-point stretch.
- Sudden jump → shift from that point.
- Random → re-align or re-time manually.
- Re-check the start, end and any joins before publishing.
If you are also splitting or joining files as part of the fix, see how to split or merge SRT files, which covers re-numbering and offsets at the join.