fifo.c 4.75 KB
Newer Older
Stefano Sabatini's avatar
Stefano Sabatini committed
1
/*
2
 * Copyright (c) 2007 Bobby Bingham
Stefano Sabatini's avatar
Stefano Sabatini committed
3
 *
4
 * This file is part of Libav.
Stefano Sabatini's avatar
Stefano Sabatini committed
5
 *
6
 * Libav is free software; you can redistribute it and/or
Stefano Sabatini's avatar
Stefano Sabatini committed
7 8 9 10
 * 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.
 *
11
 * Libav is distributed in the hope that it will be useful,
Stefano Sabatini's avatar
Stefano Sabatini committed
12 13 14 15 16
 * 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
17
 * License along with Libav; if not, write to the Free Software
Stefano Sabatini's avatar
Stefano Sabatini committed
18 19 20 21 22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/**
 * @file
23
 * FIFO buffering filter
Stefano Sabatini's avatar
Stefano Sabatini committed
24 25
 */

26
#include "audio.h"
Stefano Sabatini's avatar
Stefano Sabatini committed
27
#include "avfilter.h"
28
#include "internal.h"
29
#include "video.h"
Stefano Sabatini's avatar
Stefano Sabatini committed
30

31 32 33 34
typedef struct Buf {
    AVFilterBufferRef *buf;
    struct Buf        *next;
} Buf;
Stefano Sabatini's avatar
Stefano Sabatini committed
35 36

typedef struct {
37 38
    Buf  root;
    Buf *last;   ///< last buffered frame
Stefano Sabatini's avatar
Stefano Sabatini committed
39 40 41 42 43 44 45 46 47 48 49 50 51 52
} FifoContext;

static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
{
    FifoContext *fifo = ctx->priv;
    fifo->last = &fifo->root;

    av_log(ctx, AV_LOG_INFO, "\n");
    return 0;
}

static av_cold void uninit(AVFilterContext *ctx)
{
    FifoContext *fifo = ctx->priv;
53
    Buf *buf, *tmp;
Stefano Sabatini's avatar
Stefano Sabatini committed
54

55 56 57 58
    for (buf = fifo->root.next; buf; buf = tmp) {
        tmp = buf->next;
        avfilter_unref_buffer(buf->buf);
        av_free(buf);
Stefano Sabatini's avatar
Stefano Sabatini committed
59 60 61
    }
}

62
static void add_to_queue(AVFilterLink *inlink, AVFilterBufferRef *buf)
Stefano Sabatini's avatar
Stefano Sabatini committed
63 64 65
{
    FifoContext *fifo = inlink->dst->priv;

66
    fifo->last->next = av_mallocz(sizeof(Buf));
Stefano Sabatini's avatar
Stefano Sabatini committed
67
    fifo->last = fifo->last->next;
68
    fifo->last->buf = buf;
Stefano Sabatini's avatar
Stefano Sabatini committed
69 70 71 72 73 74 75 76 77
}

static void end_frame(AVFilterLink *inlink) { }

static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) { }

static int request_frame(AVFilterLink *outlink)
{
    FifoContext *fifo = outlink->src->priv;
78
    Buf *tmp;
Stefano Sabatini's avatar
Stefano Sabatini committed
79 80 81
    int ret;

    if (!fifo->root.next) {
82
        if ((ret = ff_request_frame(outlink->src->inputs[0])) < 0)
Stefano Sabatini's avatar
Stefano Sabatini committed
83 84 85 86 87
            return ret;
    }

    /* by doing this, we give ownership of the reference to the next filter,
     * so we don't have to worry about dereferencing it ourselves. */
88 89 90 91 92 93 94 95 96 97 98 99
    switch (outlink->type) {
    case AVMEDIA_TYPE_VIDEO:
        ff_start_frame(outlink, fifo->root.next->buf);
        ff_draw_slice (outlink, 0, outlink->h, 1);
        ff_end_frame  (outlink);
        break;
    case AVMEDIA_TYPE_AUDIO:
        ff_filter_samples(outlink, fifo->root.next->buf);
        break;
    default:
        return AVERROR(EINVAL);
    }
Stefano Sabatini's avatar
Stefano Sabatini committed
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120

    if (fifo->last == fifo->root.next)
        fifo->last = &fifo->root;
    tmp = fifo->root.next->next;
    av_free(fifo->root.next);
    fifo->root.next = tmp;

    return 0;
}

AVFilter avfilter_vf_fifo = {
    .name      = "fifo",
    .description = NULL_IF_CONFIG_SMALL("Buffer input images and send them when they are requested."),

    .init      = init,
    .uninit    = uninit,

    .priv_size = sizeof(FifoContext),

    .inputs    = (AVFilterPad[]) {{ .name            = "default",
                                    .type            = AVMEDIA_TYPE_VIDEO,
121
                                    .get_video_buffer= ff_null_get_video_buffer,
122
                                    .start_frame     = add_to_queue,
Stefano Sabatini's avatar
Stefano Sabatini committed
123 124 125 126 127 128 129 130 131
                                    .draw_slice      = draw_slice,
                                    .end_frame       = end_frame,
                                    .rej_perms       = AV_PERM_REUSE2, },
                                  { .name = NULL}},
    .outputs   = (AVFilterPad[]) {{ .name            = "default",
                                    .type            = AVMEDIA_TYPE_VIDEO,
                                    .request_frame   = request_frame, },
                                  { .name = NULL}},
};
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152

AVFilter avfilter_af_afifo = {
    .name        = "afifo",
    .description = NULL_IF_CONFIG_SMALL("Buffer input frames and send them when they are requested."),

    .init      = init,
    .uninit    = uninit,

    .priv_size = sizeof(FifoContext),

    .inputs    = (AVFilterPad[]) {{ .name             = "default",
                                    .type             = AVMEDIA_TYPE_AUDIO,
                                    .get_audio_buffer = ff_null_get_audio_buffer,
                                    .filter_samples   = add_to_queue,
                                    .rej_perms        = AV_PERM_REUSE2, },
                                  { .name = NULL}},
    .outputs   = (AVFilterPad[]) {{ .name             = "default",
                                    .type             = AVMEDIA_TYPE_AUDIO,
                                    .request_frame    = request_frame, },
                                  { .name = NULL}},
};