mirror of
https://github.com/mpv-player/mpv
synced 2025-02-16 12:17:12 +00:00
video: support positional arguments for automatic lavfi option bridge
Now e.g. --vf=pad=1000:1000 works. All in all pretty ugly and hacky. Just look away.
This commit is contained in:
parent
13160530f2
commit
31611fc46b
@ -60,11 +60,11 @@ normal filter parameters.
|
||||
implemented in mpv only).
|
||||
|
||||
If a filter is not builtin, the ``lavfi-bridge`` will be automatically
|
||||
tried. Keep in mind that this filter does not support positional arguments
|
||||
like ``--vf=name=arg1:arg2``. Instead, you must use
|
||||
``--vf=name=arg1name=arg1value:...``. This bridge also does not support
|
||||
help output, and does not verify parameters before the filter is actually
|
||||
used.
|
||||
tried. This bridge does not support help output, and does not verify
|
||||
parameters before the filter is actually used. Although the mpv syntax
|
||||
is rather similar to libavfilter's, it's not the same. (Which means not
|
||||
everything accepted by vf_lavfi's ``graph`` option will be accepted by
|
||||
``--vf``.)
|
||||
|
||||
Video filters are managed in lists. There are a few commands to manage the
|
||||
filter list.
|
||||
|
@ -302,6 +302,35 @@ void mp_avdict_print_unset(struct mp_log *log, int msgl, AVDictionary *dict)
|
||||
mp_msg(log, msgl, "Could not set AVOption %s='%s'\n", t->key, t->value);
|
||||
}
|
||||
|
||||
// If the name starts with "@", try to interpret it as a number, and set *name
|
||||
// to the name of the n-th parameter.
|
||||
static void resolve_positional_arg(void *avobj, char **name)
|
||||
{
|
||||
if (!*name || (*name)[0] != '@')
|
||||
return;
|
||||
|
||||
char *end = NULL;
|
||||
int pos = strtol(*name + 1, &end, 10);
|
||||
if (!end || *end)
|
||||
return;
|
||||
|
||||
const AVOption *opt = NULL;
|
||||
int offset = -1;
|
||||
while (1) {
|
||||
opt = av_opt_next(avobj, opt);
|
||||
if (!opt)
|
||||
return;
|
||||
// This is what libavfilter's parser does to skip aliases.
|
||||
if (opt->offset != offset && opt->type != AV_OPT_TYPE_CONST)
|
||||
pos--;
|
||||
if (pos < 0) {
|
||||
*name = (char *)opt->name;
|
||||
return;
|
||||
}
|
||||
offset = opt->offset;
|
||||
}
|
||||
}
|
||||
|
||||
// kv is in the format as by OPT_KEYVALUELIST(): kv[0]=key0, kv[1]=val0, ...
|
||||
// Set these options on given avobj (using av_opt_set..., meaning avobj must
|
||||
// point to a struct that has AVClass as first member).
|
||||
@ -313,6 +342,7 @@ int mp_set_avopts(struct mp_log *log, void *avobj, char **kv)
|
||||
for (int n = 0; kv && kv[n * 2]; n++) {
|
||||
char *k = kv[n * 2 + 0];
|
||||
char *v = kv[n * 2 + 1];
|
||||
resolve_positional_arg(avobj, &k);
|
||||
int r = av_opt_set(avobj, k, v, AV_OPT_SEARCH_CHILDREN);
|
||||
if (r == AVERROR_OPTION_NOT_FOUND) {
|
||||
mp_err(log, "AVOption '%s' not found.\n", k);
|
||||
|
@ -2606,17 +2606,33 @@ static void copy_obj_settings_list(const m_option_t *opt, void *dst,
|
||||
static int get_obj_param(struct mp_log *log, bstr opt_name, bstr obj_name,
|
||||
struct m_config *config, bstr name, bstr val,
|
||||
int flags, bool nopos,
|
||||
int *nold, bstr *out_name, bstr *out_val)
|
||||
int *nold, bstr *out_name, bstr *out_val,
|
||||
char *tmp, size_t tmp_size)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!config) {
|
||||
*out_name = name; // preserve args for opengl-hq legacy handling
|
||||
*out_val = val;
|
||||
// Duplicates the logic below, but with unknown parameter types/names.
|
||||
if (val.start || nopos) {
|
||||
*out_name = name;
|
||||
*out_val = val;
|
||||
} else {
|
||||
val = name;
|
||||
// positional fields
|
||||
if (val.len == 0) { // Empty field, count it and go on
|
||||
(*nold)++;
|
||||
return 0;
|
||||
}
|
||||
// Positional naming convention for/followed by mp_set_avopts().
|
||||
snprintf(tmp, tmp_size, "@%d", *nold);
|
||||
*out_name = bstr0(tmp);
|
||||
*out_val = val;
|
||||
(*nold)++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// va.start != NULL => of the form name=val (not positional)
|
||||
// val.start != NULL => of the form name=val (not positional)
|
||||
// If it's just "name", and the associated option exists and is a flag,
|
||||
// don't accept it as positional argument.
|
||||
if (val.start || m_config_option_requires_param(config, name) == 0 || nopos) {
|
||||
@ -2683,6 +2699,7 @@ static int m_obj_parse_sub_config(struct mp_log *log, struct bstr opt_name,
|
||||
char **args = NULL;
|
||||
int num_args = 0;
|
||||
int r = 1;
|
||||
char tmp[80];
|
||||
|
||||
if (ret) {
|
||||
args = *ret;
|
||||
@ -2708,7 +2725,7 @@ static int m_obj_parse_sub_config(struct mp_log *log, struct bstr opt_name,
|
||||
if (bstr_equals0(fname, "help"))
|
||||
goto print_help;
|
||||
r = get_obj_param(log, opt_name, name, config, fname, fval, flags,
|
||||
nopos, &nold, &fname, &fval);
|
||||
nopos, &nold, &fname, &fval, tmp, sizeof(tmp));
|
||||
if (r < 0)
|
||||
goto exit;
|
||||
|
||||
|
@ -172,7 +172,7 @@ static bool recreate_graph(struct vf_instance *vf, struct mp_image_params *fmt)
|
||||
if (!filter)
|
||||
goto error;
|
||||
|
||||
if (mp_set_avopts(vf->log, filter, p->cfg_filter_opts) < 0)
|
||||
if (mp_set_avopts(vf->log, filter->priv, p->cfg_filter_opts) < 0)
|
||||
goto error;
|
||||
|
||||
if (avfilter_init_str(filter, NULL) < 0)
|
||||
|
Loading…
Reference in New Issue
Block a user