diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c index 2dae6400c8..c1c8eeb2d8 100644 --- a/fftools/ffmpeg_filter.c +++ b/fftools/ffmpeg_filter.c @@ -2878,6 +2878,7 @@ static const char *unknown_if_null(const char *str) static int send_frame(FilterGraph *fg, FilterGraphThread *fgt, InputFilter *ifilter, AVFrame *frame) { + FilterGraphPriv *fgp = fgp_from_fg(fg); InputFilterPriv *ifp = ifp_from_ifilter(ifilter); FrameData *fd; AVFrameSideData *sd; @@ -2986,6 +2987,11 @@ static int send_frame(FilterGraph *fg, FilterGraphThread *fgt, if (reason.len > 1) reason.str[reason.len - 2] = '\0'; // remove last comma av_log(fg, AV_LOG_INFO, "Reconfiguring filter graph%s%s\n", reason.len ? " because " : "", reason.str); + } else { + /* Choke all input to avoid buffering excessive frames while the + * initial filter graph is being configured, and before we have a + * preferred input */ + sch_filter_choke_inputs(fgp->sch, fgp->sch_idx); } ret = configure_filtergraph(fg, fgt); diff --git a/fftools/ffmpeg_sched.c b/fftools/ffmpeg_sched.c index 3c5cffa594..039cd1c9aa 100644 --- a/fftools/ffmpeg_sched.c +++ b/fftools/ffmpeg_sched.c @@ -2510,6 +2510,18 @@ int sch_filter_command(Scheduler *sch, unsigned fg_idx, AVFrame *frame) return send_to_filter(sch, fg, fg->nb_inputs, frame); } +void sch_filter_choke_inputs(Scheduler *sch, unsigned fg_idx) +{ + SchFilterGraph *fg; + av_assert0(fg_idx < sch->nb_filters); + fg = &sch->filters[fg_idx]; + + pthread_mutex_lock(&sch->schedule_lock); + fg->best_input = fg->nb_inputs; + schedule_update_locked(sch); + pthread_mutex_unlock(&sch->schedule_lock); +} + static int task_cleanup(Scheduler *sch, SchedulerNode node) { switch (node.type) { diff --git a/fftools/ffmpeg_sched.h b/fftools/ffmpeg_sched.h index 24ad37b778..0c01f558e4 100644 --- a/fftools/ffmpeg_sched.h +++ b/fftools/ffmpeg_sched.h @@ -443,6 +443,13 @@ int sch_filter_send(Scheduler *sch, unsigned fg_idx, unsigned out_idx, int sch_filter_command(Scheduler *sch, unsigned fg_idx, struct AVFrame *frame); +/** + * Called by filtergraph tasks to choke all filter inputs, preventing them from + * receiving more frames until woken up again by the scheduler. Used during + * initial graph configuration to avoid unnecessary buffering. + */ +void sch_filter_choke_inputs(Scheduler *sch, unsigned fg_idx); + /** * Called by encoder tasks to obtain frames for encoding. Will wait for a frame * to become available and return it in frame.