]> git.sesse.net Git - ffmpeg/blob - libavfilter/buffersrc.c
vf_delogo: fix copying the input frame.
[ffmpeg] / libavfilter / buffersrc.c
1 /*
2  * Copyright (c) 2008 Vitor Sessak
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  * memory buffer source filter
24  */
25
26 #include "libavutil/channel_layout.h"
27 #include "libavutil/common.h"
28 #include "libavutil/fifo.h"
29 #include "libavutil/imgutils.h"
30 #include "libavutil/opt.h"
31 #include "libavutil/samplefmt.h"
32 #include "audio.h"
33 #include "avfilter.h"
34 #include "buffersrc.h"
35 #include "formats.h"
36 #include "internal.h"
37 #include "video.h"
38
39 typedef struct {
40     const AVClass    *class;
41     AVFifoBuffer     *fifo;
42     AVRational        time_base;     ///< time_base to set in the output link
43
44     /* video only */
45     int               h, w;
46     enum AVPixelFormat  pix_fmt;
47     AVRational        pixel_aspect;
48
49     /* audio only */
50     int sample_rate;
51     enum AVSampleFormat sample_fmt;
52     char               *sample_fmt_str;
53     uint64_t channel_layout;
54     char    *channel_layout_str;
55
56     int eof;
57 } BufferSourceContext;
58
59 #define CHECK_VIDEO_PARAM_CHANGE(s, c, width, height, format)\
60     if (c->w != width || c->h != height || c->pix_fmt != format) {\
61         av_log(s, AV_LOG_ERROR, "Changing frame properties on the fly is not supported.\n");\
62         return AVERROR(EINVAL);\
63     }
64
65 #define CHECK_AUDIO_PARAM_CHANGE(s, c, srate, ch_layout, format)\
66     if (c->sample_fmt != format || c->sample_rate != srate ||\
67         c->channel_layout != ch_layout) {\
68         av_log(s, AV_LOG_ERROR, "Changing frame properties on the fly is not supported.\n");\
69         return AVERROR(EINVAL);\
70     }
71
72 int av_buffersrc_write_frame(AVFilterContext *buffer_filter, const AVFrame *frame)
73 {
74     BufferSourceContext *c = buffer_filter->priv;
75     AVFilterBufferRef *buf;
76     int ret;
77
78     if (!frame) {
79         c->eof = 1;
80         return 0;
81     } else if (c->eof)
82         return AVERROR(EINVAL);
83
84     if (!av_fifo_space(c->fifo) &&
85         (ret = av_fifo_realloc2(c->fifo, av_fifo_size(c->fifo) +
86                                          sizeof(buf))) < 0)
87         return ret;
88
89     switch (buffer_filter->outputs[0]->type) {
90     case AVMEDIA_TYPE_VIDEO:
91         CHECK_VIDEO_PARAM_CHANGE(buffer_filter, c, frame->width, frame->height,
92                                  frame->format);
93         buf = ff_get_video_buffer(buffer_filter->outputs[0], AV_PERM_WRITE,
94                                   c->w, c->h);
95         if (!buf)
96             return AVERROR(ENOMEM);
97
98         av_image_copy(buf->data, buf->linesize, frame->data, frame->linesize,
99                       c->pix_fmt, c->w, c->h);
100         break;
101     case AVMEDIA_TYPE_AUDIO:
102         CHECK_AUDIO_PARAM_CHANGE(buffer_filter, c, frame->sample_rate, frame->channel_layout,
103                                  frame->format);
104         buf = ff_get_audio_buffer(buffer_filter->outputs[0], AV_PERM_WRITE,
105                                   frame->nb_samples);
106         if (!buf)
107             return AVERROR(ENOMEM);
108
109         av_samples_copy(buf->extended_data, frame->extended_data,
110                         0, 0, frame->nb_samples,
111                         av_get_channel_layout_nb_channels(frame->channel_layout),
112                         frame->format);
113         break;
114     default:
115         return AVERROR(EINVAL);
116     }
117
118     avfilter_copy_frame_props(buf, frame);
119
120     if ((ret = av_fifo_generic_write(c->fifo, &buf, sizeof(buf), NULL)) < 0) {
121         avfilter_unref_buffer(buf);
122         return ret;
123     }
124
125     return 0;
126 }
127
128 int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf)
129 {
130     BufferSourceContext *c = s->priv;
131     int ret;
132
133     if (!buf) {
134         c->eof = 1;
135         return 0;
136     } else if (c->eof)
137         return AVERROR(EINVAL);
138
139     if (!av_fifo_space(c->fifo) &&
140         (ret = av_fifo_realloc2(c->fifo, av_fifo_size(c->fifo) +
141                                          sizeof(buf))) < 0)
142         return ret;
143
144     switch (s->outputs[0]->type) {
145     case AVMEDIA_TYPE_VIDEO:
146         CHECK_VIDEO_PARAM_CHANGE(s, c, buf->video->w, buf->video->h, buf->format);
147         break;
148     case AVMEDIA_TYPE_AUDIO:
149         CHECK_AUDIO_PARAM_CHANGE(s, c, buf->audio->sample_rate, buf->audio->channel_layout,
150                                  buf->format);
151         break;
152     default:
153         return AVERROR(EINVAL);
154     }
155
156     if ((ret = av_fifo_generic_write(c->fifo, &buf, sizeof(buf), NULL)) < 0)
157         return ret;
158
159     return 0;
160 }
161
162 static av_cold int init_video(AVFilterContext *ctx, const char *args)
163 {
164     BufferSourceContext *c = ctx->priv;
165     char pix_fmt_str[128];
166     int n = 0;
167
168     if (!args ||
169         (n = sscanf(args, "%d:%d:%127[^:]:%d:%d:%d:%d", &c->w, &c->h, pix_fmt_str,
170                     &c->time_base.num, &c->time_base.den,
171                     &c->pixel_aspect.num, &c->pixel_aspect.den)) != 7) {
172         av_log(ctx, AV_LOG_ERROR, "Expected 7 arguments, but %d found in '%s'\n", n, args);
173         return AVERROR(EINVAL);
174     }
175     if ((c->pix_fmt = av_get_pix_fmt(pix_fmt_str)) == AV_PIX_FMT_NONE) {
176         char *tail;
177         c->pix_fmt = strtol(pix_fmt_str, &tail, 10);
178         if (*tail || c->pix_fmt < 0 || c->pix_fmt >= AV_PIX_FMT_NB) {
179             av_log(ctx, AV_LOG_ERROR, "Invalid pixel format string '%s'\n", pix_fmt_str);
180             return AVERROR(EINVAL);
181         }
182     }
183
184     if (!(c->fifo = av_fifo_alloc(sizeof(AVFilterBufferRef*))))
185         return AVERROR(ENOMEM);
186
187     av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d pixfmt:%s\n", c->w, c->h, av_get_pix_fmt_name(c->pix_fmt));
188     return 0;
189 }
190
191 #define OFFSET(x) offsetof(BufferSourceContext, x)
192 #define A AV_OPT_FLAG_AUDIO_PARAM
193 static const AVOption audio_options[] = {
194     { "time_base",      NULL, OFFSET(time_base),           AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, INT_MAX, A },
195     { "sample_rate",    NULL, OFFSET(sample_rate),         AV_OPT_TYPE_INT,      { .i64 = 0 }, 0, INT_MAX, A },
196     { "sample_fmt",     NULL, OFFSET(sample_fmt_str),      AV_OPT_TYPE_STRING,             .flags = A },
197     { "channel_layout", NULL, OFFSET(channel_layout_str),  AV_OPT_TYPE_STRING,             .flags = A },
198     { NULL },
199 };
200
201 static const AVClass abuffer_class = {
202     .class_name = "abuffer source",
203     .item_name  = av_default_item_name,
204     .option     = audio_options,
205     .version    = LIBAVUTIL_VERSION_INT,
206 };
207
208 static av_cold int init_audio(AVFilterContext *ctx, const char *args)
209 {
210     BufferSourceContext *s = ctx->priv;
211     int ret = 0;
212
213     s->class = &abuffer_class;
214     av_opt_set_defaults(s);
215
216     if ((ret = av_set_options_string(s, args, "=", ":")) < 0) {
217         av_log(ctx, AV_LOG_ERROR, "Error parsing options string: %s.\n", args);
218         goto fail;
219     }
220
221     s->sample_fmt = av_get_sample_fmt(s->sample_fmt_str);
222     if (s->sample_fmt == AV_SAMPLE_FMT_NONE) {
223         av_log(ctx, AV_LOG_ERROR, "Invalid sample format %s.\n",
224                s->sample_fmt_str);
225         ret = AVERROR(EINVAL);
226         goto fail;
227     }
228
229     s->channel_layout = av_get_channel_layout(s->channel_layout_str);
230     if (!s->channel_layout) {
231         av_log(ctx, AV_LOG_ERROR, "Invalid channel layout %s.\n",
232                s->channel_layout_str);
233         ret = AVERROR(EINVAL);
234         goto fail;
235     }
236
237     if (!(s->fifo = av_fifo_alloc(sizeof(AVFilterBufferRef*)))) {
238         ret = AVERROR(ENOMEM);
239         goto fail;
240     }
241
242     if (!s->time_base.num)
243         s->time_base = (AVRational){1, s->sample_rate};
244
245     av_log(ctx, AV_LOG_VERBOSE, "tb:%d/%d samplefmt:%s samplerate: %d "
246            "ch layout:%s\n", s->time_base.num, s->time_base.den, s->sample_fmt_str,
247            s->sample_rate, s->channel_layout_str);
248
249 fail:
250     av_opt_free(s);
251     return ret;
252 }
253
254 static av_cold void uninit(AVFilterContext *ctx)
255 {
256     BufferSourceContext *s = ctx->priv;
257     while (s->fifo && av_fifo_size(s->fifo)) {
258         AVFilterBufferRef *buf;
259         av_fifo_generic_read(s->fifo, &buf, sizeof(buf), NULL);
260         avfilter_unref_buffer(buf);
261     }
262     av_fifo_free(s->fifo);
263     s->fifo = NULL;
264 }
265
266 static int query_formats(AVFilterContext *ctx)
267 {
268     BufferSourceContext *c = ctx->priv;
269     AVFilterChannelLayouts *channel_layouts = NULL;
270     AVFilterFormats *formats = NULL;
271     AVFilterFormats *samplerates = NULL;
272
273     switch (ctx->outputs[0]->type) {
274     case AVMEDIA_TYPE_VIDEO:
275         ff_add_format(&formats, c->pix_fmt);
276         ff_set_common_formats(ctx, formats);
277         break;
278     case AVMEDIA_TYPE_AUDIO:
279         ff_add_format(&formats,           c->sample_fmt);
280         ff_set_common_formats(ctx, formats);
281
282         ff_add_format(&samplerates,       c->sample_rate);
283         ff_set_common_samplerates(ctx, samplerates);
284
285         ff_add_channel_layout(&channel_layouts, c->channel_layout);
286         ff_set_common_channel_layouts(ctx, channel_layouts);
287         break;
288     default:
289         return AVERROR(EINVAL);
290     }
291
292     return 0;
293 }
294
295 static int config_props(AVFilterLink *link)
296 {
297     BufferSourceContext *c = link->src->priv;
298
299     switch (link->type) {
300     case AVMEDIA_TYPE_VIDEO:
301         link->w = c->w;
302         link->h = c->h;
303         link->sample_aspect_ratio = c->pixel_aspect;
304         break;
305     case AVMEDIA_TYPE_AUDIO:
306         link->channel_layout = c->channel_layout;
307         link->sample_rate    = c->sample_rate;
308         break;
309     default:
310         return AVERROR(EINVAL);
311     }
312
313     link->time_base = c->time_base;
314     return 0;
315 }
316
317 static int request_frame(AVFilterLink *link)
318 {
319     BufferSourceContext *c = link->src->priv;
320     AVFilterBufferRef *buf;
321     int ret = 0;
322
323     if (!av_fifo_size(c->fifo)) {
324         if (c->eof)
325             return AVERROR_EOF;
326         return AVERROR(EAGAIN);
327     }
328     av_fifo_generic_read(c->fifo, &buf, sizeof(buf), NULL);
329
330     ff_filter_frame(link, buf);
331
332     return ret;
333 }
334
335 static int poll_frame(AVFilterLink *link)
336 {
337     BufferSourceContext *c = link->src->priv;
338     int size = av_fifo_size(c->fifo);
339     if (!size && c->eof)
340         return AVERROR_EOF;
341     return size/sizeof(AVFilterBufferRef*);
342 }
343
344 static const AVFilterPad avfilter_vsrc_buffer_outputs[] = {
345     {
346         .name          = "default",
347         .type          = AVMEDIA_TYPE_VIDEO,
348         .request_frame = request_frame,
349         .poll_frame    = poll_frame,
350         .config_props  = config_props,
351     },
352     { NULL }
353 };
354
355 AVFilter avfilter_vsrc_buffer = {
356     .name      = "buffer",
357     .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them accessible to the filterchain."),
358     .priv_size = sizeof(BufferSourceContext),
359     .query_formats = query_formats,
360
361     .init      = init_video,
362     .uninit    = uninit,
363
364     .inputs    = NULL,
365     .outputs   = avfilter_vsrc_buffer_outputs,
366 };
367
368 static const AVFilterPad avfilter_asrc_abuffer_outputs[] = {
369     {
370         .name          = "default",
371         .type          = AVMEDIA_TYPE_AUDIO,
372         .request_frame = request_frame,
373         .poll_frame    = poll_frame,
374         .config_props  = config_props,
375     },
376     { NULL }
377 };
378
379 AVFilter avfilter_asrc_abuffer = {
380     .name          = "abuffer",
381     .description   = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them accessible to the filterchain."),
382     .priv_size     = sizeof(BufferSourceContext),
383     .query_formats = query_formats,
384
385     .init      = init_audio,
386     .uninit    = uninit,
387
388     .inputs    = NULL,
389     .outputs   = avfilter_asrc_abuffer_outputs,
390 };