diff options
| author | Anton Khirnov <[email protected]> | 2012-05-04 19:22:38 +0200 | 
|---|---|---|
| committer | Anton Khirnov <[email protected]> | 2012-05-14 21:36:11 +0200 | 
| commit | a2cd9be212fca02dd3d6ee65cb6ab9f84c5e28e5 (patch) | |
| tree | ea5dd3dbc99b98de0c872d6fd23d8f543af4a12a | |
| parent | 4c66c4071830e74afa1aea3df52059ab163c1ddb (diff) | |
lavfi: add an audio buffer sink.
| -rw-r--r-- | doc/filters.texi | 7 | ||||
| -rw-r--r-- | libavfilter/allfilters.c | 4 | ||||
| -rw-r--r-- | libavfilter/buffersink.c | 102 | ||||
| -rw-r--r-- | libavfilter/buffersink.h | 21 | 
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 */  | 
