DEV Community

Cover image for xfade chains fall over past about 100 clips, and the concat demuxer workaround has its own trap
LoCo Pro Wrestling LLC
LoCo Pro Wrestling LLC

Posted on

xfade chains fall over past about 100 clips, and the concat demuxer workaround has its own trap

If you are chaining many clips together with xfade and acrossfade transitions, and the render takes far longer than the clip count and durations would suggest, you have hit a known scaling wall, not a misconfigured filter.

xfade and acrossfade each cross-fade exactly two streams. Chaining N clips means N-1 xfade calls piped through intermediate labels, all inside one filter_complex graph. That graph's size grows with clip count, and past roughly a hundred clips it can sit for a very long time before producing useful output.

Switching to the concat demuxer to avoid the slow filter graph fixes the speed, but introduces a second, different bug: without explicit stream selectors, the concat demuxer can emit non-monotonic DTS warnings, and the final file can end up with video and audio streams of visibly different declared duration.

The fix, for a large number of clips:

  1. Render each selected clip to its own normalized clip with fresh timestamps first (matching resolution, pixel format, framerate, SAR, timebase).
  2. Concatenate those staged clips with the concat demuxer using -c copy, no re-encode needed since they are already normalized.
  3. If you use the concat demuxer's stream selectors, pair concatdec_select for video with aselect=concatdec_select for audio. Using one without the other is exactly what produces the early-ending audio stream.
  4. Treat any render as suspect if ffprobe shows video and audio durations disagree by more than a couple seconds, that is the specific tell for this bug.

If you actually need crossfade transitions rather than hard cuts at scale, keep xfade and acrossfade chains to a smaller clip count per graph (stage sub-groups, transition within each group, then hard-concat the groups).

One more thing worth knowing: a render can hang rather than fail outright. ffprobe shows the same "moov atom not found" for both a hung process and a genuinely failed one, so check whether the ffmpeg process is still alive and still holding the output file open before assuming it crashed.

Full writeup: github.com/locoprowrestling/ffmpeg-tricks

Top comments (0)