jonny
jonny

Reputation: 3098

Bash script for splitting video using ffmpeg outputs wrong video lengths

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

Answers (1)

Cosmin Stejerean
Cosmin Stejerean

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

Related Questions