buffersink.c 7.29 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * Copyright (c) 2011 Stefano Sabatini
 *
 * This file is part of Libav.
 *
 * Libav is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * Libav is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with Libav; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/**
 * @file
 * buffer sink
 */

26
#include "libavutil/audio_fifo.h"
27
#include "libavutil/avassert.h"
28
#include "libavutil/channel_layout.h"
29
#include "libavutil/common.h"
30
#include "libavutil/internal.h"
31
#include "libavutil/mathematics.h"
32

33
#include "audio.h"
34 35
#include "avfilter.h"
#include "buffersink.h"
36
#include "internal.h"
37

38
typedef struct BufferSinkContext {
39
    AVFrame *cur_frame;          ///< last frame delivered on the sink
40
    AVAudioFifo *audio_fifo;     ///< FIFO for audio samples
41
    int64_t next_pts;            ///< interpolating audio pts
42 43 44 45 46 47
} BufferSinkContext;

static av_cold void uninit(AVFilterContext *ctx)
{
    BufferSinkContext *sink = ctx->priv;

48 49
    if (sink->audio_fifo)
        av_audio_fifo_free(sink->audio_fifo);
50 51
}

52
static int filter_frame(AVFilterLink *link, AVFrame *frame)
53
{
54
    BufferSinkContext *s = link->dst->priv;
55

56 57
    av_assert0(!s->cur_frame);
    s->cur_frame = frame;
58

59
    return 0;
60
}
61

62 63
int attribute_align_arg av_buffersink_get_frame(AVFilterContext *ctx,
                                                AVFrame *frame)
64
{
65
    BufferSinkContext *s    = ctx->priv;
66 67 68
    AVFilterLink      *link = ctx->inputs[0];
    int ret;

69
    if ((ret = ff_request_frame(link)) < 0)
70 71
        return ret;

72
    if (!s->cur_frame)
73 74
        return AVERROR(EINVAL);

75 76
    av_frame_move_ref(frame, s->cur_frame);
    av_frame_free(&s->cur_frame);
77 78 79 80

    return 0;
}

81
static int read_from_fifo(AVFilterContext *ctx, AVFrame *frame,
82 83 84 85
                          int nb_samples)
{
    BufferSinkContext *s = ctx->priv;
    AVFilterLink   *link = ctx->inputs[0];
86
    AVFrame *tmp;
87

88
    if (!(tmp = ff_get_audio_buffer(link, nb_samples)))
89
        return AVERROR(ENOMEM);
90
    av_audio_fifo_read(s->audio_fifo, (void**)tmp->extended_data, nb_samples);
91

92
    tmp->pts = s->next_pts;
93 94 95
    s->next_pts += av_rescale_q(nb_samples, (AVRational){1, link->sample_rate},
                                link->time_base);

96 97 98
    av_frame_move_ref(frame, tmp);
    av_frame_free(&tmp);

99 100 101
    return 0;
}

102 103
int attribute_align_arg av_buffersink_get_samples(AVFilterContext *ctx,
                                                  AVFrame *frame, int nb_samples)
104 105 106 107 108 109 110 111 112 113 114 115 116
{
    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) {
        if (av_audio_fifo_size(s->audio_fifo) >= nb_samples)
117
            return read_from_fifo(ctx, frame, nb_samples);
118

119
        ret = ff_request_frame(link);
120
        if (ret == AVERROR_EOF && av_audio_fifo_size(s->audio_fifo))
121
            return read_from_fifo(ctx, frame, av_audio_fifo_size(s->audio_fifo));
122 123 124
        else if (ret < 0)
            return ret;

125 126
        if (s->cur_frame->pts != AV_NOPTS_VALUE) {
            s->next_pts = s->cur_frame->pts -
127 128 129 130 131
                          av_rescale_q(av_audio_fifo_size(s->audio_fifo),
                                       (AVRational){ 1, link->sample_rate },
                                       link->time_base);
        }

132 133 134
        ret = av_audio_fifo_write(s->audio_fifo, (void**)s->cur_frame->extended_data,
                                  s->cur_frame->nb_samples);
        av_frame_free(&s->cur_frame);
135 136 137
    }

    return ret;
