// 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: return1;
} return0;
}
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 (class->state_flags_offset)
state_flags = (unsigned*)((uint8_t*)tgt + class->state_flags_offset);
if (!state_flags && obj != tgt) { class = *(const AVClass**)obj; if (class->state_flags_offset)
state_flags = (unsigned*)((uint8_t*)obj + 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); 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);
if (po)
*po = o; if (ptgt)
*ptgt = tgt; if (pdst)
*pdst = ((uint8_t *)tgt) + o->offset;
return0;
}
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; return0; case AV_OPT_TYPE_PIXEL_FMT:
*intnum = *(enum AVPixelFormat *)dst; return0; case AV_OPT_TYPE_SAMPLE_FMT:
*intnum = *(enum AVSampleFormat *)dst; return0; case AV_OPT_TYPE_BOOL: case AV_OPT_TYPE_INT:
*intnum = *(int *)dst; return0; case AV_OPT_TYPE_UINT:
*intnum = *(unsignedint *)dst; return0; case AV_OPT_TYPE_DURATION: case AV_OPT_TYPE_INT64: case AV_OPT_TYPE_UINT64:
*intnum = *(int64_t *)dst; return0; case AV_OPT_TYPE_FLOAT:
*num = *(float *)dst; return0; case AV_OPT_TYPE_DOUBLE:
*num = *(double *)dst; return0; case AV_OPT_TYPE_RATIONAL:
*intnum = ((AVRational *)dst)->num;
*den = ((AVRational *)dst)->den; return0; case AV_OPT_TYPE_CONST:
*intnum = o->default_val.i64; return0;
} 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);
} return0;
}
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;
if (!val) { return0;
} else {
ret = av_parse_color(dst, val, -1, obj); if (ret < 0)
av_log(obj, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as color\n", o->name, val); return ret;
} return0;
}
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) return0;
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; return0;
fail:
av_log(obj, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as boolean\n", o->name, 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 \"%s\" option value \"%s\" as %s\n", o->name, 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 \"%s\" option value \"%s\" as duration\n", o->name, 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; return0;
} 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 \"%s\" option value \"%s\" as channel layout\n", o->name, 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); return0;
}
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, void *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);
}
}
}
array = av_realloc_array(array, new_size, elem_size); if (!array) return AVERROR(ENOMEM);
*(void**)parray = array;
} else
av_freep(parray);
*array_size = new_size;
return0;
}
// otherwise, desired operation is insert/replace; // first, store new elements in a separate array to simplify // rollback on failure
new_elems = av_calloc(nb_elems, elem_size); if (!new_elems) return AVERROR(ENOMEM);
// convert/validate each new element for (unsigned i = 0; i < nb_elems; i++) { void *dst = opt_array_pelem(o, new_elems, i); constvoid *src = (uint8_t*)val + i * elem_size_val;
double num = 1.0; int den = 1;
int64_t intnum = 1;
if (val_type == TYPE_BASE(o->type)) { int err;
ret = opt_copy_elem(obj, val_type, dst, src); if (ret < 0) goto fail;
// validate the range for numeric options
err = read_number(o, dst, &num, &den, &intnum); if (err >= 0 && TYPE_BASE(o->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, "Cannot set array element %u for " "parameter '%s': value %f out of range [%g - %g]\n",
start_elem + i, o->name, num, o->min, o->max);
ret = AVERROR(ERANGE); goto fail;
}
} elseif (val_type == AV_OPT_TYPE_STRING) {
ret = opt_set_elem(obj, target_obj, o, *(constchar **)src, dst); if (ret < 0) goto fail;
} elseif (val_type == AV_OPT_TYPE_INT ||
val_type == AV_OPT_TYPE_INT64 ||
val_type == AV_OPT_TYPE_FLOAT ||
val_type == AV_OPT_TYPE_DOUBLE ||
val_type == AV_OPT_TYPE_RATIONAL) {
switch (val_type) { case AV_OPT_TYPE_INT: intnum = *(int*)src; break; case AV_OPT_TYPE_INT64: intnum = *(int64_t*)src; break; case AV_OPT_TYPE_FLOAT: num = *(float*)src; break; case AV_OPT_TYPE_DOUBLE: num = *(double*)src; break; case AV_OPT_TYPE_RATIONAL: intnum = ((AVRational*)src)->num;
den = ((AVRational*)src)->den; break; default: av_assert0(0);
}
ret = write_number(obj, o, dst, num, den, intnum); if (ret < 0) goto fail;
} else {
ret = AVERROR(ENOSYS); goto fail;
}
}
// commit new elements to the array if (start_elem == 0 && nb_elems == new_size) { // replacing the existing array entirely
opt_free_array(o, parray, array_size);
*(void**)parray = new_elems;
*array_size = nb_elems;
if (search_flags & AV_OPT_ARRAY_REPLACE) { // free the elements being overwritten for (unsigned i = start_elem; i < FFMIN(start_elem + nb_elems, *array_size); i++)
opt_free_elem(o->type, opt_array_pelem(o, array, i));
} else { // shift existing elements to the end
memmove(opt_array_pelem(o, array, start_elem + nb_elems),
opt_array_pelem(o, array, start_elem),
elem_size * (*array_size - start_elem));
}
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.