/* * AVOptions * Copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at> * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
// option is plain old data staticint 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: case AV_OPT_TYPE_UINT: return 1;
} return 0;
}
staticvoid opt_free_elem(enum AVOptionType type, void *ptr)
{ switch (TYPE_BASE(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;
}
}
staticvoid opt_free_array(const AVOption *o, void *parray, unsigned *count)
{ for (unsigned i = 0; i < *count; i++)
opt_free_elem(o->type, opt_array_pelem(o, *(void **)parray, i));
av_freep(parray);
*count = 0;
}
/** * Perform common setup for option-setting functions. * * @param require_type when non-0, require the option to be of this type * @param ptgt target object is written here * @param po the option is written here * @param pdst pointer to option value is written here
*/ staticint opt_set_init(void *obj, constchar *name, int search_flags, int require_type, void **ptgt, const AVOption **po, void **pdst)
{ const AVOption *o; void *tgt;
o = av_opt_find2(obj, name, NULL, 0, search_flags, &tgt); if (!o || !tgt) return AVERROR_OPTION_NOT_FOUND;
if (o->flags & AV_OPT_FLAG_READONLY) return AVERROR(EINVAL);
if (require_type && (o->type != require_type)) {
av_log(obj, AV_LOG_ERROR, "Tried to set option '%s' of type %s from value of type %s, " "this is not supported\n", o->name, opt_type_desc[o->type].name,
opt_type_desc[require_type].name); return AVERROR(EINVAL);
}
// try state flags first from the target (child), then from its parent class = *(const AVClass**)tgt; if ( #if LIBAVUTIL_VERSION_MAJOR < 60
class->version >= AV_VERSION_INT(59, 41, 100) && #endif
class->state_flags_offset)
state_flags = (unsigned*)((uint8_t*)tgt + class->state_flags_offset);
if (state_flags && (*state_flags & AV_CLASS_STATE_INITIALIZED)) {
av_log(obj, AV_LOG_ERROR, "Option '%s' is not a runtime option and " "so cannot be set after the object has been initialized\n",
o->name); #if LIBAVUTIL_VERSION_MAJOR >= 60 return AVERROR(EINVAL); #endif
}
}
if (o->flags & AV_OPT_FLAG_DEPRECATED)
av_log(obj, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", name, o->help);
if (po)
*po = o; if (ptgt)
*ptgt = tgt; if (pdst)
*pdst = ((uint8_t *)tgt) + o->offset;
return 0;
}
static AVRational double_to_rational(double d)
{
AVRational r = av_d2q(d, 1 << 24); if ((!r.num || !r.den) && d)
r = av_d2q(d, INT_MAX); return r;
}
staticint read_number(const AVOption *o, constvoid *dst, double *num, int *den, int64_t *intnum)
{ switch (TYPE_BASE(o->type)) { case AV_OPT_TYPE_FLAGS:
*intnum = *(unsignedint*)dst; return 0; case AV_OPT_TYPE_PIXEL_FMT:
*intnum = *(enum AVPixelFormat *)dst; return 0; case AV_OPT_TYPE_SAMPLE_FMT:
*intnum = *(enum AVSampleFormat *)dst; return 0; case AV_OPT_TYPE_BOOL: case AV_OPT_TYPE_INT:
*intnum = *(int *)dst; return 0; case AV_OPT_TYPE_UINT:
*intnum = *(unsignedint *)dst; return 0; case AV_OPT_TYPE_DURATION: case AV_OPT_TYPE_INT64: case AV_OPT_TYPE_UINT64:
*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_RATIONAL:
*intnum = ((AVRational *)dst)->num;
*den = ((AVRational *)dst)->den; return 0; case AV_OPT_TYPE_CONST:
*intnum = o->default_val.i64; return 0;
} return AVERROR(EINVAL);
}
staticint write_number(void *obj, const AVOption *o, void *dst, double num, int den, int64_t intnum)
{ constenum 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 (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, "Value %f for parameter '%s' is not a valid set of 32bit integer flags\n",
num*intnum/den, o->name); return AVERROR(ERANGE);
}
}
switch (type) { case AV_OPT_TYPE_PIXEL_FMT:
*(enum AVPixelFormat *)dst = llrint(num / den) * intnum; break; case AV_OPT_TYPE_SAMPLE_FMT:
*(enum AVSampleFormat *)dst = llrint(num / den) * intnum; break; case AV_OPT_TYPE_BOOL: case AV_OPT_TYPE_FLAGS: case AV_OPT_TYPE_INT: case AV_OPT_TYPE_UINT:
*(int *)dst = llrint(num / den) * intnum; break; case AV_OPT_TYPE_DURATION: case AV_OPT_TYPE_INT64:{ double d = num / den; if (intnum == 1 && d == (double)INT64_MAX) {
*(int64_t *)dst = INT64_MAX;
} else
*(int64_t *)dst = llrint(d) * intnum; break;} case AV_OPT_TYPE_UINT64:{ double d = num / den; // We must special case uint64_t here as llrint() does not support values // outside the int64_t range and there is no portable function which does // "INT64_MAX + 1ULL" is used as it is representable exactly as IEEE double // while INT64_MAX is not if (intnum == 1 && d == (double)UINT64_MAX) {
*(uint64_t *)dst = UINT64_MAX;
} elseif (d > INT64_MAX + 1ULL) {
*(uint64_t *)dst = (llrint(d - (INT64_MAX + 1ULL)) + (INT64_MAX + 1ULL))*intnum;
} else {
*(uint64_t *)dst = llrint(d) * intnum;
} break;} case AV_OPT_TYPE_FLOAT:
*(float *)dst = num * intnum / den; break; case AV_OPT_TYPE_DOUBLE:
*(double *)dst = num * intnum / den; break; case AV_OPT_TYPE_RATIONAL: case AV_OPT_TYPE_VIDEO_RATE: if ((int) num == num)
*(AVRational *)dst = (AVRational) { num *intnum, den }; else
*(AVRational *)dst = double_to_rational(num * intnum / den); break; default: return AVERROR(EINVAL);
} return 0;
}
staticint hexchar2int(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1;
}
ptr = bin = av_malloc(len); if (!ptr) return AVERROR(ENOMEM); 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;
{ int res; int ci = 0; double const_values[64]; constchar * const_names[64]; int search_flags = (o->flags & AV_OPT_FLAG_CHILD_CONSTS) ? AV_OPT_SEARCH_CHILDREN : 0; const AVOption *o_named = av_opt_find(target_obj, i ? buf : val, o->unit, 0, search_flags); if (o_named && o_named->type == AV_OPT_TYPE_CONST) {
d = DEFAULT_NUMVAL(o_named); if (o_named->flags & AV_OPT_FLAG_DEPRECATED)
av_log(obj, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n",
o_named->name, o_named->help);
} else { if (o->unit) { for (o_named = NULL; o_named = av_opt_next(target_obj, o_named); ) { if (o_named->type == AV_OPT_TYPE_CONST &&
o_named->unit &&
!strcmp(o_named->unit, o->unit)) { if (ci + 6 >= FF_ARRAY_ELEMS(const_values)) {
av_log(obj, AV_LOG_ERROR, "const_values array too small for %s\n", o->unit); return AVERROR_PATCHWELCOME;
}
const_names [ci ] = o_named->name;
const_values[ci++] = DEFAULT_NUMVAL(o_named);
}
}
}
const_names [ci ] = "default";
const_values[ci++] = DEFAULT_NUMVAL(o);
const_names [ci ] = "max";
const_values[ci++] = o->max;
const_names [ci ] = "min";
const_values[ci++] = o->min;
const_names [ci ] = "none";
const_values[ci++] = 0;
const_names [ci ] = "all";
const_values[ci++] = ~0;
const_names [ci] = NULL;
const_values[ci] = 0;
res = av_expr_parse_and_eval(&d, i ? buf : val, 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 (type == AV_OPT_TYPE_FLAGS) {
intnum = *(unsignedint*)dst; if (cmd == '+')
d = intnum | (int64_t)d; elseif (cmd == '-')
d = intnum &~(int64_t)d;
}
if ((ret = write_number(obj, o, dst, d, 1, 1)) < 0) return ret;
val += i; if (!i || !*val) return 0;
}
}
staticint set_string_image_size(void *obj, const AVOption *o, constchar *val, int *dst)
{ int ret;
if (!val || !strcmp(val, "none")) {
dst[0] =
dst[1] = 0; return 0;
}
ret = av_parse_video_size(dst, dst + 1, val); if (ret < 0)
av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as image size\n", val); return ret;
}
staticint set_string_video_rate(void *obj, const AVOption *o, constchar *val, AVRational *dst)
{ int ret = av_parse_video_rate(dst, val); if (ret < 0)
av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as video rate\n", val); return ret;
}
if (!val) { return 0;
} else {
ret = av_parse_color(dst, val, -1, obj); if (ret < 0)
av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as color\n", val); return ret;
} return 0;
}
staticconstchar *get_bool_name(int val)
{ if (val < 0) return"auto"; return val ? "true" : "false";
}
staticint set_string_bool(void *obj, const AVOption *o, constchar *val, int *dst)
{ int n;
if (!val) return 0;
if (!strcmp(val, "auto")) {
n = -1;
} elseif (av_match_name(val, "true,y,yes,enable,enabled,on")) {
n = 1;
} elseif (av_match_name(val, "false,n,no,disable,disabled,off")) {
n = 0;
} else { char *end = NULL;
n = strtol(val, &end, 10); if (val + strlen(val) != end) goto fail;
}
if (n < o->min || n > o->max) goto fail;
*dst = n; return 0;
fail:
av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as boolean\n", val); return AVERROR(EINVAL);
}
staticint set_string_fmt(void *obj, const AVOption *o, constchar *val, uint8_t *dst, int fmt_nb, int ((*get_fmt)(constchar *)), constchar *desc)
{ int fmt, min, max;
if (!val || !strcmp(val, "none")) {
fmt = -1;
} else {
fmt = get_fmt(val); if (fmt == -1) { char *tail;
fmt = strtol(val, &tail, 0); if (*tail || (unsigned)fmt >= fmt_nb) {
av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as %s\n", val, desc); return AVERROR(EINVAL);
}
}
}
min = FFMAX(o->min, -1);
max = FFMIN(o->max, fmt_nb-1);
// hack for compatibility with old ffmpeg if(min == 0 && max == 0) {
min = -1;
max = fmt_nb-1;
}
if (fmt < min || fmt > max) {
av_log(obj, AV_LOG_ERROR, "Value %d for parameter '%s' out of %s format range [%d - %d]\n",
fmt, o->name, desc, min, max); return AVERROR(ERANGE);
}
staticint opt_set_elem(void *obj, void *target_obj, const AVOption *o, constchar *val, void *dst)
{ constenum AVOptionType type = TYPE_BASE(o->type); int ret;
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);
switch (type) { case AV_OPT_TYPE_BOOL: return set_string_bool(obj, o, val, dst); case AV_OPT_TYPE_STRING: return set_string(obj, o, val, dst); case AV_OPT_TYPE_BINARY: return set_string_binary(obj, o, val, dst); case AV_OPT_TYPE_FLAGS: case AV_OPT_TYPE_INT: case AV_OPT_TYPE_UINT: case AV_OPT_TYPE_INT64: case AV_OPT_TYPE_UINT64: case AV_OPT_TYPE_FLOAT: case AV_OPT_TYPE_DOUBLE: case AV_OPT_TYPE_RATIONAL: return set_string_number(obj, target_obj, o, val, dst); case AV_OPT_TYPE_IMAGE_SIZE: return set_string_image_size(obj, o, val, dst); case AV_OPT_TYPE_VIDEO_RATE: {
AVRational tmp;
ret = set_string_video_rate(obj, o, val, &tmp); if (ret < 0) return ret; return write_number(obj, o, dst, 1, tmp.den, tmp.num);
} case AV_OPT_TYPE_PIXEL_FMT: return set_string_pixel_fmt(obj, o, val, dst); case AV_OPT_TYPE_SAMPLE_FMT: return set_string_sample_fmt(obj, o, val, dst); case AV_OPT_TYPE_DURATION:
{
int64_t usecs = 0; if (val) { if ((ret = av_parse_time(&usecs, val, 1)) < 0) {
av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as duration\n", val); return ret;
}
} if (usecs < o->min || usecs > o->max) {
av_log(obj, AV_LOG_ERROR, "Value %f for parameter '%s' out of range [%g - %g]\n",
usecs / 1000000.0, o->name, o->min / 1000000.0, o->max / 1000000.0); return AVERROR(ERANGE);
}
*(int64_t *)dst = usecs; return 0;
} case AV_OPT_TYPE_COLOR: return set_string_color(obj, o, val, dst); case AV_OPT_TYPE_CHLAYOUT:
ret = set_string_channel_layout(obj, o, val, dst); if (ret < 0) {
av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as channel layout\n", val);
ret = AVERROR(EINVAL);
} return ret; case AV_OPT_TYPE_DICT: return set_string_dict(obj, o, val, dst);
}
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;
}
staticint set_number(void *obj, constchar *name, double num, int den, int64_t intnum, int search_flags, int require_type)
{ void *dst; const AVOption *o; int ret;
ret = opt_set_init(obj, name, search_flags, require_type, NULL, &o, &dst); if (ret < 0) return ret;
return write_number(obj, o, dst, num, den, intnum);
}
int av_opt_set_int(void *obj, constchar *name, int64_t val, int search_flags)
{ return set_number(obj, name, 1, 1, val, search_flags, 0);
}
int av_opt_set_double(void *obj, constchar *name, double val, int search_flags)
{ return set_number(obj, name, val, 1, 1, search_flags, 0);
}
int av_opt_set_q(void *obj, constchar *name, AVRational val, int search_flags)
{ return set_number(obj, name, val.num, val.den, 1, search_flags, 0);
}
int av_opt_set_bin(void *obj, constchar *name, const uint8_t *val, int len, int search_flags)
{
uint8_t *ptr;
uint8_t **dst; int *lendst; int ret;
ret = opt_set_init(obj, name, search_flags, AV_OPT_TYPE_BINARY,
NULL, NULL, (void**)&dst); if (ret < 0) return ret;
ptr = len ? av_malloc(len) : NULL; if (len && !ptr) return AVERROR(ENOMEM);
int av_opt_get_image_size(void *obj, constchar *name, int search_flags, int *w_out, int *h_out)
{ 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_IMAGE_SIZE) {
av_log(obj, AV_LOG_ERROR, "The value for option '%s' is not a image size.\n", name); return AVERROR(EINVAL);
}
dst = ((uint8_t*)target_obj) + o->offset; if (w_out) *w_out = *(int *)dst; if (h_out) *h_out = *((int *)dst+1); return 0;
}
int av_opt_get_video_rate(void *obj, constchar *name, int search_flags, AVRational *out_val)
{ return av_opt_get_q(obj, name, search_flags, out_val);
}
staticint get_format(void *obj, constchar *name, int search_flags, int *out_fmt, enum AVOptionType type, constchar *desc)
{ 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 != type) {
av_log(obj, AV_LOG_ERROR, "The value for option '%s' is not a %s format.\n", desc, name); return AVERROR(EINVAL);
}
int av_opt_get_pixel_fmt(void *obj, constchar *name, int search_flags, enum AVPixelFormat *out_fmt)
{ return get_format(obj, name, search_flags, out_fmt, AV_OPT_TYPE_PIXEL_FMT, "pixel");
}
int av_opt_get_sample_fmt(void *obj, constchar *name, int search_flags, enum AVSampleFormat *out_fmt)
{ return get_format(obj, name, search_flags, out_fmt, AV_OPT_TYPE_SAMPLE_FMT, "sample");
}
int av_opt_get_chlayout(void *obj, constchar *name, int search_flags, AVChannelLayout *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_CHLAYOUT) {
av_log(obj, AV_LOG_ERROR, "The value for option '%s' is not a channel layout.\n", name); return AVERROR(EINVAL);
}
if (opt->help)
av_log(av_log_obj, AV_LOG_INFO, " %s", opt->help);
if (av_opt_query_ranges(&r, obj, opt->name, AV_OPT_SEARCH_FAKE_OBJ) >= 0) { switch (opt->type) { case AV_OPT_TYPE_INT: case AV_OPT_TYPE_UINT: case AV_OPT_TYPE_INT64: case AV_OPT_TYPE_UINT64: case AV_OPT_TYPE_DOUBLE: case AV_OPT_TYPE_FLOAT: case AV_OPT_TYPE_RATIONAL: for (i = 0; i < r->nb_ranges; i++) {
av_log(av_log_obj, AV_LOG_INFO, " (from ");
log_value(av_log_obj, AV_LOG_INFO, r->range[i]->value_min);
av_log(av_log_obj, AV_LOG_INFO, " to ");
log_value(av_log_obj, AV_LOG_INFO, r->range[i]->value_max);
av_log(av_log_obj, AV_LOG_INFO, ")");
} break;
}
av_opt_freep_ranges(&r);
}
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 */ break; case AV_OPT_TYPE_BOOL: case AV_OPT_TYPE_FLAGS: case AV_OPT_TYPE_INT: case AV_OPT_TYPE_UINT: case AV_OPT_TYPE_INT64: case AV_OPT_TYPE_UINT64: case AV_OPT_TYPE_DURATION: case AV_OPT_TYPE_PIXEL_FMT: case AV_OPT_TYPE_SAMPLE_FMT:
write_number(s, opt, dst, 1, 1, opt->default_val.i64); break; case AV_OPT_TYPE_DOUBLE: case AV_OPT_TYPE_FLOAT: { double val;
val = opt->default_val.dbl;
write_number(s, opt, dst, val, 1, 1);
} break; case AV_OPT_TYPE_RATIONAL: {
AVRational val;
val = av_d2q(opt->default_val.dbl, INT_MAX);
write_number(s, opt, dst, 1, val.den, val.num);
} break; case AV_OPT_TYPE_COLOR:
set_string_color(s, opt, opt->default_val.str, dst); break; case AV_OPT_TYPE_STRING:
set_string(s, opt, opt->default_val.str, dst); break; case AV_OPT_TYPE_IMAGE_SIZE:
set_string_image_size(s, opt, opt->default_val.str, dst); break; case AV_OPT_TYPE_VIDEO_RATE:
set_string_video_rate(s, opt, opt->default_val.str, dst); break; case AV_OPT_TYPE_BINARY:
set_string_binary(s, opt, opt->default_val.str, dst); break; case AV_OPT_TYPE_CHLAYOUT:
set_string_channel_layout(s, opt, opt->default_val.str, dst); break; case AV_OPT_TYPE_DICT:
set_string_dict(s, opt, opt->default_val.str, dst); break; default:
av_log(s, AV_LOG_DEBUG, "AVOption type %d of option %s not implemented yet\n",
opt->type, opt->name);
}
}
}
/** * Store the value in the field in ctx that is named like key. * ctx must be an AVClass context, storing is done using AVOptions. * * @param buf the string to parse, buf will be updated to point at the * separator just after the parsed key/value pair * @param key_val_sep a 0-terminated list of characters used to * separate key from value * @param pairs_sep a 0-terminated list of characters used to separate * two pairs from each other * @return 0 if the key/value pair has been successfully parsed and * set, or a negative value corresponding to an AVERROR code in case * of error: * AVERROR(EINVAL) if the key/value pair cannot be parsed, * the error code issued by av_opt_set() if the key/value pair * cannot be set
*/ staticint parse_key_value_pair(void *ctx, constchar **buf, constchar *key_val_sep, constchar *pairs_sep)
{ char *key = av_get_token(buf, key_val_sep); char *val; int ret;
if (!key) return AVERROR(ENOMEM);
if (*key && strspn(*buf, key_val_sep)) {
(*buf)++;
val = av_get_token(buf, pairs_sep); if (!val) {
av_freep(&key); return AVERROR(ENOMEM);
}
} else {
av_log(ctx, AV_LOG_ERROR, "Missing key or no key/value separator found after key '%s'\n", key);
av_free(key); return AVERROR(EINVAL);
}
av_log(ctx, AV_LOG_DEBUG, "Setting entry with key '%s' to value '%s'\n", key, val);
ret = av_opt_set(ctx, key, val, AV_OPT_SEARCH_CHILDREN); if (ret == AVERROR_OPTION_NOT_FOUND)
av_log(ctx, AV_LOG_ERROR, "Key '%s' not found.\n", key);
av_free(key);
av_free(val); return ret;
}
int av_set_options_string(void *ctx, constchar *opts, constchar *key_val_sep, constchar *pairs_sep)
{ int ret, count = 0;
if (!opts) return 0;
while (*opts) { if ((ret = parse_key_value_pair(ctx, &opts, key_val_sep, pairs_sep)) < 0) return ret;
count++;
if (*opts)
opts++;
}
return count;
}
#define WHITESPACES " \n\t\r"
staticint is_key_char(char c)
{ return (unsigned)((c | 32) - 'a') < 26 ||
(unsigned)(c - '0') < 10 ||
c == '-' || c == '_' || c == '/' || c == '.';
}
/** * Read a key from a string. * * The key consists of is_key_char characters and must be terminated by a * character from the delim string; spaces are ignored. * * @return 0 for success (even with ellipsis), <0 for failure
*/ staticint get_key(constchar **ropts, constchar *delim, char **rkey)
{ constchar *opts = *ropts; constchar *key_start, *key_end;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.