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 | ||
22 | #include <stdlib.h> | |
23 | #include <string.h> | |
24 | #include <stdio.h> | |
25 | ||
26 | #include "avfilter.h" | |
d72a138e | 27 | #include "allfilters.h" |
4dbbcdee VS |
28 | |
29 | /** list of registered filters, sorted by name */ | |
30 | static int filter_count = 0; | |
31 | static AVFilter **filters = NULL; | |
32 | ||
33 | /* TODO: buffer pool. see comment for avfilter_default_get_video_buffer() */ | |
34 | void avfilter_default_free_video_buffer(AVFilterPic *pic) | |
35 | { | |
36 | avpicture_free((AVPicture *) pic); | |
37 | av_free(pic); | |
38 | } | |
39 | ||
40 | /* TODO: set the buffer's priv member to a context structure for the whole | |
41 | * filter chain. This will allow for a buffer pool instead of the constant | |
42 | * alloc & free cycle currently implemented. */ | |
43 | AVFilterPicRef *avfilter_default_get_video_buffer(AVFilterLink *link, int perms) | |
44 | { | |
45 | AVFilterPic *pic = av_mallocz(sizeof(AVFilterPic)); | |
46 | AVFilterPicRef *ref = av_mallocz(sizeof(AVFilterPicRef)); | |
47 | ||
48 | ref->pic = pic; | |
49 | ref->w = link->w; | |
50 | ref->h = link->h; | |
51 | ref->perms = perms; | |
52 | ||
53 | pic->refcount = 1; | |
54 | pic->format = link->format; | |
55 | pic->free = avfilter_default_free_video_buffer; | |
56 | avpicture_alloc((AVPicture *)pic, pic->format, ref->w, ref->h); | |
57 | ||
58a9b20f | 58 | memcpy(ref->data, pic->data, sizeof(int *) * 4); |
c74032b7 | 59 | memcpy(ref->linesize, pic->linesize, sizeof(int *) * 4); |
4dbbcdee VS |
60 | |
61 | return ref; | |
62 | } | |
63 | ||
64 | void avfilter_default_start_frame(AVFilterLink *link, AVFilterPicRef *picref) | |
65 | { | |
66 | link->cur_pic = picref; | |
67 | } | |
68 | ||
69 | void avfilter_default_end_frame(AVFilterLink *link) | |
70 | { | |
71 | avfilter_unref_pic(link->cur_pic); | |
72 | link->cur_pic = NULL; | |
73 | } | |
74 | ||
75 | AVFilterPicRef *avfilter_ref_pic(AVFilterPicRef *ref) | |
76 | { | |
77 | AVFilterPicRef *ret = av_malloc(sizeof(AVFilterPicRef)); | |
78 | memcpy(ret, ref, sizeof(AVFilterPicRef)); | |
79 | ret->pic->refcount ++; | |
80 | return ret; | |
81 | } | |
82 | ||
83 | void avfilter_unref_pic(AVFilterPicRef *ref) | |
84 | { | |
85 | if(-- ref->pic->refcount == 0) | |
86 | ref->pic->free(ref->pic); | |
87 | av_free(ref); | |
88 | } | |
89 | ||
90 | int avfilter_link(AVFilterContext *src, unsigned srcpad, | |
91 | AVFilterContext *dst, unsigned dstpad) | |
92 | { | |
93 | AVFilterLink *link; | |
94 | ||
95 | if(src->outputs[srcpad] || dst->inputs[dstpad]) | |
96 | return -1; | |
97 | ||
98 | src->outputs[srcpad] = | |
99 | dst->inputs[dstpad] = link = av_malloc(sizeof(AVFilterLink)); | |
100 | ||
101 | link->src = src; | |
102 | link->dst = dst; | |
103 | link->srcpad = srcpad; | |
104 | link->dstpad = dstpad; | |
105 | link->cur_pic = NULL; | |
106 | ||
107 | src->filter->outputs[dstpad].set_video_props(link); | |
108 | return 0; | |
109 | } | |
110 | ||
111 | AVFilterPicRef *avfilter_get_video_buffer(AVFilterLink *link, int perms) | |
112 | { | |
113 | AVFilterPicRef *ret = NULL; | |
114 | ||
115 | if(link->dst->filter->inputs[link->dstpad].get_video_buffer) | |
116 | ret = link->dst->filter->inputs[link->dstpad].get_video_buffer(link, perms); | |
117 | ||
118 | if(!ret) | |
119 | ret = avfilter_default_get_video_buffer(link, perms); | |
120 | ||
121 | return ret; | |
122 | } | |
123 | ||
124 | void avfilter_request_frame(AVFilterLink *link) | |
125 | { | |
126 | link->src->filter->outputs[link->srcpad].request_frame(link); | |
127 | } | |
128 | ||
129 | /* XXX: should we do the duplicating of the picture ref here, instead of | |
130 | * forcing the source filter to do it? */ | |
131 | void avfilter_start_frame(AVFilterLink *link, AVFilterPicRef *picref) | |
132 | { | |
133 | void (*start_frame)(AVFilterLink *, AVFilterPicRef *); | |
134 | ||
135 | start_frame = link->dst->filter->inputs[link->dstpad].start_frame; | |
136 | if(!start_frame) | |
137 | start_frame = avfilter_default_start_frame; | |
138 | ||
139 | start_frame(link, picref); | |
140 | } | |
141 | ||
142 | void avfilter_end_frame(AVFilterLink *link) | |
143 | { | |
144 | void (*end_frame)(AVFilterLink *); | |
145 | ||
146 | end_frame = link->dst->filter->inputs[link->dstpad].end_frame; | |
147 | if(!end_frame) | |
148 | end_frame = avfilter_default_end_frame; | |
149 | ||
150 | end_frame(link); | |
151 | } | |
152 | ||
153 | void avfilter_draw_slice(AVFilterLink *link, uint8_t *data[4], int y, int h) | |
154 | { | |
155 | link->dst->filter->inputs[link->dstpad].draw_slice(link, data, y, h); | |
156 | } | |
157 | ||
158 | static int filter_cmp(const void *aa, const void *bb) | |
159 | { | |
160 | const AVFilter *a = *(const AVFilter **)aa, *b = *(const AVFilter **)bb; | |
161 | return strcmp(a->name, b->name); | |
162 | } | |
163 | ||
164 | AVFilter *avfilter_get_by_name(char *name) | |
165 | { | |
166 | AVFilter key = { .name = name, }; | |
167 | AVFilter *key2 = &key; | |
168 | AVFilter **ret; | |
169 | ||
170 | ret = bsearch(&key2, filters, filter_count, sizeof(AVFilter **), filter_cmp); | |
171 | if(ret) | |
172 | return *ret; | |
173 | return NULL; | |
174 | } | |
175 | ||
176 | /* FIXME: insert in order, rather than insert at end + resort */ | |
177 | void avfilter_register(AVFilter *filter) | |
178 | { | |
179 | filters = av_realloc(filters, sizeof(AVFilter*) * (filter_count+1)); | |
180 | filters[filter_count] = filter; | |
181 | qsort(filters, ++filter_count, sizeof(AVFilter **), filter_cmp); | |
182 | } | |
183 | ||
184 | void avfilter_init(void) | |
185 | { | |
d72a138e VS |
186 | avfilter_register(&vsrc_dummy); |
187 | avfilter_register(&vf_crop); | |
188 | avfilter_register(&vf_passthrough); | |
189 | avfilter_register(&vo_sdl); | |
4dbbcdee VS |
190 | } |
191 | ||
192 | void avfilter_uninit(void) | |
193 | { | |
194 | av_freep(&filters); | |
195 | filter_count = 0; | |
196 | } | |
197 | ||
198 | static int pad_count(const AVFilterPad *pads) | |
199 | { | |
200 | AVFilterPad *p = (AVFilterPad *) pads; | |
201 | int count; | |
202 | ||
203 | for(count = 0; p->name; count ++) p ++; | |
204 | return count; | |
205 | } | |
206 | ||
207 | static const char *filter_name(void *p) | |
208 | { | |
209 | AVFilterContext *filter = p; | |
210 | return filter->filter->name; | |
211 | } | |
212 | ||
213 | AVFilterContext *avfilter_create(AVFilter *filter) | |
214 | { | |
215 | AVFilterContext *ret = av_malloc(sizeof(AVFilterContext)); | |
216 | ||
217 | ret->av_class = av_mallocz(sizeof(AVClass)); | |
218 | ret->av_class->item_name = filter_name; | |
219 | ret->filter = filter; | |
220 | ret->inputs = av_mallocz(sizeof(AVFilterLink*) * pad_count(filter->inputs)); | |
221 | ret->outputs = av_mallocz(sizeof(AVFilterLink*) * pad_count(filter->outputs)); | |
222 | ret->priv = av_mallocz(filter->priv_size); | |
223 | ||
224 | return ret; | |
225 | } | |
226 | ||
227 | void avfilter_destroy(AVFilterContext *filter) | |
228 | { | |
229 | int i; | |
230 | ||
231 | if(filter->filter->uninit) | |
232 | filter->filter->uninit(filter); | |
233 | ||
234 | for(i = 0; i < pad_count(filter->filter->inputs); i ++) { | |
235 | if(filter->inputs[i]) | |
236 | filter->inputs[i]->src->outputs[filter->inputs[i]->srcpad] = NULL; | |
237 | av_free(filter->inputs[i]); | |
238 | } | |
239 | for(i = 0; i < pad_count(filter->filter->outputs); i ++) { | |
240 | if(filter->outputs[i]) | |
241 | filter->outputs[i]->dst->inputs[filter->outputs[i]->dstpad] = NULL; | |
242 | av_free(filter->outputs[i]); | |
243 | } | |
244 | ||
245 | av_free(filter->inputs); | |
246 | av_free(filter->outputs); | |
247 | av_free(filter->priv); | |
248 | av_free(filter->av_class); | |
249 | av_free(filter); | |
250 | } | |
251 | ||
252 | AVFilterContext *avfilter_create_by_name(char *name) | |
253 | { | |
254 | AVFilter *filt; | |
255 | ||
256 | if(!(filt = avfilter_get_by_name(name))) return NULL; | |
257 | return avfilter_create(filt); | |
258 | } | |
259 | ||
260 | int avfilter_init_filter(AVFilterContext *filter) | |
261 | { | |
262 | int ret, i; | |
263 | ||
264 | if(filter->filter->init) | |
265 | if((ret = filter->filter->init(filter))) return ret; | |
266 | for(i = 0; i < pad_count(filter->filter->outputs); i ++) | |
267 | if(filter->outputs[i]) | |
268 | filter->filter->outputs[i].set_video_props(filter->outputs[i]); | |
269 | return 0; | |
270 | } | |
271 |