FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/buffersink.c
Date: 2024-02-16 17:37:06
Exec Total Coverage
Lines: 102 180 56.7%
Functions: 18 26 69.2%
Branches: 60 156 38.5%

Line Branch Exec Source
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/avstring.h"
28 #include "libavutil/channel_layout.h"
29 #include "libavutil/common.h"
30 #include "libavutil/internal.h"
31 #include "libavutil/opt.h"
32
33 #include "audio.h"
34 #include "avfilter.h"
35 #include "buffersink.h"
36 #include "filters.h"
37 #include "formats.h"
38 #include "framequeue.h"
39 #include "internal.h"
40 #include "link_internal.h"
41 #include "video.h"
42
43 typedef struct BufferSinkContext {
44 const AVClass *class;
45 unsigned warning_limit;
46
47 /* only used for video */
48 enum AVPixelFormat *pixel_fmts; ///< list of accepted pixel formats
49 int pixel_fmts_size;
50 enum AVColorSpace *color_spaces; ///< list of accepted color spaces
51 int color_spaces_size;
52 enum AVColorRange *color_ranges; ///< list of accepted color ranges
53 int color_ranges_size;
54
55 /* only used for audio */
56 enum AVSampleFormat *sample_fmts; ///< list of accepted sample formats
57 int sample_fmts_size;
58 #if FF_API_OLD_CHANNEL_LAYOUT
59 int64_t *channel_layouts; ///< list of accepted channel layouts
60 int channel_layouts_size;
61 int *channel_counts; ///< list of accepted channel counts
62 int channel_counts_size;
63 #endif
64 char *channel_layouts_str; ///< list of accepted channel layouts
65 int all_channel_counts;
66 int *sample_rates; ///< list of accepted sample rates
67 int sample_rates_size;
68
69 AVFrame *peeked_frame;
70 } BufferSinkContext;
71
72 #define NB_ITEMS(list) (list ## _size / sizeof(*list))
73
74 #if FF_API_OLD_CHANNEL_LAYOUT
75 1254 static void cleanup_redundant_layouts(AVFilterContext *ctx)
76 {
77 1254 BufferSinkContext *buf = ctx->priv;
78 1254 int nb_layouts = NB_ITEMS(buf->channel_layouts);
79 1254 int nb_counts = NB_ITEMS(buf->channel_counts);
80 1254 uint64_t counts = 0;
81 int i, lc, n;
82
83
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1254 times.
1254 for (i = 0; i < nb_counts; i++)
84 if (buf->channel_counts[i] < 64)
85 counts |= (uint64_t)1 << buf->channel_counts[i];
86
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1254 times.
1254 for (i = lc = 0; i < nb_layouts; i++) {
87 n = av_popcount64(buf->channel_layouts[i]);
88 if (n < 64 && (counts & ((uint64_t)1 << n)))
89 av_log(ctx, AV_LOG_WARNING,
90 "Removing channel layout 0x%"PRIx64", redundant with %d channels\n",
91 buf->channel_layouts[i], n);
92 else
93 buf->channel_layouts[lc++] = buf->channel_layouts[i];
94 }
95 1254 buf->channel_layouts_size = lc * sizeof(*buf->channel_layouts);
96 1254 }
97 #endif
98
99 int attribute_align_arg av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame)
100 {
101 return av_buffersink_get_frame_flags(ctx, frame, 0);
102 }
103
104 841158 static int return_or_keep_frame(BufferSinkContext *buf, AVFrame *out, AVFrame *in, int flags)
105 {
106
2/2
✓ Branch 0 taken 419677 times.
✓ Branch 1 taken 421481 times.
841158 if ((flags & AV_BUFFERSINK_FLAG_PEEK)) {
107 419677 buf->peeked_frame = in;
108
2/2
✓ Branch 0 taken 10685 times.
✓ Branch 1 taken 408992 times.
419677 return out ? av_frame_ref(out, in) : 0;
109 } else {
110 av_assert1(out);
111 421481 buf->peeked_frame = NULL;
112 421481 av_frame_move_ref(out, in);
113 421481 av_frame_free(&in);
114 421481 return 0;
115 }
116 }
117
118 1676274 static int get_frame_internal(AVFilterContext *ctx, AVFrame *frame, int flags, int samples)
119 {
120 1676274 BufferSinkContext *buf = ctx->priv;
121 1676274 AVFilterLink *inlink = ctx->inputs[0];
122 int status, ret;
123 AVFrame *cur_frame;
124 int64_t pts;
125
126
2/2
✓ Branch 0 taken 1256597 times.
✓ Branch 1 taken 419677 times.
1676274 if (buf->peeked_frame)
127 419677 return return_or_keep_frame(buf, frame, buf->peeked_frame, flags);
128
129 while (1) {
130
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3129116 times.
3129116 ret = samples ? ff_inlink_consume_samples(inlink, samples, samples, &cur_frame) :
131 3129116 ff_inlink_consume_frame(inlink, &cur_frame);
132
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3129116 times.
3129116 if (ret < 0) {
133 return ret;
134
2/2
✓ Branch 0 taken 421481 times.
✓ Branch 1 taken 2707635 times.
3129116 } else if (ret) {
135 /* TODO return the frame instead of copying it */
136 421481 return return_or_keep_frame(buf, frame, cur_frame, flags);
137
2/2
✓ Branch 1 taken 5299 times.
✓ Branch 2 taken 2702336 times.
2707635 } else if (ff_inlink_acknowledge_status(inlink, &status, &pts)) {
138 5299 return status;
139
2/2
✓ Branch 0 taken 421908 times.
✓ Branch 1 taken 2280428 times.
2702336 } else if ((flags & AV_BUFFERSINK_FLAG_NO_REQUEST)) {
140 421908 return AVERROR(EAGAIN);
141
2/2
✓ Branch 0 taken 1864716 times.
✓ Branch 1 taken 415712 times.
2280428 } else if (inlink->frame_wanted_out) {
142 1864716 ret = ff_filter_graph_run_once(ctx->graph);
143
2/2
✓ Branch 0 taken 407909 times.
✓ Branch 1 taken 1456807 times.
1864716 if (ret < 0)
144 407909 return ret;
145 } else {
146 415712 ff_inlink_request_frame(inlink);
147 }
148 }
149 }
150
151 1676274 int attribute_align_arg av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flags)
152 {
153 1676274 return get_frame_internal(ctx, frame, flags, ctx->inputs[0]->min_samples);
154 }
155
156 int attribute_align_arg av_buffersink_get_samples(AVFilterContext *ctx,
157 AVFrame *frame, int nb_samples)
158 {
159 return get_frame_internal(ctx, frame, 0, nb_samples);
160 }
161
162 6503 static av_cold int common_init(AVFilterContext *ctx)
163 {
164 6503 BufferSinkContext *buf = ctx->priv;
165
166 6503 buf->warning_limit = 100;
167 6503 return 0;
168 }
169
170 6503 static void uninit(AVFilterContext *ctx)
171 {
172 6503 BufferSinkContext *buf = ctx->priv;
173
174 6503 av_frame_free(&buf->peeked_frame);
175 6503 }
176
177 424660 static int activate(AVFilterContext *ctx)
178 {
179 424660 BufferSinkContext *buf = ctx->priv;
180 424660 FilterLinkInternal * const li = ff_link_internal(ctx->inputs[0]);
181
182
1/2
✓ Branch 0 taken 424660 times.
✗ Branch 1 not taken.
424660 if (buf->warning_limit &&
183
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 424660 times.
424660 ff_framequeue_queued_frames(&li->fifo) >= buf->warning_limit) {
184 av_log(ctx, AV_LOG_WARNING,
185 "%d buffers queued in %s, something may be wrong.\n",
186 buf->warning_limit,
187 (char *)av_x_if_null(ctx->name, ctx->filter->name));
188 buf->warning_limit *= 10;
189 }
190
191 /* The frame is queued, the rest is up to get_frame_internal */
192 424660 return 0;
193 }
194
195 void av_buffersink_set_frame_size(AVFilterContext *ctx, unsigned frame_size)
196 {
197 AVFilterLink *inlink = ctx->inputs[0];
198
199 inlink->min_samples = inlink->max_samples = frame_size;
200 }
201
202 #define MAKE_AVFILTERLINK_ACCESSOR(type, field) \
203 type av_buffersink_get_##field(const AVFilterContext *ctx) { \
204 av_assert0(ctx->filter->activate == activate); \
205 return ctx->inputs[0]->field; \
206 }
207
208
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
45 MAKE_AVFILTERLINK_ACCESSOR(enum AVMediaType , type )
209
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 428010 times.
428010 MAKE_AVFILTERLINK_ACCESSOR(AVRational , time_base )
210
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6503 times.
6503 MAKE_AVFILTERLINK_ACCESSOR(int , format )
211
212
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8308 times.
8308 MAKE_AVFILTERLINK_ACCESSOR(AVRational , frame_rate )
213
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6479 times.
6479 MAKE_AVFILTERLINK_ACCESSOR(int , w )
214
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6479 times.
6479 MAKE_AVFILTERLINK_ACCESSOR(int , h )
215
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6479 times.
6479 MAKE_AVFILTERLINK_ACCESSOR(AVRational , sample_aspect_ratio)
216 MAKE_AVFILTERLINK_ACCESSOR(enum AVColorSpace, colorspace)
217 MAKE_AVFILTERLINK_ACCESSOR(enum AVColorRange, color_range)
218
219 #if FF_API_OLD_CHANNEL_LAYOUT
220 FF_DISABLE_DEPRECATION_WARNINGS
221 MAKE_AVFILTERLINK_ACCESSOR(uint64_t , channel_layout )
222 FF_ENABLE_DEPRECATION_WARNINGS
223 #endif
224
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6482 times.
6482 MAKE_AVFILTERLINK_ACCESSOR(int , sample_rate )
225
226 MAKE_AVFILTERLINK_ACCESSOR(AVBufferRef * , hw_frames_ctx )
227
228 int av_buffersink_get_channels(const AVFilterContext *ctx)
229 {
230 av_assert0(ctx->filter->activate == activate);
231 return ctx->inputs[0]->ch_layout.nb_channels;
232 }
233
234 6482 int av_buffersink_get_ch_layout(const AVFilterContext *ctx, AVChannelLayout *out)
235 {
236 6482 AVChannelLayout ch_layout = { 0 };
237 int ret;
238
239
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6482 times.
6482 av_assert0(ctx->filter->activate == activate);
240 6482 ret = av_channel_layout_copy(&ch_layout, &ctx->inputs[0]->ch_layout);
241
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6482 times.
6482 if (ret < 0)
242 return ret;
243 6482 *out = ch_layout;
244 6482 return 0;
245 }
246
247 #define CHECK_LIST_SIZE(field) \
248 if (buf->field ## _size % sizeof(*buf->field)) { \
249 av_log(ctx, AV_LOG_ERROR, "Invalid size for " #field ": %d, " \
250 "should be multiple of %d\n", \
251 buf->field ## _size, (int)sizeof(*buf->field)); \
252 return AVERROR(EINVAL); \
253 }
254 5249 static int vsink_query_formats(AVFilterContext *ctx)
255 {
256 5249 BufferSinkContext *buf = ctx->priv;
257 unsigned i;
258 int ret;
259
260
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5249 times.
5249 CHECK_LIST_SIZE(pixel_fmts)
261
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5249 times.
5249 CHECK_LIST_SIZE(color_spaces)
262
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5249 times.
5249 CHECK_LIST_SIZE(color_ranges)
263
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5249 times.
5249 if (buf->pixel_fmts_size) {
264 AVFilterFormats *formats = NULL;
265 for (i = 0; i < NB_ITEMS(buf->pixel_fmts); i++)
266 if ((ret = ff_add_format(&formats, buf->pixel_fmts[i])) < 0)
267 return ret;
268 if ((ret = ff_set_common_formats(ctx, formats)) < 0)
269 return ret;
270 }
271
272
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5249 times.
5249 if (buf->color_spaces_size) {
273 AVFilterFormats *formats = NULL;
274 for (i = 0; i < NB_ITEMS(buf->color_spaces); i++)
275 if ((ret = ff_add_format(&formats, buf->color_spaces[i])) < 0)
276 return ret;
277 if ((ret = ff_set_common_color_spaces(ctx, formats)) < 0)
278 return ret;
279 }
280
281
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5249 times.
5249 if (buf->color_ranges_size) {
282 AVFilterFormats *formats = NULL;
283 for (i = 0; i < NB_ITEMS(buf->color_ranges); i++)
284 if ((ret = ff_add_format(&formats, buf->color_ranges[i])) < 0)
285 return ret;
286 if ((ret = ff_set_common_color_ranges(ctx, formats)) < 0)
287 return ret;
288 }
289
290 5249 return 0;
291 }
292
293 1254 static int asink_query_formats(AVFilterContext *ctx)
294 {
295 1254 BufferSinkContext *buf = ctx->priv;
296 1254 AVFilterFormats *formats = NULL;
297 1254 AVChannelLayout layout = { 0 };
298 1254 AVFilterChannelLayouts *layouts = NULL;
299 unsigned i;
300 int ret;
301
302
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1254 times.
1254 CHECK_LIST_SIZE(sample_fmts)
303
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1254 times.
1254 CHECK_LIST_SIZE(sample_rates)
304 #if FF_API_OLD_CHANNEL_LAYOUT
305
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1254 times.
1254 CHECK_LIST_SIZE(channel_layouts)
306
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1254 times.
1254 CHECK_LIST_SIZE(channel_counts)
307 #endif
308
309
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 1230 times.
1254 if (buf->sample_fmts_size) {
310
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 24 times.
144 for (i = 0; i < NB_ITEMS(buf->sample_fmts); i++)
311
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 120 times.
120 if ((ret = ff_add_format(&formats, buf->sample_fmts[i])) < 0)
312 return ret;
313
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
24 if ((ret = ff_set_common_formats(ctx, formats)) < 0)
314 return ret;
315 }
316
317 1254 if (
318 #if FF_API_OLD_CHANNEL_LAYOUT
319
2/4
✓ Branch 0 taken 1254 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1254 times.
✗ Branch 3 not taken.
1254 buf->channel_layouts_size || buf->channel_counts_size ||
320 #endif
321
2/4
✓ Branch 0 taken 1254 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1254 times.
✗ Branch 3 not taken.
1254 buf->channel_layouts_str || buf->all_channel_counts) {
322 #if FF_API_OLD_CHANNEL_LAYOUT
323 1254 cleanup_redundant_layouts(ctx);
324
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1254 times.
1254 for (i = 0; i < NB_ITEMS(buf->channel_layouts); i++)
325 if ((ret = av_channel_layout_from_mask(&layout, buf->channel_layouts[i])) < 0 ||
326 (ret = ff_add_channel_layout(&layouts, &layout)) < 0)
327 return ret;
328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1254 times.
1254 for (i = 0; i < NB_ITEMS(buf->channel_counts); i++) {
329 layout = FF_COUNT2LAYOUT(buf->channel_counts[i]);
330 if ((ret = ff_add_channel_layout(&layouts, &layout)) < 0)
331 return ret;
332 }
333 #endif
334
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1254 times.
1254 if (buf->channel_layouts_str) {
335 const char *cur = buf->channel_layouts_str;
336
337 #if FF_API_OLD_CHANNEL_LAYOUT
338 if (layouts)
339 av_log(ctx, AV_LOG_WARNING,
340 "Conflicting ch_layouts and list of channel_counts/channel_layouts. Ignoring the former\n");
341 else
342 #endif
343 while (cur) {
344 char *next = strchr(cur, '|');
345 if (next)
346 *next++ = 0;
347
348 ret = av_channel_layout_from_string(&layout, cur);
349 if (ret < 0) {
350 av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout: %s.\n", cur);
351 return ret;
352 }
353 ret = ff_add_channel_layout(&layouts, &layout);
354 av_channel_layout_uninit(&layout);
355 if (ret < 0)
356 return ret;
357
358 cur = next;
359 }
360 }
361
362
1/2
✓ Branch 0 taken 1254 times.
✗ Branch 1 not taken.
1254 if (buf->all_channel_counts) {
363
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1254 times.
1254 if (layouts)
364 av_log(ctx, AV_LOG_WARNING,
365 "Conflicting all_channel_counts and list in options\n");
366
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1254 times.
1254 else if (!(layouts = ff_all_channel_counts()))
367 return AVERROR(ENOMEM);
368 }
369
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1254 times.
1254 if ((ret = ff_set_common_channel_layouts(ctx, layouts)) < 0)
370 return ret;
371 }
372
373
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1254 times.
1254 if (buf->sample_rates_size) {
374 formats = NULL;
375 for (i = 0; i < NB_ITEMS(buf->sample_rates); i++)
376 if ((ret = ff_add_format(&formats, buf->sample_rates[i])) < 0)
377 return ret;
378 if ((ret = ff_set_common_samplerates(ctx, formats)) < 0)
379 return ret;
380 }
381
382 1254 return 0;
383 }
384
385 #define OFFSET(x) offsetof(BufferSinkContext, x)
386 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
387 static const AVOption buffersink_options[] = {
388 { "pix_fmts", "set the supported pixel formats", OFFSET(pixel_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS },
389 { "color_spaces", "set the supported color spaces", OFFSET(color_spaces), AV_OPT_TYPE_BINARY, .flags = FLAGS },
390 { "color_ranges", "set the supported color ranges", OFFSET(color_ranges), AV_OPT_TYPE_BINARY, .flags = FLAGS },
391 { NULL },
392 };
393 #undef FLAGS
394 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_AUDIO_PARAM
395 static const AVOption abuffersink_options[] = {
396 { "sample_fmts", "set the supported sample formats", OFFSET(sample_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS },
397 { "sample_rates", "set the supported sample rates", OFFSET(sample_rates), AV_OPT_TYPE_BINARY, .flags = FLAGS },
398 #if FF_API_OLD_CHANNEL_LAYOUT
399 { "channel_layouts", "set the supported channel layouts (deprecated, use ch_layouts)",
400 OFFSET(channel_layouts), AV_OPT_TYPE_BINARY, .flags = FLAGS | AV_OPT_FLAG_DEPRECATED },
401 { "channel_counts", "set the supported channel counts (deprecated, use ch_layouts)",
402 OFFSET(channel_counts), AV_OPT_TYPE_BINARY, .flags = FLAGS | AV_OPT_FLAG_DEPRECATED },
403 #endif
404 { "ch_layouts", "set a '|'-separated list of supported channel layouts",
405 OFFSET(channel_layouts_str), AV_OPT_TYPE_STRING, .flags = FLAGS },
406 { "all_channel_counts", "accept all channel counts", OFFSET(all_channel_counts), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS },
407 { NULL },
408 };
409 #undef FLAGS
410
411 AVFILTER_DEFINE_CLASS(buffersink);
412 AVFILTER_DEFINE_CLASS(abuffersink);
413
414 const AVFilter ff_vsink_buffer = {
415 .name = "buffersink",
416 .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
417 .priv_size = sizeof(BufferSinkContext),
418 .priv_class = &buffersink_class,
419 .init = common_init,
420 .uninit = uninit,
421 .activate = activate,
422 FILTER_INPUTS(ff_video_default_filterpad),
423 .outputs = NULL,
424 FILTER_QUERY_FUNC(vsink_query_formats),
425 };
426
427 const AVFilter ff_asink_abuffer = {
428 .name = "abuffersink",
429 .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."),
430 .priv_class = &abuffersink_class,
431 .priv_size = sizeof(BufferSinkContext),
432 .init = common_init,
433 .uninit = uninit,
434 .activate = activate,
435 FILTER_INPUTS(ff_audio_default_filterpad),
436 .outputs = NULL,
437 FILTER_QUERY_FUNC(asink_query_formats),
438 };
439