This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit bd68a6130495fe17bf33e0a9ddc053baae18c81f Author: James Almer <[email protected]> AuthorDate: Sun Feb 16 21:17:53 2025 -0300 Commit: James Almer <[email protected]> CommitDate: Thu Aug 13 11:00:00 2026 -0300 avutil/opt: allow passing a fake object to av_opt_set() The result will be a dry run of the process, where no value is set but all the checks are made. Useful for, as the AV_OPT_SEARCH_FAKE_OBJ flag states, run the relevant process without having to allocate the corresponding object. Signed-off-by: James Almer <[email protected]> --- libavutil/opt.c | 140 +++++++++++++++++++++++++++++++++++++++++++------------- libavutil/opt.h | 11 +++-- 2 files changed, 114 insertions(+), 37 deletions(-) diff --git a/libavutil/opt.c b/libavutil/opt.c index 9a773e8a38..a4709740bd 100644 --- a/libavutil/opt.c +++ b/libavutil/opt.c @@ -166,18 +166,21 @@ static int opt_set_init(void *obj, const char *name, int search_flags, int require_type, void **ptgt, const AVOption **po, void **pdst) { + void *logctx; const AVOption *o; void *tgt; o = av_opt_find2(obj, name, NULL, 0, search_flags, &tgt); - if (!o || !tgt) + if (!o || (!tgt && !(search_flags & AV_OPT_SEARCH_FAKE_OBJ))) return AVERROR_OPTION_NOT_FOUND; if (o->flags & AV_OPT_FLAG_READONLY) return AVERROR(EINVAL); + logctx = tgt ? obj : NULL; + if (require_type && (o->type != require_type)) { - av_log(obj, AV_LOG_ERROR, + av_log(logctx, AV_LOG_ERROR, "Tried to set option '%s' of type %s from value of type %s, " "this is not supported\n", o->name, opt_type_desc[o->type].name, opt_type_desc[require_type].name); @@ -200,7 +203,7 @@ static int opt_set_init(void *obj, const char *name, int search_flags, } if (state_flags && (*state_flags & AV_CLASS_STATE_INITIALIZED)) { - av_log(obj, AV_LOG_ERROR, "Option '%s' is not a runtime option and " + av_log(logctx, AV_LOG_ERROR, "Option '%s' is not a runtime option and " "so cannot be set after the object has been initialized\n", o->name); return AVERROR(EINVAL); @@ -208,14 +211,14 @@ static int opt_set_init(void *obj, const char *name, int search_flags, } if (o->flags & AV_OPT_FLAG_DEPRECATED) - av_log(obj, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", name, o->help); + av_log(logctx, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", name, o->help); if (po) *po = o; if (ptgt) *ptgt = tgt; if (pdst) - *pdst = ((uint8_t *)tgt) + o->offset; + *pdst = tgt ? ((uint8_t *)tgt) + o->offset : NULL; return 0; } @@ -271,6 +274,7 @@ static int read_number(const AVOption *o, const void *dst, double *num, int *den static int write_number(void *obj, const AVOption *o, void *dst, double num, int den, int64_t intnum) { + void *logctx = dst ? obj : NULL; const enum AVOptionType type = TYPE_BASE(o->type); if (type != AV_OPT_TYPE_FLAGS && @@ -283,13 +287,16 @@ static int write_number(void *obj, const AVOption *o, void *dst, double num, int if (type == AV_OPT_TYPE_FLAGS) { double d = num*intnum/den; if (d < -1.5 || d > 0xFFFFFFFF+0.5 || (llrint(d*256) & 255)) { - av_log(obj, AV_LOG_ERROR, + av_log(logctx, AV_LOG_ERROR, "Value %f for parameter '%s' is not a valid set of 32bit integer flags\n", num*intnum/den, o->name); return AVERROR(ERANGE); } } + if (!dst) + return 0; + switch (type) { case AV_OPT_TYPE_PIXEL_FMT: *(enum AVPixelFormat *)dst = llrint(num / den) * intnum; @@ -356,12 +363,15 @@ static int hexchar2int(char c) { static int set_string_binary(void *obj, const AVOption *o, const char *val, uint8_t **dst) { - int *lendst = (int *)(dst + 1); + int *lendst; uint8_t *bin, *ptr; int len; + if (dst) { + lendst = (int *)(dst + 1); av_freep(dst); *lendst = 0; + } if (!val || !(len = strlen(val))) return 0; @@ -382,14 +392,19 @@ static int set_string_binary(void *obj, const AVOption *o, const char *val, uint } *ptr++ = (a << 4) | b; } + if (dst) { *dst = bin; *lendst = len; + } else + av_free(bin); return 0; } static int set_string(void *obj, const AVOption *o, const char *val, uint8_t **dst) { + if (!dst) + return 0; av_freep(dst); if (!val) return 0; @@ -408,6 +423,7 @@ static int set_string(void *obj, const AVOption *o, const char *val, uint8_t **d static int set_string_number(void *obj, void *target_obj, const AVOption *o, const char *val, void *dst) { + void *logctx = dst ? obj : NULL; const enum AVOptionType type = TYPE_BASE(o->type); int ret = 0; @@ -446,7 +462,7 @@ static int set_string_number(void *obj, void *target_obj, const AVOption *o, con if (o_named && o_named->type == AV_OPT_TYPE_CONST) { d = DEFAULT_NUMVAL(o_named); if (o_named->flags & AV_OPT_FLAG_DEPRECATED) - av_log(obj, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", + av_log(logctx, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", o_named->name, o_named->help); } else { if (o->unit) { @@ -455,7 +471,7 @@ static int set_string_number(void *obj, void *target_obj, const AVOption *o, con o_named->unit && !strcmp(o_named->unit, o->unit)) { if (ci + 6 >= FF_ARRAY_ELEMS(const_values)) { - av_log(obj, AV_LOG_ERROR, "const_values array too small for %s\n", o->unit); + av_log(logctx, AV_LOG_ERROR, "const_values array too small for %s\n", o->unit); return AVERROR_PATCHWELCOME; } const_names [ci ] = o_named->name; @@ -479,12 +495,12 @@ static int set_string_number(void *obj, void *target_obj, const AVOption *o, con res = av_expr_parse_and_eval(&d, i ? buf : val, const_names, const_values, NULL, NULL, NULL, NULL, NULL, 0, obj); if (res < 0) { - av_log(obj, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\"\n", o->name, val); + av_log(logctx, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\"\n", o->name, val); return res; } } } - if (type == AV_OPT_TYPE_FLAGS) { + if (type == AV_OPT_TYPE_FLAGS && dst) { intnum = *(unsigned int*)dst; if (cmd == '+') d = intnum | (int64_t)d; @@ -502,37 +518,51 @@ static int set_string_number(void *obj, void *target_obj, const AVOption *o, con static int set_string_image_size(void *obj, const AVOption *o, const char *val, int *dst) { + void *logctx = dst ? obj : NULL; + int tmp[2]; int ret; if (!val || !strcmp(val, "none")) { + if (dst) { dst[0] = dst[1] = 0; + } return 0; } - ret = av_parse_video_size(dst, dst + 1, val); + ret = av_parse_video_size(&tmp[0], &tmp[1], val); if (ret < 0) - av_log(obj, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as image size\n", o->name, val); + av_log(logctx, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as image size\n", o->name, val); + if (dst) + memcpy(dst, tmp, sizeof(tmp)); return ret; } static int set_string_video_rate(void *obj, const AVOption *o, const char *val, AVRational *dst) { - int ret = av_parse_video_rate(dst, val); + void *logctx = dst ? obj : NULL; + AVRational tmp; + int ret = av_parse_video_rate(&tmp, val); if (ret < 0) - av_log(obj, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as video rate\n", o->name, val); + av_log(logctx, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as video rate\n", o->name, val); + if (dst) + *dst = tmp; return ret; } static int set_string_color(void *obj, const AVOption *o, const char *val, uint8_t *dst) { + void *logctx = dst ? obj : NULL; int ret; if (!val) { return 0; } else { - ret = av_parse_color(dst, val, -1, obj); + uint8_t tmp[4]; + ret = av_parse_color(tmp, val, -1, obj); if (ret < 0) - av_log(obj, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as color\n", o->name, val); + av_log(logctx, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as color\n", o->name, val); + if (dst) + memcpy(dst, tmp, sizeof(tmp)); return ret; } return 0; @@ -547,6 +577,7 @@ static const char *get_bool_name(int val) static int set_string_bool(void *obj, const AVOption *o, const char *val, int *dst) { + void *logctx = dst ? obj : NULL; int n; if (!val) @@ -568,11 +599,12 @@ static int set_string_bool(void *obj, const AVOption *o, const char *val, int *d if (n < o->min || n > o->max) goto fail; + if (dst) *dst = n; return 0; fail: - av_log(obj, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as boolean\n", o->name, val); + av_log(logctx, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as boolean\n", o->name, val); return AVERROR(EINVAL); } @@ -580,6 +612,7 @@ static int set_string_fmt(void *obj, const AVOption *o, const char *val, uint8_t int fmt_nb, int ((*get_fmt)(const char *)), const char *desc, enum AVOptionType type) { + void *logctx = dst ? obj : NULL; int fmt, min, max; if (!val || !strcmp(val, "none")) { @@ -590,7 +623,7 @@ static int set_string_fmt(void *obj, const AVOption *o, const char *val, uint8_t char *tail; fmt = strtol(val, &tail, 0); if (*tail || (unsigned)fmt >= fmt_nb) { - av_log(obj, AV_LOG_ERROR, + av_log(logctx, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as %s\n", o->name, val, desc); return AVERROR(EINVAL); } @@ -607,12 +640,13 @@ static int set_string_fmt(void *obj, const AVOption *o, const char *val, uint8_t } if (fmt < min || fmt > max) { - av_log(obj, AV_LOG_ERROR, + av_log(logctx, AV_LOG_ERROR, "Value %d for parameter '%s' out of %s format range [%d - %d]\n", fmt, o->name, desc, min, max); return AVERROR(ERANGE); } + if (dst) switch (type) { case AV_OPT_TYPE_PIXEL_FMT: *(enum AVPixelFormat *)dst = fmt; break; case AV_OPT_TYPE_SAMPLE_FMT: *(enum AVSampleFormat*)dst = fmt; break; @@ -657,6 +691,11 @@ static int set_string_dict(void *obj, const AVOption *o, const char *val, uint8_ } } + if (!dst) { + av_dict_free(&options); + return 0; + } + av_dict_free((AVDictionary **)dst); *dst = (uint8_t *)options; @@ -666,16 +705,27 @@ static int set_string_dict(void *obj, const AVOption *o, const char *val, uint8_ static int set_string_channel_layout(void *obj, const AVOption *o, const char *val, void *dst) { + AVChannelLayout tmp; AVChannelLayout *channel_layout = dst; + int ret; + if (dst) av_channel_layout_uninit(channel_layout); + else + channel_layout = &tmp; if (!val) return 0; - return av_channel_layout_from_string(channel_layout, val); + ret = av_channel_layout_from_string(channel_layout, val); + if (ret < 0) + return ret; + if (!dst) + av_channel_layout_uninit(channel_layout); + return 0; } static int opt_set_elem(void *obj, void *target_obj, const AVOption *o, const char *val, void *dst) { + void *logctx = dst ? obj : NULL; const enum AVOptionType type = TYPE_BASE(o->type); int ret; @@ -720,15 +770,16 @@ static int opt_set_elem(void *obj, void *target_obj, const AVOption *o, int64_t usecs = 0; if (val) { if ((ret = av_parse_time(&usecs, val, 1)) < 0) { - av_log(obj, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as duration\n", o->name, val); + av_log(logctx, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as duration\n", o->name, val); return ret; } } if (usecs < o->min || usecs > o->max) { - av_log(obj, AV_LOG_ERROR, "Value %f for parameter '%s' out of range [%g - %g]\n", + av_log(logctx, AV_LOG_ERROR, "Value %f for parameter '%s' out of range [%g - %g]\n", usecs / 1000000.0, o->name, o->min / 1000000.0, o->max / 1000000.0); return AVERROR(ERANGE); } + if (dst) *(int64_t *)dst = usecs; return 0; } @@ -737,7 +788,7 @@ static int opt_set_elem(void *obj, void *target_obj, const AVOption *o, case AV_OPT_TYPE_CHLAYOUT: ret = set_string_channel_layout(obj, o, val, dst); if (ret < 0) { - av_log(obj, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as channel layout\n", o->name, val); + av_log(logctx, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as channel layout\n", o->name, val); ret = AVERROR(EINVAL); } return ret; @@ -745,7 +796,7 @@ static int opt_set_elem(void *obj, void *target_obj, const AVOption *o, return set_string_dict(obj, o, val, dst); } - av_log(obj, AV_LOG_ERROR, "Invalid option type.\n"); + av_log(logctx, AV_LOG_ERROR, "Invalid option type.\n"); return AVERROR(EINVAL); } @@ -757,6 +808,7 @@ static int opt_set_array(void *obj, void *target_obj, const AVOption *o, const uint8_t sep = opt_array_sep(o); uint8_t *str = NULL; + void *logctx = dst ? obj : NULL; void *elems = NULL; unsigned nb_elems = 0; int ret; @@ -773,7 +825,7 @@ static int opt_set_array(void *obj, void *target_obj, const AVOption *o, void *tmp; if (arr && arr->size_max && nb_elems >= arr->size_max) { - av_log(obj, AV_LOG_ERROR, + av_log(logctx, AV_LOG_ERROR, "Cannot assign more than %u elements to array option %s\n", arr->size_max, o->name); ret = AVERROR(EINVAL); @@ -808,18 +860,22 @@ static int opt_set_array(void *obj, void *target_obj, const AVOption *o, } av_freep(&str); + if (dst) opt_free_array(o, dst, opt_array_pcount(dst)); if (arr && nb_elems < arr->size_min) { - av_log(obj, AV_LOG_ERROR, + av_log(logctx, AV_LOG_ERROR, "Cannot assign fewer than %u elements to array option %s\n", arr->size_min, o->name); ret = AVERROR(EINVAL); goto fail; } + if (dst) { *((void **)dst) = elems; *opt_array_pcount(dst) = nb_elems; + } else + opt_free_array(o, &elems, &nb_elems); return 0; fail: @@ -869,8 +925,10 @@ static int set_number(void *obj, const char *name, double num, int den, int64_t ret = opt_set_init(obj, name, search_flags, require_type, NULL, &o, &dst); if (ret < 0) return ret; + if (dst) + ret = write_number(obj, o, dst, num, den, intnum); - return write_number(obj, o, dst, num, den, intnum); + return ret; } int av_opt_set_int(void *obj, const char *name, int64_t val, int search_flags) @@ -900,6 +958,7 @@ int av_opt_set_bin(void *obj, const char *name, const uint8_t *val, int len, int if (ret < 0) return ret; + if (dst) { ptr = len ? av_malloc(len) : NULL; if (len && !ptr) return AVERROR(ENOMEM); @@ -911,6 +970,7 @@ int av_opt_set_bin(void *obj, const char *name, const uint8_t *val, int len, int *lendst = len; if (len) memcpy(ptr, val, len); + } return 0; } @@ -918,6 +978,7 @@ int av_opt_set_bin(void *obj, const char *name, const uint8_t *val, int len, int int av_opt_set_image_size(void *obj, const char *name, int w, int h, int search_flags) { const AVOption *o; + void *logctx; int *dst; int ret; @@ -926,14 +987,18 @@ int av_opt_set_image_size(void *obj, const char *name, int w, int h, int search_ if (ret < 0) return ret; + logctx = dst ? obj : NULL; + if (w<0 || h<0) { - av_log(obj, AV_LOG_ERROR, + av_log(logctx, AV_LOG_ERROR, "Invalid negative size value %dx%d for size '%s'\n", w, h, o->name); return AVERROR(EINVAL); } + if (dst) { dst[0] = w; dst[1] = h; + } return 0; } @@ -947,6 +1012,7 @@ static int set_format(void *obj, const char *name, int fmt, int search_flags, enum AVOptionType type, const char *desc, int nb_fmts) { const AVOption *o; + void *logctx; int *dst; int min, max, ret; @@ -954,15 +1020,18 @@ static int set_format(void *obj, const char *name, int fmt, int search_flags, if (ret < 0) return ret; + logctx = dst ? obj : NULL; + min = FFMAX(o->min, -1); max = FFMIN(o->max, nb_fmts-1); if (fmt < min || fmt > max) { - av_log(obj, AV_LOG_ERROR, + av_log(logctx, AV_LOG_ERROR, "Value %d for parameter '%s' out of %s format range [%d - %d]\n", fmt, name, desc, min, max); return AVERROR(ERANGE); } + if (dst) *dst = fmt; return 0; } @@ -988,9 +1057,13 @@ int av_opt_set_dict_val(void *obj, const char *name, const AVDictionary *val, if (ret < 0) return ret; + if (dst) { av_dict_free(dst); - return av_dict_copy(dst, val, 0); + ret = av_dict_copy(dst, val, 0); + } + + return ret; } int av_opt_set_chlayout(void *obj, const char *name, @@ -1005,7 +1078,10 @@ int av_opt_set_chlayout(void *obj, const char *name, if (ret < 0) return ret; - return av_channel_layout_copy(dst, channel_layout); + if (dst) + ret = av_channel_layout_copy(dst, channel_layout); + + return ret; } static void format_duration(char *buf, size_t size, int64_t d) diff --git a/libavutil/opt.h b/libavutil/opt.h index 2a50f52fc3..7ab2b7ad7d 100644 --- a/libavutil/opt.h +++ b/libavutil/opt.h @@ -604,10 +604,10 @@ const AVClass *av_opt_child_class_iterate(const AVClass *parent, void **iter); #define AV_OPT_SEARCH_CHILDREN (1 << 0) /**< Search in possible children of the given object first. */ /** - * The obj passed to av_opt_find() is fake -- only a double pointer to AVClass - * instead of a required pointer to a struct containing AVClass. This is - * useful for searching for options without needing to allocate the corresponding - * object. + * The obj passed to av_opt_find() or av_opt_set() is fake -- only a double pointer + * to AVClass instead of a required pointer to a struct containing AVClass. This is + * useful for searching for options or verifying they can be applied without needing + * to allocate the corresponding object. */ #define AV_OPT_SEARCH_FAKE_OBJ (1 << 1) @@ -841,7 +841,8 @@ int av_opt_copy(void *dest, const void *src); * @{ * Those functions set the field of obj with the given name to value. * - * @param[in] obj A struct whose first element is a pointer to an AVClass. + * @param[in] obj A struct whose first element is a pointer to an AVClass. Alternatively + * a double pointer to an AVClass, if AV_OPT_SEARCH_FAKE_OBJ search flag is set. * @param[in] name the name of the field to set * @param[in] val The value to set. In case of av_opt_set() if the field is not * of a string type, then the given string is parsed. _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
