From 1efcdbc54d9659351c01faed59fec666ed1df3c9 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Wed, 25 Sep 2024 17:34:13 +0200 Subject: [PATCH] lavfi/buffersink: add array-type options to replace "int-list" ones "int-list" options are a hack that provides rudimentary support for array-type options by treating them as byte arrays (i.e. AV_OPT_TYPE_BINARY). Since we now have proper array-type options, they should replace "int-list" everywhere (which happens to be just buffersink). --- doc/APIchanges | 18 ++++ libavfilter/buffersink.c | 162 ++++++++++++++++++++++++++++++++---- libavfilter/buffersink.h | 21 ++--- libavfilter/version.h | 2 +- libavfilter/version_major.h | 1 + 5 files changed, 175 insertions(+), 29 deletions(-) diff --git a/doc/APIchanges b/doc/APIchanges index ddd4e6c9e0..a79353f79b 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -2,6 +2,24 @@ The last version increases of all libraries were on 2024-03-07 API changes, most recent first: +2024-09-xx - xxxxxxxxxx - lavfi 10.6.100 + Buffersink now has array-type options + - pixel_formats + - colorspaces + - colorranges + replacing the int-list options + - pix_fmts + - color_spaces + - color_ranges + abuffersink now has array-type options + - sample_formats + - samplerates + - channel_layouts + replacing the int-list/string options + - sample_fmts + - sample_rates + - ch_layouts + -------- 8< --------- FFmpeg 7.1 was cut here -------- 8< --------- 2024-09-23 - 6940a6de2f0 - lavu 59.38.100 - frame.h diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c index af4dc38792..0cfac2abd5 100644 --- a/libavfilter/buffersink.c +++ b/libavfilter/buffersink.c @@ -28,6 +28,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/common.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "audio.h" @@ -45,26 +46,46 @@ typedef struct BufferSinkContext { unsigned frame_size; /* only used for video */ +#if FF_API_BUFFERSINK_OPTS enum AVPixelFormat *pixel_fmts; ///< list of accepted pixel formats int pixel_fmts_size; enum AVColorSpace *color_spaces; ///< list of accepted color spaces int color_spaces_size; enum AVColorRange *color_ranges; ///< list of accepted color ranges int color_ranges_size; +#endif + + enum AVPixelFormat *pixel_formats; + unsigned nb_pixel_formats; + + int *colorspaces; + unsigned nb_colorspaces; + + int *colorranges; + unsigned nb_colorranges; /* only used for audio */ +#if FF_API_BUFFERSINK_OPTS enum AVSampleFormat *sample_fmts; ///< list of accepted sample formats int sample_fmts_size; char *channel_layouts_str; ///< list of accepted channel layouts int all_channel_counts; int *sample_rates; ///< list of accepted sample rates int sample_rates_size; +#endif + + enum AVSampleFormat *sample_formats; + unsigned nb_sample_formats; + + int *samplerates; + unsigned nb_samplerates; + + AVChannelLayout *channel_layouts; + unsigned nb_channel_layouts; AVFrame *peeked_frame; } BufferSinkContext; -#define NB_ITEMS(list) (list ## _size / sizeof(*list)) - int attribute_align_arg av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame) { return av_buffersink_get_frame_flags(ctx, frame, 0); @@ -138,6 +159,39 @@ static av_cold int common_init(AVFilterContext *ctx) return 0; } +#define TERMINATE_ARRAY(arr, val) \ + if (s->arr) { \ + void *tmp = av_realloc_array(s->arr, s->nb_ ## arr + 1, sizeof(*s->arr)); \ + if (!tmp) \ + return AVERROR(ENOMEM); \ + s->arr = tmp; \ + s->arr[s->nb_ ## arr] = val; \ + } + +static int init_video(AVFilterContext *ctx) +{ + BufferSinkContext *s = ctx->priv; + + TERMINATE_ARRAY(pixel_formats, AV_PIX_FMT_NONE); + TERMINATE_ARRAY(colorranges, -1); + TERMINATE_ARRAY(colorspaces, -1); + + return common_init(ctx); +} + +static int init_audio(AVFilterContext *ctx) +{ + BufferSinkContext *s = ctx->priv; + + TERMINATE_ARRAY(sample_formats, AV_SAMPLE_FMT_NONE); + TERMINATE_ARRAY(samplerates, -1); + TERMINATE_ARRAY(channel_layouts, (AVChannelLayout){ .nb_channels = 0 }); + + return common_init(ctx); +} + +#undef TERMINATE_ARRAY + static void uninit(AVFilterContext *ctx) { BufferSinkContext *buf = ctx->priv; @@ -235,6 +289,9 @@ int av_buffersink_get_ch_layout(const AVFilterContext *ctx, AVChannelLayout *out return 0; } +#if FF_API_BUFFERSINK_OPTS +#define NB_ITEMS(list) (list ## _size / sizeof(*list)) + #define CHECK_LIST_SIZE(field) \ if (buf->field ## _size % sizeof(*buf->field)) { \ av_log(ctx, AV_LOG_ERROR, "Invalid size for " #field ": %d, " \ @@ -242,12 +299,40 @@ int av_buffersink_get_ch_layout(const AVFilterContext *ctx, AVChannelLayout *out buf->field ## _size, (int)sizeof(*buf->field)); \ return AVERROR(EINVAL); \ } +#endif + static int vsink_query_formats(AVFilterContext *ctx) { BufferSinkContext *buf = ctx->priv; - unsigned i; int ret; +#if FF_API_BUFFERSINK_OPTS + if ((buf->pixel_fmts_size || buf->color_spaces_size || buf->color_ranges_size) && + (buf->nb_pixel_formats || buf->nb_colorspaces || buf->nb_colorranges)) { + av_log(ctx, AV_LOG_ERROR, "Cannot combine old and new format lists\n"); + return AVERROR(EINVAL); + } + + if (buf->nb_pixel_formats || buf->nb_colorspaces || buf->nb_colorranges) { +#endif + if (buf->nb_pixel_formats) { + ret = ff_set_common_formats_from_list(ctx, buf->pixel_formats); + if (ret < 0) + return ret; + } + if (buf->nb_colorspaces) { + ret = ff_set_common_color_spaces_from_list(ctx, buf->colorspaces); + if (ret < 0) + return ret; + } + if (buf->nb_colorranges) { + ret = ff_set_common_color_ranges_from_list(ctx, buf->colorranges); + if (ret < 0) + return ret; + } +#if FF_API_BUFFERSINK_OPTS + } else { + unsigned i; CHECK_LIST_SIZE(pixel_fmts) CHECK_LIST_SIZE(color_spaces) CHECK_LIST_SIZE(color_ranges) @@ -277,6 +362,8 @@ static int vsink_query_formats(AVFilterContext *ctx) if ((ret = ff_set_common_color_ranges(ctx, formats)) < 0) return ret; } + } +#endif return 0; } @@ -284,12 +371,38 @@ static int vsink_query_formats(AVFilterContext *ctx) static int asink_query_formats(AVFilterContext *ctx) { BufferSinkContext *buf = ctx->priv; + int ret; + +#if FF_API_BUFFERSINK_OPTS + if ((buf->sample_fmts_size || buf->channel_layouts_str || buf->sample_rates_size) && + (buf->nb_sample_formats || buf->nb_samplerates || buf->nb_channel_layouts)) { + av_log(ctx, AV_LOG_ERROR, "Cannot combine old and new format lists\n"); + return AVERROR(EINVAL); + } + + if (buf->nb_sample_formats || buf->nb_samplerates || buf->nb_channel_layouts) { +#endif + if (buf->nb_sample_formats) { + ret = ff_set_common_formats_from_list(ctx, buf->sample_formats); + if (ret < 0) + return ret; + } + if (buf->nb_samplerates) { + ret = ff_set_common_samplerates_from_list(ctx, buf->samplerates); + if (ret < 0) + return ret; + } + if (buf->nb_channel_layouts) { + ret = ff_set_common_channel_layouts_from_list(ctx, buf->channel_layouts); + if (ret < 0) + return ret; + } +#if FF_API_BUFFERSINK_OPTS + } else { AVFilterFormats *formats = NULL; AVChannelLayout layout = { 0 }; AVFilterChannelLayouts *layouts = NULL; unsigned i; - int ret; - CHECK_LIST_SIZE(sample_fmts) CHECK_LIST_SIZE(sample_rates) @@ -343,6 +456,8 @@ static int asink_query_formats(AVFilterContext *ctx) if ((ret = ff_set_common_samplerates(ctx, formats)) < 0) return ret; } + } +#endif return 0; } @@ -350,19 +465,38 @@ static int asink_query_formats(AVFilterContext *ctx) #define OFFSET(x) offsetof(BufferSinkContext, x) #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM static const AVOption buffersink_options[] = { - { "pix_fmts", "set the supported pixel formats", OFFSET(pixel_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS }, - { "color_spaces", "set the supported color spaces", OFFSET(color_spaces), AV_OPT_TYPE_BINARY, .flags = FLAGS }, - { "color_ranges", "set the supported color ranges", OFFSET(color_ranges), AV_OPT_TYPE_BINARY, .flags = FLAGS }, +#if FF_API_BUFFERSINK_OPTS + { "pix_fmts", "set the supported pixel formats", OFFSET(pixel_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS | AV_OPT_FLAG_DEPRECATED }, + { "color_spaces", "set the supported color spaces", OFFSET(color_spaces), AV_OPT_TYPE_BINARY, .flags = FLAGS | AV_OPT_FLAG_DEPRECATED }, + { "color_ranges", "set the supported color ranges", OFFSET(color_ranges), AV_OPT_TYPE_BINARY, .flags = FLAGS | AV_OPT_FLAG_DEPRECATED }, +#endif + + { "pixel_formats", "array of supported pixel formats", OFFSET(pixel_formats), + AV_OPT_TYPE_PIXEL_FMT | AV_OPT_TYPE_FLAG_ARRAY, .max = INT_MAX, .flags = FLAGS }, + { "colorspaces", "array of supported color spaces", OFFSET(colorspaces), + AV_OPT_TYPE_INT | AV_OPT_TYPE_FLAG_ARRAY, .max = INT_MAX, .flags = FLAGS }, + { "colorranges", "array of supported color ranges", OFFSET(colorranges), + AV_OPT_TYPE_INT | AV_OPT_TYPE_FLAG_ARRAY, .max = INT_MAX, .flags = FLAGS }, + { NULL }, }; #undef FLAGS #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_AUDIO_PARAM static const AVOption abuffersink_options[] = { - { "sample_fmts", "set the supported sample formats", OFFSET(sample_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS }, - { "sample_rates", "set the supported sample rates", OFFSET(sample_rates), AV_OPT_TYPE_BINARY, .flags = FLAGS }, +#if FF_API_BUFFERSINK_OPTS + { "sample_fmts", "set the supported sample formats", OFFSET(sample_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS | AV_OPT_FLAG_DEPRECATED }, + { "sample_rates", "set the supported sample rates", OFFSET(sample_rates), AV_OPT_TYPE_BINARY, .flags = FLAGS | AV_OPT_FLAG_DEPRECATED }, { "ch_layouts", "set a '|'-separated list of supported channel layouts", - OFFSET(channel_layouts_str), AV_OPT_TYPE_STRING, .flags = FLAGS }, - { "all_channel_counts", "accept all channel counts", OFFSET(all_channel_counts), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS }, + OFFSET(channel_layouts_str), AV_OPT_TYPE_STRING, .flags = FLAGS | AV_OPT_FLAG_DEPRECATED }, + { "all_channel_counts", "accept all channel counts", OFFSET(all_channel_counts), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS | AV_OPT_FLAG_DEPRECATED }, +#endif + + { "sample_formats", "array of supported sample formats", OFFSET(sample_formats), + AV_OPT_TYPE_SAMPLE_FMT | AV_OPT_TYPE_FLAG_ARRAY, .max = INT_MAX, .flags = FLAGS }, + { "samplerates", "array of supported sample formats", OFFSET(samplerates), + AV_OPT_TYPE_INT | AV_OPT_TYPE_FLAG_ARRAY, .max = INT_MAX, .flags = FLAGS }, + { "channel_layouts", "array of supported channel layouts", OFFSET(channel_layouts), + AV_OPT_TYPE_CHLAYOUT | AV_OPT_TYPE_FLAG_ARRAY, .flags = FLAGS }, { NULL }, }; #undef FLAGS @@ -375,7 +509,7 @@ const AVFilter ff_vsink_buffer = { .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."), .priv_size = sizeof(BufferSinkContext), .priv_class = &buffersink_class, - .init = common_init, + .init = init_video, .uninit = uninit, .activate = activate, FILTER_INPUTS(ff_video_default_filterpad), @@ -396,7 +530,7 @@ const AVFilter ff_asink_abuffer = { .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."), .priv_class = &abuffersink_class, .priv_size = sizeof(BufferSinkContext), - .init = common_init, + .init = init_audio, .uninit = uninit, .activate = activate, FILTER_INPUTS(inputs_audio), diff --git a/libavfilter/buffersink.h b/libavfilter/buffersink.h index 361d603679..08cb6b3804 100644 --- a/libavfilter/buffersink.h +++ b/libavfilter/buffersink.h @@ -54,20 +54,13 @@ * * The format can be constrained by setting options, using av_opt_set() and * related functions with the AV_OPT_SEARCH_CHILDREN flag. - * - pix_fmts (int list), - * - color_spaces (int list), - * - color_ranges (int list), - * - sample_fmts (int list), - * - sample_rates (int list), - * - ch_layouts (string), - * - channel_counts (int list), - * - all_channel_counts (bool). - * Most of these options are of type binary, and should be set using - * av_opt_set_int_list() or av_opt_set_bin(). If they are not set, all - * corresponding formats are accepted. - * - * As a special case, if ch_layouts is not set, all valid channel layouts are - * accepted except for UNSPEC layouts, unless all_channel_counts is set. + * - pixel_formats (array of pixel formats), + * - colorspaces (array of int), + * - colorranges (array of int), + * - sample_formats (array of sample formats), + * - samplerates (array of int), + * - channel_layouts (array of channel layouts) + * If an option is not set, all corresponding formats are accepted. */ /** diff --git a/libavfilter/version.h b/libavfilter/version.h index 523a7fe0a6..f191d98883 100644 --- a/libavfilter/version.h +++ b/libavfilter/version.h @@ -31,7 +31,7 @@ #include "version_major.h" -#define LIBAVFILTER_VERSION_MINOR 5 +#define LIBAVFILTER_VERSION_MINOR 6 #define LIBAVFILTER_VERSION_MICRO 100 diff --git a/libavfilter/version_major.h b/libavfilter/version_major.h index c5e660eeda..b2c761370f 100644 --- a/libavfilter/version_major.h +++ b/libavfilter/version_major.h @@ -36,5 +36,6 @@ */ #define FF_API_LINK_PUBLIC (LIBAVFILTER_VERSION_MAJOR < 11) +#define FF_API_BUFFERSINK_OPTS (LIBAVFILTER_VERSION_MAJOR < 11) #endif /* AVFILTER_VERSION_MAJOR_H */