[FFmpeg-devel] [PATCH 2/9] lavu/opt: introduce av_opt_serialize()

Lukasz Marek lukasz.m.luki2 at gmail.com
Tue Nov 11 08:31:24 CET 2014


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: ':'
-- 
1.9.1



More information about the ffmpeg-devel mailing list