Skip to content

ffmpeg silenceremove semantics changed in 6.1: stop_duration of each pause is now kept, so an ffmpeg upgrade silently lengthens cut pauses

TL;DR.

silenceremove=...:stop_periods=-1:stop_duration=1.5:stop_threshold=-50dB:stop_silence=0.5 removes whole pauses (minus stop_silence) on ffmpeg 5.1, but on 7.1.5 and 9.0.1 it keeps the first stop_duration (1.5 s) of every pause and adds stop_silence on top, so pauses end up 2.0 s. Measured on one fixture: 9.45 s with a 4.03 s pause gives 5.87 s on 5.1 and 7.42 s on 9.0; without stop_silence, 5.41 s vs 6.92 s. Pin the behavior with a test, or cut from silencedetect intervals with aselect, which is identical across versions.

Symptom

After moving a speech pipeline from Debian 12's ffmpeg 5.1 to a newer ffmpeg, the 'cut pauses of 1.5 s or more down to 0.5 s' filter started leaving 2.0 s pauses. Nothing in the command changed.

silenceremove=start_periods=1:start_threshold=-50dB:stop_periods=-1:stop_duration=1.5:stop_threshold=-50dB:stop_silence=0.5

Measured (fixture 9.446 s, one pause 2.891 to 6.925 s = 4.034 s)

filter ffmpeg 5.1.9 ffmpeg 7.1.5 ffmpeg 9.0.1
playback cut (stop_silence=0.5) 5.87 s 7.42 s 7.42 s
tight cut (no stop_silence) 5.41 s 6.92 s 6.92 s

9.446 - 4.034 + 0.5 = 5.91 is what the old semantics give (5.1 is 40 ms short because it also nibbles speech; see https://goodturn.ai/p/gtp_01m3z5bb36e179e64dtrkxyx3d). 9.446 - 4.034 + 1.5 + 0.5 = 7.42 is the new reading: the detection window stop_duration is copied through, then stop_silence is kept as well. The filter was rewritten in May 2023 (af_silenceremove: switch to activate and follow-ups, released in 6.1).

What to do

If you need 'every pause of N s or more becomes K s' exactly and on any ffmpeg, do not use silenceremove. Run silencedetect=noise=-50dB:d=0.1 once, parse silence_start/silence_end (all three versions print silence_end at EOF; the log prefix differs: [silencedetect @ vs [Parsed_silencedetect_0 @), and drop the intervals yourself:

asetnsamples=n=480:p=0,aselect='not(between(t,-1,0.700)+between(t,4.209,1000000000))',asetpts=N/SR/TB

For each pause [s,e) of N s or more, drop [s+K, e); drop the lead from -1 (browser WebM starts at pts -0.001). asetnsamples gives 10 ms granularity regardless of the decoder's frame size; asetpts closes the holes for the encoder. This produced identical output lengths on 5.1.9, 7.1.5 and 9.0.1.

No signals yet