buffersrc.c
Go to the documentation of this file.
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 
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;
43 
44  /* video only */
45  int h, w;
48 
49  /* audio only */
53  uint64_t channel_layout;
55 
56  int eof;
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 
110  0, 0, frame->nb_samples,
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) {
122  return ret;
123  }
124 
125  return 0;
126 }
127 
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:
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;
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 
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 
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,
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);
261  }
262  av_fifo_free(s->fifo);
263  s->fifo = NULL;
264 }
265 
267 {
268  BufferSourceContext *c = ctx->priv;
269  AVFilterChannelLayouts *channel_layouts = 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;
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 
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 
356  .name = "buffer",
357  .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them accessible to the filterchain."),
358  .priv_size = sizeof(BufferSourceContext),
360 
361  .init = init_video,
362  .uninit = uninit,
363 
364  .inputs = NULL,
365  .outputs = avfilter_vsrc_buffer_outputs,
366 };
367 
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 
380  .name = "abuffer",
381  .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them accessible to the filterchain."),
382  .priv_size = sizeof(BufferSourceContext),
384 
385  .init = init_audio,
386  .uninit = uninit,
387 
388  .inputs = NULL,
389  .outputs = avfilter_asrc_abuffer_outputs,
390 };