Skip to content

Instantly share code, notes, and snippets.

@kainabel
Created November 20, 2023 15:36
Show Gist options
  • Save kainabel/843ea04c3a47129abd851a2fe2c6caee to your computer and use it in GitHub Desktop.
Save kainabel/843ea04c3a47129abd851a2fe2c6caee to your computer and use it in GitHub Desktop.
FFmpeg silence detect wrapper - prints human-readable timecodes
#!/usr/bin/env python3
import argparse
import re
import subprocess
import sys
def format_time(s):
(h, s) = divmod(s, 3600)
(m, s) = divmod(s, 60)
h = int(h)
m = int(m)
# NOTE: Seconds are zero-padded to 8 characters
# to account for the decimal point and fractional part
return f'{h:02}:{m:02}:{s:08.5f}'
parser = argparse.ArgumentParser()
parser.add_argument(
'file',
help='input file',
)
parser.add_argument(
'-n',
'--noise',
default=0.001,
help='noise tolerance',
)
parser.add_argument(
'-d',
'--duration',
default=2,
help='silence duration until notification',
)
parser.add_argument(
'-m',
'--mono',
action='store_true',
help='process each channel separately',
)
args = parser.parse_args()
if args.mono:
mono_arg = 'y'
else:
mono_arg = 'n'
p = subprocess.Popen([
'ffmpeg',
'-i', args.file,
'-af', f'silencedetect=noise={args.noise}:duration={args.duration}:mono={mono_arg}',
'-f', 'null',
'-',
], encoding='utf-8', errors='replace', stderr=subprocess.PIPE)
stderr = []
for line in p.stderr:
line = line.rstrip('\n')
stderr.append(line)
if not line.startswith('[silencedetect'):
continue
m = re.search(r'silence_start: ([\d.]+)', line)
if m:
start = format_time(float(m.group(1)))
print(f'silence: {start} - ', end='')
m = re.search(r'silence_end: ([\d.]+) \| silence_duration: ([\d.]+)', line)
if m:
end = format_time(float(m.group(1)))
duration = format_time(float(m.group(2)))
print(f'{end} (duration: {duration})')
p.wait()
if p.returncode != 0:
print('\n'.join(stderr))
print(f'ffmpeg exited with return code {p.returncode}', file=sys.stderr)
sys.exit(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment