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.
This commit is contained in:
Anton Khirnov 2024-09-28 16:10:52 +02:00
parent 3785b27b76
commit 0548ab2e42
4 changed files with 55 additions and 1 deletions

View File

@ -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.

View File

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

View File

@ -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);

View File

@ -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, \