The issue of progressively increasing segment lengths is due to how ffmpeg handles segmenting with certain formats. By default, ffmpeg tries to avoid cutting streams mid-frame or mid-packet, which can cause segments to grow slightly longer than expected.
To strictly enforce a fixed segment duration of 10 seconds for all files, you can use the -segment_time flag along with the -reset_timestamps 1 option and specify the -force_key_frames flag for keyframe alignment. The following command ensures that every segment is exactly 10 seconds long:
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset fast -c:a aac -b:a 128k \
-force_key_frames "expr:gte(t,n_forced*10)" -f segment -segment_time 10 \
-reset_timestamps 1 -segment_format_options movflags=+faststart output_%03d.mp4
-segment_time 10: Ensures each segment is 10 seconds long.
-reset_timestamps 1: Resets timestamps for each segment to start at 0, avoiding progressive duration increases.
-force_key_frames "expr:gte(t,n_forced*10)": Forces keyframes at exact 10-second intervals for precise splitting.
movflags=+faststart: Optimises files for streaming by moving metadata to the start.
If you wish to avoid re-encoding entirely and only copy streams, use this alternative:
ffmpeg -i input.mp4 -c copy -map 0 -f segment -segment_time 10 \
-reset_timestamps 1 output_%03d.mp4
However, without re-encoding, the segments may still deviate slightly in duration due to keyframe alignment.
If none of the above meets your needs, you can resort to splitting the video with frame accuracy using ffmpeg’s trim filter. However, this requires re-encoding:
ffmpeg -i input.mp4 -vf "select='between(t,0,10)'" -c:v libx264 -crf 23 -preset fast \
-c:a aac -b:a 128k output_000.mp4
Repeat this with t values for each 10-second interval.
Let me know which approach works best for you!