summaryrefslogtreecommitdiff
path: root/libavfilter/buffersink.c
diff options
context:
space:
mode:
authorAnton Khirnov <anton@khirnov.net>2012-05-04 19:22:38 +0200
committerAnton Khirnov <anton@khirnov.net>2012-05-14 21:36:11 +0200
commita2cd9be212fca02dd3d6ee65cb6ab9f84c5e28e5 (patch)
treeea5dd3dbc99b98de0c872d6fd23d8f543af4a12a /libavfilter/buffersink.c
parent4c66c4071830e74afa1aea3df52059ab163c1ddb (diff)
lavfi: add an audio buffer sink.
Diffstat (limited to 'libavfilter/buffersink.c')
-rw-r--r--libavfilter/buffersink.c102
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 }},
+};