]> rtime.felk.cvut.cz Git - frescor/ffmpeg.git/blob - libavfilter/avfiltergraph.c
Move mess (to be removed) to where it is actually used.
[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 static void uninit(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 int graph_load_from_desc3(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     uninit(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 static AVFilterGraphDesc *parse_chain(const char *filters, int has_in)
478 {
479     AVFilterGraphDesc        *ret;
480     AVFilterGraphDescFilter **filterp, *filtern;
481     AVFilterGraphDescLink   **linkp,   *linkn;
482     AVFilterInOut           *inout=NULL;
483     AVFilterInOut           *head;
484
485     int index = 0;
486     char chr = 0;
487     int pad = 0;
488     int has_out = 0;
489
490     consume_whitespace(&filters);
491
492     if(!(ret = av_mallocz(sizeof(AVFilterGraphDesc))))
493         return NULL;
494
495     filterp = &ret->filters;
496     linkp   = &ret->links;
497
498     do {
499         if(chr == ',') {
500             linkn = av_mallocz(sizeof(AVFilterGraphDescLink));
501             linkn->src = index-1;
502             linkn->srcpad = pad;
503             linkn->dst = index;
504             linkn->dstpad = 0;
505
506             *linkp = linkn;
507             linkp = &linkn->next;
508         }
509         pad = parse_inouts(&filters, &inout, chr == ',' || (!has_in),
510                            LinkTypeIn, index);
511
512         filtern = av_mallocz(sizeof(AVFilterGraphDescFilter));
513         filtern->index = index;
514         parse_filter(&filters, &filtern->filter, &filtern->args);
515         *filterp = filtern;
516         filterp = &filtern->next;
517
518         pad = parse_inouts(&filters, &inout, 0,
519                            LinkTypeOut, index);
520         chr = consume_char(&filters);
521         index++;
522     } while (chr == ',' || chr == ';');
523
524     head = inout;
525     for (; inout != NULL; inout = inout->next) {
526         if (inout->instance == -1)
527             continue; // Already processed
528
529         if (!strcmp(inout->name, "in")) {
530             if (!has_in)
531                 goto fail;
532             ret->inputs = av_mallocz(sizeof(AVFilterGraphDescExport));
533             ret->inputs->filter = inout->instance;
534             ret->inputs->pad = inout->pad_idx;
535         } else if (!strcmp(inout->name, "out")) {
536             has_out = 1;
537             ret->outputs = av_mallocz(sizeof(AVFilterGraphDescExport));
538             ret->outputs->filter = inout->instance;
539             ret->outputs->pad = inout->pad_idx;
540         } else {
541             AVFilterInOut *p, *src, *dst;
542             for (p = inout->next;
543                  p && strcmp(p->name,inout->name); p = p->next);
544
545             if (!p) {
546                 av_log(&log_ctx, AV_LOG_ERROR, "Unmatched link: %s.\n",
547                        inout->name);
548                 goto fail;
549             }
550
551             if (p->type == LinkTypeIn && inout->type == LinkTypeOut) {
552                 src = inout;
553                 dst = p;
554             } else if (p->type == LinkTypeOut && inout->type == LinkTypeIn) {
555                 src = p;
556                 dst = inout;
557             } else {
558                 av_log(&log_ctx, AV_LOG_ERROR, "Two links named '%s' are either both input or both output\n",
559                        inout->name);
560                 goto fail;
561             }
562             linkn = av_mallocz(sizeof(AVFilterGraphDescLink));
563
564             linkn->src = src->instance;
565             linkn->srcpad = src->pad_idx;
566             linkn->dst = dst->instance;
567             linkn->dstpad = dst->pad_idx;
568
569             *linkp = linkn;
570             linkp = &linkn->next;
571
572             src->instance = -1;
573             dst->instance = -1;
574         }
575     }
576
577     free_inout(head);
578
579     if (!has_in) {
580         ret->inputs = av_mallocz(sizeof(AVFilterGraphDescExport));
581         ret->inputs->filter = 0;
582     }
583     if (!has_out) {
584         ret->outputs = av_mallocz(sizeof(AVFilterGraphDescExport));
585         ret->outputs->filter = index-1;
586     }
587
588     return ret;
589
590  fail:
591     free_inout(head);
592
593     avfilter_graph_free_desc(ret);
594     return NULL;
595 }
596
597 /**
598  * Parse a string describing a filter graph.
599  */
600 int avfilter_graph_parse_chain(AVFilterGraph *graph, const char *filters, AVFilterContext *in, int inpad, AVFilterContext *out, int outpad)
601 {
602     AVFilterGraphDesc *desc;
603
604     /* Try first to parse supposing there is no (in) element */
605     if (!(desc = parse_chain(filters, 0))) {
606         /* If it didn't work, parse supposing there is an (in) element */
607         desc = parse_chain(filters, 1);
608     }
609     if (!desc)
610         return -1;
611
612     if (graph_load_from_desc3(graph, desc, in, inpad, out, outpad) < 0) {
613         avfilter_graph_free_desc(desc);
614         return -1;
615     }
616
617     avfilter_graph_free_desc(desc);
618     return 0;
619 }
620
621 /**
622  * Free a graph description.
623  */
624 void avfilter_graph_free_desc(AVFilterGraphDesc *desc)
625 {
626     void *next;
627
628     while(desc->filters) {
629         next = desc->filters->next;
630         av_free(desc->filters->filter);
631         av_free(desc->filters->args);
632         av_free(desc->filters);
633         desc->filters = next;
634     }
635
636     while(desc->links) {
637         next = desc->links->next;
638         av_free(desc->links);
639         desc->links = next;
640     }
641
642     while(desc->inputs) {
643         next = desc->inputs->next;
644         av_free(desc->inputs);
645         desc->inputs = next;
646     }
647
648     while(desc->outputs) {
649         next = desc->outputs->next;
650         av_free(desc->outputs);
651         desc->outputs = next;
652     }
653 }
654