Commit | Line | Data |
---|---|---|
4dbbcdee | 1 | /* |
16790dc3 | 2 | * filter layer |
4dbbcdee VS |
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 | ||
96da1c51 SS |
22 | /* #define DEBUG */ |
23 | ||
245976da | 24 | #include "libavcodec/imgconvert.h" |
b4b66456 | 25 | #include "libavutil/pixdesc.h" |
4dbbcdee VS |
26 | #include "avfilter.h" |
27 | ||
540f1c7b SS |
28 | unsigned avfilter_version(void) { |
29 | return LIBAVFILTER_VERSION_INT; | |
30 | } | |
31 | ||
41600690 | 32 | const char *avfilter_configuration(void) |
c1736936 DB |
33 | { |
34 | return FFMPEG_CONFIGURATION; | |
35 | } | |
36 | ||
41600690 | 37 | const char *avfilter_license(void) |
c1736936 DB |
38 | { |
39 | #define LICENSE_PREFIX "libavfilter license: " | |
40 | return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1; | |
41 | } | |
42 | ||
6fb0648d VS |
43 | /** helper macros to get the in/out pad on the dst/src filter */ |
44 | #define link_dpad(link) link->dst-> input_pads[link->dstpad] | |
45 | #define link_spad(link) link->src->output_pads[link->srcpad] | |
46 | ||
269b9847 | 47 | AVFilterPicRef *avfilter_ref_pic(AVFilterPicRef *ref, int pmask) |
4dbbcdee VS |
48 | { |
49 | AVFilterPicRef *ret = av_malloc(sizeof(AVFilterPicRef)); | |
cdf2a332 | 50 | *ret = *ref; |
efb36bfc | 51 | ret->perms &= pmask; |
4dbbcdee VS |
52 | ret->pic->refcount ++; |
53 | return ret; | |
54 | } | |
55 | ||
56 | void avfilter_unref_pic(AVFilterPicRef *ref) | |
57 | { | |
e079d22e | 58 | if(!(--ref->pic->refcount)) |
4dbbcdee VS |
59 | ref->pic->free(ref->pic); |
60 | av_free(ref); | |
61 | } | |
62 | ||
24618441 VS |
63 | void avfilter_insert_pad(unsigned idx, unsigned *count, size_t padidx_off, |
64 | AVFilterPad **pads, AVFilterLink ***links, | |
65 | AVFilterPad *newpad) | |
66 | { | |
67 | unsigned i; | |
68 | ||
69 | idx = FFMIN(idx, *count); | |
70 | ||
71 | *pads = av_realloc(*pads, sizeof(AVFilterPad) * (*count + 1)); | |
72 | *links = av_realloc(*links, sizeof(AVFilterLink*) * (*count + 1)); | |
73 | memmove(*pads +idx+1, *pads +idx, sizeof(AVFilterPad) * (*count-idx)); | |
74 | memmove(*links+idx+1, *links+idx, sizeof(AVFilterLink*) * (*count-idx)); | |
75 | memcpy(*pads+idx, newpad, sizeof(AVFilterPad)); | |
76 | (*links)[idx] = NULL; | |
77 | ||
78 | (*count) ++; | |
79 | for(i = idx+1; i < *count; i ++) | |
80 | if(*links[i]) | |
d9b575d3 | 81 | (*(unsigned *)((uint8_t *) *links[i] + padidx_off)) ++; |
24618441 VS |
82 | } |
83 | ||
4dbbcdee VS |
84 | int avfilter_link(AVFilterContext *src, unsigned srcpad, |
85 | AVFilterContext *dst, unsigned dstpad) | |
86 | { | |
87 | AVFilterLink *link; | |
88 | ||
7d0e1392 VS |
89 | if(src->output_count <= srcpad || dst->input_count <= dstpad || |
90 | src->outputs[srcpad] || dst->inputs[dstpad]) | |
4dbbcdee VS |
91 | return -1; |
92 | ||
93 | src->outputs[srcpad] = | |
b3431ecd | 94 | dst-> inputs[dstpad] = link = av_mallocz(sizeof(AVFilterLink)); |
4dbbcdee | 95 | |
1653c11f VS |
96 | link->src = src; |
97 | link->dst = dst; | |
98 | link->srcpad = srcpad; | |
99 | link->dstpad = dstpad; | |
5bc8ebd3 | 100 | link->format = PIX_FMT_NONE; |
01942f1d VS |
101 | |
102 | return 0; | |
103 | } | |
104 | ||
52362e9d VS |
105 | int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt, |
106 | unsigned in, unsigned out) | |
107 | { | |
08f8b51f SS |
108 | av_log(link->dst, AV_LOG_INFO, "auto-inserting filter '%s' " |
109 | "between the filter '%s' and the filter '%s'\n", | |
110 | filt->name, link->src->name, link->dst->name); | |
52362e9d VS |
111 | |
112 | link->dst->inputs[link->dstpad] = NULL; | |
113 | if(avfilter_link(filt, out, link->dst, link->dstpad)) { | |
114 | /* failed to link output filter to new filter */ | |
115 | link->dst->inputs[link->dstpad] = link; | |
116 | return -1; | |
117 | } | |
118 | ||
119 | /* re-hookup the link to the new destination filter we inserted */ | |
120 | link->dst = filt; | |
121 | link->dstpad = in; | |
122 | filt->inputs[in] = link; | |
123 | ||
07d0bba5 VS |
124 | /* if any information on supported colorspaces already exists on the |
125 | * link, we need to preserve that */ | |
5b7c4033 | 126 | if(link->out_formats) |
e3065c8b VS |
127 | avfilter_formats_changeref(&link->out_formats, |
128 | &filt->outputs[out]->out_formats); | |
07d0bba5 | 129 | |
52362e9d VS |
130 | return 0; |
131 | } | |
132 | ||
69818105 | 133 | int avfilter_config_links(AVFilterContext *filter) |
01942f1d | 134 | { |
01942f1d | 135 | int (*config_link)(AVFilterLink *); |
69818105 VS |
136 | unsigned i; |
137 | ||
138 | for(i = 0; i < filter->input_count; i ++) { | |
e079d22e | 139 | AVFilterLink *link = filter->inputs[i]; |
d21cbbff | 140 | |
e079d22e | 141 | if(!link) continue; |
69818105 VS |
142 | |
143 | switch(link->init_state) { | |
144 | case AVLINK_INIT: | |
145 | continue; | |
146 | case AVLINK_STARTINIT: | |
7a9fd2a0 VS |
147 | av_log(filter, AV_LOG_INFO, "circular filter chain detected\n"); |
148 | return 0; | |
69818105 VS |
149 | case AVLINK_UNINIT: |
150 | link->init_state = AVLINK_STARTINIT; | |
151 | ||
152 | if(avfilter_config_links(link->src)) | |
153 | return -1; | |
4dbbcdee | 154 | |
2fd46877 VS |
155 | if(!(config_link = link_spad(link).config_props)) |
156 | config_link = avfilter_default_config_output_link; | |
157 | if(config_link(link)) | |
158 | return -1; | |
102fb0e3 | 159 | |
2fd46877 | 160 | if((config_link = link_dpad(link).config_props)) |
a5b5d95a VS |
161 | if(config_link(link)) |
162 | return -1; | |
102fb0e3 | 163 | |
69818105 VS |
164 | link->init_state = AVLINK_INIT; |
165 | } | |
166 | } | |
167 | ||
4dbbcdee VS |
168 | return 0; |
169 | } | |
170 | ||
96da1c51 SS |
171 | static void dprintf_picref(void *ctx, AVFilterPicRef *picref, int end) |
172 | { | |
173 | dprintf(ctx, | |
63833766 | 174 | "picref[%p data[%p, %p, %p, %p] linesize[%d, %d, %d, %d] pts:%"PRId64" a:%d/%d s:%dx%d]%s", |
96da1c51 SS |
175 | picref, |
176 | picref->data [0], picref->data [1], picref->data [2], picref->data [3], | |
177 | picref->linesize[0], picref->linesize[1], picref->linesize[2], picref->linesize[3], | |
63833766 | 178 | picref->pts, picref->pixel_aspect.num, picref->pixel_aspect.den, picref->w, picref->h, |
96da1c51 SS |
179 | end ? "\n" : ""); |
180 | } | |
181 | ||
182 | static void dprintf_link(void *ctx, AVFilterLink *link, int end) | |
183 | { | |
184 | dprintf(ctx, | |
8fdb01c1 | 185 | "link[%p s:%dx%d fmt:%-16s %-16s->%-16s]%s", |
96da1c51 | 186 | link, link->w, link->h, |
b4b66456 | 187 | av_pix_fmt_descriptors[link->format].name, |
96da1c51 SS |
188 | link->src ? link->src->filter->name : "", |
189 | link->dst ? link->dst->filter->name : "", | |
190 | end ? "\n" : ""); | |
191 | } | |
192 | ||
193 | #define DPRINTF_START(ctx, func) dprintf(NULL, "%-16s: ", #func) | |
194 | ||
0eb4ff9e | 195 | AVFilterPicRef *avfilter_get_video_buffer(AVFilterLink *link, int perms, int w, int h) |
4dbbcdee VS |
196 | { |
197 | AVFilterPicRef *ret = NULL; | |
198 | ||
0eb4ff9e | 199 | DPRINTF_START(NULL, get_video_buffer); dprintf_link(NULL, link, 0); dprintf(NULL, " perms:%d w:%d h:%d\n", perms, w, h); |
96da1c51 | 200 | |
6fb0648d | 201 | if(link_dpad(link).get_video_buffer) |
0eb4ff9e SS |
202 | ret = link_dpad(link).get_video_buffer(link, perms, w, h); |
203 | ||
4dbbcdee | 204 | if(!ret) |
0eb4ff9e | 205 | ret = avfilter_default_get_video_buffer(link, perms, w, h); |
4dbbcdee | 206 | |
96da1c51 SS |
207 | DPRINTF_START(NULL, get_video_buffer); dprintf_link(NULL, link, 0); dprintf(NULL, " returning "); dprintf_picref(NULL, ret, 1); |
208 | ||
4dbbcdee VS |
209 | return ret; |
210 | } | |
211 | ||
3306f8bd | 212 | int avfilter_request_frame(AVFilterLink *link) |
4dbbcdee | 213 | { |
96da1c51 SS |
214 | DPRINTF_START(NULL, request_frame); dprintf_link(NULL, link, 1); |
215 | ||
6fb0648d VS |
216 | if(link_spad(link).request_frame) |
217 | return link_spad(link).request_frame(link); | |
9586ba3a | 218 | else if(link->src->inputs[0]) |
3306f8bd VS |
219 | return avfilter_request_frame(link->src->inputs[0]); |
220 | else return -1; | |
4dbbcdee VS |
221 | } |
222 | ||
7b02c484 VS |
223 | int avfilter_poll_frame(AVFilterLink *link) |
224 | { | |
225 | int i, min=INT_MAX; | |
226 | ||
227 | if(link_spad(link).poll_frame) | |
228 | return link_spad(link).poll_frame(link); | |
c245ddf2 VS |
229 | |
230 | for (i=0; i<link->src->input_count; i++) { | |
9dd08b4e | 231 | int val; |
c245ddf2 VS |
232 | if(!link->src->inputs[i]) |
233 | return -1; | |
9dd08b4e VS |
234 | val = avfilter_poll_frame(link->src->inputs[i]); |
235 | min = FFMIN(min, val); | |
c245ddf2 | 236 | } |
7b02c484 VS |
237 | |
238 | return min; | |
239 | } | |
240 | ||
4dbbcdee VS |
241 | /* XXX: should we do the duplicating of the picture ref here, instead of |
242 | * forcing the source filter to do it? */ | |
243 | void avfilter_start_frame(AVFilterLink *link, AVFilterPicRef *picref) | |
244 | { | |
245 | void (*start_frame)(AVFilterLink *, AVFilterPicRef *); | |
ac8a116e | 246 | AVFilterPad *dst = &link_dpad(link); |
4dbbcdee | 247 | |
96da1c51 SS |
248 | DPRINTF_START(NULL, start_frame); dprintf_link(NULL, link, 0); dprintf(NULL, " "); dprintf_picref(NULL, picref, 1); |
249 | ||
ac8a116e | 250 | if(!(start_frame = dst->start_frame)) |
4dbbcdee VS |
251 | start_frame = avfilter_default_start_frame; |
252 | ||
c949d867 | 253 | /* prepare to copy the picture if it has insufficient permissions */ |
ac8a116e VS |
254 | if((dst->min_perms & picref->perms) != dst->min_perms || |
255 | dst->rej_perms & picref->perms) { | |
35db407e | 256 | /* |
c949d867 VS |
257 | av_log(link->dst, AV_LOG_INFO, |
258 | "frame copy needed (have perms %x, need %x, reject %x)\n", | |
269b9847 | 259 | picref->perms, |
c949d867 | 260 | link_dpad(link).min_perms, link_dpad(link).rej_perms); |
35db407e | 261 | */ |
c949d867 | 262 | |
0eb4ff9e | 263 | link->cur_pic = avfilter_default_get_video_buffer(link, dst->min_perms, link->w, link->h); |
c949d867 | 264 | link->srcpic = picref; |
be36bc09 | 265 | link->cur_pic->pts = link->srcpic->pts; |
fe479c9d | 266 | link->cur_pic->pixel_aspect = link->srcpic->pixel_aspect; |
c949d867 VS |
267 | } |
268 | else | |
269 | link->cur_pic = picref; | |
270 | ||
271 | start_frame(link, link->cur_pic); | |
4dbbcdee VS |
272 | } |
273 | ||
274 | void avfilter_end_frame(AVFilterLink *link) | |
275 | { | |
276 | void (*end_frame)(AVFilterLink *); | |
277 | ||
35db407e VS |
278 | if(!(end_frame = link_dpad(link).end_frame)) |
279 | end_frame = avfilter_default_end_frame; | |
280 | ||
281 | end_frame(link); | |
282 | ||
c949d867 VS |
283 | /* unreference the source picture if we're feeding the destination filter |
284 | * a copied version dues to permission issues */ | |
285 | if(link->srcpic) { | |
286 | avfilter_unref_pic(link->srcpic); | |
287 | link->srcpic = NULL; | |
288 | } | |
289 | ||
4dbbcdee VS |
290 | } |
291 | ||
a13a5437 | 292 | void avfilter_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) |
4dbbcdee | 293 | { |
c949d867 VS |
294 | uint8_t *src[4], *dst[4]; |
295 | int i, j, hsub, vsub; | |
a13a5437 | 296 | void (*draw_slice)(AVFilterLink *, int, int, int); |
c949d867 | 297 | |
a13a5437 | 298 | DPRINTF_START(NULL, draw_slice); dprintf_link(NULL, link, 0); dprintf(NULL, " y:%d h:%d dir:%d\n", y, h, slice_dir); |
96da1c51 | 299 | |
c949d867 VS |
300 | /* copy the slice if needed for permission reasons */ |
301 | if(link->srcpic) { | |
b4b66456 SS |
302 | hsub = av_pix_fmt_descriptors[link->format].log2_chroma_w; |
303 | vsub = av_pix_fmt_descriptors[link->format].log2_chroma_h; | |
c949d867 | 304 | |
74b46655 | 305 | for(i = 0; i < 4; i ++) { |
c949d867 | 306 | if(link->srcpic->data[i]) { |
74b46655 VS |
307 | src[i] = link->srcpic-> data[i] + |
308 | (y >> (i==0 ? 0 : vsub)) * link->srcpic-> linesize[i]; | |
309 | dst[i] = link->cur_pic->data[i] + | |
310 | (y >> (i==0 ? 0 : vsub)) * link->cur_pic->linesize[i]; | |
c949d867 VS |
311 | } else |
312 | src[i] = dst[i] = NULL; | |
313 | } | |
19dc7104 VS |
314 | |
315 | for(i = 0; i < 4; i ++) { | |
805d0232 VS |
316 | int planew = |
317 | ff_get_plane_bytewidth(link->format, link->cur_pic->w, i); | |
318 | ||
c949d867 VS |
319 | if(!src[i]) continue; |
320 | ||
19dc7104 | 321 | for(j = 0; j < h >> (i==0 ? 0 : vsub); j ++) { |
805d0232 | 322 | memcpy(dst[i], src[i], planew); |
c949d867 VS |
323 | src[i] += link->srcpic ->linesize[i]; |
324 | dst[i] += link->cur_pic->linesize[i]; | |
325 | } | |
326 | } | |
327 | } | |
328 | ||
b9609848 SS |
329 | if(!(draw_slice = link_dpad(link).draw_slice)) |
330 | draw_slice = avfilter_default_draw_slice; | |
a13a5437 | 331 | draw_slice(link, y, h, slice_dir); |
4dbbcdee VS |
332 | } |
333 | ||
86a60fa1 SS |
334 | #define MAX_REGISTERED_AVFILTERS_NB 64 |
335 | ||
336 | static AVFilter *registered_avfilters[MAX_REGISTERED_AVFILTERS_NB + 1]; | |
337 | ||
338 | static int next_registered_avfilter_idx = 0; | |
3555d2e8 | 339 | |
05decb00 | 340 | AVFilter *avfilter_get_by_name(const char *name) |
4dbbcdee | 341 | { |
86a60fa1 | 342 | int i; |
6d8c67a7 | 343 | |
86a60fa1 SS |
344 | for (i = 0; registered_avfilters[i]; i++) |
345 | if (!strcmp(registered_avfilters[i]->name, name)) | |
346 | return registered_avfilters[i]; | |
4dbbcdee | 347 | |
4dbbcdee VS |
348 | return NULL; |
349 | } | |
350 | ||
86a60fa1 | 351 | int avfilter_register(AVFilter *filter) |
4dbbcdee | 352 | { |
86a60fa1 SS |
353 | if (next_registered_avfilter_idx == MAX_REGISTERED_AVFILTERS_NB) |
354 | return -1; | |
6d8c67a7 | 355 | |
86a60fa1 SS |
356 | registered_avfilters[next_registered_avfilter_idx++] = filter; |
357 | return 0; | |
4dbbcdee VS |
358 | } |
359 | ||
1433c4ab SS |
360 | AVFilter **av_filter_next(AVFilter **filter) |
361 | { | |
362 | return filter ? ++filter : ®istered_avfilters[0]; | |
363 | } | |
364 | ||
4dbbcdee VS |
365 | void avfilter_uninit(void) |
366 | { | |
86a60fa1 SS |
367 | memset(registered_avfilters, 0, sizeof(registered_avfilters)); |
368 | next_registered_avfilter_idx = 0; | |
4dbbcdee VS |
369 | } |
370 | ||
371 | static int pad_count(const AVFilterPad *pads) | |
372 | { | |
4dbbcdee VS |
373 | int count; |
374 | ||
05decb00 | 375 | for(count = 0; pads->name; count ++) pads ++; |
4dbbcdee VS |
376 | return count; |
377 | } | |
378 | ||
379 | static const char *filter_name(void *p) | |
380 | { | |
381 | AVFilterContext *filter = p; | |
382 | return filter->filter->name; | |
383 | } | |
384 | ||
b049ad50 MR |
385 | static const AVClass avfilter_class = { |
386 | "AVFilter", | |
387 | filter_name | |
388 | }; | |
389 | ||
05decb00 | 390 | AVFilterContext *avfilter_open(AVFilter *filter, const char *inst_name) |
4dbbcdee | 391 | { |
8f618f4c VS |
392 | AVFilterContext *ret; |
393 | ||
394 | if (!filter) | |
395 | return 0; | |
396 | ||
689a5f49 | 397 | ret = av_mallocz(sizeof(AVFilterContext)); |
4dbbcdee | 398 | |
b049ad50 | 399 | ret->av_class = &avfilter_class; |
4dbbcdee | 400 | ret->filter = filter; |
2350e69c | 401 | ret->name = inst_name ? av_strdup(inst_name) : NULL; |
4dbbcdee VS |
402 | ret->priv = av_mallocz(filter->priv_size); |
403 | ||
7d0e1392 | 404 | ret->input_count = pad_count(filter->inputs); |
689a5f49 | 405 | if (ret->input_count) { |
90993b38 SS |
406 | ret->input_pads = av_malloc(sizeof(AVFilterPad) * ret->input_count); |
407 | memcpy(ret->input_pads, filter->inputs, sizeof(AVFilterPad) * ret->input_count); | |
408 | ret->inputs = av_mallocz(sizeof(AVFilterLink*) * ret->input_count); | |
689a5f49 | 409 | } |
c5ef7d7b | 410 | |
7d0e1392 | 411 | ret->output_count = pad_count(filter->outputs); |
689a5f49 | 412 | if (ret->output_count) { |
90993b38 SS |
413 | ret->output_pads = av_malloc(sizeof(AVFilterPad) * ret->output_count); |
414 | memcpy(ret->output_pads, filter->outputs, sizeof(AVFilterPad) * ret->output_count); | |
415 | ret->outputs = av_mallocz(sizeof(AVFilterLink*) * ret->output_count); | |
689a5f49 | 416 | } |
7d0e1392 | 417 | |
4dbbcdee VS |
418 | return ret; |
419 | } | |
420 | ||
421 | void avfilter_destroy(AVFilterContext *filter) | |
422 | { | |
423 | int i; | |
424 | ||
425 | if(filter->filter->uninit) | |
426 | filter->filter->uninit(filter); | |
427 | ||
c5ef7d7b | 428 | for(i = 0; i < filter->input_count; i ++) { |
4dbbcdee VS |
429 | if(filter->inputs[i]) |
430 | filter->inputs[i]->src->outputs[filter->inputs[i]->srcpad] = NULL; | |
f4cb4462 | 431 | av_freep(&filter->inputs[i]); |
4dbbcdee | 432 | } |
c5ef7d7b | 433 | for(i = 0; i < filter->output_count; i ++) { |
4dbbcdee VS |
434 | if(filter->outputs[i]) |
435 | filter->outputs[i]->dst->inputs[filter->outputs[i]->dstpad] = NULL; | |
f4cb4462 | 436 | av_freep(&filter->outputs[i]); |
4dbbcdee VS |
437 | } |
438 | ||
f4cb4462 VS |
439 | av_freep(&filter->name); |
440 | av_freep(&filter->input_pads); | |
441 | av_freep(&filter->output_pads); | |
442 | av_freep(&filter->inputs); | |
443 | av_freep(&filter->outputs); | |
444 | av_freep(&filter->priv); | |
4dbbcdee VS |
445 | av_free(filter); |
446 | } | |
447 | ||
a360f71e | 448 | int avfilter_init_filter(AVFilterContext *filter, const char *args, void *opaque) |
4dbbcdee | 449 | { |
e079d22e | 450 | int ret=0; |
4dbbcdee VS |
451 | |
452 | if(filter->filter->init) | |
e079d22e VS |
453 | ret = filter->filter->init(filter, args, opaque); |
454 | return ret; | |
4dbbcdee VS |
455 | } |
456 |