[FFmpeg-devel] [PATCH 2/9] lavu/opt: introduce av_opt_serialize()
wm4
nfxjfg at googlemail.com
Tue Nov 11 11:02:32 CET 2014
On Tue, 11 Nov 2014 08:31:24 +0100
Lukasz Marek <lukasz.m.luki2 at 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.luki2 at 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?
More information about the ffmpeg-devel
mailing list