2 * Copyright (c) 2008 Vitor Sessak
4 * This file is part of Libav.
6 * Libav 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 * Libav 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 Libav; 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 "buffersrc.h"
30 #include "vsrc_buffer.h"
32 #include "libavutil/audioconvert.h"
33 #include "libavutil/fifo.h"
34 #include "libavutil/imgutils.h"
35 #include "libavutil/opt.h"
36 #include "libavutil/samplefmt.h"
41 AVRational time_base; ///< time_base to set in the output link
45 enum PixelFormat pix_fmt;
46 AVRational pixel_aspect;
50 enum AVSampleFormat sample_fmt;
52 uint64_t channel_layout;
53 char *channel_layout_str;
56 } BufferSourceContext;
58 #define CHECK_VIDEO_PARAM_CHANGE(s, c, width, height, format)\
59 if (c->w != width || c->h != height || c->pix_fmt != format) {\
60 av_log(s, AV_LOG_ERROR, "Changing frame properties on the fly is not supported.\n");\
61 return AVERROR(EINVAL);\
64 #define CHECK_AUDIO_PARAM_CHANGE(s, c, srate, ch_layout, format)\
65 if (c->sample_fmt != format || c->sample_rate != srate ||\
66 c->channel_layout != ch_layout) {\
67 av_log(s, AV_LOG_ERROR, "Changing frame properties on the fly is not supported.\n");\
68 return AVERROR(EINVAL);\
71 #if FF_API_VSRC_BUFFER_ADD_FRAME
72 int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter, AVFrame *frame,
73 int64_t pts, AVRational pixel_aspect)
75 int64_t orig_pts = frame->pts;
76 AVRational orig_sar = frame->sample_aspect_ratio;
80 frame->sample_aspect_ratio = pixel_aspect;
81 if ((ret = av_buffersrc_write_frame(buffer_filter, frame)) < 0)
83 frame->pts = orig_pts;
84 frame->sample_aspect_ratio = orig_sar;
90 int av_buffersrc_write_frame(AVFilterContext *buffer_filter, AVFrame *frame)
92 BufferSourceContext *c = buffer_filter->priv;
93 AVFilterBufferRef *buf;
100 return AVERROR(EINVAL);
102 if (!av_fifo_space(c->fifo) &&
103 (ret = av_fifo_realloc2(c->fifo, av_fifo_size(c->fifo) +
107 switch (buffer_filter->outputs[0]->type) {
108 case AVMEDIA_TYPE_VIDEO:
109 CHECK_VIDEO_PARAM_CHANGE(buffer_filter, c, frame->width, frame->height,
111 buf = avfilter_get_video_buffer(buffer_filter->outputs[0], AV_PERM_WRITE,
113 av_image_copy(buf->data, buf->linesize, frame->data, frame->linesize,
114 c->pix_fmt, c->w, c->h);
116 case AVMEDIA_TYPE_AUDIO:
117 CHECK_AUDIO_PARAM_CHANGE(buffer_filter, c, frame->sample_rate, frame->channel_layout,
119 buf = ff_get_audio_buffer(buffer_filter->outputs[0], AV_PERM_WRITE,
121 av_samples_copy(buf->extended_data, frame->extended_data,
122 0, 0, frame->nb_samples,
123 av_get_channel_layout_nb_channels(frame->channel_layout),
127 return AVERROR(EINVAL);
130 avfilter_copy_frame_props(buf, frame);
132 if ((ret = av_fifo_generic_write(c->fifo, &buf, sizeof(buf), NULL)) < 0) {
133 avfilter_unref_buffer(buf);
140 int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf)
142 BufferSourceContext *c = s->priv;
149 return AVERROR(EINVAL);
151 if (!av_fifo_space(c->fifo) &&
152 (ret = av_fifo_realloc2(c->fifo, av_fifo_size(c->fifo) +
156 switch (s->outputs[0]->type) {
157 case AVMEDIA_TYPE_VIDEO:
158 CHECK_VIDEO_PARAM_CHANGE(s, c, buf->video->w, buf->video->h, buf->format);
160 case AVMEDIA_TYPE_AUDIO:
161 CHECK_AUDIO_PARAM_CHANGE(s, c, buf->audio->sample_rate, buf->audio->channel_layout,
165 return AVERROR(EINVAL);
168 if ((ret = av_fifo_generic_write(c->fifo, &buf, sizeof(buf), NULL)) < 0)
174 static av_cold int init_video(AVFilterContext *ctx, const char *args, void *opaque)
176 BufferSourceContext *c = ctx->priv;
177 char pix_fmt_str[128];
181 (n = sscanf(args, "%d:%d:%127[^:]:%d:%d:%d:%d", &c->w, &c->h, pix_fmt_str,
182 &c->time_base.num, &c->time_base.den,
183 &c->pixel_aspect.num, &c->pixel_aspect.den)) != 7) {
184 av_log(ctx, AV_LOG_ERROR, "Expected 7 arguments, but %d found in '%s'\n", n, args);
185 return AVERROR(EINVAL);
187 if ((c->pix_fmt = av_get_pix_fmt(pix_fmt_str)) == PIX_FMT_NONE) {
189 c->pix_fmt = strtol(pix_fmt_str, &tail, 10);
190 if (*tail || c->pix_fmt < 0 || c->pix_fmt >= PIX_FMT_NB) {
191 av_log(ctx, AV_LOG_ERROR, "Invalid pixel format string '%s'\n", pix_fmt_str);
192 return AVERROR(EINVAL);
196 if (!(c->fifo = av_fifo_alloc(sizeof(AVFilterBufferRef*))))
197 return AVERROR(ENOMEM);
199 av_log(ctx, AV_LOG_INFO, "w:%d h:%d pixfmt:%s\n", c->w, c->h, av_pix_fmt_descriptors[c->pix_fmt].name);
203 #define OFFSET(x) offsetof(BufferSourceContext, x)
204 #define A AV_OPT_FLAG_AUDIO_PARAM
205 static const AVOption audio_options[] = {
206 { "time_base", NULL, OFFSET(time_base), AV_OPT_TYPE_RATIONAL, { 0 }, 0, INT_MAX, A },
207 { "sample_rate", NULL, OFFSET(sample_rate), AV_OPT_TYPE_INT, { 0 }, 0, INT_MAX, A },
208 { "sample_fmt", NULL, OFFSET(sample_fmt_str), AV_OPT_TYPE_STRING, .flags = A },
209 { "channel_layout", NULL, OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, .flags = A },
213 static const AVClass abuffer_class = {
214 .class_name = "abuffer source",
215 .item_name = av_default_item_name,
216 .option = audio_options,
217 .version = LIBAVUTIL_VERSION_INT,
220 static av_cold int init_audio(AVFilterContext *ctx, const char *args, void *opaque)
222 BufferSourceContext *s = ctx->priv;
225 s->class = &abuffer_class;
226 av_opt_set_defaults(s);
228 if ((ret = av_set_options_string(s, args, "=", ":")) < 0) {
229 av_log(ctx, AV_LOG_ERROR, "Error parsing options string: %s.\n", args);
233 s->sample_fmt = av_get_sample_fmt(s->sample_fmt_str);
234 if (s->sample_fmt == AV_SAMPLE_FMT_NONE) {
235 av_log(ctx, AV_LOG_ERROR, "Invalid sample format %s.\n",
237 ret = AVERROR(EINVAL);
241 s->channel_layout = av_get_channel_layout(s->channel_layout_str);
242 if (!s->channel_layout) {
243 av_log(ctx, AV_LOG_ERROR, "Invalid channel layout %s.\n",
244 s->channel_layout_str);
245 ret = AVERROR(EINVAL);
249 if (!(s->fifo = av_fifo_alloc(sizeof(AVFilterBufferRef*)))) {
250 ret = AVERROR(ENOMEM);
254 if (!s->time_base.num)
255 s->time_base = (AVRational){1, s->sample_rate};
257 av_log(ctx, AV_LOG_VERBOSE, "tb:%d/%d samplefmt:%s samplerate: %d "
258 "ch layout:%s\n", s->time_base.num, s->time_base.den, s->sample_fmt_str,
259 s->sample_rate, s->channel_layout_str);
266 static av_cold void uninit(AVFilterContext *ctx)
268 BufferSourceContext *s = ctx->priv;
269 while (s->fifo && av_fifo_size(s->fifo)) {
270 AVFilterBufferRef *buf;
271 av_fifo_generic_read(s->fifo, &buf, sizeof(buf), NULL);
272 avfilter_unref_buffer(buf);
274 av_fifo_free(s->fifo);
278 static int query_formats(AVFilterContext *ctx)
280 BufferSourceContext *c = ctx->priv;
281 AVFilterChannelLayouts *channel_layouts = NULL;
282 AVFilterFormats *formats = NULL;
283 AVFilterFormats *samplerates = NULL;
285 switch (ctx->outputs[0]->type) {
286 case AVMEDIA_TYPE_VIDEO:
287 avfilter_add_format(&formats, c->pix_fmt);
288 avfilter_set_common_formats(ctx, formats);
290 case AVMEDIA_TYPE_AUDIO:
291 avfilter_add_format(&formats, c->sample_fmt);
292 avfilter_set_common_formats(ctx, formats);
294 avfilter_add_format(&samplerates, c->sample_rate);
295 ff_set_common_samplerates(ctx, samplerates);
297 ff_add_channel_layout(&channel_layouts, c->channel_layout);
298 ff_set_common_channel_layouts(ctx, channel_layouts);
301 return AVERROR(EINVAL);
307 static int config_props(AVFilterLink *link)
309 BufferSourceContext *c = link->src->priv;
311 switch (link->type) {
312 case AVMEDIA_TYPE_VIDEO:
315 link->sample_aspect_ratio = c->pixel_aspect;
317 case AVMEDIA_TYPE_AUDIO:
318 link->channel_layout = c->channel_layout;
319 link->sample_rate = c->sample_rate;
322 return AVERROR(EINVAL);
325 link->time_base = c->time_base;
329 static int request_frame(AVFilterLink *link)
331 BufferSourceContext *c = link->src->priv;
332 AVFilterBufferRef *buf;
334 if (!av_fifo_size(c->fifo)) {
337 return AVERROR(EAGAIN);
339 av_fifo_generic_read(c->fifo, &buf, sizeof(buf), NULL);
341 switch (link->type) {
342 case AVMEDIA_TYPE_VIDEO:
343 avfilter_start_frame(link, avfilter_ref_buffer(buf, ~0));
344 avfilter_draw_slice(link, 0, link->h, 1);
345 avfilter_end_frame(link);
347 case AVMEDIA_TYPE_AUDIO:
348 ff_filter_samples(link, avfilter_ref_buffer(buf, ~0));
351 return AVERROR(EINVAL);
354 avfilter_unref_buffer(buf);
359 static int poll_frame(AVFilterLink *link)
361 BufferSourceContext *c = link->src->priv;
362 int size = av_fifo_size(c->fifo);
365 return size/sizeof(AVFilterBufferRef*);
368 AVFilter avfilter_vsrc_buffer = {
370 .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them accessible to the filterchain."),
371 .priv_size = sizeof(BufferSourceContext),
372 .query_formats = query_formats,
377 .inputs = (AVFilterPad[]) {{ .name = NULL }},
378 .outputs = (AVFilterPad[]) {{ .name = "default",
379 .type = AVMEDIA_TYPE_VIDEO,
380 .request_frame = request_frame,
381 .poll_frame = poll_frame,
382 .config_props = config_props, },
386 AVFilter avfilter_asrc_abuffer = {
388 .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them accessible to the filterchain."),
389 .priv_size = sizeof(BufferSourceContext),
390 .query_formats = query_formats,
395 .inputs = (AVFilterPad[]) {{ .name = NULL }},
396 .outputs = (AVFilterPad[]) {{ .name = "default",
397 .type = AVMEDIA_TYPE_AUDIO,
398 .request_frame = request_frame,
399 .poll_frame = poll_frame,
400 .config_props = config_props, },