On date Tuesday 2014-11-11 21:24:45 +0100, Lukasz Marek encoded: > On 11.11.2014 17:19, Stefano Sabatini wrote: > >We have already av_get_opt() which serializes the value. Also we should > >probably escape the values. > > I saw that function, but don't remember why I didn't use. I was > wrong obviously. > BTW, I found few bugs in it, sent separate patch for it.
> Updated patch is attached. It is without escaping. I left it for > separate patch. Not sure this is a good idea. Indeed the API allows to specify several key/value and option separators, so this may be a limitation. > Is there any unescape function available? av_get_token() Probably we should update documentation. > From e2f15237517381bb1a7a6613ab80196cd5ae92d6 Mon Sep 17 00:00:00 2001 > From: Lukasz Marek <lukasz.m.lu...@gmail.com> > Date: Mon, 10 Nov 2014 22:28:44 +0100 > Subject: [PATCH] lavu/opt: introduce av_opt_serialize() > > 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 | 64 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++ > libavutil/opt.h | 17 +++++++++++++++ > tests/ref/fate/opt | 8 +++++++ > 3 files changed, 89 insertions(+) > > diff --git a/libavutil/opt.c b/libavutil/opt.c > index 1381cc9..1d8e4b4 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> > > @@ -1835,6 +1836,40 @@ 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 skip_defaults, char > **buffer, > + const char key_val_sep, const char pairs_sep) skip_defaults could be a flag, in case we want to extend it further (for example suppose we only want to print long or short option names). I don't know if we should also add a parameter for choosing the escaping algorithm, probably not. > +{ > + const AVOption *o = NULL; > + uint8_t *buf; > + AVBPrint bprint; > + int ret, 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 ((ret = av_opt_get(obj, o->name, 0, &buf)) < 0) { Here there is a potential problem. At the moment there is no way to distinguish between a string set to NULL and a string set to "", since av_opt_get() will return "" for a string set to NULL. For some configurable elements this will make a difference. The only solution in this case is to use "skip defaults". Also in general the user won't be able to set an option to NULL if not using the binary interface. > + av_bprint_finalize(&bprint, NULL); > + return ret; > + } This will print alias options as well. This was my solution: void av_bprint_options(struct AVBPrint *bp, void *ctx, const char *key_val_sep, const char *pairs_sep) { const AVOption *opt = NULL, *prev_opt = NULL; while (opt = av_opt_next(ctx, opt)) { uint8_t *val; char sep[2] = { pairs_sep[0], 0 }; /* skip duplicated option values */ if (prev_opt && prev_opt->offset == opt->offset) continue; av_opt_get(ctx, opt->name, AV_OPT_SEARCH_CHILDREN, &val); if (opt->offset && val) { av_bprintf(bp, "%s%s%c", prev_opt ? sep : "", opt->name, key_val_sep[0]); av_bprint_escape(bp, val, pairs_sep, AV_ESCAPE_MODE_AUTO, 0); av_freep(&val); } prev_opt = opt; } } > + if (buf) { > + if (cnt++) > + av_bprint_append_data(&bprint, &pairs_sep, 1); > + av_bprintf(&bprint, "%s%c%s", o->name, key_val_sep, buf); > + av_freep(&buf); > + } > + } > + av_bprint_finalize(&bprint, buffer); > + return 0; > +} > + > #ifdef TEST > > typedef struct TestContext > @@ -1854,6 +1889,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; > @@ -1882,6 +1921,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 }, > @@ -1949,6 +1990,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 5158067..4669c55 100644 > --- a/libavutil/opt.h > +++ b/libavutil/opt.h > @@ -870,6 +870,23 @@ 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. Create _a_ string ...? > + * Such string may be passed back to av_set_options_string() in order to > restore option values. av_set_options_string() => av_opt_set_from_string() (the former should be probably rewritten using the latter and deprecated, since it's redundant) s/restore/reset or set > + * > + * @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. > + * Buffer must be freed by the caller when is no > longer needed. > + * @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. nit: please do not capitalize and terminate with a dot incomplete sentences, like this: * @param[in] obj AVClass object to check option on * @param[in] opt_flags flags used to mark options to serialize. It will only serialize ... [...] * @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 [...] -- FFmpeg = Freak and Foolish Multipurpose Proud Elastic Gladiator _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel