2 * Copyright (c) 2008 Vitor Sessak
4 * This file is part of FFmpeg.
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.
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.
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
23 * memory buffer source filter
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"
38 #include "buffersrc.h"
44 typedef struct BufferSourceContext
{
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
;
54 enum AVPixelFormat pix_fmt
;
55 AVRational pixel_aspect
;
60 enum AVSampleFormat sample_fmt
;
62 uint64_t channel_layout
;
63 char *channel_layout_str
;
66 } BufferSourceContext
;
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");\
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);\
80 int attribute_align_arg
av_buffersrc_write_frame(AVFilterContext
*ctx
, const AVFrame
*frame
)
82 return av_buffersrc_add_frame_flags(ctx
, (AVFrame
*)frame
,
83 AV_BUFFERSRC_FLAG_KEEP_REF
);
86 int attribute_align_arg
av_buffersrc_add_frame(AVFilterContext
*ctx
, AVFrame
*frame
)
88 return av_buffersrc_add_frame_flags(ctx
, frame
, 0);
91 static int av_buffersrc_add_frame_internal(AVFilterContext
*ctx
,
92 AVFrame
*frame
, int flags
);
94 int attribute_align_arg
av_buffersrc_add_frame_flags(AVFilterContext
*ctx
, AVFrame
*frame
, int flags
)
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
);
105 if (!(flags
& AV_BUFFERSRC_FLAG_KEEP_REF
) || !frame
)
106 return av_buffersrc_add_frame_internal(ctx
, frame
, flags
);
108 if (!(copy
= av_frame_alloc()))
109 return AVERROR(ENOMEM
);
110 ret
= av_frame_ref(copy
, frame
);
112 ret
= av_buffersrc_add_frame_internal(ctx
, copy
, flags
);
114 av_frame_free(©
);
118 static int av_buffersrc_add_frame_internal(AVFilterContext
*ctx
,
119 AVFrame
*frame
, int flags
)
121 BufferSourceContext
*s
= ctx
->priv
;
125 s
->nb_failed_requests
= 0;
131 return AVERROR(EINVAL
);
133 refcounted
= !!frame
->buf
[0];
135 if (!(flags
& AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT
)) {
137 switch (ctx
->outputs
[0]->type
) {
138 case AVMEDIA_TYPE_VIDEO
:
139 CHECK_VIDEO_PARAM_CHANGE(ctx
, s
, frame
->width
, frame
->height
,
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
);
150 return AVERROR(EINVAL
);
155 if (!av_fifo_space(s
->fifo
) &&
156 (ret
= av_fifo_realloc2(s
->fifo
, av_fifo_size(s
->fifo
) +
160 if (!(copy
= av_frame_alloc()))
161 return AVERROR(ENOMEM
);
164 av_frame_move_ref(copy
, frame
);
166 ret
= av_frame_ref(copy
, frame
);
168 av_frame_free(©
);
173 if ((ret
= av_fifo_generic_write(s
->fifo
, ©
, sizeof(copy
), NULL
)) < 0) {
175 av_frame_move_ref(frame
, copy
);
176 av_frame_free(©
);
180 if ((flags
& AV_BUFFERSRC_FLAG_PUSH
))
181 if ((ret
= ctx
->output_pads
[0].request_frame(ctx
->outputs
[0])) < 0)
187 #if FF_API_AVFILTERBUFFER
188 FF_DISABLE_DEPRECATION_WARNINGS
189 static void compat_free_buffer(void *opaque
, uint8_t *data
)
191 AVFilterBufferRef
*buf
= opaque
;
192 AV_NOWARN_DEPRECATED(
193 avfilter_unref_buffer(buf
);
197 static void compat_unref_buffer(void *opaque
, uint8_t *data
)
199 AVBufferRef
*buf
= opaque
;
200 AV_NOWARN_DEPRECATED(
201 av_buffer_unref(&buf
);
205 int av_buffersrc_add_ref(AVFilterContext
*ctx
, AVFilterBufferRef
*buf
,
208 BufferSourceContext
*s
= ctx
->priv
;
209 AVFrame
*frame
= NULL
;
210 AVBufferRef
*dummy_buf
= NULL
;
211 int ret
= 0, planes
, i
;
217 return AVERROR(EINVAL
);
219 frame
= av_frame_alloc();
221 return AVERROR(ENOMEM
);
223 dummy_buf
= av_buffer_create(NULL
, 0, compat_free_buffer
, buf
,
224 (buf
->perms
& AV_PERM_WRITE
) ? 0 : AV_BUFFER_FLAG_READONLY
);
226 ret
= AVERROR(ENOMEM
);
230 AV_NOWARN_DEPRECATED(
231 if ((ret
= avfilter_copy_buf_props(frame
, buf
)) < 0)
235 #define WRAP_PLANE(ref_out, data, data_size) \
237 AVBufferRef *dummy_ref = av_buffer_ref(dummy_buf); \
239 ret = AVERROR(ENOMEM); \
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); \
245 av_frame_unref(frame); \
246 ret = AVERROR(ENOMEM); \
251 if (ctx
->outputs
[0]->type
== AVMEDIA_TYPE_VIDEO
) {
252 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(frame
->format
);
254 planes
= av_pix_fmt_count_planes(frame
->format
);
255 if (!desc
|| planes
<= 0) {
256 ret
= AVERROR(EINVAL
);
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
];
264 WRAP_PLANE(frame
->buf
[i
], frame
->data
[i
], plane_size
);
267 int planar
= av_sample_fmt_is_planar(frame
->format
);
268 int channels
= av_get_channel_layout_nb_channels(frame
->channel_layout
);
270 planes
= planar
? channels
: 1;
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
);
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]);
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
)],
291 ret
= av_buffersrc_add_frame_flags(ctx
, frame
, flags
);
294 av_buffer_unref(&dummy_buf
);
295 av_frame_free(&frame
);
299 FF_ENABLE_DEPRECATION_WARNINGS
301 int av_buffersrc_buffer(AVFilterContext
*ctx
, AVFilterBufferRef
*buf
)
303 return av_buffersrc_add_ref(ctx
, buf
, 0);
307 static av_cold
int init_video(AVFilterContext
*ctx
)
309 BufferSourceContext
*c
= ctx
->priv
;
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
);
316 if (!(c
->fifo
= av_fifo_alloc(sizeof(AVFrame
*))))
317 return AVERROR(ENOMEM
);
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;
327 unsigned av_buffersrc_get_nb_failed_requests(AVFilterContext
*buffer_src
)
329 return ((BufferSourceContext
*)buffer_src
->priv
)->nb_failed_requests
;
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
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
},
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
},
357 AVFILTER_DEFINE_CLASS(buffer
);
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
},
368 AVFILTER_DEFINE_CLASS(abuffer
);
370 static av_cold
int init_audio(AVFilterContext
*ctx
)
372 BufferSourceContext
*s
= ctx
->priv
;
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
);
380 if (s
->channel_layout_str
) {
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
);
389 n
= av_get_channel_layout_nb_channels(s
->channel_layout
);
391 if (n
!= s
->channels
) {
392 av_log(ctx
, AV_LOG_ERROR
,
393 "Mismatching channel count %d and layout '%s' "
395 s
->channels
, s
->channel_layout_str
, n
);
396 return AVERROR(EINVAL
);
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
);
406 if (!(s
->fifo
= av_fifo_alloc(sizeof(AVFrame
*))))
407 return AVERROR(ENOMEM
);
409 if (!s
->time_base
.num
)
410 s
->time_base
= (AVRational
){1, s
->sample_rate
};
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;
421 static av_cold
void uninit(AVFilterContext
*ctx
)
423 BufferSourceContext
*s
= ctx
->priv
;
424 while (s
->fifo
&& av_fifo_size(s
->fifo
)) {
426 av_fifo_generic_read(s
->fifo
, &frame
, sizeof(frame
), NULL
);
427 av_frame_free(&frame
);
429 av_fifo_freep(&s
->fifo
);
432 static int query_formats(AVFilterContext
*ctx
)
434 BufferSourceContext
*c
= ctx
->priv
;
435 AVFilterChannelLayouts
*channel_layouts
= NULL
;
436 AVFilterFormats
*formats
= NULL
;
437 AVFilterFormats
*samplerates
= NULL
;
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
);
444 case AVMEDIA_TYPE_AUDIO
:
445 ff_add_format(&formats
, c
->sample_fmt
);
446 ff_set_common_formats(ctx
, formats
);
448 ff_add_format(&samplerates
, c
->sample_rate
);
449 ff_set_common_samplerates(ctx
, samplerates
);
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
);
457 return AVERROR(EINVAL
);
463 static int config_props(AVFilterLink
*link
)
465 BufferSourceContext
*c
= link
->src
->priv
;
467 switch (link
->type
) {
468 case AVMEDIA_TYPE_VIDEO
:
471 link
->sample_aspect_ratio
= c
->pixel_aspect
;
473 case AVMEDIA_TYPE_AUDIO
:
474 if (!c
->channel_layout
)
475 c
->channel_layout
= link
->channel_layout
;
478 return AVERROR(EINVAL
);
481 link
->time_base
= c
->time_base
;
482 link
->frame_rate
= c
->frame_rate
;
486 static int request_frame(AVFilterLink
*link
)
488 BufferSourceContext
*c
= link
->src
->priv
;
491 if (!av_fifo_size(c
->fifo
)) {
494 c
->nb_failed_requests
++;
495 return AVERROR(EAGAIN
);
497 av_fifo_generic_read(c
->fifo
, &frame
, sizeof(frame
), NULL
);
499 return ff_filter_frame(link
, frame
);
502 static int poll_frame(AVFilterLink
*link
)
504 BufferSourceContext
*c
= link
->src
->priv
;
505 int size
= av_fifo_size(c
->fifo
);
508 return size
/sizeof(AVFrame
*);
511 static const AVFilterPad avfilter_vsrc_buffer_outputs
[] = {
514 .type
= AVMEDIA_TYPE_VIDEO
,
515 .request_frame
= request_frame
,
516 .poll_frame
= poll_frame
,
517 .config_props
= config_props
,
522 AVFilter ff_vsrc_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
,
532 .outputs
= avfilter_vsrc_buffer_outputs
,
533 .priv_class
= &buffer_class
,
536 static const AVFilterPad avfilter_asrc_abuffer_outputs
[] = {
539 .type
= AVMEDIA_TYPE_AUDIO
,
540 .request_frame
= request_frame
,
541 .poll_frame
= poll_frame
,
542 .config_props
= config_props
,
547 AVFilter ff_asrc_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
,
557 .outputs
= avfilter_asrc_abuffer_outputs
,
558 .priv_class
= &abuffer_class
,