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 "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  */
43 static 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 
72 {
73  return av_mallocz(sizeof(AVFilterInOut));
74 }
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 
86 static AVFilterInOut *extract_inout(const char *label, AVFilterInOut **links)
87 {
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 
103 static 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 
115 static int parse_sws_flags(const char **buf, char **dst, void *log_ctx)
116 {
117  char *p = strchr(*buf, ';');
118 
119  if (strncmp(*buf, "sws_flags=", 10))
120  return 0;
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 
156 end:
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 
262 static 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 
287  av_freep(&seg->scale_sws_opts);
288 
289  av_freep(pseg);
290 }
291 
292 static 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;
301  AVFilterPadParams *par;
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;
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 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  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 == '=') {
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;
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 static 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) {
417  AVFilterParams *p;
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) {
426  filter_params_free(&p);
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;
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 int 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;
511 fail:
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) {
524  av_freep(&seg->graph->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];
536  char name[64];
537 
538  // skip already processed filters
539  if (p->filter || !p->filter_name)
540  continue;
541 
542  if (!f) {
543  av_log(seg->graph, AV_LOG_ERROR,
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 
554  if (!p->filter)
555  return AVERROR(ENOMEM);
556 
557  if (!strcmp(f->name, "scale") && 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 
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 
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 
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 ||
632  continue;
633 
635  if (ret < 0)
636  return ret;
637  }
638  }
639 
640  return 0;
641 }
642 
643 static unsigned
644 find_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 
678 static 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) {
692  avfilter_inout_free(&io);
693  return AVERROR(ENOMEM);
694  }
695  }
696 
697  append_inout(inouts, &io);
698 
699  return 0;
700 }
701 
702 static 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) {
712  av_log(seg->graph, AV_LOG_ERROR,
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 
747 static 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) {
757  av_log(seg->graph, AV_LOG_ERROR,
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 
808 cont:;
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;
850 fail:
853  return ret;
854 }
855 
856 // print an error message if some options were not found
857 static void log_unknown_opt(const AVFilterGraphSegment *seg)
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) {
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) {
900  log_unknown_opt(seg);
901  av_log(seg->graph, AV_LOG_ERROR, "Error applying filter options\n");
902  return ret;
903  }
904 
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 
928  AVFilterGraphSegment *seg = NULL;
929  AVFilterChain *ch;
930  AVFilterParams *p;
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) {
944  log_unknown_opt(seg);
945  goto end;
946  }
947 
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);
993  avfilter_inout_free(&cur);
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 
1020 end:
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 }
AV_OPT_SEARCH_CHILDREN
#define AV_OPT_SEARCH_CHILDREN
Search in possible children of the given object first.
Definition: opt.h:605
link_inputs
static int link_inputs(AVFilterGraphSegment *seg, size_t idx_chain, size_t idx_filter, AVFilterInOut **inputs)
Definition: graphparser.c:702
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:678
AVFilterParams::instance_name
char * instance_name
Name to be used for this filter instance.
Definition: avfilter.h:892
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:516
out
FILE * out
Definition: movenc.c:55
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:864
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:115
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:744
fail_creation_pending
static int fail_creation_pending(AVFilterGraphSegment *seg, const char *fn, const char *func)
Definition: graphparser.c:577
AVFilterContext::nb_outputs
unsigned nb_outputs
number of output pads
Definition: avfilter.h:270
filter
void(* filter)(uint8_t *src, int stride, int qscale)
Definition: h263dsp.c:29
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:203
AVFilterParams::inputs
AVFilterPadParams ** inputs
Definition: avfilter.h:906
chain_parse
static int chain_parse(void *logctx, const char **pchain, AVFilterChain **pch)
Definition: graphparser.c:403
AVFilterParams::outputs
AVFilterPadParams ** outputs
Definition: avfilter.h:909
append_inout
static void append_inout(AVFilterInOut **inouts, AVFilterInOut **element)
Definition: graphparser.c:103
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:227
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:814
fail
#define fail()
Definition: checkasm.h:193
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:276
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:460
avfilter_inout_free
void avfilter_inout_free(AVFilterInOut **inout)
Free the supplied list of AVFilterInOut and set *inout to NULL.
Definition: graphparser.c:76
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:209
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:644
AVFilterChain::filters
AVFilterParams ** filters
Definition: avfilter.h:920
chain_free
static void chain_free(AVFilterChain **pch)
Definition: graphparser.c:262
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:55
filters.h
avfilter_graph_segment_init
int avfilter_graph_segment_init(AVFilterGraphSegment *seg, int flags)
Initialize all filter instances in a graph segment.
Definition: graphparser.c:616
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:1817
AVFilterPadParams::label
char * label
An av_malloc()'ed string containing the pad label.
Definition: avfilter.h:843
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:639
opts
AVDictionary * opts
Definition: movenc.c:51
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:882
NULL
#define NULL
Definition: coverity.c:32
AVFilterParams
Parameters describing a filter to be created in a filtergraph.
Definition: avfilter.h:852
AVFilterParams::filter
AVFilterContext * filter
The filter context.
Definition: avfilter.h:863
AVFilterChain::nb_filters
size_t nb_filters
Definition: avfilter.h:921
AVFilterParams::filter_name
char * filter_name
Name of the AVFilter to be used.
Definition: avfilter.h:880
AVFilterGraph::filters
AVFilterContext ** filters
Definition: avfilter.h:586
AVFilterContext::inputs
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:265
AV_CLASS_STATE_INITIALIZED
@ AV_CLASS_STATE_INITIALIZED
Object initialization has finished and it is now in the 'runtime' stage.
Definition: log.h:55
avfilter_inout_alloc
AVFilterInOut * avfilter_inout_alloc(void)
Allocate a single AVFilterInOut entry.
Definition: graphparser.c:71
AVFilterGraphSegment::chains
AVFilterChain ** chains
A list of filter chain contained in this segment.
Definition: avfilter.h:944
avfilter_internal.h
AVFilterGraph
Definition: avfilter.h:584
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:138
AVFilterParams::nb_outputs
unsigned nb_outputs
Definition: avfilter.h:910
AVFilterGraphSegment
A parsed representation of a filtergraph segment.
Definition: avfilter.h:933
AVFilterInOut::pad_idx
int pad_idx
index of the filt_ctx pad to use for linking
Definition: avfilter.h:741
AVFilterGraph::scale_sws_opts
char * scale_sws_opts
sws options to use for the auto-inserted scale filters
Definition: avfilter.h:589
f
f
Definition: af_crystalizer.c:122
AVFilterContext::nb_inputs
unsigned nb_inputs
number of input pads
Definition: avfilter.h:266
AVFilterInOut::filter_ctx
AVFilterContext * filter_ctx
filter context associated to this input/output
Definition: avfilter.h:738
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:83
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:122
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:43
WHITESPACES
#define WHITESPACES
Definition: graphparser.c:35
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:955
fn
#define fn(a)
Definition: aap_template.c:37
link_outputs
static int link_outputs(AVFilterGraphSegment *seg, size_t idx_chain, size_t idx_filter, AVFilterInOut **outputs)
Definition: graphparser.c:747
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:223
AVFilterParams::nb_inputs
unsigned nb_inputs
Definition: avfilter.h:907
FFFilterContext::state_flags
unsigned state_flags
Definition: avfilter_internal.h:104
AVFilterGraphSegment::graph
AVFilterGraph * graph
The filtergraph this segment is associated with.
Definition: avfilter.h:938
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
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:920
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:1962
extract_inout
static AVFilterInOut * extract_inout(const char *label, AVFilterInOut **links)
Definition: graphparser.c:86
fffilterctx
static FFFilterContext * fffilterctx(AVFilterContext *ctx)
Definition: avfilter_internal.h:121
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:256
AVFilterPad::name
const char * name
Pad name.
Definition: filters.h:44
outputs
static const AVFilterPad outputs[]
Definition: af_aap.c:310
AVFilter
Filter definition.
Definition: avfilter.h:199
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:904
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:315
linklabels_parse
static int linklabels_parse(void *logctx, const char **linklabels, AVFilterPadParams ***res, unsigned *nb_res)
Definition: graphparser.c:292
avfilter_init_dict
int avfilter_init_dict(AVFilterContext *ctx, AVDictionary **options)
Initialize a filter with the supplied dictionary of options.
Definition: avfilter.c:930
AVFilterChain
A filterchain is a list of filter specifications.
Definition: avfilter.h:919
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:857
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:945
AVFilterContext
An instance of a filter.
Definition: avfilter.h:257
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:164
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:272
mem.h
avfilter_free
void avfilter_free(AVFilterContext *filter)
Free a filter context.
Definition: avfilter.c:811
AVDictionaryEntry
Definition: dict.h:89
filter_params_free
static void filter_params_free(AVFilterParams **pp)
Definition: graphparser.c:239
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:735
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:482
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:586
AVDictionaryEntry::value
char * value
Definition: dict.h:91
AVFilterGraph::nb_filters
unsigned nb_filters
Definition: avfilter.h:587
avstring.h
AVFilterContext::filter
const AVFilter * filter
the AVFilter of which this is an instance
Definition: avfilter.h:260
AVFilterInOut
A linked-list of the inputs/outputs of the filter chain.
Definition: avfilter.h:733
snprintf
#define snprintf
Definition: snprintf.h:34
filter_parse
static int filter_parse(void *logctx, const char **filter, AVFilterParams **pp)
Definition: graphparser.c:338
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:835
AVFilterContext::outputs
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:269