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 | ||
52362e9d VS |
99 | int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt, |
100 | unsigned in, unsigned out) | |
101 | { | |
e3065c8b VS |
102 | AVFilterFormats *formats; |
103 | ||
52362e9d VS |
104 | av_log(NULL, AV_LOG_INFO, "auto-inserting filter '%s'\n", |
105 | filt->filter->name); | |
106 | ||
107 | link->dst->inputs[link->dstpad] = NULL; | |
108 | if(avfilter_link(filt, out, link->dst, link->dstpad)) { | |
109 | /* failed to link output filter to new filter */ | |
110 | link->dst->inputs[link->dstpad] = link; | |
111 | return -1; | |
112 | } | |
113 | ||
114 | /* re-hookup the link to the new destination filter we inserted */ | |
115 | link->dst = filt; | |
116 | link->dstpad = in; | |
117 | filt->inputs[in] = link; | |
118 | ||
07d0bba5 VS |
119 | /* if any information on supported colorspaces already exists on the |
120 | * link, we need to preserve that */ | |
e3065c8b VS |
121 | if((formats = link->out_formats)) |
122 | avfilter_formats_changeref(&link->out_formats, | |
123 | &filt->outputs[out]->out_formats); | |
07d0bba5 | 124 | |
52362e9d VS |
125 | return 0; |
126 | } | |
127 | ||
01942f1d VS |
128 | int avfilter_config_link(AVFilterLink *link) |
129 | { | |
01942f1d | 130 | int (*config_link)(AVFilterLink *); |
d21cbbff | 131 | |
01942f1d VS |
132 | if(!link) |
133 | return 0; | |
4dbbcdee | 134 | |
6fb0648d | 135 | if(!(config_link = link_spad(link).config_props)) |
01942f1d VS |
136 | config_link = avfilter_default_config_output_link; |
137 | if(config_link(link)) | |
138 | return -1; | |
102fb0e3 | 139 | |
6fb0648d | 140 | if(!(config_link = link_dpad(link).config_props)) |
01942f1d VS |
141 | config_link = avfilter_default_config_input_link; |
142 | if(config_link(link)) | |
143 | return -1; | |
102fb0e3 | 144 | |
4dbbcdee VS |
145 | return 0; |
146 | } | |
147 | ||
148 | AVFilterPicRef *avfilter_get_video_buffer(AVFilterLink *link, int perms) | |
149 | { | |
150 | AVFilterPicRef *ret = NULL; | |
151 | ||
6fb0648d VS |
152 | if(link_dpad(link).get_video_buffer) |
153 | ret = link_dpad(link).get_video_buffer(link, perms); | |
4dbbcdee VS |
154 | |
155 | if(!ret) | |
156 | ret = avfilter_default_get_video_buffer(link, perms); | |
157 | ||
158 | return ret; | |
159 | } | |
160 | ||
3306f8bd | 161 | int avfilter_request_frame(AVFilterLink *link) |
4dbbcdee | 162 | { |
6fb0648d VS |
163 | if(link_spad(link).request_frame) |
164 | return link_spad(link).request_frame(link); | |
9586ba3a | 165 | else if(link->src->inputs[0]) |
3306f8bd VS |
166 | return avfilter_request_frame(link->src->inputs[0]); |
167 | else return -1; | |
4dbbcdee VS |
168 | } |
169 | ||
170 | /* XXX: should we do the duplicating of the picture ref here, instead of | |
171 | * forcing the source filter to do it? */ | |
172 | void avfilter_start_frame(AVFilterLink *link, AVFilterPicRef *picref) | |
173 | { | |
174 | void (*start_frame)(AVFilterLink *, AVFilterPicRef *); | |
175 | ||
e675dccd | 176 | if(!(start_frame = link_dpad(link).start_frame)) |
4dbbcdee VS |
177 | start_frame = avfilter_default_start_frame; |
178 | ||
c949d867 | 179 | /* prepare to copy the picture if it has insufficient permissions */ |
269b9847 VS |
180 | if((link_dpad(link).min_perms & picref->perms) != link_dpad(link).min_perms || |
181 | link_dpad(link).rej_perms & picref->perms) { | |
c949d867 VS |
182 | av_log(link->dst, AV_LOG_INFO, |
183 | "frame copy needed (have perms %x, need %x, reject %x)\n", | |
269b9847 | 184 | picref->perms, |
c949d867 VS |
185 | link_dpad(link).min_perms, link_dpad(link).rej_perms); |
186 | ||
187 | link->cur_pic = avfilter_default_get_video_buffer(link, link_dpad(link).min_perms); | |
188 | link->srcpic = picref; | |
189 | } | |
190 | else | |
191 | link->cur_pic = picref; | |
192 | ||
193 | start_frame(link, link->cur_pic); | |
4dbbcdee VS |
194 | } |
195 | ||
196 | void avfilter_end_frame(AVFilterLink *link) | |
197 | { | |
198 | void (*end_frame)(AVFilterLink *); | |
199 | ||
c949d867 VS |
200 | /* unreference the source picture if we're feeding the destination filter |
201 | * a copied version dues to permission issues */ | |
202 | if(link->srcpic) { | |
203 | avfilter_unref_pic(link->srcpic); | |
204 | link->srcpic = NULL; | |
205 | } | |
206 | ||
e675dccd | 207 | if(!(end_frame = link_dpad(link).end_frame)) |
4dbbcdee VS |
208 | end_frame = avfilter_default_end_frame; |
209 | ||
210 | end_frame(link); | |
211 | } | |
212 | ||
ef35d13a | 213 | void avfilter_draw_slice(AVFilterLink *link, int y, int h) |
4dbbcdee | 214 | { |
c949d867 VS |
215 | uint8_t *src[4], *dst[4]; |
216 | int i, j, hsub, vsub; | |
217 | ||
218 | /* copy the slice if needed for permission reasons */ | |
219 | if(link->srcpic) { | |
220 | avcodec_get_chroma_sub_sample(link->format, &hsub, &vsub); | |
221 | ||
222 | src[0] = link->srcpic-> data[0] + y * link->srcpic-> linesize[0]; | |
223 | dst[0] = link->cur_pic->data[0] + y * link->cur_pic->linesize[0]; | |
224 | for(i = 1; i < 4; i ++) { | |
225 | if(link->srcpic->data[i]) { | |
226 | src[i] = link->srcpic-> data[i] + (y >> vsub) * link->srcpic-> linesize[i]; | |
227 | dst[i] = link->cur_pic->data[i] + (y >> vsub) * link->cur_pic->linesize[i]; | |
228 | } else | |
229 | src[i] = dst[i] = NULL; | |
230 | } | |
231 | for(j = 0; j < h; j ++) { | |
232 | memcpy(dst[0], src[0], link->cur_pic->linesize[0]); | |
233 | src[0] += link->srcpic ->linesize[0]; | |
234 | dst[0] += link->cur_pic->linesize[0]; | |
235 | } | |
236 | for(i = 1; i < 4; i ++) { | |
237 | if(!src[i]) continue; | |
238 | ||
239 | for(j = 0; j < h >> vsub; j ++) { | |
240 | memcpy(dst[i], src[i], link->cur_pic->linesize[i]); | |
241 | src[i] += link->srcpic ->linesize[i]; | |
242 | dst[i] += link->cur_pic->linesize[i]; | |
243 | } | |
244 | } | |
245 | } | |
246 | ||
6fb0648d | 247 | if(!link_dpad(link).draw_slice) |
7d0e1392 VS |
248 | return; |
249 | ||
6fb0648d | 250 | link_dpad(link).draw_slice(link, y, h); |
4dbbcdee VS |
251 | } |
252 | ||
4dbbcdee VS |
253 | AVFilter *avfilter_get_by_name(char *name) |
254 | { | |
6d8c67a7 VS |
255 | struct FilterList *filt; |
256 | ||
257 | for(filt = filters; filt; filt = filt->next) | |
258 | if(!strcmp(filt->filter->name, name)) | |
259 | return filt->filter; | |
4dbbcdee | 260 | |
4dbbcdee VS |
261 | return NULL; |
262 | } | |
263 | ||
4dbbcdee VS |
264 | void avfilter_register(AVFilter *filter) |
265 | { | |
6d8c67a7 VS |
266 | struct FilterList *newfilt = av_malloc(sizeof(struct FilterList)); |
267 | ||
268 | newfilt->filter = filter; | |
269 | newfilt->next = filters; | |
270 | filters = newfilt; | |
4dbbcdee VS |
271 | } |
272 | ||
273 | void avfilter_init(void) | |
274 | { | |
7bce27a3 VS |
275 | avfilter_register(&avfilter_vf_crop); |
276 | avfilter_register(&avfilter_vf_fifo); | |
277 | avfilter_register(&avfilter_vf_fps); | |
278 | avfilter_register(&avfilter_vf_graph); | |
279 | avfilter_register(&avfilter_vf_graphdesc); | |
280 | avfilter_register(&avfilter_vf_graphfile); | |
c35a0473 | 281 | avfilter_register(&avfilter_vf_hflip); |
f9033975 | 282 | avfilter_register(&avfilter_vf_negate); |
7bce27a3 VS |
283 | avfilter_register(&avfilter_vf_overlay); |
284 | avfilter_register(&avfilter_vf_passthrough); | |
2a553ef5 | 285 | avfilter_register(&avfilter_vf_scale); |
7bce27a3 VS |
286 | avfilter_register(&avfilter_vf_slicify); |
287 | avfilter_register(&avfilter_vf_split); | |
288 | avfilter_register(&avfilter_vf_vflip); | |
4dbbcdee VS |
289 | } |
290 | ||
291 | void avfilter_uninit(void) | |
292 | { | |
6d8c67a7 VS |
293 | struct FilterList *tmp; |
294 | ||
295 | for(; filters; filters = tmp) { | |
296 | tmp = filters->next; | |
297 | av_free(filters); | |
298 | } | |
4dbbcdee VS |
299 | } |
300 | ||
301 | static int pad_count(const AVFilterPad *pads) | |
302 | { | |
303 | AVFilterPad *p = (AVFilterPad *) pads; | |
304 | int count; | |
305 | ||
306 | for(count = 0; p->name; count ++) p ++; | |
307 | return count; | |
308 | } | |
309 | ||
310 | static const char *filter_name(void *p) | |
311 | { | |
312 | AVFilterContext *filter = p; | |
313 | return filter->filter->name; | |
314 | } | |
315 | ||
44b73497 | 316 | AVFilterContext *avfilter_open(AVFilter *filter, char *inst_name) |
4dbbcdee | 317 | { |
8f618f4c VS |
318 | AVFilterContext *ret; |
319 | ||
320 | if (!filter) | |
321 | return 0; | |
322 | ||
323 | ret = av_malloc(sizeof(AVFilterContext)); | |
4dbbcdee VS |
324 | |
325 | ret->av_class = av_mallocz(sizeof(AVClass)); | |
326 | ret->av_class->item_name = filter_name; | |
327 | ret->filter = filter; | |
2350e69c | 328 | ret->name = inst_name ? av_strdup(inst_name) : NULL; |
4dbbcdee VS |
329 | ret->priv = av_mallocz(filter->priv_size); |
330 | ||
7d0e1392 | 331 | ret->input_count = pad_count(filter->inputs); |
c5ef7d7b VS |
332 | ret->input_pads = av_malloc(sizeof(AVFilterPad) * ret->input_count); |
333 | memcpy(ret->input_pads, filter->inputs, sizeof(AVFilterPad)*ret->input_count); | |
7d0e1392 | 334 | ret->inputs = av_mallocz(sizeof(AVFilterLink*) * ret->input_count); |
c5ef7d7b | 335 | |
7d0e1392 | 336 | ret->output_count = pad_count(filter->outputs); |
c5ef7d7b VS |
337 | ret->output_pads = av_malloc(sizeof(AVFilterPad) * ret->output_count); |
338 | memcpy(ret->output_pads, filter->outputs, sizeof(AVFilterPad)*ret->output_count); | |
7d0e1392 VS |
339 | ret->outputs = av_mallocz(sizeof(AVFilterLink*) * ret->output_count); |
340 | ||
4dbbcdee VS |
341 | return ret; |
342 | } | |
343 | ||
344 | void avfilter_destroy(AVFilterContext *filter) | |
345 | { | |
346 | int i; | |
347 | ||
348 | if(filter->filter->uninit) | |
349 | filter->filter->uninit(filter); | |
350 | ||
c5ef7d7b | 351 | for(i = 0; i < filter->input_count; i ++) { |
4dbbcdee VS |
352 | if(filter->inputs[i]) |
353 | filter->inputs[i]->src->outputs[filter->inputs[i]->srcpad] = NULL; | |
f4cb4462 | 354 | av_freep(&filter->inputs[i]); |
4dbbcdee | 355 | } |
c5ef7d7b | 356 | for(i = 0; i < filter->output_count; i ++) { |
4dbbcdee VS |
357 | if(filter->outputs[i]) |
358 | filter->outputs[i]->dst->inputs[filter->outputs[i]->dstpad] = NULL; | |
f4cb4462 | 359 | av_freep(&filter->outputs[i]); |
4dbbcdee VS |
360 | } |
361 | ||
f4cb4462 VS |
362 | av_freep(&filter->name); |
363 | av_freep(&filter->input_pads); | |
364 | av_freep(&filter->output_pads); | |
365 | av_freep(&filter->inputs); | |
366 | av_freep(&filter->outputs); | |
367 | av_freep(&filter->priv); | |
368 | av_freep(&filter->av_class); | |
4dbbcdee VS |
369 | av_free(filter); |
370 | } | |
371 | ||
a360f71e | 372 | int avfilter_init_filter(AVFilterContext *filter, const char *args, void *opaque) |
4dbbcdee | 373 | { |
c6b0aa68 | 374 | int ret; |
4dbbcdee VS |
375 | |
376 | if(filter->filter->init) | |
a360f71e | 377 | if((ret = filter->filter->init(filter, args, opaque))) return ret; |
4dbbcdee VS |
378 | return 0; |
379 | } | |
380 |