[FFmpeg-devel] [PATCH v3 02/17] avcodec: add avcodec_get_supported_config()

Niklas Haas ffmpeg at haasn.xyz
Fri Aug 30 13:15:25 EEST 2024


From: Niklas Haas <git at haasn.dev>

This replaces the myriad of existing lists in AVCodec by a unified API
call, allowing us to (ultimately) trim down the sizeof(AVCodec) quite
substantially, while also making this more trivially extensible.

In addition to the already covered lists, add two new entries for color
space and color range, mirroring the newly added negotiable fields in
libavfilter.

Once the deprecation period passes for the existing public fields, the
rough plan is to move the commonly used fields (such as
pix_fmt/sample_fmt) into FFCodec, possibly as a union of audio and video
configuration types, and then implement the rarely used fields with
custom callbacks.
---
 doc/APIchanges              |  5 ++
 libavcodec/avcodec.c        | 94 +++++++++++++++++++++++++++++++++++++
 libavcodec/avcodec.h        | 30 ++++++++++++
 libavcodec/codec.h          | 19 ++++++--
 libavcodec/codec_internal.h | 27 +++++++++++
 libavcodec/version.h        |  2 +-
 6 files changed, 172 insertions(+), 5 deletions(-)

diff --git a/doc/APIchanges b/doc/APIchanges
index 226c6f8b10..e81e8b1841 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -2,6 +2,11 @@ The last version increases of all libraries were on 2024-03-07
 
 API changes, most recent first:
 
+2024-08-xx - xxxxxxxxxx - lavc 61.12.100 - avcodec.h
+  Add avcodec_get_supported_config() and enum AVCodecConfig; deprecate
+  AVCodec.pix_fmts, AVCodec.sample_fmts, AVCodec.supported_framerates,
+  AVCodec.supported_samplerates and AVCodec.ch_layouts.
+
 2024-08-xx - xxxxxxxxx - lavu 59.35.100 - opt.h
   Add av_opt_get_array_size() and av_opt_get_array().
 
diff --git a/libavcodec/avcodec.c b/libavcodec/avcodec.c
index 6065f1b689..ad25e02613 100644
--- a/libavcodec/avcodec.c
+++ b/libavcodec/avcodec.c
@@ -28,6 +28,7 @@
 #include "libavutil/avstring.h"
 #include "libavutil/bprint.h"
 #include "libavutil/channel_layout.h"
+#include "libavutil/common.h"
 #include "libavutil/emms.h"
 #include "libavutil/fifo.h"
 #include "libavutil/imgutils.h"
@@ -706,3 +707,96 @@ int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *fr
         return ff_decode_receive_frame(avctx, frame);
     return ff_encode_receive_frame(avctx, frame);
 }
