From a2cd9be212fca02dd3d6ee65cb6ab9f84c5e28e5 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Fri, 4 May 2012 19:22:38 +0200 Subject: lavfi: add an audio buffer sink. --- libavfilter/buffersink.c | 102 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 98 insertions(+), 4 deletions(-) (limited to 'libavfilter/buffersink.c') diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c index e4cbe3be42..8787268f4c 100644 --- a/libavfilter/buffersink.c +++ b/libavfilter/buffersink.c @@ -23,13 +23,20 @@ * buffer sink */ +#include "libavutil/audio_fifo.h" +#include "libavutil/audioconvert.h" #include "libavutil/fifo.h" +#include "libavutil/mathematics.h" +#include "audio.h" #include "avfilter.h" #include "buffersink.h" typedef struct { - AVFifoBuffer *fifo; ///< FIFO buffer of video frame references + AVFifoBuffer *fifo; ///< FIFO buffer of frame references + + AVAudioFifo *audio_fifo; ///< FIFO for audio samples + int64_t next_pts; ///< interpolating audio pts } BufferSinkContext; #define FIFO_INIT_SIZE 8 @@ -44,6 +51,9 @@ static av_cold void uninit(AVFilterContext *ctx) avfilter_unref_buffer(buf); } av_fifo_free(sink->fifo); + + if (sink->audio_fifo) + av_audio_fifo_free(sink->audio_fifo); } static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) @@ -58,9 +68,8 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) return 0; } -static void end_frame(AVFilterLink *link) +static void write_buf(AVFilterContext *ctx, AVFilterBufferRef *buf) { - AVFilterContext *ctx = link->dst; BufferSinkContext *sink = ctx->priv; if (av_fifo_space(sink->fifo) < sizeof(AVFilterBufferRef *) && @@ -69,10 +78,20 @@ static void end_frame(AVFilterLink *link) return; } - av_fifo_generic_write(sink->fifo, &link->cur_buf, sizeof(link->cur_buf), NULL); + av_fifo_generic_write(sink->fifo, &buf, sizeof(buf), NULL); +} + +static void end_frame(AVFilterLink *link) +{ + write_buf(link->dst, link->cur_buf); link->cur_buf = NULL; } +static void filter_samples(AVFilterLink *link, AVFilterBufferRef *buf) +{ + write_buf(link->dst, buf); +} + int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf) { BufferSinkContext *sink = ctx->priv; @@ -98,6 +117,66 @@ int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf) return 0; } +static int read_from_fifo(AVFilterContext *ctx, AVFilterBufferRef **pbuf, + int nb_samples) +{ + BufferSinkContext *s = ctx->priv; + AVFilterLink *link = ctx->inputs[0]; + AVFilterBufferRef *buf; + + if (!(buf = ff_get_audio_buffer(link, AV_PERM_WRITE, nb_samples))) + return AVERROR(ENOMEM); + av_audio_fifo_read(s->audio_fifo, (void**)buf->extended_data, nb_samples); + + buf->pts = s->next_pts; + s->next_pts += av_rescale_q(nb_samples, (AVRational){1, link->sample_rate}, + link->time_base); + + *pbuf = buf; + return 0; + +} + +int av_buffersink_read_samples(AVFilterContext *ctx, AVFilterBufferRef **pbuf, + int nb_samples) +{ + BufferSinkContext *s = ctx->priv; + AVFilterLink *link = ctx->inputs[0]; + int ret = 0; + + if (!s->audio_fifo) { + int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout); + if (!(s->audio_fifo = av_audio_fifo_alloc(link->format, nb_channels, nb_samples))) + return AVERROR(ENOMEM); + } + + while (ret >= 0) { + AVFilterBufferRef *buf; + + if (av_audio_fifo_size(s->audio_fifo) >= nb_samples) + return read_from_fifo(ctx, pbuf, nb_samples); + + ret = av_buffersink_read(ctx, &buf); + if (ret == AVERROR_EOF && av_audio_fifo_size(s->audio_fifo)) + return read_from_fifo(ctx, pbuf, av_audio_fifo_size(s->audio_fifo)); + else if (ret < 0) + return ret; + + if (buf->pts != AV_NOPTS_VALUE) { + s->next_pts = buf->pts - + av_rescale_q(av_audio_fifo_size(s->audio_fifo), + (AVRational){ 1, link->sample_rate }, + link->time_base); + } + + ret = av_audio_fifo_write(s->audio_fifo, (void**)buf->extended_data, + buf->audio->nb_samples); + avfilter_unref_buffer(buf); + } + + return ret; +} + AVFilter avfilter_vsink_buffer = { .name = "buffersink", .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."), @@ -112,3 +191,18 @@ AVFilter avfilter_vsink_buffer = { { .name = NULL }}, .outputs = (AVFilterPad[]) {{ .name = NULL }}, }; + +AVFilter avfilter_asink_abuffer = { + .name = "abuffersink", + .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."), + .priv_size = sizeof(BufferSinkContext), + .init = init, + .uninit = uninit, + + .inputs = (AVFilterPad[]) {{ .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .filter_samples = filter_samples, + .min_perms = AV_PERM_READ, }, + { .name = NULL }}, + .outputs = (AVFilterPad[]) {{ .name = NULL }}, +}; -- cgit v1.2.3