Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * Copyright (c) 2008 Vitor Sessak | |
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 | * memory buffer source filter | |
24 | */ | |
25 | ||
26 | #include <float.h> | |
27 | ||
28 | #include "libavutil/channel_layout.h" | |
29 | #include "libavutil/common.h" | |
30 | #include "libavutil/fifo.h" | |
31 | #include "libavutil/frame.h" | |
32 | #include "libavutil/imgutils.h" | |
33 | #include "libavutil/internal.h" | |
34 | #include "libavutil/opt.h" | |
35 | #include "libavutil/samplefmt.h" | |
36 | #include "audio.h" | |
37 | #include "avfilter.h" | |
38 | #include "buffersrc.h" | |
39 | #include "formats.h" | |
40 | #include "internal.h" | |
41 | #include "video.h" | |
42 | #include "avcodec.h" | |
43 | ||
44 | typedef struct BufferSourceContext { | |
45 | const AVClass *class; | |
46 | AVFifoBuffer *fifo; | |
47 | AVRational time_base; ///< time_base to set in the output link | |
48 | AVRational frame_rate; ///< frame_rate to set in the output link | |
49 | unsigned nb_failed_requests; | |
50 | unsigned warning_limit; | |
51 | ||
52 | /* video only */ | |
53 | int w, h; | |
54 | enum AVPixelFormat pix_fmt; | |
55 | AVRational pixel_aspect; | |
56 | char *sws_param; | |
57 | ||
58 | /* audio only */ | |
59 | int sample_rate; | |
60 | enum AVSampleFormat sample_fmt; | |
61 | int channels; | |
62 | uint64_t channel_layout; | |
63 | char *channel_layout_str; | |
64 | ||
65 | int eof; | |
66 | } BufferSourceContext; | |
67 | ||
68 | #define CHECK_VIDEO_PARAM_CHANGE(s, c, width, height, format)\ | |
69 | if (c->w != width || c->h != height || c->pix_fmt != format) {\ | |
70 | av_log(s, AV_LOG_INFO, "Changing frame properties on the fly is not supported by all filters.\n");\ | |
71 | } | |
72 | ||
73 | #define CHECK_AUDIO_PARAM_CHANGE(s, c, srate, ch_layout, ch_count, format)\ | |
74 | if (c->sample_fmt != format || c->sample_rate != srate ||\ | |
75 | c->channel_layout != ch_layout || c->channels != ch_count) {\ | |
76 | av_log(s, AV_LOG_ERROR, "Changing frame properties on the fly is not supported.\n");\ | |
77 | return AVERROR(EINVAL);\ | |
78 | } | |
79 | ||
80 | int attribute_align_arg av_buffersrc_write_frame(AVFilterContext *ctx, const AVFrame *frame) | |
81 | { | |
82 | return av_buffersrc_add_frame_flags(ctx, (AVFrame *)frame, | |
83 | AV_BUFFERSRC_FLAG_KEEP_REF); | |
84 | } | |
85 | ||
86 | int attribute_align_arg av_buffersrc_add_frame(AVFilterContext *ctx, AVFrame *frame) | |
87 | { | |
88 | return av_buffersrc_add_frame_flags(ctx, frame, 0); | |
89 | } | |
90 | ||
91 | static int av_buffersrc_add_frame_internal(AVFilterContext *ctx, | |
92 | AVFrame *frame, int flags); | |
93 | ||
94 | int attribute_align_arg av_buffersrc_add_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flags) | |
95 | { | |
96 | AVFrame *copy = NULL; | |
97 | int ret = 0; | |
98 | ||
99 | if (frame && frame->channel_layout && | |
100 | av_get_channel_layout_nb_channels(frame->channel_layout) != av_frame_get_channels(frame)) { | |
101 | av_log(0, AV_LOG_ERROR, "Layout indicates a different number of channels than actually present\n"); | |
102 | return AVERROR(EINVAL); | |
103 | } | |
104 | ||
105 | if (!(flags & AV_BUFFERSRC_FLAG_KEEP_REF) || !frame) | |
106 | return av_buffersrc_add_frame_internal(ctx, frame, flags); | |
107 | ||
108 | if (!(copy = av_frame_alloc())) | |
109 | return AVERROR(ENOMEM); | |
110 | ret = av_frame_ref(copy, frame); | |
111 | if (ret >= 0) | |
112 | ret = av_buffersrc_add_frame_internal(ctx, copy, flags); | |
113 | ||
114 | av_frame_free(©); | |
115 | return ret; | |
116 | } | |
117 | ||
118 | static int av_buffersrc_add_frame_internal(AVFilterContext *ctx, | |
119 | AVFrame *frame, int flags) | |
120 | { | |
121 | BufferSourceContext *s = ctx->priv; | |
122 | AVFrame *copy; | |
123 | int refcounted, ret; | |
124 | ||
125 | s->nb_failed_requests = 0; | |
126 | ||
127 | if (!frame) { | |
128 | s->eof = 1; | |
129 | return 0; | |
130 | } else if (s->eof) | |
131 | return AVERROR(EINVAL); | |
132 | ||
133 | refcounted = !!frame->buf[0]; | |
134 | ||
135 | if (!(flags & AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT)) { | |
136 | ||
137 | switch (ctx->outputs[0]->type) { | |
138 | case AVMEDIA_TYPE_VIDEO: | |
139 | CHECK_VIDEO_PARAM_CHANGE(ctx, s, frame->width, frame->height, | |
140 | frame->format); | |
141 | break; | |
142 | case AVMEDIA_TYPE_AUDIO: | |
143 | /* For layouts unknown on input but known on link after negotiation. */ | |
144 | if (!frame->channel_layout) | |
145 | frame->channel_layout = s->channel_layout; | |
146 | CHECK_AUDIO_PARAM_CHANGE(ctx, s, frame->sample_rate, frame->channel_layout, | |
147 | av_frame_get_channels(frame), frame->format); | |
148 | break; | |
149 | default: | |
150 | return AVERROR(EINVAL); | |
151 | } | |
152 | ||
153 | } | |
154 | ||
155 | if (!av_fifo_space(s->fifo) && | |
156 | (ret = av_fifo_realloc2(s->fifo, av_fifo_size(s->fifo) + | |
157 | sizeof(copy))) < 0) | |
158 | return ret; | |
159 | ||
160 | if (!(copy = av_frame_alloc())) | |
161 | return AVERROR(ENOMEM); | |
162 | ||
163 | if (refcounted) { | |
164 | av_frame_move_ref(copy, frame); | |
165 | } else { | |
166 | ret = av_frame_ref(copy, frame); | |
167 | if (ret < 0) { | |
168 | av_frame_free(©); | |
169 | return ret; | |
170 | } | |
171 | } | |
172 | ||
173 | if ((ret = av_fifo_generic_write(s->fifo, ©, sizeof(copy), NULL)) < 0) { | |
174 | if (refcounted) | |
175 | av_frame_move_ref(frame, copy); | |
176 | av_frame_free(©); | |
177 | return ret; | |
178 | } | |
179 | ||
180 | if ((flags & AV_BUFFERSRC_FLAG_PUSH)) | |
181 | if ((ret = ctx->output_pads[0].request_frame(ctx->outputs[0])) < 0) | |
182 | return ret; | |
183 | ||
184 | return 0; | |
185 | } | |
186 | ||
187 | #if FF_API_AVFILTERBUFFER | |
188 | FF_DISABLE_DEPRECATION_WARNINGS | |
189 | static void compat_free_buffer(void *opaque, uint8_t *data) | |
190 | { | |
191 | AVFilterBufferRef *buf = opaque; | |
192 | AV_NOWARN_DEPRECATED( | |
193 | avfilter_unref_buffer(buf); | |
194 | ) | |
195 | } | |
196 | ||
197 | static void compat_unref_buffer(void *opaque, uint8_t *data) | |
198 | { | |
199 | AVBufferRef *buf = opaque; | |
200 | AV_NOWARN_DEPRECATED( | |
201 | av_buffer_unref(&buf); | |
202 | ) | |
203 | } | |
204 | ||
205 | int av_buffersrc_add_ref(AVFilterContext *ctx, AVFilterBufferRef *buf, | |
206 | int flags) | |
207 | { | |
208 | BufferSourceContext *s = ctx->priv; | |
209 | AVFrame *frame = NULL; | |
210 | AVBufferRef *dummy_buf = NULL; | |
211 | int ret = 0, planes, i; | |
212 | ||
213 | if (!buf) { | |
214 | s->eof = 1; | |
215 | return 0; | |
216 | } else if (s->eof) | |
217 | return AVERROR(EINVAL); | |
218 | ||
219 | frame = av_frame_alloc(); | |
220 | if (!frame) | |
221 | return AVERROR(ENOMEM); | |
222 | ||
223 | dummy_buf = av_buffer_create(NULL, 0, compat_free_buffer, buf, | |
224 | (buf->perms & AV_PERM_WRITE) ? 0 : AV_BUFFER_FLAG_READONLY); | |
225 | if (!dummy_buf) { | |
226 | ret = AVERROR(ENOMEM); | |
227 | goto fail; | |
228 | } | |
229 | ||
230 | AV_NOWARN_DEPRECATED( | |
231 | if ((ret = avfilter_copy_buf_props(frame, buf)) < 0) | |
232 | goto fail; | |
233 | ) | |
234 | ||
235 | #define WRAP_PLANE(ref_out, data, data_size) \ | |
236 | do { \ | |
237 | AVBufferRef *dummy_ref = av_buffer_ref(dummy_buf); \ | |
238 | if (!dummy_ref) { \ | |
239 | ret = AVERROR(ENOMEM); \ | |
240 | goto fail; \ | |
241 | } \ | |
242 | ref_out = av_buffer_create(data, data_size, compat_unref_buffer, \ | |
243 | dummy_ref, (buf->perms & AV_PERM_WRITE) ? 0 : AV_BUFFER_FLAG_READONLY); \ | |
244 | if (!ref_out) { \ | |
245 | av_frame_unref(frame); \ | |
246 | ret = AVERROR(ENOMEM); \ | |
247 | goto fail; \ | |
248 | } \ | |
249 | } while (0) | |
250 | ||
251 | if (ctx->outputs[0]->type == AVMEDIA_TYPE_VIDEO) { | |
252 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); | |
253 | ||
254 | planes = av_pix_fmt_count_planes(frame->format); | |
255 | if (!desc || planes <= 0) { | |
256 | ret = AVERROR(EINVAL); | |
257 | goto fail; | |
258 | } | |
259 | ||
260 | for (i = 0; i < planes; i++) { | |
261 | int v_shift = (i == 1 || i == 2) ? desc->log2_chroma_h : 0; | |
262 | int plane_size = (frame->height >> v_shift) * frame->linesize[i]; | |
263 | ||
264 | WRAP_PLANE(frame->buf[i], frame->data[i], plane_size); | |
265 | } | |
266 | } else { | |
267 | int planar = av_sample_fmt_is_planar(frame->format); | |
268 | int channels = av_get_channel_layout_nb_channels(frame->channel_layout); | |
269 | ||
270 | planes = planar ? channels : 1; | |
271 | ||
272 | if (planes > FF_ARRAY_ELEMS(frame->buf)) { | |
273 | frame->nb_extended_buf = planes - FF_ARRAY_ELEMS(frame->buf); | |
274 | frame->extended_buf = av_mallocz_array(sizeof(*frame->extended_buf), | |
275 | frame->nb_extended_buf); | |
276 | if (!frame->extended_buf) { | |
277 | ret = AVERROR(ENOMEM); | |
278 | goto fail; | |
279 | } | |
280 | } | |
281 | ||
282 | for (i = 0; i < FFMIN(planes, FF_ARRAY_ELEMS(frame->buf)); i++) | |
283 | WRAP_PLANE(frame->buf[i], frame->extended_data[i], frame->linesize[0]); | |
284 | ||
285 | for (i = 0; i < planes - FF_ARRAY_ELEMS(frame->buf); i++) | |
286 | WRAP_PLANE(frame->extended_buf[i], | |
287 | frame->extended_data[i + FF_ARRAY_ELEMS(frame->buf)], | |
288 | frame->linesize[0]); | |
289 | } | |
290 | ||
291 | ret = av_buffersrc_add_frame_flags(ctx, frame, flags); | |
292 | ||
293 | fail: | |
294 | av_buffer_unref(&dummy_buf); | |
295 | av_frame_free(&frame); | |
296 | ||
297 | return ret; | |
298 | } | |
299 | FF_ENABLE_DEPRECATION_WARNINGS | |
300 | ||
301 | int av_buffersrc_buffer(AVFilterContext *ctx, AVFilterBufferRef *buf) | |
302 | { | |
303 | return av_buffersrc_add_ref(ctx, buf, 0); | |
304 | } | |
305 | #endif | |
306 | ||
307 | static av_cold int init_video(AVFilterContext *ctx) | |
308 | { | |
309 | BufferSourceContext *c = ctx->priv; | |
310 | ||
311 | if (c->pix_fmt == AV_PIX_FMT_NONE || !c->w || !c->h || av_q2d(c->time_base) <= 0) { | |
312 | av_log(ctx, AV_LOG_ERROR, "Invalid parameters provided.\n"); | |
313 | return AVERROR(EINVAL); | |
314 | } | |
315 | ||
316 | if (!(c->fifo = av_fifo_alloc(sizeof(AVFrame*)))) | |
317 | return AVERROR(ENOMEM); | |
318 | ||
319 | av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d pixfmt:%s tb:%d/%d fr:%d/%d sar:%d/%d sws_param:%s\n", | |
320 | c->w, c->h, av_get_pix_fmt_name(c->pix_fmt), | |
321 | c->time_base.num, c->time_base.den, c->frame_rate.num, c->frame_rate.den, | |
322 | c->pixel_aspect.num, c->pixel_aspect.den, (char *)av_x_if_null(c->sws_param, "")); | |
323 | c->warning_limit = 100; | |
324 | return 0; | |
325 | } | |
326 | ||
327 | unsigned av_buffersrc_get_nb_failed_requests(AVFilterContext *buffer_src) | |
328 | { | |
329 | return ((BufferSourceContext *)buffer_src->priv)->nb_failed_requests; | |
330 | } | |
331 | ||
332 | #define OFFSET(x) offsetof(BufferSourceContext, x) | |
333 | #define A AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_AUDIO_PARAM | |
334 | #define V AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM | |
335 | ||
336 | static const AVOption buffer_options[] = { | |
337 | { "width", NULL, OFFSET(w), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, V }, | |
338 | { "video_size", NULL, OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, .flags = V }, | |
339 | { "height", NULL, OFFSET(h), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, V }, | |
340 | { "pix_fmt", NULL, OFFSET(pix_fmt), AV_OPT_TYPE_PIXEL_FMT, { .i64 = AV_PIX_FMT_NONE }, .min = AV_PIX_FMT_NONE, .max = INT_MAX, .flags = V }, | |
341 | #if FF_API_OLD_FILTER_OPTS | |
342 | /* those 4 are for compatibility with the old option passing system where each filter | |
343 | * did its own parsing */ | |
344 | { "time_base_num", "deprecated, do not use", OFFSET(time_base.num), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, V }, | |
345 | { "time_base_den", "deprecated, do not use", OFFSET(time_base.den), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, V }, | |
346 | { "sar_num", "deprecated, do not use", OFFSET(pixel_aspect.num), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, V }, | |
347 | { "sar_den", "deprecated, do not use", OFFSET(pixel_aspect.den), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, V }, | |
348 | #endif | |
349 | { "sar", "sample aspect ratio", OFFSET(pixel_aspect), AV_OPT_TYPE_RATIONAL, { .dbl = 1 }, 0, DBL_MAX, V }, | |
350 | { "pixel_aspect", "sample aspect ratio", OFFSET(pixel_aspect), AV_OPT_TYPE_RATIONAL, { .dbl = 1 }, 0, DBL_MAX, V }, | |
351 | { "time_base", NULL, OFFSET(time_base), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, DBL_MAX, V }, | |
352 | { "frame_rate", NULL, OFFSET(frame_rate), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, DBL_MAX, V }, | |
353 | { "sws_param", NULL, OFFSET(sws_param), AV_OPT_TYPE_STRING, .flags = V }, | |
354 | { NULL }, | |
355 | }; | |
356 | ||
357 | AVFILTER_DEFINE_CLASS(buffer); | |
358 | ||
359 | static const AVOption abuffer_options[] = { | |
360 | { "time_base", NULL, OFFSET(time_base), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, INT_MAX, A }, | |
361 | { "sample_rate", NULL, OFFSET(sample_rate), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, A }, | |
362 | { "sample_fmt", NULL, OFFSET(sample_fmt), AV_OPT_TYPE_SAMPLE_FMT, { .i64 = AV_SAMPLE_FMT_NONE }, .min = AV_SAMPLE_FMT_NONE, .max = INT_MAX, .flags = A }, | |
363 | { "channel_layout", NULL, OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, .flags = A }, | |
364 | { "channels", NULL, OFFSET(channels), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, A }, | |
365 | { NULL }, | |
366 | }; | |
367 | ||
368 | AVFILTER_DEFINE_CLASS(abuffer); | |
369 | ||
370 | static av_cold int init_audio(AVFilterContext *ctx) | |
371 | { | |
372 | BufferSourceContext *s = ctx->priv; | |
373 | int ret = 0; | |
374 | ||
375 | if (s->sample_fmt == AV_SAMPLE_FMT_NONE) { | |
376 | av_log(ctx, AV_LOG_ERROR, "Sample format was not set or was invalid\n"); | |
377 | return AVERROR(EINVAL); | |
378 | } | |
379 | ||
380 | if (s->channel_layout_str) { | |
381 | int n; | |
382 | ||
383 | s->channel_layout = av_get_channel_layout(s->channel_layout_str); | |
384 | if (!s->channel_layout) { | |
385 | av_log(ctx, AV_LOG_ERROR, "Invalid channel layout %s.\n", | |
386 | s->channel_layout_str); | |
387 | return AVERROR(EINVAL); | |
388 | } | |
389 | n = av_get_channel_layout_nb_channels(s->channel_layout); | |
390 | if (s->channels) { | |
391 | if (n != s->channels) { | |
392 | av_log(ctx, AV_LOG_ERROR, | |
393 | "Mismatching channel count %d and layout '%s' " | |
394 | "(%d channels)\n", | |
395 | s->channels, s->channel_layout_str, n); | |
396 | return AVERROR(EINVAL); | |
397 | } | |
398 | } | |
399 | s->channels = n; | |
400 | } else if (!s->channels) { | |
401 | av_log(ctx, AV_LOG_ERROR, "Neither number of channels nor " | |
402 | "channel layout specified\n"); | |
403 | return AVERROR(EINVAL); | |
404 | } | |
405 | ||
406 | if (!(s->fifo = av_fifo_alloc(sizeof(AVFrame*)))) | |
407 | return AVERROR(ENOMEM); | |
408 | ||
409 | if (!s->time_base.num) | |
410 | s->time_base = (AVRational){1, s->sample_rate}; | |
411 | ||
412 | av_log(ctx, AV_LOG_VERBOSE, | |
413 | "tb:%d/%d samplefmt:%s samplerate:%d chlayout:%s\n", | |
414 | s->time_base.num, s->time_base.den, av_get_sample_fmt_name(s->sample_fmt), | |
415 | s->sample_rate, s->channel_layout_str); | |
416 | s->warning_limit = 100; | |
417 | ||
418 | return ret; | |
419 | } | |
420 | ||
421 | static av_cold void uninit(AVFilterContext *ctx) | |
422 | { | |
423 | BufferSourceContext *s = ctx->priv; | |
424 | while (s->fifo && av_fifo_size(s->fifo)) { | |
425 | AVFrame *frame; | |
426 | av_fifo_generic_read(s->fifo, &frame, sizeof(frame), NULL); | |
427 | av_frame_free(&frame); | |
428 | } | |
429 | av_fifo_freep(&s->fifo); | |
430 | } | |
431 | ||
432 | static int query_formats(AVFilterContext *ctx) | |
433 | { | |
434 | BufferSourceContext *c = ctx->priv; | |
435 | AVFilterChannelLayouts *channel_layouts = NULL; | |
436 | AVFilterFormats *formats = NULL; | |
437 | AVFilterFormats *samplerates = NULL; | |
438 | ||
439 | switch (ctx->outputs[0]->type) { | |
440 | case AVMEDIA_TYPE_VIDEO: | |
441 | ff_add_format(&formats, c->pix_fmt); | |
442 | ff_set_common_formats(ctx, formats); | |
443 | break; | |
444 | case AVMEDIA_TYPE_AUDIO: | |
445 | ff_add_format(&formats, c->sample_fmt); | |
446 | ff_set_common_formats(ctx, formats); | |
447 | ||
448 | ff_add_format(&samplerates, c->sample_rate); | |
449 | ff_set_common_samplerates(ctx, samplerates); | |
450 | ||
451 | ff_add_channel_layout(&channel_layouts, | |
452 | c->channel_layout ? c->channel_layout : | |
453 | FF_COUNT2LAYOUT(c->channels)); | |
454 | ff_set_common_channel_layouts(ctx, channel_layouts); | |
455 | break; | |
456 | default: | |
457 | return AVERROR(EINVAL); | |
458 | } | |
459 | ||
460 | return 0; | |
461 | } | |
462 | ||
463 | static int config_props(AVFilterLink *link) | |
464 | { | |
465 | BufferSourceContext *c = link->src->priv; | |
466 | ||
467 | switch (link->type) { | |
468 | case AVMEDIA_TYPE_VIDEO: | |
469 | link->w = c->w; | |
470 | link->h = c->h; | |
471 | link->sample_aspect_ratio = c->pixel_aspect; | |
472 | break; | |
473 | case AVMEDIA_TYPE_AUDIO: | |
474 | if (!c->channel_layout) | |
475 | c->channel_layout = link->channel_layout; | |
476 | break; | |
477 | default: | |
478 | return AVERROR(EINVAL); | |
479 | } | |
480 | ||
481 | link->time_base = c->time_base; | |
482 | link->frame_rate = c->frame_rate; | |
483 | return 0; | |
484 | } | |
485 | ||
486 | static int request_frame(AVFilterLink *link) | |
487 | { | |
488 | BufferSourceContext *c = link->src->priv; | |
489 | AVFrame *frame; | |
490 | ||
491 | if (!av_fifo_size(c->fifo)) { | |
492 | if (c->eof) | |
493 | return AVERROR_EOF; | |
494 | c->nb_failed_requests++; | |
495 | return AVERROR(EAGAIN); | |
496 | } | |
497 | av_fifo_generic_read(c->fifo, &frame, sizeof(frame), NULL); | |
498 | ||
499 | return ff_filter_frame(link, frame); | |
500 | } | |
501 | ||
502 | static int poll_frame(AVFilterLink *link) | |
503 | { | |
504 | BufferSourceContext *c = link->src->priv; | |
505 | int size = av_fifo_size(c->fifo); | |
506 | if (!size && c->eof) | |
507 | return AVERROR_EOF; | |
508 | return size/sizeof(AVFrame*); | |
509 | } | |
510 | ||
511 | static const AVFilterPad avfilter_vsrc_buffer_outputs[] = { | |
512 | { | |
513 | .name = "default", | |
514 | .type = AVMEDIA_TYPE_VIDEO, | |
515 | .request_frame = request_frame, | |
516 | .poll_frame = poll_frame, | |
517 | .config_props = config_props, | |
518 | }, | |
519 | { NULL } | |
520 | }; | |
521 | ||
522 | AVFilter ff_vsrc_buffer = { | |
523 | .name = "buffer", | |
524 | .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them accessible to the filterchain."), | |
525 | .priv_size = sizeof(BufferSourceContext), | |
526 | .query_formats = query_formats, | |
527 | ||
528 | .init = init_video, | |
529 | .uninit = uninit, | |
530 | ||
531 | .inputs = NULL, | |
532 | .outputs = avfilter_vsrc_buffer_outputs, | |
533 | .priv_class = &buffer_class, | |
534 | }; | |
535 | ||
536 | static const AVFilterPad avfilter_asrc_abuffer_outputs[] = { | |
537 | { | |
538 | .name = "default", | |
539 | .type = AVMEDIA_TYPE_AUDIO, | |
540 | .request_frame = request_frame, | |
541 | .poll_frame = poll_frame, | |
542 | .config_props = config_props, | |
543 | }, | |
544 | { NULL } | |
545 | }; | |
546 | ||
547 | AVFilter ff_asrc_abuffer = { | |
548 | .name = "abuffer", | |
549 | .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them accessible to the filterchain."), | |
550 | .priv_size = sizeof(BufferSourceContext), | |
551 | .query_formats = query_formats, | |
552 | ||
553 | .init = init_audio, | |
554 | .uninit = uninit, | |
555 | ||
556 | .inputs = NULL, | |
557 | .outputs = avfilter_asrc_abuffer_outputs, | |
558 | .priv_class = &abuffer_class, | |
559 | }; |