FFmpeg
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 
21 /**
22  * @file
23  * buffer sink
24  */
25 
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 {
47  static const int sample_fmts[] = { AV_SAMPLE_FMT_NONE };
48  static const int64_t channel_layouts[] = { -1 };
50 
51  if (!params)
52  return NULL;
53 
54  params->sample_fmts = sample_fmts;
55  params->channel_layouts = channel_layouts;
56  return params;
57 }
58 
59 typedef struct {
60  AVFifoBuffer *fifo; ///< FIFO buffer of video frame references
61  unsigned warning_limit;
62 
63  /* only used for video */
64  enum AVPixelFormat *pixel_fmts; ///< list of accepted pixel formats, must be terminated with -1
65 
66  /* only used for audio */
67  enum AVSampleFormat *sample_fmts; ///< list of accepted sample formats, terminated by AV_SAMPLE_FMT_NONE
68  int64_t *channel_layouts; ///< list of accepted channel layouts, terminated by -1
70 
71 #define FIFO_INIT_SIZE 8
72 
74 {
75  BufferSinkContext *buf = ctx->priv;
76 
78  if (!buf->fifo) {
79  av_log(ctx, AV_LOG_ERROR, "Failed to allocate fifo\n");
80  return AVERROR(ENOMEM);
81  }
82  buf->warning_limit = 100;
83  return 0;
84 }
85 
87 {
88  BufferSinkContext *buf = ctx->priv;
89  AVFilterBufferRef *picref;
90 
91  if (buf->fifo) {
92  while (av_fifo_size(buf->fifo) >= sizeof(AVFilterBufferRef *)) {
93  av_fifo_generic_read(buf->fifo, &picref, sizeof(picref), NULL);
94  avfilter_unref_buffer(picref);
95  }
96  av_fifo_free(buf->fifo);
97  buf->fifo = NULL;
98  }
99 }
100 
102 {
103  BufferSinkContext *buf = ctx->priv;
104 
105  if (av_fifo_space(buf->fifo) < sizeof(AVFilterBufferRef *)) {
106  /* realloc fifo size */
107  if (av_fifo_realloc2(buf->fifo, av_fifo_size(buf->fifo) * 2) < 0) {
108  av_log(ctx, AV_LOG_ERROR,
109  "Cannot buffer more frames. Consume some available frames "
110  "before adding new ones.\n");
111  return AVERROR(ENOMEM);
112  }
113  }
114 
115  /* cache frame */
116  av_fifo_generic_write(buf->fifo, &ref, sizeof(AVFilterBufferRef *), NULL);
117  return 0;
118 }
119 
120 static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *ref)
121 {
122  AVFilterContext *ctx = inlink->dst;
123  BufferSinkContext *buf = inlink->dst->priv;
124  int ret;
125 
126  if ((ret = add_buffer_ref(ctx, ref)) < 0)
127  return ret;
128  if (buf->warning_limit &&
129  av_fifo_size(buf->fifo) / sizeof(AVFilterBufferRef *) >= buf->warning_limit) {
130  av_log(ctx, AV_LOG_WARNING,
131  "%d buffers queued in %s, something may be wrong.\n",
132  buf->warning_limit,
133  (char *)av_x_if_null(ctx->name, ctx->filter->name));
134  buf->warning_limit *= 10;
135  }
136  return 0;
137 }
138 
140 {
141  AVFilterLink *inlink = ctx->inputs[0];
142 
143  inlink->min_samples = inlink->max_samples =
144  inlink->partial_buf_size = frame_size;
145 }
146 
148  AVFilterBufferRef **bufref, int flags)
149 {
150  BufferSinkContext *buf = ctx->priv;
151  AVFilterLink *inlink = ctx->inputs[0];
152  int ret;
153  *bufref = NULL;
154 
155  av_assert0( !strcmp(ctx->filter->name, "buffersink")
156  || !strcmp(ctx->filter->name, "abuffersink")
157  || !strcmp(ctx->filter->name, "ffbuffersink")
158  || !strcmp(ctx->filter->name, "ffabuffersink"));
159 
160  /* no picref available, fetch it from the filterchain */
161  if (!av_fifo_size(buf->fifo)) {
162  if (flags & AV_BUFFERSINK_FLAG_NO_REQUEST)
163  return AVERROR(EAGAIN);
164  if ((ret = ff_request_frame(inlink)) < 0)
165  return ret;
166  }
167 
168  if (!av_fifo_size(buf->fifo))
169  return AVERROR(EINVAL);
170 
171  if (flags & AV_BUFFERSINK_FLAG_PEEK)
172  *bufref = *((AVFilterBufferRef **)av_fifo_peek2(buf->fifo, 0));
173  else
174  av_fifo_generic_read(buf->fifo, bufref, sizeof(*bufref), NULL);
175 
176  return 0;
177 }
178 
180 {
181  av_assert0( !strcmp(ctx->filter->name, "buffersink")
182  || !strcmp(ctx->filter->name, "ffbuffersink"));
183 
184  return ctx->inputs[0]->frame_rate;
185 }
186 
188 {
189  BufferSinkContext *buf = ctx->priv;
190  AVFilterLink *inlink = ctx->inputs[0];
191 
192  av_assert0( !strcmp(ctx->filter->name, "buffersink")
193  || !strcmp(ctx->filter->name, "abuffersink")
194  || !strcmp(ctx->filter->name, "ffbuffersink")
195  || !strcmp(ctx->filter->name, "ffabuffersink"));
196 
197  return av_fifo_size(buf->fifo)/sizeof(AVFilterBufferRef *) + ff_poll_frame(inlink);
198 }
199 
200 static av_cold int vsink_init(AVFilterContext *ctx, const char *args, void *opaque)
201 {
202  BufferSinkContext *buf = ctx->priv;
203  AVBufferSinkParams *params = opaque;
204 
205  if (params && params->pixel_fmts) {
206  const int *pixel_fmts = params->pixel_fmts;
207 
208  buf->pixel_fmts = ff_copy_int_list(pixel_fmts);
209  if (!buf->pixel_fmts)
210  return AVERROR(ENOMEM);
211  }
212 
213  return common_init(ctx);
214 }
215 
217 {
218  BufferSinkContext *buf = ctx->priv;
219  av_freep(&buf->pixel_fmts);
220  common_uninit(ctx);
221 }
222 
224 {
225  BufferSinkContext *buf = ctx->priv;
226 
227  if (buf->pixel_fmts)
229  else
231 
232  return 0;
233 }
234 
236  {
237  .name = "default",
238  .type = AVMEDIA_TYPE_VIDEO,
239  .filter_frame = filter_frame,
240  .min_perms = AV_PERM_READ | AV_PERM_PRESERVE,
241  },
242  { NULL },
243 };
244 
246  .name = "ffbuffersink",
247  .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
248  .priv_size = sizeof(BufferSinkContext),
249  .init_opaque = vsink_init,
250  .uninit = vsink_uninit,
251 
253  .inputs = ffbuffersink_inputs,
254  .outputs = NULL,
255 };
256 
257 static const AVFilterPad buffersink_inputs[] = {
258  {
259  .name = "default",
260  .type = AVMEDIA_TYPE_VIDEO,
261  .filter_frame = filter_frame,
262  .min_perms = AV_PERM_READ | AV_PERM_PRESERVE,
263  },
264  { NULL },
265 };
266 
268  .name = "buffersink",
269  .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
270  .priv_size = sizeof(BufferSinkContext),
271  .init_opaque = vsink_init,
272  .uninit = vsink_uninit,
273 
275  .inputs = buffersink_inputs,
276  .outputs = NULL,
277 };
278 
279 static av_cold int asink_init(AVFilterContext *ctx, const char *args, void *opaque)
280 {
281  BufferSinkContext *buf = ctx->priv;
282  AVABufferSinkParams *params = opaque;
283 
284  if (params && params->sample_fmts) {
285  buf->sample_fmts = ff_copy_int_list (params->sample_fmts);
286  if (!buf->sample_fmts)
287  goto fail_enomem;
288  }
289  if (params && params->channel_layouts) {
291  if (!buf->channel_layouts)
292  goto fail_enomem;
293  }
294  if (!common_init(ctx))
295  return 0;
296 
297 fail_enomem:
298  av_freep(&buf->sample_fmts);
299  av_freep(&buf->channel_layouts);
300  return AVERROR(ENOMEM);
301 }
302 
304 {
305  BufferSinkContext *buf = ctx->priv;
306 
307  av_freep(&buf->sample_fmts);
308  av_freep(&buf->channel_layouts);
309  common_uninit(ctx);
310 }
311 
313 {
314  BufferSinkContext *buf = ctx->priv;
317 
318  if (buf->sample_fmts) {
319  if (!(formats = ff_make_format_list(buf->sample_fmts)))
320  return AVERROR(ENOMEM);
321  ff_set_common_formats(ctx, formats);
322  }
323 
324  if (buf->channel_layouts) {
325  if (!(layouts = avfilter_make_format64_list(buf->channel_layouts)))
326  return AVERROR(ENOMEM);
327  ff_set_common_channel_layouts(ctx, layouts);
328  }
329 
330  return 0;
331 }
332 
334  {
335  .name = "default",
336  .type = AVMEDIA_TYPE_AUDIO,
337  .filter_frame = filter_frame,
338  .min_perms = AV_PERM_READ | AV_PERM_PRESERVE,
339  },
340  { NULL },
341 };
342 
344  .name = "ffabuffersink",
345  .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."),
346  .init_opaque = asink_init,
347  .uninit = asink_uninit,
348  .priv_size = sizeof(BufferSinkContext),
350  .inputs = ffabuffersink_inputs,
351  .outputs = NULL,
352 };
353 
354 static const AVFilterPad abuffersink_inputs[] = {
355  {
356  .name = "default",
357  .type = AVMEDIA_TYPE_AUDIO,
358  .filter_frame = filter_frame,
359  .min_perms = AV_PERM_READ | AV_PERM_PRESERVE,
360  },
361  { NULL },
362 };
363 
365  .name = "abuffersink",
366  .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."),
367  .init_opaque = asink_init,
368  .uninit = asink_uninit,
369  .priv_size = sizeof(BufferSinkContext),
371  .inputs = abuffersink_inputs,
372  .outputs = NULL,
373 };
374 
375 /* Libav compatibility API */
376 
379 
381 {
382  AVFilterBufferRef *tbuf;
383  int ret;
384 
385  if (ctx->filter-> inputs[0].start_frame ==
386  avfilter_vsink_buffer. inputs[0].start_frame ||
387  ctx->filter-> inputs[0].filter_frame ==
388  avfilter_asink_abuffer.inputs[0].filter_frame)
389  return ff_buffersink_read_compat(ctx, buf);
390  av_assert0(ctx->filter-> inputs[0].end_frame ==
391  avfilter_vsink_ffbuffersink. inputs[0].end_frame ||
392  ctx->filter-> inputs[0].filter_frame ==
393  avfilter_asink_ffabuffersink.inputs[0].filter_frame);
394 
395  ret = av_buffersink_get_buffer_ref(ctx, &tbuf,
396  buf ? 0 : AV_BUFFERSINK_FLAG_PEEK);
397  if (!buf)
398  return ret >= 0;
399  if (ret < 0)
400  return ret;
401  *buf = tbuf;
402  return 0;
403 }
404 
406  int nb_samples)
407 {
408  BufferSinkContext *sink = ctx->priv;
409  int ret = 0, have_samples = 0, need_samples;
410  AVFilterBufferRef *tbuf, *in_buf;
411  AVFilterLink *link = ctx->inputs[0];
413 
414  if (ctx->filter-> inputs[0].filter_frame ==
415  avfilter_asink_abuffer.inputs[0].filter_frame)
416  return ff_buffersink_read_samples_compat(ctx, buf, nb_samples);
417  av_assert0(ctx->filter-> inputs[0].filter_frame ==
418  avfilter_asink_ffabuffersink.inputs[0].filter_frame);
419 
420  tbuf = ff_get_audio_buffer(link, AV_PERM_WRITE, nb_samples);
421  if (!tbuf)
422  return AVERROR(ENOMEM);
423 
424  while (have_samples < nb_samples) {
425  ret = av_buffersink_get_buffer_ref(ctx, &in_buf,
427  if (ret < 0) {
428  if (ret == AVERROR_EOF && have_samples) {
429  nb_samples = have_samples;
430  ret = 0;
431  }
432  break;
433  }
434 
435  need_samples = FFMIN(in_buf->audio->nb_samples,
436  nb_samples - have_samples);
438  have_samples, 0, need_samples,
439  nb_channels, in_buf->format);
440  have_samples += need_samples;
441  if (need_samples < in_buf->audio->nb_samples) {
442  in_buf->audio->nb_samples -= need_samples;
444  0, need_samples, in_buf->audio->nb_samples,
445  nb_channels, in_buf->format);
446  } else {
447  av_buffersink_get_buffer_ref(ctx, &in_buf, 0);
448  avfilter_unref_buffer(in_buf);
449  }
450  }
451  tbuf->audio->nb_samples = have_samples;
452 
453  if (ret < 0) {
454  av_assert0(!av_fifo_size(sink->fifo));
455  if (have_samples)
456  add_buffer_ref(ctx, tbuf);
457  else
458  avfilter_unref_buffer(tbuf);
459  return ret;
460  }
461 
462  *buf = tbuf;
463  return 0;
464 }