Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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/audio_fifo.h"
  27. #include "libavutil/avassert.h"
  28. #include "libavutil/channel_layout.h"
  29. #include "libavutil/common.h"
  30. #include "libavutil/internal.h"
  31. #include "libavutil/mathematics.h"
  32. #include "libavutil/opt.h"
  33.  
  34. #include "audio.h"
  35. #include "avfilter.h"
  36. #include "buffersink.h"
  37. #include "internal.h"
  38.  
  39. typedef struct {
  40.     const AVClass *class;
  41.     AVFifoBuffer *fifo;                      ///< FIFO buffer of video frame references
  42.     unsigned warning_limit;
  43.  
  44.     /* only used for video */
  45.     enum AVPixelFormat *pixel_fmts;           ///< list of accepted pixel formats, must be terminated with -1
  46.     int pixel_fmts_size;
  47.  
  48.     /* only used for audio */
  49.     enum AVSampleFormat *sample_fmts;       ///< list of accepted sample formats, terminated by AV_SAMPLE_FMT_NONE
  50.     int sample_fmts_size;
  51.     int64_t *channel_layouts;               ///< list of accepted channel layouts, terminated by -1
  52.     int channel_layouts_size;
  53.     int *channel_counts;                    ///< list of accepted channel counts, terminated by -1
  54.     int channel_counts_size;
  55.     int all_channel_counts;
  56.     int *sample_rates;                      ///< list of accepted sample rates, terminated by -1
  57.     int sample_rates_size;
  58.  
  59.     /* only used for compat API */
  60.     AVAudioFifo *audio_fifo;     ///< FIFO for audio samples
  61.     int64_t next_pts;            ///< interpolating audio pts
  62. } BufferSinkContext;
  63.  
  64. #define NB_ITEMS(list) (list ## _size / sizeof(*list))
  65.  
  66. static av_cold void uninit(AVFilterContext *ctx)
  67. {
  68.     BufferSinkContext *sink = ctx->priv;
  69.     AVFrame *frame;
  70.  
  71.     if (sink->audio_fifo)
  72.         av_audio_fifo_free(sink->audio_fifo);
  73.  
  74.     if (sink->fifo) {
  75.         while (av_fifo_size(sink->fifo) >= sizeof(AVFilterBufferRef *)) {
  76.             av_fifo_generic_read(sink->fifo, &frame, sizeof(frame), NULL);
  77.             av_frame_free(&frame);
  78.         }
  79.         av_fifo_free(sink->fifo);
  80.         sink->fifo = NULL;
  81.     }
  82. }
  83.  
  84. static int add_buffer_ref(AVFilterContext *ctx, AVFrame *ref)
  85. {
  86.     BufferSinkContext *buf = ctx->priv;
  87.  
  88.     if (av_fifo_space(buf->fifo) < sizeof(AVFilterBufferRef *)) {
  89.         /* realloc fifo size */
  90.         if (av_fifo_realloc2(buf->fifo, av_fifo_size(buf->fifo) * 2) < 0) {
  91.             av_log(ctx, AV_LOG_ERROR,
  92.                    "Cannot buffer more frames. Consume some available frames "
  93.                    "before adding new ones.\n");
  94.             return AVERROR(ENOMEM);
  95.         }
  96.     }
  97.  
  98.     /* cache frame */
  99.     av_fifo_generic_write(buf->fifo, &ref, sizeof(AVFilterBufferRef *), NULL);
  100.     return 0;
  101. }
  102.  
  103. static int filter_frame(AVFilterLink *link, AVFrame *frame)
  104. {
  105.     AVFilterContext *ctx = link->dst;
  106.     BufferSinkContext *buf = link->dst->priv;
  107.     int ret;
  108.  
  109.     if ((ret = add_buffer_ref(ctx, frame)) < 0)
  110.         return ret;
  111.     if (buf->warning_limit &&
  112.         av_fifo_size(buf->fifo) / sizeof(AVFilterBufferRef *) >= buf->warning_limit) {
  113.         av_log(ctx, AV_LOG_WARNING,
  114.                "%d buffers queued in %s, something may be wrong.\n",
  115.                buf->warning_limit,
  116.                (char *)av_x_if_null(ctx->name, ctx->filter->name));
  117.         buf->warning_limit *= 10;
  118.     }
  119.     return 0;
  120. }
  121.  
  122. int attribute_align_arg av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame)
  123. {
  124.     return av_buffersink_get_frame_flags(ctx, frame, 0);
  125. }
  126.  
  127. int attribute_align_arg av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flags)
  128. {
  129.     BufferSinkContext *buf = ctx->priv;
  130.     AVFilterLink *inlink = ctx->inputs[0];
  131.     int ret;
  132.     AVFrame *cur_frame;
  133.  
  134.     /* no picref available, fetch it from the filterchain */
  135.     if (!av_fifo_size(buf->fifo)) {
  136.         if (flags & AV_BUFFERSINK_FLAG_NO_REQUEST)
  137.             return AVERROR(EAGAIN);
  138.         if ((ret = ff_request_frame(inlink)) < 0)
  139.             return ret;
  140.     }
  141.  
  142.     if (!av_fifo_size(buf->fifo))
  143.         return AVERROR(EINVAL);
  144.  
  145.     if (flags & AV_BUFFERSINK_FLAG_PEEK) {
  146.         cur_frame = *((AVFrame **)av_fifo_peek2(buf->fifo, 0));
  147.         if ((ret = av_frame_ref(frame, cur_frame)) < 0)
  148.             return ret;
  149.     } else {
  150.         av_fifo_generic_read(buf->fifo, &cur_frame, sizeof(cur_frame), NULL);
  151.         av_frame_move_ref(frame, cur_frame);
  152.         av_frame_free(&cur_frame);
  153.     }
  154.  
  155.     return 0;
  156. }
  157.  
  158. static int read_from_fifo(AVFilterContext *ctx, AVFrame *frame,
  159.                           int nb_samples)
  160. {
  161.     BufferSinkContext *s = ctx->priv;
  162.     AVFilterLink   *link = ctx->inputs[0];
  163.     AVFrame *tmp;
  164.  
  165.     if (!(tmp = ff_get_audio_buffer(link, nb_samples)))
  166.         return AVERROR(ENOMEM);
  167.     av_audio_fifo_read(s->audio_fifo, (void**)tmp->extended_data, nb_samples);
  168.  
  169.     tmp->pts = s->next_pts;
  170.     if (s->next_pts != AV_NOPTS_VALUE)
  171.         s->next_pts += av_rescale_q(nb_samples, (AVRational){1, link->sample_rate},
  172.                                     link->time_base);
  173.  
  174.     av_frame_move_ref(frame, tmp);
  175.     av_frame_free(&tmp);
  176.  
  177.     return 0;
  178. }
  179.  
  180. int attribute_align_arg av_buffersink_get_samples(AVFilterContext *ctx,
  181.                                                   AVFrame *frame, int nb_samples)
  182. {
  183.     BufferSinkContext *s = ctx->priv;
  184.     AVFilterLink   *link = ctx->inputs[0];
  185.     AVFrame *cur_frame;
  186.     int ret = 0;
  187.  
  188.     if (!s->audio_fifo) {
  189.         int nb_channels = link->channels;
  190.         if (!(s->audio_fifo = av_audio_fifo_alloc(link->format, nb_channels, nb_samples)))
  191.             return AVERROR(ENOMEM);
  192.     }
  193.  
  194.     while (ret >= 0) {
  195.         if (av_audio_fifo_size(s->audio_fifo) >= nb_samples)
  196.             return read_from_fifo(ctx, frame, nb_samples);
  197.  
  198.         if (!(cur_frame = av_frame_alloc()))
  199.             return AVERROR(ENOMEM);
  200.         ret = av_buffersink_get_frame_flags(ctx, cur_frame, 0);
  201.         if (ret == AVERROR_EOF && av_audio_fifo_size(s->audio_fifo)) {
  202.             av_frame_free(&cur_frame);
  203.             return read_from_fifo(ctx, frame, av_audio_fifo_size(s->audio_fifo));
  204.         } else if (ret < 0) {
  205.             av_frame_free(&cur_frame);
  206.             return ret;
  207.         }
  208.  
  209.         if (cur_frame->pts != AV_NOPTS_VALUE) {
  210.             s->next_pts = cur_frame->pts -
  211.                           av_rescale_q(av_audio_fifo_size(s->audio_fifo),
  212.                                        (AVRational){ 1, link->sample_rate },
  213.                                        link->time_base);
  214.         }
  215.  
  216.         ret = av_audio_fifo_write(s->audio_fifo, (void**)cur_frame->extended_data,
  217.                                   cur_frame->nb_samples);
  218.         av_frame_free(&cur_frame);
  219.     }
  220.  
  221.     return ret;
  222. }
  223.  
  224. AVBufferSinkParams *av_buffersink_params_alloc(void)
  225. {
  226.     static const int pixel_fmts[] = { AV_PIX_FMT_NONE };
  227.     AVBufferSinkParams *params = av_malloc(sizeof(AVBufferSinkParams));
  228.     if (!params)
  229.         return NULL;
  230.  
  231.     params->pixel_fmts = pixel_fmts;
  232.     return params;
  233. }
  234.  
  235. AVABufferSinkParams *av_abuffersink_params_alloc(void)
  236. {
  237.     AVABufferSinkParams *params = av_mallocz(sizeof(AVABufferSinkParams));
  238.  
  239.     if (!params)
  240.         return NULL;
  241.     return params;
  242. }
  243.  
  244. #define FIFO_INIT_SIZE 8
  245.  
  246. static av_cold int common_init(AVFilterContext *ctx)
  247. {
  248.     BufferSinkContext *buf = ctx->priv;
  249.  
  250.     buf->fifo = av_fifo_alloc(FIFO_INIT_SIZE*sizeof(AVFilterBufferRef *));
  251.     if (!buf->fifo) {
  252.         av_log(ctx, AV_LOG_ERROR, "Failed to allocate fifo\n");
  253.         return AVERROR(ENOMEM);
  254.     }
  255.     buf->warning_limit = 100;
  256.     buf->next_pts = AV_NOPTS_VALUE;
  257.     return 0;
  258. }
  259.  
  260. void av_buffersink_set_frame_size(AVFilterContext *ctx, unsigned frame_size)
  261. {
  262.     AVFilterLink *inlink = ctx->inputs[0];
  263.  
  264.     inlink->min_samples = inlink->max_samples =
  265.     inlink->partial_buf_size = frame_size;
  266. }
  267.  
  268. #if FF_API_AVFILTERBUFFER
  269. FF_DISABLE_DEPRECATION_WARNINGS
  270. static void compat_free_buffer(AVFilterBuffer *buf)
  271. {
  272.     AVFrame *frame = buf->priv;
  273.     av_frame_free(&frame);
  274.     av_free(buf);
  275. }
  276.  
  277. static int compat_read(AVFilterContext *ctx,
  278.                        AVFilterBufferRef **pbuf, int nb_samples, int flags)
  279. {
  280.     AVFilterBufferRef *buf;
  281.     AVFrame *frame;
  282.     int ret;
  283.  
  284.     if (!pbuf)
  285.         return ff_poll_frame(ctx->inputs[0]);
  286.  
  287.     frame = av_frame_alloc();
  288.     if (!frame)
  289.         return AVERROR(ENOMEM);
  290.  
  291.     if (!nb_samples)
  292.         ret = av_buffersink_get_frame_flags(ctx, frame, flags);
  293.     else
  294.         ret = av_buffersink_get_samples(ctx, frame, nb_samples);
  295.  
  296.     if (ret < 0)
  297.         goto fail;
  298.  
  299.     AV_NOWARN_DEPRECATED(
  300.     if (ctx->inputs[0]->type == AVMEDIA_TYPE_VIDEO) {
  301.         buf = avfilter_get_video_buffer_ref_from_arrays(frame->data, frame->linesize,
  302.                                                         AV_PERM_READ,
  303.                                                         frame->width, frame->height,
  304.                                                         frame->format);
  305.     } else {
  306.         buf = avfilter_get_audio_buffer_ref_from_arrays(frame->extended_data,
  307.                                                         frame->linesize[0], AV_PERM_READ,
  308.                                                         frame->nb_samples,
  309.                                                         frame->format,
  310.                                                         frame->channel_layout);
  311.     }
  312.     if (!buf) {
  313.         ret = AVERROR(ENOMEM);
  314.         goto fail;
  315.     }
  316.  
  317.     avfilter_copy_frame_props(buf, frame);
  318.     )
  319.  
  320.     buf->buf->priv = frame;
  321.     buf->buf->free = compat_free_buffer;
  322.  
  323.     *pbuf = buf;
  324.  
  325.     return 0;
  326. fail:
  327.     av_frame_free(&frame);
  328.     return ret;
  329. }
  330.  
  331. int attribute_align_arg av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf)
  332. {
  333.     return compat_read(ctx, buf, 0, 0);
  334. }
  335.  
  336. int attribute_align_arg av_buffersink_read_samples(AVFilterContext *ctx, AVFilterBufferRef **buf,
  337.                                                    int nb_samples)
  338. {
  339.     return compat_read(ctx, buf, nb_samples, 0);
  340. }
  341.  
  342. int attribute_align_arg av_buffersink_get_buffer_ref(AVFilterContext *ctx,
  343.                                                      AVFilterBufferRef **bufref, int flags)
  344. {
  345.     *bufref = NULL;
  346.  
  347.     av_assert0(    !strcmp(ctx->filter->name, "buffersink")
  348.                 || !strcmp(ctx->filter->name, "abuffersink")
  349.                 || !strcmp(ctx->filter->name, "ffbuffersink")
  350.                 || !strcmp(ctx->filter->name, "ffabuffersink"));
  351.  
  352.     return compat_read(ctx, bufref, 0, flags);
  353. }
  354. FF_ENABLE_DEPRECATION_WARNINGS
  355. #endif
  356.  
  357. AVRational av_buffersink_get_frame_rate(AVFilterContext *ctx)
  358. {
  359.     av_assert0(   !strcmp(ctx->filter->name, "buffersink")
  360.                || !strcmp(ctx->filter->name, "ffbuffersink"));
  361.  
  362.     return ctx->inputs[0]->frame_rate;
  363. }
  364.  
  365. int attribute_align_arg av_buffersink_poll_frame(AVFilterContext *ctx)
  366. {
  367.     BufferSinkContext *buf = ctx->priv;
  368.     AVFilterLink *inlink = ctx->inputs[0];
  369.  
  370.     av_assert0(   !strcmp(ctx->filter->name, "buffersink")
  371.                || !strcmp(ctx->filter->name, "abuffersink")
  372.                || !strcmp(ctx->filter->name, "ffbuffersink")
  373.                || !strcmp(ctx->filter->name, "ffabuffersink"));
  374.  
  375.     return av_fifo_size(buf->fifo)/sizeof(AVFilterBufferRef *) + ff_poll_frame(inlink);
  376. }
  377.  
  378. static av_cold int vsink_init(AVFilterContext *ctx, void *opaque)
  379. {
  380.     BufferSinkContext *buf = ctx->priv;
  381.     AVBufferSinkParams *params = opaque;
  382.     int ret;
  383.  
  384.     if (params) {
  385.         if ((ret = av_opt_set_int_list(buf, "pix_fmts", params->pixel_fmts, AV_PIX_FMT_NONE, 0)) < 0)
  386.             return ret;
  387.     }
  388.  
  389.     return common_init(ctx);
  390. }
  391.  
  392. #define CHECK_LIST_SIZE(field) \
  393.         if (buf->field ## _size % sizeof(*buf->field)) { \
  394.             av_log(ctx, AV_LOG_ERROR, "Invalid size for " #field ": %d, " \
  395.                    "should be multiple of %d\n", \
  396.                    buf->field ## _size, (int)sizeof(*buf->field)); \
  397.             return AVERROR(EINVAL); \
  398.         }
  399. static int vsink_query_formats(AVFilterContext *ctx)
  400. {
  401.     BufferSinkContext *buf = ctx->priv;
  402.     AVFilterFormats *formats = NULL;
  403.     unsigned i;
  404.     int ret;
  405.  
  406.     CHECK_LIST_SIZE(pixel_fmts)
  407.     if (buf->pixel_fmts_size) {
  408.         for (i = 0; i < NB_ITEMS(buf->pixel_fmts); i++)
  409.             if ((ret = ff_add_format(&formats, buf->pixel_fmts[i])) < 0) {
  410.                 ff_formats_unref(&formats);
  411.                 return ret;
  412.             }
  413.         ff_set_common_formats(ctx, formats);
  414.     } else {
  415.         ff_default_query_formats(ctx);
  416.     }
  417.  
  418.     return 0;
  419. }
  420.  
  421. static av_cold int asink_init(AVFilterContext *ctx, void *opaque)
  422. {
  423.     BufferSinkContext *buf = ctx->priv;
  424.     AVABufferSinkParams *params = opaque;
  425.     int ret;
  426.  
  427.     if (params) {
  428.         if ((ret = av_opt_set_int_list(buf, "sample_fmts",     params->sample_fmts,  AV_SAMPLE_FMT_NONE, 0)) < 0 ||
  429.             (ret = av_opt_set_int_list(buf, "sample_rates",    params->sample_rates,    -1, 0)) < 0 ||
  430.             (ret = av_opt_set_int_list(buf, "channel_layouts", params->channel_layouts, -1, 0)) < 0 ||
  431.             (ret = av_opt_set_int_list(buf, "channel_counts",  params->channel_counts,  -1, 0)) < 0 ||
  432.             (ret = av_opt_set_int(buf, "all_channel_counts", params->all_channel_counts, 0)) < 0)
  433.             return ret;
  434.     }
  435.     return common_init(ctx);
  436. }
  437.  
  438. static int asink_query_formats(AVFilterContext *ctx)
  439. {
  440.     BufferSinkContext *buf = ctx->priv;
  441.     AVFilterFormats *formats = NULL;
  442.     AVFilterChannelLayouts *layouts = NULL;
  443.     unsigned i;
  444.     int ret;
  445.  
  446.     CHECK_LIST_SIZE(sample_fmts)
  447.     CHECK_LIST_SIZE(sample_rates)
  448.     CHECK_LIST_SIZE(channel_layouts)
  449.     CHECK_LIST_SIZE(channel_counts)
  450.  
  451.     if (buf->sample_fmts_size) {
  452.         for (i = 0; i < NB_ITEMS(buf->sample_fmts); i++)
  453.             if ((ret = ff_add_format(&formats, buf->sample_fmts[i])) < 0) {
  454.                 ff_formats_unref(&formats);
  455.                 return ret;
  456.             }
  457.         ff_set_common_formats(ctx, formats);
  458.     }
  459.  
  460.     if (buf->channel_layouts_size || buf->channel_counts_size ||
  461.         buf->all_channel_counts) {
  462.         for (i = 0; i < NB_ITEMS(buf->channel_layouts); i++)
  463.             if ((ret = ff_add_channel_layout(&layouts, buf->channel_layouts[i])) < 0) {
  464.                 ff_channel_layouts_unref(&layouts);
  465.                 return ret;
  466.             }
  467.         for (i = 0; i < NB_ITEMS(buf->channel_counts); i++)
  468.             if ((ret = ff_add_channel_layout(&layouts, FF_COUNT2LAYOUT(buf->channel_counts[i]))) < 0) {
  469.                 ff_channel_layouts_unref(&layouts);
  470.                 return ret;
  471.             }
  472.         if (buf->all_channel_counts) {
  473.             if (layouts)
  474.                 av_log(ctx, AV_LOG_WARNING,
  475.                        "Conflicting all_channel_counts and list in options\n");
  476.             else if (!(layouts = ff_all_channel_counts()))
  477.                 return AVERROR(ENOMEM);
  478.         }
  479.         ff_set_common_channel_layouts(ctx, layouts);
  480.     }
  481.  
  482.     if (buf->sample_rates_size) {
  483.         formats = NULL;
  484.         for (i = 0; i < NB_ITEMS(buf->sample_rates); i++)
  485.             if ((ret = ff_add_format(&formats, buf->sample_rates[i])) < 0) {
  486.                 ff_formats_unref(&formats);
  487.                 return ret;
  488.             }
  489.         ff_set_common_samplerates(ctx, formats);
  490.     }
  491.  
  492.     return 0;
  493. }
  494.  
  495. #define OFFSET(x) offsetof(BufferSinkContext, x)
  496. #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
  497. static const AVOption buffersink_options[] = {
  498.     { "pix_fmts", "set the supported pixel formats", OFFSET(pixel_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS },
  499.     { NULL },
  500. };
  501. #undef FLAGS
  502. #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
  503. static const AVOption abuffersink_options[] = {
  504.     { "sample_fmts",     "set the supported sample formats",  OFFSET(sample_fmts),     AV_OPT_TYPE_BINARY, .flags = FLAGS },
  505.     { "sample_rates",    "set the supported sample rates",    OFFSET(sample_rates),    AV_OPT_TYPE_BINARY, .flags = FLAGS },
  506.     { "channel_layouts", "set the supported channel layouts", OFFSET(channel_layouts), AV_OPT_TYPE_BINARY, .flags = FLAGS },
  507.     { "channel_counts",  "set the supported channel counts",  OFFSET(channel_counts),  AV_OPT_TYPE_BINARY, .flags = FLAGS },
  508.     { "all_channel_counts", "accept all channel counts", OFFSET(all_channel_counts), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS },
  509.     { NULL },
  510. };
  511. #undef FLAGS
  512.  
  513. AVFILTER_DEFINE_CLASS(buffersink);
  514. AVFILTER_DEFINE_CLASS(abuffersink);
  515.  
  516. #if FF_API_AVFILTERBUFFER
  517.  
  518. #define ffbuffersink_options buffersink_options
  519. #define ffabuffersink_options abuffersink_options
  520. AVFILTER_DEFINE_CLASS(ffbuffersink);
  521. AVFILTER_DEFINE_CLASS(ffabuffersink);
  522.  
  523. static const AVFilterPad ffbuffersink_inputs[] = {
  524.     {
  525.         .name      = "default",
  526.         .type      = AVMEDIA_TYPE_VIDEO,
  527.         .filter_frame = filter_frame,
  528.     },
  529.     { NULL },
  530. };
  531.  
  532. AVFilter avfilter_vsink_ffbuffersink = {
  533.     .name      = "ffbuffersink",
  534.     .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
  535.     .priv_size = sizeof(BufferSinkContext),
  536.     .priv_class = &ffbuffersink_class,
  537.     .init_opaque = vsink_init,
  538.     .uninit    = uninit,
  539.  
  540.     .query_formats = vsink_query_formats,
  541.     .inputs        = ffbuffersink_inputs,
  542.     .outputs       = NULL,
  543. };
  544.  
  545. static const AVFilterPad ffabuffersink_inputs[] = {
  546.     {
  547.         .name           = "default",
  548.         .type           = AVMEDIA_TYPE_AUDIO,
  549.         .filter_frame   = filter_frame,
  550.     },
  551.     { NULL },
  552. };
  553.  
  554. AVFilter avfilter_asink_ffabuffersink = {
  555.     .name      = "ffabuffersink",
  556.     .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."),
  557.     .init_opaque = asink_init,
  558.     .uninit    = uninit,
  559.     .priv_size = sizeof(BufferSinkContext),
  560.     .priv_class = &ffabuffersink_class,
  561.     .query_formats = asink_query_formats,
  562.     .inputs        = ffabuffersink_inputs,
  563.     .outputs       = NULL,
  564. };
  565. #endif /* FF_API_AVFILTERBUFFER */
  566.  
  567. static const AVFilterPad avfilter_vsink_buffer_inputs[] = {
  568.     {
  569.         .name         = "default",
  570.         .type         = AVMEDIA_TYPE_VIDEO,
  571.         .filter_frame = filter_frame,
  572.     },
  573.     { NULL }
  574. };
  575.  
  576. AVFilter avfilter_vsink_buffer = {
  577.     .name        = "buffersink",
  578.     .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
  579.     .priv_size   = sizeof(BufferSinkContext),
  580.     .priv_class  = &buffersink_class,
  581.     .init_opaque = vsink_init,
  582.     .uninit      = uninit,
  583.  
  584.     .query_formats = vsink_query_formats,
  585.     .inputs      = avfilter_vsink_buffer_inputs,
  586.     .outputs     = NULL,
  587. };
  588.  
  589. static const AVFilterPad avfilter_asink_abuffer_inputs[] = {
  590.     {
  591.         .name         = "default",
  592.         .type         = AVMEDIA_TYPE_AUDIO,
  593.         .filter_frame = filter_frame,
  594.     },
  595.     { NULL }
  596. };
  597.  
  598. AVFilter avfilter_asink_abuffer = {
  599.     .name        = "abuffersink",
  600.     .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."),
  601.     .priv_class  = &abuffersink_class,
  602.     .priv_size   = sizeof(BufferSinkContext),
  603.     .init_opaque = asink_init,
  604.     .uninit      = uninit,
  605.  
  606.     .query_formats = asink_query_formats,
  607.     .inputs      = avfilter_asink_abuffer_inputs,
  608.     .outputs     = NULL,
  609. };
  610.