2 * Copyright (c) 2011 Stefano Sabatini
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
26 #include "libavutil/audio_fifo.h"
27 #include "libavutil/audioconvert.h"
28 #include "libavutil/fifo.h"
29 #include "libavutil/mathematics.h"
33 #include "buffersink.h"
36 AVFifoBuffer *fifo; ///< FIFO buffer of frame references
38 AVAudioFifo *audio_fifo; ///< FIFO for audio samples
39 int64_t next_pts; ///< interpolating audio pts
42 #define FIFO_INIT_SIZE 8
44 static av_cold void uninit(AVFilterContext *ctx)
46 BufferSinkContext *sink = ctx->priv;
48 while (sink->fifo && av_fifo_size(sink->fifo)) {
49 AVFilterBufferRef *buf;
50 av_fifo_generic_read(sink->fifo, &buf, sizeof(buf), NULL);
51 avfilter_unref_buffer(buf);
53 av_fifo_free(sink->fifo);
56 av_audio_fifo_free(sink->audio_fifo);
59 static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
61 BufferSinkContext *sink = ctx->priv;
63 if (!(sink->fifo = av_fifo_alloc(FIFO_INIT_SIZE*sizeof(AVFilterBufferRef*)))) {
64 av_log(ctx, AV_LOG_ERROR, "Failed to allocate fifo\n");
65 return AVERROR(ENOMEM);
71 static void write_buf(AVFilterContext *ctx, AVFilterBufferRef *buf)
73 BufferSinkContext *sink = ctx->priv;
75 if (av_fifo_space(sink->fifo) < sizeof(AVFilterBufferRef *) &&
76 (av_fifo_realloc2(sink->fifo, av_fifo_size(sink->fifo) * 2) < 0)) {
77 av_log(ctx, AV_LOG_ERROR, "Error reallocating the FIFO.\n");
81 av_fifo_generic_write(sink->fifo, &buf, sizeof(buf), NULL);
84 static void end_frame(AVFilterLink *link)
86 write_buf(link->dst, link->cur_buf);
90 static void filter_samples(AVFilterLink *link, AVFilterBufferRef *buf)
92 write_buf(link->dst, buf);
95 int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf)
97 BufferSinkContext *sink = ctx->priv;
98 AVFilterLink *link = ctx->inputs[0];
102 if (av_fifo_size(sink->fifo))
103 return av_fifo_size(sink->fifo)/sizeof(*buf);
105 return avfilter_poll_frame(ctx->inputs[0]);
108 if (!av_fifo_size(sink->fifo) &&
109 (ret = avfilter_request_frame(link)) < 0)
112 if (!av_fifo_size(sink->fifo))
113 return AVERROR(EINVAL);
115 av_fifo_generic_read(sink->fifo, buf, sizeof(*buf), NULL);
120 static int read_from_fifo(AVFilterContext *ctx, AVFilterBufferRef **pbuf,
123 BufferSinkContext *s = ctx->priv;
124 AVFilterLink *link = ctx->inputs[0];
125 AVFilterBufferRef *buf;
127 if (!(buf = ff_get_audio_buffer(link, AV_PERM_WRITE, nb_samples)))
128 return AVERROR(ENOMEM);
129 av_audio_fifo_read(s->audio_fifo, (void**)buf->extended_data, nb_samples);
131 buf->pts = s->next_pts;
132 s->next_pts += av_rescale_q(nb_samples, (AVRational){1, link->sample_rate},
140 int av_buffersink_read_samples(AVFilterContext *ctx, AVFilterBufferRef **pbuf,
143 BufferSinkContext *s = ctx->priv;
144 AVFilterLink *link = ctx->inputs[0];
147 if (!s->audio_fifo) {
148 int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout);
149 if (!(s->audio_fifo = av_audio_fifo_alloc(link->format, nb_channels, nb_samples)))
150 return AVERROR(ENOMEM);
154 AVFilterBufferRef *buf;
156 if (av_audio_fifo_size(s->audio_fifo) >= nb_samples)
157 return read_from_fifo(ctx, pbuf, nb_samples);
159 ret = av_buffersink_read(ctx, &buf);
160 if (ret == AVERROR_EOF && av_audio_fifo_size(s->audio_fifo))
161 return read_from_fifo(ctx, pbuf, av_audio_fifo_size(s->audio_fifo));
165 if (buf->pts != AV_NOPTS_VALUE) {
166 s->next_pts = buf->pts -
167 av_rescale_q(av_audio_fifo_size(s->audio_fifo),
168 (AVRational){ 1, link->sample_rate },
172 ret = av_audio_fifo_write(s->audio_fifo, (void**)buf->extended_data,
173 buf->audio->nb_samples);
174 avfilter_unref_buffer(buf);
180 AVFilter avfilter_vsink_buffer = {
181 .name = "buffersink",
182 .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
183 .priv_size = sizeof(BufferSinkContext),
187 .inputs = (AVFilterPad[]) {{ .name = "default",
188 .type = AVMEDIA_TYPE_VIDEO,
189 .end_frame = end_frame,
190 .min_perms = AV_PERM_READ, },
192 .outputs = (AVFilterPad[]) {{ .name = NULL }},
195 AVFilter avfilter_asink_abuffer = {
196 .name = "abuffersink",
197 .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."),
198 .priv_size = sizeof(BufferSinkContext),
202 .inputs = (AVFilterPad[]) {{ .name = "default",
203 .type = AVMEDIA_TYPE_AUDIO,
204 .filter_samples = filter_samples,
205 .min_perms = AV_PERM_READ, },
207 .outputs = (AVFilterPad[]) {{ .name = NULL }},