From 0548ab2e4257f9c6e7a7a57138504533a6ca5507 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sat, 28 Sep 2024 16:10:52 +0200 Subject: [PATCH] lavu/log,opt: detect setting non-runtime options post-init Add a mechanism to AVClass to allow objects to signal their state to generic code. When an object flags itself with the 'initialized' state, print an error (and fail, after the next major bump) if the caller attempts to set non-runtime options. --- doc/APIchanges | 3 +++ libavutil/log.h | 18 ++++++++++++++++++ libavutil/opt.c | 33 +++++++++++++++++++++++++++++++++ libavutil/version.h | 2 +- 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/doc/APIchanges b/doc/APIchanges index 1939b8758f..d132dfab81 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2024-03-07 API changes, most recent first: +2024-10-xx - xxxxxxxxxx - lavu 59.41.100 - log.h + Add AVClass.state_flags_offset and AV_CLASS_STATE_INITIALIZED. + 2024-09-30 - xxxxxxxxxx - lavf 61.9.100 - avformat.h Add {nb_}coded_side_data to AVStreamGroupTileGrid. diff --git a/libavutil/log.h b/libavutil/log.h index 2860d4f039..4c8c92266f 100644 --- a/libavutil/log.h +++ b/libavutil/log.h @@ -46,6 +46,15 @@ typedef enum { AV_CLASS_CATEGORY_NB ///< not part of ABI/API }AVClassCategory; +enum AVClassStateFlags { + /** + * Object initialization has finished and it is now in the 'runtime' stage. + * This affects e.g. what options can be set on the object (only + * AV_OPT_FLAG_RUNTIME_PARAM options can be set on initialized objects). + */ + AV_CLASS_STATE_INITIALIZED = (1 << 0), +}; + #define AV_IS_INPUT_DEVICE(category) \ (((category) == AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT) || \ ((category) == AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT) || \ @@ -155,6 +164,15 @@ typedef struct AVClass { * instance of this class. */ const struct AVClass* (*child_class_iterate)(void **iter); + + /** + * When non-zero, offset in the object to an unsigned int holding object + * state flags, a combination of AVClassStateFlags values. The flags are + * updated by the object to signal its state to the generic code. + * + * Added in version 59.41.100. + */ + int state_flags_offset; } AVClass; /** diff --git a/libavutil/opt.c b/libavutil/opt.c index b32a9432df..7dc4fdb062 100644 --- a/libavutil/opt.c +++ b/libavutil/opt.c @@ -185,6 +185,39 @@ static int opt_set_init(void *obj, const char *name, int search_flags, return AVERROR(EINVAL); } + if (!(o->flags & AV_OPT_FLAG_RUNTIME_PARAM)) { + unsigned *state_flags = NULL; + const AVClass *class; + + // try state flags first from the target (child), then from its parent + class = *(const AVClass**)tgt; + if ( +#if LIBAVUTIL_VERSION_MAJOR < 60 + class->version >= AV_VERSION_INT(59, 41, 100) && +#endif + class->state_flags_offset) + state_flags = (unsigned*)((uint8_t*)tgt + class->state_flags_offset); + + if (!state_flags && obj != tgt) { + class = *(const AVClass**)obj; + if ( +#if LIBAVUTIL_VERSION_MAJOR < 60 + class->version >= AV_VERSION_INT(59, 41, 100) && +#endif + class->state_flags_offset) + state_flags = (unsigned*)((uint8_t*)obj + class->state_flags_offset); + } + + if (state_flags && (*state_flags & AV_CLASS_STATE_INITIALIZED)) { + av_log(obj, AV_LOG_ERROR, "Option '%s' is not a runtime option and " + "so cannot be set after the object has been initialized\n", + o->name); +#if LIBAVUTIL_VERSION_MAJOR >= 60 + return AVERROR(EINVAL); +#endif + } + } + if (o->flags & AV_OPT_FLAG_DEPRECATED) av_log(obj, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", name, o->help); diff --git a/libavutil/version.h b/libavutil/version.h index 69519cfd06..18f1d00145 100644 --- a/libavutil/version.h +++ b/libavutil/version.h @@ -79,7 +79,7 @@ */ #define LIBAVUTIL_VERSION_MAJOR 59 -#define LIBAVUTIL_VERSION_MINOR 40 +#define LIBAVUTIL_VERSION_MINOR 41 #define LIBAVUTIL_VERSION_MICRO 100 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \