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 <string.h>
24 #include <stdio.h>
25
29
30 #define WHITESPACES " \n\t"
31
32 /**
33 * Link two filters together.
34 *
35 * @see avfilter_link()
36 */
39 void *log_ctx)
40 {
44 "Cannot create the link %s:%d -> %s:%d\n",
47 }
48
49 return 0;
50 }
51
52 /**
53 * Parse the name of a link, which has the format "[linkname]".
54 *
55 * @return a pointer (that need to be freed after use) to the name
56 * between parenthesis
57 */
59 {
62 (*buf)++;
63
65
66 if (!name[0]) {
68 "Bad (empty?) label found in the following: \"%s\".\n", start);
69 goto fail;
70 }
71
72 if (*(*buf)++ != ']') {
74 "Mismatched '[' found in the following: \"%s\".\n", start);
75 fail:
77 }
78
80 }
81
82 /**
83 * Create an instance of a filter, initialize and insert it in the
84 * filtergraph in *ctx.
85 *
86 * @param filt_ctx put here a filter context in case of successful creation and configuration, NULL otherwise.
87 * @param ctx the filtergraph context
88 * @param index an index which is supposed to be unique for each filter instance added to the filtergraph
89 * @param filt_name the name of the filter to create
90 * @param args the arguments provided to the filter during its initialization
91 * @param log_ctx the log context to use
92 * @return >= 0 in case of success, a negative AVERROR code otherwise
93 */
95 const char *filt_name,
const char *
args,
void *log_ctx)
96 {
98 char inst_name[30];
99 char *tmp_args = NULL;
101
102 snprintf(inst_name,
sizeof(inst_name),
"Parsed_%s_%d", filt_name, index);
103
105
106 if (!filt) {
108 "No such filter: '%s'\n", filt_name);
110 }
111
113 if (!*filt_ctx) {
115 "Error creating filter '%s'\n", filt_name);
117 }
118
119 if (!strcmp(filt_name, "scale") && args && !strstr(args, "flags") &&
123 if (!tmp_args)
125 args = tmp_args;
126 }
127
129 if (ret < 0) {
131 "Error initializing filter '%s'", filt_name);
132 if (args)
136 *filt_ctx = NULL;
137 }
138
141 }
142
143 /**
144 * Parse a string of the form FILTER_NAME[=PARAMS], and create a
145 * corresponding filter instance which is added to graph with
146 * create_filter().
147 *
148 * @param filt_ctx Pointer that is set to the created and configured filter
149 * context on success, set to NULL on failure.
150 * @param filt_ctx put here a pointer to the created filter context on
151 * success, NULL otherwise
152 * @param buf pointer to the buffer to parse, *buf will be updated to
153 * point to the char next after the parsed string
154 * @param index an index which is assigned to the created filter
155 * instance, and which is supposed to be unique for each filter
156 * instance added to the filtergraph
157 * @return >= 0 in case of success, a negative AVERROR code otherwise
158 */
160 int index,
void *log_ctx)
161 {
162 char *opts = NULL;
165
166 if (**buf == '=') {
167 (*buf)++;
169 }
170
171 ret =
create_filter(filt_ctx, graph, index, name, opts, log_ctx);
175 }
176
178 {
180 }
181
183 {
184 while (*inout) {
188 *inout = next;
189 }
190 }
191
193 {
195
196 while (*links && (!(*links)->name || strcmp((*links)->name, label)))
197 links = &((*links)->next);
198
199 ret = *links;
200
201 if (ret) {
204 }
205
207 }
208
210 {
211 element->
next = *inouts;
212 *inouts = element;
213 }
214
216 {
217 while (*inouts && (*inouts)->
next)
218 inouts = &((*inouts)->next);
219
220 if (!*inouts)
221 *inouts = *element;
222 else
223 (*inouts)->
next = *element;
224 *element = NULL;
225 }
226
230 {
232
233 for (pad = 0; pad < filt_ctx->
nb_inputs; pad++) {
235
236 if (p) {
237 *curr_inputs = (*curr_inputs)->
next;
241
246 if (ret < 0)
248 } else {
252 }
253 }
254
255 if (*curr_inputs) {
257 "Too many inputs specified for the \"%s\" filter.\n",
260 }
261
263 while (pad--) {
265 if (!currlinkn)
270 }
271
272 return 0;
273 }
274
277 {
279 int pad = 0;
280
281 while (**buf == '[') {
284
285 if (!name)
287
288 /* First check if the label is not in the open_outputs list */
290
291 if (match) {
293 } else {
294 /* Not in the list, so add it as an input */
298 }
301 }
302
304
306 pad++;
307 }
308
310 *curr_inputs = parsed_inputs;
311
312 return pad;
313 }
314
318 {
320
321 while (**buf == '[') {
324
326
327 if (!name)
329
330 if (!input) {
332 "No output pad can be associated to link label '%s'.\n", name);
335 }
336 *curr_inputs = (*curr_inputs)->
next;
337
338 /* First check if the label is not in the open_inputs list */
340
341 if (match) {
346 }
351 } else {
352 /* Not in the list, so add the first input as a open_output */
355 }
357 pad++;
358 }
359
360 return pad;
361 }
362
364 {
365 char *p = strchr(*buf, ';');
366
367 if (strncmp(*buf, "sws_flags=", 10))
368 return 0;
369
370 if (!p) {
373 }
374
375 *buf += 4; // keep the 'flags=' part
376
381
382 *buf = p + 1;
383 return 0;
384 }
385
389 {
391 char chr = 0;
392
393 AVFilterInOut *curr_inputs = NULL, *open_inputs = NULL, *open_outputs = NULL;
394
396
398 goto fail;
399
400 do {
403
404 if ((
ret =
parse_inputs(&filters, &curr_inputs, &open_outputs, graph)) < 0)
408
409
412
413 if ((
ret =
parse_outputs(&filters, &curr_inputs, &open_inputs, &open_outputs,
414 graph)) < 0)
416
418 chr = *filters++;
419
420 if (chr == ';' && curr_inputs)
422 index++;
423 } while (chr == ',' || chr == ';');
424
425 if (chr) {
427 "Unable to parse graph description substring: \"%s\"\n",
428 filters - 1);
431 }
432
434
435
436 *inputs = open_inputs;
437 *outputs = open_outputs;
438 return 0;
439
447
448 *inputs = NULL;
449 *outputs = NULL;
450
452 }
453
454 #if HAVE_INCOMPATIBLE_LIBAV_ABI || !FF_API_OLD_GRAPH_PARSE
458 {
461
463 goto fail;
464
465 /* First input can be omitted if it is "[in]" */
466 if (inputs && !inputs->
name)
468 for (cur = inputs; cur; cur = cur->
next) {
471 "Not enough inputs specified for the \"%s\" filter.\n",
474 goto fail;
475 }
477 continue;
481 if (ret < 0)
482 goto fail;
483 }
484
485 /* Last output can be omitted if it is "[out]" */
486 if (outputs && !outputs->name)
488 for (cur = outputs; cur; cur = cur->
next) {
491 "Invalid filterchain containing an unlabelled output pad: \"%s\"\n",
492 filters);
494 goto fail;
495 }
497 continue;
501 if (ret < 0)
502 goto fail;
503 }
504
505 fail:
506 if (ret < 0) {
510 }
516 #else
519 void *log_ctx)
520 {
522 #endif
523 }
524
527 void *log_ctx)
528 {
529 int index = 0, ret = 0;
530 char chr = 0;
531
533 AVFilterInOut *open_inputs = open_inputs_ptr ? *open_inputs_ptr : NULL;
534 AVFilterInOut *open_outputs = open_outputs_ptr ? *open_outputs_ptr : NULL;
535
538
539 do {
541 const char *filterchain =
filters;
543
544 if ((ret =
parse_inputs(&filters, &curr_inputs, &open_outputs, log_ctx)) < 0)
546
547 if ((ret =
parse_filter(&filter, &filters, graph, index, log_ctx)) < 0)
549
550 if (filter->
nb_inputs == 1 && !curr_inputs && !index) {
551 /* First input pad, assume it is "[in]" if not specified */
552 const char *tmp = "[in]";
553 if ((ret =
parse_inputs(&tmp, &curr_inputs, &open_outputs, log_ctx)) < 0)
555 }
556
559
560 if ((ret =
parse_outputs(&filters, &curr_inputs, &open_inputs, &open_outputs,
561 log_ctx)) < 0)
563
565 chr = *filters++;
566
567 if (chr == ';' && curr_inputs) {
569 "Invalid filterchain containing an unlabelled output pad: \"%s\"\n",
570 filterchain);
573 }
574 index++;
575 } while (chr == ',' || chr == ';');
576
577 if (chr) {
579 "Unable to parse graph description substring: \"%s\"\n",
580 filters - 1);
583 }
584
585 if (curr_inputs) {
586 /* Last output pad, assume it is "[out]" if not specified */
587 const char *tmp = "[out]";
588 if ((ret =
parse_outputs(&tmp, &curr_inputs, &open_inputs, &open_outputs,
589 log_ctx)) < 0)
591 }
592
594 /* clear open_in/outputs only if not passed as parameters */
595 if (open_inputs_ptr) *open_inputs_ptr = open_inputs;
597 if (open_outputs_ptr) *open_outputs_ptr = open_outputs;
600
601 if (ret < 0) {
605 }
607 }