Browse Source

lavfi: add an audio buffer sink.

tags/n0.11
Anton Khirnov 13 years ago
parent
commit
a2cd9be212
4 changed files with 129 additions and 5 deletions
  1. +7
    -0
      doc/filters.texi
  2. +4
    -0
      libavfilter/allfilters.c
  3. +98
    -4
      libavfilter/buffersink.c
  4. +20
    -1
      libavfilter/buffersink.h

+ 7
- 0
doc/filters.texi View File

@@ -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


+ 4
- 0
libavfilter/allfilters.c View File

@@ -103,6 +103,10 @@ void avfilter_register_all(void)
extern AVFilter avfilter_vsink_buffer;
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);


+ 98
- 4
libavfilter/buffersink.c View File

@@ -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 }},
};

+ 20
- 1
libavfilter/buffersink.h View File

@@ -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 */

Loading…
Cancel
Save