1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2025-11-29 05:57:37 +02:00

fftools/ffmpeg_filter: allow removing filtergraphs that contain unbound outputs

Actual practical implementation of the previous commit.

Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
James Almer
2025-10-18 21:06:25 -03:00
parent cce85642c9
commit 9dcd25b7cd
2 changed files with 50 additions and 12 deletions

View File

@@ -403,6 +403,11 @@ typedef struct FilterGraph {
OutputFilter **outputs; OutputFilter **outputs;
int nb_outputs; int nb_outputs;
// true when the filtergraph is created internally for
// purposes like stream group merging. Meant to be freed
// if unbound.
int is_internal;
const char *graph_desc; const char *graph_desc;
struct AVBPrint graph_print_buf; struct AVBPrint graph_print_buf;
} FilterGraph; } FilterGraph;

View File

@@ -193,6 +193,8 @@ typedef struct OutputFilterPriv {
void *log_parent; void *log_parent;
char log_name[32]; char log_name[32];
int needed;
/* desired output stream properties */ /* desired output stream properties */
int format; int format;
int width, height; int width, height;
@@ -813,7 +815,7 @@ int ofilter_bind_enc(OutputFilter *ofilter, unsigned sched_idx_enc,
av_assert0(!opts->enc || av_assert0(!opts->enc ||
ofilter->type == opts->enc->type); ofilter->type == opts->enc->type);
ofilter->bound = 1; ofp->needed = ofilter->bound = 1;
av_freep(&ofilter->linklabel); av_freep(&ofilter->linklabel);
ofp->flags = opts->flags; ofp->flags = opts->flags;
@@ -924,7 +926,7 @@ static int ofilter_bind_ifilter(OutputFilter *ofilter, InputFilterPriv *ifp,
av_assert0(!ofilter->bound); av_assert0(!ofilter->bound);
av_assert0(ofilter->type == ifp->ifilter.type); av_assert0(ofilter->type == ifp->ifilter.type);
ofilter->bound = 1; ofp->needed = ofilter->bound = 1;
av_freep(&ofilter->linklabel); av_freep(&ofilter->linklabel);
ofilter->output_name = av_strdup(opts->name); ofilter->output_name = av_strdup(opts->name);
@@ -1264,7 +1266,7 @@ int fg_create_simple(FilterGraph **pfg,
return 0; return 0;
} }
static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter) static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter, int commit)
{ {
InputFilterPriv *ifp = ifp_from_ifilter(ifilter); InputFilterPriv *ifp = ifp_from_ifilter(ifilter);
InputStream *ist = NULL; InputStream *ist = NULL;
@@ -1315,15 +1317,20 @@ static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter)
if (!ofilter->bound && ofilter->linklabel && if (!ofilter->bound && ofilter->linklabel &&
!strcmp(ofilter->linklabel, ifilter->linklabel)) { !strcmp(ofilter->linklabel, ifilter->linklabel)) {
if (commit) {
av_log(fg, AV_LOG_VERBOSE, av_log(fg, AV_LOG_VERBOSE,
"Binding input with label '%s' to filtergraph output %d:%d\n", "Binding input with label '%s' to filtergraph output %d:%d\n",
ifilter->linklabel, i, j); ifilter->linklabel, i, j);
ret = ifilter_bind_fg(ifp, fg_src, j); ret = ifilter_bind_fg(ifp, fg_src, j);
if (ret < 0) if (ret < 0) {
av_log(fg, AV_LOG_ERROR, "Error binding filtergraph input %s\n", av_log(fg, AV_LOG_ERROR, "Error binding filtergraph input %s\n",
ifilter->linklabel); ifilter->linklabel);
return ret; return ret;
}
} else
ofp_from_ofilter(ofilter)->needed = 1;
return 0;
} }
} }
} }
@@ -1371,6 +1378,7 @@ static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter)
} }
ist = input_files[file_idx]->streams[st->index]; ist = input_files[file_idx]->streams[st->index];
if (commit)
av_log(fg, AV_LOG_VERBOSE, av_log(fg, AV_LOG_VERBOSE,
"Binding input with label '%s' to input stream %d:%d\n", "Binding input with label '%s' to input stream %d:%d\n",
ifilter->linklabel, ist->file->index, ist->index); ifilter->linklabel, ist->file->index, ist->index);
@@ -1384,12 +1392,14 @@ static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter)
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
if (commit)
av_log(fg, AV_LOG_VERBOSE, av_log(fg, AV_LOG_VERBOSE,
"Binding unlabeled input %d to input stream %d:%d\n", "Binding unlabeled input %d to input stream %d:%d\n",
ifilter->index, ist->file->index, ist->index); ifilter->index, ist->file->index, ist->index);
} }
av_assert0(ist); av_assert0(ist);
if (commit) {
ret = ifilter_bind_ist(ifilter, ist, &vs); ret = ifilter_bind_ist(ifilter, ist, &vs);
if (ret < 0) { if (ret < 0) {
av_log(fg, AV_LOG_ERROR, av_log(fg, AV_LOG_ERROR,
@@ -1397,11 +1407,12 @@ static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter)
ifilter->name); ifilter->name);
return ret; return ret;
} }
}
return 0; return 0;
} }
static int bind_inputs(FilterGraph *fg) static int bind_inputs(FilterGraph *fg, int commit)
{ {
// bind filtergraph inputs to input streams or other filtergraphs // bind filtergraph inputs to input streams or other filtergraphs
for (int i = 0; i < fg->nb_inputs; i++) { for (int i = 0; i < fg->nb_inputs; i++) {
@@ -1411,7 +1422,7 @@ static int bind_inputs(FilterGraph *fg)
if (ifp->bound) if (ifp->bound)
continue; continue;
ret = fg_complex_bind_input(fg, &ifp->ifilter); ret = fg_complex_bind_input(fg, &ifp->ifilter, commit);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
@@ -1424,27 +1435,49 @@ int fg_finalise_bindings(void)
int ret; int ret;
for (int i = 0; i < nb_filtergraphs; i++) { for (int i = 0; i < nb_filtergraphs; i++) {
ret = bind_inputs(filtergraphs[i]); ret = bind_inputs(filtergraphs[i], 0);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
// check that all outputs were bound // check that all outputs were bound
for (int i = 0; i < nb_filtergraphs; i++) { for (int i = nb_filtergraphs - 1; i >= 0; i--) {
FilterGraph *fg = filtergraphs[i]; FilterGraph *fg = filtergraphs[i];
FilterGraphPriv *fgp = fgp_from_fg(filtergraphs[i]);
for (int j = 0; j < fg->nb_outputs; j++) { for (int j = 0; j < fg->nb_outputs; j++) {
OutputFilter *output = fg->outputs[j]; OutputFilter *output = fg->outputs[j];
if (!output->bound) { if (!ofp_from_ofilter(output)->needed) {
av_log(fg, AV_LOG_FATAL, if (!fg->is_internal) {
"Filter '%s' has output %d (%s) unconnected\n", av_log(fg, AV_LOG_FATAL,
"Filter '%s' has output %d (%s) unconnected\n",
output->name, j,
output->linklabel ? (const char *)output->linklabel : "unlabeled");
return AVERROR(EINVAL);
}
av_log(fg, AV_LOG_DEBUG,
"Internal filter '%s' has output %d (%s) unconnected. Removing graph\n",
output->name, j, output->name, j,
output->linklabel ? (const char *)output->linklabel : "unlabeled"); output->linklabel ? (const char *)output->linklabel : "unlabeled");
return AVERROR(EINVAL); sch_remove_filtergraph(fgp->sch, fgp->sch_idx);
fg_free(&filtergraphs[i]);
nb_filtergraphs--;
if (nb_filtergraphs > 0)
memmove(&filtergraphs[i],
&filtergraphs[i + 1],
(nb_filtergraphs - i) * sizeof(*filtergraphs));
break;
} }
} }
} }
for (int i = 0; i < nb_filtergraphs; i++) {
ret = bind_inputs(filtergraphs[i], 1);
if (ret < 0)
return ret;
}
return 0; return 0;
} }