ffmpeg / libavfilter / avfilter.c @ efdc74ef
History | View | Annotate | Download (13.6 KB)
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 |
|
22 |
/* #define DEBUG */
|
23 |
|
24 |
#include "libavcodec/imgconvert.h" |
25 |
#include "libavutil/pixdesc.h" |
26 |
#include "avfilter.h" |
27 |
|
28 |
unsigned avfilter_version(void) { |
29 |
return LIBAVFILTER_VERSION_INT;
|
30 |
} |
31 |
|
32 |
const char *avfilter_configuration(void) |
33 |
{ |
34 |
return FFMPEG_CONFIGURATION;
|
35 |
} |
36 |
|
37 |
const char *avfilter_license(void) |
38 |
{ |
39 |
#define LICENSE_PREFIX "libavfilter license: " |
40 |
return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1; |
41 |
} |
42 |
|
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 |
|
47 |
AVFilterPicRef *avfilter_ref_pic(AVFilterPicRef *ref, int pmask)
|
48 |
{ |
49 |
AVFilterPicRef *ret = av_malloc(sizeof(AVFilterPicRef));
|
50 |
*ret = *ref; |
51 |
ret->perms &= pmask; |
52 |
ret->pic->refcount ++; |
53 |
return ret;
|
54 |
} |
55 |
|
56 |
void avfilter_unref_pic(AVFilterPicRef *ref)
|
57 |
{ |
58 |
if(!(--ref->pic->refcount))
|
59 |
ref->pic->free(ref->pic); |
60 |
av_free(ref); |
61 |
} |
62 |
|
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])
|
81 |
(*(unsigned *)((uint8_t *) *links[i] + padidx_off)) ++;
|
82 |
} |
83 |
|
84 |
int avfilter_link(AVFilterContext *src, unsigned srcpad, |
85 |
AVFilterContext *dst, unsigned dstpad)
|
86 |
{ |
87 |
AVFilterLink *link; |
88 |
|
89 |
if(src->output_count <= srcpad || dst->input_count <= dstpad ||
|
90 |
src->outputs[srcpad] || dst->inputs[dstpad]) |
91 |
return -1; |
92 |
|
93 |
src->outputs[srcpad] = |
94 |
dst-> inputs[dstpad] = link = av_mallocz(sizeof(AVFilterLink));
|
95 |
|
96 |
link->src = src; |
97 |
link->dst = dst; |
98 |
link->srcpad = srcpad; |
99 |
link->dstpad = dstpad; |
100 |
link->format = PIX_FMT_NONE; |
101 |
|
102 |
return 0; |
103 |
} |
104 |
|
105 |
int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt,
|
106 |
unsigned in, unsigned out) |
107 |
{ |
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); |
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 |
|
124 |
/* if any information on supported colorspaces already exists on the
|
125 |
* link, we need to preserve that */
|
126 |
if(link->out_formats)
|
127 |
avfilter_formats_changeref(&link->out_formats, |
128 |
&filt->outputs[out]->out_formats); |
129 |
|
130 |
return 0; |
131 |
} |
132 |
|
133 |
int avfilter_config_links(AVFilterContext *filter)
|
134 |
{ |
135 |
int (*config_link)(AVFilterLink *);
|
136 |
unsigned i;
|
137 |
|
138 |
for(i = 0; i < filter->input_count; i ++) { |
139 |
AVFilterLink *link = filter->inputs[i]; |
140 |
|
141 |
if(!link) continue; |
142 |
|
143 |
switch(link->init_state) {
|
144 |
case AVLINK_INIT:
|
145 |
continue;
|
146 |
case AVLINK_STARTINIT:
|
147 |
av_log(filter, AV_LOG_INFO, "circular filter chain detected\n");
|
148 |
return 0; |
149 |
case AVLINK_UNINIT:
|
150 |
link->init_state = AVLINK_STARTINIT; |
151 |
|
152 |
if(avfilter_config_links(link->src))
|
153 |
return -1; |
154 |
|
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; |
159 |
|
160 |
if((config_link = link_dpad(link).config_props))
|
161 |
if(config_link(link))
|
162 |
return -1; |
163 |
|
164 |
link->init_state = AVLINK_INIT; |
165 |
} |
166 |
} |
167 |
|
168 |
return 0; |
169 |
} |
170 |
|
171 |
static void dprintf_picref(void *ctx, AVFilterPicRef *picref, int end) |
172 |
{ |
173 |
dprintf(ctx, |
174 |
"picref[%p data[%p, %p, %p, %p] linesize[%d, %d, %d, %d] pts:%"PRId64" pos:%"PRId64" a:%d/%d s:%dx%d]%s", |
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], |
178 |
picref->pts, picref->pos, |
179 |
picref->pixel_aspect.num, picref->pixel_aspect.den, picref->w, picref->h, |
180 |
end ? "\n" : ""); |
181 |
} |
182 |
|
183 |
static void dprintf_link(void *ctx, AVFilterLink *link, int end) |
184 |
{ |
185 |
dprintf(ctx, |
186 |
"link[%p s:%dx%d fmt:%-16s %-16s->%-16s]%s",
|
187 |
link, link->w, link->h, |
188 |
av_pix_fmt_descriptors[link->format].name, |
189 |
link->src ? link->src->filter->name : "",
|
190 |
link->dst ? link->dst->filter->name : "",
|
191 |
end ? "\n" : ""); |
192 |
} |
193 |
|
194 |
#define DPRINTF_START(ctx, func) dprintf(NULL, "%-16s: ", #func) |
195 |
|
196 |
AVFilterPicRef *avfilter_get_video_buffer(AVFilterLink *link, int perms, int w, int h) |
197 |
{ |
198 |
AVFilterPicRef *ret = NULL;
|
199 |
|
200 |
DPRINTF_START(NULL, get_video_buffer); dprintf_link(NULL, link, 0); dprintf(NULL, " perms:%d w:%d h:%d\n", perms, w, h); |
201 |
|
202 |
if(link_dpad(link).get_video_buffer)
|
203 |
ret = link_dpad(link).get_video_buffer(link, perms, w, h); |
204 |
|
205 |
if(!ret)
|
206 |
ret = avfilter_default_get_video_buffer(link, perms, w, h); |
207 |
|
208 |
DPRINTF_START(NULL, get_video_buffer); dprintf_link(NULL, link, 0); dprintf(NULL, " returning "); dprintf_picref(NULL, ret, 1); |
209 |
|
210 |
return ret;
|
211 |
} |
212 |
|
213 |
int avfilter_request_frame(AVFilterLink *link)
|
214 |
{ |
215 |
DPRINTF_START(NULL, request_frame); dprintf_link(NULL, link, 1); |
216 |
|
217 |
if(link_spad(link).request_frame)
|
218 |
return link_spad(link).request_frame(link);
|
219 |
else if(link->src->inputs[0]) |
220 |
return avfilter_request_frame(link->src->inputs[0]); |
221 |
else return -1; |
222 |
} |
223 |
|
224 |
int avfilter_poll_frame(AVFilterLink *link)
|
225 |
{ |
226 |
int i, min=INT_MAX;
|
227 |
|
228 |
if(link_spad(link).poll_frame)
|
229 |
return link_spad(link).poll_frame(link);
|
230 |
|
231 |
for (i=0; i<link->src->input_count; i++) { |
232 |
int val;
|
233 |
if(!link->src->inputs[i])
|
234 |
return -1; |
235 |
val = avfilter_poll_frame(link->src->inputs[i]); |
236 |
min = FFMIN(min, val); |
237 |
} |
238 |
|
239 |
return min;
|
240 |
} |
241 |
|
242 |
/* XXX: should we do the duplicating of the picture ref here, instead of
|
243 |
* forcing the source filter to do it? */
|
244 |
void avfilter_start_frame(AVFilterLink *link, AVFilterPicRef *picref)
|
245 |
{ |
246 |
void (*start_frame)(AVFilterLink *, AVFilterPicRef *);
|
247 |
AVFilterPad *dst = &link_dpad(link); |
248 |
|
249 |
DPRINTF_START(NULL, start_frame); dprintf_link(NULL, link, 0); dprintf(NULL, " "); dprintf_picref(NULL, picref, 1); |
250 |
|
251 |
if(!(start_frame = dst->start_frame))
|
252 |
start_frame = avfilter_default_start_frame; |
253 |
|
254 |
/* prepare to copy the picture if it has insufficient permissions */
|
255 |
if((dst->min_perms & picref->perms) != dst->min_perms ||
|
256 |
dst->rej_perms & picref->perms) { |
257 |
/*
|
258 |
av_log(link->dst, AV_LOG_INFO,
|
259 |
"frame copy needed (have perms %x, need %x, reject %x)\n",
|
260 |
picref->perms,
|
261 |
link_dpad(link).min_perms, link_dpad(link).rej_perms);
|
262 |
*/
|
263 |
|
264 |
link->cur_pic = avfilter_default_get_video_buffer(link, dst->min_perms, link->w, link->h); |
265 |
link->srcpic = picref; |
266 |
link->cur_pic->pts = link->srcpic->pts; |
267 |
link->cur_pic->pos = link->srcpic->pos; |
268 |
link->cur_pic->pixel_aspect = link->srcpic->pixel_aspect; |
269 |
link->cur_pic->interlaced = link->srcpic->interlaced; |
270 |
link->cur_pic->top_field_first = link->srcpic->top_field_first; |
271 |
} |
272 |
else
|
273 |
link->cur_pic = picref; |
274 |
|
275 |
start_frame(link, link->cur_pic); |
276 |
} |
277 |
|
278 |
void avfilter_end_frame(AVFilterLink *link)
|
279 |
{ |
280 |
void (*end_frame)(AVFilterLink *);
|
281 |
|
282 |
if(!(end_frame = link_dpad(link).end_frame))
|
283 |
end_frame = avfilter_default_end_frame; |
284 |
|
285 |
end_frame(link); |
286 |
|
287 |
/* unreference the source picture if we're feeding the destination filter
|
288 |
* a copied version dues to permission issues */
|
289 |
if(link->srcpic) {
|
290 |
avfilter_unref_pic(link->srcpic); |
291 |
link->srcpic = NULL;
|
292 |
} |
293 |
|
294 |
} |
295 |
|
296 |
void avfilter_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) |
297 |
{ |
298 |
uint8_t *src[4], *dst[4]; |
299 |
int i, j, vsub;
|
300 |
void (*draw_slice)(AVFilterLink *, int, int, int); |
301 |
|
302 |
DPRINTF_START(NULL, draw_slice); dprintf_link(NULL, link, 0); dprintf(NULL, " y:%d h:%d dir:%d\n", y, h, slice_dir); |
303 |
|
304 |
/* copy the slice if needed for permission reasons */
|
305 |
if(link->srcpic) {
|
306 |
vsub = av_pix_fmt_descriptors[link->format].log2_chroma_h; |
307 |
|
308 |
for(i = 0; i < 4; i ++) { |
309 |
if(link->srcpic->data[i]) {
|
310 |
src[i] = link->srcpic-> data[i] + |
311 |
(y >> (i==0 ? 0 : vsub)) * link->srcpic-> linesize[i]; |
312 |
dst[i] = link->cur_pic->data[i] + |
313 |
(y >> (i==0 ? 0 : vsub)) * link->cur_pic->linesize[i]; |
314 |
} else
|
315 |
src[i] = dst[i] = NULL;
|
316 |
} |
317 |
|
318 |
for(i = 0; i < 4; i ++) { |
319 |
int planew =
|
320 |
ff_get_plane_bytewidth(link->format, link->cur_pic->w, i); |
321 |
|
322 |
if(!src[i]) continue; |
323 |
|
324 |
for(j = 0; j < h >> (i==0 ? 0 : vsub); j ++) { |
325 |
memcpy(dst[i], src[i], planew); |
326 |
src[i] += link->srcpic ->linesize[i]; |
327 |
dst[i] += link->cur_pic->linesize[i]; |
328 |
} |
329 |
} |
330 |
} |
331 |
|
332 |
if(!(draw_slice = link_dpad(link).draw_slice))
|
333 |
draw_slice = avfilter_default_draw_slice; |
334 |
draw_slice(link, y, h, slice_dir); |
335 |
} |
336 |
|
337 |
#define MAX_REGISTERED_AVFILTERS_NB 64 |
338 |
|
339 |
static AVFilter *registered_avfilters[MAX_REGISTERED_AVFILTERS_NB + 1]; |
340 |
|
341 |
static int next_registered_avfilter_idx = 0; |
342 |
|
343 |
AVFilter *avfilter_get_by_name(const char *name) |
344 |
{ |
345 |
int i;
|
346 |
|
347 |
for (i = 0; registered_avfilters[i]; i++) |
348 |
if (!strcmp(registered_avfilters[i]->name, name))
|
349 |
return registered_avfilters[i];
|
350 |
|
351 |
return NULL; |
352 |
} |
353 |
|
354 |
int avfilter_register(AVFilter *filter)
|
355 |
{ |
356 |
if (next_registered_avfilter_idx == MAX_REGISTERED_AVFILTERS_NB)
|
357 |
return -1; |
358 |
|
359 |
registered_avfilters[next_registered_avfilter_idx++] = filter; |
360 |
return 0; |
361 |
} |
362 |
|
363 |
AVFilter **av_filter_next(AVFilter **filter) |
364 |
{ |
365 |
return filter ? ++filter : ®istered_avfilters[0]; |
366 |
} |
367 |
|
368 |
void avfilter_uninit(void) |
369 |
{ |
370 |
memset(registered_avfilters, 0, sizeof(registered_avfilters)); |
371 |
next_registered_avfilter_idx = 0;
|
372 |
} |
373 |
|
374 |
static int pad_count(const AVFilterPad *pads) |
375 |
{ |
376 |
int count;
|
377 |
|
378 |
for(count = 0; pads->name; count ++) pads ++; |
379 |
return count;
|
380 |
} |
381 |
|
382 |
static const char *filter_name(void *p) |
383 |
{ |
384 |
AVFilterContext *filter = p; |
385 |
return filter->filter->name;
|
386 |
} |
387 |
|
388 |
static const AVClass avfilter_class = { |
389 |
"AVFilter",
|
390 |
filter_name, |
391 |
NULL,
|
392 |
LIBAVUTIL_VERSION_INT, |
393 |
}; |
394 |
|
395 |
AVFilterContext *avfilter_open(AVFilter *filter, const char *inst_name) |
396 |
{ |
397 |
AVFilterContext *ret; |
398 |
|
399 |
if (!filter)
|
400 |
return 0; |
401 |
|
402 |
ret = av_mallocz(sizeof(AVFilterContext));
|
403 |
|
404 |
ret->av_class = &avfilter_class; |
405 |
ret->filter = filter; |
406 |
ret->name = inst_name ? av_strdup(inst_name) : NULL;
|
407 |
ret->priv = av_mallocz(filter->priv_size); |
408 |
|
409 |
ret->input_count = pad_count(filter->inputs); |
410 |
if (ret->input_count) {
|
411 |
ret->input_pads = av_malloc(sizeof(AVFilterPad) * ret->input_count);
|
412 |
memcpy(ret->input_pads, filter->inputs, sizeof(AVFilterPad) * ret->input_count);
|
413 |
ret->inputs = av_mallocz(sizeof(AVFilterLink*) * ret->input_count);
|
414 |
} |
415 |
|
416 |
ret->output_count = pad_count(filter->outputs); |
417 |
if (ret->output_count) {
|
418 |
ret->output_pads = av_malloc(sizeof(AVFilterPad) * ret->output_count);
|
419 |
memcpy(ret->output_pads, filter->outputs, sizeof(AVFilterPad) * ret->output_count);
|
420 |
ret->outputs = av_mallocz(sizeof(AVFilterLink*) * ret->output_count);
|
421 |
} |
422 |
|
423 |
return ret;
|
424 |
} |
425 |
|
426 |
void avfilter_destroy(AVFilterContext *filter)
|
427 |
{ |
428 |
int i;
|
429 |
|
430 |
if(filter->filter->uninit)
|
431 |
filter->filter->uninit(filter); |
432 |
|
433 |
for(i = 0; i < filter->input_count; i ++) { |
434 |
if(filter->inputs[i])
|
435 |
filter->inputs[i]->src->outputs[filter->inputs[i]->srcpad] = NULL;
|
436 |
av_freep(&filter->inputs[i]); |
437 |
} |
438 |
for(i = 0; i < filter->output_count; i ++) { |
439 |
if(filter->outputs[i])
|
440 |
filter->outputs[i]->dst->inputs[filter->outputs[i]->dstpad] = NULL;
|
441 |
av_freep(&filter->outputs[i]); |
442 |
} |
443 |
|
444 |
av_freep(&filter->name); |
445 |
av_freep(&filter->input_pads); |
446 |
av_freep(&filter->output_pads); |
447 |
av_freep(&filter->inputs); |
448 |
av_freep(&filter->outputs); |
449 |
av_freep(&filter->priv); |
450 |
av_free(filter); |
451 |
} |
452 |
|
453 |
int avfilter_init_filter(AVFilterContext *filter, const char *args, void *opaque) |
454 |
{ |
455 |
int ret=0; |
456 |
|
457 |
if(filter->filter->init)
|
458 |
ret = filter->filter->init(filter, args, opaque); |
459 |
return ret;
|
460 |
} |
461 |
|