diff options
author | Anton Khirnov <anton@khirnov.net> | 2012-05-04 19:22:38 +0200 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2012-05-14 21:36:11 +0200 |
commit | a2cd9be212fca02dd3d6ee65cb6ab9f84c5e28e5 (patch) | |
tree | ea5dd3dbc99b98de0c872d6fd23d8f543af4a12a /libavfilter/buffersink.c | |
parent | 4c66c4071830e74afa1aea3df52059ab163c1ddb (diff) | |
download | ffmpeg-a2cd9be212fca02dd3d6ee65cb6ab9f84c5e28e5.tar.gz |
lavfi: add an audio buffer sink.
Diffstat (limited to 'libavfilter/buffersink.c')
-rw-r--r-- | libavfilter/buffersink.c | 102 |
1 files changed, 98 insertions, 4 deletions
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 }}, +}; |