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 | 29 | |
6d8c67a7 VS |
30 | /** list of registered filters */ |
31 | struct FilterList | |
32 | { | |
33 | AVFilter *filter; | |
34 | struct FilterList *next; | |
35 | } *filters = NULL; | |
4dbbcdee | 36 | |
6fb0648d VS |
37 | /** helper macros to get the in/out pad on the dst/src filter */ |
38 | #define link_dpad(link) link->dst-> input_pads[link->dstpad] | |
39 | #define link_spad(link) link->src->output_pads[link->srcpad] | |
40 | ||
269b9847 | 41 | AVFilterPicRef *avfilter_ref_pic(AVFilterPicRef *ref, int pmask) |
4dbbcdee VS |
42 | { |
43 | AVFilterPicRef *ret = av_malloc(sizeof(AVFilterPicRef)); | |
cdf2a332 | 44 | *ret = *ref; |
efb36bfc | 45 | ret->perms &= pmask; |
4dbbcdee VS |
46 | ret->pic->refcount ++; |
47 | return ret; | |
48 | } | |
49 | ||
50 | void avfilter_unref_pic(AVFilterPicRef *ref) | |
51 | { | |
269b9847 | 52 | if(-- ref->pic->refcount == 0) |
4dbbcdee VS |
53 | ref->pic->free(ref->pic); |
54 | av_free(ref); | |
55 | } | |
56 | ||
24618441 VS |
57 | void avfilter_insert_pad(unsigned idx, unsigned *count, size_t padidx_off, |
58 | AVFilterPad **pads, AVFilterLink ***links, | |
59 | AVFilterPad *newpad) | |
60 | { | |
61 | unsigned i; | |
62 | ||
63 | idx = FFMIN(idx, *count); | |
64 | ||
65 | *pads = av_realloc(*pads, sizeof(AVFilterPad) * (*count + 1)); | |
66 | *links = av_realloc(*links, sizeof(AVFilterLink*) * (*count + 1)); | |
67 | memmove(*pads +idx+1, *pads +idx, sizeof(AVFilterPad) * (*count-idx)); | |
68 | memmove(*links+idx+1, *links+idx, sizeof(AVFilterLink*) * (*count-idx)); | |
69 | memcpy(*pads+idx, newpad, sizeof(AVFilterPad)); | |
70 | (*links)[idx] = NULL; | |
71 | ||
72 | (*count) ++; | |
73 | for(i = idx+1; i < *count; i ++) | |
74 | if(*links[i]) | |
75 | (*(unsigned *)((uint8_t *)(*links[i]) + padidx_off)) ++; | |
76 | } | |
77 | ||
4dbbcdee VS |
78 | int avfilter_link(AVFilterContext *src, unsigned srcpad, |
79 | AVFilterContext *dst, unsigned dstpad) | |
80 | { | |
81 | AVFilterLink *link; | |
82 | ||
7d0e1392 VS |
83 | if(src->output_count <= srcpad || dst->input_count <= dstpad || |
84 | src->outputs[srcpad] || dst->inputs[dstpad]) | |
4dbbcdee VS |
85 | return -1; |
86 | ||
87 | src->outputs[srcpad] = | |
c949d867 | 88 | dst->inputs[dstpad] = link = av_mallocz(sizeof(AVFilterLink)); |
4dbbcdee | 89 | |
1653c11f VS |
90 | link->src = src; |
91 | link->dst = dst; | |
92 | link->srcpad = srcpad; | |
93 | link->dstpad = dstpad; | |
01942f1d VS |
94 | link->format = -1; |
95 | ||
96 | return 0; | |
97 | } | |
98 | ||
99 | int avfilter_config_link(AVFilterLink *link) | |
100 | { | |
101 | int *fmts[2], i, j; | |
102 | int (*config_link)(AVFilterLink *); | |
e675dccd | 103 | int *(*query_formats)(AVFilterLink *link); |
01942f1d VS |
104 | |
105 | if(!link) | |
106 | return 0; | |
4dbbcdee | 107 | |
e0752603 | 108 | /* find a format both filters support - TODO: auto-insert conversion filter */ |
998a7aa3 | 109 | link->format = -1; |
e675dccd VS |
110 | if(!(query_formats = link_spad(link).query_formats)) |
111 | query_formats = avfilter_default_query_output_formats; | |
112 | fmts[0] = query_formats(link); | |
6fb0648d | 113 | fmts[1] = link_dpad(link).query_formats(link); |
e0752603 VS |
114 | for(i = 0; fmts[0][i] != -1; i ++) |
115 | for(j = 0; fmts[1][j] != -1; j ++) | |
116 | if(fmts[0][i] == fmts[1][j]) { | |
117 | link->format = fmts[0][i]; | |
118 | goto format_done; | |
119 | } | |
120 | ||
121 | format_done: | |
122 | av_free(fmts[0]); | |
123 | av_free(fmts[1]); | |
01942f1d | 124 | if(link->format == -1) |
e0752603 | 125 | return -1; |
e0752603 | 126 | |
6fb0648d | 127 | if(!(config_link = link_spad(link).config_props)) |
01942f1d VS |
128 | config_link = avfilter_default_config_output_link; |
129 | if(config_link(link)) | |
130 | return -1; | |
102fb0e3 | 131 | |
6fb0648d | 132 | if(!(config_link = link_dpad(link).config_props)) |
01942f1d VS |
133 | config_link = avfilter_default_config_input_link; |
134 | if(config_link(link)) | |
135 | return -1; | |
102fb0e3 | 136 | |
4dbbcdee VS |
137 | return 0; |
138 | } | |
139 | ||
140 | AVFilterPicRef *avfilter_get_video_buffer(AVFilterLink *link, int perms) | |
141 | { | |
142 | AVFilterPicRef *ret = NULL; | |
143 | ||
6fb0648d VS |
144 | if(link_dpad(link).get_video_buffer) |
145 | ret = link_dpad(link).get_video_buffer(link, perms); | |
4dbbcdee VS |
146 | |
147 | if(!ret) | |
148 | ret = avfilter_default_get_video_buffer(link, perms); | |
149 | ||
150 | return ret; | |
151 | } | |
152 | ||
3306f8bd | 153 | int avfilter_request_frame(AVFilterLink *link) |
4dbbcdee | 154 | { |
6fb0648d VS |
155 | if(link_spad(link).request_frame) |
156 | return link_spad(link).request_frame(link); | |
9586ba3a | 157 | else if(link->src->inputs[0]) |
3306f8bd VS |
158 | return avfilter_request_frame(link->src->inputs[0]); |
159 | else return -1; | |
4dbbcdee VS |
160 | } |
161 | ||
162 | /* XXX: should we do the duplicating of the picture ref here, instead of | |
163 | * forcing the source filter to do it? */ | |
164 | void avfilter_start_frame(AVFilterLink *link, AVFilterPicRef *picref) | |
165 | { | |
166 | void (*start_frame)(AVFilterLink *, AVFilterPicRef *); | |
167 | ||
e675dccd | 168 | if(!(start_frame = link_dpad(link).start_frame)) |
4dbbcdee VS |
169 | start_frame = avfilter_default_start_frame; |
170 | ||
c949d867 | 171 | /* prepare to copy the picture if it has insufficient permissions */ |
269b9847 VS |
172 | if((link_dpad(link).min_perms & picref->perms) != link_dpad(link).min_perms || |
173 | link_dpad(link).rej_perms & picref->perms) { | |
c949d867 VS |
174 | av_log(link->dst, AV_LOG_INFO, |
175 | "frame copy needed (have perms %x, need %x, reject %x)\n", | |
269b9847 | 176 | picref->perms, |
c949d867 VS |
177 | link_dpad(link).min_perms, link_dpad(link).rej_perms); |
178 | ||
179 | link->cur_pic = avfilter_default_get_video_buffer(link, link_dpad(link).min_perms); | |
180 | link->srcpic = picref; | |
181 | } | |
182 | else | |
183 | link->cur_pic = picref; | |
184 | ||
185 | start_frame(link, link->cur_pic); | |
4dbbcdee VS |
186 | } |
187 | ||
188 | void avfilter_end_frame(AVFilterLink *link) | |
189 | { | |
190 | void (*end_frame)(AVFilterLink *); | |
191 | ||
c949d867 VS |
192 | /* unreference the source picture if we're feeding the destination filter |
193 | * a copied version dues to permission issues */ | |
194 | if(link->srcpic) { | |
195 | avfilter_unref_pic(link->srcpic); | |
196 | link->srcpic = NULL; | |
197 | } | |
198 | ||
e675dccd | 199 | if(!(end_frame = link_dpad(link).end_frame)) |
4dbbcdee VS |
200 | end_frame = avfilter_default_end_frame; |
201 | ||
202 | end_frame(link); | |
203 | } | |
204 | ||
ef35d13a | 205 | void avfilter_draw_slice(AVFilterLink *link, int y, int h) |
4dbbcdee | 206 | { |
c949d867 VS |
207 | uint8_t *src[4], *dst[4]; |
208 | int i, j, hsub, vsub; | |
209 | ||
210 | /* copy the slice if needed for permission reasons */ | |
211 | if(link->srcpic) { | |
212 | avcodec_get_chroma_sub_sample(link->format, &hsub, &vsub); | |
213 | ||
214 | src[0] = link->srcpic-> data[0] + y * link->srcpic-> linesize[0]; | |
215 | dst[0] = link->cur_pic->data[0] + y * link->cur_pic->linesize[0]; | |
216 | for(i = 1; i < 4; i ++) { | |
217 | if(link->srcpic->data[i]) { | |
218 | src[i] = link->srcpic-> data[i] + (y >> vsub) * link->srcpic-> linesize[i]; | |
219 | dst[i] = link->cur_pic->data[i] + (y >> vsub) * link->cur_pic->linesize[i]; | |
220 | } else | |
221 | src[i] = dst[i] = NULL; | |
222 | } | |
223 | for(j = 0; j < h; j ++) { | |
224 | memcpy(dst[0], src[0], link->cur_pic->linesize[0]); | |
225 | src[0] += link->srcpic ->linesize[0]; | |
226 | dst[0] += link->cur_pic->linesize[0]; | |
227 | } | |
228 | for(i = 1; i < 4; i ++) { | |
229 | if(!src[i]) continue; | |
230 | ||
231 | for(j = 0; j < h >> vsub; j ++) { | |
232 | memcpy(dst[i], src[i], link->cur_pic->linesize[i]); | |
233 | src[i] += link->srcpic ->linesize[i]; | |
234 | dst[i] += link->cur_pic->linesize[i]; | |
235 | } | |
236 | } | |
237 | } | |
238 | ||
6fb0648d | 239 | if(!link_dpad(link).draw_slice) |
7d0e1392 VS |
240 | return; |
241 | ||
6fb0648d | 242 | link_dpad(link).draw_slice(link, y, h); |
4dbbcdee VS |
243 | } |
244 | ||
4dbbcdee VS |
245 | AVFilter *avfilter_get_by_name(char *name) |
246 | { | |
6d8c67a7 VS |
247 | struct FilterList *filt; |
248 | ||
249 | for(filt = filters; filt; filt = filt->next) | |
250 | if(!strcmp(filt->filter->name, name)) | |
251 | return filt->filter; | |
4dbbcdee | 252 | |
4dbbcdee VS |
253 | return NULL; |
254 | } | |
255 | ||
256 | /* FIXME: insert in order, rather than insert at end + resort */ | |
257 | void avfilter_register(AVFilter *filter) | |
258 | { | |
6d8c67a7 VS |
259 | struct FilterList *newfilt = av_malloc(sizeof(struct FilterList)); |
260 | ||
261 | newfilt->filter = filter; | |
262 | newfilt->next = filters; | |
263 | filters = newfilt; | |
4dbbcdee VS |
264 | } |
265 | ||
266 | void avfilter_init(void) | |
267 | { | |
d72a138e | 268 | avfilter_register(&vsrc_dummy); |
eaf7eb66 | 269 | avfilter_register(&vsrc_ppm); |
0838e731 | 270 | avfilter_register(&vf_buffer); |
d72a138e | 271 | avfilter_register(&vf_crop); |
49d915cb | 272 | avfilter_register(&vf_fps); |
d4169dd3 | 273 | avfilter_register(&vf_graph); |
f9285377 VS |
274 | avfilter_register(&vf_graphdesc); |
275 | avfilter_register(&vf_graphfile); | |
ef712a3b | 276 | avfilter_register(&vf_overlay); |
d72a138e | 277 | avfilter_register(&vf_passthrough); |
72e3037a | 278 | avfilter_register(&vf_rgb2bgr); |
ce356b09 | 279 | avfilter_register(&vf_slicify); |
81799537 | 280 | avfilter_register(&vf_split); |
e2fcb3cb | 281 | avfilter_register(&vf_vflip); |
4dbbcdee VS |
282 | } |
283 | ||
284 | void avfilter_uninit(void) | |
285 | { | |
6d8c67a7 VS |
286 | struct FilterList *tmp; |
287 | ||
288 | for(; filters; filters = tmp) { | |
289 | tmp = filters->next; | |
290 | av_free(filters); | |
291 | } | |
4dbbcdee VS |
292 | } |
293 | ||
294 | static int pad_count(const AVFilterPad *pads) | |
295 | { | |
296 | AVFilterPad *p = (AVFilterPad *) pads; | |
297 | int count; | |
298 | ||
299 | for(count = 0; p->name; count ++) p ++; | |
300 | return count; | |
301 | } | |
302 | ||
303 | static const char *filter_name(void *p) | |
304 | { | |
305 | AVFilterContext *filter = p; | |
306 | return filter->filter->name; | |
307 | } | |
308 | ||
44b73497 | 309 | AVFilterContext *avfilter_open(AVFilter *filter, char *inst_name) |
4dbbcdee VS |
310 | { |
311 | AVFilterContext *ret = av_malloc(sizeof(AVFilterContext)); | |
312 | ||
313 | ret->av_class = av_mallocz(sizeof(AVClass)); | |
314 | ret->av_class->item_name = filter_name; | |
315 | ret->filter = filter; | |
2350e69c | 316 | ret->name = inst_name ? av_strdup(inst_name) : NULL; |
4dbbcdee VS |
317 | ret->priv = av_mallocz(filter->priv_size); |
318 | ||
7d0e1392 | 319 | ret->input_count = pad_count(filter->inputs); |
c5ef7d7b VS |
320 | ret->input_pads = av_malloc(sizeof(AVFilterPad) * ret->input_count); |
321 | memcpy(ret->input_pads, filter->inputs, sizeof(AVFilterPad)*ret->input_count); | |
7d0e1392 | 322 | ret->inputs = av_mallocz(sizeof(AVFilterLink*) * ret->input_count); |
c5ef7d7b | 323 | |
7d0e1392 | 324 | ret->output_count = pad_count(filter->outputs); |
c5ef7d7b VS |
325 | ret->output_pads = av_malloc(sizeof(AVFilterPad) * ret->output_count); |
326 | memcpy(ret->output_pads, filter->outputs, sizeof(AVFilterPad)*ret->output_count); | |
7d0e1392 VS |
327 | ret->outputs = av_mallocz(sizeof(AVFilterLink*) * ret->output_count); |
328 | ||
4dbbcdee VS |
329 | return ret; |
330 | } | |
331 | ||
332 | void avfilter_destroy(AVFilterContext *filter) | |
333 | { | |
334 | int i; | |
335 | ||
336 | if(filter->filter->uninit) | |
337 | filter->filter->uninit(filter); | |
338 | ||
c5ef7d7b | 339 | for(i = 0; i < filter->input_count; i ++) { |
4dbbcdee VS |
340 | if(filter->inputs[i]) |
341 | filter->inputs[i]->src->outputs[filter->inputs[i]->srcpad] = NULL; | |
f4cb4462 | 342 | av_freep(&filter->inputs[i]); |
4dbbcdee | 343 | } |
c5ef7d7b | 344 | for(i = 0; i < filter->output_count; i ++) { |
4dbbcdee VS |
345 | if(filter->outputs[i]) |
346 | filter->outputs[i]->dst->inputs[filter->outputs[i]->dstpad] = NULL; | |
f4cb4462 | 347 | av_freep(&filter->outputs[i]); |
4dbbcdee VS |
348 | } |
349 | ||
f4cb4462 VS |
350 | av_freep(&filter->name); |
351 | av_freep(&filter->input_pads); | |
352 | av_freep(&filter->output_pads); | |
353 | av_freep(&filter->inputs); | |
354 | av_freep(&filter->outputs); | |
355 | av_freep(&filter->priv); | |
356 | av_freep(&filter->av_class); | |
4dbbcdee VS |
357 | av_free(filter); |
358 | } | |
359 | ||
a360f71e | 360 | int avfilter_init_filter(AVFilterContext *filter, const char *args, void *opaque) |
4dbbcdee | 361 | { |
c6b0aa68 | 362 | int ret; |
4dbbcdee VS |
363 | |
364 | if(filter->filter->init) | |
a360f71e | 365 | if((ret = filter->filter->init(filter, args, opaque))) return ret; |
4dbbcdee VS |
366 | return 0; |
367 | } | |
368 | ||
e0752603 VS |
369 | int *avfilter_make_format_list(int len, ...) |
370 | { | |
371 | int *ret, i; | |
372 | va_list vl; | |
373 | ||
374 | ret = av_malloc(sizeof(int) * (len + 1)); | |
375 | va_start(vl, len); | |
376 | for(i = 0; i < len; i ++) | |
377 | ret[i] = va_arg(vl, int); | |
378 | va_end(vl); | |
379 | ret[len] = -1; | |
380 | ||
381 | return ret; | |
382 | } | |
383 |