Line | Branch | Exec | Source |
---|---|---|---|
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 | |||
26 | #include "libavutil/avstring.h" | ||
27 | #include "libavutil/dict.h" | ||
28 | #include "libavutil/mem.h" | ||
29 | #include "libavutil/opt.h" | ||
30 | |||
31 | #include "avfilter.h" | ||
32 | #include "avfilter_internal.h" | ||
33 | #include "internal.h" | ||
34 | |||
35 | #define WHITESPACES " \n\t\r" | ||
36 | |||
37 | /** | ||
38 | * Parse the name of a link, which has the format "[linkname]". | ||
39 | * | ||
40 | * @return a pointer (that need to be freed after use) to the name | ||
41 | * between parenthesis | ||
42 | */ | ||
43 | 695 | static char *parse_link_name(const char **buf, void *log_ctx) | |
44 | { | ||
45 | 695 | const char *start = *buf; | |
46 | char *name; | ||
47 | 695 | (*buf)++; | |
48 | |||
49 | 695 | name = av_get_token(buf, "]"); | |
50 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 695 times.
|
695 | if (!name) |
51 | ✗ | return NULL; | |
52 | |||
53 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 695 times.
|
695 | if (!name[0]) { |
54 | ✗ | av_log(log_ctx, AV_LOG_ERROR, | |
55 | "Bad (empty?) label found in the following: \"%s\".\n", start); | ||
56 | ✗ | goto fail; | |
57 | } | ||
58 | |||
59 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 695 times.
|
695 | if (**buf != ']') { |
60 | ✗ | av_log(log_ctx, AV_LOG_ERROR, | |
61 | "Mismatched '[' found in the following: \"%s\".\n", start); | ||
62 | ✗ | fail: | |
63 | ✗ | av_freep(&name); | |
64 | ✗ | return NULL; | |
65 | } | ||
66 | 695 | (*buf)++; | |
67 | |||
68 | 695 | return name; | |
69 | } | ||
70 | |||
71 | ✗ | AVFilterInOut *avfilter_inout_alloc(void) | |
72 | { | ||
73 | ✗ | return av_mallocz(sizeof(AVFilterInOut)); | |
74 | } | ||
75 | |||
76 | 25790 | void avfilter_inout_free(AVFilterInOut **inout) | |
77 | { | ||
78 |
2/2✓ Branch 0 taken 25793 times.
✓ Branch 1 taken 25790 times.
|
51583 | while (*inout) { |
79 | 25793 | AVFilterInOut *next = (*inout)->next; | |
80 | 25793 | av_freep(&(*inout)->name); | |
81 | 25793 | av_freep(inout); | |
82 | 25793 | *inout = next; | |
83 | } | ||
84 | 25790 | } | |
85 | |||
86 | 45 | static AVFilterInOut *extract_inout(const char *label, AVFilterInOut **links) | |
87 | { | ||
88 | AVFilterInOut *ret; | ||
89 | |||
90 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
45 | while (*links && (!(*links)->name || strcmp((*links)->name, label))) |
91 | ✗ | links = &((*links)->next); | |
92 | |||
93 | 45 | ret = *links; | |
94 | |||
95 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
|
45 | if (ret) { |
96 | ✗ | *links = ret->next; | |
97 | ✗ | ret->next = NULL; | |
98 | } | ||
99 | |||
100 | 45 | return ret; | |
101 | } | ||
102 | |||
103 | 25838 | static void append_inout(AVFilterInOut **inouts, AVFilterInOut **element) | |
104 | { | ||
105 |
4/4✓ Branch 0 taken 588 times.
✓ Branch 1 taken 25594 times.
✓ Branch 2 taken 344 times.
✓ Branch 3 taken 244 times.
|
26182 | while (*inouts && (*inouts)->next) |
106 | 344 | inouts = &((*inouts)->next); | |
107 | |||
108 |
2/2✓ Branch 0 taken 25594 times.
✓ Branch 1 taken 244 times.
|
25838 | if (!*inouts) |
109 | 25594 | *inouts = *element; | |
110 | else | ||
111 | 244 | (*inouts)->next = *element; | |
112 | 25838 | *element = NULL; | |
113 | 25838 | } | |
114 | |||
115 | 12852 | static int parse_sws_flags(const char **buf, char **dst, void *log_ctx) | |
116 | { | ||
117 | 12852 | char *p = strchr(*buf, ';'); | |
118 | |||
119 |
2/2✓ Branch 0 taken 12803 times.
✓ Branch 1 taken 49 times.
|
12852 | if (strncmp(*buf, "sws_flags=", 10)) |
120 | 12803 | return 0; | |
121 | |||
122 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 49 times.
|
49 | if (!p) { |
123 | ✗ | av_log(log_ctx, AV_LOG_ERROR, "sws_flags not terminated with ';'.\n"); | |
124 | ✗ | return AVERROR(EINVAL); | |
125 | } | ||
126 | |||
127 | 49 | *buf += 4; // keep the 'flags=' part | |
128 | |||
129 | 49 | av_freep(dst); | |
130 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 49 times.
|
49 | if (!(*dst = av_mallocz(p - *buf + 1))) |
131 | ✗ | return AVERROR(ENOMEM); | |
132 | 49 | av_strlcpy(*dst, *buf, p - *buf + 1); | |
133 | |||
134 | 49 | *buf = p + 1; | |
135 | 49 | return 0; | |
136 | } | ||
137 | |||
138 | ✗ | int avfilter_graph_parse2(AVFilterGraph *graph, const char *filters, | |
139 | AVFilterInOut **inputs, | ||
140 | AVFilterInOut **outputs) | ||
141 | { | ||
142 | AVFilterGraphSegment *seg; | ||
143 | int ret; | ||
144 | |||
145 | ✗ | ret = avfilter_graph_segment_parse(graph, filters, 0, &seg); | |
146 | ✗ | if (ret < 0) | |
147 | ✗ | return ret; | |
148 | |||
149 | ✗ | ret = avfilter_graph_segment_apply(seg, 0, inputs, outputs); | |
150 | ✗ | avfilter_graph_segment_free(&seg); | |
151 | ✗ | if (ret < 0) | |
152 | ✗ | goto end; | |
153 | |||
154 | ✗ | return 0; | |
155 | |||
156 | ✗ | end: | |
157 | ✗ | while (graph->nb_filters) | |
158 | ✗ | avfilter_free(graph->filters[0]); | |
159 | ✗ | av_freep(&graph->filters); | |
160 | |||
161 | ✗ | return ret; | |
162 | } | ||
163 | |||
164 | ✗ | int avfilter_graph_parse(AVFilterGraph *graph, const char *filters, | |
165 | AVFilterInOut *open_inputs, | ||
166 | AVFilterInOut *open_outputs, void *log_ctx) | ||
167 | { | ||
168 | int ret; | ||
169 | ✗ | AVFilterInOut *cur, *match, *inputs = NULL, *outputs = NULL; | |
170 | |||
171 | ✗ | if ((ret = avfilter_graph_parse2(graph, filters, &inputs, &outputs)) < 0) | |
172 | ✗ | goto fail; | |
173 | |||
174 | /* First input can be omitted if it is "[in]" */ | ||
175 | ✗ | if (inputs && !inputs->name) | |
176 | ✗ | inputs->name = av_strdup("in"); | |
177 | ✗ | for (cur = inputs; cur; cur = cur->next) { | |
178 | ✗ | if (!cur->name) { | |
179 | ✗ | av_log(log_ctx, AV_LOG_ERROR, | |
180 | "Not enough inputs specified for the \"%s\" filter.\n", | ||
181 | ✗ | cur->filter_ctx->filter->name); | |
182 | ✗ | ret = AVERROR(EINVAL); | |
183 | ✗ | goto fail; | |
184 | } | ||
185 | ✗ | if (!(match = extract_inout(cur->name, &open_outputs))) | |
186 | ✗ | continue; | |
187 | ✗ | ret = avfilter_link(match->filter_ctx, match->pad_idx, | |
188 | ✗ | cur->filter_ctx, cur->pad_idx); | |
189 | ✗ | avfilter_inout_free(&match); | |
190 | ✗ | if (ret < 0) | |
191 | ✗ | goto fail; | |
192 | } | ||
193 | |||
194 | /* Last output can be omitted if it is "[out]" */ | ||
195 | ✗ | if (outputs && !outputs->name) | |
196 | ✗ | outputs->name = av_strdup("out"); | |
197 | ✗ | for (cur = outputs; cur; cur = cur->next) { | |
198 | ✗ | if (!cur->name) { | |
199 | ✗ | av_log(log_ctx, AV_LOG_ERROR, | |
200 | "Invalid filterchain containing an unlabelled output pad: \"%s\"\n", | ||
201 | filters); | ||
202 | ✗ | ret = AVERROR(EINVAL); | |
203 | ✗ | goto fail; | |
204 | } | ||
205 | ✗ | if (!(match = extract_inout(cur->name, &open_inputs))) | |
206 | ✗ | continue; | |
207 | ✗ | ret = avfilter_link(cur->filter_ctx, cur->pad_idx, | |
208 | ✗ | match->filter_ctx, match->pad_idx); | |
209 | ✗ | avfilter_inout_free(&match); | |
210 | ✗ | if (ret < 0) | |
211 | ✗ | goto fail; | |
212 | } | ||
213 | |||
214 | ✗ | fail: | |
215 | ✗ | if (ret < 0) { | |
216 | ✗ | while (graph->nb_filters) | |
217 | ✗ | avfilter_free(graph->filters[0]); | |
218 | ✗ | av_freep(&graph->filters); | |
219 | } | ||
220 | ✗ | avfilter_inout_free(&inputs); | |
221 | ✗ | avfilter_inout_free(&outputs); | |
222 | ✗ | avfilter_inout_free(&open_inputs); | |
223 | ✗ | avfilter_inout_free(&open_outputs); | |
224 | ✗ | return ret; | |
225 | } | ||
226 | |||
227 | 695 | static void pad_params_free(AVFilterPadParams **pfpp) | |
228 | { | ||
229 | 695 | AVFilterPadParams *fpp = *pfpp; | |
230 | |||
231 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 695 times.
|
695 | if (!fpp) |
232 | ✗ | return; | |
233 | |||
234 | 695 | av_freep(&fpp->label); | |
235 | |||
236 | 695 | av_freep(pfpp); | |
237 | } | ||
238 | |||
239 | 25483 | static void filter_params_free(AVFilterParams **pp) | |
240 | { | ||
241 | 25483 | AVFilterParams *p = *pp; | |
242 | |||
243 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25483 times.
|
25483 | if (!p) |
244 | ✗ | return; | |
245 | |||
246 |
2/2✓ Branch 0 taken 348 times.
✓ Branch 1 taken 25483 times.
|
25831 | for (unsigned i = 0; i < p->nb_inputs; i++) |
247 | 348 | pad_params_free(&p->inputs[i]); | |
248 | 25483 | av_freep(&p->inputs); | |
249 | |||
250 |
2/2✓ Branch 0 taken 347 times.
✓ Branch 1 taken 25483 times.
|
25830 | for (unsigned i = 0; i < p->nb_outputs; i++) |
251 | 347 | pad_params_free(&p->outputs[i]); | |
252 | 25483 | av_freep(&p->outputs); | |
253 | |||
254 | 25483 | av_dict_free(&p->opts); | |
255 | |||
256 | 25483 | av_freep(&p->filter_name); | |
257 | 25483 | av_freep(&p->instance_name); | |
258 | |||
259 | 25483 | av_freep(pp); | |
260 | } | ||
261 | |||
262 | 13094 | static void chain_free(AVFilterChain **pch) | |
263 | { | ||
264 | 13094 | AVFilterChain *ch = *pch; | |
265 | |||
266 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13094 times.
|
13094 | if (!ch) |
267 | ✗ | return; | |
268 | |||
269 |
2/2✓ Branch 0 taken 25483 times.
✓ Branch 1 taken 13094 times.
|
38577 | for (size_t i = 0; i < ch->nb_filters; i++) |
270 | 25483 | filter_params_free(&ch->filters[i]); | |
271 | 13094 | av_freep(&ch->filters); | |
272 | |||
273 | 13094 | av_freep(pch); | |
274 | } | ||
275 | |||
276 | 12895 | void avfilter_graph_segment_free(AVFilterGraphSegment **pseg) | |
277 | { | ||
278 | 12895 | AVFilterGraphSegment *seg = *pseg; | |
279 | |||
280 |
2/2✓ Branch 0 taken 43 times.
✓ Branch 1 taken 12852 times.
|
12895 | if (!seg) |
281 | 43 | return; | |
282 | |||
283 |
2/2✓ Branch 0 taken 13094 times.
✓ Branch 1 taken 12852 times.
|
25946 | for (size_t i = 0; i < seg->nb_chains; i++) |
284 | 13094 | chain_free(&seg->chains[i]); | |
285 | 12852 | av_freep(&seg->chains); | |
286 | |||
287 | 12852 | av_freep(&seg->scale_sws_opts); | |
288 | |||
289 | 12852 | av_freep(pseg); | |
290 | } | ||
291 | |||
292 | 51003 | static int linklabels_parse(void *logctx, const char **linklabels, | |
293 | AVFilterPadParams ***res, unsigned *nb_res) | ||
294 | { | ||
295 | 51003 | AVFilterPadParams **pp = NULL; | |
296 | 51003 | int nb = 0; | |
297 | int ret; | ||
298 | |||
299 |
2/2✓ Branch 0 taken 695 times.
✓ Branch 1 taken 51003 times.
|
51698 | while (**linklabels == '[') { |
300 | char *label; | ||
301 | AVFilterPadParams *par; | ||
302 | |||
303 | 695 | label = parse_link_name(linklabels, logctx); | |
304 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 695 times.
|
695 | if (!label) { |
305 | ✗ | ret = AVERROR(EINVAL); | |
306 | ✗ | goto fail; | |
307 | } | ||
308 | |||
309 | 695 | par = av_mallocz(sizeof(*par)); | |
310 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 695 times.
|
695 | if (!par) { |
311 | ✗ | av_freep(&label); | |
312 | ✗ | ret = AVERROR(ENOMEM); | |
313 | ✗ | goto fail; | |
314 | } | ||
315 | |||
316 | 695 | par->label = label; | |
317 | |||
318 | 695 | ret = av_dynarray_add_nofree(&pp, &nb, par); | |
319 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 695 times.
|
695 | if (ret < 0) { |
320 | ✗ | pad_params_free(&par); | |
321 | ✗ | goto fail; | |
322 | } | ||
323 | |||
324 | 695 | *linklabels += strspn(*linklabels, WHITESPACES); | |
325 | } | ||
326 | |||
327 | 51003 | *res = pp; | |
328 | 51003 | *nb_res = nb; | |
329 | |||
330 | 51003 | return 0; | |
331 | ✗ | fail: | |
332 | ✗ | for (unsigned i = 0; i < nb; i++) | |
333 | ✗ | pad_params_free(&pp[i]); | |
334 | ✗ | av_freep(&pp); | |
335 | ✗ | return ret; | |
336 | } | ||
337 | |||
338 | 25483 | static int filter_parse(void *logctx, const char **filter, | |
339 | AVFilterParams **pp) | ||
340 | { | ||
341 | AVFilterParams *p; | ||
342 | char *inst_name; | ||
343 | int ret; | ||
344 | |||
345 | 25483 | p = av_mallocz(sizeof(*p)); | |
346 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25483 times.
|
25483 | if (!p) |
347 | ✗ | return AVERROR(ENOMEM); | |
348 | |||
349 | 25483 | ret = linklabels_parse(logctx, filter, &p->inputs, &p->nb_inputs); | |
350 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25483 times.
|
25483 | if (ret < 0) |
351 | ✗ | goto fail; | |
352 | |||
353 | 25483 | p->filter_name = av_get_token(filter, "=,;["); | |
354 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25483 times.
|
25483 | if (!p->filter_name) { |
355 | ✗ | ret = AVERROR(ENOMEM); | |
356 | ✗ | goto fail; | |
357 | } | ||
358 | |||
359 | 25483 | inst_name = strchr(p->filter_name, '@'); | |
360 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25483 times.
|
25483 | if (inst_name) { |
361 | ✗ | *inst_name++ = 0; | |
362 | ✗ | p->instance_name = av_strdup(inst_name); | |
363 | ✗ | if (!p->instance_name) { | |
364 | ✗ | ret = AVERROR(ENOMEM); | |
365 | ✗ | goto fail; | |
366 | } | ||
367 | } | ||
368 | |||
369 |
2/2✓ Branch 0 taken 13297 times.
✓ Branch 1 taken 12186 times.
|
25483 | if (**filter == '=') { |
370 | 13297 | const AVFilter *f = avfilter_get_by_name(p->filter_name); | |
371 | char *opts; | ||
372 | |||
373 | 13297 | (*filter)++; | |
374 | |||
375 | 13297 | opts = av_get_token(filter, "[],;"); | |
376 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13297 times.
|
13297 | if (!opts) { |
377 | ✗ | ret = AVERROR(ENOMEM); | |
378 | ✗ | goto fail; | |
379 | } | ||
380 | |||
381 | 13297 | ret = ff_filter_opt_parse(logctx, f ? f->priv_class : NULL, | |
382 |
1/2✓ Branch 0 taken 13297 times.
✗ Branch 1 not taken.
|
13297 | &p->opts, opts); |
383 | 13297 | av_freep(&opts); | |
384 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13297 times.
|
13297 | if (ret < 0) |
385 | ✗ | goto fail; | |
386 | } | ||
387 | |||
388 | 25483 | ret = linklabels_parse(logctx, filter, &p->outputs, &p->nb_outputs); | |
389 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25483 times.
|
25483 | if (ret < 0) |
390 | ✗ | goto fail; | |
391 | |||
392 | 25483 | *filter += strspn(*filter, WHITESPACES); | |
393 | |||
394 | 25483 | *pp = p; | |
395 | 25483 | return 0; | |
396 | ✗ | fail: | |
397 | ✗ | av_log(logctx, AV_LOG_ERROR, | |
398 | "Error parsing a filter description around: %s\n", *filter); | ||
399 | ✗ | filter_params_free(&p); | |
400 | ✗ | return ret; | |
401 | } | ||
402 | |||
403 | 13094 | static int chain_parse(void *logctx, const char **pchain, | |
404 | AVFilterChain **pch) | ||
405 | { | ||
406 | 13094 | const char *chain = *pchain; | |
407 | AVFilterChain *ch; | ||
408 | 13094 | int ret, nb_filters = 0; | |
409 | |||
410 | 13094 | *pch = NULL; | |
411 | |||
412 | 13094 | ch = av_mallocz(sizeof(*ch)); | |
413 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13094 times.
|
13094 | if (!ch) |
414 | ✗ | return AVERROR(ENOMEM); | |
415 | |||
416 |
2/2✓ Branch 0 taken 25483 times.
✓ Branch 1 taken 12838 times.
|
38321 | while (*chain) { |
417 | AVFilterParams *p; | ||
418 | char chr; | ||
419 | |||
420 | 25483 | ret = filter_parse(logctx, &chain, &p); | |
421 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25483 times.
|
25483 | if (ret < 0) |
422 | ✗ | goto fail; | |
423 | |||
424 | 25483 | ret = av_dynarray_add_nofree(&ch->filters, &nb_filters, p); | |
425 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25483 times.
|
25483 | if (ret < 0) { |
426 | ✗ | filter_params_free(&p); | |
427 | ✗ | goto fail; | |
428 | } | ||
429 | 25483 | ch->nb_filters = nb_filters; | |
430 | |||
431 | // a filter ends with one of: , ; end-of-string | ||
432 | 25483 | chr = *chain; | |
433 |
5/6✓ Branch 0 taken 12645 times.
✓ Branch 1 taken 12838 times.
✓ Branch 2 taken 256 times.
✓ Branch 3 taken 12389 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 256 times.
|
25483 | if (chr && chr != ',' && chr != ';') { |
434 | ✗ | av_log(logctx, AV_LOG_ERROR, | |
435 | "Trailing garbage after a filter: %s\n", chain); | ||
436 | ✗ | ret = AVERROR(EINVAL); | |
437 | ✗ | goto fail; | |
438 | } | ||
439 | |||
440 |
2/2✓ Branch 0 taken 12645 times.
✓ Branch 1 taken 12838 times.
|
25483 | if (chr) { |
441 | 12645 | chain++; | |
442 | 12645 | chain += strspn(chain, WHITESPACES); | |
443 | |||
444 |
2/2✓ Branch 0 taken 256 times.
✓ Branch 1 taken 12389 times.
|
12645 | if (chr == ';') |
445 | 256 | break; | |
446 | } | ||
447 | } | ||
448 | |||
449 | 13094 | *pchain = chain; | |
450 | 13094 | *pch = ch; | |
451 | |||
452 | 13094 | return 0; | |
453 | ✗ | fail: | |
454 | ✗ | av_log(logctx, AV_LOG_ERROR, | |
455 | "Error parsing filterchain '%s' around: %s\n", *pchain, chain); | ||
456 | ✗ | chain_free(&ch); | |
457 | ✗ | return ret; | |
458 | } | ||
459 | |||
460 | 12852 | int avfilter_graph_segment_parse(AVFilterGraph *graph, const char *graph_str, | |
461 | int flags, AVFilterGraphSegment **pseg) | ||
462 | { | ||
463 | AVFilterGraphSegment *seg; | ||
464 | 12852 | int ret, nb_chains = 0; | |
465 | |||
466 | 12852 | *pseg = NULL; | |
467 | |||
468 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12852 times.
|
12852 | if (flags) |
469 | ✗ | return AVERROR(ENOSYS); | |
470 | |||
471 | 12852 | seg = av_mallocz(sizeof(*seg)); | |
472 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12852 times.
|
12852 | if (!seg) |
473 | ✗ | return AVERROR(ENOMEM); | |
474 | |||
475 | 12852 | seg->graph = graph; | |
476 | |||
477 | 12852 | graph_str += strspn(graph_str, WHITESPACES); | |
478 | |||
479 | 12852 | ret = parse_sws_flags(&graph_str, &seg->scale_sws_opts, graph); | |
480 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12852 times.
|
12852 | if (ret < 0) |
481 | ✗ | goto fail; | |
482 | |||
483 | 12852 | graph_str += strspn(graph_str, WHITESPACES); | |
484 | |||
485 |
2/2✓ Branch 0 taken 13094 times.
✓ Branch 1 taken 12852 times.
|
25946 | while (*graph_str) { |
486 | AVFilterChain *ch; | ||
487 | |||
488 | 13094 | ret = chain_parse(graph, &graph_str, &ch); | |
489 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13094 times.
|
13094 | if (ret < 0) |
490 | ✗ | goto fail; | |
491 | |||
492 | 13094 | ret = av_dynarray_add_nofree(&seg->chains, &nb_chains, ch); | |
493 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13094 times.
|
13094 | if (ret < 0) { |
494 | ✗ | chain_free(&ch); | |
495 | ✗ | goto fail; | |
496 | } | ||
497 | 13094 | seg->nb_chains = nb_chains; | |
498 | |||
499 | 13094 | graph_str += strspn(graph_str, WHITESPACES); | |
500 | } | ||
501 | |||
502 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12852 times.
|
12852 | if (!seg->nb_chains) { |
503 | ✗ | av_log(graph, AV_LOG_ERROR, "No filters specified in the graph description\n"); | |
504 | ✗ | ret = AVERROR(EINVAL); | |
505 | ✗ | goto fail; | |
506 | } | ||
507 | |||
508 | 12852 | *pseg = seg; | |
509 | |||
510 | 12852 | return 0; | |
511 | ✗ | fail: | |
512 | ✗ | avfilter_graph_segment_free(&seg); | |
513 | ✗ | return ret; | |
514 | } | ||
515 | |||
516 | 25704 | int avfilter_graph_segment_create_filters(AVFilterGraphSegment *seg, int flags) | |
517 | { | ||
518 | 25704 | size_t idx = 0; | |
519 | |||
520 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25704 times.
|
25704 | if (flags) |
521 | ✗ | return AVERROR(ENOSYS); | |
522 | |||
523 |
2/2✓ Branch 0 taken 98 times.
✓ Branch 1 taken 25606 times.
|
25704 | if (seg->scale_sws_opts) { |
524 | 98 | av_freep(&seg->graph->scale_sws_opts); | |
525 | 98 | seg->graph->scale_sws_opts = av_strdup(seg->scale_sws_opts); | |
526 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
|
98 | if (!seg->graph->scale_sws_opts) |
527 | ✗ | return AVERROR(ENOMEM); | |
528 | } | ||
529 | |||
530 |
2/2✓ Branch 0 taken 26188 times.
✓ Branch 1 taken 25704 times.
|
51892 | for (size_t i = 0; i < seg->nb_chains; i++) { |
531 | 26188 | AVFilterChain *ch = seg->chains[i]; | |
532 | |||
533 |
2/2✓ Branch 0 taken 50966 times.
✓ Branch 1 taken 26188 times.
|
77154 | for (size_t j = 0; j < ch->nb_filters; j++) { |
534 | 50966 | AVFilterParams *p = ch->filters[j]; | |
535 | 50966 | const AVFilter *f = avfilter_get_by_name(p->filter_name); | |
536 | char name[64]; | ||
537 | |||
538 | // skip already processed filters | ||
539 |
3/4✓ Branch 0 taken 25483 times.
✓ Branch 1 taken 25483 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 25483 times.
|
50966 | if (p->filter || !p->filter_name) |
540 | 25483 | continue; | |
541 | |||
542 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25483 times.
|
25483 | if (!f) { |
543 | ✗ | av_log(seg->graph, AV_LOG_ERROR, | |
544 | "No such filter: '%s'\n", p->filter_name); | ||
545 | ✗ | return AVERROR_FILTER_NOT_FOUND; | |
546 | } | ||
547 | |||
548 |
1/2✓ Branch 0 taken 25483 times.
✗ Branch 1 not taken.
|
25483 | if (!p->instance_name) |
549 | 25483 | snprintf(name, sizeof(name), "Parsed_%s_%zu", f->name, idx); | |
550 | else | ||
551 | ✗ | snprintf(name, sizeof(name), "%s@%s", f->name, p->instance_name); | |
552 | |||
553 | 25483 | p->filter = avfilter_graph_alloc_filter(seg->graph, f, name); | |
554 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25483 times.
|
25483 | if (!p->filter) |
555 | ✗ | return AVERROR(ENOMEM); | |
556 | |||
557 |
4/4✓ Branch 0 taken 6028 times.
✓ Branch 1 taken 19455 times.
✓ Branch 2 taken 2682 times.
✓ Branch 3 taken 3346 times.
|
25483 | if (!strcmp(f->name, "scale") && seg->graph->scale_sws_opts) { |
558 | 2682 | int ret = av_set_options_string(p->filter, seg->graph->scale_sws_opts, | |
559 | "=", ":"); | ||
560 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2682 times.
|
2682 | if (ret < 0) { |
561 | ✗ | avfilter_free(p->filter); | |
562 | ✗ | p->filter = NULL; | |
563 | ✗ | return ret; | |
564 | } | ||
565 | } | ||
566 | |||
567 | 25483 | av_freep(&p->filter_name); | |
568 | 25483 | av_freep(&p->instance_name); | |
569 | |||
570 | 25483 | idx++; | |
571 | } | ||
572 | } | ||
573 | |||
574 | 25704 | return 0; | |
575 | } | ||
576 | |||
577 | ✗ | static int fail_creation_pending(AVFilterGraphSegment *seg, const char *fn, | |
578 | const char *func) | ||
579 | { | ||
580 | ✗ | av_log(seg->graph, AV_LOG_ERROR, | |
581 | "A creation-pending filter '%s' present in the segment. All filters " | ||
582 | "must be created or disabled before calling %s().\n", fn, func); | ||
583 | ✗ | return AVERROR(EINVAL); | |
584 | } | ||
585 | |||
586 | 12895 | int avfilter_graph_segment_apply_opts(AVFilterGraphSegment *seg, int flags) | |
587 | { | ||
588 | 12895 | int ret, leftover_opts = 0; | |
589 | |||
590 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12895 times.
|
12895 | if (flags) |
591 | ✗ | return AVERROR(ENOSYS); | |
592 | |||
593 |
2/2✓ Branch 0 taken 13141 times.
✓ Branch 1 taken 12895 times.
|
26036 | for (size_t i = 0; i < seg->nb_chains; i++) { |
594 | 13141 | AVFilterChain *ch = seg->chains[i]; | |
595 | |||
596 |
2/2✓ Branch 0 taken 25554 times.
✓ Branch 1 taken 13141 times.
|
38695 | for (size_t j = 0; j < ch->nb_filters; j++) { |
597 | 25554 | AVFilterParams *p = ch->filters[j]; | |
598 | |||
599 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25554 times.
|
25554 | if (p->filter_name) |
600 | ✗ | return fail_creation_pending(seg, p->filter_name, __func__); | |
601 |
3/4✓ Branch 0 taken 25554 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25489 times.
✓ Branch 3 taken 65 times.
|
25554 | if (!p->filter || !p->opts) |
602 | 25489 | continue; | |
603 | |||
604 | 65 | ret = av_opt_set_dict2(p->filter, &p->opts, AV_OPT_SEARCH_CHILDREN); | |
605 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 65 times.
|
65 | if (ret < 0) |
606 | ✗ | return ret; | |
607 | |||
608 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 65 times.
|
65 | if (av_dict_count(p->opts)) |
609 | ✗ | leftover_opts = 1; | |
610 | } | ||
611 | } | ||
612 | |||
613 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12895 times.
|
12895 | return leftover_opts ? AVERROR_OPTION_NOT_FOUND : 0; |
614 | } | ||
615 | |||
616 | 12895 | int avfilter_graph_segment_init(AVFilterGraphSegment *seg, int flags) | |
617 | { | ||
618 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12895 times.
|
12895 | if (flags) |
619 | ✗ | return AVERROR(ENOSYS); | |
620 | |||
621 |
2/2✓ Branch 0 taken 13141 times.
✓ Branch 1 taken 12895 times.
|
26036 | for (size_t i = 0; i < seg->nb_chains; i++) { |
622 | 13141 | AVFilterChain *ch = seg->chains[i]; | |
623 | |||
624 |
2/2✓ Branch 0 taken 25554 times.
✓ Branch 1 taken 13141 times.
|
38695 | for (size_t j = 0; j < ch->nb_filters; j++) { |
625 | 25554 | AVFilterParams *p = ch->filters[j]; | |
626 | int ret; | ||
627 | |||
628 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25554 times.
|
25554 | if (p->filter_name) |
629 | ✗ | return fail_creation_pending(seg, p->filter_name, __func__); | |
630 |
3/4✓ Branch 0 taken 25554 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 71 times.
✓ Branch 4 taken 25483 times.
|
25554 | if (!p->filter || fffilterctx(p->filter)->initialized) |
631 | 71 | continue; | |
632 | |||
633 | 25483 | ret = avfilter_init_dict(p->filter, NULL); | |
634 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25483 times.
|
25483 | if (ret < 0) |
635 | ✗ | return ret; | |
636 | } | ||
637 | } | ||
638 | |||
639 | 12895 | return 0; | |
640 | } | ||
641 | |||
642 | static unsigned | ||
643 | 501 | find_linklabel(AVFilterGraphSegment *seg, const char *label, | |
644 | int output, size_t idx_chain, size_t idx_filter, | ||
645 | AVFilterParams **pp) | ||
646 | { | ||
647 |
2/2✓ Branch 0 taken 1345 times.
✓ Branch 1 taken 307 times.
|
1652 | for (; idx_chain < seg->nb_chains; idx_chain++) { |
648 | 1345 | AVFilterChain *ch = seg->chains[idx_chain]; | |
649 | |||
650 |
2/2✓ Branch 0 taken 1409 times.
✓ Branch 1 taken 1151 times.
|
2560 | for (; idx_filter < ch->nb_filters; idx_filter++) { |
651 | 1409 | AVFilterParams *p = ch->filters[idx_filter]; | |
652 |
2/2✓ Branch 0 taken 444 times.
✓ Branch 1 taken 965 times.
|
1409 | AVFilterPadParams **io = output ? p->outputs : p->inputs; |
653 |
2/2✓ Branch 0 taken 444 times.
✓ Branch 1 taken 965 times.
|
1409 | unsigned nb_io = output ? p->nb_outputs : p->nb_inputs; |
654 | AVFilterLink **l; | ||
655 | unsigned nb_l; | ||
656 | |||
657 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1409 times.
|
1409 | if (!p->filter) |
658 | ✗ | continue; | |
659 | |||
660 |
2/2✓ Branch 0 taken 444 times.
✓ Branch 1 taken 965 times.
|
1409 | l = output ? p->filter->outputs : p->filter->inputs; |
661 |
2/2✓ Branch 0 taken 444 times.
✓ Branch 1 taken 965 times.
|
1409 | nb_l = output ? p->filter->nb_outputs : p->filter->nb_inputs; |
662 | |||
663 |
2/2✓ Branch 0 taken 1175 times.
✓ Branch 1 taken 1215 times.
|
2390 | for (unsigned i = 0; i < FFMIN(nb_io, nb_l); i++) |
664 |
5/6✓ Branch 0 taken 1050 times.
✓ Branch 1 taken 125 times.
✓ Branch 2 taken 1050 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 194 times.
✓ Branch 5 taken 856 times.
|
1175 | if (!l[i] && io[i]->label && !strcmp(io[i]->label, label)) { |
665 | 194 | *pp = p; | |
666 | 194 | return i; | |
667 | } | ||
668 | } | ||
669 | |||
670 | 1151 | idx_filter = 0; | |
671 | } | ||
672 | |||
673 | 307 | *pp = NULL; | |
674 | 307 | return 0; | |
675 | } | ||
676 | |||
677 | 25793 | static int inout_add(AVFilterInOut **inouts, AVFilterContext *f, unsigned pad_idx, | |
678 | const char *label) | ||
679 | { | ||
680 | 25793 | AVFilterInOut *io = av_mallocz(sizeof(*io)); | |
681 | |||
682 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25793 times.
|
25793 | if (!io) |
683 | ✗ | return AVERROR(ENOMEM); | |
684 | |||
685 | 25793 | io->filter_ctx = f; | |
686 | 25793 | io->pad_idx = pad_idx; | |
687 | |||
688 |
2/2✓ Branch 0 taken 307 times.
✓ Branch 1 taken 25486 times.
|
25793 | if (label) { |
689 | 307 | io->name = av_strdup(label); | |
690 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 307 times.
|
307 | if (!io->name) { |
691 | ✗ | avfilter_inout_free(&io); | |
692 | ✗ | return AVERROR(ENOMEM); | |
693 | } | ||
694 | } | ||
695 | |||
696 | 25793 | append_inout(inouts, &io); | |
697 | |||
698 | 25793 | return 0; | |
699 | } | ||
700 | |||
701 | 25483 | static int link_inputs(AVFilterGraphSegment *seg, size_t idx_chain, | |
702 | size_t idx_filter, AVFilterInOut **inputs) | ||
703 | { | ||
704 | 25483 | AVFilterChain *ch = seg->chains[idx_chain]; | |
705 | 25483 | AVFilterParams *p = ch->filters[idx_filter]; | |
706 | 25483 | AVFilterContext *f = p->filter; | |
707 | |||
708 | int ret; | ||
709 | |||
710 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25483 times.
|
25483 | if (f->nb_inputs < p->nb_inputs) { |
711 | ✗ | av_log(seg->graph, AV_LOG_ERROR, | |
712 | "More input link labels specified for filter '%s' than " | ||
713 | ✗ | "it has inputs: %u > %d\n", f->filter->name, | |
714 | p->nb_inputs, f->nb_inputs); | ||
715 | ✗ | return AVERROR(EINVAL); | |
716 | } | ||
717 | |||
718 |
2/2✓ Branch 0 taken 25424 times.
✓ Branch 1 taken 25483 times.
|
50907 | for (unsigned in = 0; in < f->nb_inputs; in++) { |
719 |
2/2✓ Branch 0 taken 348 times.
✓ Branch 1 taken 25076 times.
|
25424 | const char *label = (in < p->nb_inputs) ? p->inputs[in]->label : NULL; |
720 | |||
721 | // skip already linked inputs | ||
722 |
2/2✓ Branch 0 taken 12585 times.
✓ Branch 1 taken 12839 times.
|
25424 | if (f->inputs[in]) |
723 | 12585 | continue; | |
724 | |||
725 |
2/2✓ Branch 0 taken 154 times.
✓ Branch 1 taken 12685 times.
|
12839 | if (label) { |
726 | 154 | AVFilterParams *po = NULL; | |
727 | 154 | unsigned idx = find_linklabel(seg, label, 1, idx_chain, idx_filter, &po); | |
728 | |||
729 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 154 times.
|
154 | if (po) { |
730 | ✗ | ret = avfilter_link(po->filter, idx, f, in); | |
731 | ✗ | if (ret < 0) | |
732 | ✗ | return ret; | |
733 | |||
734 | ✗ | continue; | |
735 | } | ||
736 | } | ||
737 | |||
738 | 12839 | ret = inout_add(inputs, f, in, label); | |
739 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12839 times.
|
12839 | if (ret < 0) |
740 | ✗ | return ret; | |
741 | } | ||
742 | |||
743 | 25483 | return 0; | |
744 | } | ||
745 | |||
746 | 25483 | static int link_outputs(AVFilterGraphSegment *seg, size_t idx_chain, | |
747 | size_t idx_filter, AVFilterInOut **outputs) | ||
748 | { | ||
749 | 25483 | AVFilterChain *ch = seg->chains[idx_chain]; | |
750 | 25483 | AVFilterParams *p = ch->filters[idx_filter]; | |
751 | 25483 | AVFilterContext *f = p->filter; | |
752 | |||
753 | int ret; | ||
754 | |||
755 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25483 times.
|
25483 | if (f->nb_outputs < p->nb_outputs) { |
756 | ✗ | av_log(seg->graph, AV_LOG_ERROR, | |
757 | "More output link labels specified for filter '%s' than " | ||
758 | ✗ | "it has outputs: %u > %d\n", f->filter->name, | |
759 | p->nb_outputs, f->nb_outputs); | ||
760 | ✗ | return AVERROR(EINVAL); | |
761 | } | ||
762 |
2/2✓ Branch 0 taken 25539 times.
✓ Branch 1 taken 25483 times.
|
51022 | for (unsigned out = 0; out < f->nb_outputs; out++) { |
763 |
2/2✓ Branch 0 taken 347 times.
✓ Branch 1 taken 25192 times.
|
25539 | char *label = (out < p->nb_outputs) ? p->outputs[out]->label : NULL; |
764 | |||
765 | // skip already linked outputs | ||
766 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25539 times.
|
25539 | if (f->outputs[out]) |
767 | ✗ | continue; | |
768 | |||
769 |
2/2✓ Branch 0 taken 347 times.
✓ Branch 1 taken 25192 times.
|
25539 | if (label) { |
770 | 347 | AVFilterParams *po = NULL; | |
771 | 347 | unsigned idx = find_linklabel(seg, label, 0, idx_chain, idx_filter, &po); | |
772 | |||
773 |
2/2✓ Branch 0 taken 194 times.
✓ Branch 1 taken 153 times.
|
347 | if (po) { |
774 | 194 | ret = avfilter_link(f, out, po->filter, idx); | |
775 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 194 times.
|
194 | if (ret < 0) |
776 | ✗ | return ret; | |
777 | |||
778 | 194 | continue; | |
779 | } | ||
780 | } | ||
781 | |||
782 | // if this output is unlabeled, try linking it to an unlabeled | ||
783 | // input in the next non-disabled filter in the chain | ||
784 |
3/4✓ Branch 0 taken 12391 times.
✓ Branch 1 taken 12954 times.
✓ Branch 2 taken 12391 times.
✗ Branch 3 not taken.
|
25345 | for (size_t i = idx_filter + 1; i < ch->nb_filters && !label; i++) { |
785 | 12391 | AVFilterParams *p_next = ch->filters[i]; | |
786 | |||
787 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12391 times.
|
12391 | if (!p_next->filter) |
788 | ✗ | continue; | |
789 | |||
790 |
1/2✓ Branch 0 taken 12395 times.
✗ Branch 1 not taken.
|
12395 | for (unsigned in = 0; in < p_next->filter->nb_inputs; in++) { |
791 |
2/2✓ Branch 0 taken 12391 times.
✓ Branch 1 taken 4 times.
|
12395 | if (!p_next->filter->inputs[in] && |
792 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 12391 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
12391 | (in >= p_next->nb_inputs || !p_next->inputs[in]->label)) { |
793 | 12391 | ret = avfilter_link(f, out, p_next->filter, in); | |
794 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12391 times.
|
12391 | if (ret < 0) |
795 | ✗ | return ret; | |
796 | |||
797 | 12391 | goto cont; | |
798 | } | ||
799 | } | ||
800 | ✗ | break; | |
801 | } | ||
802 | |||
803 | 12954 | ret = inout_add(outputs, f, out, label); | |
804 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12954 times.
|
12954 | if (ret < 0) |
805 | ✗ | return ret; | |
806 | |||
807 | 25345 | cont:; | |
808 | } | ||
809 | |||
810 | 25483 | return 0; | |
811 | } | ||
812 | |||
813 | 12852 | int avfilter_graph_segment_link(AVFilterGraphSegment *seg, int flags, | |
814 | AVFilterInOut **inputs, | ||
815 | AVFilterInOut **outputs) | ||
816 | { | ||
817 | int ret; | ||
818 | |||
819 | 12852 | *inputs = NULL; | |
820 | 12852 | *outputs = NULL; | |
821 | |||
822 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12852 times.
|
12852 | if (flags) |
823 | ✗ | return AVERROR(ENOSYS); | |
824 | |||
825 |
2/2✓ Branch 0 taken 13094 times.
✓ Branch 1 taken 12852 times.
|
25946 | for (size_t idx_chain = 0; idx_chain < seg->nb_chains; idx_chain++) { |
826 | 13094 | AVFilterChain *ch = seg->chains[idx_chain]; | |
827 | |||
828 |
2/2✓ Branch 0 taken 25483 times.
✓ Branch 1 taken 13094 times.
|
38577 | for (size_t idx_filter = 0; idx_filter < ch->nb_filters; idx_filter++) { |
829 | 25483 | AVFilterParams *p = ch->filters[idx_filter]; | |
830 | |||
831 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25483 times.
|
25483 | if (p->filter_name) { |
832 | ✗ | ret = fail_creation_pending(seg, p->filter_name, __func__); | |
833 | ✗ | goto fail; | |
834 | } | ||
835 | |||
836 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25483 times.
|
25483 | if (!p->filter) |
837 | ✗ | continue; | |
838 | |||
839 | 25483 | ret = link_inputs(seg, idx_chain, idx_filter, inputs); | |
840 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25483 times.
|
25483 | if (ret < 0) |
841 | ✗ | goto fail; | |
842 | |||
843 | 25483 | ret = link_outputs(seg, idx_chain, idx_filter, outputs); | |
844 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25483 times.
|
25483 | if (ret < 0) |
845 | ✗ | goto fail; | |
846 | } | ||
847 | } | ||
848 | 12852 | return 0; | |
849 | ✗ | fail: | |
850 | ✗ | avfilter_inout_free(inputs); | |
851 | ✗ | avfilter_inout_free(outputs); | |
852 | ✗ | return ret; | |
853 | } | ||
854 | |||
855 | // print an error message if some options were not found | ||
856 | ✗ | static void log_unknown_opt(const AVFilterGraphSegment *seg) | |
857 | { | ||
858 | ✗ | for (size_t i = 0; i < seg->nb_chains; i++) { | |
859 | ✗ | const AVFilterChain *ch = seg->chains[i]; | |
860 | |||
861 | ✗ | for (size_t j = 0; j < ch->nb_filters; j++) { | |
862 | ✗ | const AVFilterParams *p = ch->filters[j]; | |
863 | const AVDictionaryEntry *e; | ||
864 | |||
865 | ✗ | if (!p->filter) | |
866 | ✗ | continue; | |
867 | |||
868 | ✗ | e = av_dict_iterate(p->opts, NULL); | |
869 | |||
870 | ✗ | if (e) { | |
871 | ✗ | av_log(p->filter, AV_LOG_ERROR, | |
872 | "Could not set non-existent option '%s' to value '%s'\n", | ||
873 | ✗ | e->key, e->value); | |
874 | ✗ | return; | |
875 | } | ||
876 | } | ||
877 | } | ||
878 | |||
879 | } | ||
880 | |||
881 | 12852 | int avfilter_graph_segment_apply(AVFilterGraphSegment *seg, int flags, | |
882 | AVFilterInOut **inputs, | ||
883 | AVFilterInOut **outputs) | ||
884 | { | ||
885 | int ret; | ||
886 | |||
887 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12852 times.
|
12852 | if (flags) |
888 | ✗ | return AVERROR(ENOSYS); | |
889 | |||
890 | 12852 | ret = avfilter_graph_segment_create_filters(seg, 0); | |
891 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12852 times.
|
12852 | if (ret < 0) { |
892 | ✗ | av_log(seg->graph, AV_LOG_ERROR, "Error creating filters\n"); | |
893 | ✗ | return ret; | |
894 | } | ||
895 | |||
896 | 12852 | ret = avfilter_graph_segment_apply_opts(seg, 0); | |
897 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12852 times.
|
12852 | if (ret < 0) { |
898 | ✗ | if (ret == AVERROR_OPTION_NOT_FOUND) | |
899 | ✗ | log_unknown_opt(seg); | |
900 | ✗ | av_log(seg->graph, AV_LOG_ERROR, "Error applying filter options\n"); | |
901 | ✗ | return ret; | |
902 | } | ||
903 | |||
904 | 12852 | ret = avfilter_graph_segment_init(seg, 0); | |
905 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12852 times.
|
12852 | if (ret < 0) { |
906 | ✗ | av_log(seg->graph, AV_LOG_ERROR, "Error initializing filters\n"); | |
907 | ✗ | return ret; | |
908 | } | ||
909 | |||
910 | 12852 | ret = avfilter_graph_segment_link(seg, 0, inputs, outputs); | |
911 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12852 times.
|
12852 | if (ret < 0) { |
912 | ✗ | av_log(seg->graph, AV_LOG_ERROR, "Error linking filters\n"); | |
913 | ✗ | return ret; | |
914 | } | ||
915 | |||
916 | 12852 | return 0; | |
917 | } | ||
918 | |||
919 | 43 | int avfilter_graph_parse_ptr(AVFilterGraph *graph, const char *filters, | |
920 | AVFilterInOut **open_inputs_ptr, AVFilterInOut **open_outputs_ptr, | ||
921 | void *log_ctx) | ||
922 | { | ||
923 |
1/2✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
|
43 | AVFilterInOut *user_inputs = open_inputs_ptr ? *open_inputs_ptr : NULL; |
924 |
1/2✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
|
43 | AVFilterInOut *user_outputs = open_outputs_ptr ? *open_outputs_ptr : NULL; |
925 | |||
926 | 43 | AVFilterInOut *inputs = NULL, *outputs = NULL; | |
927 | 43 | AVFilterGraphSegment *seg = NULL; | |
928 | AVFilterChain *ch; | ||
929 | AVFilterParams *p; | ||
930 | int ret; | ||
931 | |||
932 | 43 | ret = avfilter_graph_segment_parse(graph, filters, 0, &seg); | |
933 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
|
43 | if (ret < 0) |
934 | ✗ | goto end; | |
935 | |||
936 | 43 | ret = avfilter_graph_segment_create_filters(seg, 0); | |
937 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
|
43 | if (ret < 0) |
938 | ✗ | goto end; | |
939 | |||
940 | 43 | ret = avfilter_graph_segment_apply_opts(seg, 0); | |
941 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
|
43 | if (ret < 0) { |
942 | ✗ | if (ret == AVERROR_OPTION_NOT_FOUND) | |
943 | ✗ | log_unknown_opt(seg); | |
944 | ✗ | goto end; | |
945 | } | ||
946 | |||
947 | 43 | ret = avfilter_graph_segment_init(seg, 0); | |
948 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
|
43 | if (ret < 0) |
949 | ✗ | goto end; | |
950 | |||
951 | /* First input pad, assume it is "[in]" if not specified */ | ||
952 | 43 | p = seg->chains[0]->filters[0]; | |
953 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
43 | if (p->filter->nb_inputs == 1 && !p->inputs) { |
954 | ✗ | const char *tmp = "[in]"; | |
955 | |||
956 | ✗ | ret = linklabels_parse(graph, &tmp, &p->inputs, &p->nb_inputs); | |
957 | ✗ | if (ret < 0) | |
958 | ✗ | goto end; | |
959 | } | ||
960 | |||
961 | /* Last output pad, assume it is "[out]" if not specified */ | ||
962 | 43 | ch = seg->chains[seg->nb_chains - 1]; | |
963 | 43 | p = ch->filters[ch->nb_filters - 1]; | |
964 |
3/4✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✓ Branch 3 taken 6 times.
|
43 | if (p->filter->nb_outputs == 1 && !p->outputs) { |
965 | 37 | const char *tmp = "[out]"; | |
966 | |||
967 | 37 | ret = linklabels_parse(graph, &tmp, &p->outputs, &p->nb_outputs); | |
968 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
|
37 | if (ret < 0) |
969 | ✗ | goto end; | |
970 | } | ||
971 | |||
972 | 43 | ret = avfilter_graph_segment_apply(seg, 0, &inputs, &outputs); | |
973 | 43 | avfilter_graph_segment_free(&seg); | |
974 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
|
43 | if (ret < 0) |
975 | ✗ | goto end; | |
976 | |||
977 | // process user-supplied inputs/outputs | ||
978 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
|
43 | while (inputs) { |
979 | ✗ | AVFilterInOut *cur, *match = NULL; | |
980 | |||
981 | ✗ | cur = inputs; | |
982 | ✗ | inputs = cur->next; | |
983 | ✗ | cur->next = NULL; | |
984 | |||
985 | ✗ | if (cur->name) | |
986 | ✗ | match = extract_inout(cur->name, &user_outputs); | |
987 | |||
988 | ✗ | if (match) { | |
989 | ✗ | ret = avfilter_link(match->filter_ctx, match->pad_idx, | |
990 | ✗ | cur->filter_ctx, cur->pad_idx); | |
991 | ✗ | avfilter_inout_free(&match); | |
992 | ✗ | avfilter_inout_free(&cur); | |
993 | ✗ | if (ret < 0) | |
994 | ✗ | goto end; | |
995 | } else | ||
996 | ✗ | append_inout(&user_inputs, &cur); | |
997 | } | ||
998 |
2/2✓ Branch 0 taken 45 times.
✓ Branch 1 taken 43 times.
|
88 | while (outputs) { |
999 | 45 | AVFilterInOut *cur, *match = NULL; | |
1000 | |||
1001 | 45 | cur = outputs; | |
1002 | 45 | outputs = cur->next; | |
1003 | 45 | cur->next = NULL; | |
1004 | |||
1005 |
1/2✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
|
45 | if (cur->name) |
1006 | 45 | match = extract_inout(cur->name, &user_inputs); | |
1007 | |||
1008 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
|
45 | if (match) { |
1009 | ✗ | ret = avfilter_link(cur->filter_ctx, cur->pad_idx, | |
1010 | ✗ | match->filter_ctx, match->pad_idx); | |
1011 | ✗ | avfilter_inout_free(&match); | |
1012 | ✗ | avfilter_inout_free(&cur); | |
1013 | ✗ | if (ret < 0) | |
1014 | ✗ | goto end; | |
1015 | } else | ||
1016 | 45 | append_inout(&user_outputs, &cur); | |
1017 | } | ||
1018 | |||
1019 | 43 | end: | |
1020 | 43 | avfilter_graph_segment_free(&seg); | |
1021 | |||
1022 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
|
43 | if (ret < 0) { |
1023 | ✗ | av_log(graph, AV_LOG_ERROR, "Error processing filtergraph: %s\n", | |
1024 | ✗ | av_err2str(ret)); | |
1025 | |||
1026 | ✗ | while (graph->nb_filters) | |
1027 | ✗ | avfilter_free(graph->filters[0]); | |
1028 | ✗ | av_freep(&graph->filters); | |
1029 | } | ||
1030 | |||
1031 | /* clear open_in/outputs only if not passed as parameters */ | ||
1032 |
1/2✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
|
43 | if (open_inputs_ptr) *open_inputs_ptr = user_inputs; |
1033 | ✗ | else avfilter_inout_free(&user_inputs); | |
1034 |
1/2✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
|
43 | if (open_outputs_ptr) *open_outputs_ptr = user_outputs; |
1035 | ✗ | else avfilter_inout_free(&user_outputs); | |
1036 | |||
1037 | 43 | avfilter_inout_free(&inputs); | |
1038 | 43 | avfilter_inout_free(&outputs); | |
1039 | |||
1040 | 43 | return ret; | |
1041 | } | ||
1042 |