Fix FFmpeg Concat Filter Shortest Option Not Working

When concatenating multimedia streams using FFmpeg’s concat filter, the -shortest command-line option frequently fails to terminate the output at the end of the shortest stream, resulting in frozen frames, bloated file sizes, or indefinite encoding loops. This article explains the underlying causes of this synchronization failure within FFmpeg's filtergraph architecture and outlines reliable methods to properly terminate your encoded media.

Why -shortest Fails with the Concat Filter

The -shortest option tells the output muxer to stop writing once the shortest input stream reaches its end-of-file (EOF). When paired with the concat video/audio filter, several issues prevent this mechanism from working as expected:

  1. Filtergraph Abstraction: The concat filter operates inside filter_complex. The output muxer does not monitor the original source files directly; it monitors the synthetic stream generated by the filter. If the filter does not propagate EOF properly or keeps an internal buffer open, the muxer never receives the termination signal.
  2. Muxer Interleaving Buffers: FFmpeg buffers packets to ensure audio and video remain interleaved. If an audio stream finishes but the video concat filter still holds unrendered or buffered frames, the muxer may wait indefinitely for stream closure or overshoot the actual duration.
  3. Timestamp Inconsistencies: Concatenating segments with differing frame rates, missing timebases, or non-zero start Presentation Timestamps (PTS) confuses the internal clock. If the audio and video timestamps diverge, -shortest fails to determine which stream actually reached the target end point.

How to Fix the Issue

1. Add -fflags +shortest and Disable Interleave Delta

Modern versions of FFmpeg include an extended flag to enforce stricter EOF checks on the shortest stream. Combining this with -max_interleave_delta 0 forces the muxer to stop buffering once any stream terminates.

ffmpeg -f concat -safe 0 -i list.txt -i background.mp3 \
  -filter_complex "[0:v][0:a]concat=n=2:v=1:a=1[v][a]" \
  -map "[v]" -map "[a]" \
  -fflags +shortest -max_interleave_delta 0 -shortest output.mp4

2. Reset Presentation Timestamps (PTS) Before Concatenating

Mismatched timestamps across segments frequently cause the concat filter to miscalculate the true duration. Reset timestamps on each segment before passing them to concat:

ffmpeg -i input1.mp4 -i input2.mp4 -i audio.mp3 \
  -filter_complex "\
    [0:v]setpts=PTS-STARTPTS[v0]; \
    [0:a]asetpts=PTS-STARTPTS[a0]; \
    [1:v]setpts=PTS-STARTPTS[1]; \
    [1:a]asetpts=PTS-STARTPTS[a1]; \
    [v0][a0][v1][a1]concat=n=2:v=1:a=1[v][a]" \
  -map "[v]" -map "[a]" -shortest output.mp4

3. Use trim and atrim Filters Instead of -shortest

If you know the expected duration of your segments, bypass -shortest entirely. Enforce termination directly inside the filtergraph using the trim and atrim filters:

ffmpeg -i video1.mp4 -i video2.mp4 -i audio.mp3 \
  -filter_complex "\
    [0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[v][a]; \
    [2:a]atrim=0:60,asetpts=PTS-STARTPTS[music]" \
  -map "[v]" -map "[music]" -t 60 output.mp4

4. Switch to the Concat Demuxer

If all input files share the identical codec, resolution, and audio sample rate, bypass the concat filter entirely by using the concat demuxer. The demuxer operates at the container level where -shortest handles EOF signaling much more reliably:

ffmpeg -f concat -safe 0 -i filelist.txt -i audio.mp3 \
  -c:v copy -c:a aac -shortest output.mp4