Media
How to Remove Silence from Video and Audio with FFmpeg
FFmpeg can find every silent gap in a recording and cut it out. Here are the commands, a short Python script for video, and what to tune.
By Prolificrew Engineering · · 3 min read
In this article
Dead air is the most tedious part of editing talking-head videos, podcasts and screen recordings. FFmpeg, the open-source media toolkit, can find the silent sections and remove them automatically. This guide shows three techniques, from a one-line command for audio to a script that cuts silence out of video while keeping audio and picture in sync. It is the same underlying approach our app Cut Video Gaps builds on, wrapped in an interface.
Step 1: detect silence with silencedetect
The silencedetect audio filter reports where audio stays below a loudness threshold for at least a minimum duration. It does not change the file; it prints timestamps to the log:
ffmpeg -hide_banner -i input.mp4 -af silencedetect=noise=-30dB:d=0.5 -f null -In the output you will see pairs of lines like these:
[silencedetect @ 0x...] silence_start: 12.48
[silencedetect @ 0x...] silence_end: 14.91 | silence_duration: 2.43noise=-30dBis the threshold. Anything quieter counts as silence. Use a lower number (for example-40dB) for noisy rooms, and a higher one (-25dB) for very clean recordings.d=0.5is the minimum silence length in seconds. Shorter pauses are kept, which preserves natural speech rhythm.
Step 2 (audio only): remove silence in one command
For audio files, the silenceremove filter does everything in one pass:
ffmpeg -i input.wav -af "silenceremove=start_periods=1:start_threshold=-40dB:stop_periods=-1:stop_duration=0.5:stop_threshold=-40dB" output.wavstart_periods=1 trims silence at the beginning, and stop_periods=-1 removes every silent stretch longer than stop_duration throughout the file. This works well for podcasts and voice memos. Do not use it directly on video, because it changes the audio length while the picture stays the same, and the two fall out of sync.
Step 3 (video): cut the silent sections from picture and sound together
For video, the approach is: detect silence, work out the segments to keep, and use select and aselect filters to keep only those time ranges in both the video and the audio streams, resetting timestamps so the result plays continuously. The script below automates all three steps.
#!/usr/bin/env python3
"""Remove silent gaps from a video using FFmpeg. Usage: python cut_silence.py in.mp4 out.mp4"""
import re
import subprocess
import sys
import tempfile
from pathlib import Path
NOISE = "-30dB" # quieter than this counts as silence
MIN_SILENCE = 0.5 # seconds of silence required before we cut
PAD = 0.12 # seconds of silence kept around speech so cuts sound natural
def duration(path):
out = subprocess.run(
["ffprobe", "-v", "error", "-show_entries", "format=duration",
"-of", "default=noprint_wrappers=1:nokey=1", path],
capture_output=True, text=True, check=True,
).stdout
return float(out.strip())
def detect(path):
cmd = ["ffmpeg", "-hide_banner", "-i", path,
"-af", f"silencedetect=noise={NOISE}:d={MIN_SILENCE}",
"-f", "null", "-"]
log = subprocess.run(cmd, stderr=subprocess.PIPE, text=True).stderr
starts = [max(float(x), 0.0) for x in re.findall(r"silence_start: (-?[\d.]+)", log)]
ends = [float(x) for x in re.findall(r"silence_end: (-?[\d.]+)", log)]
return starts, ends
def segments_to_keep(total, starts, ends):
if len(starts) > len(ends): # the file ends in silence
ends = ends + [total]
keep, cursor = [], 0.0
for s, e in zip(starts, ends):
stop = min(s + PAD, total)
if stop - cursor > 0.05:
keep.append((cursor, stop))
cursor = max(e - PAD, stop)
if total - cursor > 0.05:
keep.append((cursor, total))
return keep
def main(src, dst):
total = duration(src)
starts, ends = detect(src)
keep = segments_to_keep(total, starts, ends)
if not keep:
sys.exit("Nothing to keep. Try a lower threshold.")
expr = "+".join(f"between(t,{a:.3f},{b:.3f})" for a, b in keep)
with tempfile.TemporaryDirectory() as tmp:
vf = Path(tmp, "v.txt")
af = Path(tmp, "a.txt")
vf.write_text(f"select='{expr}',setpts=N/FRAME_RATE/TB")
af.write_text(f"aselect='{expr}',asetpts=N/SR/TB")
subprocess.run(
["ffmpeg", "-y", "-i", src,
"-filter_script:v", str(vf), "-filter_script:a", str(af),
"-c:v", "libx264", "-crf", "20", "-preset", "medium",
"-c:a", "aac", "-b:a", "192k", dst],
check=True,
)
print(f"Kept {sum(b - a for a, b in keep):.1f}s of {total:.1f}s")
if __name__ == "__main__":
if len(sys.argv) != 3:
sys.exit(__doc__)
main(sys.argv[1], sys.argv[2])A few notes on how it works. The filters are written to script files because a long recording can have hundreds of segments, and a very long expression can exceed command-line limits. setpts=N/FRAME_RATE/TB and asetpts=N/SR/TB renumber timestamps so the kept pieces play back-to-back. Because the video is filtered, it has to be re-encoded, so choose your quality settings (-crf, -preset) to suit your needs.
Tuning for natural-sounding results
- Threshold. If the tool cuts words, your threshold is too high. If it leaves background hiss untouched, it is too low. Measure your noise floor in a quiet moment and set the threshold a few decibels above it.
- Minimum silence. Between 0.4 and 0.8 seconds works for most speech. Shorter values chop the rhythm of normal sentences.
- Padding. Keeping about a tenth of a second on either side of speech avoids clipped consonants and abrupt cuts.
- Breaths and filler words. Silence detection will not remove “um” or loud breaths. Those need transcription or speech-aware models.
- Variable frame rate. Screen recordings and phone videos are often variable frame rate, which can make the
setptsapproach drift. Convert to a constant frame rate first if you see sync problems.
When a script is not enough
A script is perfect for batch jobs and one-off cleanups. For a creator’s daily workflow you usually want to preview the cuts, adjust the threshold with instant feedback and export to an editor such as Final Cut Pro. That is the gap our macOS app Cut Video Gaps fills.
If you are building video processing into your own product, from automated editing to transcoding and detection, see our video and computer vision development service or get in touch.