+
+#define WRAP_CONFIG(allowed_type, field, terminator)                        \
+    do {                                                                    \
+        static const __typeof__(*(field)) sentinel = terminator;            \
+        if (codec->type != (allowed_type))                                  \
+            return AVERROR(EINVAL);                                         \
+        *out_configs = (field);                                             \
+        if (out_num_configs) {                                              \
+            for (int i = 0;; i++) {                                         \
+                if (!memcmp(&(field)[i], &sentinel, sizeof(sentinel))) {    \
+                    *out_num_configs = i;                                   \
+                    break;                                                  \
+                }                                                           \
+            }                                                               \
+        }                                                                   \
+        return 0;                                                           \
+    } while (0)
+
+static const enum AVColorRange color_range_jpeg[] = {
+    AVCOL_RANGE_JPEG, AVCOL_RANGE_UNSPECIFIED
+};
+
+static const enum AVColorRange color_range_mpeg[] = {
+    AVCOL_RANGE_MPEG, AVCOL_RANGE_UNSPECIFIED
+};
+
+static const enum AVColorRange color_range_all[] = {
+    AVCOL_RANGE_MPEG, AVCOL_RANGE_JPEG, AVCOL_RANGE_UNSPECIFIED
+};
+
+static const enum AVColorRange *color_range_table[] = {
+    [AVCOL_RANGE_MPEG] = color_range_mpeg,
+    [AVCOL_RANGE_JPEG] = color_range_jpeg,
+    [AVCOL_RANGE_MPEG | AVCOL_RANGE_JPEG] = color_range_all,
+};
+
+int ff_default_get_supported_config(const AVCodecContext *avctx,
+                                    const AVCodec *codec,
+                                    enum AVCodecConfig config,
+                                    unsigned flags,
+                                    const void **out_configs,
+                                    int *out_num_configs)
+{
+    switch (config) {
+FF_DISABLE_DEPRECATION_WARNINGS
+    case AV_CODEC_CONFIG_PIX_FORMAT:
+        WRAP_CONFIG(AVMEDIA_TYPE_VIDEO, codec->pix_fmts, AV_PIX_FMT_NONE);
+    case AV_CODEC_CONFIG_FRAME_RATE:
+        WRAP_CONFIG(AVMEDIA_TYPE_VIDEO, codec->supported_framerates, (AVRational){0});
+    case AV_CODEC_CONFIG_SAMPLE_RATE:
+        WRAP_CONFIG(AVMEDIA_TYPE_AUDIO, codec->supported_samplerates, 0);
+    case AV_CODEC_CONFIG_SAMPLE_FORMAT:
+        WRAP_CONFIG(AVMEDIA_TYPE_AUDIO, codec->sample_fmts, AV_SAMPLE_FMT_NONE);
+    case AV_CODEC_CONFIG_CHANNEL_LAYOUT:
+        WRAP_CONFIG(AVMEDIA_TYPE_AUDIO, codec->ch_layouts, (AVChannelLayout){0});
+FF_ENABLE_DEPRECATION_WARNINGS
+
+    case AV_CODEC_CONFIG_COLOR_RANGE:
+        if (codec->type != AVMEDIA_TYPE_VIDEO)
+            return AVERROR(EINVAL);
+        *out_configs = color_range_table[ffcodec(codec)->color_ranges];
+        if (out_num_configs)
+            *out_num_configs = av_popcount(ffcodec(codec)->color_ranges);
+        return 0;
+
+    case AV_CODEC_CONFIG_COLOR_SPACE:
+        *out_configs = NULL;
+        if (out_num_configs)
+            *out_num_configs = 0;
+        return 0;
+    default:
+        return AVERROR(EINVAL);
+    }
+}
+
+int avcodec_get_supported_config(const AVCodecContext *avctx, const AVCodec *codec,
+                                 enum AVCodecConfig config, unsigned flags,
+                                 const void **out, int *out_num)
+{
+    const FFCodec *codec2;
+    int dummy_num = 0;
+    if (!codec)
+        codec = avctx->codec;
+    if (!out_num)
+        out_num = &dummy_num;
+
+    codec2 = ffcodec(codec);
+    if (codec2->get_supported_config) {
+        return codec2->get_supported_config(avctx, codec, config, flags, out, out_num);
+    } else {
+        return ff_default_get_supported_config(avctx, codec, config, flags, out, out_num);
+    }
+}
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 7a67300134..376e130f7d 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -2695,6 +2695,36 @@ int avcodec_get_hw_frames_parameters(AVCodecContext *avctx,
                                      enum AVPixelFormat hw_pix_fmt,
                                      AVBufferRef **out_frames_ref);
 
+enum AVCodecConfig {
+    AV_CODEC_CONFIG_PIX_FORMAT,     ///< AVPixelFormat, terminated by AV_PIX_FMT_NONE
+    AV_CODEC_CONFIG_FRAME_RATE,     ///< AVRational, terminated by {0, 0}
+    AV_CODEC_CONFIG_SAMPLE_RATE,    ///< int, terminated by 0
+    AV_CODEC_CONFIG_SAMPLE_FORMAT,  ///< AVSampleFormat, terminated by AV_SAMPLE_FMT_NONE
+    AV_CODEC_CONFIG_CHANNEL_LAYOUT, ///< AVChannelLayout, terminated by {0}
+    AV_CODEC_CONFIG_COLOR_RANGE,    ///< AVColorRange, terminated by AVCOL_RANGE_UNSPECIFIED
+    AV_CODEC_CONFIG_COLOR_SPACE,    ///< AVColorSpace, terminated by AVCOL_SPC_UNSPECIFIED
+};
+
+/**
+ * Retrieve a list of all supported values for a given configuration type.
+ *
+ * @param avctx An optional context to use. Values such as
+ *              `strict_std_compliance` may affect the result. If NULL,
+ *              default values are used.
+ * @param codec The codec to query, or NULL to use avctx->codec.
+ * @param config The configuration to query.
+ * @param flags Currently unused; should be set to zero.
+ * @param out_configs On success, set to a list of configurations, terminated
+ *                    by a config-specific terminator, or NULL if all
+ *                    possible values are supported.
+ * @param out_num_configs On success, set to the number of elements in
+                          *out_configs, excluding the terminator. Optional.
+ */
+int avcodec_get_supported_config(const AVCodecContext *avctx,
+                                 const AVCodec *codec, enum AVCodecConfig config,
+                                 unsigned flags, const void **out_configs,
+                                 int *out_num_configs);
+
 
 
 /**
diff --git a/libavcodec/codec.h b/libavcodec/codec.h
index 6f9b42760d..f7541ffc42 100644
--- a/libavcodec/codec.h
+++ b/libavcodec/codec.h
@@ -205,10 +205,19 @@ typedef struct AVCodec {
      */
     int capabilities;
     uint8_t max_lowres;                     ///< maximum value for lowres supported by the decoder
