aboutsummaryrefslogtreecommitdiffstats
path: root/libavfilter/graphparser.c
diff options
context:
space:
mode:
authorAnton Khirnov <anton@khirnov.net>2012-03-21 07:46:56 +0100
committerAnton Khirnov <anton@khirnov.net>2012-04-14 09:25:46 +0200
commitd7bcc71dadea71d86a2b95a4f46aedd392f8b948 (patch)
treed9ceee7b910f008a59074bd17b93b81d6f0b8272 /libavfilter/graphparser.c
parent7ae7c41413beb601714a06b4fd18cdb4610b2eda (diff)
downloadffmpeg-d7bcc71dadea71d86a2b95a4f46aedd392f8b948.tar.gz
graphparser: add avfilter_graph_parse2().
Unlike avfilter_graph_parse(), it returns unlinked inputs and outputs to the caller, which allows parsing of graphs where inputs/outputs are not known in advance.
Diffstat (limited to 'libavfilter/graphparser.c')
-rw-r--r--libavfilter/graphparser.c136
1 files changed, 102 insertions, 34 deletions
diff --git a/libavfilter/graphparser.c b/libavfilter/graphparser.c
index 90f2936590..7a899a815c 100644
--- a/libavfilter/graphparser.c
+++ b/libavfilter/graphparser.c
@@ -184,13 +184,15 @@ static AVFilterInOut *extract_inout(const char *label, AVFilterInOut **links)
{
AVFilterInOut *ret;
- while (*links && strcmp((*links)->name, label))
+ while (*links && (!(*links)->name || strcmp((*links)->name, label)))
links = &((*links)->next);
ret = *links;
- if (ret)
+ if (ret) {
*links = ret->next;
+ ret->next = NULL;
+ }
return ret;
}
@@ -201,6 +203,18 @@ static void insert_inout(AVFilterInOut **inouts, AVFilterInOut *element)
*inouts = element;
}
+static void append_inout(AVFilterInOut **inouts, AVFilterInOut **element)
+{
+ while (*inouts && (*inouts)->next)
+ inouts = &((*inouts)->next);
+
+ if (!*inouts)
+ *inouts = *element;
+ else
+ (*inouts)->next = *element;
+ *element = NULL;
+}
+
static int link_filter_inouts(AVFilterContext *filt_ctx,
AVFilterInOut **curr_inputs,
AVFilterInOut **open_inputs, void *log_ctx)
@@ -209,14 +223,11 @@ static int link_filter_inouts(AVFilterContext *filt_ctx,
while (pad--) {
AVFilterInOut *p = *curr_inputs;
- if (!p) {
- av_log(log_ctx, AV_LOG_ERROR,
- "Not enough inputs specified for the \"%s\" filter.\n",
- filt_ctx->filter->name);
- return AVERROR(EINVAL);
- }
- *curr_inputs = (*curr_inputs)->next;
+ if (p)
+ *curr_inputs = (*curr_inputs)->next;
+ else if (!(p = av_mallocz(sizeof(*p))))
+ return AVERROR(ENOMEM);
if (p->filter_ctx) {
if ((ret = link_filter(p->filter_ctx, p->pad_idx, filt_ctx, pad, log_ctx)) < 0)
@@ -329,18 +340,22 @@ static int parse_outputs(const char **buf, AVFilterInOut **curr_inputs,
return pad;
}
-int avfilter_graph_parse(AVFilterGraph *graph, const char *filters,
- AVFilterInOut *open_inputs,
- AVFilterInOut *open_outputs, void *log_ctx)
+#if FF_API_GRAPH_AVCLASS
+#define log_ctx graph
+#else
+#define log_ctx NULL
+#endif
+int avfilter_graph_parse2(AVFilterGraph *graph, const char *filters,
+ AVFilterInOut **inputs,
+ AVFilterInOut **outputs)
{
int index = 0, ret;
char chr = 0;
- AVFilterInOut *curr_inputs = NULL;
+ AVFilterInOut *curr_inputs = NULL, *open_inputs = NULL, *open_outputs = NULL;
do {
AVFilterContext *filter;
- const char *filterchain = filters;
filters += strspn(filters, WHITESPACES);
if ((ret = parse_inputs(&filters, &curr_inputs, &open_outputs, log_ctx)) < 0)
@@ -349,12 +364,6 @@ int avfilter_graph_parse(AVFilterGraph *graph, const char *filters,
if ((ret = parse_filter(&filter, &filters, graph, index, log_ctx)) < 0)
goto fail;
- if (filter->input_count == 1 && !curr_inputs && !index) {
- /* First input can be omitted if it is "[in]" */
- const char *tmp = "[in]";
- if ((ret = parse_inputs(&tmp, &curr_inputs, &open_outputs, log_ctx)) < 0)
- goto fail;
- }
if ((ret = link_filter_inouts(filter, &curr_inputs, &open_inputs, log_ctx)) < 0)
goto fail;
@@ -366,13 +375,8 @@ int avfilter_graph_parse(AVFilterGraph *graph, const char *filters,
filters += strspn(filters, WHITESPACES);
chr = *filters++;
- if (chr == ';' && curr_inputs) {
- av_log(log_ctx, AV_LOG_ERROR,
- "Invalid filterchain containing an unlabelled output pad: \"%s\"\n",
- filterchain);
- ret = AVERROR(EINVAL);
- goto fail;
- }
+ if (chr == ';' && curr_inputs)
+ append_inout(&open_outputs, &curr_inputs);
index++;
} while (chr == ',' || chr == ';');
@@ -384,14 +388,10 @@ int avfilter_graph_parse(AVFilterGraph *graph, const char *filters,
goto fail;
}
- if (open_inputs && !strcmp(open_inputs->name, "out") && curr_inputs) {
- /* Last output can be omitted if it is "[out]" */
- const char *tmp = "[out]";
- if ((ret = parse_outputs(&tmp, &curr_inputs, &open_inputs, &open_outputs,
- log_ctx)) < 0)
- goto fail;
- }
+ append_inout(&open_outputs, &curr_inputs);
+ *inputs = open_inputs;
+ *outputs = open_outputs;
return 0;
fail:
@@ -401,5 +401,73 @@ int avfilter_graph_parse(AVFilterGraph *graph, const char *filters,
free_inout(open_inputs);
free_inout(open_outputs);
free_inout(curr_inputs);
+
+ *inputs = NULL;
+ *outputs = NULL;
+
+ return ret;
+}
+#undef log_ctx
+
+int avfilter_graph_parse(AVFilterGraph *graph, const char *filters,
+ AVFilterInOut *open_inputs,
+ AVFilterInOut *open_outputs, void *log_ctx)
+{
+ int ret;
+ AVFilterInOut *cur, *match, *inputs = NULL, *outputs = NULL;
+
+ if ((ret = avfilter_graph_parse2(graph, filters, &inputs, &outputs)) < 0)
+ goto fail;
+
+ /* First input can be omitted if it is "[in]" */
+ if (inputs && !inputs->name)
+ inputs->name = av_strdup("in");
+ for (cur = inputs; cur; cur = cur->next) {
+ if (!cur->name) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Not enough inputs specified for the \"%s\" filter.\n",
+ cur->filter_ctx->filter->name);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ if (!(match = extract_inout(cur->name, &open_outputs)))
+ continue;
+ ret = avfilter_link(match->filter_ctx, match->pad_idx,
+ cur->filter_ctx, cur->pad_idx);
+ free_inout(match);
+ if (ret < 0)
+ goto fail;
+ }
+
+ /* Last output can be omitted if it is "[out]" */
+ if (outputs && !outputs->name)
+ outputs->name = av_strdup("out");
+ for (cur = outputs; cur; cur = cur->next) {
+ if (!cur->name) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Invalid filterchain containing an unlabelled output pad: \"%s\"\n",
+ filters);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ if (!(match = extract_inout(cur->name, &open_inputs)))
+ continue;
+ ret = avfilter_link(cur->filter_ctx, cur->pad_idx,
+ match->filter_ctx, match->pad_idx);
+ free_inout(match);
+ if (ret < 0)
+ goto fail;
+ }
+
+ fail:
+ if (ret < 0) {
+ for (; graph->filter_count > 0; graph->filter_count--)
+ avfilter_free(graph->filters[graph->filter_count - 1]);
+ av_freep(&graph->filters);
+ }
+ free_inout(inputs);
+ free_inout(outputs);
+ free_inout(open_inputs);
+ free_inout(open_outputs);
return ret;
}