Last active
July 12, 2022 18:40
-
-
Save bobbicodes/8261d999e62f9e06b0813f7d520b7111 to your computer and use it in GitHub Desktop.
Babashka script to trim silence from video with ffmpeg and moviepy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns silence | |
(:require [clojure.string :as str] | |
[clojure.java.shell :as shell] | |
[babashka.process :as p])) | |
(defn silences-output [file] | |
(:err | |
(shell/sh | |
"ffmpeg" "-hide_banner" "-vn" "-i" | |
file "-af" "silencedetect=n=-50dB:d=1" "-f" "null" "-"))) | |
(defn lines [s] | |
(filter #(str/includes? % "silence_end") | |
(str/split (silences-output s) #"\r?\n|\r"))) | |
(defn silences [line] | |
(str (nth line 4) " " (nth line 7))) | |
(defn generate-timestamps [file] | |
(let [base-name (apply str (take-while #(not= \. %) file))] | |
(->> | |
(map silences (map #(str/split % #"\s+") (lines file))) | |
(interpose \newline) | |
(apply str) | |
(spit (str base-name "-timestamps.txt"))))) | |
(defn trim-video [file] | |
(let [base-name (apply str (take-while #(not= \. %) file)) | |
cmd ["python3" "trim-silence.py" file | |
(str base-name "-trimmed.mp4") | |
(str base-name "-timestamps.txt")] | |
proc (p/process cmd {:inherit true | |
:shutdown p/destroy-tree})] | |
proc)) | |
(def file (first *command-line-args*)) | |
(generate-timestamps file) | |
@(trim-video file) | |
(comment | |
(def file "JavaScript-3-Poetry-club.mp4") | |
(generate-timestamps file) | |
(trim-video file) | |
) | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import sys | |
import subprocess | |
import os | |
import shutil | |
from moviepy.editor import VideoFileClip, concatenate_videoclips | |
# Input file path | |
file_in = sys.argv[1] | |
# Output file path | |
file_out = sys.argv[2] | |
# Silence timestamps | |
silence_file = sys.argv[3] | |
minimum_duration = 1 | |
def main(): | |
# number of clips generated | |
count = 0 | |
# start of next clip | |
last = 0 | |
in_handle = open(silence_file, "r", errors='replace') | |
video = VideoFileClip(file_in) | |
full_duration = video.duration | |
clips = [] | |
while True: | |
line = in_handle.readline() | |
if not line: | |
break | |
end,duration = line.strip().split() | |
to = float(end) - float(duration) | |
start = float(last) | |
clip_duration = float(to) - start | |
# Clips less than one seconds don't seem to work | |
print("Clip Duration: {} seconds".format(clip_duration)) | |
print("Clip {} (Start: {}, End: {})".format(count, start, to)) | |
clip = video.subclip(start, to) | |
clips.append(clip) | |
last = end | |
count += 1 | |
if full_duration - float(last) > minimum_duration: | |
print("Clip {} (Start: {}, End: {})".format(count, last, 'EOF')) | |
clips.append(video.subclip(float(last))) | |
processed_video = concatenate_videoclips(clips) | |
processed_video.write_videofile( | |
file_out, | |
fps=30, | |
preset='ultrafast', | |
codec='libx264' | |
) | |
in_handle.close() | |
video.close() | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment