TODO: bump minor version, update doc/APIchanges Function allows to create string containing object's serialized options. Such string may be passed back to av_set_options_string() in order to restore options.
Signed-off-by: Lukasz Marek <lukasz.m.lu...@gmail.com> --- libavutil/opt.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++++ libavutil/opt.h | 17 +++++++ tests/ref/fate/opt | 8 ++++ 3 files changed, 160 insertions(+) diff --git a/libavutil/opt.c b/libavutil/opt.c index 85c9379..a490583 100644 --- a/libavutil/opt.c +++ b/libavutil/opt.c @@ -37,6 +37,7 @@ #include "pixdesc.h" #include "mathematics.h" #include "samplefmt.h" +#include "bprint.h" #include <float.h> @@ -69,6 +70,7 @@ static int read_number(const AVOption *o, void *dst, double *num, int *den, int6 case AV_OPT_TYPE_INT64: *intnum = *(int64_t *)dst;return 0; case AV_OPT_TYPE_FLOAT: *num = *(float *)dst;return 0; case AV_OPT_TYPE_DOUBLE: *num = *(double *)dst;return 0; + case AV_OPT_TYPE_VIDEO_RATE: case AV_OPT_TYPE_RATIONAL: *intnum = ((AVRational*)dst)->num; *den = ((AVRational*)dst)->den; return 0; @@ -1830,6 +1832,110 @@ 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); } +static int opt_serialize_option(void *obj, const AVOption *o, char *buffer, size_t size, + const char key_val_sep) +{ + void *dst; + int64_t i64; + double d; + int i, ret, ret2; + + dst = ((uint8_t*)obj) + o->offset; + ret = snprintf(buffer, size, "%s%c", o->name, key_val_sep); + if (ret >= size || ret < 0) + return AVERROR(ENOMEM); + switch (o->type) { + case AV_OPT_TYPE_FLAGS: + case AV_OPT_TYPE_PIXEL_FMT: + case AV_OPT_TYPE_SAMPLE_FMT: + case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_CHANNEL_LAYOUT: + case AV_OPT_TYPE_INT64: + read_number(o, dst, NULL, NULL, &i64); + ret2 = snprintf(buffer + ret, size - ret, "%"PRId64, i64); + break; + case AV_OPT_TYPE_DURATION: + read_number(o, dst, NULL, NULL, &i64); + ret2 = snprintf(buffer + ret, size - ret, "%f", i64 / 1000000.0); + break; + case AV_OPT_TYPE_STRING: + ret2 = snprintf(buffer + ret, size - ret, "%s", *(char **)dst); + break; + case AV_OPT_TYPE_DOUBLE: + case AV_OPT_TYPE_FLOAT: + read_number(o, dst, &d, NULL, NULL); + ret2 = snprintf(buffer + ret, size - ret, "%.10f", d); + break; + case AV_OPT_TYPE_VIDEO_RATE: + case AV_OPT_TYPE_RATIONAL: + read_number(o, dst, NULL, &i, &i64); + if (i == 1) + ret2 = snprintf(buffer + ret, size - ret, "%"PRId64, i64); + else + ret2 = snprintf(buffer + ret, size - ret, "%"PRId64"/%d", i64, i); + break; + case AV_OPT_TYPE_IMAGE_SIZE: + ret2 = snprintf(buffer + ret, size - ret, "%dx%d", ((int *)dst)[0], ((int *)dst)[1]); + break; + case AV_OPT_TYPE_COLOR: + ret2 = snprintf(buffer + ret, size - ret, "0x%.2x%.2x%.2x%.2x", + ((uint8_t *)dst)[0], ((uint8_t *)dst)[1], ((uint8_t *)dst)[2], ((uint8_t *)dst)[3]); + break; + case AV_OPT_TYPE_BINARY: { + int opt_size = *(int *)((void **)dst + 1); + uint8_t *opt_ptr = *(uint8_t **)dst; + ret2 = opt_size * 2; + if (ret2 >= size - ret) + break; + i = -1; + while(++i < opt_size) + snprintf(buffer + ret + i * 2, size - ret - i * 2, "%.2x", opt_ptr[i]); + break; + } + case AV_OPT_TYPE_DICT: + av_log(NULL, AV_LOG_WARNING, "Dictionary option is not serialized.\n"); + return AVERROR_PATCHWELCOME; + default: + return AVERROR_PATCHWELCOME; + } + if (ret2 >= size - ret || ret2 < 0) + return AVERROR(ENOMEM); + return ret + ret2; +} + +int av_opt_serialize(void *obj, int opt_flags, int skip_defaults, char **buffer, + const char key_val_sep, const char pairs_sep) +{ + const AVOption *o = NULL; + char pair[1024]; + AVBPrint bprint; + int size, cnt = 0; + + if (!obj || !buffer) + return AVERROR(EINVAL); + + *buffer = NULL; + av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED); + + while (o = av_opt_next(obj, o)) { + if (o->flags & opt_flags != opt_flags || o->type == AV_OPT_TYPE_CONST) + continue; + if (skip_defaults && av_opt_is_set_to_default(obj, o) > 0) + continue; + if ((size = opt_serialize_option(obj, o, pair, sizeof(pair), key_val_sep)) < 0) { + if (size == AVERROR_PATCHWELCOME) + continue; + av_bprint_finalize(&bprint, NULL); + return size; + } + if (cnt++) + av_bprint_append_data(&bprint, &pairs_sep, 1); + av_bprint_append_data(&bprint, pair, size); + } + av_bprint_finalize(&bprint, buffer); + return 0; +} + #ifdef TEST typedef struct TestContext @@ -1849,6 +1955,10 @@ typedef struct TestContext int64_t channel_layout; void *binary; int binary_size; + void *binary1; + int binary_size1; + void *binary2; + int binary_size2; int64_t num64; float flt; double dbl; @@ -1877,6 +1987,8 @@ static const AVOption test_options[]= { {"color", "set color", OFFSET(color), AV_OPT_TYPE_COLOR, {.str = "pink"}, 0, 0}, {"cl", "set channel layout", OFFSET(channel_layout), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64 = AV_CH_LAYOUT_HEXAGONAL}, 0, INT64_MAX}, {"bin", "set binary value", OFFSET(binary), AV_OPT_TYPE_BINARY, {.str="62696e00"}, 0, 0 }, +{"bin1", "set binary value", OFFSET(binary1), AV_OPT_TYPE_BINARY, {.str=NULL}, 0, 0 }, +{"bin2", "set binary value", OFFSET(binary2), AV_OPT_TYPE_BINARY, {.str=""}, 0, 0 }, {"num64", "set num 64bit", OFFSET(num64), AV_OPT_TYPE_INT64, {.i64 = 1}, 0, 100 }, {"flt", "set float", OFFSET(flt), AV_OPT_TYPE_FLOAT, {.dbl = 1.0/3}, 0, 100 }, {"dbl", "set double", OFFSET(dbl), AV_OPT_TYPE_DOUBLE, {.dbl = 1.0/3}, 0, 100 }, @@ -1947,6 +2059,29 @@ int main(void) } } + printf("\nTest av_opt_serialize()\n"); + { + TestContext test_ctx = { 0 }; + char *buf; + test_ctx.class = &test_class; + + av_log_set_level(AV_LOG_QUIET); + + av_opt_set_defaults(&test_ctx); + if (av_opt_serialize(&test_ctx, 0, 0, &buf, '=', ',') >= 0) { + printf("%s\n", buf); + av_opt_free(&test_ctx); + memset(&test_ctx, 0, sizeof(test_ctx)); + test_ctx.class = &test_class; + av_set_options_string(&test_ctx, buf, "=", ","); + av_free(buf); + if (av_opt_serialize(&test_ctx, 0, 0, &buf, '=', ',') >= 0) { + printf("%s\n", buf); + av_free(buf); + } + } + } + printf("\nTesting av_set_options_string()\n"); { TestContext test_ctx = { 0 }; diff --git a/libavutil/opt.h b/libavutil/opt.h index a3ad7cc..4c5f28b 100644 --- a/libavutil/opt.h +++ b/libavutil/opt.h @@ -844,6 +844,7 @@ int av_opt_copy(void *dest, void *src); int av_opt_query_ranges_default(AVOptionRanges **, void *obj, const char *key, int flags); /** + * Check if given option is set to its default. * * Options o must belong to the obj. This function must not be called to check child's options state. @@ -870,6 +871,22 @@ int av_opt_is_set_to_default(void *obj, const AVOption *o); int av_opt_is_set_to_default_by_name(void *obj, const char *name, int search_flags); /** + * Serialize object's options. + * + * Create string containing object's serialized options. + * Such string may be passed back to av_set_options_string() in order to restore option values. + * + * @param[in] obj AVClass object to check option on. + * @param[in] opt_flags Serialize only options with all the specified flags set (AV_OPT_FLAG). + * @param[in] skip_defaults When set to non-zero options that are set to their default will not be serialized. + * @param[out] buffer Pointer to buffer that will be allocated with string containg serialized options. + * @param[in] key_val_sep Character used to separate key from value. + * @param[in] pairs_sep Character used to separate two pairs from each other. + * @return >= 0 on success, negative on error. + */ +int av_opt_serialize(void *obj, int opt_flags, int skip_defaults, char **buffer, + const char key_val_sep, const char pairs_sep); +/** * @} */ diff --git a/tests/ref/fate/opt b/tests/ref/fate/opt index 21008bc..825027e 100644 --- a/tests/ref/fate/opt +++ b/tests/ref/fate/opt @@ -34,6 +34,8 @@ option not detected as set to default: 'duration' option not detected as set to default: 'color' option not detected as set to default: 'cl' option not detected as set to default: 'bin' +option detected as set to default: 'bin1' +option detected as set to default: 'bin2' option not detected as set to default: 'num64' option not detected as set to default: 'flt' option not detected as set to default: 'dbl' @@ -53,10 +55,16 @@ option detected as set to default: 'duration' option detected as set to default: 'color' option detected as set to default: 'cl' option detected as set to default: 'bin' +option detected as set to default: 'bin1' +option detected as set to default: 'bin2' option detected as set to default: 'num64' option detected as set to default: 'flt' option detected as set to default: 'dbl' +Test av_opt_serialize() +num=0,toggle=1,rational=1,string=default,flags=1,size=200x300,pix_fmt=297,sample_fmt=1,video_rate=25,duration=0.001000,color=0xffc0cbff,cl=311,bin=62696e00,bin1=,bin2=,num64=1,flt=0.3333333433,dbl=0.3333333333 +num=0,toggle=1,rational=1,string=default,flags=1,size=200x300,pix_fmt=297,sample_fmt=1,video_rate=25,duration=0.001000,color=0xffc0cbff,cl=311,bin=62696e00,bin1=,bin2=,num64=1,flt=0.3333333433,dbl=0.3333333333 + Testing av_set_options_string() OK setting options string: '' Error setting options string: ':' -- 1.9.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel