[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