]> git.sesse.net Git - ffmpeg/blob - libavfilter/avfiltergraph.c
Make the filter graph just another normal filter.
[ffmpeg] / libavfilter / avfiltergraph.c
1 /*
2  * Filter graphs
3  * copyright (c) 2007 Bobby Bingham
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 #include <string.h>
23 #include <stddef.h>
24
25 #include "avstring.h"
26 #include "avfilter.h"
27 #include "avfiltergraph.h"
28
29 typedef struct AVFilterGraph {
30     unsigned filter_count;
31     AVFilterContext **filters;
32 } GraphContext;
33
34 static void uninit(AVFilterContext *ctx)
35 {
36     GraphContext *graph = ctx->priv;
37
38     for(; graph->filter_count > 0; graph->filter_count --)
39         avfilter_destroy(graph->filters[graph->filter_count - 1]);
40     av_freep(&graph->filters);
41 }
42
43 void avfilter_graph_add_filter(AVFilterContext *graphctx, AVFilterContext *filter)
44 {
45     GraphContext *graph = graphctx->priv;
46
47     graph->filters = av_realloc(graph->filters,
48                                 sizeof(AVFilterContext*) * ++graph->filter_count);
49     graph->filters[graph->filter_count - 1] = filter;
50 }
51
52 static AVFilterContext *create_filter_with_args(const char *filt, void *opaque)
53 {
54     AVFilterContext *ret;
55     char *filter = av_strdup(filt); /* copy - don't mangle the input string */
56     char *name, *args;
57
58     name = filter;
59     if((args = strchr(filter, '='))) {
60         /* ensure we at least have a name */
61         if(args == filter)
62             goto fail;
63
64         *args ++ = 0;
65     }
66
67     av_log(NULL, AV_LOG_INFO, "creating filter \"%s\" with args \"%s\"\n",
68            name, args ? args : "(none)");
69
70     if((ret = avfilter_create_by_name(name, NULL))) {
71         if(avfilter_init_filter(ret, args, opaque)) {
72             av_log(NULL, AV_LOG_ERROR, "error initializing filter!\n");
73             avfilter_destroy(ret);
74             goto fail;
75         }
76     } else av_log(NULL, AV_LOG_ERROR, "error creating filter!\n");
77
78     return ret;
79
80 fail:
81     av_free(filter);
82     return NULL;
83 }
84
85 static int graph_load_chain(AVFilterContext *graphctx,
86                               unsigned count, char **filter_list, void **opaque,
87                               AVFilterContext **first, AVFilterContext **last)
88 {
89     unsigned i;
90     AVFilterContext *filters[2] = {NULL,NULL};
91
92     for(i = 0; i < count; i ++) {
93         void *op;
94
95         if(opaque) op = opaque[i];
96         else       op = NULL;
97
98         if(!(filters[1] = create_filter_with_args(filter_list[i], op)))
99             goto fail;
100         if(i == 0) {
101             if(first) *first = filters[1];
102         } else {
103             if(avfilter_link(filters[0], 0, filters[1], 0)) {
104                 av_log(NULL, AV_LOG_ERROR, "error linking filters!\n");
105                 goto fail;
106             }
107         }
108         avfilter_graph_add_filter(graphctx, filters[1]);
109         filters[0] = filters[1];
110     }
111
112     if(last) *last = filters[1];
113     return 0;
114
115 fail:
116     uninit(graphctx);
117     if(first) *first = NULL;
118     if(last)  *last  = NULL;
119     return -1;
120 }
121
122 static int graph_load_chain_from_string(AVFilterContext *ctx, const char *str,
123                                         AVFilterContext **first,
124                                         AVFilterContext **last)
125 {
126     int count, ret = 0;
127     char **strings;
128     char *filt;
129
130     strings    = av_malloc(sizeof(char *));
131     strings[0] = av_strdup(str);
132
133     filt = strchr(strings[0], ',');
134     for(count = 1; filt; count ++) {
135         if(filt == strings[count-1]) {
136             ret = -1;
137             goto done;
138         }
139
140         strings = av_realloc(strings, sizeof(char *) * (count+1));
141         strings[count] = filt + 1;
142         *filt = '\0';
143         filt = strchr(strings[count], ',');
144     }
145
146     ret = graph_load_chain(ctx, count, strings, NULL, first, last);
147
148 done:
149     av_free(strings[0]);
150     av_free(strings);
151
152     return ret;
153 }
154
155 static int init(AVFilterContext *ctx, const char *args, void *opaque)
156 {
157     AVFilterContext **filters = opaque;
158
159     if(!args)
160         return 0;
161     if(!opaque)
162         return -1;
163
164     return graph_load_chain_from_string(ctx, args, filters, filters + 1);
165 }
166
167 AVFilter vf_graph =
168 {
169     .name      = "graph",
170     .author    = "Bobby Bingham",
171
172     .priv_size = sizeof(GraphContext),
173
174     .init      = init,
175     .uninit    = uninit,
176
177     .inputs    = (AVFilterPad[]) {{ .name = NULL, }},
178     .outputs   = (AVFilterPad[]) {{ .name = NULL, }},
179 };
180