138 139 140
}

#if FF_API_AVFILTERBUFFER
141
FF_DISABLE_DEPRECATION_WARNINGS
142 143 144 145 146 147 148
static void compat_free_buffer(AVFilterBuffer *buf)
{
    AVFrame *frame = buf->priv;
    av_frame_free(&frame);
    av_free(buf);
}

149 150
static int compat_read(AVFilterContext *ctx,
                       AVFilterBufferRef **pbuf, int nb_samples)
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
{
    AVFilterBufferRef *buf;
    AVFrame *frame;
    int ret;

    if (!pbuf)
        return ff_poll_frame(ctx->inputs[0]);

    frame = av_frame_alloc();
    if (!frame)
        return AVERROR(ENOMEM);

    if (!nb_samples)
        ret = av_buffersink_get_frame(ctx, frame);
    else
        ret = av_buffersink_get_samples(ctx, frame, nb_samples);

    if (ret < 0)
        goto fail;

    if (ctx->inputs[0]->type == AVMEDIA_TYPE_VIDEO) {
        buf = avfilter_get_video_buffer_ref_from_arrays(frame->data, frame->linesize,
                                                        AV_PERM_READ,
                                                        frame->width, frame->height,
                                                        frame->format);
    } else {
        buf = avfilter_get_audio_buffer_ref_from_arrays(frame->extended_data,
                                                        frame->linesize[0], AV_PERM_READ,
                                                        frame->nb_samples,
                                                        frame->format,
                                                        frame->channel_layout);
    }
    if (!buf) {
        ret = AVERROR(ENOMEM);
        goto fail;
    }

    avfilter_copy_frame_props(buf, frame);

    buf->buf->priv = frame;
    buf->buf->free = compat_free_buffer;

    *pbuf = buf;

    return 0;
fail:
    av_frame_free(&frame);
    return ret;
}

201
int attribute_align_arg av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf)
202 203 204 205
{
    return compat_read(ctx, buf, 0);
}

206
int attribute_align_arg av_buffersink_read_samples(AVFilterContext *ctx, AVFilterBufferRef **buf,
207
                                                   int nb_samples)
208 209
{
    return compat_read(ctx, buf, nb_samples);
210
}
211
FF_ENABLE_DEPRECATION_WARNINGS
212
#endif
213

214 215
static const AVFilterPad avfilter_vsink_buffer_inputs[] = {
    {
216 217
        .name         = "default",
        .type         = AVMEDIA_TYPE_VIDEO,
218
        .filter_frame = filter_frame,
219
        .needs_fifo   = 1
220 221 222 223
    },
    { NULL }
};

224
AVFilter ff_vsink_buffer = {
225
    .name        = "buffersink",
226
    .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
227 228
    .priv_size   = sizeof(BufferSinkContext),
    .uninit      = uninit,
229

230 231
    .inputs      = avfilter_vsink_buffer_inputs,
    .outputs     = NULL,
232
};
233

234 235
static const AVFilterPad avfilter_asink_abuffer_inputs[] = {
    {
236 237 238 239
        .name         = "default",
        .type         = AVMEDIA_TYPE_AUDIO,
        .filter_frame = filter_frame,
        .needs_fifo   = 1
240 241 242 243
    },
    { NULL }
};

244
AVFilter ff_asink_abuffer = {
245
    .name        = "abuffersink",
246
    .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."),
247 248
    .priv_size   = sizeof(BufferSinkContext),
    .uninit      = uninit,
249

250 251
    .inputs      = avfilter_asink_abuffer_inputs,
    .outputs     = NULL,
252
};