lavfi: add video buffer sink, and use it in avtools
[libav.git] / libavfilter / buffersink.c
CommitLineData
ac712309
AK
1/*
2 * Copyright (c) 2011 Stefano Sabatini
3 *
4 * This file is part of Libav.
5 *
6 * Libav is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * Libav is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with Libav; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21/**
22 * @file
23 * buffer sink
24 */
25
26#include "libavutil/fifo.h"
27
28#include "avfilter.h"
29#include "buffersink.h"
30
31typedef struct {
32 AVFifoBuffer *fifo; ///< FIFO buffer of video frame references
33} BufferSinkContext;
34
35#define FIFO_INIT_SIZE 8
36
37static av_cold void uninit(AVFilterContext *ctx)
38{
39 BufferSinkContext *sink = ctx->priv;
40
41 while (sink->fifo && av_fifo_size(sink->fifo)) {
42 AVFilterBufferRef *buf;
43 av_fifo_generic_read(sink->fifo, &buf, sizeof(buf), NULL);
44 avfilter_unref_buffer(buf);
45 }
46 av_fifo_free(sink->fifo);
47}
48
49static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
50{
51 BufferSinkContext *sink = ctx->priv;
52
53 if (!(sink->fifo = av_fifo_alloc(FIFO_INIT_SIZE*sizeof(AVFilterBufferRef*)))) {
54 av_log(ctx, AV_LOG_ERROR, "Failed to allocate fifo\n");
55 return AVERROR(ENOMEM);
56 }
57
58 return 0;
59}
60
61static void end_frame(AVFilterLink *link)
62{
63 AVFilterContext *ctx = link->dst;
64 BufferSinkContext *sink = ctx->priv;
65
66 if (av_fifo_space(sink->fifo) < sizeof(AVFilterBufferRef *) &&
67 (av_fifo_realloc2(sink->fifo, av_fifo_size(sink->fifo) * 2) < 0)) {
68 av_log(ctx, AV_LOG_ERROR, "Error reallocating the FIFO.\n");
69 return;
70 }
71
72 av_fifo_generic_write(sink->fifo, &link->cur_buf, sizeof(link->cur_buf), NULL);
73 link->cur_buf = NULL;
74}
75
76int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf)
77{
78 BufferSinkContext *sink = ctx->priv;
79 AVFilterLink *link = ctx->inputs[0];
80 int ret;
81
82 if (!buf) {
83 if (av_fifo_size(sink->fifo))
84 return av_fifo_size(sink->fifo)/sizeof(*buf);
85 else
86 return avfilter_poll_frame(ctx->inputs[0]);
87 }
88
89 if (!av_fifo_size(sink->fifo) &&
90 (ret = avfilter_request_frame(link)) < 0)
91 return ret;
92
93 if (!av_fifo_size(sink->fifo))
94 return AVERROR(EINVAL);
95
96 av_fifo_generic_read(sink->fifo, buf, sizeof(*buf), NULL);
97
98 return 0;
99}
100
101AVFilter avfilter_vsink_buffer = {
102 .name = "buffersink",
103 .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
104 .priv_size = sizeof(BufferSinkContext),
105 .init = init,
106 .uninit = uninit,
107
108 .inputs = (AVFilterPad[]) {{ .name = "default",
109 .type = AVMEDIA_TYPE_VIDEO,
110 .end_frame = end_frame,
111 .min_perms = AV_PERM_READ, },
112 { .name = NULL }},
113 .outputs = (AVFilterPad[]) {{ .name = NULL }},
114};