Fix memory leak.
[ffmpeg.git] / 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     av_free(filter);
79
80     return ret;
81
82 fail:
83     av_free(filter);
84     return NULL;
85 }
86
87 static int graph_load_chain(AVFilterContext *graphctx,
88                               unsigned count, char **filter_list, void **opaque,
89                               AVFilterContext **first, AVFilterContext **last)
90 {
91     unsigned i;
92     AVFilterContext *filters[2] = {NULL,NULL};
93
94     for(i = 0; i < count; i ++) {
95         void *op;
96
97         if(opaque) op = opaque[i];
98         else       op = NULL;
99
100         if(!(filters[1] = create_filter_with_args(filter_list[i], op)))
101             goto fail;
102         if(i == 0) {
103             if(first) *first = filters[1];
104         } else {
105             if(avfilter_link(filters[0], 0, filters[1], 0)) {
106                 av_log(NULL, AV_LOG_ERROR, "error linking filters!\n");
107                 goto fail;
108             }
109         }
110         avfilter_graph_add_filter(graphctx, filters[1]);
111         filters[0] = filters[1];
112     }
113
114     if(last) *last = filters[1];
115     return 0;
116
117 fail:
118     uninit(graphctx);
119     if(first) *first = NULL;
120     if(last)  *last  = NULL;
121     return -1;
122 }
123
124 static int graph_load_chain_from_string(AVFilterContext *ctx, const char *str,
125                                         AVFilterContext **first,
126                                         AVFilterContext **last)
127 {
128     int count, ret = 0;
129     char **strings;
130     char *filt;
131
132     strings    = av_malloc(sizeof(char *));
133     strings[0] = av_strdup(str);
134
135     filt = strchr(strings[0], ',');
136     for(count = 1; filt; count ++) {
137         if(filt == strings[count-1]) {
138             ret = -1;
139             goto done;
140         }
141
142         strings = av_realloc(strings, sizeof(char *) * (count+1));
143         strings[count] = filt + 1;
144         *filt = '\0';
145         filt = strchr(strings[count], ',');
146     }
147
148     ret = graph_load_chain(ctx, count, strings, NULL, first, last);
149
150 done:
151     av_free(strings[0]);
152     av_free(strings);
153
154     return ret;
155 }
156
157 static int init(AVFilterContext *ctx, const char *args, void *opaque)
158 {
159     AVFilterContext **filters = opaque;
160
161     if(!args)
162         return 0;
163     if(!opaque)
164         return -1;
165
166     return graph_load_chain_from_string(ctx, args, filters, filters + 1);
167 }
168
169 AVFilter vf_graph =
170 {
171     .name      = "graph",
172     .author    = "Bobby Bingham",
173
174     .priv_size = sizeof(GraphContext),
175
176     .init      = init,
177     .uninit    = uninit,
178
179     .inputs    = (AVFilterPad[]) {{ .name = NULL, }},
180     .outputs   = (AVFilterPad[]) {{ .name = NULL, }},
181 };
182