NumberVideo_Bot / trim_silence.py
eyuvaraj's picture
Upload 41 files
b1d4203
import subprocess
import tempfile
import sys
import os
import logging
log_level = logging.ERROR
log_filename = 'silence_cutter.log'
logger = logging.getLogger('')
logger.setLevel(log_level)
log_handler = logging.FileHandler(log_filename, delay=True)
logger.addHandler(log_handler)
def findSilences(filename, dB = -25):
"""
returns a list:
even elements (0,2,4, ...) denote silence start time
uneven elements (1,3,5, ...) denote silence end time
"""
logging.debug(f"findSilences ()")
logging.debug(f" - filename = {filename}")
logging.debug(f" - dB = {dB}")
command = ["ffmpeg","-i",filename,
"-af","silencedetect=n=" + str (dB) + "dB:d=1",
"-f","null","-"]
output = subprocess.run (command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
s = str(output)
lines = s.split("\\n")
time_list = []
logging.debug(" lines: ```\n" + "\n".join(lines) + "```\n\n")
for line in lines:
if ("silencedetect" in line):
words = line.split(" ")
logging.debug(" words: " + str(words))
for i in range (len(words)):
if ("silence_start" in words[i]):
time_list.append (float(words[i+1]))
if "silence_end" in words[i]:
time_list.append (float (words[i+1]))
silence_section_list = list (zip(*[iter(time_list)]*2))
#return silence_section_list
return time_list
def getVideoDuration(filename:str) -> float:
logging.debug(f"getVideoDuration ()")
logging.debug(f" - filename = {filename}")
command = ["ffprobe","-i",filename,"-v","quiet",
"-show_entries","format=duration","-hide_banner",
"-of","default=noprint_wrappers=1:nokey=1"]
output = subprocess.run (command, stdout=subprocess.PIPE)
s = str(output.stdout, "UTF-8")
return float (s)
def getSectionsOfNewVideo (silences, duration):
"""Returns timings for parts, where the video should be kept"""
return [0.0] + silences + [duration]
def ffmpeg_filter_getSegmentFilter(videoSectionTimings):
ret = ""
for i in range (int (len(videoSectionTimings)/2)):
start = videoSectionTimings[2*i]
end = videoSectionTimings[2*i+1]
ret += "between(t," + str(start) + "," + str(end) + ")+"
# cut away last "+"
ret = ret[:-1]
return ret
def getFileContent_videoFilter(videoSectionTimings):
ret = "select='"
ret += ffmpeg_filter_getSegmentFilter (videoSectionTimings)
ret += "', setpts=N/FRAME_RATE/TB"
return ret
def getFileContent_audioFilter(videoSectionTimings):
ret = "aselect='"
ret += ffmpeg_filter_getSegmentFilter (videoSectionTimings)
ret += "', asetpts=N/SR/TB"
return ret
def writeFile (filename, content):
logging.debug(f"writeFile ()")
logging.debug(f" - filename = {filename}")
with open (filename, "w") as file:
file.write (str(content))
def ffmpeg_run (file, videoFilter, audioFilter, outfile):
logging.debug(f"ffmpeg_run ()")
# prepare filter files
vFile = tempfile.NamedTemporaryFile (mode="w", encoding="UTF-8", prefix="silence_video")
aFile = tempfile.NamedTemporaryFile (mode="w", encoding="UTF-8", prefix="silence_audio")
videoFilter_file = vFile.name #"/tmp/videoFilter" # TODO: replace with tempfile
audioFilter_file = aFile.name #"/tmp/audioFilter" # TODO: replace with tempfile
writeFile (videoFilter_file, videoFilter)
writeFile (audioFilter_file, audioFilter)
command = ["ffmpeg","-i",file,
"-filter_script:v",videoFilter_file,
"-filter_script:a",audioFilter_file,
outfile]
subprocess.run (command)
vFile.close()
aFile.close()
def cut_silences(infile, outfile, dB = -35):
logging.debug(f"cut_silences ()")
logging.debug(f" - infile = {infile}")
logging.debug(f" - outfile = {outfile}")
logging.debug(f" - dB = {dB}")
print ("detecting silences")
silences = findSilences (infile,dB)
duration = getVideoDuration (infile)
videoSegments = getSectionsOfNewVideo (silences, duration)
videoFilter = getFileContent_videoFilter (videoSegments)
audioFilter = getFileContent_audioFilter (videoSegments)
print ("create new video")
ffmpeg_run (infile, videoFilter, audioFilter, outfile)
def printHelp():
print ("Usage:")
print (" silence_cutter.py [infile] [optional: outfile] [optional: dB]")
print (" ")
print (" [outfile]")
print (" Default: [infile]_cut")
print (" ")
print (" [dB]")
print (" Default: -30")
print (" A suitable value might be around -50 to -35.")
print (" The lower the more volume will be defined das 'silent'")
print (" -30: Cut Mouse clicks and mouse movent; cuts are very recognizable.")
print (" -35: Cut inhaling breath before speaking; cuts are quite recognizable.")
print (" -40: Cuts are almost not recognizable.")
print (" -50: Cuts are almost not recognizable.")
print (" Cuts nothing, if there is background noise.")
print (" ")
print ("")
print ("Dependencies:")
print (" ffmpeg")
print (" ffprobe")
def main():
logging.debug(f"main ()")
args = sys.argv[1:]
if (len(args) < 1):
printHelp()
return
if (args[0] == "--help"):
printHelp()
return
infile = args[0]
if (not os.path.isfile (infile)):
print ("ERROR: The infile could not be found:\n" + infile)
return
# set default values for optionl arguments
tmp = os.path.splitext (infile)
outfile = tmp[0] + "_cut" + tmp[1]
dB = -20
if (len(args) >= 2):
outfile = args[1]
if (len(args) >= 3):
dB = args[2]
cut_silences (infile, outfile, dB)
if __name__ == "__main__":
# main()
import os
for file in os.listdir():
if file.endswith(".mp4"):
cut_silences(file, file.split(".mp4")[0] + "_cut.mp4", -20)