FFmpeg
Loading...
Searching...
No Matches
graphparser.c
Go to the documentation of this file.
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 "filters.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 */
43static char *parse_link_name(const char **buf, void *log_ctx)
44{
45 const char *start = *buf;
46 char *name;
47 (*buf)++;
48
49 name = av_get_token(buf, "]");
50 if (!name)
51 return NULL;
52
53 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 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 (*buf)++;
67
68 return name;
69}
70
75
77{
78 while (*inout) {
79 AVFilterInOut *next = (*inout)->next;
80 av_freep(&(*inout)->name);
81 av_freep(inout);
82 *inout = next;
83 }
84}
85
86static AVFilterInOut *extract_inout(const char *label, AVFilterInOut **links)
87{
88 AVFilterInOut *ret;
89
90 while (*links && (!(*links)->name || strcmp((*links)->name, label)))
91 links = &((*links)->next);
92
93 ret = *links;
94
95 if (ret) {
96 *links = ret->next;
97 ret->next = NULL;
98 }
99
100 return ret;
101}
102
103static void append_inout(AVFilterInOut **inouts, AVFilterInOut **element)
104{
105 while (*inouts && (*inouts)->next)
106 inouts = &((*inouts)->next);
107
108 if (!*inouts)
109 *inouts = *element;
110 else
111 (*inouts)->next = *element;
112 *element = NULL;
113}
114
115static int parse_sws_flags(const char **buf, char **dst, void *log_ctx)
116{
117 if (strncmp(*buf, "sws_flags=", 10))
118 return 0;
119
120 const char *p = strchr(*buf, ';');
121
122 if (!p) {
123 av_log(log_ctx, AV_LOG_ERROR, "sws_flags not terminated with ';'.\n");
124 return AVERROR(EINVAL);
125 }
126
127 *buf += 4; // keep the 'flags=' part
128
129 av_freep(dst);
130 if (!(*dst = av_mallocz(p - *buf + 1)))
131 return AVERROR(ENOMEM);
132 av_strlcpy(*dst, *buf, p - *buf + 1);
133
134 *buf = p + 1;
135 return 0;
136}
137
141{
143 int ret;
144
145 ret = avfilter_graph_segment_parse(graph, filters, 0, &seg);
146 if (ret < 0)
147 return ret;
148
151 if (ret < 0)
152 goto end;
153
154 return 0;
155
156end:
157 while (graph->nb_filters)
158 avfilter_free(graph->filters[0]);
159 av_freep(&graph->filters);
160
161 return ret;
162}
163
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 }
222 avfilter_inout_free(&open_inputs);
223 avfilter_inout_free(&open_outputs);
224 return ret;
225}
226
228{
229 AVFilterPadParams *fpp = *pfpp;
230
231 if (!fpp)
232 return;
233
234 av_freep(&fpp->label);
235
236 av_freep(pfpp);
237}
238
240{
241 AVFilterParams *p = *pp;
242
243 if (!p)
244 return;
245
246 for (unsigned i = 0; i < p->nb_inputs; i++)
247 pad_params_free(&p->inputs[i]);
248 av_freep(&p->inputs);
249
250 for (unsigned i = 0; i < p->nb_outputs; i++)
251 pad_params_free(&p->outputs[i]);
252 av_freep(&p->outputs);
253
254 av_dict_free(&p->opts);
255
256 av_freep(&p->filter_name);
257 av_freep(&p->instance_name);
258
259 av_freep(pp);
260}
261
262static void chain_free(AVFilterChain **pch)
263{
264 AVFilterChain *ch = *pch;
265
266 if (!ch)
267 return;
268
269 for (size_t i = 0; i < ch->nb_filters; i++)
271 av_freep(&ch->filters);
272
273 av_freep(pch);
274}
275
277{
278 AVFilterGraphSegment *seg = *pseg;
279
280 if (!seg)
281 return;
282
283 for (size_t i = 0; i < seg->nb_chains; i++)
284 chain_free(&seg->chains[i]);
285 av_freep(&seg->chains);
286
288
289 av_freep(pseg);
290}
291
292static int linklabels_parse(void *logctx, const char **linklabels,
293 AVFilterPadParams ***res, unsigned *nb_res)
294{
295 AVFilterPadParams **pp = NULL;
296 int nb = 0;
297 int ret;
298
299 while (**linklabels == '[') {
300 char *label;
302
303 label = parse_link_name(linklabels, logctx);
304 if (!label) {
305 ret = AVERROR(EINVAL);
306 goto fail;
307 }
308
309 par = av_mallocz(sizeof(*par));
310 if (!par) {
311 av_freep(&label);
312 ret = AVERROR(ENOMEM);
313 goto fail;
314 }
315
316 par->label = label;
317
318 ret = av_dynarray_add_nofree(&pp, &nb, par);
319 if (ret < 0) {
320 pad_params_free(&par);
321 goto fail;
322 }
323
324 *linklabels += strspn(*linklabels, WHITESPACES);
325 }
326
327 *res = pp;
328 *nb_res = nb;
329
330 return 0;
331fail:
332 for (unsigned i = 0; i < nb; i++)
333 pad_params_free(&pp[i]);
334 av_freep(&pp);
335 return ret;
336}
337
338static int filter_parse(void *logctx, const char **filter,
339 AVFilterParams **pp)
340{
342 char *inst_name;
343 int ret;
344
345 p = av_mallocz(sizeof(*p));
346 if (!p)
347 return AVERROR(ENOMEM);
348
349 ret = linklabels_parse(logctx, filter, &p->inputs, &p->nb_inputs);
350 if (ret < 0)
351 goto fail;
352
353 p->filter_name = av_get_token(filter, "=,;[");
354 if (!p->filter_name) {
355 ret = AVERROR(ENOMEM);
356 goto fail;
357 }
358
359 inst_name = strchr(p->filter_name, '@');
360 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 if (**filter == '=') {
370 const AVFilter *f = avfilter_get_by_name(p->filter_name);
371 char *opts;
372
373 (*filter)++;
374
375 opts = av_get_token(filter, "[],;");
376 if (!opts) {
377 ret = AVERROR(ENOMEM);
378 goto fail;
379 }
380
381 ret = ff_filter_opt_parse(logctx, f ? f->priv_class : NULL,
382 &p->opts, opts);
383 av_freep(&opts);
384 if (ret < 0)
385 goto fail;
386 }
387
388 ret = linklabels_parse(logctx, filter, &p->outputs, &p->nb_outputs);
389 if (ret < 0)
390 goto fail;
391
392 *filter += strspn(*filter, WHITESPACES);
393
394 *pp = p;
395 return 0;
396fail:
397 av_log(logctx, AV_LOG_ERROR,
398 "Error parsing a filter description around: %s\n", *filter);
400 return ret;
401}
402
403static int chain_parse(void *logctx, const char **pchain,
404 AVFilterChain **pch)
405{
406 const char *chain = *pchain;
407 AVFilterChain *ch;
408 int ret, nb_filters = 0;
409
410 *pch = NULL;
411
412 ch = av_mallocz(sizeof(*ch));
413 if (!ch)
414 return AVERROR(ENOMEM);
415
416 while (*chain) {
418 char chr;
419
420 ret = filter_parse(logctx, &chain, &p);
421 if (ret < 0)
422 goto fail;
423
424 ret = av_dynarray_add_nofree(&ch->filters, &nb_filters, p);
425 if (ret < 0) {
427 goto fail;
428 }
429 ch->nb_filters = nb_filters;
430
431 // a filter ends with one of: , ; end-of-string
432 chr = *chain;
433 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 if (chr) {
441 chain++;
442 chain += strspn(chain, WHITESPACES);
443
444 if (chr == ';')
445 break;
446 }
447 }
448
449 *pchain = chain;
450 *pch = ch;
451
452 return 0;
453fail:
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
460int avfilter_graph_segment_parse(AVFilterGraph *graph, const char *graph_str,
461 int flags, AVFilterGraphSegment **pseg)
462{
464 int ret, nb_chains = 0;
465
466 *pseg = NULL;
467
468 if (flags)
469 return AVERROR(ENOSYS);
470
471 seg = av_mallocz(sizeof(*seg));
472 if (!seg)
473 return AVERROR(ENOMEM);
474
475 seg->graph = graph;
476
477 graph_str += strspn(graph_str, WHITESPACES);
478
479 ret = parse_sws_flags(&graph_str, &seg->scale_sws_opts, graph);
480 if (ret < 0)
481 goto fail;
482
483 graph_str += strspn(graph_str, WHITESPACES);
484
485 while (*graph_str) {
486 AVFilterChain *ch;
487
488 ret = chain_parse(graph, &graph_str, &ch);
489 if (ret < 0)
490 goto fail;
491
492 ret = av_dynarray_add_nofree(&seg->chains, &nb_chains, ch);
493 if (ret < 0) {
494 chain_free(&ch);
495 goto fail;
496 }
497 seg->nb_chains = nb_chains;
498
499 graph_str += strspn(graph_str, WHITESPACES);
500 }
501
502 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 *pseg = seg;
509
510 return 0;
511fail:
513 return ret;
514}
515
517{
518 size_t idx = 0;
519
520 if (flags)
521 return AVERROR(ENOSYS);
522
523 if (seg->scale_sws_opts) {
526 if (!seg->graph->scale_sws_opts)
527 return AVERROR(ENOMEM);
528 }
529
530 for (size_t i = 0; i < seg->nb_chains; i++) {
531 AVFilterChain *ch = seg->chains[i];
532
533 for (size_t j = 0; j < ch->nb_filters; j++) {
534 AVFilterParams *p = ch->filters[j];
535 const AVFilter *f = avfilter_get_by_name(p->filter_name);
536 char name[64];
537
538 // skip already processed filters
539 if (p->filter || !p->filter_name)
540 continue;
541
542 if (!f) {
544 "No such filter: '%s'\n", p->filter_name);
546 }
547
548 if (!p->instance_name)
549 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 p->filter = avfilter_graph_alloc_filter(seg->graph, f, name);
554 if (!p->filter)
555 return AVERROR(ENOMEM);
556
557 if (!strcmp(f->name, "scale") && seg->graph->scale_sws_opts) {
558 int ret = av_set_options_string(p->filter, seg->graph->scale_sws_opts,
559 "=", ":");
560 if (ret < 0) {
561 avfilter_free(p->filter);
562 p->filter = NULL;
563 return ret;
564 }
565 }
566
567 av_freep(&p->filter_name);
568 av_freep(&p->instance_name);
569
570 idx++;
571 }
572 }
573
574 return 0;
575}
576
577static int fail_creation_pending(AVFilterGraphSegment *seg, const char *fn,
578 const char *func)
579{
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
587{
588 int ret, leftover_opts = 0;
589
590 if (flags)
591 return AVERROR(ENOSYS);
592
593 for (size_t i = 0; i < seg->nb_chains; i++) {
594 AVFilterChain *ch = seg->chains[i];
595
596 for (size_t j = 0; j < ch->nb_filters; j++) {
597 AVFilterParams *p = ch->filters[j];
598
599 if (p->filter_name)
600 return fail_creation_pending(seg, p->filter_name, __func__);
601 if (!p->filter || !p->opts)
602 continue;
603
604 ret = av_opt_set_dict2(p->filter, &p->opts, AV_OPT_SEARCH_CHILDREN);
605 if (ret < 0)
606 return ret;
607
608 if (av_dict_count(p->opts))
609 leftover_opts = 1;
610 }
611 }
612
613 return leftover_opts ? AVERROR_OPTION_NOT_FOUND : 0;
614}
615
617{
618 if (flags)
619 return AVERROR(ENOSYS);
620
621 for (size_t i = 0; i < seg->nb_chains; i++) {
622 AVFilterChain *ch = seg->chains[i];
623
624 for (size_t j = 0; j < ch->nb_filters; j++) {
625 AVFilterParams *p = ch->filters[j];
626 int ret;
627
628 if (p->filter_name)
629 return fail_creation_pending(seg, p->filter_name, __func__);
630 if (!p->filter ||
631 (fffilterctx(p->filter)->state_flags & AV_CLASS_STATE_INITIALIZED))
632 continue;
633
634 ret = avfilter_init_dict(p->filter, NULL);
635 if (ret < 0)
636 return ret;
637 }
638 }
639
640 return 0;
641}
642
643static unsigned
644find_linklabel(AVFilterGraphSegment *seg, const char *label,
645 int output, size_t idx_chain, size_t idx_filter,
646 AVFilterParams **pp)
647{
648 for (; idx_chain < seg->nb_chains; idx_chain++) {
649 AVFilterChain *ch = seg->chains[idx_chain];
650
651 for (; idx_filter < ch->nb_filters; idx_filter++) {
652 AVFilterParams *p = ch->filters[idx_filter];
653 AVFilterPadParams **io = output ? p->outputs : p->inputs;
654 unsigned nb_io = output ? p->nb_outputs : p->nb_inputs;
655 AVFilterLink **l;
656 unsigned nb_l;
657
658 if (!p->filter)
659 continue;
660
661 l = output ? p->filter->outputs : p->filter->inputs;
662 nb_l = output ? p->filter->nb_outputs : p->filter->nb_inputs;
663
664 for (unsigned i = 0; i < FFMIN(nb_io, nb_l); i++)
665 if (!l[i] && io[i]->label && !strcmp(io[i]->label, label)) {
666 *pp = p;
667 return i;
668 }
669 }
670
671 idx_filter = 0;
672 }
673
674 *pp = NULL;
675 return 0;
676}
677
678static int inout_add(AVFilterInOut **inouts, AVFilterContext *f, unsigned pad_idx,
679 const char *label)
680{
681 AVFilterInOut *io = av_mallocz(sizeof(*io));
682
683 if (!io)
684 return AVERROR(ENOMEM);
685
686 io->filter_ctx = f;
687 io->pad_idx = pad_idx;
688
689 if (label) {
690 io->name = av_strdup(label);
691 if (!io->name) {
693 return AVERROR(ENOMEM);
694 }
695 }
696
697 append_inout(inouts, &io);
698
699 return 0;
700}
701
702static int link_inputs(AVFilterGraphSegment *seg, size_t idx_chain,
703 size_t idx_filter, AVFilterInOut **inputs)
704{
705 AVFilterChain *ch = seg->chains[idx_chain];
706 AVFilterParams *p = ch->filters[idx_filter];
707 AVFilterContext *f = p->filter;
708
709 int ret;
710
711 if (f->nb_inputs < p->nb_inputs) {
713 "More input link labels specified for filter '%s' than "
714 "it has inputs: %u > %d\n", f->filter->name,
715 p->nb_inputs, f->nb_inputs);
716 return AVERROR(EINVAL);
717 }
718
719 for (unsigned in = 0; in < f->nb_inputs; in++) {
720 const char *label = (in < p->nb_inputs) ? p->inputs[in]->label : NULL;
721
722 // skip already linked inputs
723 if (f->inputs[in])
724 continue;
725
726 if (label) {
727 AVFilterParams *po = NULL;
728 unsigned idx = find_linklabel(seg, label, 1, idx_chain, idx_filter, &po);
729
730 if (po) {
731 ret = avfilter_link(po->filter, idx, f, in);
732 if (ret < 0)
733 return ret;
734
735 continue;
736 }
737 }
738
739 ret = inout_add(inputs, f, in, label);
740 if (ret < 0)
741 return ret;
742 }
743
744 return 0;
745}
746
747static int link_outputs(AVFilterGraphSegment *seg, size_t idx_chain,
748 size_t idx_filter, AVFilterInOut **outputs)
749{
750 AVFilterChain *ch = seg->chains[idx_chain];
751 AVFilterParams *p = ch->filters[idx_filter];
752 AVFilterContext *f = p->filter;
753
754 int ret;
755
756 if (f->nb_outputs < p->nb_outputs) {
758 "More output link labels specified for filter '%s' than "
759 "it has outputs: %u > %d\n", f->filter->name,
760 p->nb_outputs, f->nb_outputs);
761 return AVERROR(EINVAL);
762 }
763 for (unsigned out = 0; out < f->nb_outputs; out++) {
764 char *label = (out < p->nb_outputs) ? p->outputs[out]->label : NULL;
765
766 // skip already linked outputs
767 if (f->outputs[out])
768 continue;
769
770 if (label) {
771 AVFilterParams *po = NULL;
772 unsigned idx = find_linklabel(seg, label, 0, idx_chain, idx_filter, &po);
773
774 if (po) {
775 ret = avfilter_link(f, out, po->filter, idx);
776 if (ret < 0)
777 return ret;
778
779 continue;
780 }
781 }
782
783 // if this output is unlabeled, try linking it to an unlabeled
784 // input in the next non-disabled filter in the chain
785 for (size_t i = idx_filter + 1; i < ch->nb_filters && !label; i++) {
786 AVFilterParams *p_next = ch->filters[i];
787
788 if (!p_next->filter)
789 continue;
790
791 for (unsigned in = 0; in < p_next->filter->nb_inputs; in++) {
792 if (!p_next->filter->inputs[in] &&
793 (in >= p_next->nb_inputs || !p_next->inputs[in]->label)) {
794 ret = avfilter_link(f, out, p_next->filter, in);
795 if (ret < 0)
796 return ret;
797
798 goto cont;
799 }
800 }
801 break;
802 }
803
804 ret = inout_add(outputs, f, out, label);
805 if (ret < 0)
806 return ret;
807
808cont:;
809 }
810
811 return 0;
812}
813
817{
818 int ret;
819
820 *inputs = NULL;
821 *outputs = NULL;
822
823 if (flags)
824 return AVERROR(ENOSYS);
825
826 for (size_t idx_chain = 0; idx_chain < seg->nb_chains; idx_chain++) {
827 AVFilterChain *ch = seg->chains[idx_chain];
828
829 for (size_t idx_filter = 0; idx_filter < ch->nb_filters; idx_filter++) {
830 AVFilterParams *p = ch->filters[idx_filter];
831
832 if (p->filter_name) {
833 ret = fail_creation_pending(seg, p->filter_name, __func__);
834 goto fail;
835 }
836
837 if (!p->filter)
838 continue;
839
840 ret = link_inputs(seg, idx_chain, idx_filter, inputs);
841 if (ret < 0)
842 goto fail;
843
844 ret = link_outputs(seg, idx_chain, idx_filter, outputs);
845 if (ret < 0)
846 goto fail;
847 }
848 }
849 return 0;
850fail:
853 return ret;
854}
855
856// print an error message if some options were not found
858{
859 for (size_t i = 0; i < seg->nb_chains; i++) {
860 const AVFilterChain *ch = seg->chains[i];
861
862 for (size_t j = 0; j < ch->nb_filters; j++) {
863 const AVFilterParams *p = ch->filters[j];
864 const AVDictionaryEntry *e;
865
866 if (!p->filter)
867 continue;
868
869 e = av_dict_iterate(p->opts, NULL);
870
871 if (e) {
872 av_log(p->filter, AV_LOG_ERROR,
873 "Could not set non-existent option '%s' to value '%s'\n",
874 e->key, e->value);
875 return;
876 }
877 }
878 }
879
880}
881
885{
886 int ret;
887
888 if (flags)
889 return AVERROR(ENOSYS);
890
892 if (ret < 0) {
893 av_log(seg->graph, AV_LOG_ERROR, "Error creating filters\n");
894 return ret;
895 }
896
898 if (ret < 0) {
899 if (ret == AVERROR_OPTION_NOT_FOUND)
900 log_unknown_opt(seg);
901 av_log(seg->graph, AV_LOG_ERROR, "Error applying filter options\n");
902 return ret;
903 }
904
905 ret = avfilter_graph_segment_init(seg, 0);
906 if (ret < 0) {
907 av_log(seg->graph, AV_LOG_ERROR, "Error initializing filters\n");
908 return ret;
909 }
910
912 if (ret < 0) {
913 av_log(seg->graph, AV_LOG_ERROR, "Error linking filters\n");
914 return ret;
915 }
916
917 return 0;
918}
919
921 AVFilterInOut **open_inputs_ptr, AVFilterInOut **open_outputs_ptr,
922 void *log_ctx)
923{
924 AVFilterInOut *user_inputs = open_inputs_ptr ? *open_inputs_ptr : NULL;
925 AVFilterInOut *user_outputs = open_outputs_ptr ? *open_outputs_ptr : NULL;
926
929 AVFilterChain *ch;
931 int ret;
932
933 ret = avfilter_graph_segment_parse(graph, filters, 0, &seg);
934 if (ret < 0)
935 goto end;
936
938 if (ret < 0)
939 goto end;
940
942 if (ret < 0) {
943 if (ret == AVERROR_OPTION_NOT_FOUND)
944 log_unknown_opt(seg);
945 goto end;
946 }
947
948 ret = avfilter_graph_segment_init(seg, 0);
949 if (ret < 0)
950 goto end;
951
952 /* First input pad, assume it is "[in]" if not specified */
953 p = seg->chains[0]->filters[0];
954 if (p->filter->nb_inputs == 1 && !p->inputs) {
955 const char *tmp = "[in]";
956
957 ret = linklabels_parse(graph, &tmp, &p->inputs, &p->nb_inputs);
958 if (ret < 0)
959 goto end;
960 }
961
962 /* Last output pad, assume it is "[out]" if not specified */
963 ch = seg->chains[seg->nb_chains - 1];
964 p = ch->filters[ch->nb_filters - 1];
965 if (p->filter->nb_outputs == 1 && !p->outputs) {
966 const char *tmp = "[out]";
967
968 ret = linklabels_parse(graph, &tmp, &p->outputs, &p->nb_outputs);
969 if (ret < 0)
970 goto end;
971 }
972
975 if (ret < 0)
976 goto end;
977
978 // process user-supplied inputs/outputs
979 while (inputs) {
980 AVFilterInOut *cur, *match = NULL;
981
982 cur = inputs;
983 inputs = cur->next;
984 cur->next = NULL;
985
986 if (cur->name)
987 match = extract_inout(cur->name, &user_outputs);
988
989 if (match) {
990 ret = avfilter_link(match->filter_ctx, match->pad_idx,
991 cur->filter_ctx, cur->pad_idx);
992 avfilter_inout_free(&match);
994 if (ret < 0)
995 goto end;
996 } else
997 append_inout(&user_inputs, &cur);
998 }
999 while (outputs) {
1000 AVFilterInOut *cur, *match = NULL;
1001
1002 cur = outputs;
1003 outputs = cur->next;
1004 cur->next = NULL;
1005
1006 if (cur->name)
1007 match = extract_inout(cur->name, &user_inputs);
1008
1009 if (match) {
1010 ret = avfilter_link(cur->filter_ctx, cur->pad_idx,
1011 match->filter_ctx, match->pad_idx);
1012 avfilter_inout_free(&match);
1013 avfilter_inout_free(&cur);
1014 if (ret < 0)
1015 goto end;
1016 } else
1017 append_inout(&user_outputs, &cur);
1018 }
1019
1020end:
1022
1023 if (ret < 0) {
1024 av_log(graph, AV_LOG_ERROR, "Error processing filtergraph: %s\n",
1025 av_err2str(ret));
1026
1027 while (graph->nb_filters)
1028 avfilter_free(graph->filters[0]);
1029 av_freep(&graph->filters);
1030 }
1031
1032 /* clear open_in/outputs only if not passed as parameters */
1033 if (open_inputs_ptr) *open_inputs_ptr = user_inputs;
1034 else avfilter_inout_free(&user_inputs);
1035 if (open_outputs_ptr) *open_outputs_ptr = user_outputs;
1036 else avfilter_inout_free(&user_outputs);
1037
1040
1041 return ret;
1042}
#define fn(a)
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
static const AVFilterPad inputs[]
Definition af_aap.c:299
static const AVFilterPad outputs[]
Definition af_aap.c:310
#define filters(fmt, type, inverse, clp, inverset, clip, one, clip_fn, packed)
static FILE * out
static AVDictionary * opts
int ff_filter_opt_parse(void *logctx, const AVClass *priv_class, AVDictionary **options, const char *args)
Parse filter options into a dictionary.
Definition avfilter.c:853
Main libavfilter public API header.
static FFFilterContext * fffilterctx(AVFilterContext *ctx)
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define f(width, name)
Definition cbs_vp8.c:236
#define NULL
Definition coverity.c:32
Public dictionary API.
static unsigned find_linklabel(AVFilterGraphSegment *seg, const char *label, int output, size_t idx_chain, size_t idx_filter, AVFilterParams **pp)
static int link_outputs(AVFilterGraphSegment *seg, size_t idx_chain, size_t idx_filter, AVFilterInOut **outputs)
static int filter_parse(void *logctx, const char **filter, AVFilterParams **pp)
static int linklabels_parse(void *logctx, const char **linklabels, AVFilterPadParams ***res, unsigned *nb_res)
static int parse_sws_flags(const char **buf, char **dst, void *log_ctx)
static int chain_parse(void *logctx, const char **pchain, AVFilterChain **pch)
static int inout_add(AVFilterInOut **inouts, AVFilterContext *f, unsigned pad_idx, const char *label)
static void append_inout(AVFilterInOut **inouts, AVFilterInOut **element)
static AVFilterInOut * extract_inout(const char *label, AVFilterInOut **links)
Definition graphparser.c:86
static void filter_params_free(AVFilterParams **pp)
static void log_unknown_opt(const AVFilterGraphSegment *seg)
static int fail_creation_pending(AVFilterGraphSegment *seg, const char *fn, const char *func)
static void chain_free(AVFilterChain **pch)
static void pad_params_free(AVFilterPadParams **pfpp)
static char * parse_link_name(const char **buf, void *log_ctx)
Parse the name of a link, which has the format "[linkname]".
Definition graphparser.c:43
#define WHITESPACES
Definition graphparser.c:35
static int link_inputs(AVFilterGraphSegment *seg, size_t idx_chain, size_t idx_filter, AVFilterInOut **inputs)
#define fail
Definition test.h:479
void avfilter_free(AVFilterContext *filter)
Free a filter context.
Definition avfilter.c:800
const AVFilter * avfilter_get_by_name(const char *name)
Get a filter definition matching the given name.
Definition allfilters.c:654
void avfilter_inout_free(AVFilterInOut **inout)
Free the supplied list of AVFilterInOut and set *inout to NULL.
Definition graphparser.c:76
int avfilter_graph_segment_parse(AVFilterGraph *graph, const char *graph_str, int flags, AVFilterGraphSegment **pseg)
Parse a textual filtergraph description into an intermediate form.
int avfilter_graph_parse_ptr(AVFilterGraph *graph, const char *filters, AVFilterInOut **open_inputs_ptr, AVFilterInOut **open_outputs_ptr, void *log_ctx)
Add a graph described by a string to a graph.
void avfilter_graph_segment_free(AVFilterGraphSegment **pseg)
Free the provided AVFilterGraphSegment and everything associated with it.
AVFilterContext * avfilter_graph_alloc_filter(AVFilterGraph *graph, const AVFilter *filter, const char *name)
Create a new filter instance in a filter graph.
int avfilter_graph_parse2(AVFilterGraph *graph, const char *filters, AVFilterInOut **inputs, AVFilterInOut **outputs)
Add a graph described by a string to a graph.
int avfilter_init_dict(AVFilterContext *ctx, AVDictionary **options)
Initialize a filter with the supplied dictionary of options.
Definition avfilter.c:919
int avfilter_graph_segment_apply_opts(AVFilterGraphSegment *seg, int flags)
Apply parsed options to filter instances in a graph segment.
int avfilter_graph_segment_init(AVFilterGraphSegment *seg, int flags)
Initialize all filter instances in a graph segment.
int avfilter_graph_parse(AVFilterGraph *graph, const char *filters, AVFilterInOut *open_inputs, AVFilterInOut *open_outputs, void *log_ctx)
Add a graph described by a string to a graph.
int avfilter_link(AVFilterContext *src, unsigned srcpad, AVFilterContext *dst, unsigned dstpad)
Link two filters together.
Definition avfilter.c:149
int avfilter_graph_segment_link(AVFilterGraphSegment *seg, int flags, AVFilterInOut **inputs, AVFilterInOut **outputs)
Link filters in a graph segment.
int avfilter_graph_segment_apply(AVFilterGraphSegment *seg, int flags, AVFilterInOut **inputs, AVFilterInOut **outputs)
Apply all filter/link descriptions from a graph segment to the associated filtergraph.
int avfilter_graph_segment_create_filters(AVFilterGraphSegment *seg, int flags)
Create filters specified in a graph segment.
AVFilterInOut * avfilter_inout_alloc(void)
Allocate a single AVFilterInOut entry.
Definition graphparser.c:71
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition dict.c:233
const AVDictionaryEntry * av_dict_iterate(const AVDictionary *m, const AVDictionaryEntry *prev)
Iterate over a dictionary.
Definition dict.c:42
int av_dict_count(const AVDictionary *m)
Get number of entries in dictionary.
Definition dict.c:37
#define AVERROR_FILTER_NOT_FOUND
Filter not found.
Definition error.h:60
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition error.h:122
#define AVERROR(e)
Definition error.h:45
#define AVERROR_OPTION_NOT_FOUND
Option not found.
Definition error.h:63
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem)
Add an element to a dynamic array.
Definition mem.c:313
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
Definition avstring.c:85
char * av_get_token(const char **buf, const char *term)
Unescape the given string until a non escaped terminating char, and return the token corresponding to...
Definition avstring.c:143
#define AV_OPT_SEARCH_CHILDREN
Search in possible children of the given object first.
Definition opt.h:604
int av_opt_set_dict2(void *obj, AVDictionary **options, int search_flags)
Set all the options from a given dictionary on an object.
Definition opt.c:2040
int av_set_options_string(void *ctx, const char *opts, const char *key_val_sep, const char *pairs_sep)
Parse the key/value pairs list in opts.
Definition opt.c:1895
int(* func)(AVBPrint *dst, const char *in, const char *arg)
Definition jacosubdec.c:66
@ AV_CLASS_STATE_INITIALIZED
Object initialization has finished and it is now in the 'runtime' stage.
Definition log.h:56
#define FFMIN(a, b)
Definition macros.h:49
Memory handling functions.
#define av_strdup(s)
Definition ops_static.c:55
AVOptions.
const char * name
Definition qsvenc.c:142
#define snprintf
Definition snprintf.h:34
char * key
Definition dict.h:91
char * value
Definition dict.h:92
A filterchain is a list of filter specifications.
Definition avfilter.h:904
size_t nb_filters
Definition avfilter.h:906
AVFilterParams ** filters
Definition avfilter.h:905
An instance of a filter.
Definition avfilter.h:273
unsigned nb_inputs
number of input pads
Definition avfilter.h:282
AVFilterLink ** inputs
array of pointers to input links
Definition avfilter.h:281
const AVFilter * filter
the AVFilter of which this is an instance
Definition avfilter.h:276
A parsed representation of a filtergraph segment.
Definition avfilter.h:918
char * scale_sws_opts
A string containing a colon-separated list of key=value options applied to all scale filters in this ...
Definition avfilter.h:940
AVFilterGraph * graph
The filtergraph this segment is associated with.
Definition avfilter.h:923
AVFilterChain ** chains
A list of filter chain contained in this segment.
Definition avfilter.h:929
unsigned nb_filters
Definition avfilter.h:564
char * scale_sws_opts
sws options to use for the auto-inserted scale filters
Definition avfilter.h:566
AVFilterContext ** filters
Definition avfilter.h:563
A linked-list of the inputs/outputs of the filter chain.
Definition avfilter.h:718
AVFilterContext * filter_ctx
filter context associated to this input/output
Definition avfilter.h:723
int pad_idx
index of the filt_ctx pad to use for linking
Definition avfilter.h:726
char * name
unique name for this input/output in the list
Definition avfilter.h:720
struct AVFilterInOut * next
next input/input in the list, NULL if this is the last
Definition avfilter.h:729
Parameters of a filter's input or output pad.
Definition avfilter.h:820
char * label
An av_malloc()'ed string containing the pad label.
Definition avfilter.h:828
Parameters describing a filter to be created in a filtergraph.
Definition avfilter.h:837
unsigned nb_inputs
Definition avfilter.h:892
AVFilterPadParams ** inputs
Definition avfilter.h:891
AVFilterContext * filter
The filter context.
Definition avfilter.h:848
Filter definition.
Definition avfilter.h:215
const char * name
Filter name.
Definition avfilter.h:219
#define av_mallocz(s)
#define av_freep(p)
#define av_log(a,...)
static uint8_t tmp[40]
Definition aes_ctr.c:52
void(* filter)(uint8_t *src, ptrdiff_t stride, int qscale)
Definition h263dsp.c:29