FFmpeg
sink_buffer.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011 Stefano Sabatini
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg 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  * FFmpeg 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 FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
26 #include "libavutil/avassert.h"
28 #include "libavutil/fifo.h"
29 #include "avfilter.h"
30 #include "buffersink.h"
31 #include "audio.h"
32 #include "internal.h"
33 
35 {
36  static const int pixel_fmts[] = { AV_PIX_FMT_NONE };
38  if (!params)
39  return NULL;
40 
41  params->pixel_fmts = pixel_fmts;
42  return params;
43 }
44 
46 {
48 
49  if (!params)
50  return NULL;
51  return params;
52 }
53 
54 typedef struct {
56  unsigned warning_limit;
57 
58  /* only used for video */
60 
61  /* only used for audio */
63  int64_t *channel_layouts;
65  int *sample_rates;
67 
68 #define FIFO_INIT_SIZE 8
69 
71 {
72  BufferSinkContext *buf = ctx->priv;
73 
75  if (!buf->fifo) {
76  av_log(ctx, AV_LOG_ERROR, "Failed to allocate fifo\n");
77  return AVERROR(ENOMEM);
78  }
79  buf->warning_limit = 100;
80  return 0;
81 }
82 
84 {
85  BufferSinkContext *buf = ctx->priv;
86  AVFilterBufferRef *picref;
87 
88  if (buf->fifo) {
89  while (av_fifo_size(buf->fifo) >= sizeof(AVFilterBufferRef *)) {
90  av_fifo_generic_read(buf->fifo, &picref, sizeof(picref), NULL);
91  avfilter_unref_buffer(picref);
92  }
93  av_fifo_free(buf->fifo);
94  buf->fifo = NULL;
95  }
96 }
97 
99 {
100  BufferSinkContext *buf = ctx->priv;
101 
102  if (av_fifo_space(buf->fifo) < sizeof(AVFilterBufferRef *)) {
103  /* realloc fifo size */
104  if (av_fifo_realloc2(buf->fifo, av_fifo_size(buf->fifo) * 2) < 0) {
105  av_log(ctx, AV_LOG_ERROR,
106  "Cannot buffer more frames. Consume some available frames "
107  "before adding new ones.\n");
108  return AVERROR(ENOMEM);
109  }
110  }
111 
112  /* cache frame */
113  av_fifo_generic_write(buf->fifo, &ref, sizeof(AVFilterBufferRef *), NULL);
114  return 0;
115 }
116 
117 static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *ref)
118 {
119  AVFilterContext *ctx = inlink->dst;
120  BufferSinkContext *buf = inlink->dst->priv;
121  int ret;
122 
123  if ((ret = add_buffer_ref(ctx, ref)) < 0)
124  return ret;
125  if (buf->warning_limit &&
126  av_fifo_size(buf->fifo) / sizeof(AVFilterBufferRef *) >= buf->warning_limit) {
127  av_log(ctx, AV_LOG_WARNING,
128  "%d buffers queued in %s, something may be wrong.\n",
129  buf->warning_limit,
130  (char *)av_x_if_null(ctx->name, ctx->filter->name));
131  buf->warning_limit *= 10;
132  }
133  return 0;
134 }
135 
137 {
138  AVFilterLink *inlink = ctx->inputs[0];
139 
140  inlink->min_samples = inlink->max_samples =
141  inlink->partial_buf_size = frame_size;
142 }
143 
145  AVFilterBufferRef **bufref, int flags)
146 {
147  BufferSinkContext *buf = ctx->priv;
148  AVFilterLink *inlink = ctx->inputs[0];
149  int ret;
150  *bufref = NULL;
151 
152  av_assert0( !strcmp(ctx->filter->name, "buffersink")
153  || !strcmp(ctx->filter->name, "abuffersink")
154  || !strcmp(ctx->filter->name, "ffbuffersink")
155  || !strcmp(ctx->filter->name, "ffabuffersink"));
156 
157  /* no picref available, fetch it from the filterchain */
158  if (!av_fifo_size(buf->fifo)) {
159  if (flags & AV_BUFFERSINK_FLAG_NO_REQUEST)
160  return AVERROR(EAGAIN);
161  if ((ret = ff_request_frame(inlink)) < 0)
162  return ret;
163  }
164 
165  if (!av_fifo_size(buf->fifo))
166  return AVERROR(EINVAL);
167 
168  if (flags & AV_BUFFERSINK_FLAG_PEEK)
169  *bufref = *((AVFilterBufferRef **)av_fifo_peek2(buf->fifo, 0));
170  else
171  av_fifo_generic_read(buf->fifo, bufref, sizeof(*bufref), NULL);
172 
173  return 0;
174 }
175 
177 {
178  av_assert0( !strcmp(ctx->filter->name, "buffersink")
179  || !strcmp(ctx->filter->name, "ffbuffersink"));
180 
181  return ctx->inputs[0]->frame_rate;
182 }
183 
185 {
186  BufferSinkContext *buf = ctx->priv;
187  AVFilterLink *inlink = ctx->inputs[0];
188 
189  av_assert0( !strcmp(ctx->filter->name, "buffersink")
190  || !strcmp(ctx->filter->name, "abuffersink")
191  || !strcmp(ctx->filter->name, "ffbuffersink")
192  || !strcmp(ctx->filter->name, "ffabuffersink"));
193 
194  return av_fifo_size(buf->fifo)/sizeof(AVFilterBufferRef *) + ff_poll_frame(inlink);
195 }
196 
197 static av_cold int vsink_init(AVFilterContext *ctx, const char *args, void *opaque)
198 {
199  BufferSinkContext *buf = ctx->priv;
200  AVBufferSinkParams *params = opaque;
201 
202  if (params && params->pixel_fmts) {
203  const int *pixel_fmts = params->pixel_fmts;
204 
205  buf->pixel_fmts = ff_copy_int_list(pixel_fmts);
206  if (!buf->pixel_fmts)
207  return AVERROR(ENOMEM);
208  }
209 
210  return common_init(ctx);
211 }
212 
214 {
215  BufferSinkContext *buf = ctx->priv;
216  av_freep(&buf->pixel_fmts);
217  common_uninit(ctx);
218 }
219 
221 {
222  BufferSinkContext *buf = ctx->priv;
223 
224  if (buf->pixel_fmts)
226  else
228 
229  return 0;
230 }
231 
233  {
234  .name = "default",
235  .type = AVMEDIA_TYPE_VIDEO,
236  .filter_frame = filter_frame,
237  .min_perms = AV_PERM_READ | AV_PERM_PRESERVE,
238  },
239  { NULL },
240 };
241 
243  .name = "ffbuffersink",
244  .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
245  .priv_size = sizeof(BufferSinkContext),
246  .init_opaque = vsink_init,
247  .uninit = vsink_uninit,
248 
250  .inputs = ffbuffersink_inputs,
251  .outputs = NULL,
252 };
253 
254 static const AVFilterPad buffersink_inputs[] = {
255  {
256  .name = "default",
257  .type = AVMEDIA_TYPE_VIDEO,
258  .filter_frame = filter_frame,
259  .min_perms = AV_PERM_READ | AV_PERM_PRESERVE,
260  },
261  { NULL },
262 };
263 
265  .name = "buffersink",
266  .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
267  .priv_size = sizeof(BufferSinkContext),
268  .init_opaque = vsink_init,
269  .uninit = vsink_uninit,
270 
272  .inputs = buffersink_inputs,
273  .outputs = NULL,
274 };
275 
276 static int64_t *concat_channels_lists(const int64_t *layouts, const int *counts)
277 {
278  int nb_layouts = 0, nb_counts = 0, i;
279  int64_t *list;
280 
281  if (layouts)
282  for (; layouts[nb_layouts] != -1; nb_layouts++);
283  if (counts)
284  for (; counts[nb_counts] != -1; nb_counts++);
285  if (nb_counts > INT_MAX - 1 - nb_layouts)
286  return NULL;
287  if (!(list = av_calloc(nb_layouts + nb_counts + 1, sizeof(*list))))
288  return NULL;
289  for (i = 0; i < nb_layouts; i++)
290  list[i] = layouts[i];
291  for (i = 0; i < nb_counts; i++)
292  list[nb_layouts + i] = FF_COUNT2LAYOUT(counts[i]);
293  list[nb_layouts + nb_counts] = -1;
294  return list;
295 }
296 
297 static av_cold int asink_init(AVFilterContext *ctx, const char *args, void *opaque)
298 {
299  BufferSinkContext *buf = ctx->priv;
300  AVABufferSinkParams *params = opaque;
301 
302  if (params && params->sample_fmts) {
303  buf->sample_fmts = ff_copy_int_list(params->sample_fmts);
304  if (!buf->sample_fmts)
305  return AVERROR(ENOMEM);
306  }
307  if (params && params->sample_rates) {
309  if (!buf->sample_rates)
310  return AVERROR(ENOMEM);
311  }
312  if (params && (params->channel_layouts || params->channel_counts)) {
313  if (params->all_channel_counts) {
314  av_log(ctx, AV_LOG_ERROR,
315  "Conflicting all_channel_counts and list in parameters\n");
316  return AVERROR(EINVAL);
317  }
319  params->channel_counts);
320  if (!buf->channel_layouts)
321  return AVERROR(ENOMEM);
322  }
323  if (params)
324  buf->all_channel_counts = params->all_channel_counts;
325  return common_init(ctx);
326 }
327 
329 {
330  BufferSinkContext *buf = ctx->priv;
331 
332  av_freep(&buf->sample_fmts);
333  av_freep(&buf->sample_rates);
334  av_freep(&buf->channel_layouts);
335  common_uninit(ctx);
336 }
337 
339 {
340  BufferSinkContext *buf = ctx->priv;
343 
344  if (buf->sample_fmts) {
345  if (!(formats = ff_make_format_list(buf->sample_fmts)))
346  return AVERROR(ENOMEM);
347  ff_set_common_formats(ctx, formats);
348  }
349 
350  if (buf->channel_layouts || buf->all_channel_counts) {
351  layouts = buf->all_channel_counts ? ff_all_channel_counts() :
353  if (!layouts)
354  return AVERROR(ENOMEM);
355  ff_set_common_channel_layouts(ctx, layouts);
356  }
357 
358  if (buf->sample_rates) {
359  formats = ff_make_format_list(buf->sample_rates);
360  if (!formats)
361  return AVERROR(ENOMEM);
362  ff_set_common_samplerates(ctx, formats);
363  }
364 
365  return 0;
366 }
367 
369  {
370  .name = "default",
371  .type = AVMEDIA_TYPE_AUDIO,
372  .filter_frame = filter_frame,
373  .min_perms = AV_PERM_READ | AV_PERM_PRESERVE,
374  },
375  { NULL },
376 };
377 
379  .name = "ffabuffersink",
380  .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."),
381  .init_opaque = asink_init,
382  .uninit = asink_uninit,
383  .priv_size = sizeof(BufferSinkContext),
385  .inputs = ffabuffersink_inputs,
386  .outputs = NULL,
387 };
388 
389 static const AVFilterPad abuffersink_inputs[] = {
390  {
391  .name = "default",
392  .type = AVMEDIA_TYPE_AUDIO,
393  .filter_frame = filter_frame,
394  .min_perms = AV_PERM_READ | AV_PERM_PRESERVE,
395  },
396  { NULL },
397 };
398 
400  .name = "abuffersink",
401  .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."),
402  .init_opaque = asink_init,
403  .uninit = asink_uninit,
404  .priv_size = sizeof(BufferSinkContext),
406  .inputs = abuffersink_inputs,
407  .outputs = NULL,
408 };
409 
410 /* Libav compatibility API */
411 
414 
416 {
417  AVFilterBufferRef *tbuf;
418  int ret;
419 
420  if (ctx->filter-> inputs[0].start_frame ==
421  avfilter_vsink_buffer. inputs[0].start_frame ||
422  ctx->filter-> inputs[0].filter_frame ==
423  avfilter_asink_abuffer.inputs[0].filter_frame)
424  return ff_buffersink_read_compat(ctx, buf);
425  av_assert0(ctx->filter-> inputs[0].end_frame ==
426  avfilter_vsink_ffbuffersink. inputs[0].end_frame ||
427  ctx->filter-> inputs[0].filter_frame ==
428  avfilter_asink_ffabuffersink.inputs[0].filter_frame);
429 
430  ret = av_buffersink_get_buffer_ref(ctx, &tbuf,
431  buf ? 0 : AV_BUFFERSINK_FLAG_PEEK);
432  if (!buf)
433  return ret >= 0;
434  if (ret < 0)
435  return ret;
436  *buf = tbuf;
437  return 0;
438 }
439 
441  int nb_samples)
442 {
443  BufferSinkContext *sink = ctx->priv;
444  int ret = 0, have_samples = 0, need_samples;
445  AVFilterBufferRef *tbuf, *in_buf;
446  AVFilterLink *link = ctx->inputs[0];
448 
449  if (ctx->filter-> inputs[0].filter_frame ==
450  avfilter_asink_abuffer.inputs[0].filter_frame)
451  return ff_buffersink_read_samples_compat(ctx, buf, nb_samples);
452  av_assert0(ctx->filter-> inputs[0].filter_frame ==
453  avfilter_asink_ffabuffersink.inputs[0].filter_frame);
454 
455  tbuf = ff_get_audio_buffer(link, AV_PERM_WRITE, nb_samples);
456  if (!tbuf)
457  return AVERROR(ENOMEM);
458 
459  while (have_samples < nb_samples) {
460  ret = av_buffersink_get_buffer_ref(ctx, &in_buf,
462  if (ret < 0) {
463  if (ret == AVERROR_EOF && have_samples) {
464  nb_samples = have_samples;
465  ret = 0;
466  }
467  break;
468  }
469 
470  need_samples = FFMIN(in_buf->audio->nb_samples,
471  nb_samples - have_samples);
473  have_samples, 0, need_samples,
474  nb_channels, in_buf->format);
475  have_samples += need_samples;
476  if (need_samples < in_buf->audio->nb_samples) {
477  in_buf->audio->nb_samples -= need_samples;
479  0, need_samples, in_buf->audio->nb_samples,
480  nb_channels, in_buf->format);
481  } else {
482  av_buffersink_get_buffer_ref(ctx, &in_buf, 0);
483  avfilter_unref_buffer(in_buf);
484  }
485  }
486  tbuf->audio->nb_samples = have_samples;
487 
488  if (ret < 0) {
489  av_assert0(!av_fifo_size(sink->fifo));
490  if (have_samples)
491  add_buffer_ref(ctx, tbuf);
492  else
493  avfilter_unref_buffer(tbuf);
494  return ret;
495  }
496 
497  *buf = tbuf;
498  return 0;
499 }