From patchwork Wed Mar 6 14:47:33 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Almer X-Patchwork-Id: 46854 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:d90e:b0:19e:cdac:8cce with SMTP id jd14csp431851pzb; Wed, 6 Mar 2024 06:47:46 -0800 (PST) X-Forwarded-Encrypted: i=2; AJvYcCUmxQnxJXYcmC6vaSlYSDMDr8Ql+Yt3hKHE3OO7KMTBkOnzyeutxps66tuF2fVijeE5KOTgiTtM1izv6p1/hLXPYX6wHKbO86l5TQ== X-Google-Smtp-Source: AGHT+IGAtC5+ipzDVJXx5qqI/mv7Rl2wx4D52pBlrjIROcC4NKb2oCzDr3rFVM4oEeMO57hXNo6W X-Received: by 2002:a50:8dc5:0:b0:566:ef9:30ce with SMTP id s5-20020a508dc5000000b005660ef930cemr10908481edh.3.1709736466165; Wed, 06 Mar 2024 06:47:46 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1709736466; cv=none; d=google.com; s=arc-20160816; b=DTwnrgCJdMFEAVnSxXp3ibZxYpsfgE+R/o3CfqaVUXmAmtAbW6lyZl2iFyUq3Rr73O L/5jx1Y7M3v+iVVd1/20ZmNLFVVy9Sz4Z4zq3NYU1skc81NXzfEMYARxPcaBRLZEa+NI tyi980fmhjZDz2CXqRwchxC7KXv2evkUZF8wsZtNHsE8OWi+RJ7Phl9wMdIaeNzWdPdX QxKTNCR/LKqWRLKVvFgYE2npLSKoxJDUziDylZlKDMCZipkCV7wDN+3z6R/KVYFnAEX0 7Mqhs0uFM5oLso8eGdEJC0vLlb+EPgUI/ArcvesDGLOL0i2+izcP+uYnAP4TYEXSARy1 E2MQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:reply-to:list-subscribe :list-help:list-post:list-archive:list-unsubscribe:list-id :precedence:subject:mime-version:message-id:date:to:from :dkim-signature:delivered-to; bh=KMC/xeYzv26LCTYjUrCPdAeNd0zxdFDqAeB+DXi4Q6c=; fh=YOA8vD9MJZuwZ71F/05pj6KdCjf6jQRmzLS+CATXUQk=; b=bFyPnlLzan3I5AgS+x2BryevcTW+nQit6A4Palqr7zSRE/gPAfG5430MWGYcWoVp/L qN3vewiflWk/X5cUuVcbjxBKEK/sr7an1MZ9VS4dwAdzFYs//1Y/vvhY80Z77Oygx5Ap 8ndhHT/HCnGilEyHnrWjoCAY3xDx/rPKwBhjlSdKmsCrqVolEy72x67exvhsE5mrDBw5 oEe6zFTxxb2qgjFVFkB4kMjH1YzZlrB0l3ImemBA82Je6Qx28WBQt8CIU0ZF8wUhqN04 XSpWzJyahud9874iCf+O2bbvGTbSLd9PdBXzfiJUpJvtL/xGLzPendZePVnBiKVCIzQP y8ww==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20230601 header.b="F/yTX7bO"; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id m28-20020a50d7dc000000b005649f9ea4c2si6008429edj.507.2024.03.06.06.47.45; Wed, 06 Mar 2024 06:47:46 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20230601 header.b="F/yTX7bO"; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 6AC8168CBD2; Wed, 6 Mar 2024 16:47:42 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-pf1-f177.google.com (mail-pf1-f177.google.com [209.85.210.177]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 83CDA68C62C for ; Wed, 6 Mar 2024 16:47:36 +0200 (EET) Received: by mail-pf1-f177.google.com with SMTP id d2e1a72fcca58-6e56d594b31so1400412b3a.1 for ; Wed, 06 Mar 2024 06:47:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1709736454; x=1710341254; darn=ffmpeg.org; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:from:to:cc:subject:date:message-id:reply-to; bh=/81m76wDzQItv2YeB9icjHGSEHNxrdPvDnzrIMT/jGE=; b=F/yTX7bOq5uKDS+BnJb0zsDivD4La/7VqXy9manWZBXOd0CYQu1TystsOC7Nj3MOqt 6m2g7Kvdy5YxFkdirLj3udQrPhWwXaloGey7tpTcGiZFPtkXo+ewGS6LajqeRIKZy1fV oLXQCYxEwUFZ2OTTB3cdhOY/4bjOqB4QC7TaBN36zumxBIgiD316jfLQnRcorKHtCie8 U+urFKmyDGS1fzufMdFKuydKUn0BOwx35fiuuPaJPehFjSdhrdgDnXyzPAjyP+3PDgzk HgMdf910+rY6m+tK7cdHUL3uZCnWPrCvWC8jYAiVTOJwzr7x+6IJ64k7ItkycPoEZ46e ZBxQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1709736454; x=1710341254; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=/81m76wDzQItv2YeB9icjHGSEHNxrdPvDnzrIMT/jGE=; b=KA5HbOQSA5lhaBkVmSloPgtpKsfetUv9HCeyUhBbAsvWlI8wfmgjMl0l7Sc10uqFUC mHrZkvDUvysMVY9q5yZIuBmDWRSxYjBZkgIIhy8cXrUHJ3oM3eS7ZXNIC6iXKo85G67B 6aOMPwpUpEW8yMFLFZerx4MCtR8fuOM0eamBAdZUopq5of+CL/n/1OL0y6Fx6MJI4WJs gIxStO8IgyNAtYmtDDF4PovQtg8wBjNsMCxVyDcod1o2dDczlSstqTzNfH9wgIPjSJx9 Jajs4ujd94H3rgpi+bd347JxMNj88l9LAkxMGmaK2IojWusGPKHEEN2Wz2z/lPu3sU2N l59A== X-Gm-Message-State: AOJu0Yw+1qEeCIT9VxdG3WF7EX7tH/VqjYAzKpl/xadcY3Nr6cJ99XIw dnatxlocLZBpMzaZyO42o8/+k2v64GjC3t27NneKr8BdCoP+oIZJbqmWXt82 X-Received: by 2002:a05:6a00:3d13:b0:6e6:269d:1a38 with SMTP id lo19-20020a056a003d1300b006e6269d1a38mr9885718pfb.25.1709736451873; Wed, 06 Mar 2024 06:47:31 -0800 (PST) Received: from localhost.localdomain ([190.194.169.124]) by smtp.gmail.com with ESMTPSA id c9-20020aa78c09000000b006e56da42e24sm10856223pfd.158.2024.03.06.06.47.30 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 06 Mar 2024 06:47:31 -0800 (PST) From: James Almer To: ffmpeg-devel@ffmpeg.org Date: Wed, 6 Mar 2024 11:47:33 -0300 Message-ID: <20240306144733.2229-1-jamrial@gmail.com> X-Mailer: git-send-email 2.44.0 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH] avutil/opt: add a flag to get the default value of an option in av_opt_get X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: sQjU5W3Z4yu7 Signed-off-by: James Almer --- 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\=\\:-)