-    const AVRational *supported_framerates; ///< array of supported framerates, or NULL if any, array is terminated by {0,0}
-    const enum AVPixelFormat *pix_fmts;     ///< array of supported pixel formats, or NULL if unknown, array is terminated by -1
-    const int *supported_samplerates;       ///< array of supported audio samplerates, or NULL if unknown, array is terminated by 0
-    const enum AVSampleFormat *sample_fmts; ///< array of supported sample formats, or NULL if unknown, array is terminated by -1
+
+    /**
+     * Deprecated codec capabilities.
+     */
+    attribute_deprecated
+    const AVRational *supported_framerates; ///< @deprecated use avcodec_get_supported_config()
+    attribute_deprecated
+    const enum AVPixelFormat *pix_fmts;     ///< @deprecated use avcodec_get_supported_config()
+    attribute_deprecated
+    const int *supported_samplerates;       ///< @deprecated use avcodec_get_supported_config()
+    attribute_deprecated
+    const enum AVSampleFormat *sample_fmts; ///< @deprecated use avcodec_get_supported_config()
+
     const AVClass *priv_class;              ///< AVClass for the private context
     const AVProfile *profiles;              ///< array of recognized profiles, or NULL if unknown, array is terminated by {AV_PROFILE_UNKNOWN}
 
@@ -226,7 +235,9 @@ typedef struct AVCodec {
 
     /**
      * Array of supported channel layouts, terminated with a zeroed layout.
+     * @deprecated use avcodec_get_supported_config()
      */
+    attribute_deprecated
     const AVChannelLayout *ch_layouts;
 } AVCodec;
 
diff --git a/libavcodec/codec_internal.h b/libavcodec/codec_internal.h
index 6fdd261066..84a4376753 100644
--- a/libavcodec/codec_internal.h
+++ b/libavcodec/codec_internal.h
@@ -22,6 +22,7 @@
 #include <stdint.h>
 
 #include "libavutil/attributes.h"
+#include "avcodec.h"
 #include "codec.h"
 #include "config.h"
 
@@ -269,8 +270,34 @@ typedef struct FFCodec {
      * List of supported codec_tags, terminated by FF_CODEC_TAGS_END.
      */
     const uint32_t *codec_tags;
+
+    /**
+     * Custom callback for avcodec_get_supported_config(). If absent,
+     * ff_default_get_supported_config() will be used. `out_num_configs` will
+     * always be set to a valid pointer.
+     */
+    int (*get_supported_config)(const AVCodecContext *avctx,
+                                const AVCodec *codec,
+                                enum AVCodecConfig config,
+                                unsigned flags,
+                                const void **out_configs,
+                                int *out_num_configs);
 } FFCodec;
 
+/**
+ * Default implementation for avcodec_get_supported_config(). Will return the
+ * relevant fields from AVCodec if present, or NULL otherwise.
+ *
+ * For AVCODEC_CONFIG_COLOR_RANGE, the output will depend on the bitmask in
+ * FFCodec.color_ranges, with a value of 0 returning NULL.
+ */
+int ff_default_get_supported_config(const AVCodecContext *avctx,
+                                    const AVCodec *codec,
+                                    enum AVCodecConfig config,
+                                    unsigned flags,
+                                    const void **out_configs,
+                                    int *out_num_configs);
+
 #if CONFIG_SMALL
 #define CODEC_LONG_NAME(str) .p.long_name = NULL
 #else
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 8b53586be1..da2264a097 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -29,7 +29,7 @@
 
 #include "version_major.h"
 
-#define LIBAVCODEC_VERSION_MINOR  11
+#define LIBAVCODEC_VERSION_MINOR  12
 #define LIBAVCODEC_VERSION_MICRO 100
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
-- 
2.46.0



More information about the ffmpeg-devel mailing list