1 |
|
|
/* |
2 |
|
|
* Copyright (c) 2011 Stefano Sabatini |
3 |
|
|
* |
4 |
|
|
* This file is part of FFmpeg. |
5 |
|
|
* |
6 |
|
|
* FFmpeg is free software; you can redistribute it and/or |
7 |
|
|
* modify it under the terms of the GNU Lesser General Public |
8 |
|
|
* License as published by the Free Software Foundation; either |
9 |
|
|
* version 2.1 of the License, or (at your option) any later version. |
10 |
|
|
* |
11 |
|
|
* FFmpeg is distributed in the hope that it will be useful, |
12 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 |
|
|
* Lesser General Public License for more details. |
15 |
|
|
* |
16 |
|
|
* You should have received a copy of the GNU Lesser General Public |
17 |
|
|
* License along with FFmpeg; if not, write to the Free Software |
18 |
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 |
|
|
*/ |
20 |
|
|
|
21 |
|
|
/** |
22 |
|
|
* @file |
23 |
|
|
* buffer sink |
24 |
|
|
*/ |
25 |
|
|
|
26 |
|
|
#include "libavutil/avassert.h" |
27 |
|
|
#include "libavutil/channel_layout.h" |
28 |
|
|
#include "libavutil/common.h" |
29 |
|
|
#include "libavutil/internal.h" |
30 |
|
|
#include "libavutil/opt.h" |
31 |
|
|
|
32 |
|
|
#define FF_INTERNAL_FIELDS 1 |
33 |
|
|
#include "framequeue.h" |
34 |
|
|
|
35 |
|
|
#include "audio.h" |
36 |
|
|
#include "avfilter.h" |
37 |
|
|
#include "buffersink.h" |
38 |
|
|
#include "filters.h" |
39 |
|
|
#include "internal.h" |
40 |
|
|
|
41 |
|
|
typedef struct BufferSinkContext { |
42 |
|
|
const AVClass *class; |
43 |
|
|
unsigned warning_limit; |
44 |
|
|
|
45 |
|
|
/* only used for video */ |
46 |
|
|
enum AVPixelFormat *pixel_fmts; ///< list of accepted pixel formats, must be terminated with -1 |
47 |
|
|
int pixel_fmts_size; |
48 |
|
|
|
49 |
|
|
/* only used for audio */ |
50 |
|
|
enum AVSampleFormat *sample_fmts; ///< list of accepted sample formats, terminated by AV_SAMPLE_FMT_NONE |
51 |
|
|
int sample_fmts_size; |
52 |
|
|
int64_t *channel_layouts; ///< list of accepted channel layouts, terminated by -1 |
53 |
|
|
int channel_layouts_size; |
54 |
|
|
int *channel_counts; ///< list of accepted channel counts, terminated by -1 |
55 |
|
|
int channel_counts_size; |
56 |
|
|
int all_channel_counts; |
57 |
|
|
int *sample_rates; ///< list of accepted sample rates, terminated by -1 |
58 |
|
|
int sample_rates_size; |
59 |
|
|
|
60 |
|
|
AVFrame *peeked_frame; |
61 |
|
|
} BufferSinkContext; |
62 |
|
|
|
63 |
|
|
#define NB_ITEMS(list) (list ## _size / sizeof(*list)) |
64 |
|
|
|
65 |
|
1145 |
static void cleanup_redundant_layouts(AVFilterContext *ctx) |
66 |
|
|
{ |
67 |
|
1145 |
BufferSinkContext *buf = ctx->priv; |
68 |
|
1145 |
int nb_layouts = NB_ITEMS(buf->channel_layouts); |
69 |
|
1145 |
int nb_counts = NB_ITEMS(buf->channel_counts); |
70 |
|
1145 |
uint64_t counts = 0; |
71 |
|
|
int i, lc, n; |
72 |
|
|
|
73 |
✗✓ |
1145 |
for (i = 0; i < nb_counts; i++) |
74 |
|
|
if (buf->channel_counts[i] < 64) |
75 |
|
|
counts |= (uint64_t)1 << buf->channel_counts[i]; |
76 |
✗✓ |
1145 |
for (i = lc = 0; i < nb_layouts; i++) { |
77 |
|
|
n = av_get_channel_layout_nb_channels(buf->channel_layouts[i]); |
78 |
|
|
if (n < 64 && (counts & ((uint64_t)1 << n))) |
79 |
|
|
av_log(ctx, AV_LOG_WARNING, |
80 |
|
|
"Removing channel layout 0x%"PRIx64", redundant with %d channels\n", |
81 |
|
|
buf->channel_layouts[i], n); |
82 |
|
|
else |
83 |
|
|
buf->channel_layouts[lc++] = buf->channel_layouts[i]; |
84 |
|
|
} |
85 |
|
1145 |
buf->channel_layouts_size = lc * sizeof(*buf->channel_layouts); |
86 |
|
1145 |
} |
87 |
|
|
|
88 |
|
|
int attribute_align_arg av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame) |
89 |
|
|
{ |
90 |
|
|
return av_buffersink_get_frame_flags(ctx, frame, 0); |
91 |
|
|
} |
92 |
|
|
|
93 |
|
421737 |
static int return_or_keep_frame(BufferSinkContext *buf, AVFrame *out, AVFrame *in, int flags) |
94 |
|
|
{ |
95 |
✓✓ |
421737 |
if ((flags & AV_BUFFERSINK_FLAG_PEEK)) { |
96 |
|
11402 |
buf->peeked_frame = in; |
97 |
✓✓ |
11402 |
return out ? av_frame_ref(out, in) : 0; |
98 |
|
|
} else { |
99 |
|
|
av_assert1(out); |
100 |
|
410335 |
buf->peeked_frame = NULL; |
101 |
|
410335 |
av_frame_move_ref(out, in); |
102 |
|
410335 |
av_frame_free(&in); |
103 |
|
410335 |
return 0; |
104 |
|
|
} |
105 |
|
|
} |
106 |
|
|
|
107 |
|
1164453 |
static int get_frame_internal(AVFilterContext *ctx, AVFrame *frame, int flags, int samples) |
108 |
|
|
{ |
109 |
|
1164453 |
BufferSinkContext *buf = ctx->priv; |
110 |
|
1164453 |
AVFilterLink *inlink = ctx->inputs[0]; |
111 |
|
|
int status, ret; |
112 |
|
|
AVFrame *cur_frame; |
113 |
|
|
int64_t pts; |
114 |
|
|
|
115 |
✓✓ |
1164453 |
if (buf->peeked_frame) |
116 |
|
11402 |
return return_or_keep_frame(buf, frame, buf->peeked_frame, flags); |
117 |
|
|
|
118 |
|
|
while (1) { |
119 |
✓✓ |
2434668 |
ret = samples ? ff_inlink_consume_samples(inlink, samples, samples, &cur_frame) : |
120 |
|
2134198 |
ff_inlink_consume_frame(inlink, &cur_frame); |
121 |
✗✓ |
2434668 |
if (ret < 0) { |
122 |
|
|
return ret; |
123 |
✓✓ |
2434668 |
} else if (ret) { |
124 |
|
|
/* TODO return the frame instead of copying it */ |
125 |
|
410335 |
return return_or_keep_frame(buf, frame, cur_frame, flags); |
126 |
✓✓ |
2024333 |
} else if (ff_inlink_acknowledge_status(inlink, &status, &pts)) { |
127 |
|
7517 |
return status; |
128 |
✓✓ |
2016816 |
} else if ((flags & AV_BUFFERSINK_FLAG_NO_REQUEST)) { |
129 |
|
374152 |
return AVERROR(EAGAIN); |
130 |
✓✓ |
1642664 |
} else if (inlink->frame_wanted_out) { |
131 |
|
1285514 |
ret = ff_filter_graph_run_once(ctx->graph); |
132 |
✓✓ |
1285514 |
if (ret < 0) |
133 |
|
361047 |
return ret; |
134 |
|
|
} else { |
135 |
|
357150 |
ff_inlink_request_frame(inlink); |
136 |
|
|
} |
137 |
|
|
} |
138 |
|
|
} |
139 |
|
|
|
140 |
|
1164453 |
int attribute_align_arg av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flags) |
141 |
|
|
{ |
142 |
|
1164453 |
return get_frame_internal(ctx, frame, flags, ctx->inputs[0]->min_samples); |
143 |
|
|
} |
144 |
|
|
|
145 |
|
|
int attribute_align_arg av_buffersink_get_samples(AVFilterContext *ctx, |
146 |
|
|
AVFrame *frame, int nb_samples) |
147 |
|
|
{ |
148 |
|
|
return get_frame_internal(ctx, frame, 0, nb_samples); |
149 |
|
|
} |
150 |
|
|
|
151 |
|
|
#if FF_API_BUFFERSINK_ALLOC |
152 |
|
|
AVBufferSinkParams *av_buffersink_params_alloc(void) |
153 |
|
|
{ |
154 |
|
|
static const int pixel_fmts[] = { AV_PIX_FMT_NONE }; |
155 |
|
|
AVBufferSinkParams *params = av_malloc(sizeof(AVBufferSinkParams)); |
156 |
|
|
if (!params) |
157 |
|
|
return NULL; |
158 |
|
|
|
159 |
|
|
params->pixel_fmts = pixel_fmts; |
160 |
|
|
return params; |
161 |
|
|
} |
162 |
|
|
|
163 |
|
|
AVABufferSinkParams *av_abuffersink_params_alloc(void) |
164 |
|
|
{ |
165 |
|
|
AVABufferSinkParams *params = av_mallocz(sizeof(AVABufferSinkParams)); |
166 |
|
|
|
167 |
|
|
if (!params) |
168 |
|
|
return NULL; |
169 |
|
|
return params; |
170 |
|
|
} |
171 |
|
|
#endif |
172 |
|
|
|
173 |
|
5886 |
static av_cold int common_init(AVFilterContext *ctx) |
174 |
|
|
{ |
175 |
|
5886 |
BufferSinkContext *buf = ctx->priv; |
176 |
|
|
|
177 |
|
5886 |
buf->warning_limit = 100; |
178 |
|
5886 |
return 0; |
179 |
|
|
} |
180 |
|
|
|
181 |
|
395722 |
static int activate(AVFilterContext *ctx) |
182 |
|
|
{ |
183 |
|
395722 |
BufferSinkContext *buf = ctx->priv; |
184 |
|
|
|
185 |
✓✗ |
395722 |
if (buf->warning_limit && |
186 |
✓✓ |
395722 |
ff_framequeue_queued_frames(&ctx->inputs[0]->fifo) >= buf->warning_limit) { |
187 |
|
5 |
av_log(ctx, AV_LOG_WARNING, |
188 |
|
|
"%d buffers queued in %s, something may be wrong.\n", |
189 |
|
|
buf->warning_limit, |
190 |
|
5 |
(char *)av_x_if_null(ctx->name, ctx->filter->name)); |
191 |
|
5 |
buf->warning_limit *= 10; |
192 |
|
|
} |
193 |
|
|
|
194 |
|
|
/* The frame is queued, the rest is up to get_frame_internal */ |
195 |
|
395722 |
return 0; |
196 |
|
|
} |
197 |
|
|
|
198 |
|
202 |
void av_buffersink_set_frame_size(AVFilterContext *ctx, unsigned frame_size) |
199 |
|
|
{ |
200 |
|
202 |
AVFilterLink *inlink = ctx->inputs[0]; |
201 |
|
|
|
202 |
|
202 |
inlink->min_samples = inlink->max_samples = |
203 |
|
202 |
inlink->partial_buf_size = frame_size; |
204 |
|
202 |
} |
205 |
|
|
|
206 |
|
|
#define MAKE_AVFILTERLINK_ACCESSOR(type, field) \ |
207 |
|
|
type av_buffersink_get_##field(const AVFilterContext *ctx) { \ |
208 |
|
|
av_assert0(ctx->filter->activate == activate); \ |
209 |
|
|
return ctx->inputs[0]->field; \ |
210 |
|
|
} |
211 |
|
|
|
212 |
✗✓ |
1148433 |
MAKE_AVFILTERLINK_ACCESSOR(enum AVMediaType , type ) |
213 |
✗✓ |
410434 |
MAKE_AVFILTERLINK_ACCESSOR(AVRational , time_base ) |
214 |
✗✓ |
11741 |
MAKE_AVFILTERLINK_ACCESSOR(int , format ) |
215 |
|
|
|
216 |
✗✓ |
106753 |
MAKE_AVFILTERLINK_ACCESSOR(AVRational , frame_rate ) |
217 |
✗✓ |
10581 |
MAKE_AVFILTERLINK_ACCESSOR(int , w ) |
218 |
✗✓ |
10581 |
MAKE_AVFILTERLINK_ACCESSOR(int , h ) |
219 |
✗✓ |
4701 |
MAKE_AVFILTERLINK_ACCESSOR(AVRational , sample_aspect_ratio) |
220 |
|
|
|
221 |
✗✓ |
1144 |
MAKE_AVFILTERLINK_ACCESSOR(int , channels ) |
222 |
✗✓ |
6993 |
MAKE_AVFILTERLINK_ACCESSOR(uint64_t , channel_layout ) |
223 |
✗✓ |
6993 |
MAKE_AVFILTERLINK_ACCESSOR(int , sample_rate ) |
224 |
|
|
|
225 |
✗✓ |
5812 |
MAKE_AVFILTERLINK_ACCESSOR(AVBufferRef * , hw_frames_ctx ) |
226 |
|
|
|
227 |
|
|
#define CHECK_LIST_SIZE(field) \ |
228 |
|
|
if (buf->field ## _size % sizeof(*buf->field)) { \ |
229 |
|
|
av_log(ctx, AV_LOG_ERROR, "Invalid size for " #field ": %d, " \ |
230 |
|
|
"should be multiple of %d\n", \ |
231 |
|
|
buf->field ## _size, (int)sizeof(*buf->field)); \ |
232 |
|
|
return AVERROR(EINVAL); \ |
233 |
|
|
} |
234 |
|
4741 |
static int vsink_query_formats(AVFilterContext *ctx) |
235 |
|
|
{ |
236 |
|
4741 |
BufferSinkContext *buf = ctx->priv; |
237 |
|
4741 |
AVFilterFormats *formats = NULL; |
238 |
|
|
unsigned i; |
239 |
|
|
int ret; |
240 |
|
|
|
241 |
✗✓ |
4741 |
CHECK_LIST_SIZE(pixel_fmts) |
242 |
✓✓ |
4741 |
if (buf->pixel_fmts_size) { |
243 |
✓✓ |
3111 |
for (i = 0; i < NB_ITEMS(buf->pixel_fmts); i++) |
244 |
✗✓ |
3094 |
if ((ret = ff_add_format(&formats, buf->pixel_fmts[i])) < 0) |
245 |
|
|
return ret; |
246 |
✗✓ |
17 |
if ((ret = ff_set_common_formats(ctx, formats)) < 0) |
247 |
|
|
return ret; |
248 |
|
|
} else { |
249 |
✗✓ |
4724 |
if ((ret = ff_default_query_formats(ctx)) < 0) |
250 |
|
|
return ret; |
251 |
|
|
} |
252 |
|
|
|
253 |
|
4741 |
return 0; |
254 |
|
|
} |
255 |
|
|
|
256 |
|
1145 |
static int asink_query_formats(AVFilterContext *ctx) |
257 |
|
|
{ |
258 |
|
1145 |
BufferSinkContext *buf = ctx->priv; |
259 |
|
1145 |
AVFilterFormats *formats = NULL; |
260 |
|
1145 |
AVFilterChannelLayouts *layouts = NULL; |
261 |
|
|
unsigned i; |
262 |
|
|
int ret; |
263 |
|
|
|
264 |
✗✓ |
1145 |
CHECK_LIST_SIZE(sample_fmts) |
265 |
✗✓ |
1145 |
CHECK_LIST_SIZE(sample_rates) |
266 |
✗✓ |
1145 |
CHECK_LIST_SIZE(channel_layouts) |
267 |
✗✓ |
1145 |
CHECK_LIST_SIZE(channel_counts) |
268 |
|
|
|
269 |
✓✓ |
1145 |
if (buf->sample_fmts_size) { |
270 |
✓✓ |
96 |
for (i = 0; i < NB_ITEMS(buf->sample_fmts); i++) |
271 |
✗✓ |
80 |
if ((ret = ff_add_format(&formats, buf->sample_fmts[i])) < 0) |
272 |
|
|
return ret; |
273 |
✗✓ |
16 |
if ((ret = ff_set_common_formats(ctx, formats)) < 0) |
274 |
|
|
return ret; |
275 |
|
|
} |
276 |
|
|
|
277 |
✓✗✓✗
|
1145 |
if (buf->channel_layouts_size || buf->channel_counts_size || |
278 |
✓✗ |
1145 |
buf->all_channel_counts) { |
279 |
|
1145 |
cleanup_redundant_layouts(ctx); |
280 |
✗✓ |
1145 |
for (i = 0; i < NB_ITEMS(buf->channel_layouts); i++) |
281 |
|
|
if ((ret = ff_add_channel_layout(&layouts, buf->channel_layouts[i])) < 0) |
282 |
|
|
return ret; |
283 |
✗✓ |
1145 |
for (i = 0; i < NB_ITEMS(buf->channel_counts); i++) |
284 |
|
|
if ((ret = ff_add_channel_layout(&layouts, FF_COUNT2LAYOUT(buf->channel_counts[i]))) < 0) |
285 |
|
|
return ret; |
286 |
✓✗ |
1145 |
if (buf->all_channel_counts) { |
287 |
✗✓ |
1145 |
if (layouts) |
288 |
|
|
av_log(ctx, AV_LOG_WARNING, |
289 |
|
|
"Conflicting all_channel_counts and list in options\n"); |
290 |
✗✓ |
1145 |
else if (!(layouts = ff_all_channel_counts())) |
291 |
|
|
return AVERROR(ENOMEM); |
292 |
|
|
} |
293 |
✗✓ |
1145 |
if ((ret = ff_set_common_channel_layouts(ctx, layouts)) < 0) |
294 |
|
|
return ret; |
295 |
|
|
} |
296 |
|
|
|
297 |
✗✓ |
1145 |
if (buf->sample_rates_size) { |
298 |
|
|
formats = NULL; |
299 |
|
|
for (i = 0; i < NB_ITEMS(buf->sample_rates); i++) |
300 |
|
|
if ((ret = ff_add_format(&formats, buf->sample_rates[i])) < 0) |
301 |
|
|
return ret; |
302 |
|
|
if ((ret = ff_set_common_samplerates(ctx, formats)) < 0) |
303 |
|
|
return ret; |
304 |
|
|
} |
305 |
|
|
|
306 |
|
1145 |
return 0; |
307 |
|
|
} |
308 |
|
|
|
309 |
|
|
#define OFFSET(x) offsetof(BufferSinkContext, x) |
310 |
|
|
#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM |
311 |
|
|
static const AVOption buffersink_options[] = { |
312 |
|
|
{ "pix_fmts", "set the supported pixel formats", OFFSET(pixel_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS }, |
313 |
|
|
{ NULL }, |
314 |
|
|
}; |
315 |
|
|
#undef FLAGS |
316 |
|
|
#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_AUDIO_PARAM |
317 |
|
|
static const AVOption abuffersink_options[] = { |
318 |
|
|
{ "sample_fmts", "set the supported sample formats", OFFSET(sample_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS }, |
319 |
|
|
{ "sample_rates", "set the supported sample rates", OFFSET(sample_rates), AV_OPT_TYPE_BINARY, .flags = FLAGS }, |
320 |
|
|
{ "channel_layouts", "set the supported channel layouts", OFFSET(channel_layouts), AV_OPT_TYPE_BINARY, .flags = FLAGS }, |
321 |
|
|
{ "channel_counts", "set the supported channel counts", OFFSET(channel_counts), AV_OPT_TYPE_BINARY, .flags = FLAGS }, |
322 |
|
|
{ "all_channel_counts", "accept all channel counts", OFFSET(all_channel_counts), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS }, |
323 |
|
|
{ NULL }, |
324 |
|
|
}; |
325 |
|
|
#undef FLAGS |
326 |
|
|
|
327 |
|
|
AVFILTER_DEFINE_CLASS(buffersink); |
328 |
|
|
AVFILTER_DEFINE_CLASS(abuffersink); |
329 |
|
|
|
330 |
|
|
static const AVFilterPad avfilter_vsink_buffer_inputs[] = { |
331 |
|
|
{ |
332 |
|
|
.name = "default", |
333 |
|
|
.type = AVMEDIA_TYPE_VIDEO, |
334 |
|
|
}, |
335 |
|
|
{ NULL } |
336 |
|
|
}; |
337 |
|
|
|
338 |
|
|
AVFilter ff_vsink_buffer = { |
339 |
|
|
.name = "buffersink", |
340 |
|
|
.description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."), |
341 |
|
|
.priv_size = sizeof(BufferSinkContext), |
342 |
|
|
.priv_class = &buffersink_class, |
343 |
|
|
.init = common_init, |
344 |
|
|
.query_formats = vsink_query_formats, |
345 |
|
|
.activate = activate, |
346 |
|
|
.inputs = avfilter_vsink_buffer_inputs, |
347 |
|
|
.outputs = NULL, |
348 |
|
|
}; |
349 |
|
|
|
350 |
|
|
static const AVFilterPad avfilter_asink_abuffer_inputs[] = { |
351 |
|
|
{ |
352 |
|
|
.name = "default", |
353 |
|
|
.type = AVMEDIA_TYPE_AUDIO, |
354 |
|
|
}, |
355 |
|
|
{ NULL } |
356 |
|
|
}; |
357 |
|
|
|
358 |
|
|
AVFilter ff_asink_abuffer = { |
359 |
|
|
.name = "abuffersink", |
360 |
|
|
.description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."), |
361 |
|
|
.priv_class = &abuffersink_class, |
362 |
|
|
.priv_size = sizeof(BufferSinkContext), |
363 |
|
|
.init = common_init, |
364 |
|
|
.query_formats = asink_query_formats, |
365 |
|
|
.activate = activate, |
366 |
|
|
.inputs = avfilter_asink_abuffer_inputs, |
367 |
|
|
.outputs = NULL, |
368 |
|
|
}; |