Rename another var
[libav.git] / libavfilter / graphparser.c
CommitLineData
27afb09d
VS
1/*
2 * filter graph parser
3 * copyright (c) 2008 Vitor Sessak
4 * copyright (c) 2007 Bobby Bingham
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg 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 * FFmpeg 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 FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#include <ctype.h>
24#include <string.h>
25
26#include "avfilter.h"
27#include "avfiltergraph.h"
28
9710beaf 29static AVFilterContext *create_filter(AVFilterGraph *ctx, int index,
3a70bb2d
VS
30 const char *name, const char *args,
31 AVClass *log_ctx)
27afb09d
VS
32{
33 AVFilterContext *filt;
34
35 AVFilter *filterdef;
58a2d7a5 36 char inst_name[30];
27afb09d 37
58a2d7a5 38 snprintf(inst_name, sizeof(inst_name), "Parsed filter %d", index);
27a669ab
VS
39
40 if(!(filterdef = avfilter_get_by_name(name))) {
dd8e311e 41 av_log(log_ctx, AV_LOG_ERROR,
27a669ab 42 "no such filter: '%s'\n", name);
9710beaf 43 return NULL;
27a669ab
VS
44 }
45
58a2d7a5 46 if(!(filt = avfilter_open(filterdef, inst_name))) {
3a70bb2d 47 av_log(log_ctx, AV_LOG_ERROR,
27afb09d 48 "error creating filter '%s'\n", name);
9710beaf 49 return NULL;
27afb09d 50 }
046f49ba 51
2839ff5e 52 if(avfilter_graph_add_filter(ctx, filt) < 0)
9710beaf 53 return NULL;
046f49ba 54
27afb09d 55 if(avfilter_init_filter(filt, args, NULL)) {
3a70bb2d 56 av_log(log_ctx, AV_LOG_ERROR,
27a669ab 57 "error initializing filter '%s' with args '%s'\n", name, args);
9710beaf 58 return NULL;
27afb09d
VS
59 }
60
9710beaf 61 return filt;
27afb09d
VS
62}
63
9710beaf 64static int link_filter(AVFilterContext *src, int srcpad,
3a70bb2d
VS
65 AVFilterContext *dst, int dstpad,
66 AVClass *log_ctx)
27afb09d 67{
9710beaf 68 if(avfilter_link(src, srcpad, dst, dstpad)) {
3a70bb2d 69 av_log(log_ctx, AV_LOG_ERROR,
9710beaf
VS
70 "cannot create the link %s:%d -> %s:%d\n",
71 src->filter->name, srcpad, dst->filter->name, dstpad);
27afb09d
VS
72 return -1;
73 }
74
75 return 0;
76}
77
78static void consume_whitespace(const char **buf)
79{
80 *buf += strspn(*buf, " \n\t");
81}
82
83/**
27afb09d
VS
84 * Consumes a string from *buf.
85 * @return a copy of the consumed string, which should be free'd after use
86 */
87static char *consume_string(const char **buf)
88{
2255026d 89 char *out = av_malloc(strlen(*buf) + 1);
93b7a0f6 90 char *ret = out;
27afb09d
VS
91
92 consume_whitespace(buf);
93
93b7a0f6 94 do{
a64821f4 95 char c = *(*buf)++;
93b7a0f6
VS
96 switch (c) {
97 case '\\':
a64821f4 98 *out++= *(*buf)++;
27afb09d 99 break;
93b7a0f6 100 case '\'':
a64821f4
VS
101 while(**buf && **buf != '\'')
102 *out++= *(*buf)++;
103 if(**buf) (*buf)++;
93b7a0f6
VS
104 break;
105 case 0:
d7ff2297
VS
106 case ']':
107 case '[':
93b7a0f6
VS
108 case '=':
109 case ',':
dbec351d 110 case ';':
a78f2ccd
VS
111 case ' ':
112 case '\n':
93b7a0f6
VS
113 *out++= 0;
114 break;
115 default:
116 *out++= c;
117 }
118 } while(out[-1]);
27afb09d 119
a64821f4 120 (*buf)--;
a78f2ccd
VS
121 consume_whitespace(buf);
122
27afb09d
VS
123 return ret;
124}
125
126/**
ffac8784 127 * Parse "[linkname]"
27afb09d
VS
128 * @arg name a pointer (that need to be free'd after use) to the name between
129 * parenthesis
130 */
3a70bb2d 131static void parse_link_name(const char **buf, char **name, AVClass *log_ctx)
27afb09d 132{
22260824 133 const char *start = *buf;
27afb09d
VS
134 (*buf)++;
135
136 *name = consume_string(buf);
137
22260824 138 if(!*name[0]) {
3a70bb2d 139 av_log(log_ctx, AV_LOG_ERROR,
22260824 140 "Bad (empty?) label found in the following: \"%s\".\n", start);
27afb09d 141 goto fail;
22260824 142 }
27afb09d 143
22260824 144 if(*(*buf)++ != ']') {
3a70bb2d 145 av_log(log_ctx, AV_LOG_ERROR,
22260824 146 "Mismatched '[' found in the following: \"%s\".\n", start);
85cb8af7
VS
147 fail:
148 av_freep(name);
22260824 149 }
27afb09d
VS
150}
151
27afb09d
VS
152
153enum LinkType {
154 LinkTypeIn,
155 LinkTypeOut,
156};
157
158/**
159 * A linked-list of the inputs/outputs of the filter chain.
160 */
161typedef struct AVFilterInOut {
162 enum LinkType type;
498f0305 163 const char *name;
37161d64 164 AVFilterContext *filter;
27afb09d
VS
165 int pad_idx;
166
167 struct AVFilterInOut *next;
168} AVFilterInOut;
169
170static void free_inout(AVFilterInOut *head)
171{
172 while (head) {
55672c83 173 AVFilterInOut *next = head->next;
27afb09d
VS
174 av_free(head);
175 head = next;
176 }
177}
178
c9987633
VS
179static AVFilterInOut *extract_inout(const char *label, AVFilterInOut **links)
180{
181 AVFilterInOut *ret;
c9987633 182
c9987633 183
fec2e513
VS
184 while(*links && strcmp((*links)->name, label))
185 links= &((*links)->next);
c9987633 186
fec2e513 187 ret= *links;
c9987633 188
fec2e513
VS
189 if(ret)
190 *links= ret->next;
c9987633
VS
191
192 return ret;
193}
194
195
196static int link_filter_inouts(AVFilterContext *filter,
197 AVFilterInOut **currInputs,
198 AVFilterInOut **openLinks, AVClass *log_ctx)
199{
200 AVFilterInOut *p;
201 int pad = 0;
202
203 pad = filter->input_count;
4fd9d074 204 while(pad--) {
c9987633 205 p = *currInputs;
c9987633
VS
206 if(!p) {
207 av_log(log_ctx, AV_LOG_ERROR,
208 "Not enough inputs specified for the \"%s\" filter.\n",
209 filter->name);
210 return -1;
211 }
212
213 if(p->filter) {
214 if(link_filter(p->filter, p->pad_idx, filter, pad, log_ctx))
215 return -1;
216 *currInputs = (*currInputs)->next;
217 av_free(p);
218 } else {
c9987633
VS
219 *currInputs = (*currInputs)->next;
220 p->filter = filter;
221 p->pad_idx = pad;
222 p->next = *openLinks;
223 *openLinks = p;
224 }
225 }
226
227
228 if(*currInputs) {
229 av_log(log_ctx, AV_LOG_ERROR,
230 "Too many inputs specified for the \"%s\" filter.\n",
231 filter->name);
232 return -1;
233 }
234
235 pad = filter->output_count;
4fd9d074 236 while(pad--) {
c9987633 237 AVFilterInOut *currlinkn = av_malloc(sizeof(AVFilterInOut));
c9987633
VS
238 currlinkn->name = NULL;
239 currlinkn->type = LinkTypeOut;
240 currlinkn->filter = filter;
241 currlinkn->pad_idx = pad;
242 currlinkn->next = *currInputs;
243 *currInputs = currlinkn;
244 }
245
246 return 0;
247}
248
27afb09d 249/**
c9987633
VS
250 * Parse "filter=params"
251 * @arg name a pointer (that need to be free'd after use) to the name of the
252 * filter
253 * @arg ars a pointer (that need to be free'd after use) to the args of the
254 * filter
27afb09d 255 */
c9987633
VS
256static AVFilterContext *parse_filter(const char **buf, AVFilterGraph *graph,
257 int index, AVClass *log_ctx)
258{
259 char *opts;
260 char *name = consume_string(buf);
261
262 if(**buf == '=') {
263 (*buf)++;
264 opts = consume_string(buf);
265 } else {
266 opts = NULL;
267 }
268
269 return create_filter(graph, index, name, opts, log_ctx);
270}
271
272static int parse_inputs(const char **buf, AVFilterInOut **currInputs,
273 AVFilterInOut **openLinks, AVClass *log_ctx)
27afb09d 274{
c9987633 275 int pad = 0;
c9987633 276
d7ff2297 277 while (**buf == '[') {
2b7defc7 278 char *name;
b2ac16da 279 AVFilterInOut *match;
22260824 280
3a70bb2d 281 parse_link_name(buf, &name, log_ctx);
2b7defc7 282
a4501887 283 if(!name)
22260824 284 return -1;
22260824 285
c9987633 286 /* First check if the label is not in the openLinks list */
b2ac16da 287 match = extract_inout(name, openLinks);
cf4f7d38 288
b2ac16da 289 if(match) {
c9987633
VS
290 /* A label of a open link. Make it one of the inputs of the next
291 filter */
b2ac16da
VS
292 AVFilterInOut *currlinkn = match;
293 if (match->type != LinkTypeOut) {
cf4f7d38 294 av_log(log_ctx, AV_LOG_ERROR,
b2ac16da 295 "Label \"%s\" appears twice as input!\n", match->name);
cf4f7d38
VS
296 return -1;
297 }
c9987633
VS
298 currlinkn->next = *currInputs;
299 *currInputs = currlinkn;
0de3407b
VS
300 } else {
301 /* Not in the list, so add it as an input */
302 AVFilterInOut *currlinkn = av_malloc(sizeof(AVFilterInOut));
303
304 currlinkn->name = name;
305 currlinkn->type = LinkTypeIn;
306 currlinkn->filter = NULL;
307 currlinkn->pad_idx = pad;
308 currlinkn->next = *currInputs;
309 *currInputs = currlinkn;
cf4f7d38 310 }
8095a014 311 consume_whitespace(buf);
c9987633 312 pad++;
27afb09d 313 }
cf4f7d38 314
27afb09d
VS
315 return pad;
316}
317
c9987633
VS
318static int parse_outputs(const char **buf, AVFilterInOut **currInputs,
319 AVFilterInOut **openLinks, AVClass *log_ctx)
9710beaf 320{
c9987633
VS
321 int pad = 0;
322
323 while (**buf == '[') {
324 char *name;
325 AVFilterInOut *match;
326
327 parse_link_name(buf, &name, log_ctx);
328
329 if(!name)
330 return -1;
331
332 /* First check if the label is not in the openLinks list */
333 match = extract_inout(name, openLinks);
334
0de3407b 335 if(match) {
c9987633 336 /* A label of a open link. Link it. */
7baa6210 337 AVFilterInOut *input = *currInputs;
c9987633
VS
338 if (match->type != LinkTypeIn) {
339 av_log(log_ctx, AV_LOG_ERROR,
340 "Label \"%s\" appears twice as output!\n", match->name);
341 return -1;
342 }
343
344 *currInputs = (*currInputs)->next;
7baa6210 345 if(link_filter(input->filter, input->pad_idx,
c9987633
VS
346 match->filter, match->pad_idx, log_ctx) < 0)
347 return -1;
348 av_free(match);
7baa6210 349 av_free(input);
0de3407b
VS
350 } else {
351 /* Not in the list, so add the first input as a openLink */
7baa6210 352 AVFilterInOut *input = *currInputs;
0de3407b 353 *currInputs = (*currInputs)->next;
7baa6210
VS
354 input->next = *openLinks;
355 input->type = LinkTypeOut;
356 input->name = name;
357 *openLinks = input;
c9987633
VS
358 }
359 consume_whitespace(buf);
360 pad++;
8095a014 361 }
9710beaf 362
c9987633
VS
363 return pad;
364}
9710beaf 365
27afb09d
VS
366/**
367 * Parse a string describing a filter graph.
368 */
92973a04
VS
369int avfilter_parse_graph(AVFilterGraph *graph, const char *filters,
370 AVFilterContext *in, int inpad,
3a70bb2d
VS
371 AVFilterContext *out, int outpad,
372 AVClass *log_ctx)
27afb09d 373{
27afb09d
VS
374 int index = 0;
375 char chr = 0;
376 int pad = 0;
27afb09d 377
c9987633
VS
378 AVFilterInOut *currInputs=NULL;
379 AVFilterInOut *openLinks = av_malloc(sizeof(AVFilterInOut));
380
381 openLinks->name = "in";
382 openLinks->filter = in;
383 openLinks->type = LinkTypeOut;
384 openLinks->pad_idx = inpad;
385 openLinks->next = av_malloc(sizeof(AVFilterInOut));
386
387 openLinks->next->name = "out";
388 openLinks->next->filter = out;
389 openLinks->next->type = LinkTypeIn;
390 openLinks->next->pad_idx = outpad;
391 openLinks->next->next = NULL;
27afb09d 392
27afb09d 393 do {
9710beaf 394 AVFilterContext *filter;
7a57c8d9 395 consume_whitespace(&filters);
27afb09d 396
c9987633 397 pad = parse_inputs(&filters, &currInputs, &openLinks, log_ctx);
27afb09d 398
c9987633 399 if(pad < 0)
27afb09d
VS
400 goto fail;
401
c9987633 402 if(!(filter = parse_filter(&filters, graph, index, log_ctx)))
22260824
VS
403 goto fail;
404
c9987633
VS
405 if(filter->input_count == 1 && !currInputs && !index) {
406 // First input can be ommitted if it is "[in]"
407 const char *tmp = "[in]";
408 pad = parse_inputs(&tmp, &currInputs, &openLinks, log_ctx);
409 if (pad < 0)
27afb09d 410 goto fail;
27afb09d
VS
411 }
412
c9987633
VS
413 if(link_filter_inouts(filter, &currInputs, &openLinks, log_ctx) < 0)
414 goto fail;
da790674 415
c9987633 416 pad = parse_outputs(&filters, &currInputs, &openLinks, log_ctx);
7a57c8d9 417
c9987633 418 if(pad < 0)
e84f0b62
VS
419 goto fail;
420
7a57c8d9 421 consume_whitespace(&filters);
27afb09d 422 chr = *filters++;
27afb09d 423
c9987633
VS
424 if (chr == ';' && currInputs) {
425 av_log(log_ctx, AV_LOG_ERROR,
426 "Could not find a output to link when parsing \"%s\"\n",
427 filters - 1);
428 goto fail;
27afb09d 429 }
c9987633
VS
430 index++;
431 } while (chr == ',' || chr == ';');
27afb09d 432
c9987633
VS
433 if(openLinks && !strcmp(openLinks->name, "out") && currInputs) {
434 // Last output can be ommitted if it is "[out]"
435 const char *tmp = "[out]";
436 if(parse_outputs(&tmp, &currInputs, &openLinks, log_ctx) < 0)
27afb09d 437 goto fail;
27afb09d
VS
438 }
439
440 return 0;
441
442 fail:
27afb09d 443 avfilter_destroy_graph(graph);
c9987633
VS
444 free_inout(openLinks);
445 free_inout(currInputs);
27afb09d
VS
446 return -1;
447}