aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Khirnov <anton@khirnov.net>2023-05-21 22:18:57 +0200
committerAnton Khirnov <anton@khirnov.net>2023-05-31 16:15:47 +0200
commitdc5864a00c7a7ebab3cc478e6abcadc231a68433 (patch)
treefb3add422f4133dfd003213e86edd8f9192a157d
parenta1061d4bdcbfb866011c18e787ec334ae48f2820 (diff)
downloadffmpeg-dc5864a00c7a7ebab3cc478e6abcadc231a68433.tar.gz
fftools/ffmpeg_filter: create Input/OutputFilters together with FilterGraph
This way the list of filtergraph inputs/outputs is always known after FilterGraph creation. This will allow treating simple and complex filtergraphs in a more uniform manner.
-rw-r--r--fftools/ffmpeg_filter.c157
1 files changed, 74 insertions, 83 deletions
diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index 5169a3ca82..d74eeef52a 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -62,6 +62,10 @@ typedef struct InputFilterPriv {
// used to hold submitted input
AVFrame *frame;
+ /* for filters that are not yet bound to an input stream,
+ * this stores the input linklabel, if any */
+ uint8_t *linklabel;
+
// filter data type
enum AVMediaType type;
// source data type: AVMEDIA_TYPE_SUBTITLE for sub2video,
@@ -456,8 +460,6 @@ static int ifilter_bind_ist(InputFilter *ifilter, InputStream *ist)
ifp->ist = ist;
ifp->type_src = ist->st->codecpar->codec_type;
- ifp->type = ifp->type_src == AVMEDIA_TYPE_SUBTITLE ?
- AVMEDIA_TYPE_VIDEO : ifp->type_src;
return 0;
}
@@ -505,7 +507,7 @@ void fg_free(FilterGraph **pfg)
av_frame_free(&frame);
av_fifo_freep2(&ifp->frame_queue);
}
- if (ist->sub2video.sub_queue) {
+ if (ist && ist->sub2video.sub_queue) {
AVSubtitle sub;
while (av_fifo_read(ist->sub2video.sub_queue, &sub, 1) >= 0)
avsubtitle_free(&sub);
@@ -517,6 +519,7 @@ void fg_free(FilterGraph **pfg)
av_frame_free(&ifp->frame);
av_buffer_unref(&ifp->hw_frames_ctx);
+ av_freep(&ifp->linklabel);
av_freep(&ifilter->name);
av_freep(&fg->inputs[j]);
}
@@ -542,6 +545,10 @@ FilterGraph *fg_create(char *graph_desc)
FilterGraphPriv *fgp = allocate_array_elem(&filtergraphs, sizeof(*fgp), &nb_filtergraphs);
FilterGraph *fg = &fgp->fg;
+ AVFilterInOut *inputs, *outputs;
+ AVFilterGraph *graph;
+ int ret = 0;
+
fg->index = nb_filtergraphs - 1;
fgp->graph_desc = graph_desc;
@@ -549,6 +556,48 @@ FilterGraph *fg_create(char *graph_desc)
if (!fgp->frame)
report_and_exit(AVERROR(ENOMEM));
+ /* this graph is only used for determining the kinds of inputs
+ * and outputs we have, and is discarded on exit from this function */
+ graph = avfilter_graph_alloc();
+ if (!graph)
+ report_and_exit(AVERROR(ENOMEM));
+ graph->nb_threads = 1;
+
+ ret = graph_parse(graph, fgp->graph_desc, &inputs, &outputs, NULL);
+ if (ret < 0)
+ goto fail;
+
+ for (AVFilterInOut *cur = inputs; cur; cur = cur->next) {
+ InputFilter *const ifilter = ifilter_alloc(fg);
+ InputFilterPriv *ifp = ifp_from_ifilter(ifilter);
+
+ ifp->linklabel = cur->name;
+ cur->name = NULL;
+
+ ifp->type = avfilter_pad_get_type(cur->filter_ctx->input_pads,
+ cur->pad_idx);
+ ifilter->name = describe_filter_link(fg, cur, 1);
+ }
+
+ for (AVFilterInOut *cur = outputs; cur; cur = cur->next) {
+ OutputFilter *const ofilter = ofilter_alloc(fg);
+
+ ofilter->linklabel = cur->name;
+ cur->name = NULL;
+
+ ofilter->type = avfilter_pad_get_type(cur->filter_ctx->output_pads,
+ cur->pad_idx);
+ ofilter->name = describe_filter_link(fg, cur, 0);
+ }
+
+fail:
+ avfilter_inout_free(&inputs);
+ avfilter_inout_free(&outputs);
+ avfilter_graph_free(&graph);
+
+ if (ret < 0)
+ report_and_exit(ret);
+
return fg;
}
@@ -557,8 +606,6 @@ int init_simple_filtergraph(InputStream *ist, OutputStream *ost,
{
FilterGraph *fg;
FilterGraphPriv *fgp;
- OutputFilter *ofilter;
- InputFilter *ifilter;
int ret;
fg = fg_create(graph_desc);
@@ -568,26 +615,32 @@ int init_simple_filtergraph(InputStream *ist, OutputStream *ost,
fgp->is_simple = 1;
- ofilter = ofilter_alloc(fg);
- ofilter->ost = ost;
+ if (fg->nb_inputs != 1 || fg->nb_outputs != 1) {
+ av_log(NULL, AV_LOG_ERROR, "Simple filtergraph '%s' was expected "
+ "to have exactly 1 input and 1 output. "
+ "However, it had %d input(s) and %d output(s). Please adjust, "
+ "or use a complex filtergraph (-filter_complex) instead.\n",
+ graph_desc, fg->nb_inputs, fg->nb_outputs);
+ return AVERROR(EINVAL);
+ }
- ost->filter = ofilter;
+ fg->outputs[0]->ost = ost;
- ifilter = ifilter_alloc(fg);
+ ost->filter = fg->outputs[0];
- ret = ifilter_bind_ist(ifilter, ist);
+ ret = ifilter_bind_ist(fg->inputs[0], ist);
if (ret < 0)
return ret;
return 0;
}
-static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
+static void init_input_filter(FilterGraph *fg, InputFilter *ifilter)
{
FilterGraphPriv *fgp = fgp_from_fg(fg);
+ InputFilterPriv *ifp = ifp_from_ifilter(ifilter);
InputStream *ist = NULL;
- enum AVMediaType type = avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx);
- InputFilter *ifilter;
+ enum AVMediaType type = ifp->type;
int i, ret;
// TODO: support other filter types
@@ -597,11 +650,11 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
exit_program(1);
}
- if (in->name) {
+ if (ifp->linklabel) {
AVFormatContext *s;
AVStream *st = NULL;
char *p;
- int file_idx = strtol(in->name, &p, 0);
+ int file_idx = strtol(ifp->linklabel, &p, 0);
if (file_idx < 0 || file_idx >= nb_input_files) {
av_log(NULL, AV_LOG_FATAL, "Invalid file index %d in filtergraph description %s.\n",
@@ -631,63 +684,27 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
ist = ist_find_unused(type);
if (!ist) {
av_log(NULL, AV_LOG_FATAL, "Cannot find a matching stream for "
- "unlabeled input pad %d on filter %s\n", in->pad_idx,
- in->filter_ctx->name);
+ "unlabeled input pad %s\n", ifilter->name);
exit_program(1);
}
}
av_assert0(ist);
- ifilter = ifilter_alloc(fg);
- ifilter->name = describe_filter_link(fg, in, 1);
-
ret = ifilter_bind_ist(ifilter, ist);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR,
"Error binding an input stream to complex filtergraph input %s.\n",
- in->name ? in->name : "");
+ ifilter->name);
exit_program(1);
}
}
int init_complex_filtergraph(FilterGraph *fg)
{
- FilterGraphPriv *fgp = fgp_from_fg(fg);
- AVFilterInOut *inputs, *outputs, *cur;
- AVFilterGraph *graph;
- int ret = 0;
-
- /* this graph is only used for determining the kinds of inputs
- * and outputs we have, and is discarded on exit from this function */
- graph = avfilter_graph_alloc();
- if (!graph)
- return AVERROR(ENOMEM);
- graph->nb_threads = 1;
-
- ret = graph_parse(graph, fgp->graph_desc, &inputs, &outputs, NULL);
- if (ret < 0)
- goto fail;
-
- for (cur = inputs; cur; cur = cur->next)
- init_input_filter(fg, cur);
-
- for (cur = outputs; cur;) {
- OutputFilter *const ofilter = ofilter_alloc(fg);
-
- ofilter->linklabel = cur->name;
- cur->name = NULL;
-
- ofilter->type = avfilter_pad_get_type(cur->filter_ctx->output_pads,
- cur->pad_idx);
- ofilter->name = describe_filter_link(fg, cur, 0);
- cur = cur->next;
- }
-
-fail:
- avfilter_inout_free(&inputs);
- avfilter_inout_free(&outputs);
- avfilter_graph_free(&graph);
- return ret;
+ // bind filtergraph inputs to input streams
+ for (int i = 0; i < fg->nb_inputs; i++)
+ init_input_filter(fg, fg->inputs[i]);
+ return 0;
}
static int insert_trim(int64_t start_time, int64_t duration,
@@ -1324,32 +1341,6 @@ int configure_filtergraph(FilterGraph *fg)
if ((ret = graph_parse(fg->graph, graph_desc, &inputs, &outputs, hw_device)) < 0)
goto fail;
- if (simple && (!inputs || inputs->next || !outputs || outputs->next)) {
- const char *num_inputs;
- const char *num_outputs;
- if (!outputs) {
- num_outputs = "0";
- } else if (outputs->next) {
- num_outputs = ">1";
- } else {
- num_outputs = "1";
- }
- if (!inputs) {
- num_inputs = "0";
- } else if (inputs->next) {
- num_inputs = ">1";
- } else {
- num_inputs = "1";
- }
- av_log(NULL, AV_LOG_ERROR, "Simple filtergraph '%s' was expected "
- "to have exactly 1 input and 1 output."
- " However, it had %s input(s) and %s output(s)."
- " Please adjust, or use a complex filtergraph (-filter_complex) instead.\n",
- graph_desc, num_inputs, num_outputs);
- ret = AVERROR(EINVAL);
- goto fail;
- }
-
for (cur = inputs, i = 0; cur; cur = cur->next, i++)
if ((ret = configure_input_filter(fg, fg->inputs[i], cur)) < 0) {
avfilter_inout_free(&inputs);