Skip to content

Instantly share code, notes, and snippets.

@vi
Last active February 23, 2024 13:18
Show Gist options
  • Star 37 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save vi/2fe3eb63383fcfdad7483ac7c97e9deb to your computer and use it in GitHub Desktop.
Save vi/2fe3eb63383fcfdad7483ac7c97e9deb to your computer and use it in GitHub Desktop.
Using FFmpeg to split multimedia file into parts based on audio volume level
#!/bin/bash
IN=$1
OUT=$2
true ${SD_PARAMS:="-55dB:d=0.3"};
true ${MIN_FRAGMENT_DURATION:="20"};
export MIN_FRAGMENT_DURATION
if [ -z "$OUT" ]; then
echo "Usage: split_by_silence.sh input_media.mp4 output_template_%03d.mkv"
echo "Depends on FFmpeg, Bash, Awk, Perl 5. Not tested on Mac or Windows."
echo ""
echo "Environment variables (with their current values):"
echo " SD_PARAMS=$SD_PARAMS Parameters for FFmpeg's silencedetect filter: noise tolerance and minimal silence duration"
echo " MIN_FRAGMENT_DURATION=$MIN_FRAGMENT_DURATION Minimal fragment duration"
exit 1
fi
echo "Determining split points..." >& 2
SPLITS=$(
ffmpeg -v warning -i "$IN" -af silencedetect="$SD_PARAMS",ametadata=mode=print:file=-:key=lavfi.silence_start -vn -sn -f s16le -y /dev/null \
| grep lavfi.silence_start= \
| cut -f 2-2 -d= \
| perl -ne '
our $prev;
INIT { $prev = 0.0; }
chomp;
if (($_ - $prev) >= $ENV{MIN_FRAGMENT_DURATION}) {
print "$_,";
$prev = $_;
}
' \
| sed 's!,$!!'
)
echo "Splitting points are $SPLITS"
ffmpeg -v warning -i "$IN" -c copy -map 0 -f segment -segment_times "$SPLITS" "$OUT"
@vi
Copy link
Author

vi commented Apr 23, 2020

@denimboiz Do you know how to use command line in general? Are you starting scripts by double-clicking at their icon?

This script accepts requires command-line parameters. This means just simply starting it won't work.

Your options are:

  • Create a Windows shortcut for this script (if you are using Windows) and edit this shortcut to include command line parameters. There should be two of them and second one should include someting like %03d.
  • Modify the script, replacing $1 with a file path to you input video and $2 with path template for your output videos. Template is like file path, but with a %03d inside it, meaning the place for putting sequence numbers.
  • Learn how to you command line and start the script interactively in command prompt. This way you get error messages in case something goes wrong (e.g. not all required components are installed). The command should look like ./split_by_silence.sh my_video.mp4 my_outputs_videos_%03d.mp4.

@denimboiz
Copy link

@vi - firstly big thanks for helping!

UPDATE: I have managed to split the .mp4 or .mov files using this scripts however... when i split it only the first of the split videos actually plays, the others when i click on them are just a blank screen for different intervals. E.g. 000.mov works but 001,002,etc do not.
I have tried both .mp4 & .mov but neither working - any thoughts?

@vi
Copy link
Author

vi commented Apr 23, 2020

@denimboiz
Copy link

Yes, I've tried both version on that page and still getting the same issue - every output after the first is a black screen with no audio....

@vi
Copy link
Author

vi commented Apr 24, 2020

@denimbioz, Are those black screen files small? You can publish such file somewhere for analysis.

@denimboiz
Copy link

Appreciate your patience on this! Unfortunately i can only publish GIF, JPEG, JPG or PNG here. Not mp4 or mov - I have emailed you some examples of the outputs though. Let me know your thoughts.

Thank you!

@sadez
Copy link

sadez commented Nov 17, 2020

With some type of videos I get this message :
Could not write header for output file #0 (incorrect codec parameters ?): Invalid argument
Do you know what can be the cause ?

@vi
Copy link
Author

vi commented Nov 17, 2020

@sadez, Does simply remuxing the file with FFMpeg work?:

ffmpeg -i input_media.mp4 -c copy -y output.mkv

@sadez
Copy link

sadez commented Nov 17, 2020

Yeah it's work,
I find the problem, I used a video with no silence on it and it's generate no split points...
I added a condition to manage it :

if [ $SPLITS ]; then
    ffmpeg -v warning -i "$IN" -c copy -map 0 -reset_timestamps 1 -f segment -segment_times "$SPLITS" "$OUT"
else
    # do something else
fi

@abrefael
Copy link

abrefael commented Aug 1, 2021

Thank you Vitaly.
If anyone here is on M$ wndws they can use a vbscript I created:
https://github.com/abrefael/split_by_silence.vbs/blob/main/split_by_silence.vbs
Good luck.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment