ea0a86d51aff5e1e3aa649138b343edf8cce2316
[ffmpeg.git] / libavfilter / graphparser.c
1 /*
2  * filter graph parser
3  * Copyright (c) 2008 Vitor Sessak
4  * Copyright (c) 2007 Bobby Bingham
5  *
6  * This file is part of Libav.
7  *
8  * Libav is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * Libav is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with Libav; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22
23 #include <string.h>
24 #include <stdio.h>
25
26 #include "libavutil/avstring.h"
27 #include "libavutil/mem.h"
28 #include "avfilter.h"
29 #include "avfiltergraph.h"
30
31 #define WHITESPACES " \n\t"
32
33 /**
34  * Link two filters together.
35  *
36  * @see avfilter_link()
37  */
38 static int link_filter(AVFilterContext *src, int srcpad,
39                        AVFilterContext *dst, int dstpad,
40                        void *log_ctx)
41 {
42     int ret;
43     if ((ret = avfilter_link(src, srcpad, dst, dstpad))) {
44         av_log(log_ctx, AV_LOG_ERROR,
45                "Cannot create the link %s:%d -> %s:%d\n",
46                src->filter->name, srcpad, dst->filter->name, dstpad);
47         return ret;
48     }
49
50     return 0;
51 }
52
53 /**
54  * Parse the name of a link, which has the format "[linkname]".
55  *
56  * @return a pointer (that need to be freed after use) to the name
57  * between parenthesis
58  */
59 static char *parse_link_name(const char **buf, void *log_ctx)
60 {
61     const char *start = *buf;
62     char *name;
63     (*buf)++;
64
65     name = av_get_token(buf, "]");
66
67     if (!name[0]) {
68         av_log(log_ctx, AV_LOG_ERROR,
69                "Bad (empty?) label found in the following: \"%s\".\n", start);
70         goto fail;
71     }
72
73     if (*(*buf)++ != ']') {
74         av_log(log_ctx, AV_LOG_ERROR,
75                "Mismatched '[' found in the following: \"%s\".\n", start);
76     fail:
77         av_freep(&name);
78     }
79
80     return name;
81 }
82
83 /**
84  * Create an instance of a filter, initialize and insert it in the
85  * filtergraph in *ctx.
86  *
87  * @param filt_ctx put here a filter context in case of successful creation and configuration, NULL otherwise.
88  * @param ctx the filtergraph context
89  * @param index an index which is supposed to be unique for each filter instance added to the filtergraph
90  * @param filt_name the name of the filter to create
91  * @param args the arguments provided to the filter during its initialization
92  * @param log_ctx the log context to use
93  * @return 0 in case of success, a negative AVERROR code otherwise
94  */
95 static int create_filter(AVFilterContext **filt_ctx, AVFilterGraph *ctx, int index,
96                          const char *filt_name, const char *args, void *log_ctx)
97 {
98     AVFilter *filt;
99     char inst_name[30];
100     char tmp_args[256];
101     int ret;
102
103     snprintf(inst_name, sizeof(inst_name), "Parsed filter %d %s", index, filt_name);
104
105     filt = avfilter_get_by_name(filt_name);
106
107     if (!filt) {
108         av_log(log_ctx, AV_LOG_ERROR,
109                "No such filter: '%s'\n", filt_name);
110         return AVERROR(EINVAL);
111     }
112
113     ret = avfilter_open(filt_ctx, filt, inst_name);
114     if (!*filt_ctx) {
115         av_log(log_ctx, AV_LOG_ERROR,
116                "Error creating filter '%s'\n", filt_name);
117         return ret;
118     }
119
120     if ((ret = avfilter_graph_add_filter(ctx, *filt_ctx)) < 0) {
121         avfilter_free(*filt_ctx);
122         return ret;
123     }
124
125     if (!strcmp(filt_name, "scale") && args && !strstr(args, "flags")) {
126         snprintf(tmp_args, sizeof(tmp_args), "%s:%s",
127                  args, ctx->scale_sws_opts);
128         args = tmp_args;
129     }
130
131     if ((ret = avfilter_init_filter(*filt_ctx, args, NULL)) < 0) {
132         av_log(log_ctx, AV_LOG_ERROR,
133                "Error initializing filter '%s' with args '%s'\n", filt_name, args);
134         return ret;
135     }
136
137     return 0;
138 }
139
140 /**
141  * Parse a string of the form FILTER_NAME[=PARAMS], and create a
142  * corresponding filter instance which is added to graph with
143  * create_filter().
144  *
145  * @param filt_ctx Pointer that is set to the created and configured filter
146  *                 context on success, set to NULL on failure.
147  * @param filt_ctx put here a pointer to the created filter context on
148  * success, NULL otherwise
149  * @param buf pointer to the buffer to parse, *buf will be updated to
150  * point to the char next after the parsed string
151  * @param index an index which is assigned to the created filter
152  * instance, and which is supposed to be unique for each filter
153  * instance added to the filtergraph
154  * @return 0 in case of success, a negative AVERROR code otherwise
155  */
156 static int parse_filter(AVFilterContext **filt_ctx, const char **buf, AVFilterGraph *graph,
157                         int index, void *log_ctx)
158 {
159     char *opts = NULL;
160     char *name = av_get_token(buf, "=,;[\n");
161     int ret;
162
163     if (**buf == '=') {
164         (*buf)++;
165         opts = av_get_token(buf, "[],;\n");
166     }
167
168     ret = create_filter(filt_ctx, graph, index, name, opts, log_ctx);
169     av_free(name);
170     av_free(opts);
171     return ret;
172 }
173
174 AVFilterInOut *avfilter_inout_alloc(void)
175 {
176     return av_mallocz(sizeof(AVFilterInOut));
177 }
178
179 void avfilter_inout_free(AVFilterInOut **inout)
180 {
181     while (*inout) {
182         AVFilterInOut *next = (*inout)->next;
183         av_freep(&(*inout)->name);
184         av_freep(inout);
185         *inout = next;
186     }
187 }
188
189 static AVFilterInOut *extract_inout(const char *label, AVFilterInOut **links)
190 {
191     AVFilterInOut *ret;
192
193     while (*links && (!(*links)->name || strcmp((*links)->name, label)))
194         links = &((*links)->next);
195
196     ret = *links;
197
198     if (ret) {
199         *links = ret->next;
200         ret->next = NULL;
201     }
202
203     return ret;
204 }
205
206 static void insert_inout(AVFilterInOut **inouts, AVFilterInOut *element)
207 {
208     element->next = *inouts;
209     *inouts = element;
210 }
211
212 static void append_inout(AVFilterInOut **inouts, AVFilterInOut **element)
213 {
214     while (*inouts && (*inouts)->next)
215         inouts = &((*inouts)->next);
216
217     if (!*inouts)
218         *inouts = *element;
219     else
220         (*inouts)->next = *element;
221     *element = NULL;
222 }
223
224 static int link_filter_inouts(AVFilterContext *filt_ctx,
225                               AVFilterInOut **curr_inputs,
226                               AVFilterInOut **open_inputs, void *log_ctx)
227 {
228     int pad, ret;
229
230     for (pad = 0; pad < filt_ctx->nb_inputs; pad++) {
231         AVFilterInOut *p = *curr_inputs;
232
233         if (p) {
234             *curr_inputs = (*curr_inputs)->next;
235             p->next = NULL;
236         } else if (!(p = av_mallocz(sizeof(*p))))
237             return AVERROR(ENOMEM);
238
239         if (p->filter_ctx) {
240             ret = link_filter(p->filter_ctx, p->pad_idx, filt_ctx, pad, log_ctx);
241             av_free(p->name);
242             av_free(p);
243             if (ret < 0)
244                 return ret;
245         } else {
246             p->filter_ctx = filt_ctx;
247             p->pad_idx = pad;
248             append_inout(open_inputs, &p);
249         }
250     }
251
252     if (*curr_inputs) {
253         av_log(log_ctx, AV_LOG_ERROR,
254                "Too many inputs specified for the \"%s\" filter.\n",
255                filt_ctx->filter->name);
256         return AVERROR(EINVAL);
257     }
258
259     pad = filt_ctx->nb_outputs;
260     while (pad--) {
261         AVFilterInOut *currlinkn = av_mallocz(sizeof(AVFilterInOut));
262         if (!currlinkn)
263             return AVERROR(ENOMEM);
264         currlinkn->filter_ctx  = filt_ctx;
265         currlinkn->pad_idx = pad;
266         insert_inout(curr_inputs, currlinkn);
267     }
268
269     return 0;
270 }
271
272 static int parse_inputs(const char **buf, AVFilterInOut **curr_inputs,
273                         AVFilterInOut **open_outputs, void *log_ctx)
274 {
275     AVFilterInOut *parsed_inputs = NULL;
276     int pad = 0;
277
278     while (**buf == '[') {
279         char *name = parse_link_name(buf, log_ctx);
280         AVFilterInOut *match;
281
282         if (!name)
283             return AVERROR(EINVAL);
284
285         /* First check if the label is not in the open_outputs list */
286         match = extract_inout(name, open_outputs);
287
288         if (match) {
289             av_free(name);
290         } else {
291             /* Not in the list, so add it as an input */
292             if (!(match = av_mallocz(sizeof(AVFilterInOut)))) {
293                 av_free(name);
294                 return AVERROR(ENOMEM);
295             }
296             match->name    = name;
297             match->pad_idx = pad;
298         }
299
300         append_inout(&parsed_inputs, &match);
301
302         *buf += strspn(*buf, WHITESPACES);
303         pad++;
304     }
305
306     append_inout(&parsed_inputs, curr_inputs);
307     *curr_inputs = parsed_inputs;
308
309     return pad;
310 }
311
312 static int parse_outputs(const char **buf, AVFilterInOut **curr_inputs,
313                          AVFilterInOut **open_inputs,
314                          AVFilterInOut **open_outputs, void *log_ctx)
315 {
316     int ret, pad = 0;
317
318     while (**buf == '[') {
319         char *name = parse_link_name(buf, log_ctx);
320         AVFilterInOut *match;
321
322         AVFilterInOut *input = *curr_inputs;
323
324         if (!name)
325             return AVERROR(EINVAL);
326
327         if (!input) {
328             av_log(log_ctx, AV_LOG_ERROR,
329                    "No output pad can be associated to link label '%s'.\n", name);
330             av_free(name);
331             return AVERROR(EINVAL);
332         }
333         *curr_inputs = (*curr_inputs)->next;
334
335         /* First check if the label is not in the open_inputs list */
336         match = extract_inout(name, open_inputs);
337
338         if (match) {
339             if ((ret = link_filter(input->filter_ctx, input->pad_idx,
340                                    match->filter_ctx, match->pad_idx, log_ctx)) < 0) {
341                 av_free(name);
342                 return ret;
343             }
344             av_free(match->name);
345             av_free(name);
346             av_free(match);
347             av_free(input);
348         } else {
349             /* Not in the list, so add the first input as a open_output */
350             input->name = name;
351             insert_inout(open_outputs, input);
352         }
353         *buf += strspn(*buf, WHITESPACES);
354         pad++;
355     }
356
357     return pad;
358 }
359
360 static int parse_sws_flags(const char **buf, AVFilterGraph *graph)
361 {
362     char *p = strchr(*buf, ';');
363
364     if (strncmp(*buf, "sws_flags=", 10))
365         return 0;
366
367     if (!p) {
368         av_log(graph, AV_LOG_ERROR, "sws_flags not terminated with ';'.\n");
369         return AVERROR(EINVAL);
370     }
371
372     *buf += 4;  // keep the 'flags=' part
373
374     av_freep(&graph->scale_sws_opts);
375     if (!(graph->scale_sws_opts = av_mallocz(p - *buf + 1)))
376         return AVERROR(ENOMEM);
377     av_strlcpy(graph->scale_sws_opts, *buf, p - *buf + 1);
378
379     *buf = p + 1;
380     return 0;
381 }
382
383 int avfilter_graph_parse2(AVFilterGraph *graph, const char *filters,
384                           AVFilterInOut **inputs,
385                           AVFilterInOut **outputs)
386 {
387     int index = 0, ret;
388     char chr = 0;
389
390     AVFilterInOut *curr_inputs = NULL, *open_inputs = NULL, *open_outputs = NULL;
391
392     filters += strspn(filters, WHITESPACES);
393
394     if ((ret = parse_sws_flags(&filters, graph)) < 0)
395         goto fail;
396
397     do {
398         AVFilterContext *filter;
399         filters += strspn(filters, WHITESPACES);
400
401         if ((ret = parse_inputs(&filters, &curr_inputs, &open_outputs, graph)) < 0)
402             goto fail;
403
404         if ((ret = parse_filter(&filter, &filters, graph, index, graph)) < 0)
405             goto fail;
406
407
408         if ((ret = link_filter_inouts(filter, &curr_inputs, &open_inputs, graph)) < 0)
409             goto fail;
410
411         if ((ret = parse_outputs(&filters, &curr_inputs, &open_inputs, &open_outputs,
412                                  graph)) < 0)
413             goto fail;
414
415         filters += strspn(filters, WHITESPACES);
416         chr = *filters++;
417
418         if (chr == ';' && curr_inputs)
419             append_inout(&open_outputs, &curr_inputs);
420         index++;
421     } while (chr == ',' || chr == ';');
422
423     if (chr) {
424         av_log(graph, AV_LOG_ERROR,
425                "Unable to parse graph description substring: \"%s\"\n",
426                filters - 1);
427         ret = AVERROR(EINVAL);
428         goto fail;
429     }
430
431     append_inout(&open_outputs, &curr_inputs);
432
433     *inputs  = open_inputs;
434     *outputs = open_outputs;
435     return 0;
436
437  fail:
438     for (; graph->nb_filters > 0; graph->nb_filters--)
439         avfilter_free(graph->filters[graph->nb_filters - 1]);
440     av_freep(&graph->filters);
441     avfilter_inout_free(&open_inputs);
442     avfilter_inout_free(&open_outputs);
443     avfilter_inout_free(&curr_inputs);
444
445     *inputs  = NULL;
446     *outputs = NULL;
447
448     return ret;
449 }
450
451 int avfilter_graph_parse(AVFilterGraph *graph, const char *filters,
452                          AVFilterInOut *open_inputs,
453                          AVFilterInOut *open_outputs, void *log_ctx)
454 {
455     int ret;
456     AVFilterInOut *cur, *match, *inputs = NULL, *outputs = NULL;
457
458     if ((ret = avfilter_graph_parse2(graph, filters, &inputs, &outputs)) < 0)
459         goto fail;
460
461     /* First input can be omitted if it is "[in]" */
462     if (inputs && !inputs->name)
463         inputs->name = av_strdup("in");
464     for (cur = inputs; cur; cur = cur->next) {
465         if (!cur->name) {
466               av_log(log_ctx, AV_LOG_ERROR,
467                      "Not enough inputs specified for the \"%s\" filter.\n",
468                      cur->filter_ctx->filter->name);
469               ret = AVERROR(EINVAL);
470               goto fail;
471         }
472         if (!(match = extract_inout(cur->name, &open_outputs)))
473             continue;
474         ret = avfilter_link(match->filter_ctx, match->pad_idx,
475                             cur->filter_ctx,   cur->pad_idx);
476         avfilter_inout_free(&match);
477         if (ret < 0)
478             goto fail;
479     }
480
481     /* Last output can be omitted if it is "[out]" */
482     if (outputs && !outputs->name)
483         outputs->name = av_strdup("out");
484     for (cur = outputs; cur; cur = cur->next) {
485         if (!cur->name) {
486             av_log(log_ctx, AV_LOG_ERROR,
487                    "Invalid filterchain containing an unlabelled output pad: \"%s\"\n",
488                    filters);
489             ret = AVERROR(EINVAL);
490             goto fail;
491         }
492         if (!(match = extract_inout(cur->name, &open_inputs)))
493             continue;
494         ret = avfilter_link(cur->filter_ctx,   cur->pad_idx,
495                             match->filter_ctx, match->pad_idx);
496         avfilter_inout_free(&match);
497         if (ret < 0)
498             goto fail;
499     }
500
501  fail:
502     if (ret < 0) {
503         for (; graph->nb_filters > 0; graph->nb_filters--)
504             avfilter_free(graph->filters[graph->nb_filters - 1]);
505         av_freep(&graph->filters);
506     }
507     avfilter_inout_free(&inputs);
508     avfilter_inout_free(&outputs);
509     avfilter_inout_free(&open_inputs);
510     avfilter_inout_free(&open_outputs);
511     return ret;
512 }