Opened 6 months ago

Last modified 6 months ago

#10550 new defect

complex_filtergraph (trim, concat) memory leak

Reported by: Kurt Owned by:
Priority: normal Component: avfilter
Version: git-master Keywords: filter_complex trim memleak
Cc: Kurt Blocked By:
Blocking: Reproduced by developer: no
Analyzed by developer: no


Summary of the bug:
ffmpeg runs out of memory quickly when fed a complex_filtergraph with several trim and concat commands.

More precisely:

  • The filtergraph looks like: [0:video]trim=start=st1:end=en1,setpts=PTS-STARTPTS[v1];[0:video]trim=start=st2:end=en2,setpts=PTS=STARTPTS[v2];[v1][v2]concat[vout]

to create a video from several pieces.
ffmpeg runs fine before st1 and still until en1. After en1, it starts leaking memory at an amazing rate until it runs OOM.

How to reproduce:

% ffmpeg -i input.ts -filter_complex "[0:2]trim=start=200:end=220,setpts=PTS-STARTPTS[v1];[0:2]trim=start=400:end=440,setpts=PTS-STARTPTS[v2];[v1][v2]concat[v3];[0:2]trim=start=1440:end=1500,setpts=PTS-STARTPTS[v4];[v3][v4]concat[vout]" -map [vout]  -c:v libx264 output.mkv

ffmpeg version N-111899-g4489615e8f Copyright (c) 2000-2023 the FFmpeg developers

built with gcc 12.3.1 (GCC) 20230702
configuration: --enable-gpl --enable-gnutls --enable-libass --enable-libbluray --enable-libcdio --enable-libdav1d --enable-libopus --enable-libpulse --enable-libmp3lame --enable-librav1e --enable-librtmp --enable-libspeex --enable-libtwolame --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libx265 --enable-opengl --enable-libdrm --enable-libsvtav1 --enable-libzvbi --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-shared --libdir=/usr/local/lib64

Change History (3)

comment:1 by Kurt, 6 months ago

I have spent some time trying to debug and fix this without luck.
trim_filter_frame() gets called for the trim that starts at 200s, correctly dropping (and av_frame_free'ing) frames till pts=90000*200, then passing on frames till 220s, then setting the eof status and never being called again. (The code path in trim_filter_frame() that would drop frames after 220s is never called.)
No reason to leak memory as far as I can see ...

Looking at the filtergraph with the debugger, I see
[0] ff_vf_trim(200s-220s) "Parsed_trim_0"
[1] ff_vf_setpts "Parsed_setpts_1"
[2] ff_vf_trim(400-440s) "Parsed_trim_2"
[3] ff_vf_setpts "Parsed_setpts_3"
[4] ff_avf_concat "Parsed_concat_4"
[5] ff_vf_trim(1440-1500s) "Parsed_trim_5"
[6] ff_vf_setpts "Parsed_setpts_6"
[7] ff_avf_concat "Parsed_concat_7"
There's more which does not directly stem from my passed filtergraph:
[8] ff_vsrc_buffer "graph 0 input from stream 0:2"
[9] ff_vf_trim(0-AV_NOPTS_VAL) "trim_in_0_2"
[10] ff_vsrc_buffer "graph 0 input from stream 0:2"
[11] ff_vf_trim(0-AV_NOPTS_VAL) "trim_in_0_2"
[12] ff_vsrc_buffer "graph 0 input from stream 0:2"
[13] ff_vf_trim(0-AV_NOPTS_VAL) "trim_in_0_2"
[14] ff_vsink_buffer "out_0_0"
[15] ff_vf_format "format"

I have not yet spent a lot of time looking at filters 8 .. 15, but the existence of the trims there are surprising to me.
After [0] is in EOF (after 220s), [9]+[10] continue to run, but we may somehow miss an EOF check that frees the frames that go nowhere?

comment:2 by Elon Musk, 6 months ago

Known issue,

Use instead:

ffmpeg -i input.ts -i input.ts -filter_complex "[0:2]trim=start=200:end=220,setpts=PTS-STARTPTS[v1];[1:2]trim=start=400:end=440,setpts=PTS-STARTPTS[v2];[v1][v2]concat[v3];[0:2]trim=start=1440:end=1500,setpts=PTS-STARTPTS[v4];[v3][v4]concat[vout]" -map [vout] -c:v libx264 output.mkv

comment:3 by Kurt, 6 months ago

The trick works. Almost -- I need to add -i 3 times and use 0:2 1:2 and 2:2 to make it fully work.
When you say "Known issue": Is there a bug report where this is tracked?

Note: See TracTickets for help on using tickets.