[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