aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Almer <jamrial@gmail.com>2024-04-12 19:10:25 -0300
committerJames Almer <jamrial@gmail.com>2024-04-23 23:54:46 -0300
commit8616cfe0890e49437d2b373f97a9c791eb1b7c4c (patch)
tree1ae274c18177a035880b37baaf8c26ed20100298
parent855d4b52547b2f8fc38b400e5d18cf44e621e163 (diff)
downloadffmpeg-8616cfe0890e49437d2b373f97a9c791eb1b7c4c.tar.gz
avutil/opt: add support for children objects in av_opt_serialize
Signed-off-by: James Almer <jamrial@gmail.com>
-rw-r--r--doc/APIchanges3
-rw-r--r--libavutil/opt.c65
-rw-r--r--libavutil/opt.h1
-rw-r--r--libavutil/tests/opt.c49
-rw-r--r--libavutil/version.h2
-rw-r--r--tests/ref/fate/opt2
6 files changed, 96 insertions, 26 deletions
diff --git a/doc/APIchanges b/doc/APIchanges
index 63e7a47126..05912d2ed0 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -2,6 +2,9 @@ The last version increases of all libraries were on 2024-03-07
API changes, most recent first:
+2024-04-11 - xxxxxxxxxx - lavu 59.16.100 - opt.h
+ Add AV_OPT_SERIALIZE_SEARCH_CHILDREN.
+
2024-04-11 - xxxxxxxxxx - lavc 61.5.102 - avcodec.h
AVCodecContext.decoded_side_data may now be set by libavcodec after
calling avcodec_open2().
diff --git a/libavutil/opt.c b/libavutil/opt.c
index d11e9d2ac5..ecbf7efe5f 100644
--- a/libavutil/opt.c
+++ b/libavutil/opt.c
@@ -2386,26 +2386,22 @@ int av_opt_is_set_to_default_by_name(void *obj, const char *name, int search_fla
return av_opt_is_set_to_default(target, o);
}
-int av_opt_serialize(void *obj, int opt_flags, int flags, char **buffer,
- const char key_val_sep, const char pairs_sep)
+static int opt_serialize(void *obj, int opt_flags, int flags, int *cnt,
+ AVBPrint *bprint, const char key_val_sep, const char pairs_sep)
{
const AVOption *o = NULL;
+ void *child = NULL;
uint8_t *buf;
- AVBPrint bprint;
- int ret, cnt = 0;
+ int ret;
const char special_chars[] = {pairs_sep, key_val_sep, '\0'};
- if (pairs_sep == '\0' || key_val_sep == '\0' || pairs_sep == key_val_sep ||
- pairs_sep == '\\' || key_val_sep == '\\') {
- av_log(obj, AV_LOG_ERROR, "Invalid separator(s) found.");
- return AVERROR(EINVAL);
- }
-
- if (!obj || !buffer)
- return AVERROR(EINVAL);
-
- *buffer = NULL;
- av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED);
+ if (flags & AV_OPT_SERIALIZE_SEARCH_CHILDREN)
+ while (child = av_opt_child_next(obj, child)) {
+ ret = opt_serialize(child, opt_flags, flags, cnt, bprint,
+ key_val_sep, pairs_sep);
+ if (ret < 0)
+ return ret;
+ }
while (o = av_opt_next(obj, o)) {
if (o->type == AV_OPT_TYPE_CONST)
@@ -2417,18 +2413,45 @@ int av_opt_serialize(void *obj, int opt_flags, int flags, char **buffer,
if (flags & AV_OPT_SERIALIZE_SKIP_DEFAULTS && av_opt_is_set_to_default(obj, o) > 0)
continue;
if ((ret = av_opt_get(obj, o->name, 0, &buf)) < 0) {
- av_bprint_finalize(&bprint, NULL);
+ av_bprint_finalize(bprint, NULL);
return ret;
}
if (buf) {
- if (cnt++)
- av_bprint_append_data(&bprint, &pairs_sep, 1);
- av_bprint_escape(&bprint, o->name, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0);
- av_bprint_append_data(&bprint, &key_val_sep, 1);
- av_bprint_escape(&bprint, buf, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0);
+ if ((*cnt)++)
+ av_bprint_append_data(bprint, &pairs_sep, 1);
+ av_bprint_escape(bprint, o->name, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0);
+ av_bprint_append_data(bprint, &key_val_sep, 1);
+ av_bprint_escape(bprint, buf, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0);
av_freep(&buf);
}
}
+
+ return 0;
+}
+
+int av_opt_serialize(void *obj, int opt_flags, int flags, char **buffer,
+ const char key_val_sep, const char pairs_sep)
+{
+ AVBPrint bprint;
+ int ret, cnt = 0;
+
+ if (pairs_sep == '\0' || key_val_sep == '\0' || pairs_sep == key_val_sep ||
+ pairs_sep == '\\' || key_val_sep == '\\') {
+ av_log(obj, AV_LOG_ERROR, "Invalid separator(s) found.");
+ return AVERROR(EINVAL);
+ }
+
+ if (!obj || !buffer)
+ return AVERROR(EINVAL);
+
+ *buffer = NULL;
+ av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED);
+
+ ret = opt_serialize(obj, opt_flags, flags, &cnt, &bprint,
+ key_val_sep, pairs_sep);
+ if (ret < 0)
+ return ret;
+
ret = av_bprint_finalize(&bprint, buffer);
if (ret < 0)
return ret;
diff --git a/libavutil/opt.h b/libavutil/opt.h
index e6013662f6..855e363091 100644
--- a/libavutil/opt.h
+++ b/libavutil/opt.h
@@ -929,6 +929,7 @@ int av_opt_flag_is_set(void *obj, const char *field_name, const char *flag_name)
#define AV_OPT_SERIALIZE_SKIP_DEFAULTS 0x00000001 ///< Serialize options that are not set to default values only.
#define AV_OPT_SERIALIZE_OPT_FLAGS_EXACT 0x00000002 ///< Serialize options that exactly match opt_flags only.
+#define AV_OPT_SERIALIZE_SEARCH_CHILDREN 0x00000004 ///< Serialize options in possible children of the given object.
/**
* Serialize object's options.
diff --git a/libavutil/tests/opt.c b/libavutil/tests/opt.c
index d43391025a..abe1b0dee4 100644
--- a/libavutil/tests/opt.c
+++ b/libavutil/tests/opt.c
@@ -30,6 +30,7 @@
typedef struct TestContext {
const AVClass *class;
+ struct ChildContext *child;
int num;
int toggle;
char *string;
@@ -123,10 +124,46 @@ static const char *test_get_name(void *ctx)
return "test";
}
+typedef struct ChildContext {
+ const AVClass *class;
+ int64_t child_num64;
+ int child_num;
+} ChildContext;
+
+#undef OFFSET
+#define OFFSET(x) offsetof(ChildContext, x)
+
+static const AVOption child_options[]= {
+ {"child_num64", "set num 64bit", OFFSET(child_num64), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, 100, 1 },
+ {"child_num", "set child_num", OFFSET(child_num), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 100, 1 },
+ { NULL },
+};
+
+static const char *child_get_name(void *ctx)
+{
+ return "child";
+}
+
+static const AVClass child_class = {
+ .class_name = "ChildContext",
+ .item_name = child_get_name,
+ .option = child_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+static void *test_child_next(void *obj, void *prev)
+{
+ TestContext *test_ctx = obj;
+ if (!prev)
+ return test_ctx->child;
+ return NULL;
+}
+
static const AVClass test_class = {
.class_name = "TestContext",
.item_name = test_get_name,
.option = test_options,
+ .child_next = test_child_next,
.version = LIBAVUTIL_VERSION_INT,
};
@@ -277,13 +314,19 @@ int main(void)
av_set_options_string(&test_ctx, buf, "=", ",");
av_free(buf);
if (av_opt_serialize(&test_ctx, 0, 0, &buf, '=', ',') >= 0) {
+ ChildContext child_ctx = { 0 };
printf("%s\n", buf);
av_free(buf);
- if (av_opt_serialize(&test_ctx, 0, AV_OPT_SERIALIZE_SKIP_DEFAULTS, &buf, '=', ',') >= 0) {
- if (strlen(buf))
- printf("%s\n", buf);
+ child_ctx.class = &child_class;
+ test_ctx.child = &child_ctx;
+ if (av_opt_serialize(&test_ctx, 0,
+ AV_OPT_SERIALIZE_SKIP_DEFAULTS|AV_OPT_SERIALIZE_SEARCH_CHILDREN,
+ &buf, '=', ',') >= 0) {
+ printf("%s\n", buf);
av_free(buf);
}
+ av_opt_free(&child_ctx);
+ test_ctx.child = NULL;
}
}
av_opt_free(&test_ctx);
diff --git a/libavutil/version.h b/libavutil/version.h
index 1f2bddc022..ea289c406f 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -79,7 +79,7 @@
*/
#define LIBAVUTIL_VERSION_MAJOR 59
-#define LIBAVUTIL_VERSION_MINOR 15
+#define LIBAVUTIL_VERSION_MINOR 16
#define LIBAVUTIL_VERSION_MICRO 100
#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
diff --git a/tests/ref/fate/opt b/tests/ref/fate/opt
index f780097622..0a3362e8fa 100644
--- a/tests/ref/fate/opt
+++ b/tests/ref/fate/opt
@@ -179,7 +179,7 @@ Setting entry with key 'array_int' to value ''
Setting entry with key 'array_str' to value 'str0|str\|1|str\\2'
Setting entry with key 'array_dict' to value 'k00=v\\\\00:k01=v\,01,k10=v\\=1\\:0'
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\=\\:-),array_int=,array_str=str0|str\\|1|str\\\\2,array_dict=k00\=v\\\\\\\\00:k01\=v\\\,01\,k10\=v\\\\\=1\\\\:0
-flt=0.333333,dbl=0.333333,array_int=
+child_num=0,flt=0.333333,dbl=0.333333,array_int=
Testing av_set_options_string()
Setting options string ''