2 * Copyright (c) 2007 Bobby Bingham
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 * FIFO buffering filter
26 #include "libavutil/avassert.h"
27 #include "libavutil/audioconvert.h"
28 #include "libavutil/common.h"
29 #include "libavutil/mathematics.h"
30 #include "libavutil/samplefmt.h"
38 AVFilterBufferRef *buf;
44 Buf *last; ///< last buffered frame
47 * When a specific number of output samples is requested, the partial
48 * buffer is stored here
50 AVFilterBufferRef *buf_out;
51 int allocated_samples; ///< number of samples buf_out was allocated for
54 static av_cold int init(AVFilterContext *ctx, const char *args)
56 FifoContext *fifo = ctx->priv;
57 fifo->last = &fifo->root;
62 static av_cold void uninit(AVFilterContext *ctx)
64 FifoContext *fifo = ctx->priv;
67 for (buf = fifo->root.next; buf; buf = tmp) {
69 avfilter_unref_bufferp(&buf->buf);
73 avfilter_unref_bufferp(&fifo->buf_out);
76 static int add_to_queue(AVFilterLink *inlink, AVFilterBufferRef *buf)
78 FifoContext *fifo = inlink->dst->priv;
80 inlink->cur_buf = NULL;
81 fifo->last->next = av_mallocz(sizeof(Buf));
82 if (!fifo->last->next) {
83 avfilter_unref_buffer(buf);
84 return AVERROR(ENOMEM);
87 fifo->last = fifo->last->next;
88 fifo->last->buf = buf;
93 static void queue_pop(FifoContext *s)
95 Buf *tmp = s->root.next->next;
96 if (s->last == s->root.next)
98 av_freep(&s->root.next);
102 static int end_frame(AVFilterLink *inlink)
107 static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
113 * Move data pointers and pts offset samples forward.
115 static void buffer_offset(AVFilterLink *link, AVFilterBufferRef *buf,
118 int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout);
119 int planar = av_sample_fmt_is_planar(link->format);
120 int planes = planar ? nb_channels : 1;
121 int block_align = av_get_bytes_per_sample(link->format) * (planar ? 1 : nb_channels);
124 av_assert0(buf->audio->nb_samples > offset);
126 for (i = 0; i < planes; i++)
127 buf->extended_data[i] += block_align*offset;
128 if (buf->data != buf->extended_data)
129 memcpy(buf->data, buf->extended_data,
130 FFMIN(planes, FF_ARRAY_ELEMS(buf->data)) * sizeof(*buf->data));
131 buf->linesize[0] -= block_align*offset;
132 buf->audio->nb_samples -= offset;
134 if (buf->pts != AV_NOPTS_VALUE) {
135 buf->pts += av_rescale_q(offset, (AVRational){1, link->sample_rate},
140 static int calc_ptr_alignment(AVFilterBufferRef *buf)
142 int planes = av_sample_fmt_is_planar(buf->format) ?
143 av_get_channel_layout_nb_channels(buf->audio->channel_layout) : 1;
147 for (p = 0; p < planes; p++) {
149 while ((intptr_t)buf->extended_data[p] % cur_align)
151 if (cur_align < min_align)
152 min_align = cur_align;
157 static int return_audio_frame(AVFilterContext *ctx)
159 AVFilterLink *link = ctx->outputs[0];
160 FifoContext *s = ctx->priv;
161 AVFilterBufferRef *head = s->root.next->buf;
162 AVFilterBufferRef *buf_out;
166 head->audio->nb_samples >= link->request_samples &&
167 calc_ptr_alignment(head) >= 32) {
168 if (head->audio->nb_samples == link->request_samples) {
172 buf_out = avfilter_ref_buffer(head, AV_PERM_READ);
174 return AVERROR(ENOMEM);
176 buf_out->audio->nb_samples = link->request_samples;
177 buffer_offset(link, head, link->request_samples);
180 int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout);
183 s->buf_out = ff_get_audio_buffer(link, AV_PERM_WRITE,
184 link->request_samples);
186 return AVERROR(ENOMEM);
188 s->buf_out->audio->nb_samples = 0;
189 s->buf_out->pts = head->pts;
190 s->allocated_samples = link->request_samples;
191 } else if (link->request_samples != s->allocated_samples) {
192 av_log(ctx, AV_LOG_ERROR, "request_samples changed before the "
193 "buffer was returned.\n");
194 return AVERROR(EINVAL);
197 while (s->buf_out->audio->nb_samples < s->allocated_samples) {
198 int len = FFMIN(s->allocated_samples - s->buf_out->audio->nb_samples,
199 head->audio->nb_samples);
201 av_samples_copy(s->buf_out->extended_data, head->extended_data,
202 s->buf_out->audio->nb_samples, 0, len, nb_channels,
204 s->buf_out->audio->nb_samples += len;
206 if (len == head->audio->nb_samples) {
207 avfilter_unref_buffer(head);
211 (ret = ff_request_frame(ctx->inputs[0])) < 0) {
212 if (ret == AVERROR_EOF) {
213 av_samples_set_silence(s->buf_out->extended_data,
214 s->buf_out->audio->nb_samples,
215 s->allocated_samples -
216 s->buf_out->audio->nb_samples,
217 nb_channels, link->format);
218 s->buf_out->audio->nb_samples = s->allocated_samples;
223 head = s->root.next->buf;
225 buffer_offset(link, head, len);
228 buf_out = s->buf_out;
231 return ff_filter_samples(link, buf_out);
234 static int request_frame(AVFilterLink *outlink)
236 FifoContext *fifo = outlink->src->priv;
239 if (!fifo->root.next) {
240 if ((ret = ff_request_frame(outlink->src->inputs[0])) < 0)
244 /* by doing this, we give ownership of the reference to the next filter,
245 * so we don't have to worry about dereferencing it ourselves. */
246 switch (outlink->type) {
247 case AVMEDIA_TYPE_VIDEO:
248 if ((ret = ff_start_frame(outlink, fifo->root.next->buf)) < 0 ||
249 (ret = ff_draw_slice(outlink, 0, outlink->h, 1)) < 0 ||
250 (ret = ff_end_frame(outlink)) < 0)
255 case AVMEDIA_TYPE_AUDIO:
256 if (outlink->request_samples) {
257 return return_audio_frame(outlink->src);
259 ret = ff_filter_samples(outlink, fifo->root.next->buf);
264 return AVERROR(EINVAL);
270 static const AVFilterPad avfilter_vf_fifo_inputs[] = {
273 .type = AVMEDIA_TYPE_VIDEO,
274 .get_video_buffer = ff_null_get_video_buffer,
275 .start_frame = add_to_queue,
276 .draw_slice = draw_slice,
277 .end_frame = end_frame,
278 .rej_perms = AV_PERM_REUSE2,
283 static const AVFilterPad avfilter_vf_fifo_outputs[] = {
286 .type = AVMEDIA_TYPE_VIDEO,
287 .request_frame = request_frame,
292 AVFilter avfilter_vf_fifo = {
294 .description = NULL_IF_CONFIG_SMALL("Buffer input images and send them when they are requested."),
299 .priv_size = sizeof(FifoContext),
301 .inputs = avfilter_vf_fifo_inputs,
302 .outputs = avfilter_vf_fifo_outputs,
305 static const AVFilterPad avfilter_af_afifo_inputs[] = {
308 .type = AVMEDIA_TYPE_AUDIO,
309 .get_audio_buffer = ff_null_get_audio_buffer,
310 .filter_samples = add_to_queue,
311 .rej_perms = AV_PERM_REUSE2,
316 static const AVFilterPad avfilter_af_afifo_outputs[] = {
319 .type = AVMEDIA_TYPE_AUDIO,
320 .request_frame = request_frame,
325 AVFilter avfilter_af_afifo = {
327 .description = NULL_IF_CONFIG_SMALL("Buffer input frames and send them when they are requested."),
332 .priv_size = sizeof(FifoContext),
334 .inputs = avfilter_af_afifo_inputs,
335 .outputs = avfilter_af_afifo_outputs,