diff --git a/filters/f_lavfi.c b/filters/f_lavfi.c index 66e045eb2c..23af326c9b 100644 --- a/filters/f_lavfi.c +++ b/filters/f_lavfi.c @@ -941,6 +941,12 @@ static bool is_usable(const AVFilter *filter, int media_type) is_single_media_only(filter->outputs, media_type); } +bool mp_lavfi_is_usable(const char *name, int media_type) +{ + const AVFilter *f = avfilter_get_by_name(name); + return f && is_usable(f, media_type); +} + static void dump_list(struct mp_log *log, int media_type) { mp_info(log, "Available libavfilter filters:\n"); diff --git a/filters/f_lavfi.h b/filters/f_lavfi.h index b43be284cd..c6cf86f500 100644 --- a/filters/f_lavfi.h +++ b/filters/f_lavfi.h @@ -34,3 +34,6 @@ void print_lavfi_help_list(struct mp_log *log, int media_type); // Print libavfilter help for the given filter void print_lavfi_help(struct mp_log *log, const char *name, int media_type); + +// Return whether the given filter exists and has the required media_type in/outs. +bool mp_lavfi_is_usable(const char *name, int media_type); diff --git a/filters/user_filters.c b/filters/user_filters.c index 1a4cf3b122..5ca5b43090 100644 --- a/filters/user_filters.c +++ b/filters/user_filters.c @@ -48,11 +48,17 @@ static void print_af_lavfi_help(struct mp_log *log, const char *name) print_lavfi_help(log, name, AVMEDIA_TYPE_AUDIO); } +static bool check_af_lavfi(const char *name) +{ + return mp_lavfi_is_usable(name, AVMEDIA_TYPE_AUDIO); +} + const struct m_obj_list af_obj_list = { .get_desc = get_af_desc, .description = "audio filters", .allow_disable_entries = true, .allow_unknown_entries = true, + .check_unknown_entry = check_af_lavfi, .print_help_list = print_af_help_list, .print_unknown_entry_help = print_af_lavfi_help, }; @@ -96,11 +102,17 @@ static void print_vf_lavfi_help(struct mp_log *log, const char *name) print_lavfi_help(log, name, AVMEDIA_TYPE_VIDEO); } +static bool check_vf_lavfi(const char *name) +{ + return mp_lavfi_is_usable(name, AVMEDIA_TYPE_VIDEO); +} + const struct m_obj_list vf_obj_list = { .get_desc = get_vf_desc, .description = "video filters", .allow_disable_entries = true, .allow_unknown_entries = true, + .check_unknown_entry = check_vf_lavfi, .print_help_list = print_vf_help_list, .print_unknown_entry_help = print_vf_lavfi_help, }; diff --git a/options/m_option.c b/options/m_option.c index 892016c935..d0f5e7a418 100644 --- a/options/m_option.c +++ b/options/m_option.c @@ -3021,7 +3021,11 @@ static int parse_obj_settings(struct mp_log *log, struct bstr opt, int op, mp_warn(log, "Driver '%s' has been replaced with '%s'!\n", desc.replaced_name, desc.name); } else { - if (!list->allow_unknown_entries) { + char name[80]; + snprintf(name, sizeof(name), "%.*s", BSTR_P(str)); + if (!list->allow_unknown_entries || + (list->check_unknown_entry && !list->check_unknown_entry(name))) + { mp_err(log, "Option %.*s: %.*s doesn't exist.\n", BSTR_P(opt), BSTR_P(str)); return M_OPT_INVALID; diff --git a/options/m_option.h b/options/m_option.h index 4289fa5a2e..a5f9618462 100644 --- a/options/m_option.h +++ b/options/m_option.h @@ -149,6 +149,9 @@ struct m_obj_list { // Allow unknown entries, for which a dummy entry is inserted, and whose // options are skipped and ignored. bool allow_unknown_entries; + // Callback to test whether an unknown entry should be allowed. (This can + // be useful if adding them as explicit entries is too much work.) + bool (*check_unknown_entry)(const char *name); // Allow syntax for disabling entries. bool allow_disable_entries; // This helps with confusing error messages if unknown flag options are used.