• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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"
27 #include "libavutil/channel_layout.h"
28 #include "libavutil/common.h"
29 #include "libavutil/internal.h"
30 #include "libavutil/opt.h"
31 
32 #define FF_INTERNAL_FIELDS 1
33 #include "framequeue.h"
34 
35 #include "audio.h"
36 #include "avfilter.h"
37 #include "buffersink.h"
38 #include "filters.h"
39 #include "internal.h"
40 
41 typedef struct BufferSinkContext {
42     const AVClass *class;
43     unsigned warning_limit;
44 
45     /* only used for video */
46     enum AVPixelFormat *pixel_fmts;           ///< list of accepted pixel formats, must be terminated with -1
47     int pixel_fmts_size;
48 
49     /* only used for audio */
50     enum AVSampleFormat *sample_fmts;       ///< list of accepted sample formats, terminated by AV_SAMPLE_FMT_NONE
51     int sample_fmts_size;
52     int64_t *channel_layouts;               ///< list of accepted channel layouts, terminated by -1
53     int channel_layouts_size;
54     int *channel_counts;                    ///< list of accepted channel counts, terminated by -1
55     int channel_counts_size;
56     int all_channel_counts;
57     int *sample_rates;                      ///< list of accepted sample rates, terminated by -1
58     int sample_rates_size;
59 
60     AVFrame *peeked_frame;
61 } BufferSinkContext;
62 
63 #define NB_ITEMS(list) (list ## _size / sizeof(*list))
64 
cleanup_redundant_layouts(AVFilterContext * ctx)65 static void cleanup_redundant_layouts(AVFilterContext *ctx)
66 {
67     BufferSinkContext *buf = ctx->priv;
68     int nb_layouts = NB_ITEMS(buf->channel_layouts);
69     int nb_counts = NB_ITEMS(buf->channel_counts);
70     uint64_t counts = 0;
71     int i, lc, n;
72 
73     for (i = 0; i < nb_counts; i++)
74         if (buf->channel_counts[i] < 64)
75             counts |= (uint64_t)1 << buf->channel_counts[i];
76     for (i = lc = 0; i < nb_layouts; i++) {
77         n = av_get_channel_layout_nb_channels(buf->channel_layouts[i]);
78         if (n < 64 && (counts & ((uint64_t)1 << n)))
79             av_log(ctx, AV_LOG_WARNING,
80                    "Removing channel layout 0x%"PRIx64", redundant with %d channels\n",
81                    buf->channel_layouts[i], n);
82         else
83             buf->channel_layouts[lc++] = buf->channel_layouts[i];
84     }
85     buf->channel_layouts_size = lc * sizeof(*buf->channel_layouts);
86 }
87 
av_buffersink_get_frame(AVFilterContext * ctx,AVFrame * frame)88 int attribute_align_arg av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame)
89 {
90     return av_buffersink_get_frame_flags(ctx, frame, 0);
91 }
92 
return_or_keep_frame(BufferSinkContext * buf,AVFrame * out,AVFrame * in,int flags)93 static int return_or_keep_frame(BufferSinkContext *buf, AVFrame *out, AVFrame *in, int flags)
94 {
95     if ((flags & AV_BUFFERSINK_FLAG_PEEK)) {
96         buf->peeked_frame = in;
97         return out ? av_frame_ref(out, in) : 0;
98     } else {
99         av_assert1(out);
100         buf->peeked_frame = NULL;
101         av_frame_move_ref(out, in);
102         av_frame_free(&in);
103         return 0;
104     }
105 }
106 
get_frame_internal(AVFilterContext * ctx,AVFrame * frame,int flags,int samples)107 static int get_frame_internal(AVFilterContext *ctx, AVFrame *frame, int flags, int samples)
108 {
109     BufferSinkContext *buf = ctx->priv;
110     AVFilterLink *inlink = ctx->inputs[0];
111     int status, ret;
112     AVFrame *cur_frame;
113     int64_t pts;
114 
115     if (buf->peeked_frame)
116         return return_or_keep_frame(buf, frame, buf->peeked_frame, flags);
117 
118     while (1) {
119         ret = samples ? ff_inlink_consume_samples(inlink, samples, samples, &cur_frame) :
120                         ff_inlink_consume_frame(inlink, &cur_frame);
121         if (ret < 0) {
122             return ret;
123         } else if (ret) {
124             /* TODO return the frame instead of copying it */
125             return return_or_keep_frame(buf, frame, cur_frame, flags);
126         } else if (ff_inlink_acknowledge_status(inlink, &status, &pts)) {
127             return status;
128         } else if ((flags & AV_BUFFERSINK_FLAG_NO_REQUEST)) {
129             return AVERROR(EAGAIN);
130         } else if (inlink->frame_wanted_out) {
131             ret = ff_filter_graph_run_once(ctx->graph);
132             if (ret < 0)
133                 return ret;
134         } else {
135             ff_inlink_request_frame(inlink);
136         }
137     }
138 }
139 
av_buffersink_get_frame_flags(AVFilterContext * ctx,AVFrame * frame,int flags)140 int attribute_align_arg av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flags)
141 {
142     return get_frame_internal(ctx, frame, flags, ctx->inputs[0]->min_samples);
143 }
144 
av_buffersink_get_samples(AVFilterContext * ctx,AVFrame * frame,int nb_samples)145 int attribute_align_arg av_buffersink_get_samples(AVFilterContext *ctx,
146                                                   AVFrame *frame, int nb_samples)
147 {
148     return get_frame_internal(ctx, frame, 0, nb_samples);
149 }
150 
151 #if FF_API_BUFFERSINK_ALLOC
av_buffersink_params_alloc(void)152 AVBufferSinkParams *av_buffersink_params_alloc(void)
153 {
154     static const int pixel_fmts[] = { AV_PIX_FMT_NONE };
155     AVBufferSinkParams *params = av_malloc(sizeof(AVBufferSinkParams));
156     if (!params)
157         return NULL;
158 
159     params->pixel_fmts = pixel_fmts;
160     return params;
161 }
162 
av_abuffersink_params_alloc(void)163 AVABufferSinkParams *av_abuffersink_params_alloc(void)
164 {
165     AVABufferSinkParams *params = av_mallocz(sizeof(AVABufferSinkParams));
166 
167     if (!params)
168         return NULL;
169     return params;
170 }
171 #endif
172 
common_init(AVFilterContext * ctx)173 static av_cold int common_init(AVFilterContext *ctx)
174 {
175     BufferSinkContext *buf = ctx->priv;
176 
177     buf->warning_limit = 100;
178     return 0;
179 }
180 
activate(AVFilterContext * ctx)181 static int activate(AVFilterContext *ctx)
182 {
183     BufferSinkContext *buf = ctx->priv;
184 
185     if (buf->warning_limit &&
186         ff_framequeue_queued_frames(&ctx->inputs[0]->fifo) >= buf->warning_limit) {
187         av_log(ctx, AV_LOG_WARNING,
188                "%d buffers queued in %s, something may be wrong.\n",
189                buf->warning_limit,
190                (char *)av_x_if_null(ctx->name, ctx->filter->name));
191         buf->warning_limit *= 10;
192     }
193 
194     /* The frame is queued, the rest is up to get_frame_internal */
195     return 0;
196 }
197 
av_buffersink_set_frame_size(AVFilterContext * ctx,unsigned frame_size)198 void av_buffersink_set_frame_size(AVFilterContext *ctx, unsigned frame_size)
199 {
200     AVFilterLink *inlink = ctx->inputs[0];
201 
202     inlink->min_samples = inlink->max_samples =
203     inlink->partial_buf_size = frame_size;
204 }
205 
206 #define MAKE_AVFILTERLINK_ACCESSOR(type, field) \
207 type av_buffersink_get_##field(const AVFilterContext *ctx) { \
208     av_assert0(ctx->filter->activate == activate); \
209     return ctx->inputs[0]->field; \
210 }
211 
MAKE_AVFILTERLINK_ACCESSOR(enum AVMediaType,type)212 MAKE_AVFILTERLINK_ACCESSOR(enum AVMediaType , type               )
213 MAKE_AVFILTERLINK_ACCESSOR(AVRational       , time_base          )
214 MAKE_AVFILTERLINK_ACCESSOR(int              , format             )
215 
216 MAKE_AVFILTERLINK_ACCESSOR(AVRational       , frame_rate         )
217 MAKE_AVFILTERLINK_ACCESSOR(int              , w                  )
218 MAKE_AVFILTERLINK_ACCESSOR(int              , h                  )
219 MAKE_AVFILTERLINK_ACCESSOR(AVRational       , sample_aspect_ratio)
220 
221 MAKE_AVFILTERLINK_ACCESSOR(int              , channels           )
222 MAKE_AVFILTERLINK_ACCESSOR(uint64_t         , channel_layout     )
223 MAKE_AVFILTERLINK_ACCESSOR(int              , sample_rate        )
224 
225 MAKE_AVFILTERLINK_ACCESSOR(AVBufferRef *    , hw_frames_ctx      )
226 
227 #define CHECK_LIST_SIZE(field) \
228         if (buf->field ## _size % sizeof(*buf->field)) { \
229             av_log(ctx, AV_LOG_ERROR, "Invalid size for " #field ": %d, " \
230                    "should be multiple of %d\n", \
231                    buf->field ## _size, (int)sizeof(*buf->field)); \
232             return AVERROR(EINVAL); \
233         }
234 static int vsink_query_formats(AVFilterContext *ctx)
235 {
236     BufferSinkContext *buf = ctx->priv;
237     AVFilterFormats *formats = NULL;
238     unsigned i;
239     int ret;
240 
241     CHECK_LIST_SIZE(pixel_fmts)
242     if (buf->pixel_fmts_size) {
243         for (i = 0; i < NB_ITEMS(buf->pixel_fmts); i++)
244             if ((ret = ff_add_format(&formats, buf->pixel_fmts[i])) < 0)
245                 return ret;
246         if ((ret = ff_set_common_formats(ctx, formats)) < 0)
247             return ret;
248     } else {
249         if ((ret = ff_default_query_formats(ctx)) < 0)
250             return ret;
251     }
252 
253     return 0;
254 }
255 
asink_query_formats(AVFilterContext * ctx)256 static int asink_query_formats(AVFilterContext *ctx)
257 {
258     BufferSinkContext *buf = ctx->priv;
259     AVFilterFormats *formats = NULL;
260     AVFilterChannelLayouts *layouts = NULL;
261     unsigned i;
262     int ret;
263 
264     CHECK_LIST_SIZE(sample_fmts)
265     CHECK_LIST_SIZE(sample_rates)
266     CHECK_LIST_SIZE(channel_layouts)
267     CHECK_LIST_SIZE(channel_counts)
268 
269     if (buf->sample_fmts_size) {
270         for (i = 0; i < NB_ITEMS(buf->sample_fmts); i++)
271             if ((ret = ff_add_format(&formats, buf->sample_fmts[i])) < 0)
272                 return ret;
273         if ((ret = ff_set_common_formats(ctx, formats)) < 0)
274             return ret;
275     }
276 
277     if (buf->channel_layouts_size || buf->channel_counts_size ||
278         buf->all_channel_counts) {
279         cleanup_redundant_layouts(ctx);
280         for (i = 0; i < NB_ITEMS(buf->channel_layouts); i++)
281             if ((ret = ff_add_channel_layout(&layouts, buf->channel_layouts[i])) < 0)
282                 return ret;
283         for (i = 0; i < NB_ITEMS(buf->channel_counts); i++)
284             if ((ret = ff_add_channel_layout(&layouts, FF_COUNT2LAYOUT(buf->channel_counts[i]))) < 0)
285                 return ret;
286         if (buf->all_channel_counts) {
287             if (layouts)
288                 av_log(ctx, AV_LOG_WARNING,
289                        "Conflicting all_channel_counts and list in options\n");
290             else if (!(layouts = ff_all_channel_counts()))
291                 return AVERROR(ENOMEM);
292         }
293         if ((ret = ff_set_common_channel_layouts(ctx, layouts)) < 0)
294             return ret;
295     }
296 
297     if (buf->sample_rates_size) {
298         formats = NULL;
299         for (i = 0; i < NB_ITEMS(buf->sample_rates); i++)
300             if ((ret = ff_add_format(&formats, buf->sample_rates[i])) < 0)
301                 return ret;
302         if ((ret = ff_set_common_samplerates(ctx, formats)) < 0)
303             return ret;
304     }
305 
306     return 0;
307 }
308 
309 #define OFFSET(x) offsetof(BufferSinkContext, x)
310 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
311 static const AVOption buffersink_options[] = {
312     { "pix_fmts", "set the supported pixel formats", OFFSET(pixel_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS },
313     { NULL },
314 };
315 #undef FLAGS
316 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_AUDIO_PARAM
317 static const AVOption abuffersink_options[] = {
318     { "sample_fmts",     "set the supported sample formats",  OFFSET(sample_fmts),     AV_OPT_TYPE_BINARY, .flags = FLAGS },
319     { "sample_rates",    "set the supported sample rates",    OFFSET(sample_rates),    AV_OPT_TYPE_BINARY, .flags = FLAGS },
320     { "channel_layouts", "set the supported channel layouts", OFFSET(channel_layouts), AV_OPT_TYPE_BINARY, .flags = FLAGS },
321     { "channel_counts",  "set the supported channel counts",  OFFSET(channel_counts),  AV_OPT_TYPE_BINARY, .flags = FLAGS },
322     { "all_channel_counts", "accept all channel counts", OFFSET(all_channel_counts), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS },
323     { NULL },
324 };
325 #undef FLAGS
326 
327 AVFILTER_DEFINE_CLASS(buffersink);
328 AVFILTER_DEFINE_CLASS(abuffersink);
329 
330 static const AVFilterPad avfilter_vsink_buffer_inputs[] = {
331     {
332         .name = "default",
333         .type = AVMEDIA_TYPE_VIDEO,
334     },
335     { NULL }
336 };
337 
338 AVFilter ff_vsink_buffer = {
339     .name          = "buffersink",
340     .description   = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
341     .priv_size     = sizeof(BufferSinkContext),
342     .priv_class    = &buffersink_class,
343     .init          = common_init,
344     .query_formats = vsink_query_formats,
345     .activate      = activate,
346     .inputs        = avfilter_vsink_buffer_inputs,
347     .outputs       = NULL,
348 };
349 
350 static const AVFilterPad avfilter_asink_abuffer_inputs[] = {
351     {
352         .name = "default",
353         .type = AVMEDIA_TYPE_AUDIO,
354     },
355     { NULL }
356 };
357 
358 AVFilter ff_asink_abuffer = {
359     .name          = "abuffersink",
360     .description   = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."),
361     .priv_class    = &abuffersink_class,
362     .priv_size     = sizeof(BufferSinkContext),
363     .init          = common_init,
364     .query_formats = asink_query_formats,
365     .activate      = activate,
366     .inputs        = avfilter_asink_abuffer_inputs,
367     .outputs       = NULL,
368 };
369