diff mbox series

[FFmpeg-devel,13/17] lavfi/buffersink: add array-type options to replace "int-list" ones

Message ID 20240926161901.31421-3-anton@khirnov.net
State New
Headers show
Series [FFmpeg-devel,01/10] fftools/ffmpeg_filter: stop using avfilter_graph_alloc_filter() incorrectly | expand

Checks

Context Check Description
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Anton Khirnov Sept. 26, 2024, 4:18 p.m. UTC
"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 mbox series

Patch

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 */