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]

Reply via email to