On Tue, 11 Nov 2014 08:31:24 +0100 Lukasz Marek <lukasz.m.lu...@gmail.com> wrote:
> 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: ':' IMO it's quite WTFish to introduce such extensive functionality that is only going to be needed by a single broken thing (FFserver). Can't FFserver's design be fixed instead? _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel