Subversion Repositories Kolibri OS

Rev

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