Reputation: 3098
I have a video that's x
seconds long. I want to split that video up into equal segments, where each segment is no longer than a minute. To do that, I cobbled together a fairly simple bash script which uses ffmprobe
to get the duration of the video, find out how long each segment should be, and then iteratively split the video up using ffmpeg
:
INPUT_FILE=$1
INPUT_DURATION="$(./bin/ffprobe.exe -i "$INPUT_FILE" -show_entries format=duration -v quiet -of csv="p=0")"
NUM_SPLITS="$(perl -w -e "use POSIX; print ceil($INPUT_DURATION/60), qq{\n}")"
printf "\nVideo duration: $INPUT_DURATION; "
printf "Number of videos to output: $NUM_SPLITS; "
printf "Approximate length of each video: $(echo "$INPUT_DURATION" "$NUM_SPLITS" | awk '{print ($1 / $2)}')\n\n"
for i in `seq 1 "$NUM_SPLITS"`; do
START="$(echo "$INPUT_DURATION" "$NUM_SPLITS" "$i" | awk '{print (($1 / $2) * ($3 - 1))}')"
END="$(echo "$INPUT_DURATION" "$NUM_SPLITS" "$i" | awk '{print (($1 / $2) * $3)}')"
echo ./bin/ffmpeg.exe -v quiet -y -i "$INPUT_FILE" \
-vcodec copy -acodec copy -ss "$START" -t "$END" -sn test_${i}.mp4
./bin/ffmpeg.exe -v quiet -y -i "$INPUT_FILE" \
-vcodec copy -acodec copy -ss "$START" -t "$END" -sn test_${i}.mp4
done
printf "\ndone\n"
If I run that script on the 30MB / 02:50 duration Big Buck Bunny sample from here, the output of the program would suggest the videos should all be of equal length:
λ bash split.bash .\media\SampleVideo_1280x720_30mb.mp4
Video duration: 170.859000; Number of videos to output: 3; Approximate length of each video: 56.953
./bin/ffmpeg.exe -v quiet -y -i .\media\SampleVideo_1280x720_30mb.mp4 -vcodec copy -acodec copy -ss 0 -t 56.953 -sn test_1.mp4
./bin/ffmpeg.exe -v quiet -y -i .\media\SampleVideo_1280x720_30mb.mp4 -vcodec copy -acodec copy -ss 56.953 -t 113.906 -sn test_2.mp4
./bin/ffmpeg.exe -v quiet -y -i .\media\SampleVideo_1280x720_30mb.mp4 -vcodec copy -acodec copy -ss 113.906 -t 170.859 -sn test_3.mp4
done
As the duration of each partial video, i.e. the time between -ss
and -t
, are equal for each subsequent ffmpeg
command. But the durations I get are closer to:
test_1.mp4 = 00:56
test_2.mp4 = 01:53
test_3.mp4 = 00:56
Where the contents of each partial video overlap. What am I missing here?
Upvotes: 1
Views: 242
Reputation: 1398
It looks like you're using -t
, which is the duration to copy, but you're passing it the end position. Perhaps you meant to use -to
which is the end position? Or you could use -t
but you'll need to compute the duration from your start and end.
That said, there are better ways to split the video into segments of approximately equal length, you should look at the segment muxer.
In order to guarantee segments of a certain duration you will most likely also need to transcode the video and introduce keyframes at fixed intervals, otherwise your split will be on the nearest keyframe rather than the exact duration you want.
Upvotes: 1