FFmpeg
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 "internal.h"
33 
34 #define WHITESPACES " \n\t\r"
35 
36 /**
37  * Parse the name of a link, which has the format "[linkname]".
38  *
39  * @return a pointer (that need to be freed after use) to the name
40  * between parenthesis
41  */
42 static char *parse_link_name(const char **buf, void *log_ctx)
43 {
44  const char *start = *buf;
45  char *name;
46  (*buf)++;
47 
48  name = av_get_token(buf, "]");
49  if (!name)
50  return NULL;
51 
52  if (!name[0]) {
53  av_log(log_ctx, AV_LOG_ERROR,
54  "Bad (empty?) label found in the following: \"%s\".\n", start);
55  goto fail;
56  }
57 
58  if (**buf != ']') {
59  av_log(log_ctx, AV_LOG_ERROR,
60  "Mismatched '[' found in the following: \"%s\".\n", start);
61  fail:
62  av_freep(&name);
63  return NULL;
64  }
65  (*buf)++;
66 
67  return name;
68 }
69 
71 {
72  return av_mallocz(sizeof(AVFilterInOut));
73 }
74 
76 {
77  while (*inout) {
78  AVFilterInOut *next = (*inout)->next;
79  av_freep(&(*inout)->name);
80  av_freep(inout);
81  *inout = next;
82  }
83 }
84 
85 static AVFilterInOut *extract_inout(const char *label, AVFilterInOut **links)
86 {
88 
89  while (*links && (!(*links)->name || strcmp((*links)->name, label)))
90  links = &((*links)->next);
91 
92  ret = *links;
93 
94  if (ret) {
95  *links = ret->next;
96  ret->next = NULL;
97  }
98 
99  return ret;
100 }
101 
102 static void append_inout(AVFilterInOut **inouts, AVFilterInOut **element)
103 {
104  while (*inouts && (*inouts)->next)
105  inouts = &((*inouts)->next);
106 
107  if (!*inouts)
108  *inouts = *element;
109  else
110  (*inouts)->next = *element;
111  *element = NULL;
112 }
113 
114 static int parse_sws_flags(const char **buf, char **dst, void *log_ctx)
115 {
116  char *p = strchr(*buf, ';');
117 
118  if (strncmp(*buf, "sws_flags=", 10))
119  return 0;
120 
121  if (!p) {
122  av_log(log_ctx, AV_LOG_ERROR, "sws_flags not terminated with ';'.\n");
123  return AVERROR(EINVAL);
124  }
125 
126  *buf += 4; // keep the 'flags=' part
127 
128  av_freep(dst);
129  if (!(*dst = av_mallocz(p - *buf + 1)))
130  return AVERROR(ENOMEM);
131  av_strlcpy(*dst, *buf, p - *buf + 1);
132 
133  *buf = p + 1;
134  return 0;
135 }
136 
140 {
142  int ret;
143 
144  ret = avfilter_graph_segment_parse(graph, filters, 0, &seg);
145  if (ret < 0)
146  return ret;
147 
150  if (ret < 0)
151  goto end;
152 
153  return 0;
154 
155 end:
156  while (graph->nb_filters)
157  avfilter_free(graph->filters[0]);
158  av_freep(&graph->filters);
159 
160  return ret;
161 }
162 
164  AVFilterInOut *open_inputs,
165  AVFilterInOut *open_outputs, void *log_ctx)
166 {
167  int ret;
168  AVFilterInOut *cur, *match, *inputs = NULL, *outputs = NULL;
169 
170  if ((ret = avfilter_graph_parse2(graph, filters, &inputs, &outputs)) < 0)
171  goto fail;
172 
173  /* First input can be omitted if it is "[in]" */
174  if (inputs && !inputs->name)
175  inputs->name = av_strdup("in");
176  for (cur = inputs; cur; cur = cur->next) {
177  if (!cur->name) {
178  av_log(log_ctx, AV_LOG_ERROR,
179  "Not enough inputs specified for the \"%s\" filter.\n",
180  cur->filter_ctx->filter->name);
181  ret = AVERROR(EINVAL);
182  goto fail;
183  }
184  if (!(match = extract_inout(cur->name, &open_outputs)))
185  continue;
186  ret = avfilter_link(match->filter_ctx, match->pad_idx,
187  cur->filter_ctx, cur->pad_idx);
188  avfilter_inout_free(&match);
189  if (ret < 0)
190  goto fail;
191  }
192 
193  /* Last output can be omitted if it is "[out]" */
194  if (outputs && !outputs->name)
195  outputs->name = av_strdup("out");
196  for (cur = outputs; cur; cur = cur->next) {
197  if (!cur->name) {
198  av_log(log_ctx, AV_LOG_ERROR,
199  "Invalid filterchain containing an unlabelled output pad: \"%s\"\n",
200  filters);
201  ret = AVERROR(EINVAL);
202  goto fail;
203  }
204  if (!(match = extract_inout(cur->name, &open_inputs)))
205  continue;
206  ret = avfilter_link(cur->filter_ctx, cur->pad_idx,
207  match->filter_ctx, match->pad_idx);
208  avfilter_inout_free(&match);
209  if (ret < 0)
210  goto fail;
211  }
212 
213  fail:
214  if (ret < 0) {
215  while (graph->nb_filters)
216  avfilter_free(graph->filters[0]);
217  av_freep(&graph->filters);
218  }
221  avfilter_inout_free(&open_inputs);
222  avfilter_inout_free(&open_outputs);
223  return ret;
224 }
225 
227 {
228  AVFilterPadParams *fpp = *pfpp;
229 
230  if (!fpp)
231  return;
232 
233  av_freep(&fpp->label);
234 
235  av_freep(pfpp);
236 }
237 
239 {
240  AVFilterParams *p = *pp;
241 
242  if (!p)
243  return;
244 
245  for (unsigned i = 0; i < p->nb_inputs; i++)
246  pad_params_free(&p->inputs[i]);
247  av_freep(&p->inputs);
248 
249  for (unsigned i = 0; i < p->nb_outputs; i++)
250  pad_params_free(&p->outputs[i]);
251  av_freep(&p->outputs);
252 
253  av_dict_free(&p->opts);
254 
255  av_freep(&p->filter_name);
256  av_freep(&p->instance_name);
257 
258  av_freep(pp);
259 }
260 
261 static void chain_free(AVFilterChain **pch)
262 {
263  AVFilterChain *ch = *pch;
264 
265  if (!ch)
266  return;
267 
268  for (size_t i = 0; i < ch->nb_filters; i++)
270  av_freep(&ch->filters);
271 
272  av_freep(pch);
273 }
274 
276 {
277  AVFilterGraphSegment *seg = *pseg;
278 
279  if (!seg)
280  return;
281 
282  for (size_t i = 0; i < seg->nb_chains; i++)
283  chain_free(&seg->chains[i]);
284  av_freep(&seg->chains);
285 
286  av_freep(&seg->scale_sws_opts);
287 
288  av_freep(pseg);
289 }
290 
291 static int linklabels_parse(void *logctx, const char **linklabels,
292  AVFilterPadParams ***res, unsigned *nb_res)
293 {
294  AVFilterPadParams **pp = NULL;
295  int nb = 0;
296  int ret;
297 
298  while (**linklabels == '[') {
299  char *label;
300  AVFilterPadParams *par;
301 
302  label = parse_link_name(linklabels, logctx);
303  if (!label) {
304  ret = AVERROR(EINVAL);
305  goto fail;
306  }
307 
308  par = av_mallocz(sizeof(*par));
309  if (!par) {
310  av_freep(&label);
311  ret = AVERROR(ENOMEM);
312  goto fail;
313  }
314 
315  par->label = label;
316 
317  ret = av_dynarray_add_nofree(&pp, &nb, par);
318  if (ret < 0) {
319  pad_params_free(&par);
320  goto fail;
321  }
322 
323  *linklabels += strspn(*linklabels, WHITESPACES);
324  }
325 
326  *res = pp;
327  *nb_res = nb;
328 
329  return 0;
330 fail:
331  for (unsigned i = 0; i < nb; i++)
332  pad_params_free(&pp[i]);
333  av_freep(&pp);
334  return ret;
335 }
336 
337 static int filter_parse(void *logctx, const char **filter,
338  AVFilterParams **pp)
339 {
340  AVFilterParams *p;
341  char *inst_name;
342  int ret;
343 
344  p = av_mallocz(sizeof(*p));
345  if (!p)
346  return AVERROR(ENOMEM);
347 
348  ret = linklabels_parse(logctx, filter, &p->inputs, &p->nb_inputs);
349  if (ret < 0)
350  goto fail;
351 
352  p->filter_name = av_get_token(filter, "=,;[");
353  if (!p->filter_name) {
354  ret = AVERROR(ENOMEM);
355  goto fail;
356  }
357 
358  inst_name = strchr(p->filter_name, '@');
359  if (inst_name) {
360  *inst_name++ = 0;
361  p->instance_name = av_strdup(inst_name);
362  if (!p->instance_name) {
363  ret = AVERROR(ENOMEM);
364  goto fail;
365  }
366  }
367 
368  if (**filter == '=') {
370  char *opts;
371 
372  (*filter)++;
373 
374  opts = av_get_token(filter, "[],;");
375  if (!opts) {
376  ret = AVERROR(ENOMEM);
377  goto fail;
378  }
379 
380  ret = ff_filter_opt_parse(logctx, f ? f->priv_class : NULL,
381  &p->opts, opts);
382  av_freep(&opts);
383  if (ret < 0)
384  goto fail;
385  }
386 
387  ret = linklabels_parse(logctx, filter, &p->outputs, &p->nb_outputs);
388  if (ret < 0)
389  goto fail;
390 
391  *filter += strspn(*filter, WHITESPACES);
392 
393  *pp = p;
394  return 0;
395 fail:
396  av_log(logctx, AV_LOG_ERROR,
397  "Error parsing a filter description around: %s\n", *filter);
398  filter_params_free(&p);
399  return ret;
400 }
401 
402 static int chain_parse(void *logctx, const char **pchain,
403  AVFilterChain **pch)
404 {
405  const char *chain = *pchain;
406  AVFilterChain *ch;
407  int ret, nb_filters = 0;
408 
409  *pch = NULL;
410 
411  ch = av_mallocz(sizeof(*ch));
412  if (!ch)
413  return AVERROR(ENOMEM);
414 
415  while (*chain) {
416  AVFilterParams *p;
417  char chr;
418 
419  ret = filter_parse(logctx, &chain, &p);
420  if (ret < 0)
421  goto fail;
422 
423  ret = av_dynarray_add_nofree(&ch->filters, &nb_filters, p);
424  if (ret < 0) {
425  filter_params_free(&p);
426  goto fail;
427  }
428  ch->nb_filters = nb_filters;
429 
430  // a filter ends with one of: , ; end-of-string
431  chr = *chain;
432  if (chr && chr != ',' && chr != ';') {
433  av_log(logctx, AV_LOG_ERROR,
434  "Trailing garbage after a filter: %s\n", chain);
435  ret = AVERROR(EINVAL);
436  goto fail;
437  }
438 
439  if (chr) {
440  chain++;
441  chain += strspn(chain, WHITESPACES);
442 
443  if (chr == ';')
444  break;
445  }
446  }
447 
448  *pchain = chain;
449  *pch = ch;
450 
451  return 0;
452 fail:
453  av_log(logctx, AV_LOG_ERROR,
454  "Error parsing filterchain '%s' around: %s\n", *pchain, chain);
455  chain_free(&ch);
456  return ret;
457 }
458 
459 int avfilter_graph_segment_parse(AVFilterGraph *graph, const char *graph_str,
460  int flags, AVFilterGraphSegment **pseg)
461 {
463  int ret, nb_chains = 0;
464 
465  *pseg = NULL;
466 
467  if (flags)
468  return AVERROR(ENOSYS);
469 
470  seg = av_mallocz(sizeof(*seg));
471  if (!seg)
472  return AVERROR(ENOMEM);
473 
474  seg->graph = graph;
475 
476  graph_str += strspn(graph_str, WHITESPACES);
477 
478  ret = parse_sws_flags(&graph_str, &seg->scale_sws_opts, graph);
479  if (ret < 0)
480  goto fail;
481 
482  graph_str += strspn(graph_str, WHITESPACES);
483 
484  while (*graph_str) {
485  AVFilterChain *ch;
486 
487  ret = chain_parse(graph, &graph_str, &ch);
488  if (ret < 0)
489  goto fail;
490 
491  ret = av_dynarray_add_nofree(&seg->chains, &nb_chains, ch);
492  if (ret < 0) {
493  chain_free(&ch);
494  goto fail;
495  }
496  seg->nb_chains = nb_chains;
497 
498  graph_str += strspn(graph_str, WHITESPACES);
499  }
500 
501  if (!seg->nb_chains) {
502  av_log(graph, AV_LOG_ERROR, "No filters specified in the graph description\n");
503  ret = AVERROR(EINVAL);
504  goto fail;
505  }
506 
507  *pseg = seg;
508 
509  return 0;
510 fail:
512  return ret;
513 }
514 
516 {
517  size_t idx = 0;
518 
519  if (flags)
520  return AVERROR(ENOSYS);
521 
522  if (seg->scale_sws_opts) {
523  av_freep(&seg->graph->scale_sws_opts);
525  if (!seg->graph->scale_sws_opts)
526  return AVERROR(ENOMEM);
527  }
528 
529  for (size_t i = 0; i < seg->nb_chains; i++) {
530  AVFilterChain *ch = seg->chains[i];
531 
532  for (size_t j = 0; j < ch->nb_filters; j++) {
533  AVFilterParams *p = ch->filters[j];
535  char name[64];
536 
537  // skip already processed filters
538  if (p->filter || !p->filter_name)
539  continue;
540 
541  if (!f) {
542  av_log(seg->graph, AV_LOG_ERROR,
543  "No such filter: '%s'\n", p->filter_name);
545  }
546 
547  if (!p->instance_name)
548  snprintf(name, sizeof(name), "Parsed_%s_%zu", f->name, idx);
549  else
550  snprintf(name, sizeof(name), "%s@%s", f->name, p->instance_name);
551 
553  if (!p->filter)
554  return AVERROR(ENOMEM);
555 
556  if (!strcmp(f->name, "scale") && seg->graph->scale_sws_opts) {
558  "=", ":");
559  if (ret < 0) {
560  avfilter_free(p->filter);
561  p->filter = NULL;
562  return ret;
563  }
564  }
565 
566  av_freep(&p->filter_name);
567  av_freep(&p->instance_name);
568 
569  idx++;
570  }
571  }
572 
573  return 0;
574 }
575 
576 static int fail_creation_pending(AVFilterGraphSegment *seg, const char *fn,
577  const char *func)
578 {
579  av_log(seg->graph, AV_LOG_ERROR,
580  "A creation-pending filter '%s' present in the segment. All filters "
581  "must be created or disabled before calling %s().\n", fn, func);
582  return AVERROR(EINVAL);
583 }
584 
586 {
587  int ret, leftover_opts = 0;
588 
589  if (flags)
590  return AVERROR(ENOSYS);
591 
592  for (size_t i = 0; i < seg->nb_chains; i++) {
593  AVFilterChain *ch = seg->chains[i];
594 
595  for (size_t j = 0; j < ch->nb_filters; j++) {
596  AVFilterParams *p = ch->filters[j];
597 
598  if (p->filter_name)
599  return fail_creation_pending(seg, p->filter_name, __func__);
600  if (!p->filter || !p->opts)
601  continue;
602 
604  if (ret < 0)
605  return ret;
606 
607  if (av_dict_count(p->opts))
608  leftover_opts = 1;
609  }
610  }
611 
612  return leftover_opts ? AVERROR_OPTION_NOT_FOUND : 0;
613 }
614 
616 {
617  if (flags)
618  return AVERROR(ENOSYS);
619 
620  for (size_t i = 0; i < seg->nb_chains; i++) {
621  AVFilterChain *ch = seg->chains[i];
622 
623  for (size_t j = 0; j < ch->nb_filters; j++) {
624  AVFilterParams *p = ch->filters[j];
625  int ret;
626 
627  if (p->filter_name)
628  return fail_creation_pending(seg, p->filter_name, __func__);
629  if (!p->filter || p->filter->internal->initialized)
630  continue;
631 
633  if (ret < 0)
634  return ret;
635  }
636  }
637 
638  return 0;
639 }
640 
641 static unsigned
642 find_linklabel(AVFilterGraphSegment *seg, const char *label,
643  int output, size_t idx_chain, size_t idx_filter,
644  AVFilterParams **pp)
645 {
646  for (; idx_chain < seg->nb_chains; idx_chain++) {
647  AVFilterChain *ch = seg->chains[idx_chain];
648 
649  for (; idx_filter < ch->nb_filters; idx_filter++) {
650  AVFilterParams *p = ch->filters[idx_filter];
651  AVFilterPadParams **io = output ? p->outputs : p->inputs;
652  unsigned nb_io = output ? p->nb_outputs : p->nb_inputs;
653  AVFilterLink **l;
654  unsigned nb_l;
655 
656  if (!p->filter)
657  continue;
658 
659  l = output ? p->filter->outputs : p->filter->inputs;
660  nb_l = output ? p->filter->nb_outputs : p->filter->nb_inputs;
661 
662  for (unsigned i = 0; i < FFMIN(nb_io, nb_l); i++)
663  if (!l[i] && io[i]->label && !strcmp(io[i]->label, label)) {
664  *pp = p;
665  return i;
666  }
667  }
668 
669  idx_filter = 0;
670  }
671 
672  *pp = NULL;
673  return 0;
674 }
675 
676 static int inout_add(AVFilterInOut **inouts, AVFilterContext *f, unsigned pad_idx,
677  const char *label)
678 {
679  AVFilterInOut *io = av_mallocz(sizeof(*io));
680 
681  if (!io)
682  return AVERROR(ENOMEM);
683 
684  io->filter_ctx = f;
685  io->pad_idx = pad_idx;
686 
687  if (label) {
688  io->name = av_strdup(label);
689  if (!io->name) {
690  avfilter_inout_free(&io);
691  return AVERROR(ENOMEM);
692  }
693  }
694 
695  append_inout(inouts, &io);
696 
697  return 0;
698 }
699 
700 static int link_inputs(AVFilterGraphSegment *seg, size_t idx_chain,
701  size_t idx_filter, AVFilterInOut **inputs)
702 {
703  AVFilterChain *ch = seg->chains[idx_chain];
704  AVFilterParams *p = ch->filters[idx_filter];
705  AVFilterContext *f = p->filter;
706 
707  int ret;
708 
709  if (f->nb_inputs < p->nb_inputs) {
710  av_log(seg->graph, AV_LOG_ERROR,
711  "More input link labels specified for filter '%s' than "
712  "it has inputs: %u > %d\n", f->filter->name,
713  p->nb_inputs, f->nb_inputs);
714  return AVERROR(EINVAL);
715  }
716 
717  for (unsigned in = 0; in < f->nb_inputs; in++) {
718  const char *label = (in < p->nb_inputs) ? p->inputs[in]->label : NULL;
719 
720  // skip already linked inputs
721  if (f->inputs[in])
722  continue;
723 
724  if (label) {
725  AVFilterParams *po = NULL;
726  unsigned idx = find_linklabel(seg, label, 1, idx_chain, idx_filter, &po);
727 
728  if (po) {
729  ret = avfilter_link(po->filter, idx, f, in);
730  if (ret < 0)
731  return ret;
732 
733  continue;
734  }
735  }
736 
737  ret = inout_add(inputs, f, in, label);
738  if (ret < 0)
739  return ret;
740  }
741 
742  return 0;
743 }
744 
745 static int link_outputs(AVFilterGraphSegment *seg, size_t idx_chain,
746  size_t idx_filter, AVFilterInOut **outputs)
747 {
748  AVFilterChain *ch = seg->chains[idx_chain];
749  AVFilterParams *p = ch->filters[idx_filter];
750  AVFilterContext *f = p->filter;
751 
752  int ret;
753 
754  if (f->nb_outputs < p->nb_outputs) {
755  av_log(seg->graph, AV_LOG_ERROR,
756  "More output link labels specified for filter '%s' than "
757  "it has outputs: %u > %d\n", f->filter->name,
758  p->nb_outputs, f->nb_outputs);
759  return AVERROR(EINVAL);
760  }
761  for (unsigned out = 0; out < f->nb_outputs; out++) {
762  char *label = (out < p->nb_outputs) ? p->outputs[out]->label : NULL;
763 
764  // skip already linked outputs
765  if (f->outputs[out])
766  continue;
767 
768  if (label) {
769  AVFilterParams *po = NULL;
770  unsigned idx = find_linklabel(seg, label, 0, idx_chain, idx_filter, &po);
771 
772  if (po) {
773  ret = avfilter_link(f, out, po->filter, idx);
774  if (ret < 0)
775  return ret;
776 
777  continue;
778  }
779  }
780 
781  // if this output is unlabeled, try linking it to an unlabeled
782  // input in the next non-disabled filter in the chain
783  for (size_t i = idx_filter + 1; i < ch->nb_filters && !label; i++) {
784  AVFilterParams *p_next = ch->filters[i];
785 
786  if (!p_next->filter)
787  continue;
788 
789  for (unsigned in = 0; in < p_next->filter->nb_inputs; in++) {
790  if (!p_next->filter->inputs[in] &&
791  (in >= p_next->nb_inputs || !p_next->inputs[in]->label)) {
792  ret = avfilter_link(f, out, p_next->filter, in);
793  if (ret < 0)
794  return ret;
795 
796  goto cont;
797  }
798  }
799  break;
800  }
801 
802  ret = inout_add(outputs, f, out, label);
803  if (ret < 0)
804  return ret;
805 
806 cont:;
807  }
808 
809  return 0;
810 }
811 
815 {
816  int ret;
817 
818  *inputs = NULL;
819  *outputs = NULL;
820 
821  if (flags)
822  return AVERROR(ENOSYS);
823 
824  for (size_t idx_chain = 0; idx_chain < seg->nb_chains; idx_chain++) {
825  AVFilterChain *ch = seg->chains[idx_chain];
826 
827  for (size_t idx_filter = 0; idx_filter < ch->nb_filters; idx_filter++) {
828  AVFilterParams *p = ch->filters[idx_filter];
829 
830  if (p->filter_name) {
831  ret = fail_creation_pending(seg, p->filter_name, __func__);
832  goto fail;
833  }
834 
835  if (!p->filter)
836  continue;
837 
838  ret = link_inputs(seg, idx_chain, idx_filter, inputs);
839  if (ret < 0)
840  goto fail;
841 
842  ret = link_outputs(seg, idx_chain, idx_filter, outputs);
843  if (ret < 0)
844  goto fail;
845  }
846  }
847  return 0;
848 fail:
851  return ret;
852 }
853 
854 // print an error message if some options were not found
855 static void log_unknown_opt(const AVFilterGraphSegment *seg)
856 {
857  for (size_t i = 0; i < seg->nb_chains; i++) {
858  const AVFilterChain *ch = seg->chains[i];
859 
860  for (size_t j = 0; j < ch->nb_filters; j++) {
861  const AVFilterParams *p = ch->filters[j];
862  const AVDictionaryEntry *e;
863 
864  if (!p->filter)
865  continue;
866 
867  e = av_dict_iterate(p->opts, NULL);
868 
869  if (e) {
871  "Could not set non-existent option '%s' to value '%s'\n",
872  e->key, e->value);
873  return;
874  }
875  }
876  }
877 
878 }
879 
883 {
884  int ret;
885 
886  if (flags)
887  return AVERROR(ENOSYS);
888 
890  if (ret < 0) {
891  av_log(seg->graph, AV_LOG_ERROR, "Error creating filters\n");
892  return ret;
893  }
894 
896  if (ret < 0) {
898  log_unknown_opt(seg);
899  av_log(seg->graph, AV_LOG_ERROR, "Error applying filter options\n");
900  return ret;
901  }
902 
904  if (ret < 0) {
905  av_log(seg->graph, AV_LOG_ERROR, "Error initializing filters\n");
906  return ret;
907  }
908 
910  if (ret < 0) {
911  av_log(seg->graph, AV_LOG_ERROR, "Error linking filters\n");
912  return ret;
913  }
914 
915  return 0;
916 }
917 
919  AVFilterInOut **open_inputs_ptr, AVFilterInOut **open_outputs_ptr,
920  void *log_ctx)
921 {
922  AVFilterInOut *user_inputs = open_inputs_ptr ? *open_inputs_ptr : NULL;
923  AVFilterInOut *user_outputs = open_outputs_ptr ? *open_outputs_ptr : NULL;
924 
926  AVFilterGraphSegment *seg = NULL;
927  AVFilterChain *ch;
928  AVFilterParams *p;
929  int ret;
930 
931  ret = avfilter_graph_segment_parse(graph, filters, 0, &seg);
932  if (ret < 0)
933  goto end;
934 
936  if (ret < 0)
937  goto end;
938 
940  if (ret < 0) {
942  log_unknown_opt(seg);
943  goto end;
944  }
945 
947  if (ret < 0)
948  goto end;
949 
950  /* First input pad, assume it is "[in]" if not specified */
951  p = seg->chains[0]->filters[0];
952  if (p->filter->nb_inputs == 1 && !p->inputs) {
953  const char *tmp = "[in]";
954 
955  ret = linklabels_parse(graph, &tmp, &p->inputs, &p->nb_inputs);
956  if (ret < 0)
957  goto end;
958  }
959 
960  /* Last output pad, assume it is "[out]" if not specified */
961  ch = seg->chains[seg->nb_chains - 1];
962  p = ch->filters[ch->nb_filters - 1];
963  if (p->filter->nb_outputs == 1 && !p->outputs) {
964  const char *tmp = "[out]";
965 
966  ret = linklabels_parse(graph, &tmp, &p->outputs, &p->nb_outputs);
967  if (ret < 0)
968  goto end;
969  }
970 
973  if (ret < 0)
974  goto end;
975 
976  // process user-supplied inputs/outputs
977  while (inputs) {
978  AVFilterInOut *cur, *match = NULL;
979 
980  cur = inputs;
981  inputs = cur->next;
982  cur->next = NULL;
983 
984  if (cur->name)
985  match = extract_inout(cur->name, &user_outputs);
986 
987  if (match) {
988  ret = avfilter_link(match->filter_ctx, match->pad_idx,
989  cur->filter_ctx, cur->pad_idx);
990  avfilter_inout_free(&match);
991  avfilter_inout_free(&cur);
992  if (ret < 0)
993  goto end;
994  } else
995  append_inout(&user_inputs, &cur);
996  }
997  while (outputs) {
998  AVFilterInOut *cur, *match = NULL;
999 
1000  cur = outputs;
1001  outputs = cur->next;
1002  cur->next = NULL;
1003 
1004  if (cur->name)
1005  match = extract_inout(cur->name, &user_inputs);
1006 
1007  if (match) {
1008  ret = avfilter_link(cur->filter_ctx, cur->pad_idx,
1009  match->filter_ctx, match->pad_idx);
1010  avfilter_inout_free(&match);
1011  avfilter_inout_free(&cur);
1012  if (ret < 0)
1013  goto end;
1014  } else
1015  append_inout(&user_outputs, &cur);
1016  }
1017 
1018 end:
1020 
1021  if (ret < 0) {
1022  av_log(graph, AV_LOG_ERROR, "Error processing filtergraph: %s\n",
1023  av_err2str(ret));
1024 
1025  while (graph->nb_filters)
1026  avfilter_free(graph->filters[0]);
1027  av_freep(&graph->filters);
1028  }
1029 
1030  /* clear open_in/outputs only if not passed as parameters */
1031  if (open_inputs_ptr) *open_inputs_ptr = user_inputs;
1032  else avfilter_inout_free(&user_inputs);
1033  if (open_outputs_ptr) *open_outputs_ptr = user_outputs;
1034  else avfilter_inout_free(&user_outputs);
1035 
1038 
1039  return ret;
1040 }
link_inputs
static int link_inputs(AVFilterGraphSegment *seg, size_t idx_chain, size_t idx_filter, AVFilterInOut **inputs)
Definition: graphparser.c:700
func
int(* func)(AVBPrint *dst, const char *in, const char *arg)
Definition: jacosubdec.c:68
name
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option name
Definition: writing_filters.txt:88
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
inout_add
static int inout_add(AVFilterInOut **inouts, AVFilterContext *f, unsigned pad_idx, const char *label)
Definition: graphparser.c:676
AVFilterParams::instance_name
char * instance_name
Name to be used for this filter instance.
Definition: avfilter.h:1183
avfilter_graph_segment_create_filters
int avfilter_graph_segment_create_filters(AVFilterGraphSegment *seg, int flags)
Create filters specified in a graph segment.
Definition: graphparser.c:515
out
FILE * out
Definition: movenc.c:54
ff_filter_opt_parse
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:793
av_dict_count
int av_dict_count(const AVDictionary *m)
Get number of entries in dictionary.
Definition: dict.c:39
output
filter_frame For filters that do not use the this method is called when a frame is pushed to the filter s input It can be called at any time except in a reentrant way If the input frame is enough to produce output
Definition: filter_design.txt:225
parse_sws_flags
static int parse_sws_flags(const char **buf, char **dst, void *log_ctx)
Definition: graphparser.c:114
tmp
static uint8_t tmp[11]
Definition: aes_ctr.c:28
AVFilterInOut::next
struct AVFilterInOut * next
next input/input in the list, NULL if this is the last
Definition: avfilter.h:1035
fail_creation_pending
static int fail_creation_pending(AVFilterGraphSegment *seg, const char *fn, const char *func)
Definition: graphparser.c:576
AVFilterContext::nb_outputs
unsigned nb_outputs
number of output pads
Definition: avfilter.h:410
fn
#define fn(a)
Definition: adynamicequalizer_template.c:61
filter
filter_frame For filters that do not use the this method is called when a frame is pushed to the filter s input It can be called at any time except in a reentrant way If the input frame is enough to produce then the filter should push the output frames on the output link immediately As an exception to the previous rule if the input frame is enough to produce several output frames then the filter needs output only at least one per link The additional frames can be left buffered in the filter
Definition: filter_design.txt:228
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:170
AVFilterInternal::initialized
int initialized
Definition: internal.h:141
AVFilterParams::inputs
AVFilterPadParams ** inputs
Definition: avfilter.h:1197
chain_parse
static int chain_parse(void *logctx, const char **pchain, AVFilterChain **pch)
Definition: graphparser.c:402
AVFilterParams::outputs
AVFilterPadParams ** outputs
Definition: avfilter.h:1200
av_set_options_string
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:1587
append_inout
static void append_inout(AVFilterInOut **inouts, AVFilterInOut **element)
Definition: graphparser.c:102
avfilter_graph_alloc_filter
AVFilterContext * avfilter_graph_alloc_filter(AVFilterGraph *graph, const AVFilter *filter, const char *name)
Create a new filter instance in a filter graph.
Definition: avfiltergraph.c:165
pad_params_free
static void pad_params_free(AVFilterPadParams **pfpp)
Definition: graphparser.c:226
avfilter_graph_segment_link
int avfilter_graph_segment_link(AVFilterGraphSegment *seg, int flags, AVFilterInOut **inputs, AVFilterInOut **outputs)
Link filters in a graph segment.
Definition: graphparser.c:812
fail
#define fail()
Definition: checkasm.h:138
AVERROR_OPTION_NOT_FOUND
#define AVERROR_OPTION_NOT_FOUND
Option not found.
Definition: error.h:63
avfilter_graph_segment_free
void avfilter_graph_segment_free(AVFilterGraphSegment **pseg)
Free the provided AVFilterGraphSegment and everything associated with it.
Definition: graphparser.c:275
avfilter_graph_segment_parse
int avfilter_graph_segment_parse(AVFilterGraph *graph, const char *graph_str, int flags, AVFilterGraphSegment **pseg)
Parse a textual filtergraph description into an intermediate form.
Definition: graphparser.c:459
avfilter_inout_free
void avfilter_inout_free(AVFilterInOut **inout)
Free the supplied list of AVFilterInOut and set *inout to NULL.
Definition: graphparser.c:75
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
find_linklabel
static unsigned find_linklabel(AVFilterGraphSegment *seg, const char *label, int output, size_t idx_chain, size_t idx_filter, AVFilterParams **pp)
Definition: graphparser.c:642
AVFilterChain::filters
AVFilterParams ** filters
Definition: avfilter.h:1211
chain_free
static void chain_free(AVFilterChain **pch)
Definition: graphparser.c:261
AVDictionaryEntry::key
char * key
Definition: dict.h:90
filters
#define filters(fmt, type, inverse, clp, inverset, clip, one, clip_fn, packed)
Definition: af_crystalizer.c:54
avfilter_graph_segment_init
int avfilter_graph_segment_init(AVFilterGraphSegment *seg, int flags)
Initialize all filter instances in a graph segment.
Definition: graphparser.c:615
AVFilterPadParams::label
char * label
An av_malloc()'ed string containing the pad label.
Definition: avfilter.h:1134
if
if(ret)
Definition: filter_design.txt:179
avfilter_get_by_name
const AVFilter * avfilter_get_by_name(const char *name)
Get a filter definition matching the given name.
Definition: allfilters.c:625
opts
AVDictionary * opts
Definition: movenc.c:50
avfilter_graph_segment_apply
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.
Definition: graphparser.c:880
NULL
#define NULL
Definition: coverity.c:32
AVFilterParams
Parameters describing a filter to be created in a filtergraph.
Definition: avfilter.h:1143
AVFilterParams::filter
AVFilterContext * filter
The filter context.
Definition: avfilter.h:1154
AVFilterChain::nb_filters
size_t nb_filters
Definition: avfilter.h:1212
AVFilterParams::filter_name
char * filter_name
Name of the AVFilter to be used.
Definition: avfilter.h:1171
AVFilterGraph::filters
AVFilterContext ** filters
Definition: avfilter.h:866
AVFilterContext::inputs
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:405
avfilter_inout_alloc
AVFilterInOut * avfilter_inout_alloc(void)
Allocate a single AVFilterInOut entry.
Definition: graphparser.c:70
AVFilterGraphSegment::chains
AVFilterChain ** chains
A list of filter chain contained in this segment.
Definition: avfilter.h:1235
AVFilterGraph
Definition: avfilter.h:864
inputs
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several inputs
Definition: filter_design.txt:243
avfilter_graph_parse2
int avfilter_graph_parse2(AVFilterGraph *graph, const char *filters, AVFilterInOut **inputs, AVFilterInOut **outputs)
Add a graph described by a string to a graph.
Definition: graphparser.c:137
AVFilterParams::nb_outputs
unsigned nb_outputs
Definition: avfilter.h:1201
AVFilterGraphSegment
A parsed representation of a filtergraph segment.
Definition: avfilter.h:1224
AVFilterInOut::pad_idx
int pad_idx
index of the filt_ctx pad to use for linking
Definition: avfilter.h:1032
AVFilterGraph::scale_sws_opts
char * scale_sws_opts
sws options to use for the auto-inserted scale filters
Definition: avfilter.h:869
f
f
Definition: af_crystalizer.c:121
AVFilterContext::nb_inputs
unsigned nb_inputs
number of input pads
Definition: avfilter.h:406
AVFilterInOut::filter_ctx
AVFilterContext * filter_ctx
filter context associated to this input/output
Definition: avfilter.h:1029
av_err2str
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:121
avfilter_link
int avfilter_link(AVFilterContext *src, unsigned srcpad, AVFilterContext *dst, unsigned dstpad)
Link two filters together.
Definition: avfilter.c:149
parse_link_name
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:42
WHITESPACES
#define WHITESPACES
Definition: graphparser.c:34
AVFilterGraphSegment::scale_sws_opts
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:1246
AV_OPT_SEARCH_CHILDREN
#define AV_OPT_SEARCH_CHILDREN
Search in possible children of the given object first.
Definition: opt.h:563
link_outputs
static int link_outputs(AVFilterGraphSegment *seg, size_t idx_chain, size_t idx_filter, AVFilterInOut **outputs)
Definition: graphparser.c:745
av_opt_set_dict2
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:1743
av_dict_free
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition: dict.c:225
internal.h
AVFilterParams::nb_inputs
unsigned nb_inputs
Definition: avfilter.h:1198
AVFilterGraphSegment::graph
AVFilterGraph * graph
The filtergraph this segment is associated with.
Definition: avfilter.h:1229
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:255
avfilter_graph_parse_ptr
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.
Definition: graphparser.c:918
extract_inout
static AVFilterInOut * extract_inout(const char *label, AVFilterInOut **links)
Definition: graphparser.c:85
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:254
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:53
AVFilter
Filter definition.
Definition: avfilter.h:166
ret
ret
Definition: filter_design.txt:187
links
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output links
Definition: filter_design.txt:14
AVFilterParams::opts
AVDictionary * opts
Options to be apllied to the filter.
Definition: avfilter.h:1195
dict.h
av_dynarray_add_nofree
int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem)
Add an element to a dynamic array.
Definition: mem.c:313
linklabels_parse
static int linklabels_parse(void *logctx, const char **linklabels, AVFilterPadParams ***res, unsigned *nb_res)
Definition: graphparser.c:291
outputs
static const AVFilterPad outputs[]
Definition: af_afwtdn.c:1291
avfilter_init_dict
int avfilter_init_dict(AVFilterContext *ctx, AVDictionary **options)
Initialize a filter with the supplied dictionary of options.
Definition: avfilter.c:864
AVFilterChain
A filterchain is a list of filter specifications.
Definition: avfilter.h:1210
avfilter.h
av_get_token
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
log_unknown_opt
static void log_unknown_opt(const AVFilterGraphSegment *seg)
Definition: graphparser.c:855
AVFilterContext::internal
AVFilterInternal * internal
An opaque struct for libavfilter internal use.
Definition: avfilter.h:437
AVERROR_FILTER_NOT_FOUND
#define AVERROR_FILTER_NOT_FOUND
Filter not found.
Definition: error.h:60
AVFilterGraphSegment::nb_chains
size_t nb_chains
Definition: avfilter.h:1236
AVFilterContext
An instance of a filter.
Definition: avfilter.h:397
avfilter_graph_parse
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.
Definition: graphparser.c:163
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:270
mem.h
avfilter_free
void avfilter_free(AVFilterContext *filter)
Free a filter context.
Definition: avfilter.c:740
AVDictionaryEntry
Definition: dict.h:89
filter_params_free
static void filter_params_free(AVFilterParams **pp)
Definition: graphparser.c:238
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
AVFilterInOut::name
char * name
unique name for this input/output in the list
Definition: avfilter.h:1026
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:474
av_strlcpy
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
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
avfilter_graph_segment_apply_opts
int avfilter_graph_segment_apply_opts(AVFilterGraphSegment *seg, int flags)
Apply parsed options to filter instances in a graph segment.
Definition: graphparser.c:585
AVDictionaryEntry::value
char * value
Definition: dict.h:91
AVFilterGraph::nb_filters
unsigned nb_filters
Definition: avfilter.h:867
avstring.h
AVFilterContext::filter
const AVFilter * filter
the AVFilter of which this is an instance
Definition: avfilter.h:400
AVFilterInOut
A linked-list of the inputs/outputs of the filter chain.
Definition: avfilter.h:1024
snprintf
#define snprintf
Definition: snprintf.h:34
filter_parse
static int filter_parse(void *logctx, const char **filter, AVFilterParams **pp)
Definition: graphparser.c:337
av_dict_iterate
const AVDictionaryEntry * av_dict_iterate(const AVDictionary *m, const AVDictionaryEntry *prev)
Iterate over a dictionary.
Definition: dict.c:44
AVFilterPadParams
Parameters of a filter's input or output pad.
Definition: avfilter.h:1126
AVFilterContext::outputs
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:409