Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4349 | Serge | 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/audio_fifo.h" |
||
27 | #include "libavutil/avassert.h" |
||
28 | #include "libavutil/channel_layout.h" |
||
29 | #include "libavutil/common.h" |
||
30 | #include "libavutil/internal.h" |
||
31 | #include "libavutil/mathematics.h" |
||
32 | #include "libavutil/opt.h" |
||
33 | |||
34 | #include "audio.h" |
||
35 | #include "avfilter.h" |
||
36 | #include "buffersink.h" |
||
37 | #include "internal.h" |
||
38 | |||
39 | typedef struct { |
||
40 | const AVClass *class; |
||
41 | AVFifoBuffer *fifo; ///< FIFO buffer of video frame references |
||
42 | unsigned warning_limit; |
||
43 | |||
44 | /* only used for video */ |
||
45 | enum AVPixelFormat *pixel_fmts; ///< list of accepted pixel formats, must be terminated with -1 |
||
46 | int pixel_fmts_size; |
||
47 | |||
48 | /* only used for audio */ |
||
49 | enum AVSampleFormat *sample_fmts; ///< list of accepted sample formats, terminated by AV_SAMPLE_FMT_NONE |
||
50 | int sample_fmts_size; |
||
51 | int64_t *channel_layouts; ///< list of accepted channel layouts, terminated by -1 |
||
52 | int channel_layouts_size; |
||
53 | int *channel_counts; ///< list of accepted channel counts, terminated by -1 |
||
54 | int channel_counts_size; |
||
55 | int all_channel_counts; |
||
56 | int *sample_rates; ///< list of accepted sample rates, terminated by -1 |
||
57 | int sample_rates_size; |
||
58 | |||
59 | /* only used for compat API */ |
||
60 | AVAudioFifo *audio_fifo; ///< FIFO for audio samples |
||
61 | int64_t next_pts; ///< interpolating audio pts |
||
62 | } BufferSinkContext; |
||
63 | |||
64 | #define NB_ITEMS(list) (list ## _size / sizeof(*list)) |
||
65 | |||
66 | static av_cold void uninit(AVFilterContext *ctx) |
||
67 | { |
||
68 | BufferSinkContext *sink = ctx->priv; |
||
69 | AVFrame *frame; |
||
70 | |||
71 | if (sink->audio_fifo) |
||
72 | av_audio_fifo_free(sink->audio_fifo); |
||
73 | |||
74 | if (sink->fifo) { |
||
75 | while (av_fifo_size(sink->fifo) >= sizeof(AVFilterBufferRef *)) { |
||
76 | av_fifo_generic_read(sink->fifo, &frame, sizeof(frame), NULL); |
||
77 | av_frame_free(&frame); |
||
78 | } |
||
79 | av_fifo_free(sink->fifo); |
||
80 | sink->fifo = NULL; |
||
81 | } |
||
82 | } |
||
83 | |||
84 | static int add_buffer_ref(AVFilterContext *ctx, AVFrame *ref) |
||
85 | { |
||
86 | BufferSinkContext *buf = ctx->priv; |
||
87 | |||
88 | if (av_fifo_space(buf->fifo) < sizeof(AVFilterBufferRef *)) { |
||
89 | /* realloc fifo size */ |
||
90 | if (av_fifo_realloc2(buf->fifo, av_fifo_size(buf->fifo) * 2) < 0) { |
||
91 | av_log(ctx, AV_LOG_ERROR, |
||
92 | "Cannot buffer more frames. Consume some available frames " |
||
93 | "before adding new ones.\n"); |
||
94 | return AVERROR(ENOMEM); |
||
95 | } |
||
96 | } |
||
97 | |||
98 | /* cache frame */ |
||
99 | av_fifo_generic_write(buf->fifo, &ref, sizeof(AVFilterBufferRef *), NULL); |
||
100 | return 0; |
||
101 | } |
||
102 | |||
103 | static int filter_frame(AVFilterLink *link, AVFrame *frame) |
||
104 | { |
||
105 | AVFilterContext *ctx = link->dst; |
||
106 | BufferSinkContext *buf = link->dst->priv; |
||
107 | int ret; |
||
108 | |||
109 | if ((ret = add_buffer_ref(ctx, frame)) < 0) |
||
110 | return ret; |
||
111 | if (buf->warning_limit && |
||
112 | av_fifo_size(buf->fifo) / sizeof(AVFilterBufferRef *) >= buf->warning_limit) { |
||
113 | av_log(ctx, AV_LOG_WARNING, |
||
114 | "%d buffers queued in %s, something may be wrong.\n", |
||
115 | buf->warning_limit, |
||
116 | (char *)av_x_if_null(ctx->name, ctx->filter->name)); |
||
117 | buf->warning_limit *= 10; |
||
118 | } |
||
119 | return 0; |
||
120 | } |
||
121 | |||
122 | int attribute_align_arg av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame) |
||
123 | { |
||
124 | return av_buffersink_get_frame_flags(ctx, frame, 0); |
||
125 | } |
||
126 | |||
127 | int attribute_align_arg av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flags) |
||
128 | { |
||
129 | BufferSinkContext *buf = ctx->priv; |
||
130 | AVFilterLink *inlink = ctx->inputs[0]; |
||
131 | int ret; |
||
132 | AVFrame *cur_frame; |
||
133 | |||
134 | /* no picref available, fetch it from the filterchain */ |
||
135 | if (!av_fifo_size(buf->fifo)) { |
||
136 | if (flags & AV_BUFFERSINK_FLAG_NO_REQUEST) |
||
137 | return AVERROR(EAGAIN); |
||
138 | if ((ret = ff_request_frame(inlink)) < 0) |
||
139 | return ret; |
||
140 | } |
||
141 | |||
142 | if (!av_fifo_size(buf->fifo)) |
||
143 | return AVERROR(EINVAL); |
||
144 | |||
145 | if (flags & AV_BUFFERSINK_FLAG_PEEK) { |
||
146 | cur_frame = *((AVFrame **)av_fifo_peek2(buf->fifo, 0)); |
||
147 | if ((ret = av_frame_ref(frame, cur_frame)) < 0) |
||
148 | return ret; |
||
149 | } else { |
||
150 | av_fifo_generic_read(buf->fifo, &cur_frame, sizeof(cur_frame), NULL); |
||
151 | av_frame_move_ref(frame, cur_frame); |
||
152 | av_frame_free(&cur_frame); |
||
153 | } |
||
154 | |||
155 | return 0; |
||
156 | } |
||
157 | |||
158 | static int read_from_fifo(AVFilterContext *ctx, AVFrame *frame, |
||
159 | int nb_samples) |
||
160 | { |
||
161 | BufferSinkContext *s = ctx->priv; |
||
162 | AVFilterLink *link = ctx->inputs[0]; |
||
163 | AVFrame *tmp; |
||
164 | |||
165 | if (!(tmp = ff_get_audio_buffer(link, nb_samples))) |
||
166 | return AVERROR(ENOMEM); |
||
167 | av_audio_fifo_read(s->audio_fifo, (void**)tmp->extended_data, nb_samples); |
||
168 | |||
169 | tmp->pts = s->next_pts; |
||
170 | if (s->next_pts != AV_NOPTS_VALUE) |
||
171 | s->next_pts += av_rescale_q(nb_samples, (AVRational){1, link->sample_rate}, |
||
172 | link->time_base); |
||
173 | |||
174 | av_frame_move_ref(frame, tmp); |
||
175 | av_frame_free(&tmp); |
||
176 | |||
177 | return 0; |
||
178 | } |
||
179 | |||
180 | int attribute_align_arg av_buffersink_get_samples(AVFilterContext *ctx, |
||
181 | AVFrame *frame, int nb_samples) |
||
182 | { |
||
183 | BufferSinkContext *s = ctx->priv; |
||
184 | AVFilterLink *link = ctx->inputs[0]; |
||
185 | AVFrame *cur_frame; |
||
186 | int ret = 0; |
||
187 | |||
188 | if (!s->audio_fifo) { |
||
189 | int nb_channels = link->channels; |
||
190 | if (!(s->audio_fifo = av_audio_fifo_alloc(link->format, nb_channels, nb_samples))) |
||
191 | return AVERROR(ENOMEM); |
||
192 | } |
||
193 | |||
194 | while (ret >= 0) { |
||
195 | if (av_audio_fifo_size(s->audio_fifo) >= nb_samples) |
||
196 | return read_from_fifo(ctx, frame, nb_samples); |
||
197 | |||
198 | if (!(cur_frame = av_frame_alloc())) |
||
199 | return AVERROR(ENOMEM); |
||
200 | ret = av_buffersink_get_frame_flags(ctx, cur_frame, 0); |
||
201 | if (ret == AVERROR_EOF && av_audio_fifo_size(s->audio_fifo)) { |
||
202 | av_frame_free(&cur_frame); |
||
203 | return read_from_fifo(ctx, frame, av_audio_fifo_size(s->audio_fifo)); |
||
204 | } else if (ret < 0) { |
||
205 | av_frame_free(&cur_frame); |
||
206 | return ret; |
||
207 | } |
||
208 | |||
209 | if (cur_frame->pts != AV_NOPTS_VALUE) { |
||
210 | s->next_pts = cur_frame->pts - |
||
211 | av_rescale_q(av_audio_fifo_size(s->audio_fifo), |
||
212 | (AVRational){ 1, link->sample_rate }, |
||
213 | link->time_base); |
||
214 | } |
||
215 | |||
216 | ret = av_audio_fifo_write(s->audio_fifo, (void**)cur_frame->extended_data, |
||
217 | cur_frame->nb_samples); |
||
218 | av_frame_free(&cur_frame); |
||
219 | } |
||
220 | |||
221 | return ret; |
||
222 | } |
||
223 | |||
224 | AVBufferSinkParams *av_buffersink_params_alloc(void) |
||
225 | { |
||
226 | static const int pixel_fmts[] = { AV_PIX_FMT_NONE }; |
||
227 | AVBufferSinkParams *params = av_malloc(sizeof(AVBufferSinkParams)); |
||
228 | if (!params) |
||
229 | return NULL; |
||
230 | |||
231 | params->pixel_fmts = pixel_fmts; |
||
232 | return params; |
||
233 | } |
||
234 | |||
235 | AVABufferSinkParams *av_abuffersink_params_alloc(void) |
||
236 | { |
||
237 | AVABufferSinkParams *params = av_mallocz(sizeof(AVABufferSinkParams)); |
||
238 | |||
239 | if (!params) |
||
240 | return NULL; |
||
241 | return params; |
||
242 | } |
||
243 | |||
244 | #define FIFO_INIT_SIZE 8 |
||
245 | |||
246 | static av_cold int common_init(AVFilterContext *ctx) |
||
247 | { |
||
248 | BufferSinkContext *buf = ctx->priv; |
||
249 | |||
250 | buf->fifo = av_fifo_alloc(FIFO_INIT_SIZE*sizeof(AVFilterBufferRef *)); |
||
251 | if (!buf->fifo) { |
||
252 | av_log(ctx, AV_LOG_ERROR, "Failed to allocate fifo\n"); |
||
253 | return AVERROR(ENOMEM); |
||
254 | } |
||
255 | buf->warning_limit = 100; |
||
256 | buf->next_pts = AV_NOPTS_VALUE; |
||
257 | return 0; |
||
258 | } |
||
259 | |||
260 | void av_buffersink_set_frame_size(AVFilterContext *ctx, unsigned frame_size) |
||
261 | { |
||
262 | AVFilterLink *inlink = ctx->inputs[0]; |
||
263 | |||
264 | inlink->min_samples = inlink->max_samples = |
||
265 | inlink->partial_buf_size = frame_size; |
||
266 | } |
||
267 | |||
268 | #if FF_API_AVFILTERBUFFER |
||
269 | FF_DISABLE_DEPRECATION_WARNINGS |
||
270 | static void compat_free_buffer(AVFilterBuffer *buf) |
||
271 | { |
||
272 | AVFrame *frame = buf->priv; |
||
273 | av_frame_free(&frame); |
||
274 | av_free(buf); |
||
275 | } |
||
276 | |||
277 | static int compat_read(AVFilterContext *ctx, |
||
278 | AVFilterBufferRef **pbuf, int nb_samples, int flags) |
||
279 | { |
||
280 | AVFilterBufferRef *buf; |
||
281 | AVFrame *frame; |
||
282 | int ret; |
||
283 | |||
284 | if (!pbuf) |
||
285 | return ff_poll_frame(ctx->inputs[0]); |
||
286 | |||
287 | frame = av_frame_alloc(); |
||
288 | if (!frame) |
||
289 | return AVERROR(ENOMEM); |
||
290 | |||
291 | if (!nb_samples) |
||
292 | ret = av_buffersink_get_frame_flags(ctx, frame, flags); |
||
293 | else |
||
294 | ret = av_buffersink_get_samples(ctx, frame, nb_samples); |
||
295 | |||
296 | if (ret < 0) |
||
297 | goto fail; |
||
298 | |||
299 | AV_NOWARN_DEPRECATED( |
||
300 | if (ctx->inputs[0]->type == AVMEDIA_TYPE_VIDEO) { |
||
301 | buf = avfilter_get_video_buffer_ref_from_arrays(frame->data, frame->linesize, |
||
302 | AV_PERM_READ, |
||
303 | frame->width, frame->height, |
||
304 | frame->format); |
||
305 | } else { |
||
306 | buf = avfilter_get_audio_buffer_ref_from_arrays(frame->extended_data, |
||
307 | frame->linesize[0], AV_PERM_READ, |
||
308 | frame->nb_samples, |
||
309 | frame->format, |
||
310 | frame->channel_layout); |
||
311 | } |
||
312 | if (!buf) { |
||
313 | ret = AVERROR(ENOMEM); |
||
314 | goto fail; |
||
315 | } |
||
316 | |||
317 | avfilter_copy_frame_props(buf, frame); |
||
318 | ) |
||
319 | |||
320 | buf->buf->priv = frame; |
||
321 | buf->buf->free = compat_free_buffer; |
||
322 | |||
323 | *pbuf = buf; |
||
324 | |||
325 | return 0; |
||
326 | fail: |
||
327 | av_frame_free(&frame); |
||
328 | return ret; |
||
329 | } |
||
330 | |||
331 | int attribute_align_arg av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf) |
||
332 | { |
||
333 | return compat_read(ctx, buf, 0, 0); |
||
334 | } |
||
335 | |||
336 | int attribute_align_arg av_buffersink_read_samples(AVFilterContext *ctx, AVFilterBufferRef **buf, |
||
337 | int nb_samples) |
||
338 | { |
||
339 | return compat_read(ctx, buf, nb_samples, 0); |
||
340 | } |
||
341 | |||
342 | int attribute_align_arg av_buffersink_get_buffer_ref(AVFilterContext *ctx, |
||
343 | AVFilterBufferRef **bufref, int flags) |
||
344 | { |
||
345 | *bufref = NULL; |
||
346 | |||
347 | av_assert0( !strcmp(ctx->filter->name, "buffersink") |
||
348 | || !strcmp(ctx->filter->name, "abuffersink") |
||
349 | || !strcmp(ctx->filter->name, "ffbuffersink") |
||
350 | || !strcmp(ctx->filter->name, "ffabuffersink")); |
||
351 | |||
352 | return compat_read(ctx, bufref, 0, flags); |
||
353 | } |
||
354 | FF_ENABLE_DEPRECATION_WARNINGS |
||
355 | #endif |
||
356 | |||
357 | AVRational av_buffersink_get_frame_rate(AVFilterContext *ctx) |
||
358 | { |
||
359 | av_assert0( !strcmp(ctx->filter->name, "buffersink") |
||
360 | || !strcmp(ctx->filter->name, "ffbuffersink")); |
||
361 | |||
362 | return ctx->inputs[0]->frame_rate; |
||
363 | } |
||
364 | |||
365 | int attribute_align_arg av_buffersink_poll_frame(AVFilterContext *ctx) |
||
366 | { |
||
367 | BufferSinkContext *buf = ctx->priv; |
||
368 | AVFilterLink *inlink = ctx->inputs[0]; |
||
369 | |||
370 | av_assert0( !strcmp(ctx->filter->name, "buffersink") |
||
371 | || !strcmp(ctx->filter->name, "abuffersink") |
||
372 | || !strcmp(ctx->filter->name, "ffbuffersink") |
||
373 | || !strcmp(ctx->filter->name, "ffabuffersink")); |
||
374 | |||
375 | return av_fifo_size(buf->fifo)/sizeof(AVFilterBufferRef *) + ff_poll_frame(inlink); |
||
376 | } |
||
377 | |||
378 | static av_cold int vsink_init(AVFilterContext *ctx, void *opaque) |
||
379 | { |
||
380 | BufferSinkContext *buf = ctx->priv; |
||
381 | AVBufferSinkParams *params = opaque; |
||
382 | int ret; |
||
383 | |||
384 | if (params) { |
||
385 | if ((ret = av_opt_set_int_list(buf, "pix_fmts", params->pixel_fmts, AV_PIX_FMT_NONE, 0)) < 0) |
||
386 | return ret; |
||
387 | } |
||
388 | |||
389 | return common_init(ctx); |
||
390 | } |
||
391 | |||
392 | #define CHECK_LIST_SIZE(field) \ |
||
393 | if (buf->field ## _size % sizeof(*buf->field)) { \ |
||
394 | av_log(ctx, AV_LOG_ERROR, "Invalid size for " #field ": %d, " \ |
||
395 | "should be multiple of %d\n", \ |
||
396 | buf->field ## _size, (int)sizeof(*buf->field)); \ |
||
397 | return AVERROR(EINVAL); \ |
||
398 | } |
||
399 | static int vsink_query_formats(AVFilterContext *ctx) |
||
400 | { |
||
401 | BufferSinkContext *buf = ctx->priv; |
||
402 | AVFilterFormats *formats = NULL; |
||
403 | unsigned i; |
||
404 | int ret; |
||
405 | |||
406 | CHECK_LIST_SIZE(pixel_fmts) |
||
407 | if (buf->pixel_fmts_size) { |
||
408 | for (i = 0; i < NB_ITEMS(buf->pixel_fmts); i++) |
||
409 | if ((ret = ff_add_format(&formats, buf->pixel_fmts[i])) < 0) { |
||
410 | ff_formats_unref(&formats); |
||
411 | return ret; |
||
412 | } |
||
413 | ff_set_common_formats(ctx, formats); |
||
414 | } else { |
||
415 | ff_default_query_formats(ctx); |
||
416 | } |
||
417 | |||
418 | return 0; |
||
419 | } |
||
420 | |||
421 | static av_cold int asink_init(AVFilterContext *ctx, void *opaque) |
||
422 | { |
||
423 | BufferSinkContext *buf = ctx->priv; |
||
424 | AVABufferSinkParams *params = opaque; |
||
425 | int ret; |
||
426 | |||
427 | if (params) { |
||
428 | if ((ret = av_opt_set_int_list(buf, "sample_fmts", params->sample_fmts, AV_SAMPLE_FMT_NONE, 0)) < 0 || |
||
429 | (ret = av_opt_set_int_list(buf, "sample_rates", params->sample_rates, -1, 0)) < 0 || |
||
430 | (ret = av_opt_set_int_list(buf, "channel_layouts", params->channel_layouts, -1, 0)) < 0 || |
||
431 | (ret = av_opt_set_int_list(buf, "channel_counts", params->channel_counts, -1, 0)) < 0 || |
||
432 | (ret = av_opt_set_int(buf, "all_channel_counts", params->all_channel_counts, 0)) < 0) |
||
433 | return ret; |
||
434 | } |
||
435 | return common_init(ctx); |
||
436 | } |
||
437 | |||
438 | static int asink_query_formats(AVFilterContext *ctx) |
||
439 | { |
||
440 | BufferSinkContext *buf = ctx->priv; |
||
441 | AVFilterFormats *formats = NULL; |
||
442 | AVFilterChannelLayouts *layouts = NULL; |
||
443 | unsigned i; |
||
444 | int ret; |
||
445 | |||
446 | CHECK_LIST_SIZE(sample_fmts) |
||
447 | CHECK_LIST_SIZE(sample_rates) |
||
448 | CHECK_LIST_SIZE(channel_layouts) |
||
449 | CHECK_LIST_SIZE(channel_counts) |
||
450 | |||
451 | if (buf->sample_fmts_size) { |
||
452 | for (i = 0; i < NB_ITEMS(buf->sample_fmts); i++) |
||
453 | if ((ret = ff_add_format(&formats, buf->sample_fmts[i])) < 0) { |
||
454 | ff_formats_unref(&formats); |
||
455 | return ret; |
||
456 | } |
||
457 | ff_set_common_formats(ctx, formats); |
||
458 | } |
||
459 | |||
460 | if (buf->channel_layouts_size || buf->channel_counts_size || |
||
461 | buf->all_channel_counts) { |
||
462 | for (i = 0; i < NB_ITEMS(buf->channel_layouts); i++) |
||
463 | if ((ret = ff_add_channel_layout(&layouts, buf->channel_layouts[i])) < 0) { |
||
464 | ff_channel_layouts_unref(&layouts); |
||
465 | return ret; |
||
466 | } |
||
467 | for (i = 0; i < NB_ITEMS(buf->channel_counts); i++) |
||
468 | if ((ret = ff_add_channel_layout(&layouts, FF_COUNT2LAYOUT(buf->channel_counts[i]))) < 0) { |
||
469 | ff_channel_layouts_unref(&layouts); |
||
470 | return ret; |
||
471 | } |
||
472 | if (buf->all_channel_counts) { |
||
473 | if (layouts) |
||
474 | av_log(ctx, AV_LOG_WARNING, |
||
475 | "Conflicting all_channel_counts and list in options\n"); |
||
476 | else if (!(layouts = ff_all_channel_counts())) |
||
477 | return AVERROR(ENOMEM); |
||
478 | } |
||
479 | ff_set_common_channel_layouts(ctx, layouts); |
||
480 | } |
||
481 | |||
482 | if (buf->sample_rates_size) { |
||
483 | formats = NULL; |
||
484 | for (i = 0; i < NB_ITEMS(buf->sample_rates); i++) |
||
485 | if ((ret = ff_add_format(&formats, buf->sample_rates[i])) < 0) { |
||
486 | ff_formats_unref(&formats); |
||
487 | return ret; |
||
488 | } |
||
489 | ff_set_common_samplerates(ctx, formats); |
||
490 | } |
||
491 | |||
492 | return 0; |
||
493 | } |
||
494 | |||
495 | #define OFFSET(x) offsetof(BufferSinkContext, x) |
||
496 | #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM |
||
497 | static const AVOption buffersink_options[] = { |
||
498 | { "pix_fmts", "set the supported pixel formats", OFFSET(pixel_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS }, |
||
499 | { NULL }, |
||
500 | }; |
||
501 | #undef FLAGS |
||
502 | #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM |
||
503 | static const AVOption abuffersink_options[] = { |
||
504 | { "sample_fmts", "set the supported sample formats", OFFSET(sample_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS }, |
||
505 | { "sample_rates", "set the supported sample rates", OFFSET(sample_rates), AV_OPT_TYPE_BINARY, .flags = FLAGS }, |
||
506 | { "channel_layouts", "set the supported channel layouts", OFFSET(channel_layouts), AV_OPT_TYPE_BINARY, .flags = FLAGS }, |
||
507 | { "channel_counts", "set the supported channel counts", OFFSET(channel_counts), AV_OPT_TYPE_BINARY, .flags = FLAGS }, |
||
508 | { "all_channel_counts", "accept all channel counts", OFFSET(all_channel_counts), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS }, |
||
509 | { NULL }, |
||
510 | }; |
||
511 | #undef FLAGS |
||
512 | |||
513 | AVFILTER_DEFINE_CLASS(buffersink); |
||
514 | AVFILTER_DEFINE_CLASS(abuffersink); |
||
515 | |||
516 | #if FF_API_AVFILTERBUFFER |
||
517 | |||
518 | #define ffbuffersink_options buffersink_options |
||
519 | #define ffabuffersink_options abuffersink_options |
||
520 | AVFILTER_DEFINE_CLASS(ffbuffersink); |
||
521 | AVFILTER_DEFINE_CLASS(ffabuffersink); |
||
522 | |||
523 | static const AVFilterPad ffbuffersink_inputs[] = { |
||
524 | { |
||
525 | .name = "default", |
||
526 | .type = AVMEDIA_TYPE_VIDEO, |
||
527 | .filter_frame = filter_frame, |
||
528 | }, |
||
529 | { NULL }, |
||
530 | }; |
||
531 | |||
532 | AVFilter avfilter_vsink_ffbuffersink = { |
||
533 | .name = "ffbuffersink", |
||
534 | .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."), |
||
535 | .priv_size = sizeof(BufferSinkContext), |
||
536 | .priv_class = &ffbuffersink_class, |
||
537 | .init_opaque = vsink_init, |
||
538 | .uninit = uninit, |
||
539 | |||
540 | .query_formats = vsink_query_formats, |
||
541 | .inputs = ffbuffersink_inputs, |
||
542 | .outputs = NULL, |
||
543 | }; |
||
544 | |||
545 | static const AVFilterPad ffabuffersink_inputs[] = { |
||
546 | { |
||
547 | .name = "default", |
||
548 | .type = AVMEDIA_TYPE_AUDIO, |
||
549 | .filter_frame = filter_frame, |
||
550 | }, |
||
551 | { NULL }, |
||
552 | }; |
||
553 | |||
554 | AVFilter avfilter_asink_ffabuffersink = { |
||
555 | .name = "ffabuffersink", |
||
556 | .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."), |
||
557 | .init_opaque = asink_init, |
||
558 | .uninit = uninit, |
||
559 | .priv_size = sizeof(BufferSinkContext), |
||
560 | .priv_class = &ffabuffersink_class, |
||
561 | .query_formats = asink_query_formats, |
||
562 | .inputs = ffabuffersink_inputs, |
||
563 | .outputs = NULL, |
||
564 | }; |
||
565 | #endif /* FF_API_AVFILTERBUFFER */ |
||
566 | |||
567 | static const AVFilterPad avfilter_vsink_buffer_inputs[] = { |
||
568 | { |
||
569 | .name = "default", |
||
570 | .type = AVMEDIA_TYPE_VIDEO, |
||
571 | .filter_frame = filter_frame, |
||
572 | }, |
||
573 | { NULL } |
||
574 | }; |
||
575 | |||
576 | AVFilter avfilter_vsink_buffer = { |
||
577 | .name = "buffersink", |
||
578 | .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."), |
||
579 | .priv_size = sizeof(BufferSinkContext), |
||
580 | .priv_class = &buffersink_class, |
||
581 | .init_opaque = vsink_init, |
||
582 | .uninit = uninit, |
||
583 | |||
584 | .query_formats = vsink_query_formats, |
||
585 | .inputs = avfilter_vsink_buffer_inputs, |
||
586 | .outputs = NULL, |
||
587 | }; |
||
588 | |||
589 | static const AVFilterPad avfilter_asink_abuffer_inputs[] = { |
||
590 | { |
||
591 | .name = "default", |
||
592 | .type = AVMEDIA_TYPE_AUDIO, |
||
593 | .filter_frame = filter_frame, |
||
594 | }, |
||
595 | { NULL } |
||
596 | }; |
||
597 | |||
598 | AVFilter avfilter_asink_abuffer = { |
||
599 | .name = "abuffersink", |
||
600 | .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."), |
||
601 | .priv_class = &abuffersink_class, |
||
602 | .priv_size = sizeof(BufferSinkContext), |
||
603 | .init_opaque = asink_init, |
||
604 | .uninit = uninit, |
||
605 | |||
606 | .query_formats = asink_query_formats, |
||
607 | .inputs = avfilter_asink_abuffer_inputs, |
||
608 | .outputs = NULL, |
||
609 | };>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> |