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 "graphparser.h"
28 #include "avfiltergraph.h"
29 #include "parseutils.h"
31 #define WHITESPACES " \n\t"
33 static int link_filter(AVFilterContext
*src
, int srcpad
,
34 AVFilterContext
*dst
, int dstpad
,
37 if(avfilter_link(src
, srcpad
, dst
, dstpad
)) {
38 av_log(log_ctx
, AV_LOG_ERROR
,
39 "cannot create the link %s:%d -> %s:%d\n",
40 src
->filter
->name
, srcpad
, dst
->filter
->name
, dstpad
);
49 * @param name a pointer (that need to be free'd after use) to the name between
52 static char *parse_link_name(const char **buf
, AVClass
*log_ctx
)
54 const char *start
= *buf
;
58 name
= av_get_token(buf
, "]");
61 av_log(log_ctx
, AV_LOG_ERROR
,
62 "Bad (empty?) label found in the following: \"%s\".\n", start
);
66 if(*(*buf
)++ != ']') {
67 av_log(log_ctx
, AV_LOG_ERROR
,
68 "Mismatched '[' found in the following: \"%s\".\n", start
);
76 static AVFilterContext
*create_filter(AVFilterGraph
*ctx
, int index
,
77 const char *filt_name
, const char *args
,
80 AVFilterContext
*filt_ctx
;
85 snprintf(inst_name
, sizeof(inst_name
), "Parsed filter %d", index
);
87 filt
= avfilter_get_by_name(filt_name
);
90 av_log(log_ctx
, AV_LOG_ERROR
,
91 "no such filter: '%s'\n", filt_name
);
95 filt_ctx
= avfilter_open(filt
, inst_name
);
97 av_log(log_ctx
, AV_LOG_ERROR
,
98 "error creating filter '%s'\n", filt_name
);
102 if(avfilter_graph_add_filter(ctx
, filt_ctx
) < 0) {
103 avfilter_destroy(filt_ctx
);
107 if(avfilter_init_filter(filt_ctx
, args
, NULL
)) {
108 av_log(log_ctx
, AV_LOG_ERROR
,
109 "error initializing filter '%s' with args '%s'\n", filt_name
, args
);
117 * Parse "filter=params"
119 static AVFilterContext
*parse_filter(const char **buf
, AVFilterGraph
*graph
,
120 int index
, AVClass
*log_ctx
)
123 char *name
= av_get_token(buf
, "=,[");
124 AVFilterContext
*ret
;
128 opts
= av_get_token(buf
, "[],\n");
131 ret
= create_filter(graph
, index
, name
, opts
, log_ctx
);
137 static void free_inout(AVFilterInOut
*head
)
140 AVFilterInOut
*next
= head
->next
;
147 static AVFilterInOut
*extract_inout(const char *label
, AVFilterInOut
**links
)
151 while(*links
&& strcmp((*links
)->name
, label
))
152 links
= &((*links
)->next
);
162 static void insert_inout(AVFilterInOut
**inouts
, AVFilterInOut
*element
)
164 element
->next
= *inouts
;
168 static int link_filter_inouts(AVFilterContext
*filter
,
169 AVFilterInOut
**curr_inputs
,
170 AVFilterInOut
**open_inputs
, AVClass
*log_ctx
)
172 int pad
= filter
->input_count
;
175 AVFilterInOut
*p
= *curr_inputs
;
177 av_log(log_ctx
, AV_LOG_ERROR
,
178 "Not enough inputs specified for the \"%s\" filter.\n",
179 filter
->filter
->name
);
183 *curr_inputs
= (*curr_inputs
)->next
;
186 if(link_filter(p
->filter
, p
->pad_idx
, filter
, pad
, log_ctx
))
193 insert_inout(open_inputs
, p
);
198 av_log(log_ctx
, AV_LOG_ERROR
,
199 "Too many inputs specified for the \"%s\" filter.\n",
200 filter
->filter
->name
);
204 pad
= filter
->output_count
;
206 AVFilterInOut
*currlinkn
= av_mallocz(sizeof(AVFilterInOut
));
207 currlinkn
->filter
= filter
;
208 currlinkn
->pad_idx
= pad
;
209 insert_inout(curr_inputs
, currlinkn
);
215 static int parse_inputs(const char **buf
, AVFilterInOut
**curr_inputs
,
216 AVFilterInOut
**open_outputs
, AVClass
*log_ctx
)
220 while(**buf
== '[') {
221 char *name
= parse_link_name(buf
, log_ctx
);
222 AVFilterInOut
*match
;
227 /* First check if the label is not in the open_outputs list */
228 match
= extract_inout(name
, open_outputs
);
233 /* Not in the list, so add it as an input */
234 match
= av_mallocz(sizeof(AVFilterInOut
));
236 match
->pad_idx
= pad
;
239 insert_inout(curr_inputs
, match
);
241 *buf
+= strspn(*buf
, WHITESPACES
);
248 static int parse_outputs(const char **buf
, AVFilterInOut
**curr_inputs
,
249 AVFilterInOut
**open_inputs
,
250 AVFilterInOut
**open_outputs
, AVClass
*log_ctx
)
254 while(**buf
== '[') {
255 char *name
= parse_link_name(buf
, log_ctx
);
256 AVFilterInOut
*match
;
258 AVFilterInOut
*input
= *curr_inputs
;
259 *curr_inputs
= (*curr_inputs
)->next
;
264 /* First check if the label is not in the open_inputs list */
265 match
= extract_inout(name
, open_inputs
);
268 if(link_filter(input
->filter
, input
->pad_idx
,
269 match
->filter
, match
->pad_idx
, log_ctx
) < 0)
271 av_free(match
->name
);
276 /* Not in the list, so add the first input as a open_output */
278 insert_inout(open_outputs
, input
);
280 *buf
+= strspn(*buf
, WHITESPACES
);
287 int avfilter_graph_parse(AVFilterGraph
*graph
, const char *filters
,
288 AVFilterInOut
*open_inputs
,
289 AVFilterInOut
*open_outputs
, AVClass
*log_ctx
)
294 AVFilterInOut
*curr_inputs
= NULL
;
297 AVFilterContext
*filter
;
298 filters
+= strspn(filters
, WHITESPACES
);
300 if(parse_inputs(&filters
, &curr_inputs
, &open_outputs
, log_ctx
) < 0)
303 filter
= parse_filter(&filters
, graph
, index
, log_ctx
);
308 if(filter
->input_count
== 1 && !curr_inputs
&& !index
) {
309 /* First input can be omitted if it is "[in]" */
310 const char *tmp
= "[in]";
311 if(parse_inputs(&tmp
, &curr_inputs
, &open_outputs
, log_ctx
) < 0)
315 if(link_filter_inouts(filter
, &curr_inputs
, &open_inputs
, log_ctx
) < 0)
318 if(parse_outputs(&filters
, &curr_inputs
, &open_inputs
, &open_outputs
,
322 filters
+= strspn(filters
, WHITESPACES
);
325 if(chr
== ';' && curr_inputs
) {
326 av_log(log_ctx
, AV_LOG_ERROR
,
327 "Could not find a output to link when parsing \"%s\"\n",
332 } while(chr
== ',' || chr
== ';');
335 av_log(log_ctx
, AV_LOG_ERROR
,
336 "Unable to parse graph description substring: \"%s\"\n",
341 if(open_inputs
&& !strcmp(open_inputs
->name
, "out") && curr_inputs
) {
342 /* Last output can be omitted if it is "[out]" */
343 const char *tmp
= "[out]";
344 if(parse_outputs(&tmp
, &curr_inputs
, &open_inputs
,
345 &open_outputs
, log_ctx
) < 0)
352 avfilter_graph_destroy(graph
);
353 free_inout(open_inputs
);
354 free_inout(open_outputs
);
355 free_inout(curr_inputs
);