]> rtime.felk.cvut.cz Git - frescor/ffmpeg.git/blob - libavfilter/avfiltergraph.c
Rename uninit() to avfilter_destroy_graph() and make it non-static
[frescor/ffmpeg.git] / libavfilter / avfiltergraph.c
1 /*
2  * filter graphs
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 <ctype.h>
24 #include <string.h>
25
26 #include "avfilter.h"
27 #include "avfiltergraph.h"
28
29
30 /** Linked-list of filters to create for an AVFilterGraphDesc */
31 typedef struct AVFilterGraphDescFilter
32 {
33     int index;              ///< filter instance index
34     char *filter;           ///< name of filter type
35     char *args;             ///< filter parameters
36     struct AVFilterGraphDescFilter *next;
37 } AVFilterGraphDescFilter;
38
39 /** Linked-list of links between filters */
40 typedef struct AVFilterGraphDescLink
41 {
42     /* TODO: allow referencing pads by name, not just by index */
43     int src;                ///< index of the source filter
44     unsigned srcpad;        ///< index of the output pad on the source filter
45
46     int dst;                ///< index of the dest filter
47     unsigned dstpad;        ///< index of the input pad on the dest filter
48
49     struct AVFilterGraphDescLink *next;
50 } AVFilterGraphDescLink;
51
52 /** Linked-list of filter pads to be exported from the graph */
53 typedef struct AVFilterGraphDescExport
54 {
55     /* TODO: allow referencing pads by name, not just by index */
56     char *name;             ///< name of the exported pad
57     int filter;             ///< index of the filter
58     unsigned pad;           ///< index of the pad to be exported
59
60     struct AVFilterGraphDescExport *next;
61 } AVFilterGraphDescExport;
62
63 /** Description of a graph to be loaded from a file, etc */
64 typedef struct
65 {
66     AVFilterGraphDescFilter *filters;   ///< filters in the graph
67     AVFilterGraphDescLink   *links;     ///< links between the filters
68     AVFilterGraphDescExport *inputs;    ///< inputs to export
69     AVFilterGraphDescExport *outputs;   ///< outputs to export
70 } AVFilterGraphDesc;
71
72 /**
73  * For use in av_log
74  */
75 static const char *log_name(void *p)
76 {
77     return "Filter parser";
78 }
79
80 static const AVClass filter_parser_class = {
81     "Filter parser",
82     log_name
83 };
84
85 static const AVClass *log_ctx = &filter_parser_class;
86
87 void avfilter_destroy_graph(AVFilterGraph *graph)
88 {
89     for(; graph->filter_count > 0; graph->filter_count --)
90         avfilter_destroy(graph->filters[graph->filter_count - 1]);
91     av_freep(&graph->filters);
92 }
93
94 /* TODO: insert in sorted order */
95 void avfilter_graph_add_filter(AVFilterGraph *graph, AVFilterContext *filter)
96 {
97     graph->filters = av_realloc(graph->filters,
98                                 sizeof(AVFilterContext*) * ++graph->filter_count);
99     graph->filters[graph->filter_count - 1] = filter;
100 }
101
102 /* search intelligently, once we insert in order */
103 AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, char *name)
104 {
105     int i;
106
107     if(!name)
108         return NULL;
109
110     for(i = 0; i < graph->filter_count; i ++)
111         if(graph->filters[i]->name && !strcmp(name, graph->filters[i]->name))
112             return graph->filters[i];
113
114     return NULL;
115 }
116
117 static int query_formats(AVFilterGraph *graph)
118 {
119     int i, j;
120
121     /* ask all the sub-filters for their supported colorspaces */
122     for(i = 0; i < graph->filter_count; i ++) {
123         if(graph->filters[i]->filter->query_formats)
124             graph->filters[i]->filter->query_formats(graph->filters[i]);
125         else
126             avfilter_default_query_formats(graph->filters[i]);
127     }
128
129     /* go through and merge as many format lists as possible */
130     for(i = 0; i < graph->filter_count; i ++) {
131         AVFilterContext *filter = graph->filters[i];
132
133         for(j = 0; j < filter->input_count; j ++) {
134             AVFilterLink *link;
135             if(!(link = filter->inputs[j]))
136                 continue;
137             if(link->in_formats != link->out_formats) {
138                 if(!avfilter_merge_formats(link->in_formats,
139                                            link->out_formats)) {
140                     /* couldn't merge format lists. auto-insert scale filter */
141                     AVFilterContext *scale;
142
143                     if(!(scale =
144                          avfilter_open(avfilter_get_by_name("scale"), NULL)))
145                         return -1;
146                     if(scale->filter->init(scale, NULL, NULL) ||
147                        avfilter_insert_filter(link, scale, 0, 0)) {
148                         avfilter_destroy(scale);
149                         return -1;
150                     }
151
152                     avfilter_graph_add_filter(graph, scale);
153                     scale->filter->query_formats(scale);
154                     if(!avfilter_merge_formats(scale-> inputs[0]->in_formats,
155                                               scale-> inputs[0]->out_formats) ||
156                        !avfilter_merge_formats(scale->outputs[0]->in_formats,
157                                               scale->outputs[0]->out_formats))
158                         return -1;
159                 }
160             }
161         }
162     }
163
164     return 0;
165 }
166
167 static void pick_format(AVFilterLink *link)
168 {
169     if(!link || !link->in_formats)
170         return;
171
172     link->in_formats->format_count = 1;
173     link->format = link->in_formats->formats[0];
174
175     avfilter_formats_unref(&link->in_formats);
176     avfilter_formats_unref(&link->out_formats);
177 }
178
179 static void pick_formats(AVFilterGraph *graph)
180 {
181     int i, j;
182
183     for(i = 0; i < graph->filter_count; i ++) {
184         AVFilterContext *filter = graph->filters[i];
185
186         for(j = 0; j < filter->input_count; j ++)
187             pick_format(filter->inputs[j]);
188         for(j = 0; j < filter->output_count; j ++)
189             pick_format(filter->outputs[j]);
190     }
191 }
192
193 int avfilter_graph_config_formats(AVFilterGraph *graph)
194 {
195     /* find supported formats from sub-filters, and merge along links */
196     if(query_formats(graph))
197         return -1;
198
199     /* Once everything is merged, it's possible that we'll still have
200      * multiple valid colorspace choices. We pick the first one. */
201     pick_formats(graph);
202
203     return 0;
204 }
205
206 static int create_filter(AVFilterGraph *ctx, int index, char *name,
207                          char *args)
208 {
209     AVFilterContext *filt;
210
211     AVFilter *filterdef;
212     char tmp[20];
213
214     snprintf(tmp, 20, "%d", index);
215     if(!(filterdef = avfilter_get_by_name(name)) ||
216        !(filt = avfilter_open(filterdef, tmp))) {
217         av_log(&log_ctx, AV_LOG_ERROR,
218                "error creating filter '%s'\n", name);
219         return -1;
220     }
221     avfilter_graph_add_filter(ctx, filt);
222     if(avfilter_init_filter(filt, args, NULL)) {
223         av_log(&log_ctx, AV_LOG_ERROR,
224                "error initializing filter '%s'\n", name);
225         return -1;
226     }
227
228     return 0;
229 }
230
231 static int link_filter(AVFilterGraph *ctx, int src, int srcpad,
232                        int dst, int dstpad)
233 {
234     AVFilterContext *filt, *filtb;
235
236     char tmp[20];
237
238     snprintf(tmp, 20, "%d", src);
239     if(!(filt = avfilter_graph_get_filter(ctx, tmp))) {
240         av_log(&log_ctx, AV_LOG_ERROR, "link source does not exist in graph\n");
241         return -1;
242     }
243     snprintf(tmp, 20, "%d", dst);
244     if(!(filtb = avfilter_graph_get_filter(ctx, tmp))) {
245         av_log(&log_ctx, AV_LOG_ERROR, "link destination does not exist in graph\n");
246         return -1;
247     }
248     if(avfilter_link(filt, srcpad, filtb, dstpad)) {
249         av_log(&log_ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n");
250         return -1;
251     }
252
253     return 0;
254 }
255
256 static int load_from_desc(AVFilterGraph *graph, AVFilterGraphDesc *desc, AVFilterContext *in, int inpad, AVFilterContext *out, int outpad)
257 {
258     AVFilterGraphDescExport *curpad;
259     char tmp[20];
260     AVFilterContext *filt;
261     AVFilterGraphDescFilter *curfilt;
262     AVFilterGraphDescLink   *curlink;
263
264
265     /* create all filters */
266     for(curfilt = desc->filters; curfilt; curfilt = curfilt->next) {
267         if (create_filter(graph, curfilt->index, curfilt->filter,
268                           curfilt->args) < 0)
269             goto fail;
270     }
271
272     /* create all links */
273     for(curlink = desc->links; curlink; curlink = curlink->next) {
274         if (link_filter(graph, curlink->src, curlink->srcpad,
275                           curlink->dst, curlink->dstpad) < 0)
276             goto fail;
277     }
278
279     /* export all input pads */
280     for(curpad = desc->inputs; curpad; curpad = curpad->next) {
281         snprintf(tmp, 20, "%d", curpad->filter);
282         if(!(filt = avfilter_graph_get_filter(graph, tmp))) {
283             av_log(&log_ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n");
284             goto fail;
285         }
286         if(avfilter_link(in, inpad, filt, curpad->pad)) {
287             av_log(&log_ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n");
288             goto fail;
289         }
290     }
291
292     /* export all output pads */
293     for(curpad = desc->outputs; curpad; curpad = curpad->next) {
294         snprintf(tmp, 20, "%d", curpad->filter);
295         if(!(filt = avfilter_graph_get_filter(graph, tmp))) {
296             av_log(&log_ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n");
297             goto fail;
298         }
299
300         if(avfilter_link(filt, curpad->pad, out, outpad)) {
301             av_log(&log_ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n");
302             goto fail;
303         }
304     }
305
306     return 0;
307
308 fail:
309     avfilter_destroy_graph(graph);
310     return -1;
311 }
312
313
314 static void consume_whitespace(const char **buf)
315 {
316     *buf += strspn(*buf, " \n\t");
317 }
318
319 /**
320  * get the next non-whitespace char
321  */
322 static char consume_char(const char **buf)
323 {
324     char out;
325     consume_whitespace(buf);
326
327     out = **buf;
328
329     if (out)
330         (*buf)++;
331
332     return out;
333 }
334
335 /**
336  * remove the quotation marks from a string. Ex: "aaa'bb'cc" -> "aaabbcc"
337  */
338 static void unquote(char *str)
339 {
340     char *p1, *p2;
341     p1=p2=str;
342     while (*p1 != 0) {
343         if (*p1 != '\'')
344             *p2++ = *p1;
345         p1++;
346     }
347
348     *p2 = 0;
349 }
350
351 /**
352  * Consumes a string from *buf.
353  * @return a copy of the consumed string, which should be free'd after use
354  */
355 static char *consume_string(const char **buf)
356 {
357     const char *start;
358     char *ret;
359     int size;
360
361     consume_whitespace(buf);
362
363     if (!(**buf))
364         return av_mallocz(1);
365
366     start = *buf;
367
368     *buf += strcspn(*buf, " ()=,'");
369
370     if (**buf == '\'') {
371         char *p = strchr(*buf + 1, '\'');
372         if (p)
373             *buf = p + 1;
374         else
375             *buf += strlen(*buf); // Move the pointer to the null end byte
376     }
377
378     size = *buf - start + 1;
379     ret = av_malloc(size);
380     memcpy(ret, start, size - 1);
381     ret[size-1] = 0;
382
383     unquote(ret);
384
385     return ret;
386 }
387
388 /**
389  * Parse "(linkname)"
390  * @arg name a pointer (that need to be free'd after use) to the name between
391  *           parenthesis
392  */
393 static void parse_link_name(const char **buf, char **name)
394 {
395     consume_char(buf);
396
397     *name = consume_string(buf);
398
399     if (!*name[0])
400         goto fail;
401
402     if (consume_char(buf) != ')')
403         goto fail;
404
405     return;
406  fail:
407     av_freep(name);
408     av_log(&log_ctx, AV_LOG_ERROR, "Could not parse link name!\n");
409 }
410
411 /**
412  * Parse "filter=params"
413  * @arg name a pointer (that need to be free'd after use) to the name of the
414  *           filter
415  * @arg ars  a pointer (that need to be free'd after use) to the args of the
416  *           filter
417  */
418 static void parse_filter(const char **buf, char **name, char **opts)
419 {
420     *name = consume_string(buf);
421
422     if (**buf == '=') {
423         consume_char(buf);
424         *opts = consume_string(buf);
425     } else {
426         *opts = NULL;
427     }
428
429 }
430
431 enum LinkType {
432     LinkTypeIn,
433     LinkTypeOut,
434 };
435
436 /**
437  * A linked-list of the inputs/outputs of the filter chain.
438  */
439 typedef struct AVFilterInOut {
440     enum LinkType type;
441     char *name;
442     int instance;
443     int pad_idx;
444
445     struct AVFilterInOut *next;
446 } AVFilterInOut;
447
448 static void free_inout(AVFilterInOut *head)
449 {
450     while (head) {
451         AVFilterInOut *next;
452         next = head->next;
453         av_free(head);
454         head = next;
455     }
456 }
457
458 /**
459  * Parse "(a1)(link2) ... (etc)"
460  */
461 static int parse_inouts(const char **buf, AVFilterInOut **inout, int firstpad,
462                         enum LinkType type, int instance)
463 {
464     int pad = firstpad;
465     while (**buf == '(') {
466         AVFilterInOut *inoutn = av_malloc(sizeof(AVFilterInOut));
467         parse_link_name(buf, &inoutn->name);
468         inoutn->type = type;
469         inoutn->instance = instance;
470         inoutn->pad_idx = pad++;
471         inoutn->next = *inout;
472         *inout = inoutn;
473     }
474     return pad;
475 }
476
477 /**
478  * Free a graph description.
479  */
480 static void free_desc(AVFilterGraphDesc *desc)
481 {
482     void *next;
483
484     while(desc->filters) {
485         next = desc->filters->next;
486         av_free(desc->filters->filter);
487         av_free(desc->filters->args);
488         av_free(desc->filters);
489         desc->filters = next;
490     }
491
492     while(desc->links) {
493         next = desc->links->next;
494         av_free(desc->links);
495         desc->links = next;
496     }
497
498     while(desc->inputs) {
499         next = desc->inputs->next;
500         av_free(desc->inputs);
501         desc->inputs = next;
502     }
503
504     while(desc->outputs) {
505         next = desc->outputs->next;
506         av_free(desc->outputs);
507         desc->outputs = next;
508     }
509 }
510
511 static AVFilterGraphDesc *parse_chain(const char *filters, int has_in)
512 {
513     AVFilterGraphDesc        *ret;
514     AVFilterGraphDescFilter **filterp, *filtern;
515     AVFilterGraphDescLink   **linkp,   *linkn;
516     AVFilterInOut           *inout=NULL;
517     AVFilterInOut           *head;
518
519     int index = 0;
520     char chr = 0;
521     int pad = 0;
522     int has_out = 0;
523
524     consume_whitespace(&filters);
525
526     if(!(ret = av_mallocz(sizeof(AVFilterGraphDesc))))
527         return NULL;
528
529     filterp = &ret->filters;
530     linkp   = &ret->links;
531
532     do {
533         if(chr == ',') {
534             linkn = av_mallocz(sizeof(AVFilterGraphDescLink));
535             linkn->src = index-1;
536             linkn->srcpad = pad;
537             linkn->dst = index;
538             linkn->dstpad = 0;
539
540             *linkp = linkn;
541             linkp = &linkn->next;
542         }
543         pad = parse_inouts(&filters, &inout, chr == ',' || (!has_in),
544                            LinkTypeIn, index);
545
546         filtern = av_mallocz(sizeof(AVFilterGraphDescFilter));
547         filtern->index = index;
548         parse_filter(&filters, &filtern->filter, &filtern->args);
549         *filterp = filtern;
550         filterp = &filtern->next;
551
552         pad = parse_inouts(&filters, &inout, 0,
553                            LinkTypeOut, index);
554         chr = consume_char(&filters);
555         index++;
556     } while (chr == ',' || chr == ';');
557
558     head = inout;
559     for (; inout != NULL; inout = inout->next) {
560         if (inout->instance == -1)
561             continue; // Already processed
562
563         if (!strcmp(inout->name, "in")) {
564             if (!has_in)
565                 goto fail;
566             ret->inputs = av_mallocz(sizeof(AVFilterGraphDescExport));
567             ret->inputs->filter = inout->instance;
568             ret->inputs->pad = inout->pad_idx;
569         } else if (!strcmp(inout->name, "out")) {
570             has_out = 1;
571             ret->outputs = av_mallocz(sizeof(AVFilterGraphDescExport));
572             ret->outputs->filter = inout->instance;
573             ret->outputs->pad = inout->pad_idx;
574         } else {
575             AVFilterInOut *p, *src, *dst;
576             for (p = inout->next;
577                  p && strcmp(p->name,inout->name); p = p->next);
578
579             if (!p) {
580                 av_log(&log_ctx, AV_LOG_ERROR, "Unmatched link: %s.\n",
581                        inout->name);
582                 goto fail;
583             }
584
585             if (p->type == LinkTypeIn && inout->type == LinkTypeOut) {
586                 src = inout;
587                 dst = p;
588             } else if (p->type == LinkTypeOut && inout->type == LinkTypeIn) {
589                 src = p;
590                 dst = inout;
591             } else {
592                 av_log(&log_ctx, AV_LOG_ERROR, "Two links named '%s' are either both input or both output\n",
593                        inout->name);
594                 goto fail;
595             }
596             linkn = av_mallocz(sizeof(AVFilterGraphDescLink));
597
598             linkn->src = src->instance;
599             linkn->srcpad = src->pad_idx;
600             linkn->dst = dst->instance;
601             linkn->dstpad = dst->pad_idx;
602
603             *linkp = linkn;
604             linkp = &linkn->next;
605
606             src->instance = -1;
607             dst->instance = -1;
608         }
609     }
610
611     free_inout(head);
612
613     if (!has_in) {
614         ret->inputs = av_mallocz(sizeof(AVFilterGraphDescExport));
615         ret->inputs->filter = 0;
616     }
617     if (!has_out) {
618         ret->outputs = av_mallocz(sizeof(AVFilterGraphDescExport));
619         ret->outputs->filter = index-1;
620     }
621
622     return ret;
623
624  fail:
625     free_inout(head);
626
627     free_desc(ret);
628     return NULL;
629 }
630
631 /**
632  * Parse a string describing a filter graph.
633  */
634 int avfilter_graph_parse_chain(AVFilterGraph *graph, const char *filters, AVFilterContext *in, int inpad, AVFilterContext *out, int outpad)
635 {
636     AVFilterGraphDesc *desc;
637
638     /* Try first to parse supposing there is no (in) element */
639     if (!(desc = parse_chain(filters, 0))) {
640         /* If it didn't work, parse supposing there is an (in) element */
641         desc = parse_chain(filters, 1);
642     }
643     if (!desc)
644         return -1;
645
646     if (load_from_desc(graph, desc, in, inpad, out, outpad) < 0) {
647         free_desc(desc);
648         return -1;
649     }
650
651     free_desc(desc);
652     return 0;
653 }