The name field of AVFilterInOut can be declared const
[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
152/**
153 * Parse "filter=params"
154 * @arg name a pointer (that need to be free'd after use) to the name of the
155 * filter
156 * @arg ars a pointer (that need to be free'd after use) to the args of the
157 * filter
158 */
3a70bb2d
VS
159static AVFilterContext *parse_filter(const char **buf,
160 AVFilterGraph *graph, int index,
161 AVClass *log_ctx)
27afb09d
VS
162{
163 char *name, *opts;
164 name = consume_string(buf);
165
2839ff5e 166 if(**buf == '=') {
27afb09d
VS
167 (*buf)++;
168 opts = consume_string(buf);
169 } else {
170 opts = NULL;
171 }
172
3a70bb2d 173 return create_filter(graph, index, name, opts, log_ctx);
27afb09d
VS
174}
175
176enum LinkType {
177 LinkTypeIn,
178 LinkTypeOut,
179};
180
181/**
182 * A linked-list of the inputs/outputs of the filter chain.
183 */
184typedef struct AVFilterInOut {
185 enum LinkType type;
498f0305 186 const char *name;
37161d64 187 AVFilterContext *filter;
27afb09d
VS
188 int pad_idx;
189
190 struct AVFilterInOut *next;
191} AVFilterInOut;
192
193static void free_inout(AVFilterInOut *head)
194{
195 while (head) {
55672c83 196 AVFilterInOut *next = head->next;
27afb09d
VS
197 av_free(head);
198 head = next;
199 }
200}
201
202/**
ffac8784 203 * Parse "[a1][link2] ... [etc]"
27afb09d 204 */
325cb1ef 205static int parse_inouts(const char **buf, AVFilterInOut **inout, int pad,
3a70bb2d
VS
206 enum LinkType type, AVFilterContext *filter,
207 AVClass *log_ctx)
27afb09d 208{
d7ff2297 209 while (**buf == '[') {
2b7defc7 210 char *name;
cf4f7d38 211 AVFilterInOut *p = *inout;
22260824 212
3a70bb2d 213 parse_link_name(buf, &name, log_ctx);
2b7defc7 214
a4501887 215 if(!name)
22260824 216 return -1;
22260824 217
cf4f7d38
VS
218 for (; p && strcmp(p->name, name); p = p->next);
219
220 if(!p) {
221 // First label apearence, add it to the linked list
222 AVFilterInOut *inoutn = av_malloc(sizeof(AVFilterInOut));
223
224 inoutn->name = name;
225 inoutn->type = type;
226 inoutn->filter = filter;
227 inoutn->pad_idx = pad;
228 inoutn->next = *inout;
229 *inout = inoutn;
230 } else {
231
232 if(p->type == LinkTypeIn && type == LinkTypeOut) {
233 if(link_filter(filter, pad, p->filter, p->pad_idx, log_ctx) < 0)
234 return -1;
235 } else if(p->type == LinkTypeOut && type == LinkTypeIn) {
236 if(link_filter(p->filter, p->pad_idx, filter, pad, log_ctx) < 0)
237 return -1;
238 } else {
239 av_log(log_ctx, AV_LOG_ERROR,
240 "Two links named '%s' are either both input or both output\n",
241 name);
242 return -1;
243 }
244
245 p->filter = NULL;
246 }
7693be92 247
cf4f7d38 248 pad++;
8095a014 249 consume_whitespace(buf);
27afb09d 250 }
cf4f7d38 251
27afb09d
VS
252 return pad;
253}
254
9710beaf
VS
255static const char *skip_inouts(const char *buf)
256{
8095a014 257 while (*buf == '[') {
a3acd1d9 258 buf += strcspn(buf, "]") + 1;
8095a014
VS
259 consume_whitespace(&buf);
260 }
9710beaf
VS
261 return buf;
262}
263
264
27afb09d
VS
265/**
266 * Parse a string describing a filter graph.
267 */
92973a04
VS
268int avfilter_parse_graph(AVFilterGraph *graph, const char *filters,
269 AVFilterContext *in, int inpad,
3a70bb2d
VS
270 AVFilterContext *out, int outpad,
271 AVClass *log_ctx)
27afb09d
VS
272{
273 AVFilterInOut *inout=NULL;
274 AVFilterInOut *head=NULL;
275
276 int index = 0;
277 char chr = 0;
278 int pad = 0;
279 int has_out = 0;
280
9710beaf 281 AVFilterContext *last_filt = NULL;
27afb09d 282
27afb09d 283 do {
9710beaf 284 AVFilterContext *filter;
27afb09d 285 int oldpad = pad;
7a57c8d9
VS
286 const char *inouts;
287
288 consume_whitespace(&filters);
289 inouts = filters;
27afb09d 290
9710beaf
VS
291 // We need to parse the inputs of the filter after we create it, so
292 // skip it by now
293 filters = skip_inouts(filters);
27afb09d 294
3a70bb2d 295 if(!(filter = parse_filter(&filters, graph, index, log_ctx)))
27afb09d
VS
296 goto fail;
297
3a70bb2d
VS
298 pad = parse_inouts(&inouts, &inout, chr == ',', LinkTypeIn, filter,
299 log_ctx);
9710beaf 300
22260824
VS
301 if(pad < 0)
302 goto fail;
303
27afb09d
VS
304 // If the first filter has an input and none was given, it is
305 // implicitly the input of the whole graph.
2839ff5e 306 if(pad == 0 && filter->input_count == 1) {
3a70bb2d 307 if(link_filter(in, inpad, filter, 0, log_ctx))
27afb09d 308 goto fail;
27afb09d
VS
309 }
310
311 if(chr == ',') {
3a70bb2d 312 if(link_filter(last_filt, oldpad, filter, 0, log_ctx) < 0)
27afb09d 313 goto fail;
27afb09d 314 }
da790674 315
3a70bb2d 316 pad = parse_inouts(&filters, &inout, 0, LinkTypeOut, filter, log_ctx);
7a57c8d9 317
3a70bb2d 318 if (pad < 0)
e84f0b62
VS
319 goto fail;
320
7a57c8d9
VS
321 consume_whitespace(&filters);
322
27afb09d
VS
323 chr = *filters++;
324 index++;
9710beaf 325 last_filt = filter;
27afb09d
VS
326 } while (chr == ',' || chr == ';');
327
328 head = inout;
2b7defc7 329 // Process remaining labels. Only inputs and outputs should be left.
a59a7734
VS
330 for (; inout; inout = inout->next) {
331 if(!inout->filter)
27afb09d
VS
332 continue; // Already processed
333
2839ff5e 334 if(!strcmp(inout->name, "in")) {
3a70bb2d 335 if(link_filter(in, inpad, inout->filter, inout->pad_idx, log_ctx))
27afb09d 336 goto fail;
ee75692a 337
2839ff5e 338 } else if(!strcmp(inout->name, "out")) {
27afb09d 339 has_out = 1;
27afb09d 340
3a70bb2d 341 if(link_filter(inout->filter, inout->pad_idx, out, outpad, log_ctx))
27afb09d 342 goto fail;
27afb09d
VS
343
344 } else {
3a70bb2d 345 av_log(log_ctx, AV_LOG_ERROR, "Unmatched link: %s.\n",
2b7defc7 346 inout->name);
27afb09d 347 goto fail;
27afb09d
VS
348 }
349 }
350
351 free_inout(head);
352
2839ff5e 353 if(!has_out) {
3a70bb2d 354 if(link_filter(last_filt, pad, out, outpad, log_ctx))
27afb09d 355 goto fail;
27afb09d
VS
356 }
357
358 return 0;
359
360 fail:
361 free_inout(head);
362 avfilter_destroy_graph(graph);
363 return -1;
364}