diff options
Diffstat (limited to '')
-rw-r--r-- | media/ffvpx/libavutil/opt.c | 1059 |
1 files changed, 627 insertions, 432 deletions
diff --git a/media/ffvpx/libavutil/opt.c b/media/ffvpx/libavutil/opt.c index 0908751752..d11e9d2ac5 100644 --- a/media/ffvpx/libavutil/opt.c +++ b/media/ffvpx/libavutil/opt.c @@ -29,10 +29,10 @@ #include "avassert.h" #include "avstring.h" #include "channel_layout.h" -#include "common.h" #include "dict.h" #include "eval.h" #include "log.h" +#include "mem.h" #include "parseutils.h" #include "pixdesc.h" #include "mathematics.h" @@ -43,6 +43,8 @@ #include <float.h> +#define TYPE_BASE(type) ((type) & ~AV_OPT_TYPE_FLAG_ARRAY) + const AVOption *av_opt_next(const void *obj, const AVOption *last) { const AVClass *class; @@ -56,6 +58,98 @@ const AVOption *av_opt_next(const void *obj, const AVOption *last) return NULL; } +static const size_t opt_elem_size[] = { + [AV_OPT_TYPE_FLAGS] = sizeof(unsigned), + [AV_OPT_TYPE_INT] = sizeof(int), + [AV_OPT_TYPE_INT64] = sizeof(int64_t), + [AV_OPT_TYPE_UINT64] = sizeof(uint64_t), + [AV_OPT_TYPE_DOUBLE] = sizeof(double), + [AV_OPT_TYPE_FLOAT] = sizeof(float), + [AV_OPT_TYPE_STRING] = sizeof(char *), + [AV_OPT_TYPE_RATIONAL] = sizeof(AVRational), + [AV_OPT_TYPE_BINARY] = sizeof(uint8_t *), + [AV_OPT_TYPE_DICT] = sizeof(AVDictionary *), + [AV_OPT_TYPE_IMAGE_SIZE] = sizeof(int[2]), + [AV_OPT_TYPE_VIDEO_RATE] = sizeof(AVRational), + [AV_OPT_TYPE_PIXEL_FMT] = sizeof(int), + [AV_OPT_TYPE_SAMPLE_FMT] = sizeof(int), + [AV_OPT_TYPE_DURATION] = sizeof(int64_t), + [AV_OPT_TYPE_COLOR] = sizeof(uint8_t[4]), + [AV_OPT_TYPE_CHLAYOUT] = sizeof(AVChannelLayout), + [AV_OPT_TYPE_BOOL] = sizeof(int), +}; + +// option is plain old data +static int opt_is_pod(enum AVOptionType type) +{ + switch (type) { + case AV_OPT_TYPE_FLAGS: + case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_INT64: + case AV_OPT_TYPE_DOUBLE: + case AV_OPT_TYPE_FLOAT: + case AV_OPT_TYPE_RATIONAL: + case AV_OPT_TYPE_UINT64: + case AV_OPT_TYPE_IMAGE_SIZE: + case AV_OPT_TYPE_PIXEL_FMT: + case AV_OPT_TYPE_SAMPLE_FMT: + case AV_OPT_TYPE_VIDEO_RATE: + case AV_OPT_TYPE_DURATION: + case AV_OPT_TYPE_COLOR: + case AV_OPT_TYPE_BOOL: + return 1; + } + return 0; +} + +static uint8_t opt_array_sep(const AVOption *o) +{ + const AVOptionArrayDef *d = o->default_val.arr; + av_assert1(o->type & AV_OPT_TYPE_FLAG_ARRAY); + return (d && d->sep) ? d->sep : ','; +} + +static void *opt_array_pelem(const AVOption *o, void *array, unsigned idx) +{ + av_assert1(o->type & AV_OPT_TYPE_FLAG_ARRAY); + return (uint8_t *)array + idx * opt_elem_size[TYPE_BASE(o->type)]; +} + +static unsigned *opt_array_pcount(const void *parray) +{ + return (unsigned *)((const void * const *)parray + 1); +} + +static void opt_free_elem(const AVOption *o, void *ptr) +{ + switch (TYPE_BASE(o->type)) { + case AV_OPT_TYPE_STRING: + case AV_OPT_TYPE_BINARY: + av_freep(ptr); + break; + + case AV_OPT_TYPE_DICT: + av_dict_free((AVDictionary **)ptr); + break; + + case AV_OPT_TYPE_CHLAYOUT: + av_channel_layout_uninit((AVChannelLayout *)ptr); + break; + + default: + break; + } +} + +static void opt_free_array(const AVOption *o, void *parray, unsigned *count) +{ + for (unsigned i = 0; i < *count; i++) + opt_free_elem(o, opt_array_pelem(o, *(void **)parray, i)); + + av_freep(parray); + *count = 0; +} + static int read_number(const AVOption *o, const void *dst, double *num, int *den, int64_t *intnum) { switch (o->type) { @@ -72,11 +166,6 @@ static int read_number(const AVOption *o, const void *dst, double *num, int *den case AV_OPT_TYPE_INT: *intnum = *(int *)dst; return 0; -#if FF_API_OLD_CHANNEL_LAYOUT -FF_DISABLE_DEPRECATION_WARNINGS - case AV_OPT_TYPE_CHANNEL_LAYOUT: -FF_ENABLE_DEPRECATION_WARNINGS -#endif case AV_OPT_TYPE_DURATION: case AV_OPT_TYPE_INT64: case AV_OPT_TYPE_UINT64: @@ -93,7 +182,7 @@ FF_ENABLE_DEPRECATION_WARNINGS *den = ((AVRational *)dst)->den; return 0; case AV_OPT_TYPE_CONST: - *num = o->default_val.dbl; + *intnum = o->default_val.i64; return 0; } return AVERROR(EINVAL); @@ -101,14 +190,16 @@ FF_ENABLE_DEPRECATION_WARNINGS static int write_number(void *obj, const AVOption *o, void *dst, double num, int den, int64_t intnum) { - if (o->type != AV_OPT_TYPE_FLAGS && + const enum AVOptionType type = TYPE_BASE(o->type); + + if (type != AV_OPT_TYPE_FLAGS && (!den || o->max * den < num * intnum || o->min * den > num * intnum)) { num = den ? num * intnum / den : (num && intnum ? INFINITY : NAN); av_log(obj, AV_LOG_ERROR, "Value %f for parameter '%s' out of range [%g - %g]\n", num, o->name, o->min, o->max); return AVERROR(ERANGE); } - if (o->type == AV_OPT_TYPE_FLAGS) { + if (type == AV_OPT_TYPE_FLAGS) { double d = num*intnum/den; if (d < -1.5 || d > 0xFFFFFFFF+0.5 || (llrint(d*256) & 255)) { av_log(obj, AV_LOG_ERROR, @@ -118,7 +209,7 @@ static int write_number(void *obj, const AVOption *o, void *dst, double num, int } } - switch (o->type) { + switch (type) { case AV_OPT_TYPE_PIXEL_FMT: *(enum AVPixelFormat *)dst = llrint(num / den) * intnum; break; @@ -131,11 +222,6 @@ static int write_number(void *obj, const AVOption *o, void *dst, double num, int *(int *)dst = llrint(num / den) * intnum; break; case AV_OPT_TYPE_DURATION: -#if FF_API_OLD_CHANNEL_LAYOUT -FF_DISABLE_DEPRECATION_WARNINGS - case AV_OPT_TYPE_CHANNEL_LAYOUT: -FF_ENABLE_DEPRECATION_WARNINGS -#endif case AV_OPT_TYPE_INT64:{ double d = num / den; if (intnum == 1 && d == (double)INT64_MAX) { @@ -223,6 +309,8 @@ static int set_string_binary(void *obj, const AVOption *o, const char *val, uint static int set_string(void *obj, const AVOption *o, const char *val, uint8_t **dst) { av_freep(dst); + if (!val) + return 0; *dst = av_strdup(val); return *dst ? 0 : AVERROR(ENOMEM); } @@ -237,9 +325,10 @@ static int set_string(void *obj, const AVOption *o, const char *val, uint8_t **d static int set_string_number(void *obj, void *target_obj, const AVOption *o, const char *val, void *dst) { + const enum AVOptionType type = TYPE_BASE(o->type); int ret = 0; - if (o->type == AV_OPT_TYPE_RATIONAL || o->type == AV_OPT_TYPE_VIDEO_RATE) { + if (type == AV_OPT_TYPE_RATIONAL || type == AV_OPT_TYPE_VIDEO_RATE) { int num, den; char c; if (sscanf(val, "%d%*1[:/]%d%c", &num, &den, &c) == 2) { @@ -256,7 +345,7 @@ static int set_string_number(void *obj, void *target_obj, const AVOption *o, con double d; int64_t intnum = 1; - if (o->type == AV_OPT_TYPE_FLAGS) { + if (type == AV_OPT_TYPE_FLAGS) { if (*val == '+' || *val == '-') cmd = *(val++); for (; i < sizeof(buf) - 1 && val[i] && val[i] != '+' && val[i] != '-'; i++) @@ -312,8 +401,8 @@ static int set_string_number(void *obj, void *target_obj, const AVOption *o, con } } } - if (o->type == AV_OPT_TYPE_FLAGS) { - read_number(o, dst, NULL, NULL, &intnum); + if (type == AV_OPT_TYPE_FLAGS) { + intnum = *(unsigned int*)dst; if (cmd == '+') d = intnum | (int64_t)d; else if (cmd == '-') @@ -444,16 +533,26 @@ static int set_string_fmt(void *obj, const AVOption *o, const char *val, uint8_t return 0; } +static int get_pix_fmt(const char *name) +{ + return av_get_pix_fmt(name); +} + static int set_string_pixel_fmt(void *obj, const AVOption *o, const char *val, uint8_t *dst) { return set_string_fmt(obj, o, val, dst, - AV_PIX_FMT_NB, av_get_pix_fmt, "pixel format"); + AV_PIX_FMT_NB, get_pix_fmt, "pixel format"); +} + +static int get_sample_fmt(const char *name) +{ + return av_get_sample_fmt(name); } static int set_string_sample_fmt(void *obj, const AVOption *o, const char *val, uint8_t *dst) { return set_string_fmt(obj, o, val, dst, - AV_SAMPLE_FMT_NB, av_get_sample_fmt, "sample format"); + AV_SAMPLE_FMT_NB, get_sample_fmt, "sample format"); } static int set_string_dict(void *obj, const AVOption *o, const char *val, uint8_t **dst) @@ -484,33 +583,20 @@ static int set_string_channel_layout(void *obj, const AVOption *o, return av_channel_layout_from_string(channel_layout, val); } -int av_opt_set(void *obj, const char *name, const char *val, int search_flags) +static int opt_set_elem(void *obj, void *target_obj, const AVOption *o, + const char *val, void *dst) { - int ret = 0; - void *dst, *target_obj; - const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); - if (!o || !target_obj) - return AVERROR_OPTION_NOT_FOUND; -FF_DISABLE_DEPRECATION_WARNINGS - if (!val && (o->type != AV_OPT_TYPE_STRING && - o->type != AV_OPT_TYPE_PIXEL_FMT && o->type != AV_OPT_TYPE_SAMPLE_FMT && - o->type != AV_OPT_TYPE_IMAGE_SIZE && - o->type != AV_OPT_TYPE_DURATION && o->type != AV_OPT_TYPE_COLOR && -#if FF_API_OLD_CHANNEL_LAYOUT - o->type != AV_OPT_TYPE_CHANNEL_LAYOUT && -#endif - o->type != AV_OPT_TYPE_BOOL)) - return AVERROR(EINVAL); -FF_ENABLE_DEPRECATION_WARNINGS + const enum AVOptionType type = TYPE_BASE(o->type); + int ret; - if (o->flags & AV_OPT_FLAG_READONLY) + if (!val && (type != AV_OPT_TYPE_STRING && + type != AV_OPT_TYPE_PIXEL_FMT && type != AV_OPT_TYPE_SAMPLE_FMT && + type != AV_OPT_TYPE_IMAGE_SIZE && + type != AV_OPT_TYPE_DURATION && type != AV_OPT_TYPE_COLOR && + type != AV_OPT_TYPE_BOOL)) return AVERROR(EINVAL); - if (o->flags & AV_OPT_FLAG_DEPRECATED) - av_log(obj, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", name, o->help); - - dst = ((uint8_t *)target_obj) + o->offset; - switch (o->type) { + switch (type) { case AV_OPT_TYPE_BOOL: return set_string_bool(obj, o, val, dst); case AV_OPT_TYPE_STRING: @@ -557,23 +643,6 @@ FF_ENABLE_DEPRECATION_WARNINGS } case AV_OPT_TYPE_COLOR: return set_string_color(obj, o, val, dst); -#if FF_API_OLD_CHANNEL_LAYOUT -FF_DISABLE_DEPRECATION_WARNINGS - case AV_OPT_TYPE_CHANNEL_LAYOUT: - if (!val || !strcmp(val, "none")) { - *(int64_t *)dst = 0; - } else { - int64_t cl = av_get_channel_layout(val); - if (!cl) { - av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as channel layout\n", val); - ret = AVERROR(EINVAL); - } - *(int64_t *)dst = cl; - return ret; - } - break; -FF_ENABLE_DEPRECATION_WARNINGS -#endif case AV_OPT_TYPE_CHLAYOUT: ret = set_string_channel_layout(obj, o, val, dst); if (ret < 0) { @@ -589,6 +658,104 @@ FF_ENABLE_DEPRECATION_WARNINGS return AVERROR(EINVAL); } +static int opt_set_array(void *obj, void *target_obj, const AVOption *o, + const char *val, void *dst) +{ + const AVOptionArrayDef *arr = o->default_val.arr; + const size_t elem_size = opt_elem_size[TYPE_BASE(o->type)]; + const uint8_t sep = opt_array_sep(o); + uint8_t *str = NULL; + + void *elems = NULL; + unsigned nb_elems = 0; + int ret; + + if (val && *val) { + str = av_malloc(strlen(val) + 1); + if (!str) + return AVERROR(ENOMEM); + } + + // split and unescape the string + while (val && *val) { + uint8_t *p = str; + void *tmp; + + if (arr && arr->size_max && nb_elems >= arr->size_max) { + av_log(obj, AV_LOG_ERROR, + "Cannot assign more than %u elements to array option %s\n", + arr->size_max, o->name); + ret = AVERROR(EINVAL); + goto fail; + } + + for (; *val; val++, p++) { + if (*val == '\\' && val[1]) + val++; + else if (*val == sep) { + val++; + break; + } + *p = *val; + } + *p = 0; + + tmp = av_realloc_array(elems, nb_elems + 1, elem_size); + if (!tmp) { + ret = AVERROR(ENOMEM); + goto fail; + } + elems = tmp; + + tmp = opt_array_pelem(o, elems, nb_elems); + memset(tmp, 0, elem_size); + + ret = opt_set_elem(obj, target_obj, o, str, tmp); + if (ret < 0) + goto fail; + nb_elems++; + } + av_freep(&str); + + opt_free_array(o, dst, opt_array_pcount(dst)); + + if (arr && nb_elems < arr->size_min) { + av_log(obj, AV_LOG_ERROR, + "Cannot assign fewer than %u elements to array option %s\n", + arr->size_min, o->name); + ret = AVERROR(EINVAL); + goto fail; + } + + *((void **)dst) = elems; + *opt_array_pcount(dst) = nb_elems; + + return 0; +fail: + av_freep(&str); + opt_free_array(o, &elems, &nb_elems); + return ret; +} + +int av_opt_set(void *obj, const char *name, const char *val, int search_flags) +{ + void *dst, *target_obj; + const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + if (!o || !target_obj) + return AVERROR_OPTION_NOT_FOUND; + + if (o->flags & AV_OPT_FLAG_READONLY) + return AVERROR(EINVAL); + + if (o->flags & AV_OPT_FLAG_DEPRECATED) + av_log(obj, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", name, o->help); + + dst = ((uint8_t *)target_obj) + o->offset; + + return ((o->type & AV_OPT_TYPE_FLAG_ARRAY) ? + opt_set_array : opt_set_elem)(obj, target_obj, o, val, dst); +} + #define OPT_EVAL_NUMBER(name, opttype, vartype) \ int av_opt_eval_ ## name(void *obj, const AVOption *o, \ const char *val, vartype *name ## _out) \ @@ -614,7 +781,7 @@ static int set_number(void *obj, const char *name, double num, int den, int64_t if (!o || !target_obj) return AVERROR_OPTION_NOT_FOUND; - if (o->flags & AV_OPT_FLAG_READONLY) + if ((o->flags & AV_OPT_FLAG_READONLY) || (o->type & AV_OPT_TYPE_FLAG_ARRAY)) return AVERROR(EINVAL); dst = ((uint8_t *)target_obj) + o->offset; @@ -697,7 +864,8 @@ int av_opt_set_video_rate(void *obj, const char *name, AVRational val, int searc return AVERROR_OPTION_NOT_FOUND; if (o->type != AV_OPT_TYPE_VIDEO_RATE) { av_log(obj, AV_LOG_ERROR, - "The value set by option '%s' is not a video rate.\n", o->name); + "The value set by option '%s' is not a video rate.\n", + o->name); return AVERROR(EINVAL); } if (val.num <= 0 || val.den <= 0) @@ -744,26 +912,6 @@ int av_opt_set_sample_fmt(void *obj, const char *name, enum AVSampleFormat fmt, return set_format(obj, name, fmt, search_flags, AV_OPT_TYPE_SAMPLE_FMT, "sample", AV_SAMPLE_FMT_NB); } -#if FF_API_OLD_CHANNEL_LAYOUT -FF_DISABLE_DEPRECATION_WARNINGS -int av_opt_set_channel_layout(void *obj, const char *name, int64_t cl, int search_flags) -{ - void *target_obj; - const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); - - if (!o || !target_obj) - return AVERROR_OPTION_NOT_FOUND; - if (o->type != AV_OPT_TYPE_CHANNEL_LAYOUT) { - av_log(obj, AV_LOG_ERROR, - "The value set by option '%s' is not a channel layout.\n", o->name); - return AVERROR(EINVAL); - } - *(int64_t *)(((uint8_t *)target_obj) + o->offset) = cl; - return 0; -} -FF_ENABLE_DEPRECATION_WARNINGS -#endif - int av_opt_set_dict_val(void *obj, const char *name, const AVDictionary *val, int search_flags) { @@ -834,145 +982,224 @@ static void format_duration(char *buf, size_t size, int64_t d) *(--e) = 0; } -int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val) +static int opt_get_elem(const AVOption *o, uint8_t **pbuf, size_t buf_len, + void *dst, int search_flags) { - void *dst, *target_obj; - const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); - uint8_t *bin, buf[128]; - int len, i, ret; - int64_t i64; - - if (!o || !target_obj || (o->offset<=0 && o->type != AV_OPT_TYPE_CONST)) - return AVERROR_OPTION_NOT_FOUND; - - if (o->flags & AV_OPT_FLAG_DEPRECATED) - av_log(obj, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", name, o->help); - - dst = (uint8_t *)target_obj + o->offset; + int ret; - buf[0] = 0; - switch (o->type) { + switch (TYPE_BASE(o->type)) { case AV_OPT_TYPE_BOOL: - ret = snprintf(buf, sizeof(buf), "%s", (char *)av_x_if_null(get_bool_name(*(int *)dst), "invalid")); + ret = snprintf(*pbuf, buf_len, "%s", get_bool_name(*(int *)dst)); break; case AV_OPT_TYPE_FLAGS: - ret = snprintf(buf, sizeof(buf), "0x%08X", *(int *)dst); + ret = snprintf(*pbuf, buf_len, "0x%08X", *(int *)dst); break; case AV_OPT_TYPE_INT: - ret = snprintf(buf, sizeof(buf), "%d", *(int *)dst); + ret = snprintf(*pbuf, buf_len, "%d", *(int *)dst); break; case AV_OPT_TYPE_INT64: - ret = snprintf(buf, sizeof(buf), "%"PRId64, *(int64_t *)dst); + ret = snprintf(*pbuf, buf_len, "%"PRId64, *(int64_t *)dst); break; case AV_OPT_TYPE_UINT64: - ret = snprintf(buf, sizeof(buf), "%"PRIu64, *(uint64_t *)dst); + ret = snprintf(*pbuf, buf_len, "%"PRIu64, *(uint64_t *)dst); break; case AV_OPT_TYPE_FLOAT: - ret = snprintf(buf, sizeof(buf), "%f", *(float *)dst); + ret = snprintf(*pbuf, buf_len, "%f", *(float *)dst); break; case AV_OPT_TYPE_DOUBLE: - ret = snprintf(buf, sizeof(buf), "%f", *(double *)dst); + ret = snprintf(*pbuf, buf_len, "%f", *(double *)dst); break; case AV_OPT_TYPE_VIDEO_RATE: case AV_OPT_TYPE_RATIONAL: - ret = snprintf(buf, sizeof(buf), "%d/%d", ((AVRational *)dst)->num, ((AVRational *)dst)->den); + ret = snprintf(*pbuf, buf_len, "%d/%d", ((AVRational *)dst)->num, ((AVRational *)dst)->den); break; case AV_OPT_TYPE_CONST: - ret = snprintf(buf, sizeof(buf), "%f", o->default_val.dbl); + ret = snprintf(*pbuf, buf_len, "%"PRId64, o->default_val.i64); break; case AV_OPT_TYPE_STRING: if (*(uint8_t **)dst) { - *out_val = av_strdup(*(uint8_t **)dst); + *pbuf = av_strdup(*(uint8_t **)dst); } else if (search_flags & AV_OPT_ALLOW_NULL) { - *out_val = NULL; + *pbuf = NULL; return 0; } else { - *out_val = av_strdup(""); + *pbuf = av_strdup(""); } - return *out_val ? 0 : AVERROR(ENOMEM); - case AV_OPT_TYPE_BINARY: + return *pbuf ? 0 : AVERROR(ENOMEM); + case AV_OPT_TYPE_BINARY: { + const uint8_t *bin; + int len; + if (!*(uint8_t **)dst && (search_flags & AV_OPT_ALLOW_NULL)) { - *out_val = NULL; + *pbuf = NULL; return 0; } len = *(int *)(((uint8_t *)dst) + sizeof(uint8_t *)); if ((uint64_t)len * 2 + 1 > INT_MAX) return AVERROR(EINVAL); - if (!(*out_val = av_malloc(len * 2 + 1))) + if (!(*pbuf = av_malloc(len * 2 + 1))) return AVERROR(ENOMEM); if (!len) { - *out_val[0] = '\0'; + *pbuf[0] = '\0'; return 0; } bin = *(uint8_t **)dst; - for (i = 0; i < len; i++) - snprintf(*out_val + i * 2, 3, "%02X", bin[i]); + for (int i = 0; i < len; i++) + snprintf(*pbuf + i * 2, 3, "%02X", bin[i]); return 0; + } case AV_OPT_TYPE_IMAGE_SIZE: - ret = snprintf(buf, sizeof(buf), "%dx%d", ((int *)dst)[0], ((int *)dst)[1]); + ret = snprintf(*pbuf, buf_len, "%dx%d", ((int *)dst)[0], ((int *)dst)[1]); break; case AV_OPT_TYPE_PIXEL_FMT: - ret = snprintf(buf, sizeof(buf), "%s", (char *)av_x_if_null(av_get_pix_fmt_name(*(enum AVPixelFormat *)dst), "none")); + ret = snprintf(*pbuf, buf_len, "%s", (char *)av_x_if_null(av_get_pix_fmt_name(*(enum AVPixelFormat *)dst), "none")); break; case AV_OPT_TYPE_SAMPLE_FMT: - ret = snprintf(buf, sizeof(buf), "%s", (char *)av_x_if_null(av_get_sample_fmt_name(*(enum AVSampleFormat *)dst), "none")); + ret = snprintf(*pbuf, buf_len, "%s", (char *)av_x_if_null(av_get_sample_fmt_name(*(enum AVSampleFormat *)dst), "none")); break; - case AV_OPT_TYPE_DURATION: - i64 = *(int64_t *)dst; - format_duration(buf, sizeof(buf), i64); - ret = strlen(buf); // no overflow possible, checked by an assert + case AV_OPT_TYPE_DURATION: { + int64_t i64 = *(int64_t *)dst; + format_duration(*pbuf, buf_len, i64); + ret = strlen(*pbuf); // no overflow possible, checked by an assert break; + } case AV_OPT_TYPE_COLOR: - ret = snprintf(buf, sizeof(buf), "0x%02x%02x%02x%02x", + ret = snprintf(*pbuf, buf_len, "0x%02x%02x%02x%02x", (int)((uint8_t *)dst)[0], (int)((uint8_t *)dst)[1], (int)((uint8_t *)dst)[2], (int)((uint8_t *)dst)[3]); break; -#if FF_API_OLD_CHANNEL_LAYOUT -FF_DISABLE_DEPRECATION_WARNINGS - case AV_OPT_TYPE_CHANNEL_LAYOUT: - - i64 = *(int64_t *)dst; - ret = snprintf(buf, sizeof(buf), "0x%"PRIx64, i64); - break; -FF_ENABLE_DEPRECATION_WARNINGS -#endif case AV_OPT_TYPE_CHLAYOUT: - ret = av_channel_layout_describe(dst, buf, sizeof(buf)); + ret = av_channel_layout_describe(dst, *pbuf, buf_len); break; case AV_OPT_TYPE_DICT: if (!*(AVDictionary **)dst && (search_flags & AV_OPT_ALLOW_NULL)) { - *out_val = NULL; + *pbuf = NULL; return 0; } - return av_dict_get_string(*(AVDictionary **)dst, (char **)out_val, '=', ':'); + return av_dict_get_string(*(AVDictionary **)dst, (char **)pbuf, '=', ':'); default: return AVERROR(EINVAL); } + return ret; +} + +static int opt_get_array(const AVOption *o, void *dst, uint8_t **out_val) +{ + const unsigned count = *opt_array_pcount(dst); + const uint8_t sep = opt_array_sep(o); + + uint8_t *str = NULL; + size_t str_len = 0; + int ret; + + *out_val = NULL; + + for (unsigned i = 0; i < count; i++) { + uint8_t buf[128], *out = buf; + size_t out_len; + + ret = opt_get_elem(o, &out, sizeof(buf), + opt_array_pelem(o, *(void **)dst, i), 0); + if (ret < 0) + goto fail; + + out_len = strlen(out); + if (out_len > SIZE_MAX / 2 - !!i || + !!i + out_len * 2 > SIZE_MAX - str_len - 1) { + ret = AVERROR(ERANGE); + goto fail; + } + + // terminator escaping separator + // ↓ ↓ ↓ + ret = av_reallocp(&str, str_len + 1 + out_len * 2 + !!i); + if (ret < 0) + goto fail; + + // add separator if needed + if (i) + str[str_len++] = sep; + + // escape the element + for (unsigned j = 0; j < out_len; j++) { + uint8_t val = out[j]; + if (val == sep || val == '\\') + str[str_len++] = '\\'; + str[str_len++] = val; + } + str[str_len] = 0; + +fail: + if (out != buf) + av_freep(&out); + if (ret < 0) { + av_freep(&str); + return ret; + } + } + + *out_val = str; + + return 0; +} + +int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val) +{ + void *dst, *target_obj; + const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + uint8_t *out, buf[128]; + int ret; + + if (!o || !target_obj || (o->offset<=0 && o->type != AV_OPT_TYPE_CONST)) + return AVERROR_OPTION_NOT_FOUND; + + if (o->flags & AV_OPT_FLAG_DEPRECATED) + av_log(obj, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", name, o->help); + + dst = (uint8_t *)target_obj + o->offset; + + if (o->type & AV_OPT_TYPE_FLAG_ARRAY) { + ret = opt_get_array(o, dst, out_val); + if (ret < 0) + return ret; + if (!*out_val && !(search_flags & AV_OPT_ALLOW_NULL)) { + *out_val = av_strdup(""); + if (!*out_val) + return AVERROR(ENOMEM); + } + return 0; + } + + buf[0] = 0; + out = buf; + ret = opt_get_elem(o, &out, sizeof(buf), dst, search_flags); + if (ret < 0) + return ret; + if (out != buf) { + *out_val = out; + return 0; + } + if (ret >= sizeof(buf)) return AVERROR(EINVAL); - *out_val = av_strdup(buf); + *out_val = av_strdup(out); return *out_val ? 0 : AVERROR(ENOMEM); } -static int get_number(void *obj, const char *name, const AVOption **o_out, double *num, int *den, int64_t *intnum, +static int get_number(void *obj, const char *name, double *num, int *den, int64_t *intnum, int search_flags) { void *dst, *target_obj; const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); if (!o || !target_obj) - goto error; + return AVERROR_OPTION_NOT_FOUND; + if (o->type & AV_OPT_TYPE_FLAG_ARRAY) + return AVERROR(EINVAL); dst = ((uint8_t *)target_obj) + o->offset; - if (o_out) *o_out= o; - return read_number(o, dst, num, den, intnum); - -error: - *den = - *intnum = 0; - return -1; } int av_opt_get_int(void *obj, const char *name, int search_flags, int64_t *out_val) @@ -981,7 +1208,7 @@ int av_opt_get_int(void *obj, const char *name, int search_flags, int64_t *out_v double num = 1; int ret, den = 1; - if ((ret = get_number(obj, name, NULL, &num, &den, &intnum, search_flags)) < 0) + if ((ret = get_number(obj, name, &num, &den, &intnum, search_flags)) < 0) return ret; if (num == den) *out_val = intnum; @@ -996,7 +1223,7 @@ int av_opt_get_double(void *obj, const char *name, int search_flags, double *out double num = 1; int ret, den = 1; - if ((ret = get_number(obj, name, NULL, &num, &den, &intnum, search_flags)) < 0) + if ((ret = get_number(obj, name, &num, &den, &intnum, search_flags)) < 0) return ret; *out_val = num * intnum / den; return 0; @@ -1008,7 +1235,7 @@ int av_opt_get_q(void *obj, const char *name, int search_flags, AVRational *out_ double num = 1; int ret, den = 1; - if ((ret = get_number(obj, name, NULL, &num, &den, &intnum, search_flags)) < 0) + if ((ret = get_number(obj, name, &num, &den, &intnum, search_flags)) < 0) return ret; if (num == 1.0 && (int)intnum == intnum) @@ -1026,7 +1253,7 @@ int av_opt_get_image_size(void *obj, const char *name, int search_flags, int *w_ return AVERROR_OPTION_NOT_FOUND; if (o->type != AV_OPT_TYPE_IMAGE_SIZE) { av_log(obj, AV_LOG_ERROR, - "The value for option '%s' is not an image size.\n", name); + "The value for option '%s' is not a image size.\n", name); return AVERROR(EINVAL); } @@ -1042,7 +1269,7 @@ int av_opt_get_video_rate(void *obj, const char *name, int search_flags, AVRatio double num = 1; int ret, den = 1; - if ((ret = get_number(obj, name, NULL, &num, &den, &intnum, search_flags)) < 0) + if ((ret = get_number(obj, name, &num, &den, &intnum, search_flags)) < 0) return ret; if (num == 1.0 && (int)intnum == intnum) @@ -1080,27 +1307,6 @@ int av_opt_get_sample_fmt(void *obj, const char *name, int search_flags, enum AV return get_format(obj, name, search_flags, out_fmt, AV_OPT_TYPE_SAMPLE_FMT, "sample"); } -#if FF_API_OLD_CHANNEL_LAYOUT -FF_DISABLE_DEPRECATION_WARNINGS -int av_opt_get_channel_layout(void *obj, const char *name, int search_flags, int64_t *cl) -{ - void *dst, *target_obj; - const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); - if (!o || !target_obj) - return AVERROR_OPTION_NOT_FOUND; - if (o->type != AV_OPT_TYPE_CHANNEL_LAYOUT) { - av_log(obj, AV_LOG_ERROR, - "The value for option '%s' is not a channel layout.\n", name); - return AVERROR(EINVAL); - } - - dst = ((uint8_t*)target_obj) + o->offset; - *cl = *(int64_t *)dst; - return 0; -} -FF_ENABLE_DEPRECATION_WARNINGS -#endif - int av_opt_get_chlayout(void *obj, const char *name, int search_flags, AVChannelLayout *cl) { void *dst, *target_obj; @@ -1231,6 +1437,120 @@ static char *get_opt_flags_string(void *obj, const char *unit, int64_t value) return NULL; } +static void log_type(void *av_log_obj, const AVOption *o, + enum AVOptionType parent_type) +{ + const char *desc[] = { + [AV_OPT_TYPE_FLAGS] = "<flags>", + [AV_OPT_TYPE_INT] = "<int>", + [AV_OPT_TYPE_INT64] = "<int64>", + [AV_OPT_TYPE_UINT64] = "<uint64>", + [AV_OPT_TYPE_DOUBLE] = "<double>", + [AV_OPT_TYPE_FLOAT] = "<float>", + [AV_OPT_TYPE_STRING] = "<string>", + [AV_OPT_TYPE_RATIONAL] = "<rational>", + [AV_OPT_TYPE_BINARY] = "<binary>", + [AV_OPT_TYPE_DICT] = "<dictionary>", + [AV_OPT_TYPE_IMAGE_SIZE] = "<image_size>", + [AV_OPT_TYPE_VIDEO_RATE] = "<video_rate>", + [AV_OPT_TYPE_PIXEL_FMT] = "<pix_fmt>", + [AV_OPT_TYPE_SAMPLE_FMT] = "<sample_fmt>", + [AV_OPT_TYPE_DURATION] = "<duration>", + [AV_OPT_TYPE_COLOR] = "<color>", + [AV_OPT_TYPE_CHLAYOUT] = "<channel_layout>", + [AV_OPT_TYPE_BOOL] = "<boolean>", + }; + const enum AVOptionType type = TYPE_BASE(o->type); + + if (o->type == AV_OPT_TYPE_CONST && TYPE_BASE(parent_type) == AV_OPT_TYPE_INT) + av_log(av_log_obj, AV_LOG_INFO, "%-12"PRId64" ", o->default_val.i64); + else if (type < FF_ARRAY_ELEMS(desc) && desc[type]) { + if (o->type & AV_OPT_TYPE_FLAG_ARRAY) + av_log(av_log_obj, AV_LOG_INFO, "[%-10s]", desc[type]); + else + av_log(av_log_obj, AV_LOG_INFO, "%-12s ", desc[type]); + } + else + av_log(av_log_obj, AV_LOG_INFO, "%-12s ", ""); +} + +static void log_default(void *obj, void *av_log_obj, const AVOption *opt) +{ + if (opt->type == AV_OPT_TYPE_CONST || opt->type == AV_OPT_TYPE_BINARY) + return; + if ((opt->type == AV_OPT_TYPE_COLOR || + opt->type == AV_OPT_TYPE_IMAGE_SIZE || + opt->type == AV_OPT_TYPE_STRING || + opt->type == AV_OPT_TYPE_DICT || + opt->type == AV_OPT_TYPE_CHLAYOUT || + opt->type == AV_OPT_TYPE_VIDEO_RATE) && + !opt->default_val.str) + return; + + if (opt->type & AV_OPT_TYPE_FLAG_ARRAY) { + const AVOptionArrayDef *arr = opt->default_val.arr; + if (arr && arr->def) + av_log(av_log_obj, AV_LOG_INFO, " (default %s)", arr->def); + return; + } + + av_log(av_log_obj, AV_LOG_INFO, " (default "); + switch (opt->type) { + case AV_OPT_TYPE_BOOL: + av_log(av_log_obj, AV_LOG_INFO, "%s", get_bool_name(opt->default_val.i64)); + break; + case AV_OPT_TYPE_FLAGS: { + char *def_flags = get_opt_flags_string(obj, opt->unit, opt->default_val.i64); + if (def_flags) { + av_log(av_log_obj, AV_LOG_INFO, "%s", def_flags); + av_freep(&def_flags); + } else { + av_log(av_log_obj, AV_LOG_INFO, "%"PRIX64, opt->default_val.i64); + } + break; + } + case AV_OPT_TYPE_DURATION: { + char buf[25]; + format_duration(buf, sizeof(buf), opt->default_val.i64); + av_log(av_log_obj, AV_LOG_INFO, "%s", buf); + break; + } + case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_UINT64: + case AV_OPT_TYPE_INT64: { + const char *def_const = get_opt_const_name(obj, opt->unit, opt->default_val.i64); + if (def_const) + av_log(av_log_obj, AV_LOG_INFO, "%s", def_const); + else + log_int_value(av_log_obj, AV_LOG_INFO, opt->default_val.i64); + break; + } + case AV_OPT_TYPE_DOUBLE: + case AV_OPT_TYPE_FLOAT: + log_value(av_log_obj, AV_LOG_INFO, opt->default_val.dbl); + break; + case AV_OPT_TYPE_RATIONAL: { + AVRational q = av_d2q(opt->default_val.dbl, INT_MAX); + av_log(av_log_obj, AV_LOG_INFO, "%d/%d", q.num, q.den); } + break; + case AV_OPT_TYPE_PIXEL_FMT: + av_log(av_log_obj, AV_LOG_INFO, "%s", (char *)av_x_if_null(av_get_pix_fmt_name(opt->default_val.i64), "none")); + break; + case AV_OPT_TYPE_SAMPLE_FMT: + av_log(av_log_obj, AV_LOG_INFO, "%s", (char *)av_x_if_null(av_get_sample_fmt_name(opt->default_val.i64), "none")); + break; + case AV_OPT_TYPE_COLOR: + case AV_OPT_TYPE_IMAGE_SIZE: + case AV_OPT_TYPE_STRING: + case AV_OPT_TYPE_DICT: + case AV_OPT_TYPE_VIDEO_RATE: + case AV_OPT_TYPE_CHLAYOUT: + av_log(av_log_obj, AV_LOG_INFO, "\"%s\"", opt->default_val.str); + break; + } + av_log(av_log_obj, AV_LOG_INFO, ")"); +} + static void opt_list(void *obj, void *av_log_obj, const char *unit, int req_flags, int rej_flags, enum AVOptionType parent_type) { @@ -1259,76 +1579,8 @@ static void opt_list(void *obj, void *av_log_obj, const char *unit, (opt->flags & AV_OPT_FLAG_FILTERING_PARAM) ? " " : "-", opt->name); - switch (opt->type) { - case AV_OPT_TYPE_FLAGS: - av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<flags>"); - break; - case AV_OPT_TYPE_INT: - av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<int>"); - break; - case AV_OPT_TYPE_INT64: - av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<int64>"); - break; - case AV_OPT_TYPE_UINT64: - av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<uint64>"); - break; - case AV_OPT_TYPE_DOUBLE: - av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<double>"); - break; - case AV_OPT_TYPE_FLOAT: - av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<float>"); - break; - case AV_OPT_TYPE_STRING: - av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<string>"); - break; - case AV_OPT_TYPE_RATIONAL: - av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<rational>"); - break; - case AV_OPT_TYPE_BINARY: - av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<binary>"); - break; - case AV_OPT_TYPE_DICT: - av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<dictionary>"); - break; - case AV_OPT_TYPE_IMAGE_SIZE: - av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<image_size>"); - break; - case AV_OPT_TYPE_VIDEO_RATE: - av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<video_rate>"); - break; - case AV_OPT_TYPE_PIXEL_FMT: - av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<pix_fmt>"); - break; - case AV_OPT_TYPE_SAMPLE_FMT: - av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<sample_fmt>"); - break; - case AV_OPT_TYPE_DURATION: - av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<duration>"); - break; - case AV_OPT_TYPE_COLOR: - av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<color>"); - break; - case AV_OPT_TYPE_CHLAYOUT: -#if FF_API_OLD_CHANNEL_LAYOUT -FF_DISABLE_DEPRECATION_WARNINGS - case AV_OPT_TYPE_CHANNEL_LAYOUT: -FF_ENABLE_DEPRECATION_WARNINGS -#endif - av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<channel_layout>"); - break; - case AV_OPT_TYPE_BOOL: - av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<boolean>"); - break; - case AV_OPT_TYPE_CONST: - if (parent_type == AV_OPT_TYPE_INT) - av_log(av_log_obj, AV_LOG_INFO, "%-12"PRId64" ", opt->default_val.i64); - else - av_log(av_log_obj, AV_LOG_INFO, "%-12s ", ""); - break; - default: - av_log(av_log_obj, AV_LOG_INFO, "%-12s ", ""); - break; - } + log_type(av_log_obj, opt, parent_type); + av_log(av_log_obj, AV_LOG_INFO, "%c%c%c%c%c%c%c%c%c%c%c", (opt->flags & AV_OPT_FLAG_ENCODING_PARAM) ? 'E' : '.', (opt->flags & AV_OPT_FLAG_DECODING_PARAM) ? 'D' : '.', @@ -1365,78 +1617,7 @@ FF_ENABLE_DEPRECATION_WARNINGS av_opt_freep_ranges(&r); } - if (opt->type != AV_OPT_TYPE_CONST && - opt->type != AV_OPT_TYPE_BINARY && - !((opt->type == AV_OPT_TYPE_COLOR || - opt->type == AV_OPT_TYPE_IMAGE_SIZE || - opt->type == AV_OPT_TYPE_STRING || - opt->type == AV_OPT_TYPE_DICT || - opt->type == AV_OPT_TYPE_CHLAYOUT || - opt->type == AV_OPT_TYPE_VIDEO_RATE) && - !opt->default_val.str)) { - av_log(av_log_obj, AV_LOG_INFO, " (default "); - switch (opt->type) { - case AV_OPT_TYPE_BOOL: - av_log(av_log_obj, AV_LOG_INFO, "%s", (char *)av_x_if_null(get_bool_name(opt->default_val.i64), "invalid")); - break; - case AV_OPT_TYPE_FLAGS: { - char *def_flags = get_opt_flags_string(obj, opt->unit, opt->default_val.i64); - if (def_flags) { - av_log(av_log_obj, AV_LOG_INFO, "%s", def_flags); - av_freep(&def_flags); - } else { - av_log(av_log_obj, AV_LOG_INFO, "%"PRIX64, opt->default_val.i64); - } - break; - } - case AV_OPT_TYPE_DURATION: { - char buf[25]; - format_duration(buf, sizeof(buf), opt->default_val.i64); - av_log(av_log_obj, AV_LOG_INFO, "%s", buf); - break; - } - case AV_OPT_TYPE_INT: - case AV_OPT_TYPE_UINT64: - case AV_OPT_TYPE_INT64: { - const char *def_const = get_opt_const_name(obj, opt->unit, opt->default_val.i64); - if (def_const) - av_log(av_log_obj, AV_LOG_INFO, "%s", def_const); - else - log_int_value(av_log_obj, AV_LOG_INFO, opt->default_val.i64); - break; - } - case AV_OPT_TYPE_DOUBLE: - case AV_OPT_TYPE_FLOAT: - log_value(av_log_obj, AV_LOG_INFO, opt->default_val.dbl); - break; - case AV_OPT_TYPE_RATIONAL: { - AVRational q = av_d2q(opt->default_val.dbl, INT_MAX); - av_log(av_log_obj, AV_LOG_INFO, "%d/%d", q.num, q.den); } - break; - case AV_OPT_TYPE_PIXEL_FMT: - av_log(av_log_obj, AV_LOG_INFO, "%s", (char *)av_x_if_null(av_get_pix_fmt_name(opt->default_val.i64), "none")); - break; - case AV_OPT_TYPE_SAMPLE_FMT: - av_log(av_log_obj, AV_LOG_INFO, "%s", (char *)av_x_if_null(av_get_sample_fmt_name(opt->default_val.i64), "none")); - break; - case AV_OPT_TYPE_COLOR: - case AV_OPT_TYPE_IMAGE_SIZE: - case AV_OPT_TYPE_STRING: - case AV_OPT_TYPE_DICT: - case AV_OPT_TYPE_VIDEO_RATE: - case AV_OPT_TYPE_CHLAYOUT: - av_log(av_log_obj, AV_LOG_INFO, "\"%s\"", opt->default_val.str); - break; -#if FF_API_OLD_CHANNEL_LAYOUT -FF_DISABLE_DEPRECATION_WARNINGS - case AV_OPT_TYPE_CHANNEL_LAYOUT: - av_log(av_log_obj, AV_LOG_INFO, "0x%"PRIx64, opt->default_val.i64); - break; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - } - av_log(av_log_obj, AV_LOG_INFO, ")"); - } + log_default(obj, av_log_obj, opt); av_log(av_log_obj, AV_LOG_INFO, "\n"); if (opt->unit && opt->type != AV_OPT_TYPE_CONST) @@ -1473,6 +1654,21 @@ void av_opt_set_defaults2(void *s, int mask, int flags) if (opt->flags & AV_OPT_FLAG_READONLY) continue; + if (opt->type & AV_OPT_TYPE_FLAG_ARRAY) { + const AVOptionArrayDef *arr = opt->default_val.arr; + const char sep = opt_array_sep(opt); + + av_assert0(sep && sep != '\\' && + (sep < 'a' || sep > 'z') && + (sep < 'A' || sep > 'Z') && + (sep < '0' || sep > '9')); + + if (arr && arr->def) + opt_set_array(s, s, opt, arr->def, dst); + + continue; + } + switch (opt->type) { case AV_OPT_TYPE_CONST: /* Nothing to be done here */ @@ -1483,11 +1679,6 @@ void av_opt_set_defaults2(void *s, int mask, int flags) case AV_OPT_TYPE_INT64: case AV_OPT_TYPE_UINT64: case AV_OPT_TYPE_DURATION: -#if FF_API_OLD_CHANNEL_LAYOUT -FF_DISABLE_DEPRECATION_WARNINGS - case AV_OPT_TYPE_CHANNEL_LAYOUT: -FF_ENABLE_DEPRECATION_WARNINGS -#endif case AV_OPT_TYPE_PIXEL_FMT: case AV_OPT_TYPE_SAMPLE_FMT: write_number(s, opt, dst, 1, 1, opt->default_val.i64); @@ -1670,7 +1861,6 @@ int av_opt_set_from_string(void *ctx, const char *opts, { int ret, count = 0; const char *dummy_shorthand = NULL; - char *av_uninit(parsed_key), *av_uninit(value); const char *key; if (!opts) @@ -1679,6 +1869,7 @@ int av_opt_set_from_string(void *ctx, const char *opts, shorthand = &dummy_shorthand; while (*opts) { + char *parsed_key, *value; ret = av_opt_get_key_value(&opts, key_val_sep, pairs_sep, *shorthand ? AV_OPT_FLAG_IMPLICIT_KEY : 0, &parsed_key, &value); @@ -1720,23 +1911,12 @@ void av_opt_free(void *obj) { const AVOption *o = NULL; while ((o = av_opt_next(obj, o))) { - switch (o->type) { - case AV_OPT_TYPE_STRING: - case AV_OPT_TYPE_BINARY: - av_freep((uint8_t *)obj + o->offset); - break; - - case AV_OPT_TYPE_DICT: - av_dict_free((AVDictionary **)(((uint8_t *)obj) + o->offset)); - break; + void *pitem = (uint8_t *)obj + o->offset; - case AV_OPT_TYPE_CHLAYOUT: - av_channel_layout_uninit((AVChannelLayout *)(((uint8_t *)obj) + o->offset)); - break; - - default: - break; - } + if (o->type & AV_OPT_TYPE_FLAG_ARRAY) + opt_free_array(o, pitem, opt_array_pcount(pitem)); + else + opt_free_elem(o, pitem); } } @@ -1838,48 +2018,93 @@ const AVClass *av_opt_child_class_iterate(const AVClass *parent, void **iter) void *av_opt_ptr(const AVClass *class, void *obj, const char *name) { const AVOption *opt= av_opt_find2(&class, name, NULL, 0, AV_OPT_SEARCH_FAKE_OBJ, NULL); - if(!opt) + + // no direct access to array-type options + if (!opt || (opt->type & AV_OPT_TYPE_FLAG_ARRAY)) return NULL; return (uint8_t*)obj + opt->offset; } -static int opt_size(enum AVOptionType type) +static int opt_copy_elem(void *logctx, enum AVOptionType type, + void *dst, const void *src) { - switch(type) { - case AV_OPT_TYPE_BOOL: - case AV_OPT_TYPE_INT: - case AV_OPT_TYPE_FLAGS: - return sizeof(int); - case AV_OPT_TYPE_DURATION: -#if FF_API_OLD_CHANNEL_LAYOUT -FF_DISABLE_DEPRECATION_WARNINGS - case AV_OPT_TYPE_CHANNEL_LAYOUT: -FF_ENABLE_DEPRECATION_WARNINGS -#endif - case AV_OPT_TYPE_INT64: - case AV_OPT_TYPE_UINT64: - return sizeof(int64_t); - case AV_OPT_TYPE_DOUBLE: - return sizeof(double); - case AV_OPT_TYPE_FLOAT: - return sizeof(float); - case AV_OPT_TYPE_STRING: - return sizeof(uint8_t*); - case AV_OPT_TYPE_VIDEO_RATE: - case AV_OPT_TYPE_RATIONAL: - return sizeof(AVRational); - case AV_OPT_TYPE_BINARY: - return sizeof(uint8_t*) + sizeof(int); - case AV_OPT_TYPE_IMAGE_SIZE: - return sizeof(int[2]); - case AV_OPT_TYPE_PIXEL_FMT: - return sizeof(enum AVPixelFormat); - case AV_OPT_TYPE_SAMPLE_FMT: - return sizeof(enum AVSampleFormat); - case AV_OPT_TYPE_COLOR: - return 4; + if (type == AV_OPT_TYPE_STRING) { + const char *src_str = *(const char *const *)src; + char **dstp = (char **)dst; + if (*dstp != src_str) + av_freep(dstp); + if (src_str) { + *dstp = av_strdup(src_str); + if (!*dstp) + return AVERROR(ENOMEM); + } + } else if (type == AV_OPT_TYPE_BINARY) { + const uint8_t *const *src8 = (const uint8_t *const *)src; + uint8_t **dst8 = (uint8_t **)dst; + int len = *(const int *)(src8 + 1); + if (*dst8 != *src8) + av_freep(dst8); + *dst8 = av_memdup(*src8, len); + if (len && !*dst8) { + *(int *)(dst8 + 1) = 0; + return AVERROR(ENOMEM); + } + *(int *)(dst8 + 1) = len; + } else if (type == AV_OPT_TYPE_CONST) { + // do nothing + } else if (type == AV_OPT_TYPE_DICT) { + const AVDictionary *sdict = *(const AVDictionary * const *)src; + AVDictionary **ddictp = (AVDictionary **)dst; + if (sdict != *ddictp) + av_dict_free(ddictp); + *ddictp = NULL; + return av_dict_copy(ddictp, sdict, 0); + } else if (type == AV_OPT_TYPE_CHLAYOUT) { + if (dst != src) + return av_channel_layout_copy(dst, src); + } else if (opt_is_pod(type)) { + size_t size = opt_elem_size[type]; + memcpy(dst, src, size); + } else { + av_log(logctx, AV_LOG_ERROR, "Unhandled option type: %d\n", type); + return AVERROR(EINVAL); } - return AVERROR(EINVAL); + + return 0; +} + +static int opt_copy_array(void *logctx, const AVOption *o, + void **pdst, const void * const *psrc) +{ + unsigned nb_elems = *opt_array_pcount(psrc); + void *dst = NULL; + int ret; + + if (*pdst == *psrc) { + *pdst = NULL; + *opt_array_pcount(pdst) = 0; + } + + opt_free_array(o, pdst, opt_array_pcount(pdst)); + + dst = av_calloc(nb_elems, opt_elem_size[TYPE_BASE(o->type)]); + if (!dst) + return AVERROR(ENOMEM); + + for (unsigned i = 0; i < nb_elems; i++) { + ret = opt_copy_elem(logctx, TYPE_BASE(o->type), + opt_array_pelem(o, dst, i), + opt_array_pelem(o, *(void**)psrc, i)); + if (ret < 0) { + opt_free_array(o, &dst, &nb_elems); + return ret; + } + } + + *pdst = dst; + *opt_array_pcount(pdst) = nb_elems; + + return 0; } int av_opt_copy(void *dst, const void *src) @@ -1898,47 +2123,12 @@ int av_opt_copy(void *dst, const void *src) while ((o = av_opt_next(src, o))) { void *field_dst = (uint8_t *)dst + o->offset; void *field_src = (uint8_t *)src + o->offset; - uint8_t **field_dst8 = (uint8_t **)field_dst; - uint8_t **field_src8 = (uint8_t **)field_src; - - if (o->type == AV_OPT_TYPE_STRING) { - if (*field_dst8 != *field_src8) - av_freep(field_dst8); - *field_dst8 = av_strdup(*field_src8); - if (*field_src8 && !*field_dst8) - ret = AVERROR(ENOMEM); - } else if (o->type == AV_OPT_TYPE_BINARY) { - int len = *(int *)(field_src8 + 1); - if (*field_dst8 != *field_src8) - av_freep(field_dst8); - *field_dst8 = av_memdup(*field_src8, len); - if (len && !*field_dst8) { - ret = AVERROR(ENOMEM); - len = 0; - } - *(int *)(field_dst8 + 1) = len; - } else if (o->type == AV_OPT_TYPE_CONST) { - // do nothing - } else if (o->type == AV_OPT_TYPE_DICT) { - AVDictionary **sdict = (AVDictionary **) field_src; - AVDictionary **ddict = (AVDictionary **) field_dst; - int ret2; - if (*sdict != *ddict) - av_dict_free(ddict); - *ddict = NULL; - ret2 = av_dict_copy(ddict, *sdict, 0); - if (ret2 < 0) - ret = ret2; - } else if (o->type == AV_OPT_TYPE_CHLAYOUT) { - if (field_dst != field_src) - ret = av_channel_layout_copy(field_dst, field_src); - } else { - int size = opt_size(o->type); - if (size < 0) - ret = size; - else - memcpy(field_dst, field_src, size); - } + + int err = (o->type & AV_OPT_TYPE_FLAG_ARRAY) ? + opt_copy_array(dst, o, field_dst, field_src) : + opt_copy_elem (dst, o->type, field_dst, field_src); + if (err < 0) + ret = err; } return ret; } @@ -1995,11 +2185,6 @@ int av_opt_query_ranges_default(AVOptionRanges **ranges_arg, void *obj, const ch case AV_OPT_TYPE_DOUBLE: case AV_OPT_TYPE_DURATION: case AV_OPT_TYPE_COLOR: -#if FF_API_OLD_CHANNEL_LAYOUT -FF_DISABLE_DEPRECATION_WARNINGS - case AV_OPT_TYPE_CHANNEL_LAYOUT: -FF_ENABLE_DEPRECATION_WARNINGS -#endif break; case AV_OPT_TYPE_STRING: range->component_min = 0; @@ -2059,8 +2244,7 @@ void av_opt_freep_ranges(AVOptionRanges **rangesp) int av_opt_is_set_to_default(void *obj, const AVOption *o) { int64_t i64; - double d, d2; - float f; + double d; AVRational q; int ret, w, h; char *str; @@ -2071,6 +2255,24 @@ int av_opt_is_set_to_default(void *obj, const AVOption *o) dst = ((uint8_t*)obj) + o->offset; + if (o->type & AV_OPT_TYPE_FLAG_ARRAY) { + const char *def = o->default_val.arr ? o->default_val.arr->def : NULL; + uint8_t *val; + + ret = opt_get_array(o, dst, &val); + if (ret < 0) + return ret; + + if (!!val != !!def) + ret = 0; + else if (val) + ret = !strcmp(val, def); + + av_freep(&val); + + return ret; + } + switch (o->type) { case AV_OPT_TYPE_CONST: return 1; @@ -2079,11 +2281,6 @@ int av_opt_is_set_to_default(void *obj, const AVOption *o) case AV_OPT_TYPE_PIXEL_FMT: case AV_OPT_TYPE_SAMPLE_FMT: case AV_OPT_TYPE_INT: -#if FF_API_OLD_CHANNEL_LAYOUT -FF_DISABLE_DEPRECATION_WARNINGS - case AV_OPT_TYPE_CHANNEL_LAYOUT: -FF_ENABLE_DEPRECATION_WARNINGS -#endif case AV_OPT_TYPE_DURATION: case AV_OPT_TYPE_INT64: case AV_OPT_TYPE_UINT64: @@ -2105,13 +2302,11 @@ FF_ENABLE_DEPRECATION_WARNINGS return 0; return !strcmp(str, o->default_val.str); case AV_OPT_TYPE_DOUBLE: - read_number(o, dst, &d, NULL, NULL); + d = *(double *)dst; return o->default_val.dbl == d; case AV_OPT_TYPE_FLOAT: - read_number(o, dst, &d, NULL, NULL); - f = o->default_val.dbl; - d2 = f; - return d2 == d; + d = *(float *)dst; + return (float)o->default_val.dbl == d; case AV_OPT_TYPE_RATIONAL: q = av_d2q(o->default_val.dbl, INT_MAX); return !av_cmp_q(*(AVRational*)dst, q); |