diff --git a/libavutil/opt.c b/libavutil/opt.c index 1dec9a67d4..876ea4c511 100644 --- a/libavutil/opt.c +++ b/libavutil/opt.c @@ -116,10 +116,98 @@ static int hexchar2int(char c) { return -1; } +static int set_string_binary(void *obj, const AVOption *o, const char *val, uint8_t **dst) +{ + int *lendst = (int *)(dst + 1); + uint8_t *bin, *ptr; + int len = strlen(val); + + av_freep(dst); + *lendst = 0; + + if (len & 1) + return AVERROR(EINVAL); + len /= 2; + + ptr = bin = av_malloc(len); + while (*val) { + int a = hexchar2int(*val++); + int b = hexchar2int(*val++); + if (a < 0 || b < 0) { + av_free(bin); + return AVERROR(EINVAL); + } + *ptr++ = (a << 4) | b; + } + *dst = bin; + *lendst = len; + + return 0; +} + +static int set_string(void *obj, const AVOption *o, const char *val, uint8_t **dst) +{ + av_freep(dst); + *dst = av_strdup(val); + return 0; +} + +static int set_string_number(void *obj, const AVOption *o, const char *val, void *dst) +{ + int ret = 0, notfirst = 0; + for (;;) { + int i; + char buf[256]; + int cmd = 0; + double d; + + if (*val == '+' || *val == '-') + cmd = *(val++); + + for (i = 0; i < sizeof(buf) - 1 && val[i] && val[i] != '+' && val[i] != '-'; i++) + buf[i] = val[i]; + buf[i] = 0; + + { + const AVOption *o_named = av_opt_find(obj, buf, o->unit, 0, 0); + if (o_named && o_named->type == FF_OPT_TYPE_CONST) + d = o_named->default_val.dbl; + else if (!strcmp(buf, "default")) d = o->default_val.dbl; + else if (!strcmp(buf, "max" )) d = o->max; + else if (!strcmp(buf, "min" )) d = o->min; + else if (!strcmp(buf, "none" )) d = 0; + else if (!strcmp(buf, "all" )) d = ~0; + else { + int res = av_expr_parse_and_eval(&d, buf, const_names, const_values, NULL, NULL, NULL, NULL, NULL, 0, obj); + if (res < 0) { + av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\"\n", val); + return res; + } + } + } + if (o->type == FF_OPT_TYPE_FLAGS) { + if (cmd == '+') d = av_get_int(obj, o->name, NULL) | (int64_t)d; + else if (cmd == '-') d = av_get_int(obj, o->name, NULL) &~(int64_t)d; + } else { + if (cmd == '+') d = notfirst*av_get_double(obj, o->name, NULL) + d; + else if (cmd == '-') d = notfirst*av_get_double(obj, o->name, NULL) - d; + } + + if ((ret = av_set_number2(obj, o->name, d, 1, 1, NULL)) < 0) + return ret; + val += i; + if (!*val) + return 0; + notfirst = 1; + } + + return 0; +} + int av_set_string3(void *obj, const char *name, const char *val, int alloc, const AVOption **o_out) { - int ret; const AVOption *o = av_opt_find(obj, name, NULL, 0, 0); + void *dst; if (o_out) *o_out = o; if (!o) @@ -127,85 +215,20 @@ int av_set_string3(void *obj, const char *name, const char *val, int alloc, cons if (!val) return AVERROR(EINVAL); - if (o->type == FF_OPT_TYPE_BINARY) { - uint8_t **dst = (uint8_t **)(((uint8_t*)obj) + o->offset); - int *lendst = (int *)(dst + 1); - uint8_t *bin, *ptr; - int len = strlen(val); - av_freep(dst); - *lendst = 0; - if (len & 1) return AVERROR(EINVAL); - len /= 2; - ptr = bin = av_malloc(len); - while (*val) { - int a = hexchar2int(*val++); - int b = hexchar2int(*val++); - if (a < 0 || b < 0) { - av_free(bin); - return AVERROR(EINVAL); - } - *ptr++ = (a << 4) | b; - } - *dst = bin; - *lendst = len; - return 0; - } - if (o->type != FF_OPT_TYPE_STRING) { - int notfirst=0; - for (;;) { - int i; - char buf[256]; - int cmd=0; - double d; - - if (*val == '+' || *val == '-') - cmd= *(val++); - - for (i=0; iunit, 0, 0); - if (o_named && o_named->type == FF_OPT_TYPE_CONST) - d= o_named->default_val.dbl; - else if (!strcmp(buf, "default")) d= o->default_val.dbl; - else if (!strcmp(buf, "max" )) d= o->max; - else if (!strcmp(buf, "min" )) d= o->min; - else if (!strcmp(buf, "none" )) d= 0; - else if (!strcmp(buf, "all" )) d= ~0; - else { - int res = av_expr_parse_and_eval(&d, buf, const_names, const_values, NULL, NULL, NULL, NULL, NULL, 0, obj); - if (res < 0) { - av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\"\n", val); - return res; - } - } - } - if (o->type == FF_OPT_TYPE_FLAGS) { - if (cmd=='+') d= av_get_int(obj, name, NULL) | (int64_t)d; - else if (cmd=='-') d= av_get_int(obj, name, NULL) &~(int64_t)d; - } else { - if (cmd=='+') d= notfirst*av_get_double(obj, name, NULL) + d; - else if (cmd=='-') d= notfirst*av_get_double(obj, name, NULL) - d; - } - - if ((ret = av_set_number2(obj, name, d, 1, 1, o_out)) < 0) - return ret; - val+= i; - if (!*val) - return 0; - notfirst=1; - } + dst = ((uint8_t*)obj) + o->offset; + switch (o->type) { + case FF_OPT_TYPE_STRING: return set_string(obj, o, val, dst); + case FF_OPT_TYPE_BINARY: return set_string_binary(obj, o, val, dst); + case FF_OPT_TYPE_FLAGS: + case FF_OPT_TYPE_INT: + case FF_OPT_TYPE_INT64: + case FF_OPT_TYPE_FLOAT: + case FF_OPT_TYPE_DOUBLE: + case FF_OPT_TYPE_RATIONAL: return set_string_number(obj, o, val, dst); } - if (alloc) { - av_free(*(void**)(((uint8_t*)obj) + o->offset)); - val= av_strdup(val); - } - - memcpy(((uint8_t*)obj) + o->offset, &val, sizeof(val)); - return 0; + av_log(obj, AV_LOG_ERROR, "Invalid option type.\n"); + return AVERROR(EINVAL); } const AVOption *av_set_double(void *obj, const char *name, double n) diff --git a/libavutil/opt.h b/libavutil/opt.h index c6a59196be..50c0a33bc7 100644 --- a/libavutil/opt.h +++ b/libavutil/opt.h @@ -129,9 +129,7 @@ const AVOption *av_find_opt(void *obj, const char *name, const char *unit, int m * similarly, '-' unsets a flag. * @param[out] o_out if non-NULL put here a pointer to the AVOption * found - * @param alloc when 1 then the old value will be av_freed() and the - * new av_strduped() - * when 0 then no av_free() nor av_strdup() will be used + * @param alloc this parameter is currently ignored * @return 0 if the value has been set, or an AVERROR code in case of * error: * AVERROR_OPTION_NOT_FOUND if no matching option exists