Calculate deblock strength per-MB instead of per-row
[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"
dd04911c 29#include "parseutils.h"
27afb09d 30
fd548e5b
SS
31#define WHITESPACES " \n\t"
32
9710beaf 33static int link_filter(AVFilterContext *src, int srcpad,
3a70bb2d
VS
34 AVFilterContext *dst, int dstpad,
35 AVClass *log_ctx)
27afb09d 36{
9710beaf 37 if(avfilter_link(src, srcpad, dst, dstpad)) {
3a70bb2d 38 av_log(log_ctx, AV_LOG_ERROR,
9710beaf
VS
39 "cannot create the link %s:%d -> %s:%d\n",
40 src->filter->name, srcpad, dst->filter->name, dstpad);
27afb09d
VS
41 return -1;
42 }
43
44 return 0;
45}
46
27afb09d 47/**
ffac8784 48 * Parse "[linkname]"
69fa7e80
VS
49 * @param name a pointer (that need to be free'd after use) to the name between
50 * parenthesis
27afb09d 51 */
bd80b349 52static char *parse_link_name(const char **buf, AVClass *log_ctx)
27afb09d 53{
22260824 54 const char *start = *buf;
bd80b349 55 char *name;
27afb09d
VS
56 (*buf)++;
57
dd04911c 58 name = av_get_token(buf, "]");
27afb09d 59
bd80b349 60 if(!name[0]) {
3a70bb2d 61 av_log(log_ctx, AV_LOG_ERROR,
22260824 62 "Bad (empty?) label found in the following: \"%s\".\n", start);
27afb09d 63 goto fail;
22260824 64 }
27afb09d 65
22260824 66 if(*(*buf)++ != ']') {
3a70bb2d 67 av_log(log_ctx, AV_LOG_ERROR,
22260824 68 "Mismatched '[' found in the following: \"%s\".\n", start);
85cb8af7 69 fail:
bd80b349 70 av_freep(&name);
22260824 71 }
bd80b349
VS
72
73 return name;
27afb09d
VS
74}
75
8e74c889 76static AVFilterContext *create_filter(AVFilterGraph *ctx, int index,
e4a5f397 77 const char *filt_name, const char *args,
8e74c889
VS
78 AVClass *log_ctx)
79{
e4a5f397 80 AVFilterContext *filt_ctx;
8e74c889 81
e4a5f397 82 AVFilter *filt;
8e74c889 83 char inst_name[30];
b5049814 84 char tmp_args[256];
8e74c889 85
03c3bb5c 86 snprintf(inst_name, sizeof(inst_name), "Filter %d %s", index, filt_name);
8e74c889 87
e4a5f397 88 filt = avfilter_get_by_name(filt_name);
5e600185 89
e4a5f397 90 if(!filt) {
8e74c889 91 av_log(log_ctx, AV_LOG_ERROR,
e4a5f397 92 "no such filter: '%s'\n", filt_name);
8e74c889
VS
93 return NULL;
94 }
95
e4a5f397
SS
96 filt_ctx = avfilter_open(filt, inst_name);
97 if(!filt_ctx) {
8e74c889 98 av_log(log_ctx, AV_LOG_ERROR,
e4a5f397 99 "error creating filter '%s'\n", filt_name);
8e74c889
VS
100 return NULL;
101 }
102
e4a5f397
SS
103 if(avfilter_graph_add_filter(ctx, filt_ctx) < 0) {
104 avfilter_destroy(filt_ctx);
8e74c889 105 return NULL;
64b164f4 106 }
8e74c889 107
b5049814
BC
108 if (!strcmp(filt_name, "scale") && !strstr(args, "flags")) {
109 snprintf(tmp_args, sizeof(tmp_args), "%s:%s",
110 args, ctx->scale_sws_opts);
111 args = tmp_args;
112 }
113
e4a5f397 114 if(avfilter_init_filter(filt_ctx, args, NULL)) {
8e74c889 115 av_log(log_ctx, AV_LOG_ERROR,
e4a5f397 116 "error initializing filter '%s' with args '%s'\n", filt_name, args);
8e74c889
VS
117 return NULL;
118 }
119
e4a5f397 120 return filt_ctx;
8e74c889
VS
121}
122
f5cbde2e
VS
123/**
124 * Parse "filter=params"
f5cbde2e
VS
125 */
126static AVFilterContext *parse_filter(const char **buf, AVFilterGraph *graph,
127 int index, AVClass *log_ctx)
128{
ba3fed2f 129 char *opts = NULL;
15a316c0 130 char *name = av_get_token(buf, "=,;[\n");
64b164f4 131 AVFilterContext *ret;
f5cbde2e 132
12849837 133 if(**buf == '=') {
f5cbde2e 134 (*buf)++;
15a316c0 135 opts = av_get_token(buf, "[],;\n");
12849837 136 }
f5cbde2e 137
64b164f4
VS
138 ret = create_filter(graph, index, name, opts, log_ctx);
139 av_free(name);
140 av_free(opts);
141 return ret;
f5cbde2e
VS
142}
143
27afb09d
VS
144static void free_inout(AVFilterInOut *head)
145{
487c0e67 146 while(head) {
55672c83 147 AVFilterInOut *next = head->next;
64b164f4 148 av_free(head->name);
27afb09d
VS
149 av_free(head);
150 head = next;
151 }
152}
153
c9987633
VS
154static AVFilterInOut *extract_inout(const char *label, AVFilterInOut **links)
155{
156 AVFilterInOut *ret;
c9987633 157
fec2e513 158 while(*links && strcmp((*links)->name, label))
f6557d5e 159 links = &((*links)->next);
c9987633 160
f6557d5e 161 ret = *links;
c9987633 162
fec2e513 163 if(ret)
f6557d5e 164 *links = ret->next;
c9987633
VS
165
166 return ret;
167}
168
e97908ee
VS
169static void insert_inout(AVFilterInOut **inouts, AVFilterInOut *element)
170{
171 element->next = *inouts;
172 *inouts = element;
173}
c9987633
VS
174
175static int link_filter_inouts(AVFilterContext *filter,
7f9b3266
SS
176 AVFilterInOut **curr_inputs,
177 AVFilterInOut **open_inputs, AVClass *log_ctx)
c9987633 178{
90ed076c 179 int pad = filter->input_count;
c9987633 180
4fd9d074 181 while(pad--) {
7f9b3266 182 AVFilterInOut *p = *curr_inputs;
c9987633
VS
183 if(!p) {
184 av_log(log_ctx, AV_LOG_ERROR,
185 "Not enough inputs specified for the \"%s\" filter.\n",
089d3714 186 filter->filter->name);
c9987633
VS
187 return -1;
188 }
189
7f9b3266 190 *curr_inputs = (*curr_inputs)->next;
4d11beb2 191
c9987633
VS
192 if(p->filter) {
193 if(link_filter(p->filter, p->pad_idx, filter, pad, log_ctx))
194 return -1;
64b164f4 195 av_free(p->name);
c9987633
VS
196 av_free(p);
197 } else {
c9987633
VS
198 p->filter = filter;
199 p->pad_idx = pad;
7f9b3266 200 insert_inout(open_inputs, p);
c9987633
VS
201 }
202 }
203
7f9b3266 204 if(*curr_inputs) {
c9987633
VS
205 av_log(log_ctx, AV_LOG_ERROR,
206 "Too many inputs specified for the \"%s\" filter.\n",
089d3714 207 filter->filter->name);
c9987633
VS
208 return -1;
209 }
210
211 pad = filter->output_count;
4fd9d074 212 while(pad--) {
c956dd43 213 AVFilterInOut *currlinkn = av_mallocz(sizeof(AVFilterInOut));
c9987633
VS
214 currlinkn->filter = filter;
215 currlinkn->pad_idx = pad;
7f9b3266 216 insert_inout(curr_inputs, currlinkn);
c9987633
VS
217 }
218
219 return 0;
220}
221
7f9b3266
SS
222static int parse_inputs(const char **buf, AVFilterInOut **curr_inputs,
223 AVFilterInOut **open_outputs, AVClass *log_ctx)
27afb09d 224{
c9987633 225 int pad = 0;
c9987633 226
487c0e67 227 while(**buf == '[') {
bd80b349 228 char *name = parse_link_name(buf, log_ctx);
b2ac16da 229 AVFilterInOut *match;
22260824 230
a4501887 231 if(!name)
22260824 232 return -1;
22260824 233
7f9b3266
SS
234 /* First check if the label is not in the open_outputs list */
235 match = extract_inout(name, open_outputs);
cf4f7d38 236
b2ac16da 237 if(match) {
64fbf5e2 238 av_free(name);
0de3407b
VS
239 } else {
240 /* Not in the list, so add it as an input */
c880791f
VS
241 match = av_mallocz(sizeof(AVFilterInOut));
242 match->name = name;
c880791f 243 match->pad_idx = pad;
cf4f7d38 244 }
e97908ee 245
7f9b3266 246 insert_inout(curr_inputs, match);
e97908ee 247
fd548e5b 248 *buf += strspn(*buf, WHITESPACES);
c9987633 249 pad++;
27afb09d 250 }
cf4f7d38 251
27afb09d
VS
252 return pad;
253}
254
7f9b3266
SS
255static int parse_outputs(const char **buf, AVFilterInOut **curr_inputs,
256 AVFilterInOut **open_inputs,
257 AVFilterInOut **open_outputs, AVClass *log_ctx)
9710beaf 258{
c9987633
VS
259 int pad = 0;
260
487c0e67 261 while(**buf == '[') {
bd80b349 262 char *name = parse_link_name(buf, log_ctx);
c9987633
VS
263 AVFilterInOut *match;
264
7f9b3266
SS
265 AVFilterInOut *input = *curr_inputs;
266 *curr_inputs = (*curr_inputs)->next;
443c10ef 267
c9987633
VS
268 if(!name)
269 return -1;
270
7f9b3266
SS
271 /* First check if the label is not in the open_inputs list */
272 match = extract_inout(name, open_inputs);
c9987633 273
0de3407b 274 if(match) {
7baa6210 275 if(link_filter(input->filter, input->pad_idx,
c9987633
VS
276 match->filter, match->pad_idx, log_ctx) < 0)
277 return -1;
64b164f4
VS
278 av_free(match->name);
279 av_free(name);
c9987633 280 av_free(match);
7baa6210 281 av_free(input);
0de3407b 282 } else {
7f9b3266 283 /* Not in the list, so add the first input as a open_output */
7baa6210 284 input->name = name;
7f9b3266 285 insert_inout(open_outputs, input);
c9987633 286 }
fd548e5b 287 *buf += strspn(*buf, WHITESPACES);
c9987633 288 pad++;
8095a014 289 }
9710beaf 290
c9987633
VS
291 return pad;
292}
9710beaf 293
86a47378 294int avfilter_graph_parse(AVFilterGraph *graph, const char *filters,
7f9b3266
SS
295 AVFilterInOut *open_inputs,
296 AVFilterInOut *open_outputs, AVClass *log_ctx)
27afb09d 297{
27afb09d
VS
298 int index = 0;
299 char chr = 0;
27afb09d 300
7f9b3266 301 AVFilterInOut *curr_inputs = NULL;
27afb09d 302
27afb09d 303 do {
9710beaf 304 AVFilterContext *filter;
fd548e5b 305 filters += strspn(filters, WHITESPACES);
27afb09d 306
7f9b3266 307 if(parse_inputs(&filters, &curr_inputs, &open_outputs, log_ctx) < 0)
27afb09d
VS
308 goto fail;
309
5e600185
VS
310 filter = parse_filter(&filters, graph, index, log_ctx);
311
312 if(!filter)
22260824
VS
313 goto fail;
314
7f9b3266 315 if(filter->input_count == 1 && !curr_inputs && !index) {
e916c2ac 316 /* First input can be omitted if it is "[in]" */
c9987633 317 const char *tmp = "[in]";
7f9b3266 318 if(parse_inputs(&tmp, &curr_inputs, &open_outputs, log_ctx) < 0)
27afb09d 319 goto fail;
27afb09d
VS
320 }
321
7f9b3266 322 if(link_filter_inouts(filter, &curr_inputs, &open_inputs, log_ctx) < 0)
c9987633 323 goto fail;
da790674 324
7f9b3266 325 if(parse_outputs(&filters, &curr_inputs, &open_inputs, &open_outputs,
e2b5fdaf 326 log_ctx) < 0)
e84f0b62
VS
327 goto fail;
328
fd548e5b 329 filters += strspn(filters, WHITESPACES);
27afb09d 330 chr = *filters++;
27afb09d 331
7f9b3266 332 if(chr == ';' && curr_inputs) {
c9987633
VS
333 av_log(log_ctx, AV_LOG_ERROR,
334 "Could not find a output to link when parsing \"%s\"\n",
335 filters - 1);
336 goto fail;
27afb09d 337 }
c9987633 338 index++;
487c0e67 339 } while(chr == ',' || chr == ';');
27afb09d 340
fd51ff16 341 if (chr) {
78471234
SS
342 av_log(log_ctx, AV_LOG_ERROR,
343 "Unable to parse graph description substring: \"%s\"\n",
344 filters - 1);
345 goto fail;
346 }
347
7f9b3266 348 if(open_inputs && !strcmp(open_inputs->name, "out") && curr_inputs) {
e916c2ac 349 /* Last output can be omitted if it is "[out]" */
c9987633 350 const char *tmp = "[out]";
7f9b3266
SS
351 if(parse_outputs(&tmp, &curr_inputs, &open_inputs,
352 &open_outputs, log_ctx) < 0)
27afb09d 353 goto fail;
27afb09d
VS
354 }
355
356 return 0;
357
358 fail:
d7dbe558 359 avfilter_graph_destroy(graph);
7f9b3266
SS
360 free_inout(open_inputs);
361 free_inout(open_outputs);
362 free_inout(curr_inputs);
27afb09d
VS
363 return -1;
364}