-
-
Save davidwebca/e26186b8f4c6795b19c043fffb6f9861 to your computer and use it in GitHub Desktop.
# Splits video to separate scenes files when full black frames are found in the video | |
# Inspired by https://gist.github.com/achesco/4dc2ebf13378a0a61fc26c7fe01f539e | |
# Who got inspired by https://stackoverflow.com/a/38205105 | |
#!/bin/bash | |
file="" | |
out="./" | |
dur=0.05 | |
stripaudio="" | |
ratio=1.00 | |
th=0.05 | |
add=0.00 | |
trim=0.00 | |
usage () { | |
echo "Usage: $(basename $0) [[[-o folder] [-d black duration]] | [-h]] -f file.mp4" | |
echo | |
echo "Options:" | |
echo "-f, --file Input file" | |
echo "-o, --out Outpup files folder path, default" | |
echo " to current folder" | |
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. 1.00 default" | |
echo "-th, --threshold ffmpeg pix_th : Set the threshold for considering a pixel black. 0.00 default." | |
echo "-t, --trim Substracts to splitting timestamp in seconds. 0 default" | |
echo "-a, --add Adds to splitting timestamp in seconds. 0 default" | |
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 during more than 0.5 second" | |
echo "and saves output parts to /tmp/parts folder" | |
} | |
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 () { | |
duration_flag="" | |
if [[ "$3" != "" ]]; then | |
duration_flag="-t" | |
fi | |
echo "cutting from $1 during $3" | |
printf -v fileout "$out/%04d_%s" $2 $filename | |
ffmpeg -y -loglevel error -hide_banner -i $file -ss $1 $stripaudio $duration_flag $3 $fileout < /dev/null | |
} | |
filename=`basename $file` | |
mkdir -p $out | |
timefrom=0 | |
i=1 | |
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 | |
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=`expr $i + 1` | |
done < timestamps | |
if [[ "$timefrom" != 0 ]]; then | |
cut_part $timefrom $i | |
fi |
First of all, I would like to thank you for your script, it's really useful for my needs. I don't know how I would have managed what I need to do without you!
I had some accuracy problem with splitting : videos had about 5 seconds from the previous one to the next. Black scenes were detected properly but splitting was wrong. Weird.
Then I managed to resolve this problem by replacing :
ffmpeg -y -loglevel error -hide_banner -ss $1 -i $file -c:v copy -c:a copy $stripaudio $duration_flag $3 $fileout < /dev/null
By :
ffmpeg -y -loglevel error -hide_banner -i $file -ss $1 $stripaudio $duration_flag $3 $fileout < /dev/null
- I put
-i file
before the-ss
option. Apparently doing this ffmpeg does not work the same that way and is more accurate : https://stackoverflow.com/questions/45004159/ffmpeg-ss-and-t-for-cutting-mp3 - I removed
-c:v copy -c:a copy
as it seems it can create inaccuracy : https://superuser.com/questions/1129396/ffmpeg-ss-t-seeking-output-is-not-accurate-any-workarounds ; that way file is re-encoded so it's slower but it works as expected.
Thanks so much! I’ll give those edits a go in a project I have to do soon and I’ll update the gist after testing 👌
Hello ! That's a really nice script !
I just noticed one issue when using it: when you are getting the black_start and black_duration value, if the value is an integer grep will not catch it. (for example "7" is not recognized by grep "[0-9]*\.[0-9]*" -o
since there is no ".")
I just replaced those final grep by
grep "[0-9]*(\.[0-9]*)?" -oE
so the entire lines become
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) )
and it works just fine
Ooh nice catch, thanks!
Any way we are getting a Windows Command line version?
I can’t translate this bash script to a straight Windows version without learning about it first, but I used ffmpeg in Windows before, so that can give you a head start. The other thing I know is possible is to use WSL which allows to use bash as a sub system directly in Windows 10/11.
Thank you for doing this! I was getting some unexpected behavior until I realized that your script's default's are different from ffmpeg
's defaults for the blackdetect
filter. To match the defaults, you could set
dur=2.00
ratio=0.98
th=0.10
at the beginning of the script.
Nice, thanks for the input!
nice script!
This worked great for me. In my instance, was splitting a transfer from a VHS videotape, so had to use the ffmpeg blackdetect
defaults (see above).
That message just means you either didn’t install or didn’t install correctly ffmpeg. There you go. Here’s how to install it for Ubuntu : https://linuxize.com/post/how-to-install-ffmpeg-on-ubuntu-18-04/