7e25282d0de874d9365667f993e14fbe3fad3c07
3 * Copyright (c) 2008 Vitor Sessak
4 * Copyright (c) 2007 Bobby Bingham
6 * This file is part of FFmpeg.
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.
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.
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
26 #include "libavutil/avstring.h"
27 #include "libavutil/mem.h"
30 #define WHITESPACES " \n\t"
33 * Link two filters together.
35 * @see avfilter_link()
37 static int link_filter(AVFilterContext
*src
, int srcpad
,
38 AVFilterContext
*dst
, int dstpad
,
42 if ((ret
= avfilter_link(src
, srcpad
, dst
, dstpad
))) {
43 av_log(log_ctx
, AV_LOG_ERROR
,
44 "Cannot create the link %s:%d -> %s:%d\n",
45 src
->filter
->name
, srcpad
, dst
->filter
->name
, dstpad
);
53 * Parse the name of a link, which has the format "[linkname]".
55 * @return a pointer (that need to be freed after use) to the name
58 static char *parse_link_name(const char **buf
, void *log_ctx
)
60 const char *start
= *buf
;
64 name
= av_get_token(buf
, "]");
67 av_log(log_ctx
, AV_LOG_ERROR
,
68 "Bad (empty?) label found in the following: \"%s\".\n", start
);
72 if (*(*buf
)++ != ']') {
73 av_log(log_ctx
, AV_LOG_ERROR
,
74 "Mismatched '[' found in the following: \"%s\".\n", start
);
83 * Create an instance of a filter, initialize and insert it in the
84 * filtergraph in *ctx.
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
94 static int create_filter(AVFilterContext
**filt_ctx
, AVFilterGraph
*ctx
, int index
,
95 const char *filt_name
, const char *args
, void *log_ctx
)
99 char *tmp_args
= NULL
;
102 snprintf(inst_name
, sizeof(inst_name
), "Parsed_%s_%d", filt_name
, index
);
104 filt
= avfilter_get_by_name(filt_name
);
107 av_log(log_ctx
, AV_LOG_ERROR
,
108 "No such filter: '%s'\n", filt_name
);
109 return AVERROR(EINVAL
);
112 *filt_ctx
= avfilter_graph_alloc_filter(ctx
, filt
, inst_name
);
114 av_log(log_ctx
, AV_LOG_ERROR
,
115 "Error creating filter '%s'\n", filt_name
);
116 return AVERROR(ENOMEM
);
119 if (!strcmp(filt_name
, "scale") && args
&& !strstr(args
, "flags") &&
120 ctx
->scale_sws_opts
) {
121 tmp_args
= av_asprintf("%s:%s",
122 args
, ctx
->scale_sws_opts
);
124 return AVERROR(ENOMEM
);
128 ret
= avfilter_init_str(*filt_ctx
, args
);
130 av_log(log_ctx
, AV_LOG_ERROR
,
131 "Error initializing filter '%s'", filt_name
);
133 av_log(log_ctx
, AV_LOG_ERROR
, " with args '%s'", args
);
134 av_log(log_ctx
, AV_LOG_ERROR
, "\n");
135 avfilter_free(*filt_ctx
);
144 * Parse a string of the form FILTER_NAME[=PARAMS], and create a
145 * corresponding filter instance which is added to graph with
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
159 static int parse_filter(AVFilterContext
**filt_ctx
, const char **buf
, AVFilterGraph
*graph
,
160 int index
, void *log_ctx
)
163 char *name
= av_get_token(buf
, "=,;[\n");
168 opts
= av_get_token(buf
, "[],;\n");
171 ret
= create_filter(filt_ctx
, graph
, index
, name
, opts
, log_ctx
);
177 AVFilterInOut
*avfilter_inout_alloc(void)
179 return av_mallocz(sizeof(AVFilterInOut
));
182 void avfilter_inout_free(AVFilterInOut
**inout
)
185 AVFilterInOut
*next
= (*inout
)->next
;
186 av_freep(&(*inout
)->name
);
192 static AVFilterInOut
*extract_inout(const char *label
, AVFilterInOut
**links
)
196 while (*links
&& (!(*links
)->name
|| strcmp((*links
)->name
, label
)))
197 links
= &((*links
)->next
);
209 static void insert_inout(AVFilterInOut
**inouts
, AVFilterInOut
*element
)
211 element
->next
= *inouts
;
215 static void append_inout(AVFilterInOut
**inouts
, AVFilterInOut
**element
)
217 while (*inouts
&& (*inouts
)->next
)
218 inouts
= &((*inouts
)->next
);
223 (*inouts
)->next
= *element
;
227 static int link_filter_inouts(AVFilterContext
*filt_ctx
,
228 AVFilterInOut
**curr_inputs
,
229 AVFilterInOut
**open_inputs
, void *log_ctx
)
233 for (pad
= 0; pad
< filt_ctx
->nb_inputs
; pad
++) {
234 AVFilterInOut
*p
= *curr_inputs
;
237 *curr_inputs
= (*curr_inputs
)->next
;
239 } else if (!(p
= av_mallocz(sizeof(*p
))))
240 return AVERROR(ENOMEM
);
243 ret
= link_filter(p
->filter_ctx
, p
->pad_idx
, filt_ctx
, pad
, log_ctx
);
249 p
->filter_ctx
= filt_ctx
;
251 append_inout(open_inputs
, &p
);
256 av_log(log_ctx
, AV_LOG_ERROR
,
257 "Too many inputs specified for the \"%s\" filter.\n",
258 filt_ctx
->filter
->name
);
259 return AVERROR(EINVAL
);
262 pad
= filt_ctx
->nb_outputs
;
264 AVFilterInOut
*currlinkn
= av_mallocz(sizeof(AVFilterInOut
));
266 return AVERROR(ENOMEM
);
267 currlinkn
->filter_ctx
= filt_ctx
;
268 currlinkn
->pad_idx
= pad
;
269 insert_inout(curr_inputs
, currlinkn
);
275 static int parse_inputs(const char **buf
, AVFilterInOut
**curr_inputs
,
276 AVFilterInOut
**open_outputs
, void *log_ctx
)
278 AVFilterInOut
*parsed_inputs
= NULL
;
281 while (**buf
== '[') {
282 char *name
= parse_link_name(buf
, log_ctx
);
283 AVFilterInOut
*match
;
286 return AVERROR(EINVAL
);
288 /* First check if the label is not in the open_outputs list */
289 match
= extract_inout(name
, open_outputs
);
294 /* Not in the list, so add it as an input */
295 if (!(match
= av_mallocz(sizeof(AVFilterInOut
)))) {
297 return AVERROR(ENOMEM
);
300 match
->pad_idx
= pad
;
303 append_inout(&parsed_inputs
, &match
);
305 *buf
+= strspn(*buf
, WHITESPACES
);
309 append_inout(&parsed_inputs
, curr_inputs
);
310 *curr_inputs
= parsed_inputs
;
315 static int parse_outputs(const char **buf
, AVFilterInOut
**curr_inputs
,
316 AVFilterInOut
**open_inputs
,
317 AVFilterInOut
**open_outputs
, void *log_ctx
)
321 while (**buf
== '[') {
322 char *name
= parse_link_name(buf
, log_ctx
);
323 AVFilterInOut
*match
;
325 AVFilterInOut
*input
= *curr_inputs
;
328 return AVERROR(EINVAL
);
331 av_log(log_ctx
, AV_LOG_ERROR
,
332 "No output pad can be associated to link label '%s'.\n", name
);
334 return AVERROR(EINVAL
);
336 *curr_inputs
= (*curr_inputs
)->next
;
338 /* First check if the label is not in the open_inputs list */
339 match
= extract_inout(name
, open_inputs
);
342 if ((ret
= link_filter(input
->filter_ctx
, input
->pad_idx
,
343 match
->filter_ctx
, match
->pad_idx
, log_ctx
)) < 0) {
347 av_free(match
->name
);
352 /* Not in the list, so add the first input as a open_output */
354 insert_inout(open_outputs
, input
);
356 *buf
+= strspn(*buf
, WHITESPACES
);
363 static int parse_sws_flags(const char **buf
, AVFilterGraph
*graph
)
365 char *p
= strchr(*buf
, ';');
367 if (strncmp(*buf
, "sws_flags=", 10))
371 av_log(graph
, AV_LOG_ERROR
, "sws_flags not terminated with ';'.\n");
372 return AVERROR(EINVAL
);
375 *buf
+= 4; // keep the 'flags=' part
377 av_freep(&graph
->scale_sws_opts
);
378 if (!(graph
->scale_sws_opts
= av_mallocz(p
- *buf
+ 1)))
379 return AVERROR(ENOMEM
);
380 av_strlcpy(graph
->scale_sws_opts
, *buf
, p
- *buf
+ 1);
386 int avfilter_graph_parse2(AVFilterGraph
*graph
, const char *filters
,
387 AVFilterInOut
**inputs
,
388 AVFilterInOut
**outputs
)
390 int index
= 0, ret
= 0;
393 AVFilterInOut
*curr_inputs
= NULL
, *open_inputs
= NULL
, *open_outputs
= NULL
;
395 filters
+= strspn(filters
, WHITESPACES
);
397 if ((ret
= parse_sws_flags(&filters
, graph
)) < 0)
401 AVFilterContext
*filter
;
402 filters
+= strspn(filters
, WHITESPACES
);
404 if ((ret
= parse_inputs(&filters
, &curr_inputs
, &open_outputs
, graph
)) < 0)
406 if ((ret
= parse_filter(&filter
, &filters
, graph
, index
, graph
)) < 0)
410 if ((ret
= link_filter_inouts(filter
, &curr_inputs
, &open_inputs
, graph
)) < 0)
413 if ((ret
= parse_outputs(&filters
, &curr_inputs
, &open_inputs
, &open_outputs
,
417 filters
+= strspn(filters
, WHITESPACES
);
420 if (chr
== ';' && curr_inputs
)
421 append_inout(&open_outputs
, &curr_inputs
);
423 } while (chr
== ',' || chr
== ';');
426 av_log(graph
, AV_LOG_ERROR
,
427 "Unable to parse graph description substring: \"%s\"\n",
429 ret
= AVERROR(EINVAL
);
433 append_inout(&open_outputs
, &curr_inputs
);
436 *inputs
= open_inputs
;
437 *outputs
= open_outputs
;
441 while (graph
->nb_filters
)
442 avfilter_free(graph
->filters
[0]);
443 av_freep(&graph
->filters
);
444 avfilter_inout_free(&open_inputs
);
445 avfilter_inout_free(&open_outputs
);
446 avfilter_inout_free(&curr_inputs
);
454 #if HAVE_INCOMPATIBLE_LIBAV_ABI || !FF_API_OLD_GRAPH_PARSE
455 int avfilter_graph_parse(AVFilterGraph
*graph
, const char *filters
,
456 AVFilterInOut
*open_inputs
,
457 AVFilterInOut
*open_outputs
, void *log_ctx
)
460 AVFilterInOut
*cur
, *match
, *inputs
= NULL
, *outputs
= NULL
;
462 if ((ret
= avfilter_graph_parse2(graph
, filters
, &inputs
, &outputs
)) < 0)
465 /* First input can be omitted if it is "[in]" */
466 if (inputs
&& !inputs
->name
)
467 inputs
->name
= av_strdup("in");
468 for (cur
= inputs
; cur
; cur
= cur
->next
) {
470 av_log(log_ctx
, AV_LOG_ERROR
,
471 "Not enough inputs specified for the \"%s\" filter.\n",
472 cur
->filter_ctx
->filter
->name
);
473 ret
= AVERROR(EINVAL
);
476 if (!(match
= extract_inout(cur
->name
, &open_outputs
)))
478 ret
= avfilter_link(match
->filter_ctx
, match
->pad_idx
,
479 cur
->filter_ctx
, cur
->pad_idx
);
480 avfilter_inout_free(&match
);
485 /* Last output can be omitted if it is "[out]" */
486 if (outputs
&& !outputs
->name
)
487 outputs
->name
= av_strdup("out");
488 for (cur
= outputs
; cur
; cur
= cur
->next
) {
490 av_log(log_ctx
, AV_LOG_ERROR
,
491 "Invalid filterchain containing an unlabelled output pad: \"%s\"\n",
493 ret
= AVERROR(EINVAL
);
496 if (!(match
= extract_inout(cur
->name
, &open_inputs
)))
498 ret
= avfilter_link(cur
->filter_ctx
, cur
->pad_idx
,
499 match
->filter_ctx
, match
->pad_idx
);
500 avfilter_inout_free(&match
);
507 while (graph
->nb_filters
)
508 avfilter_free(graph
->filters
[0]);
509 av_freep(&graph
->filters
);
511 avfilter_inout_free(&inputs
);
512 avfilter_inout_free(&outputs
);
513 avfilter_inout_free(&open_inputs
);
514 avfilter_inout_free(&open_outputs
);
517 int avfilter_graph_parse(AVFilterGraph
*graph
, const char *filters
,
518 AVFilterInOut
**inputs
, AVFilterInOut
**outputs
,
521 return avfilter_graph_parse_ptr(graph
, filters
, inputs
, outputs
, log_ctx
);
525 int avfilter_graph_parse_ptr(AVFilterGraph
*graph
, const char *filters
,
526 AVFilterInOut
**open_inputs_ptr
, AVFilterInOut
**open_outputs_ptr
,
529 int index
= 0, ret
= 0;
532 AVFilterInOut
*curr_inputs
= NULL
;
533 AVFilterInOut
*open_inputs
= open_inputs_ptr
? *open_inputs_ptr
: NULL
;
534 AVFilterInOut
*open_outputs
= open_outputs_ptr
? *open_outputs_ptr
: NULL
;
536 if ((ret
= parse_sws_flags(&filters
, graph
)) < 0)
540 AVFilterContext
*filter
;
541 const char *filterchain
= filters
;
542 filters
+= strspn(filters
, WHITESPACES
);
544 if ((ret
= parse_inputs(&filters
, &curr_inputs
, &open_outputs
, log_ctx
)) < 0)
547 if ((ret
= parse_filter(&filter
, &filters
, graph
, index
, log_ctx
)) < 0)
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)
557 if ((ret
= link_filter_inouts(filter
, &curr_inputs
, &open_inputs
, log_ctx
)) < 0)
560 if ((ret
= parse_outputs(&filters
, &curr_inputs
, &open_inputs
, &open_outputs
,
564 filters
+= strspn(filters
, WHITESPACES
);
567 if (chr
== ';' && curr_inputs
) {
568 av_log(log_ctx
, AV_LOG_ERROR
,
569 "Invalid filterchain containing an unlabelled output pad: \"%s\"\n",
571 ret
= AVERROR(EINVAL
);
575 } while (chr
== ',' || chr
== ';');
578 av_log(log_ctx
, AV_LOG_ERROR
,
579 "Unable to parse graph description substring: \"%s\"\n",
581 ret
= AVERROR(EINVAL
);
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
,
594 /* clear open_in/outputs only if not passed as parameters */
595 if (open_inputs_ptr
) *open_inputs_ptr
= open_inputs
;
596 else avfilter_inout_free(&open_inputs
);
597 if (open_outputs_ptr
) *open_outputs_ptr
= open_outputs
;
598 else avfilter_inout_free(&open_outputs
);
599 avfilter_inout_free(&curr_inputs
);
602 while (graph
->nb_filters
)
603 avfilter_free(graph
->filters
[0]);
604 av_freep(&graph
->filters
);