diff --git a/DOCS/man/en/input.rst b/DOCS/man/en/input.rst index 671e05bf05..59d48f5a28 100644 --- a/DOCS/man/en/input.rst +++ b/DOCS/man/en/input.rst @@ -260,6 +260,11 @@ vf set|add|toggle|del "filter1=params,filter2,..." indexes start from the last filter, and ``-1`` denotes the last filter. + You can assign labels to filter by prefixing them with ``@name:`` (where + ``name`` is a user-chosen arbitrary identifiers). Labels can be used to + refer to filters by name in all of the filter chain modification commands. + For ``add``, using an already used label will replace the existing filter. + *EXAMPLE for input.conf*: - ``a vf set flip`` turn video upside-down on the ``a`` key diff --git a/core/m_option.c b/core/m_option.c index e9feef7db9..1f2ba1123e 100644 --- a/core/m_option.c +++ b/core/m_option.c @@ -1938,6 +1938,15 @@ static int parse_obj_settings(struct bstr opt, struct bstr *pstr, char **plist = NULL; const m_struct_t *desc; m_obj_settings_t *ret = _ret ? *_ret : NULL; + bstr label = {0}; + + if (bstr_eatstart0(pstr, "@")) { + if (!bstr_split_tok(*pstr, ":", &label, pstr)) { + mp_msg(MSGT_CFGPARSER, MSGL_ERR, + "Option %.*s: ':' expected after label.\n", BSTR_P(opt)); + return M_OPT_INVALID; + } + } bool has_param = false; int idx = bstrspn(*pstr, NAMECH); @@ -1982,6 +1991,7 @@ static int parse_obj_settings(struct bstr opt, struct bstr *pstr, ret = talloc_realloc(NULL, ret, struct m_obj_settings, ret_n + 2); memset(&ret[ret_n], 0, 2 * sizeof(m_obj_settings_t)); ret[ret_n].name = bstrto0(NULL, str); + ret[ret_n].label = bstrdup0(NULL, label); ret[ret_n].attribs = plist; *_ret = ret; @@ -1999,6 +2009,7 @@ static int obj_settings_list_num_items(m_obj_settings_t *obj_list) static void obj_settings_free_item(m_obj_settings_t *item) { talloc_free(item->name); + talloc_free(item->label); free_str_list(&(item->attribs)); } @@ -2018,19 +2029,30 @@ static void del_obj_settings_list_at(m_obj_settings_t **p_obj_list, int idx) *p_obj_list = talloc_realloc(NULL, obj_list, struct m_obj_settings, num); } -// memory referenced by *item is not copied -static void append_obj_settings_list(m_obj_settings_t **p_obj_list, - m_obj_settings_t *item) +// Insert such that *p_obj_list[idx] is set to item. +// If idx < 0, set idx = count + idx + 1 (i.e. -1 inserts it as last element). +// Memory referenced by *item is not copied. +static void insert_obj_settings_list_at(m_obj_settings_t **p_obj_list, int idx, + m_obj_settings_t *item) { int num = obj_settings_list_num_items(*p_obj_list); + if (idx < 0) + idx = num + idx + 1; + assert(idx >= 0 && idx <= num); *p_obj_list = talloc_realloc(NULL, *p_obj_list, struct m_obj_settings, num + 2); - (*p_obj_list)[num] = *item; + memmove(*p_obj_list + idx + 1, *p_obj_list + idx, + (num - idx) * sizeof(m_obj_settings_t)); + (*p_obj_list)[idx] = *item; (*p_obj_list)[num + 1] = (m_obj_settings_t){0}; } +// If at least one item has a label, compare labels only - otherwise ignore them. static bool obj_setting_equals(m_obj_settings_t *a, m_obj_settings_t *b) { + bstr la = bstr0(a->label), lb = bstr0(b->label); + if (la.len || lb.len) + return bstr_equals(la, lb); if (strcmp(a->name, b->name) != 0) return false; @@ -2049,6 +2071,15 @@ static bool obj_setting_equals(m_obj_settings_t *a, m_obj_settings_t *b) return true; } +static int obj_settings_find_by_label(m_obj_settings_t *obj_list, bstr label) +{ + for (int n = 0; obj_list && obj_list[n].name; n++) { + if (label.len && bstr_equals0(label, obj_list[n].label)) + return n; + } + return -1; +} + static int obj_settings_list_del(struct bstr opt_name, struct bstr param, void *dst) { @@ -2069,6 +2100,19 @@ static int obj_settings_list_del(struct bstr opt_name, struct bstr param, bstr item; bstr_split_tok(param, ",", &item, ¶m); + if (bstr_eatstart0(&item, "@")) { + int label_index = obj_settings_find_by_label(obj_list, item); + if (label_index >= 0) { + mark_del[label_index] = true; + goto found; + } else { + mp_msg(MSGT_CFGPARSER, MSGL_WARN, + "Option %.*s: item label %.*s not found.\n", + BSTR_P(opt_name), BSTR_P(item)); + continue; + } + } + for (int n = 0; n < idx_max; n++) { if (!mark_del[n] && bstr_equals0(item, obj_list[n].name)) { mark_del[n] = true; @@ -2194,11 +2238,6 @@ static int parse_obj_settings_list(const m_option_t *opt, struct bstr name, return M_OPT_EXIT - 1; } - if (op == OP_NONE) { - if (dst && VAL(dst)) - free_obj_settings_list(dst); - } - int num = 0; while (param.len > 0) { int r = parse_obj_settings(name, ¶m, opt->priv, @@ -2217,19 +2256,33 @@ static int parse_obj_settings_list(const m_option_t *opt, struct bstr name, if (dst) { m_obj_settings_t *list = VAL(dst); if (op == OP_PRE) { - int qsize = obj_settings_list_num_items(list); - res = talloc_realloc(NULL, res, struct m_obj_settings, - qsize + num + 1); - memcpy(&res[num], list, (qsize + 1) * sizeof(m_obj_settings_t)); - talloc_free(list); - } else if (op == OP_ADD) { - m_obj_settings_t *list = VAL(dst); - int hsize = obj_settings_list_num_items(list); - list = talloc_realloc(NULL, list, struct m_obj_settings, - hsize + num + 1); - memcpy(&list[hsize], res, (num + 1) * sizeof(m_obj_settings_t)); + int prepend_counter = 0; + for (int n = 0; res && res[n].name; n++) { + int label = obj_settings_find_by_label(list, bstr0(res[n].label)); + if (label < 0) { + insert_obj_settings_list_at(&list, prepend_counter, &res[n]); + prepend_counter++; + } else { + // Prefer replacement semantics, instead of actually + // prepending. + obj_settings_free_item(&list[label]); + list[label] = res[n]; + } + } + talloc_free(res); + } else if (op == OP_ADD) { + for (int n = 0; res && res[n].name; n++) { + int label = obj_settings_find_by_label(list, bstr0(res[n].label)); + if (label < 0) { + insert_obj_settings_list_at(&list, -1, &res[n]); + } else { + // Prefer replacement semantics, instead of actually + // appending. + obj_settings_free_item(&list[label]); + list[label] = res[n]; + } + } talloc_free(res); - res = list; } else if (op == OP_TOGGLE) { for (int n = 0; res && res[n].name; n++) { int found = -1; @@ -2240,16 +2293,19 @@ static int parse_obj_settings_list(const m_option_t *opt, struct bstr name, } } if (found < 0) { - append_obj_settings_list(&list, &res[n]); + insert_obj_settings_list_at(&list, -1, &res[n]); } else { del_obj_settings_list_at(&list, found); obj_settings_free_item(&res[n]); } } talloc_free(res); - res = list; + } else { + assert(op == OP_NONE); + free_obj_settings_list(&list); + list = res; } - VAL(dst) = res; + VAL(dst) = list; } return 1; } @@ -2270,17 +2326,17 @@ static void copy_obj_settings_list(const m_option_t *opt, void *dst, if (!s) return; - - for (n = 0; s[n].name; n++) /* NOP */; d = talloc_array(NULL, struct m_obj_settings, n + 1); for (n = 0; s[n].name; n++) { d[n].name = talloc_strdup(NULL, s[n].name); + d[n].label = talloc_strdup(NULL, s[n].label); d[n].attribs = NULL; copy_str_list(NULL, &(d[n].attribs), &(s[n].attribs)); } d[n].name = NULL; + d[n].label = NULL; d[n].attribs = NULL; VAL(dst) = d; } diff --git a/core/m_option.h b/core/m_option.h index c94b170424..6a8bcfbf1a 100644 --- a/core/m_option.h +++ b/core/m_option.h @@ -110,6 +110,8 @@ typedef struct { typedef struct m_obj_settings { // Type of the object. char *name; + // Optional user-defined name. + char *label; // NULL terminated array of parameter/value pairs. char **attribs; } m_obj_settings_t; diff --git a/video/filter/vf.c b/video/filter/vf.c index 215bf0dc0e..94df76c0e1 100644 --- a/video/filter/vf.c +++ b/video/filter/vf.c @@ -487,13 +487,26 @@ vf_instance_t *append_filters(vf_instance_t *last, //printf("Open filter %s\n",vf_settings[i].name); vf = vf_open_filter(opts, last, vf_settings[i].name, vf_settings[i].attribs); - if (vf) + if (vf) { + if (vf_settings[i].label) + vf->label = talloc_strdup(vf, vf_settings[i].label); last = vf; + } } } return last; } +vf_instance_t *vf_find_by_label(vf_instance_t *chain, const char *label) +{ + while (chain) { + if (chain->label && label && strcmp(chain->label, label) == 0) + return chain; + chain = chain->next; + } + return NULL; +} + //============================================================================ void vf_uninit_filter(vf_instance_t *vf) diff --git a/video/filter/vf.h b/video/filter/vf.h index 3ff4b5ea87..fd0118e152 100644 --- a/video/filter/vf.h +++ b/video/filter/vf.h @@ -66,6 +66,8 @@ typedef struct vf_instance { void (*uninit)(struct vf_instance *vf); + char *label; + // data: struct vf_format fmt_in, fmt_out; struct vf_instance *next; @@ -133,6 +135,8 @@ struct m_obj_settings; vf_instance_t *append_filters(vf_instance_t *last, struct m_obj_settings *vf_settings); +vf_instance_t *vf_find_by_label(vf_instance_t *chain, const char *label); + void vf_uninit_filter(vf_instance_t *vf); void vf_uninit_filter_chain(vf_instance_t *vf);