avutil/opt: add support for children objects in av_opt_serialize
Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
		
							parent
							
								
									855d4b5254
								
							
						
					
					
						commit
						8616cfe089
					
				| @ -2,6 +2,9 @@ The last version increases of all libraries were on 2024-03-07 | |||||||
| 
 | 
 | ||||||
| API changes, most recent first: | 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 | 2024-04-11 - xxxxxxxxxx - lavc 61.5.102 - avcodec.h | ||||||
|   AVCodecContext.decoded_side_data may now be set by libavcodec after |   AVCodecContext.decoded_side_data may now be set by libavcodec after | ||||||
|   calling avcodec_open2(). |   calling avcodec_open2(). | ||||||
|  | |||||||
| @ -2386,14 +2386,54 @@ 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); |     return av_opt_is_set_to_default(target, o); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 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; | ||||||
|  |     int ret; | ||||||
|  |     const char special_chars[] = {pairs_sep, key_val_sep, '\0'}; | ||||||
|  | 
 | ||||||
|  |     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) | ||||||
|  |             continue; | ||||||
|  |         if ((flags & AV_OPT_SERIALIZE_OPT_FLAGS_EXACT) && o->flags != opt_flags) | ||||||
|  |             continue; | ||||||
|  |         else if (((o->flags & opt_flags) != opt_flags)) | ||||||
|  |             continue; | ||||||
|  |         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); | ||||||
|  |             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); | ||||||
|  |             av_freep(&buf); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int av_opt_serialize(void *obj, int opt_flags, int flags, char **buffer, | int av_opt_serialize(void *obj, int opt_flags, int flags, char **buffer, | ||||||
|                      const char key_val_sep, const char pairs_sep) |                      const char key_val_sep, const char pairs_sep) | ||||||
| { | { | ||||||
|     const AVOption *o = NULL; |  | ||||||
|     uint8_t *buf; |  | ||||||
|     AVBPrint bprint; |     AVBPrint bprint; | ||||||
|     int ret, cnt = 0; |     int ret, cnt = 0; | ||||||
|     const char special_chars[] = {pairs_sep, key_val_sep, '\0'}; |  | ||||||
| 
 | 
 | ||||||
|     if (pairs_sep == '\0' || key_val_sep == '\0' || pairs_sep == key_val_sep || |     if (pairs_sep == '\0' || key_val_sep == '\0' || pairs_sep == key_val_sep || | ||||||
|         pairs_sep == '\\' || key_val_sep == '\\') { |         pairs_sep == '\\' || key_val_sep == '\\') { | ||||||
| @ -2407,28 +2447,11 @@ int av_opt_serialize(void *obj, int opt_flags, int flags, char **buffer, | |||||||
|     *buffer = NULL; |     *buffer = NULL; | ||||||
|     av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED); |     av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED); | ||||||
| 
 | 
 | ||||||
|     while (o = av_opt_next(obj, o)) { |     ret = opt_serialize(obj, opt_flags, flags, &cnt, &bprint, | ||||||
|         if (o->type == AV_OPT_TYPE_CONST) |                         key_val_sep, pairs_sep); | ||||||
|             continue; |     if (ret < 0) | ||||||
|         if ((flags & AV_OPT_SERIALIZE_OPT_FLAGS_EXACT) && o->flags != opt_flags) |         return ret; | ||||||
|             continue; | 
 | ||||||
|         else if (((o->flags & opt_flags) != opt_flags)) |  | ||||||
|             continue; |  | ||||||
|         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); |  | ||||||
|             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); |  | ||||||
|             av_freep(&buf); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     ret = av_bprint_finalize(&bprint, buffer); |     ret = av_bprint_finalize(&bprint, buffer); | ||||||
|     if (ret < 0) |     if (ret < 0) | ||||||
|         return ret; |         return ret; | ||||||
|  | |||||||
| @ -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_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_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. |  * Serialize object's options. | ||||||
|  | |||||||
| @ -30,6 +30,7 @@ | |||||||
| 
 | 
 | ||||||
| typedef struct TestContext { | typedef struct TestContext { | ||||||
|     const AVClass *class; |     const AVClass *class; | ||||||
|  |     struct ChildContext *child; | ||||||
|     int num; |     int num; | ||||||
|     int toggle; |     int toggle; | ||||||
|     char *string; |     char *string; | ||||||
| @ -123,10 +124,46 @@ static const char *test_get_name(void *ctx) | |||||||
|     return "test"; |     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 = { | static const AVClass test_class = { | ||||||
|     .class_name = "TestContext", |     .class_name = "TestContext", | ||||||
|     .item_name  = test_get_name, |     .item_name  = test_get_name, | ||||||
|     .option     = test_options, |     .option     = test_options, | ||||||
|  |     .child_next = test_child_next, | ||||||
|     .version    = LIBAVUTIL_VERSION_INT, |     .version    = LIBAVUTIL_VERSION_INT, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -277,13 +314,19 @@ int main(void) | |||||||
|             av_set_options_string(&test_ctx, buf, "=", ","); |             av_set_options_string(&test_ctx, buf, "=", ","); | ||||||
|             av_free(buf); |             av_free(buf); | ||||||
|             if (av_opt_serialize(&test_ctx, 0, 0, &buf, '=', ',') >= 0) { |             if (av_opt_serialize(&test_ctx, 0, 0, &buf, '=', ',') >= 0) { | ||||||
|  |                 ChildContext child_ctx = { 0 }; | ||||||
|                 printf("%s\n", buf); |                 printf("%s\n", buf); | ||||||
|                 av_free(buf); |                 av_free(buf); | ||||||
|                 if (av_opt_serialize(&test_ctx, 0, AV_OPT_SERIALIZE_SKIP_DEFAULTS, &buf, '=', ',') >= 0) { |                 child_ctx.class = &child_class; | ||||||
|                     if (strlen(buf)) |                 test_ctx.child = &child_ctx; | ||||||
|                         printf("%s\n", buf); |                 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_free(buf); | ||||||
|                 } |                 } | ||||||
|  |                 av_opt_free(&child_ctx); | ||||||
|  |                 test_ctx.child = NULL; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         av_opt_free(&test_ctx); |         av_opt_free(&test_ctx); | ||||||
|  | |||||||
| @ -79,7 +79,7 @@ | |||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #define LIBAVUTIL_VERSION_MAJOR  59 | #define LIBAVUTIL_VERSION_MAJOR  59 | ||||||
| #define LIBAVUTIL_VERSION_MINOR  15 | #define LIBAVUTIL_VERSION_MINOR  16 | ||||||
| #define LIBAVUTIL_VERSION_MICRO 100 | #define LIBAVUTIL_VERSION_MICRO 100 | ||||||
| 
 | 
 | ||||||
| #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ | #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ | ||||||
|  | |||||||
| @ -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_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' | 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 | 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() | Testing av_set_options_string() | ||||||
| Setting options string '' | Setting options string '' | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user