Commit | Line | Data |
---|---|---|
4dbbcdee VS |
1 | /* |
2 | * Filter layer | |
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 | ||
e0752603 | 22 | #include <stdarg.h> |
4dbbcdee VS |
23 | #include <stdlib.h> |
24 | #include <string.h> | |
25 | #include <stdio.h> | |
26 | ||
27 | #include "avfilter.h" | |
d72a138e | 28 | #include "allfilters.h" |
4dbbcdee VS |
29 | |
30 | /** list of registered filters, sorted by name */ | |
31 | static int filter_count = 0; | |
32 | static AVFilter **filters = NULL; | |
33 | ||
efb36bfc | 34 | AVFilterPicRef *avfilter_ref_pic(AVFilterPicRef *ref, int pmask) |
4dbbcdee VS |
35 | { |
36 | AVFilterPicRef *ret = av_malloc(sizeof(AVFilterPicRef)); | |
37 | memcpy(ret, ref, sizeof(AVFilterPicRef)); | |
efb36bfc | 38 | ret->perms &= pmask; |
4dbbcdee VS |
39 | ret->pic->refcount ++; |
40 | return ret; | |
41 | } | |
42 | ||
43 | void avfilter_unref_pic(AVFilterPicRef *ref) | |
44 | { | |
45 | if(-- ref->pic->refcount == 0) | |
46 | ref->pic->free(ref->pic); | |
47 | av_free(ref); | |
48 | } | |
49 | ||
50 | int avfilter_link(AVFilterContext *src, unsigned srcpad, | |
51 | AVFilterContext *dst, unsigned dstpad) | |
52 | { | |
53 | AVFilterLink *link; | |
e0752603 | 54 | int *fmts[2], i, j; |
4dbbcdee | 55 | |
7d0e1392 VS |
56 | if(src->output_count <= srcpad || dst->input_count <= dstpad || |
57 | src->outputs[srcpad] || dst->inputs[dstpad]) | |
4dbbcdee VS |
58 | return -1; |
59 | ||
60 | src->outputs[srcpad] = | |
61 | dst->inputs[dstpad] = link = av_malloc(sizeof(AVFilterLink)); | |
62 | ||
1653c11f VS |
63 | link->src = src; |
64 | link->dst = dst; | |
65 | link->srcpad = srcpad; | |
66 | link->dstpad = dstpad; | |
4dbbcdee VS |
67 | link->cur_pic = NULL; |
68 | ||
e0752603 | 69 | /* find a format both filters support - TODO: auto-insert conversion filter */ |
998a7aa3 | 70 | link->format = -1; |
c5ef7d7b VS |
71 | if(src->output_pads[srcpad].query_formats) |
72 | fmts[0] = src->output_pads[srcpad].query_formats(link); | |
102fb0e3 | 73 | else |
78b0c0bb | 74 | fmts[0] = avfilter_default_query_output_formats(link); |
c5ef7d7b | 75 | fmts[1] = dst->input_pads[dstpad].query_formats(link); |
e0752603 VS |
76 | for(i = 0; fmts[0][i] != -1; i ++) |
77 | for(j = 0; fmts[1][j] != -1; j ++) | |
78 | if(fmts[0][i] == fmts[1][j]) { | |
79 | link->format = fmts[0][i]; | |
80 | goto format_done; | |
81 | } | |
82 | ||
83 | format_done: | |
84 | av_free(fmts[0]); | |
85 | av_free(fmts[1]); | |
86 | if(link->format == -1) { | |
87 | /* failed to find a format. fail at creating the link */ | |
88 | av_free(link); | |
89 | src->outputs[srcpad] = NULL; | |
90 | dst->inputs[dstpad] = NULL; | |
91 | return -1; | |
92 | } | |
93 | ||
c5ef7d7b VS |
94 | if (src->output_pads[srcpad].config_props) |
95 | src->output_pads[srcpad].config_props(link); | |
102fb0e3 | 96 | else |
78b0c0bb | 97 | avfilter_default_config_output_link(link); |
102fb0e3 | 98 | |
c5ef7d7b VS |
99 | if (dst->input_pads[dstpad].config_props) |
100 | dst->input_pads[dstpad].config_props(link); | |
102fb0e3 | 101 | |
4dbbcdee VS |
102 | return 0; |
103 | } | |
104 | ||
105 | AVFilterPicRef *avfilter_get_video_buffer(AVFilterLink *link, int perms) | |
106 | { | |
107 | AVFilterPicRef *ret = NULL; | |
108 | ||
c5ef7d7b VS |
109 | if(link->dst->input_pads[link->dstpad].get_video_buffer) |
110 | ret = link->dst->input_pads[link->dstpad].get_video_buffer(link, perms); | |
4dbbcdee VS |
111 | |
112 | if(!ret) | |
113 | ret = avfilter_default_get_video_buffer(link, perms); | |
114 | ||
115 | return ret; | |
116 | } | |
117 | ||
118 | void avfilter_request_frame(AVFilterLink *link) | |
119 | { | |
c5ef7d7b | 120 | const AVFilterPad *pad = &link->src->output_pads[link->srcpad]; |
9586ba3a VS |
121 | |
122 | if(pad->request_frame) | |
123 | pad->request_frame(link); | |
124 | else if(link->src->inputs[0]) | |
125 | avfilter_request_frame(link->src->inputs[0]); | |
4dbbcdee VS |
126 | } |
127 | ||
128 | /* XXX: should we do the duplicating of the picture ref here, instead of | |
129 | * forcing the source filter to do it? */ | |
130 | void avfilter_start_frame(AVFilterLink *link, AVFilterPicRef *picref) | |
131 | { | |
132 | void (*start_frame)(AVFilterLink *, AVFilterPicRef *); | |
133 | ||
c5ef7d7b | 134 | start_frame = link->dst->input_pads[link->dstpad].start_frame; |
4dbbcdee VS |
135 | if(!start_frame) |
136 | start_frame = avfilter_default_start_frame; | |
137 | ||
138 | start_frame(link, picref); | |
139 | } | |
140 | ||
141 | void avfilter_end_frame(AVFilterLink *link) | |
142 | { | |
143 | void (*end_frame)(AVFilterLink *); | |
144 | ||
c5ef7d7b | 145 | end_frame = link->dst->input_pads[link->dstpad].end_frame; |
4dbbcdee VS |
146 | if(!end_frame) |
147 | end_frame = avfilter_default_end_frame; | |
148 | ||
149 | end_frame(link); | |
150 | } | |
151 | ||
152 | void avfilter_draw_slice(AVFilterLink *link, uint8_t *data[4], int y, int h) | |
153 | { | |
c5ef7d7b | 154 | if(!link->dst->input_pads[link->dstpad].draw_slice) |
7d0e1392 VS |
155 | return; |
156 | ||
c5ef7d7b | 157 | link->dst->input_pads[link->dstpad].draw_slice(link, data, y, h); |
4dbbcdee VS |
158 | } |
159 | ||
160 | static int filter_cmp(const void *aa, const void *bb) | |
161 | { | |
162 | const AVFilter *a = *(const AVFilter **)aa, *b = *(const AVFilter **)bb; | |
163 | return strcmp(a->name, b->name); | |
164 | } | |
165 | ||
166 | AVFilter *avfilter_get_by_name(char *name) | |
167 | { | |
168 | AVFilter key = { .name = name, }; | |
169 | AVFilter *key2 = &key; | |
170 | AVFilter **ret; | |
171 | ||
172 | ret = bsearch(&key2, filters, filter_count, sizeof(AVFilter **), filter_cmp); | |
173 | if(ret) | |
174 | return *ret; | |
175 | return NULL; | |
176 | } | |
177 | ||
178 | /* FIXME: insert in order, rather than insert at end + resort */ | |
179 | void avfilter_register(AVFilter *filter) | |
180 | { | |
181 | filters = av_realloc(filters, sizeof(AVFilter*) * (filter_count+1)); | |
182 | filters[filter_count] = filter; | |
183 | qsort(filters, ++filter_count, sizeof(AVFilter **), filter_cmp); | |
184 | } | |
185 | ||
186 | void avfilter_init(void) | |
187 | { | |
d72a138e | 188 | avfilter_register(&vsrc_dummy); |
eaf7eb66 | 189 | avfilter_register(&vsrc_ppm); |
d72a138e | 190 | avfilter_register(&vf_crop); |
d4169dd3 | 191 | avfilter_register(&vf_graph); |
d72a138e | 192 | avfilter_register(&vf_passthrough); |
72e3037a | 193 | avfilter_register(&vf_rgb2bgr); |
ce356b09 | 194 | avfilter_register(&vf_slicify); |
d72a138e | 195 | avfilter_register(&vo_sdl); |
4dbbcdee VS |
196 | } |
197 | ||
198 | void avfilter_uninit(void) | |
199 | { | |
200 | av_freep(&filters); | |
201 | filter_count = 0; | |
202 | } | |
203 | ||
204 | static int pad_count(const AVFilterPad *pads) | |
205 | { | |
206 | AVFilterPad *p = (AVFilterPad *) pads; | |
207 | int count; | |
208 | ||
209 | for(count = 0; p->name; count ++) p ++; | |
210 | return count; | |
211 | } | |
212 | ||
213 | static const char *filter_name(void *p) | |
214 | { | |
215 | AVFilterContext *filter = p; | |
216 | return filter->filter->name; | |
217 | } | |
218 | ||
6ae82d1e | 219 | AVFilterContext *avfilter_create(AVFilter *filter, char *inst_name) |
4dbbcdee VS |
220 | { |
221 | AVFilterContext *ret = av_malloc(sizeof(AVFilterContext)); | |
222 | ||
223 | ret->av_class = av_mallocz(sizeof(AVClass)); | |
224 | ret->av_class->item_name = filter_name; | |
225 | ret->filter = filter; | |
2350e69c | 226 | ret->name = inst_name ? av_strdup(inst_name) : NULL; |
4dbbcdee VS |
227 | ret->priv = av_mallocz(filter->priv_size); |
228 | ||
7d0e1392 | 229 | ret->input_count = pad_count(filter->inputs); |
c5ef7d7b VS |
230 | ret->input_pads = av_malloc(sizeof(AVFilterPad) * ret->input_count); |
231 | memcpy(ret->input_pads, filter->inputs, sizeof(AVFilterPad)*ret->input_count); | |
7d0e1392 | 232 | ret->inputs = av_mallocz(sizeof(AVFilterLink*) * ret->input_count); |
c5ef7d7b | 233 | |
7d0e1392 | 234 | ret->output_count = pad_count(filter->outputs); |
c5ef7d7b VS |
235 | ret->output_pads = av_malloc(sizeof(AVFilterPad) * ret->output_count); |
236 | memcpy(ret->output_pads, filter->outputs, sizeof(AVFilterPad)*ret->output_count); | |
7d0e1392 VS |
237 | ret->outputs = av_mallocz(sizeof(AVFilterLink*) * ret->output_count); |
238 | ||
4dbbcdee VS |
239 | return ret; |
240 | } | |
241 | ||
242 | void avfilter_destroy(AVFilterContext *filter) | |
243 | { | |
244 | int i; | |
245 | ||
246 | if(filter->filter->uninit) | |
247 | filter->filter->uninit(filter); | |
248 | ||
c5ef7d7b | 249 | for(i = 0; i < filter->input_count; i ++) { |
4dbbcdee VS |
250 | if(filter->inputs[i]) |
251 | filter->inputs[i]->src->outputs[filter->inputs[i]->srcpad] = NULL; | |
252 | av_free(filter->inputs[i]); | |
253 | } | |
c5ef7d7b | 254 | for(i = 0; i < filter->output_count; i ++) { |
4dbbcdee VS |
255 | if(filter->outputs[i]) |
256 | filter->outputs[i]->dst->inputs[filter->outputs[i]->dstpad] = NULL; | |
257 | av_free(filter->outputs[i]); | |
258 | } | |
259 | ||
2350e69c | 260 | av_free(filter->name); |
c5ef7d7b VS |
261 | av_free(filter->input_pads); |
262 | av_free(filter->output_pads); | |
4dbbcdee VS |
263 | av_free(filter->inputs); |
264 | av_free(filter->outputs); | |
265 | av_free(filter->priv); | |
266 | av_free(filter->av_class); | |
267 | av_free(filter); | |
268 | } | |
269 | ||
6ae82d1e | 270 | AVFilterContext *avfilter_create_by_name(char *name, char *inst_name) |
4dbbcdee VS |
271 | { |
272 | AVFilter *filt; | |
273 | ||
274 | if(!(filt = avfilter_get_by_name(name))) return NULL; | |
6ae82d1e | 275 | return avfilter_create(filt, inst_name); |
4dbbcdee VS |
276 | } |
277 | ||
a360f71e | 278 | int avfilter_init_filter(AVFilterContext *filter, const char *args, void *opaque) |
4dbbcdee | 279 | { |
c6b0aa68 | 280 | int ret; |
4dbbcdee VS |
281 | |
282 | if(filter->filter->init) | |
a360f71e | 283 | if((ret = filter->filter->init(filter, args, opaque))) return ret; |
4dbbcdee VS |
284 | return 0; |
285 | } | |
286 | ||
e0752603 VS |
287 | int *avfilter_make_format_list(int len, ...) |
288 | { | |
289 | int *ret, i; | |
290 | va_list vl; | |
291 | ||
292 | ret = av_malloc(sizeof(int) * (len + 1)); | |
293 | va_start(vl, len); | |
294 | for(i = 0; i < len; i ++) | |
295 | ret[i] = va_arg(vl, int); | |
296 | va_end(vl); | |
297 | ret[len] = -1; | |
298 | ||
299 | return ret; | |
300 | } | |
301 |