From: James Almer <jamrial@gmail.com> To: ffmpeg-devel@ffmpeg.org Subject: [FFmpeg-devel] [PATCH] avutil/opt: add a flag to get the default value of an option in av_opt_get Date: Wed, 6 Mar 2024 11:47:33 -0300 Message-ID: <20240306144733.2229-1-jamrial@gmail.com> (raw) Signed-off-by: James Almer <jamrial@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 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
reply other threads:[~2024-03-06 14:47 UTC|newest] Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20240306144733.2229-1-jamrial@gmail.com \ --to=jamrial@gmail.com \ --cc=ffmpeg-devel@ffmpeg.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git