[FFmpeg-devel] [PATCH] avutil/opt: add a flag to get the default value of an option in av_opt_get

James Almer jamrial at gmail.com
Wed Mar 6 16:47:33 EET 2024


Signed-off-by: James Almer <jamrial at gmail.com>
---
 libavutil/opt.c       | 150 ++++++++++++++++++++++++++++++++++++++++++
 libavutil/opt.h       |   8 +++
 libavutil/tests/opt.c |   7 +-
 tests/ref/fate/opt    |  48 +++++++-------
 4 files changed, 188 insertions(+), 25 deletions(-)

diff --git a/libavutil/opt.c b/libavutil/opt.c
index d68184c2cc..226df1da7a 100644
--- a/libavutil/opt.c
+++ b/libavutil/opt.c
@@ -844,6 +844,153 @@ static void format_duration(char *buf, size_t size, int64_t d)
         *(--e) = 0;
 }
 
+static int get_default(const AVOption *o, int flags, uint8_t **out_val)
+{
+    uint8_t buf[128];
+    int ret = 0;
+
+    av_assert0(o);
+
+    buf[0] = 0;
+    switch (o->type) {
+    case AV_OPT_TYPE_BOOL:
+        ret = snprintf(buf, sizeof(buf), "%s", get_bool_name(o->default_val.i64));
+        break;
+    case AV_OPT_TYPE_FLAGS:
+        ret = snprintf(buf, sizeof(buf), "0x%08X", (unsigned)o->default_val.i64);
+        break;
+    case AV_OPT_TYPE_INT:
+    case AV_OPT_TYPE_INT64:
+    case AV_OPT_TYPE_CONST:
+        ret = snprintf(buf, sizeof(buf), "%"PRId64, o->default_val.i64);
+        break;
+    case AV_OPT_TYPE_UINT64:
+        ret = snprintf(buf, sizeof(buf), "%"PRIu64, (uint64_t)o->default_val.i64);
+        break;
+    case AV_OPT_TYPE_FLOAT:
+        ret = snprintf(buf, sizeof(buf), "%f", (float)o->default_val.dbl);
+        break;
+    case AV_OPT_TYPE_DOUBLE:
+        ret = snprintf(buf, sizeof(buf), "%f", o->default_val.dbl);
+        break;
+    case AV_OPT_TYPE_RATIONAL: {
+        AVRational q = av_d2q(o->default_val.dbl, INT_MAX);
+        ret = snprintf(buf, sizeof(buf), "%d/%d", q.num, q.den);
+        break;
+    }
+    case AV_OPT_TYPE_VIDEO_RATE: {
+        AVRational q = (AVRational){0, 0};
+        if (o->default_val.str) {
+            if ((ret = av_parse_video_rate(&q, o->default_val.str)) < 0)
+                return ret;
+            ret = snprintf(buf, sizeof(buf), "%d/%d", q.num, q.den);
+        } else {
+            *out_val = av_strdup("");
+            return *out_val ? 0 : AVERROR(ENOMEM);
+        }
+        break;
+    }
+    case AV_OPT_TYPE_STRING:
+    case AV_OPT_TYPE_CHLAYOUT:
+        if (o->default_val.str)
+            *out_val = av_strdup(o->default_val.str);
+        else if (flags & AV_OPT_ALLOW_NULL) {
+            *out_val = NULL;
+             return 0;
+        } else
+            *out_val = av_strdup("");
+        return *out_val ? 0 : AVERROR(ENOMEM);
+    case AV_OPT_TYPE_DICT: {
+        AVDictionary *dict = NULL;
+        if (!o->default_val.str && (flags & AV_OPT_ALLOW_NULL)) {
+            *out_val = NULL;
+            return 0;
+        }
+        ret = set_string_dict(NULL, NULL, o->default_val.str, (uint8_t **)&dict);
+        if (ret < 0)
+            return ret;
+        ret = av_dict_get_string(dict, (char **)out_val, '=', ':');
+        av_dict_free(&dict);
+        return ret;
+    }
+    case AV_OPT_TYPE_BINARY: {
+        struct {
+            uint8_t *data;
+            int size;
+        } bin = { 0 };
+        if (!o->default_val.str && (flags & AV_OPT_ALLOW_NULL)) {
+            av_free(bin.data);
+            *out_val = NULL;
+            return 0;
+        }
+        ret = set_string_binary(NULL, NULL, o->default_val.str, &bin.data);
+        if (ret < 0) {
+            av_free(bin.data);
+            return AVERROR(ENOMEM);
+        }
+        if ((uint64_t)bin.size * 2 + 1 > INT_MAX) {
+            av_free(bin.data);
+            return AVERROR(EINVAL);
+        }
+        if (!(*out_val = av_malloc(bin.size * 2 + 1))) {
+            av_free(bin.data);
+            return AVERROR(ENOMEM);
+        }
+        if (!bin.size) {
+            *out_val[0] = '\0';
+            av_free(bin.data);
+            return 0;
+        }
+        for (int i = 0; i < bin.size; i++)
+            snprintf(*out_val + i * 2, 3, "%02X", bin.data[i]);
+        return 0;
+    }
+    case AV_OPT_TYPE_IMAGE_SIZE: {
+        int w = 0, h = 0;
+        if (o->default_val.str && strcmp(o->default_val.str, "none"))
+            ret = av_parse_video_size(&w, &h, o->default_val.str);
+        if (ret < 0)
+            return ret;
+        ret = snprintf(buf, sizeof(buf), "%dx%d", w, h);
+        break;
+    }
+    case AV_OPT_TYPE_PIXEL_FMT:
+        ret = snprintf(buf, sizeof(buf), "%s", (char *)av_x_if_null(av_get_pix_fmt_name((enum AVPixelFormat)o->default_val.i64), "none"));
+        break;
+    case AV_OPT_TYPE_SAMPLE_FMT:
+        ret = snprintf(buf, sizeof(buf), "%s", (char *)av_x_if_null(av_get_sample_fmt_name((enum AVSampleFormat)o->default_val.i64), "none"));
+        break;
+    case AV_OPT_TYPE_DURATION:
+        format_duration(buf, sizeof(buf), o->default_val.i64);
+        ret = strlen(buf); // no overflow possible, checked by an assert
+        break;
+    case AV_OPT_TYPE_COLOR: {
+        uint8_t color[4] = {0, 0, 0, 0};
+        if (o->default_val.str) {
+            if ((ret = av_parse_color(color, o->default_val.str, -1, NULL)) < 0)
+                return ret;
+        }
+        ret = snprintf(buf, sizeof(buf), "0x%02x%02x%02x%02x",
+                       color[0], color[1], color[2], color[3]);
+        break;
+    }
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
+    case AV_OPT_TYPE_CHANNEL_LAYOUT:
+        ret = snprintf(buf, sizeof(buf), "0x%"PRIx64, o->default_val.i64);
+        break;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+    default:
+        return AVERROR(EINVAL);
+    }
+
+    if (ret >= sizeof(buf))
+        return AVERROR(EINVAL);
+    *out_val = av_strdup(buf);
+    return *out_val ? 0 : AVERROR(ENOMEM);
+}
+
 int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
 {
     void *dst, *target_obj;
@@ -858,6 +1005,9 @@ int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
     if (o->flags & AV_OPT_FLAG_DEPRECATED)
         av_log(obj, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", name, o->help);
 
+    if (search_flags & AV_OPT_GET_DEFAULT)
+        return get_default(o, search_flags, out_val);
+
     dst = (uint8_t *)target_obj + o->offset;
 
     buf[0] = 0;
diff --git a/libavutil/opt.h b/libavutil/opt.h
index e34b8506f8..b4e94e3f4e 100644
--- a/libavutil/opt.h
+++ b/libavutil/opt.h
@@ -472,6 +472,12 @@ const AVClass *av_opt_child_class_iterate(const AVClass *parent, void **iter);
  */
 #define AV_OPT_ALLOW_NULL (1 << 2)
 
+/**
+ *  In av_opt_get, return the default value of the option rather than returning the
+ *  value set in the object.
+ */
+#define AV_OPT_GET_DEFAULT (1 << 3)
+
 /**
  *  Allows av_opt_query_ranges and av_opt_query_ranges_default to return more than
  *  one component for certain option types.
@@ -763,6 +769,8 @@ int av_opt_set_dict_val(void *obj, const char *name, const AVDictionary *val, in
 /**
  * @defgroup opt_get_funcs Option getting functions
  * @{
+ */
+/**
  * Those functions get a value of the option with the given name from an object.
  *
  * @param[in] obj a struct whose first element is a pointer to an AVClass.
diff --git a/libavutil/tests/opt.c b/libavutil/tests/opt.c
index e2582cc93d..c909cfb43a 100644
--- a/libavutil/tests/opt.c
+++ b/libavutil/tests/opt.c
@@ -187,9 +187,11 @@ int main(void)
         while (o = av_opt_next(&test_ctx, o)) {
             char *value1 = NULL;
             char *value2 = NULL;
+            char *value3 = NULL;
             int ret1 = AVERROR_BUG;
             int ret2 = AVERROR_BUG;
             int ret3 = AVERROR_BUG;
+            int ret4 = AVERROR_BUG;
 
             if (o->type == AV_OPT_TYPE_CONST)
                 continue;
@@ -200,14 +202,17 @@ int main(void)
                 if (ret2 >= 0)
                     ret3 = av_opt_get(&test2_ctx, o->name, 0, (uint8_t **)&value2);
             }
+            ret4 = av_opt_get(&test_ctx, o->name, AV_OPT_GET_DEFAULT, (uint8_t **)&value3);
 
-            printf("name: %-11s get: %-16s set: %-16s get: %-16s %s\n", o->name,
+            printf("name: %-11s default: %-16s get: %-16s set: %-16s get: %-16s %s\n", o->name,
+                    ret4 >= 0 ? value3 : av_err2str(ret4),
                     ret1 >= 0 ? value1 : av_err2str(ret1),
                     ret2 >= 0 ? "OK" : av_err2str(ret2),
                     ret3 >= 0 ? value2 : av_err2str(ret3),
                     ret1 >= 0 && ret2 >= 0 && ret3 >= 0 && !strcmp(value1, value2) ? "OK" : "Mismatch");
             av_free(value1);
             av_free(value2);
+            av_free(value3);
         }
         av_opt_free(&test_ctx);
         av_opt_free(&test2_ctx);
diff --git a/tests/ref/fate/opt b/tests/ref/fate/opt
index 832f9cc8a9..5420494735 100644
--- a/tests/ref/fate/opt
+++ b/tests/ref/fate/opt
@@ -103,30 +103,30 @@ name:     dict1 default:1 error:
 name:     dict2 default:1 error:
 
 Testing av_opt_get/av_opt_set()
-name: num         get: 0                set: OK               get: 0                OK
-name: toggle      get: 1                set: OK               get: 1                OK
-name: rational    get: 1/1              set: OK               get: 1/1              OK
-name: string      get: default          set: OK               get: default          OK
-name: escape      get: \=,              set: OK               get: \=,              OK
-name: flags       get: 0x00000001       set: OK               get: 0x00000001       OK
-name: size        get: 200x300          set: OK               get: 200x300          OK
-name: pix_fmt     get: 0bgr             set: OK               get: 0bgr             OK
-name: sample_fmt  get: s16              set: OK               get: s16              OK
-name: video_rate  get: 25/1             set: OK               get: 25/1             OK
-name: duration    get: 0.001            set: OK               get: 0.001            OK
-name: color       get: 0xffc0cbff       set: OK               get: 0xffc0cbff       OK
-name: cl          get: hexagonal        set: OK               get: hexagonal        OK
-name: bin         get: 62696E00         set: OK               get: 62696E00         OK
-name: bin1        get:                  set: OK               get:                  OK
-name: bin2        get:                  set: OK               get:                  OK
-name: num64       get: 1                set: OK               get: 1                OK
-name: flt         get: 0.333333         set: OK               get: 0.333333         OK
-name: dbl         get: 0.333333         set: OK               get: 0.333333         OK
-name: bool1       get: auto             set: OK               get: auto             OK
-name: bool2       get: true             set: OK               get: true             OK
-name: bool3       get: false            set: OK               get: false            OK
-name: dict1       get:                  set: OK               get:                  OK
-name: dict2       get: happy=\:-)       set: OK               get: happy=\:-)       OK
+name: num         default: 0                get: 0                set: OK               get: 0                OK
+name: toggle      default: 1                get: 1                set: OK               get: 1                OK
+name: rational    default: 1/1              get: 1/1              set: OK               get: 1/1              OK
+name: string      default: default          get: default          set: OK               get: default          OK
+name: escape      default: \=,              get: \=,              set: OK               get: \=,              OK
+name: flags       default: 0x00000001       get: 0x00000001       set: OK               get: 0x00000001       OK
+name: size        default: 200x300          get: 200x300          set: OK               get: 200x300          OK
+name: pix_fmt     default: 0bgr             get: 0bgr             set: OK               get: 0bgr             OK
+name: sample_fmt  default: s16              get: s16              set: OK               get: s16              OK
+name: video_rate  default: 25/1             get: 25/1             set: OK               get: 25/1             OK
+name: duration    default: 0.001            get: 0.001            set: OK               get: 0.001            OK
+name: color       default: 0xffc0cbff       get: 0xffc0cbff       set: OK               get: 0xffc0cbff       OK
+name: cl          default: hexagonal        get: hexagonal        set: OK               get: hexagonal        OK
+name: bin         default: 62696E00         get: 62696E00         set: OK               get: 62696E00         OK
+name: bin1        default:                  get:                  set: OK               get:                  OK
+name: bin2        default:                  get:                  set: OK               get:                  OK
+name: num64       default: 1                get: 1                set: OK               get: 1                OK
+name: flt         default: 0.333333         get: 0.333333         set: OK               get: 0.333333         OK
+name: dbl         default: 0.333333         get: 0.333333         set: OK               get: 0.333333         OK
+name: bool1       default: auto             get: auto             set: OK               get: auto             OK
+name: bool2       default: true             get: true             set: OK               get: true             OK
+name: bool3       default: false            get: false            set: OK               get: false            OK
+name: dict1       default:                  get:                  set: OK               get:                  OK
+name: dict2       default: happy=\:-)       get: happy=\:-)       set: OK               get: happy=\:-)       OK
 
 Test av_opt_serialize()
 num=0,toggle=1,rational=1/1,string=default,escape=\\\=\,,flags=0x00000001,size=200x300,pix_fmt=0bgr,sample_fmt=s16,video_rate=25/1,duration=0.001,color=0xffc0cbff,cl=hexagonal,bin=62696E00,bin1=,bin2=,num64=1,flt=0.333333,dbl=0.333333,bool1=auto,bool2=true,bool3=false,dict1=,dict2=happy\=\\:-)
-- 
2.44.0



More information about the ffmpeg-devel mailing list