PR #24301 opened by Niklas Haas (haasn)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24301
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24301.patch

Filters may want to deliberately set a default value that is outside the
range of permissible values. One use case for this is AV_OPT_TYPE_RATIONAL,
which does not currently permit a value of { .dbl = NAN } by default, even
though the semi-equivalent AV_OPT_TYPE_FLOAT/DOUBLE do.

This is a genuine inconsistency, and universally rejecting the range check
for default options is probably the right way to solve it.

Signed-off-by: Niklas Haas <[email protected]>

# Summary of changes

Briefly describe what this PR does and why.

<!--
If this PR requires new FATE test samples, attach them to the PR and
list their target paths below (relative to the fate-suite root).

Attached filenames must match the sample's filename:

```fate-samples
# e.g. vorbis/new-sample.ogg
```
-->



>From 0ade1d2e1d09dcd87bcf92f442c9a44c79c4ba02 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Fri, 28 Aug 2026 13:18:32 +0200
Subject: [PATCH] avutil/opt: ignore range check on default values

Filters may want to deliberately set a default value that is outside the
range of permissible values. One use case for this is AV_OPT_TYPE_RATIONAL,
which does not currently permit a value of { .dbl = NAN } by default, even
though the semi-equivalent AV_OPT_TYPE_FLOAT/DOUBLE do.

This is a genuine inconsistency, and universally rejecting the range check
for default options is probably the right way to solve it.

Signed-off-by: Niklas Haas <[email protected]>
---
 libavutil/opt.c | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/libavutil/opt.c b/libavutil/opt.c
index 6fa1ec9929..17bd453dad 100644
--- a/libavutil/opt.c
+++ b/libavutil/opt.c
@@ -272,19 +272,21 @@ static int read_number(const AVOption *o, const void 
*dst, double *num, int *den
     return AVERROR(EINVAL);
 }
 
-static int write_number(void *obj, const AVOption *o, void *dst, double num, 
int den, int64_t intnum)
+static int write_number(void *obj, const AVOption *o, void *dst,
+                        double num, int den, int64_t intnum,
+                        int ignore_range)
 {
     void *logctx = dst ? obj : NULL;
     const enum AVOptionType type = TYPE_BASE(o->type);
 
-    if (type != AV_OPT_TYPE_FLAGS &&
+    if (!ignore_range && type != AV_OPT_TYPE_FLAGS &&
         (!den || o->max * den < num * intnum || o->min * den > num * intnum)) {
         num = den ? num * intnum / den : (num && intnum ? INFINITY : NAN);
         av_log(obj, AV_LOG_ERROR, "Value %f for parameter '%s' out of range 
[%g - %g]\n",
                num, o->name, o->min, o->max);
         return AVERROR(ERANGE);
     }
-    if (type == AV_OPT_TYPE_FLAGS) {
+    if (!ignore_range && type == AV_OPT_TYPE_FLAGS) {
         double d = num*intnum/den;
         if (d < -1.5 || d > 0xFFFFFFFF+0.5 || (llrint(d*256) & 255)) {
             av_log(logctx, AV_LOG_ERROR,
@@ -433,7 +435,7 @@ static int set_string_number(void *obj, void *target_obj, 
const AVOption *o, con
         int num, den;
         char c;
         if (sscanf(val, "%d%*1[:/]%d%c", &num, &den, &c) == 2) {
-            if ((ret = write_number(obj, o, dst, 1, den, num)) >= 0)
+            if ((ret = write_number(obj, o, dst, 1, den, num, 0)) >= 0)
                 return ret;
             ret = 0;
         }
@@ -510,7 +512,7 @@ static int set_string_number(void *obj, void *target_obj, 
const AVOption *o, con
                 d = intnum &~(int64_t)d;
         }
 
-        if ((ret = write_number(obj, o, dst, d, 1, 1)) < 0)
+        if ((ret = write_number(obj, o, dst, d, 1, 1, 0)) < 0)
             return ret;
         val += i;
         if (!i || !*val)
@@ -761,7 +763,7 @@ static int opt_set_elem(void *obj, void *target_obj, const 
AVOption *o,
         ret = set_string_video_rate(obj, o, val, &tmp);
         if (ret < 0)
             return ret;
-        return write_number(obj, o, dst, 1, tmp.den, tmp.num);
+        return write_number(obj, o, dst, 1, tmp.den, tmp.num, 0);
     }
     case AV_OPT_TYPE_PIXEL_FMT:
         return set_string_pixel_fmt(obj, o, val, dst);
@@ -928,7 +930,7 @@ static int set_number(void *obj, const char *name, double 
num, int den, int64_t
     if (ret < 0)
         return ret;
     if (dst)
-        ret = write_number(obj, o, dst, num, den, intnum);
+        ret = write_number(obj, o, dst, num, den, intnum, 0);
 
     return ret;
 }
@@ -1798,19 +1800,19 @@ void av_opt_set_defaults2(void *s, int mask, int flags)
             case AV_OPT_TYPE_DURATION:
             case AV_OPT_TYPE_PIXEL_FMT:
             case AV_OPT_TYPE_SAMPLE_FMT:
-                write_number(s, opt, dst, 1, 1, opt->default_val.i64);
+                write_number(s, opt, dst, 1, 1, opt->default_val.i64, 1);
                 break;
             case AV_OPT_TYPE_DOUBLE:
             case AV_OPT_TYPE_FLOAT: {
                 double val;
                 val = opt->default_val.dbl;
-                write_number(s, opt, dst, val, 1, 1);
+                write_number(s, opt, dst, val, 1, 1, 1);
             }
             break;
             case AV_OPT_TYPE_RATIONAL: {
                 AVRational val;
                 val = av_d2q(opt->default_val.dbl, INT_MAX);
-                write_number(s, opt, dst, 1, val.den, val.num);
+                write_number(s, opt, dst, 1, val.den, val.num, 1);
             }
             break;
             case AV_OPT_TYPE_COLOR:
@@ -2482,7 +2484,7 @@ int av_opt_set_array(void *obj, const char *name, int 
search_flags,
             default: av_assert0(0);
             }
 
-            ret = write_number(obj, o, dst, num, den, intnum);
+            ret = write_number(obj, o, dst, num, den, intnum, 0);
             if (ret < 0)
                 goto fail;
         } else {
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to