[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