lavfi: add an audio buffer sink.
This commit is contained in:
parent
4c66c40718
commit
a2cd9be212
@ -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
|
mainly useful as a template and to be employed in analysis / debugging
|
||||||
tools.
|
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
|
@c man end AUDIO SINKS
|
||||||
|
|
||||||
@chapter Video Filters
|
@chapter Video Filters
|
||||||
|
@ -103,6 +103,10 @@ void avfilter_register_all(void)
|
|||||||
extern AVFilter avfilter_vsink_buffer;
|
extern AVFilter avfilter_vsink_buffer;
|
||||||
avfilter_register(&avfilter_vsink_buffer);
|
avfilter_register(&avfilter_vsink_buffer);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
extern AVFilter avfilter_asink_abuffer;
|
||||||
|
avfilter_register(&avfilter_asink_abuffer);
|
||||||
|
}
|
||||||
{
|
{
|
||||||
extern AVFilter avfilter_vf_scale;
|
extern AVFilter avfilter_vf_scale;
|
||||||
avfilter_register(&avfilter_vf_scale);
|
avfilter_register(&avfilter_vf_scale);
|
||||||
|
@ -23,13 +23,20 @@
|
|||||||
* buffer sink
|
* buffer sink
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "libavutil/audio_fifo.h"
|
||||||
|
#include "libavutil/audioconvert.h"
|
||||||
#include "libavutil/fifo.h"
|
#include "libavutil/fifo.h"
|
||||||
|
#include "libavutil/mathematics.h"
|
||||||
|
|
||||||
|
#include "audio.h"
|
||||||
#include "avfilter.h"
|
#include "avfilter.h"
|
||||||
#include "buffersink.h"
|
#include "buffersink.h"
|
||||||
|
|
||||||
typedef struct {
|
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;
|
} BufferSinkContext;
|
||||||
|
|
||||||
#define FIFO_INIT_SIZE 8
|
#define FIFO_INIT_SIZE 8
|
||||||
@ -44,6 +51,9 @@ static av_cold void uninit(AVFilterContext *ctx)
|
|||||||
avfilter_unref_buffer(buf);
|
avfilter_unref_buffer(buf);
|
||||||
}
|
}
|
||||||
av_fifo_free(sink->fifo);
|
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)
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void end_frame(AVFilterLink *link)
|
static void write_buf(AVFilterContext *ctx, AVFilterBufferRef *buf)
|
||||||
{
|
{
|
||||||
AVFilterContext *ctx = link->dst;
|
|
||||||
BufferSinkContext *sink = ctx->priv;
|
BufferSinkContext *sink = ctx->priv;
|
||||||
|
|
||||||
if (av_fifo_space(sink->fifo) < sizeof(AVFilterBufferRef *) &&
|
if (av_fifo_space(sink->fifo) < sizeof(AVFilterBufferRef *) &&
|
||||||
@ -69,10 +78,20 @@ static void end_frame(AVFilterLink *link)
|
|||||||
return;
|
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;
|
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)
|
int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf)
|
||||||
{
|
{
|
||||||
BufferSinkContext *sink = ctx->priv;
|
BufferSinkContext *sink = ctx->priv;
|
||||||
@ -98,6 +117,66 @@ int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf)
|
|||||||
return 0;
|
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 = {
|
AVFilter avfilter_vsink_buffer = {
|
||||||
.name = "buffersink",
|
.name = "buffersink",
|
||||||
.description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
|
.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 }},
|
{ .name = NULL }},
|
||||||
.outputs = (AVFilterPad[]) {{ .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 }},
|
||||||
|
};
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
/**
|
/**
|
||||||
* Get a buffer with filtered data from sink and put it in buf.
|
* 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
|
* @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().
|
* must be freed by the caller using avfilter_unref_buffer().
|
||||||
* Buf may also be NULL to query whether a buffer is ready to be
|
* 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);
|
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 */
|
#endif /* AVFILTER_BUFFERSINK_H */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user