summaryrefslogtreecommitdiff
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
parent4c66c4071830e74afa1aea3df52059ab163c1ddb (diff)
lavfi: add an audio buffer sink.
-rw-r--r--doc/filters.texi7
-rw-r--r--libavfilter/allfilters.c4
-rw-r--r--libavfilter/buffersink.c102
-rw-r--r--libavfilter/buffersink.h21
4 files changed, 129 insertions, 5 deletions
diff --git a/doc/filters.texi b/doc/filters.texi
index 8d4242607a..0314bfaf20 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -191,6 +191,13 @@ Null audio sink, do absolutely nothing with the input audio. It is
mainly useful as a template and to be employed in analysis / debugging
tools.
+@section abuffersink
+This sink is intended for programmatic use. Frames that arrive on this sink can
+be retrieved by the calling program using the interface defined in
+@file{libavfilter/buffersink.h}.
+
+This filter accepts no parameters.
+
@c man end AUDIO SINKS
@chapter Video Filters
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 25cd8222c3..c84b3f2587 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -104,6 +104,10 @@ void avfilter_register_all(void)
avfilter_register(&avfilter_vsink_buffer);
}
{
+ extern AVFilter avfilter_asink_abuffer;
+ avfilter_register(&avfilter_asink_abuffer);
+ }
+ {
extern AVFilter avfilter_vf_scale;
avfilter_register(&avfilter_vf_scale);
}
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 }},
+};
diff --git a/libavfilter/buffersink.h b/libavfilter/buffersink.h
index e579b9ad03..8f94a9c94d 100644
--- a/libavfilter/buffersink.h
+++ b/libavfilter/buffersink.h
@@ -29,7 +29,7 @@
/**
* Get a buffer with filtered data from sink and put it in buf.
*
- * @param sink pointer to a context of a buffersink AVFilter.
+ * @param sink pointer to a context of a buffersink or abuffersink AVFilter.
* @param buf pointer to the buffer will be written here if buf is non-NULL. buf
* must be freed by the caller using avfilter_unref_buffer().
* Buf may also be NULL to query whether a buffer is ready to be
@@ -40,4 +40,23 @@
*/
int av_buffersink_read(AVFilterContext *sink, AVFilterBufferRef **buf);
+/**
+ * Same as av_buffersink_read, but with the ability to specify the number of
+ * samples read. This function is less efficient than av_buffersink_read(),
+ * because it copies the data around.
+ *
+ * @param sink pointer to a context of the abuffersink AVFilter.
+ * @param buf pointer to the buffer will be written here if buf is non-NULL. buf
+ * must be freed by the caller using avfilter_unref_buffer(). buf
+ * will contain exactly nb_samples audio samples, except at the end
+ * of stream, when it can contain less than nb_samples.
+ * Buf may also be NULL to query whether a buffer is ready to be
+ * output.
+ *
+ * @warning do not mix this function with av_buffersink_read(). Use only one or
+ * the other with a single sink, not both.
+ */
+int av_buffersink_read_samples(AVFilterContext *ctx, AVFilterBufferRef **buf,
+ int nb_samples);
+
#endif /* AVFILTER_BUFFERSINK_H */