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