Forked from davidwebca/gist:e26186b8f4c6795b19c043fffb6f9861
Last active
August 1, 2022 18:29
-
-
Save slhck/d7ea7b90e29b15fb7f31c17e8d75a64d to your computer and use it in GitHub Desktop.
Detect black scenes and split with ffmpeg remux
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 bash | |
# Splits video to separate scenes files when full black frames are found in the video | |
# | |
# Author: Werner Robitza | |
# | |
# Forked from: https://gist.github.com/davidwebca/e26186b8f4c6795b19c043fffb6f9861 | |
# Inspired by https://gist.github.com/achesco/4dc2ebf13378a0a61fc26c7fe01f539e | |
# Who got inspired by https://stackoverflow.com/a/38205105 | |
set -e | |
file="" | |
out="./" | |
stripaudio="" | |
add=0.00 | |
trim=0.00 | |
dur=2.00 | |
ratio=0.98 | |
th=0.10 | |
usage () { | |
echo "Usage: $(basename $0) [[[-o folder] [-d black duration]] | [-h]] -f <input>" | |
echo | |
echo "Options:" | |
echo "-f, --file Input file" | |
echo "-o, --out Output files folder path, defaults to current directory" | |
echo "-d, --dur Duration for black detection in seconds. 0.05 default (practical single frame)" | |
echo "-r, --ratio ffmpeg pic_th : Set the threshold for considering a picture black. Default: $ratio" | |
echo "-th, --threshold ffmpeg pix_th : Set the threshold for considering a pixel black. Default: $th" | |
echo "-t, --trim Substracts to splitting timestamp in seconds. Default: 0" | |
echo "-a, --add Adds to splitting timestamp in seconds. Default: 0" | |
echo "-sa, --strip-audio Strip audio" | |
echo "-h, --help Display this help message" | |
echo | |
echo "Example: split.sh -d 0.5 -o /tmp/parts -f file.mp4" | |
echo "Splits file.mp4 file to scenes with black frames for more than 0.5 seconds" | |
echo "and saves output parts to /tmp/parts." | |
} | |
cleanup() { | |
rm -f ffout timestamps | |
} | |
trap 'cleanup' EXIT SIGINT SIGTERM | |
if [ "$1" = "" ]; then | |
usage | |
fi | |
while [ "$1" != "" ]; do | |
case $1 in | |
-f | --file ) | |
shift | |
file=$1 | |
;; | |
-d | --dur ) | |
shift | |
dur=$1 | |
;; | |
-r | --ratio ) | |
shift | |
ratio=$1 | |
;; | |
-th | --threshold ) | |
shift | |
th=$1 | |
;; | |
-o | --out ) | |
shift | |
out=$1 | |
;; | |
-t | --trim ) | |
shift | |
trim=$1 | |
;; | |
-a | --add ) | |
shift | |
add=$1 | |
;; | |
-sa | --strip-audio ) | |
stripaudio="-an" | |
;; | |
-h | --help ) | |
usage | |
exit | |
;; | |
* ) | |
usage | |
exit 1 | |
esac | |
shift | |
done | |
cut_part () { | |
printf -v fileout "$out/%04d_%s" "$2" "$filename" | |
if [[ "$3" != "" ]]; then | |
echo "Cutting from $1 for $3 seconds, writing to $fileout ..." | |
ffmpeg -nostdin -y -loglevel error -hide_banner -i "$file" -ss "$1" -t "$3" "$fileout" | |
else | |
echo "Cutting from $1 until end, writing to $fileout ..." | |
ffmpeg -nostdin -y -loglevel error -hide_banner -i "$file" -ss "$1" "$fileout" | |
fi | |
} | |
cd "$(dirname "$0")" || exit 1 | |
filename=$(basename "$file") | |
mkdir -p "$out" | |
timefrom=0 | |
i=1 | |
echo "Running blackdetect filter ..." | |
ffmpeg -i "$file" -vf "blackdetect=d=$dur:pic_th=$ratio:pix_th=$th" -f null - 2> ffout | |
black_start=( $(grep blackdetect ffout | grep black_start:[0-9.]* -o | grep "[0-9]*(\.[0-9]*)?" -oE) ) | |
black_duration=( $(grep blackdetect ffout | grep black_duration:[0-9.]* -o | grep "[0-9]*(\.[0-9]*)?" -oE) ) | |
> timestamps | |
for ii in "${!black_start[@]}"; do | |
half=$(bc -l <<< "${black_duration[$ii]}/2") | |
middletime=$(bc -l <<< "${black_start[$ii]} + $half") | |
echo "$middletime" | LC_ALL=en_US.UTF-8 awk '{printf "%f", $0}' >> timestamps | |
echo "" >> timestamps | |
done | |
echo "Found the following timestamps: " | |
echo | |
cat timestamps | |
echo | |
while read -r timestamp; do | |
duration=$(bc -l <<< "$timestamp-$timefrom+$add-$trim" | LC_ALL=en_US.UTF-8 awk '{printf "%f", $0}') | |
cut_part "$timefrom" "$i" "$duration" | |
timefrom=$(bc -l <<< "$timestamp+$add-$trim" | LC_ALL=en_US.UTF-8 awk '{printf "%f", $0}') | |
i=$((i+1)) | |
done < timestamps | |
if [[ "$timefrom" != 0 ]]; then | |
cut_part "$timefrom" "$i" | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment