ffmpeg / libavfilter / defaults.c @ d38c340f
History | View | Annotate | Download (10.3 KB)
1 |
/*
|
---|---|
2 |
* Filter layer - default implementations
|
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 "libavcore/audioconvert.h" |
23 |
#include "libavcore/imgutils.h" |
24 |
#include "libavcore/samplefmt.h" |
25 |
#include "avfilter.h" |
26 |
#include "internal.h" |
27 |
|
28 |
/* TODO: buffer pool. see comment for avfilter_default_get_video_buffer() */
|
29 |
void ff_avfilter_default_free_buffer(AVFilterBuffer *ptr)
|
30 |
{ |
31 |
av_free(ptr->data[0]);
|
32 |
av_free(ptr); |
33 |
} |
34 |
|
35 |
/* TODO: set the buffer's priv member to a context structure for the whole
|
36 |
* filter chain. This will allow for a buffer pool instead of the constant
|
37 |
* alloc & free cycle currently implemented. */
|
38 |
AVFilterBufferRef *avfilter_default_get_video_buffer(AVFilterLink *link, int perms, int w, int h) |
39 |
{ |
40 |
char *buf = NULL; |
41 |
int linesize[4], i, tempsize; |
42 |
uint8_t *data[4];
|
43 |
AVFilterBufferRef *picref = NULL;
|
44 |
|
45 |
av_image_fill_linesizes(linesize, link->format, w); |
46 |
for (i = 0; i < 4; i++) |
47 |
linesize[i] = FFALIGN(linesize[i], 16);
|
48 |
tempsize = av_image_fill_pointers(data, link->format, h, NULL, linesize);
|
49 |
buf = av_malloc(tempsize + 16); // +2 is needed for swscaler, +16 to be |
50 |
// SIMD-friendly
|
51 |
if (!buf)
|
52 |
return NULL; |
53 |
|
54 |
av_image_fill_pointers(data, link->format, h, buf, linesize); |
55 |
|
56 |
picref = avfilter_get_video_buffer_ref_from_arrays(data, linesize, |
57 |
perms, w, h, link->format); |
58 |
if (!picref) {
|
59 |
av_free(buf); |
60 |
return NULL; |
61 |
} |
62 |
|
63 |
return picref;
|
64 |
} |
65 |
|
66 |
AVFilterBufferRef *avfilter_default_get_audio_buffer(AVFilterLink *link, int perms,
|
67 |
enum AVSampleFormat sample_fmt, int size, |
68 |
int64_t channel_layout, int planar)
|
69 |
{ |
70 |
AVFilterBuffer *samples = av_mallocz(sizeof(AVFilterBuffer));
|
71 |
AVFilterBufferRef *ref = NULL;
|
72 |
int i, sample_size, chans_nb, bufsize, per_channel_size, step_size = 0; |
73 |
char *buf;
|
74 |
|
75 |
if (!samples || !(ref = av_mallocz(sizeof(AVFilterBufferRef)))) |
76 |
goto fail;
|
77 |
|
78 |
ref->buf = samples; |
79 |
ref->format = sample_fmt; |
80 |
|
81 |
ref->audio = av_mallocz(sizeof(AVFilterBufferRefAudioProps));
|
82 |
if (!ref->audio)
|
83 |
goto fail;
|
84 |
|
85 |
ref->audio->channel_layout = channel_layout; |
86 |
ref->audio->size = size; |
87 |
ref->audio->planar = planar; |
88 |
|
89 |
/* make sure the buffer gets read permission or it's useless for output */
|
90 |
ref->perms = perms | AV_PERM_READ; |
91 |
|
92 |
samples->refcount = 1;
|
93 |
samples->free = ff_avfilter_default_free_buffer; |
94 |
|
95 |
sample_size = av_get_bits_per_sample_fmt(sample_fmt) >>3;
|
96 |
chans_nb = av_get_channel_layout_nb_channels(channel_layout); |
97 |
|
98 |
per_channel_size = size/chans_nb; |
99 |
ref->audio->samples_nb = per_channel_size/sample_size; |
100 |
|
101 |
/* Set the number of bytes to traverse to reach next sample of a particular channel:
|
102 |
* For planar, this is simply the sample size.
|
103 |
* For packed, this is the number of samples * sample_size.
|
104 |
*/
|
105 |
for (i = 0; i < chans_nb; i++) |
106 |
samples->linesize[i] = planar > 0 ? per_channel_size : sample_size;
|
107 |
memset(&samples->linesize[chans_nb], 0, (8-chans_nb) * sizeof(samples->linesize[0])); |
108 |
|
109 |
/* Calculate total buffer size, round to multiple of 16 to be SIMD friendly */
|
110 |
bufsize = (size + 15)&~15; |
111 |
buf = av_malloc(bufsize); |
112 |
if (!buf)
|
113 |
goto fail;
|
114 |
|
115 |
/* For planar, set the start point of each channel's data within the buffer
|
116 |
* For packed, set the start point of the entire buffer only
|
117 |
*/
|
118 |
samples->data[0] = buf;
|
119 |
if (buf && planar) {
|
120 |
for (i = 1; i < chans_nb; i++) { |
121 |
step_size += per_channel_size; |
122 |
samples->data[i] = buf + step_size; |
123 |
} |
124 |
} else {
|
125 |
for (i = 1; i < chans_nb; i++) |
126 |
samples->data[i] = buf; |
127 |
} |
128 |
|
129 |
memset(&samples->data[chans_nb], 0, (8-chans_nb) * sizeof(samples->data[0])); |
130 |
|
131 |
memcpy(ref->data, samples->data, sizeof(ref->data));
|
132 |
memcpy(ref->linesize, samples->linesize, sizeof(ref->linesize));
|
133 |
|
134 |
return ref;
|
135 |
|
136 |
fail:
|
137 |
av_free(buf); |
138 |
if (ref && ref->audio)
|
139 |
av_free(ref->audio); |
140 |
av_free(ref); |
141 |
av_free(samples); |
142 |
return NULL; |
143 |
} |
144 |
|
145 |
void avfilter_default_start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
|
146 |
{ |
147 |
AVFilterLink *outlink = NULL;
|
148 |
|
149 |
if (inlink->dst->output_count)
|
150 |
outlink = inlink->dst->outputs[0];
|
151 |
|
152 |
if (outlink) {
|
153 |
outlink->out_buf = avfilter_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h); |
154 |
avfilter_copy_buffer_ref_props(outlink->out_buf, picref); |
155 |
avfilter_start_frame(outlink, avfilter_ref_buffer(outlink->out_buf, ~0));
|
156 |
} |
157 |
} |
158 |
|
159 |
void avfilter_default_draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) |
160 |
{ |
161 |
AVFilterLink *outlink = NULL;
|
162 |
|
163 |
if (inlink->dst->output_count)
|
164 |
outlink = inlink->dst->outputs[0];
|
165 |
|
166 |
if (outlink)
|
167 |
avfilter_draw_slice(outlink, y, h, slice_dir); |
168 |
} |
169 |
|
170 |
void avfilter_default_end_frame(AVFilterLink *inlink)
|
171 |
{ |
172 |
AVFilterLink *outlink = NULL;
|
173 |
|
174 |
if (inlink->dst->output_count)
|
175 |
outlink = inlink->dst->outputs[0];
|
176 |
|
177 |
avfilter_unref_buffer(inlink->cur_buf); |
178 |
inlink->cur_buf = NULL;
|
179 |
|
180 |
if (outlink) {
|
181 |
if (outlink->out_buf) {
|
182 |
avfilter_unref_buffer(outlink->out_buf); |
183 |
outlink->out_buf = NULL;
|
184 |
} |
185 |
avfilter_end_frame(outlink); |
186 |
} |
187 |
} |
188 |
|
189 |
/* FIXME: samplesref is same as link->cur_buf. Need to consider removing the redundant parameter. */
|
190 |
void avfilter_default_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *samplesref)
|
191 |
{ |
192 |
AVFilterLink *outlink = NULL;
|
193 |
|
194 |
if (inlink->dst->output_count)
|
195 |
outlink = inlink->dst->outputs[0];
|
196 |
|
197 |
if (outlink) {
|
198 |
outlink->out_buf = avfilter_default_get_audio_buffer(inlink, AV_PERM_WRITE, samplesref->format, |
199 |
samplesref->audio->size, |
200 |
samplesref->audio->channel_layout, |
201 |
samplesref->audio->planar); |
202 |
outlink->out_buf->pts = samplesref->pts; |
203 |
outlink->out_buf->audio->sample_rate = samplesref->audio->sample_rate; |
204 |
avfilter_filter_samples(outlink, avfilter_ref_buffer(outlink->out_buf, ~0));
|
205 |
avfilter_unref_buffer(outlink->out_buf); |
206 |
outlink->out_buf = NULL;
|
207 |
} |
208 |
avfilter_unref_buffer(samplesref); |
209 |
inlink->cur_buf = NULL;
|
210 |
} |
211 |
|
212 |
/**
|
213 |
* default config_link() implementation for output video links to simplify
|
214 |
* the implementation of one input one output video filters */
|
215 |
int avfilter_default_config_output_link(AVFilterLink *link)
|
216 |
{ |
217 |
if (link->src->input_count && link->src->inputs[0]) { |
218 |
if (link->type == AVMEDIA_TYPE_VIDEO) {
|
219 |
link->w = link->src->inputs[0]->w;
|
220 |
link->h = link->src->inputs[0]->h;
|
221 |
link->time_base = link->src->inputs[0]->time_base;
|
222 |
} else if (link->type == AVMEDIA_TYPE_AUDIO) { |
223 |
link->channel_layout = link->src->inputs[0]->channel_layout;
|
224 |
link->sample_rate = link->src->inputs[0]->sample_rate;
|
225 |
} |
226 |
} else {
|
227 |
/* XXX: any non-simple filter which would cause this branch to be taken
|
228 |
* really should implement its own config_props() for this link. */
|
229 |
return -1; |
230 |
} |
231 |
|
232 |
return 0; |
233 |
} |
234 |
|
235 |
/**
|
236 |
* A helper for query_formats() which sets all links to the same list of
|
237 |
* formats. If there are no links hooked to this filter, the list of formats is
|
238 |
* freed.
|
239 |
*
|
240 |
* FIXME: this will need changed for filters with a mix of pad types
|
241 |
* (video + audio, etc)
|
242 |
*/
|
243 |
void avfilter_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
|
244 |
{ |
245 |
int count = 0, i; |
246 |
|
247 |
for (i = 0; i < ctx->input_count; i++) { |
248 |
if (ctx->inputs[i]) {
|
249 |
avfilter_formats_ref(formats, &ctx->inputs[i]->out_formats); |
250 |
count++; |
251 |
} |
252 |
} |
253 |
for (i = 0; i < ctx->output_count; i++) { |
254 |
if (ctx->outputs[i]) {
|
255 |
avfilter_formats_ref(formats, &ctx->outputs[i]->in_formats); |
256 |
count++; |
257 |
} |
258 |
} |
259 |
|
260 |
if (!count) {
|
261 |
av_free(formats->formats); |
262 |
av_free(formats->refs); |
263 |
av_free(formats); |
264 |
} |
265 |
} |
266 |
|
267 |
int avfilter_default_query_formats(AVFilterContext *ctx)
|
268 |
{ |
269 |
enum AVMediaType type = ctx->inputs && ctx->inputs [0] ? ctx->inputs [0]->type : |
270 |
ctx->outputs && ctx->outputs[0] ? ctx->outputs[0]->type : |
271 |
AVMEDIA_TYPE_VIDEO; |
272 |
|
273 |
avfilter_set_common_formats(ctx, avfilter_all_formats(type)); |
274 |
return 0; |
275 |
} |
276 |
|
277 |
void avfilter_null_start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
|
278 |
{ |
279 |
avfilter_start_frame(link->dst->outputs[0], picref);
|
280 |
} |
281 |
|
282 |
void avfilter_null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) |
283 |
{ |
284 |
avfilter_draw_slice(link->dst->outputs[0], y, h, slice_dir);
|
285 |
} |
286 |
|
287 |
void avfilter_null_end_frame(AVFilterLink *link)
|
288 |
{ |
289 |
avfilter_end_frame(link->dst->outputs[0]);
|
290 |
} |
291 |
|
292 |
void avfilter_null_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref)
|
293 |
{ |
294 |
avfilter_filter_samples(link->dst->outputs[0], samplesref);
|
295 |
} |
296 |
|
297 |
AVFilterBufferRef *avfilter_null_get_video_buffer(AVFilterLink *link, int perms, int w, int h) |
298 |
{ |
299 |
return avfilter_get_video_buffer(link->dst->outputs[0], perms, w, h); |
300 |
} |
301 |
|
302 |
AVFilterBufferRef *avfilter_null_get_audio_buffer(AVFilterLink *link, int perms,
|
303 |
enum AVSampleFormat sample_fmt, int size, |
304 |
int64_t channel_layout, int packed)
|
305 |
{ |
306 |
return avfilter_get_audio_buffer(link->dst->outputs[0], perms, sample_fmt, |
307 |
size, channel_layout, packed); |
308 |
} |
309 |
|