mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2024-12-25 08:42:39 +00:00
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
|
||||
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
|
||||
|
@ -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);
|
||||
|
@ -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 }},
|
||||
};
|
||||
|
@ -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…
Reference in New Issue
Block a user