mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2025-12-05 14:30:00 +01:00
fftools/ffmpeg_filter: close all no-longer needed inputs
Currently, the thread loop of ffmpeg_filter essentially works like this:
while (1) {
frame, idx = get_from_decoder();
err = send_to_filter_graph(frame);
if (err) { // i.e. EOF
close_input(idx);
continue;
}
while (filtered_frame = get_filtered_frame())
send_to_encoder(filtered_frame);
}
The exact details are not 100% correct since the actual control flow is a bit
more complicated as a result of the scheduler, but this is the general flow.
Notably, this leaves the possibility of leaving a no-longer-needed input
permanently open if the filter graph starts producing infinite frames (during
the second loop) *after* it finishes reading from an input, e.g. in a filter
graph like -af atrim,apad.
This patch avoids this issue by always querying the status of all filter graph
inputs and explicitly closing any that were closed downstream; after each round
of reading output frames. As a result, information about the filtergraph being
closed can now propagate back upstream, even if the filter is no longer
requesting any input frames (i.e. input_idx == fg->nb_inputs).
Fixes: https://trac.ffmpeg.org/ticket/11061
See-Also: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20457#issuecomment-6208
This commit is contained in:
@@ -2616,6 +2616,16 @@ finish:
|
||||
fps->dropped_keyframe |= fps->last_dropped && (frame->flags & AV_FRAME_FLAG_KEY);
|
||||
}
|
||||
|
||||
static void close_input(InputFilterPriv *ifp)
|
||||
{
|
||||
FilterGraphPriv *fgp = fgp_from_fg(ifp->ifilter.graph);
|
||||
|
||||
if (!ifp->eof) {
|
||||
sch_filter_receive_finish(fgp->sch, fgp->sch_idx, ifp->ifilter.index);
|
||||
ifp->eof = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int close_output(OutputFilterPriv *ofp, FilterGraphThread *fgt)
|
||||
{
|
||||
FilterGraphPriv *fgp = fgp_from_fg(ofp->ofilter.graph);
|
||||
@@ -3343,7 +3353,7 @@ static int filter_thread(void *arg)
|
||||
if (ret == AVERROR_EOF) {
|
||||
av_log(fg, AV_LOG_VERBOSE, "Input %u no longer accepts new data\n",
|
||||
input_idx);
|
||||
sch_filter_receive_finish(fgp->sch, fgp->sch_idx, input_idx);
|
||||
close_input(ifp);
|
||||
continue;
|
||||
}
|
||||
if (ret < 0)
|
||||
@@ -3362,6 +3372,13 @@ read_frames:
|
||||
av_err2str(ret));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
// ensure all inputs no longer accepting data are closed
|
||||
for (int i = 0; fgt.graph && i < fg->nb_inputs; i++) {
|
||||
InputFilterPriv *ifp = ifp_from_ifilter(fg->inputs[i]);
|
||||
if (av_buffersrc_get_status(ifp->ifilter.filter))
|
||||
close_input(ifp);
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < fg->nb_outputs; i++) {
|
||||
|
||||
Reference in New Issue
Block a user