diff options
-rwxr-xr-x | TOOLS/zsh.pl | 8 | ||||
-rw-r--r-- | filters/f_lavfi.c | 51 | ||||
-rw-r--r-- | filters/f_lavfi.h | 6 | ||||
-rw-r--r-- | filters/user_filters.c | 26 | ||||
-rw-r--r-- | options/m_option.c | 10 | ||||
-rw-r--r-- | options/m_option.h | 6 |
6 files changed, 97 insertions, 10 deletions
diff --git a/TOOLS/zsh.pl b/TOOLS/zsh.pl index 45c3ced3a0..482aa5e125 100755 --- a/TOOLS/zsh.pl +++ b/TOOLS/zsh.pl @@ -29,11 +29,11 @@ my @opts = parse_main_opts('--list-options', '^ (\-\-[^\s\*]*)\*?\s*(.*)'); die "Couldn't find any options" unless (@opts); -my @ao = parse_opts('--ao=help', '^ ([^\s\:]*)\s*: (.*)'); -my @vo = parse_opts('--vo=help', '^ ([^\s\:]*)\s*: (.*)'); +my @ao = parse_opts('--ao=help', '^ ([^\s\:]*)\s*(.*)'); +my @vo = parse_opts('--vo=help', '^ ([^\s\:]*)\s*(.*)'); -my @af = parse_opts('--af=help', '^ ([^\s\:]*)\s*: (.*)'); -my @vf = parse_opts('--vf=help', '^ ([^\s\:]*)\s*: (.*)'); +my @af = parse_opts('--af=help', '^ ([^\s\:]*)\s*(.*)'); +my @vf = parse_opts('--vf=help', '^ ([^\s\:]*)\s*(.*)'); my @protos = parse_opts('--list-protocols', '^ ([^\s]*)'); diff --git a/filters/f_lavfi.c b/filters/f_lavfi.c index b3f74b508b..745d1699a7 100644 --- a/filters/f_lavfi.c +++ b/filters/f_lavfi.c @@ -903,15 +903,58 @@ static bool is_usable(const AVFilter *filter, int media_type) is_single_media_only(filter->outputs, media_type); } -static void print_help(struct mp_log *log, int mediatype, char *name, char *ex) +static void dump_list(struct mp_log *log, int media_type) { - mp_info(log, "List of libavfilter filters:\n"); + mp_info(log, "Available libavfilter filters:\n"); for (const AVFilter *filter = avfilter_next(NULL); filter; filter = avfilter_next(filter)) { - if (is_usable(filter, mediatype)) - mp_info(log, " %-16s %s\n", filter->name, filter->description); + if (is_usable(filter, media_type)) + mp_info(log, " %-16s %s\n", filter->name, filter->description); } +} + +void print_lavfi_help(struct mp_log *log, const char *name, int media_type) +{ + const AVFilter *f = avfilter_get_by_name(name); + if (!f) { + mp_err(log, "Filter '%s' not found.\n", name); + return; + } + if (!is_usable(f, media_type)) { + mp_err(log, "Filter '%s' is not usable in this context (wrong media \n" + "types or wrong number of inputs/outputs).\n", name); + } + mp_info(log, "Options:\n\n"); + const AVClass *class = f->priv_class; + // av_opt_next() requires this for some retarded incomprehensible reason. + const AVClass **c = &class; + int offset= -1; + int count = 0; + for (const AVOption *o = av_opt_next(c, 0); o; o = av_opt_next(c, o)) { + // This is how libavfilter (at the time) decided to assign positional + // options (called "shorthand" in the libavfilter code). So we + // duplicate it exactly. + if (o->type == AV_OPT_TYPE_CONST || o->offset == offset) + continue; + offset = o->offset; + + mp_info(log, " %s\n", o->name); + count++; + } + mp_info(log, "\nTotal: %d options\n", count); +} + +void print_lavfi_help_list(struct mp_log *log, int media_type) +{ + dump_list(log, media_type); + mp_info(log, "\nIf libavfilter filters clash with builtin mpv filters,\n" + "prefix them with lavfi- to select the libavfilter one.\n\n"); +} + +static void print_help(struct mp_log *log, int mediatype, char *name, char *ex) +{ + dump_list(log, mediatype); mp_info(log, "\n" "This lists %s->%s filters only. Refer to\n" "\n" diff --git a/filters/f_lavfi.h b/filters/f_lavfi.h index 7efc96c3de..089d4aee1f 100644 --- a/filters/f_lavfi.h +++ b/filters/f_lavfi.h @@ -28,3 +28,9 @@ struct mp_lavfi *mp_lavfi_create_filter(struct mp_filter *parent, enum mp_frame_type type, bool bidir, char **graph_opts, const char *filter, char **filter_opts); + +// Print libavfilter list for --vf/--af +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); diff --git a/filters/user_filters.c b/filters/user_filters.c index 30358a4a94..89d7743d53 100644 --- a/filters/user_filters.c +++ b/filters/user_filters.c @@ -1,3 +1,5 @@ +#include <libavutil/avutil.h> + #include "config.h" #include "common/common.h" @@ -36,11 +38,23 @@ static bool get_af_desc(struct m_obj_desc *dst, int index) return get_desc_from(af_list, MP_ARRAY_SIZE(af_list), dst, index); } +static void print_af_help_list(struct mp_log *log) +{ + print_lavfi_help_list(log, AVMEDIA_TYPE_AUDIO); +} + +static void print_af_lavfi_help(struct mp_log *log, const char *name) +{ + print_lavfi_help(log, 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, + .print_help_list = print_af_help_list, + .print_unknown_entry_help = print_af_lavfi_help, }; // --vf option @@ -72,11 +86,23 @@ static bool get_vf_desc(struct m_obj_desc *dst, int index) return get_desc_from(vf_list, MP_ARRAY_SIZE(vf_list), dst, index); } +static void print_vf_help_list(struct mp_log *log) +{ + print_lavfi_help_list(log, AVMEDIA_TYPE_VIDEO); +} + +static void print_vf_lavfi_help(struct mp_log *log, const char *name) +{ + print_lavfi_help(log, 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, + .print_help_list = print_vf_help_list, + .print_unknown_entry_help = print_vf_lavfi_help, }; // Create a bidir, single-media filter from command line arguments. diff --git a/options/m_option.c b/options/m_option.c index 522e771356..e777c5a19e 100644 --- a/options/m_option.c +++ b/options/m_option.c @@ -2940,6 +2940,8 @@ print_help: ; if (desc->print_help) desc->print_help(log); m_config_print_option_list(config, "*"); + } else if (list->print_unknown_entry_help) { + list->print_unknown_entry_help(log, mp_tprintf(80, "%.*s", BSTR_P(name))); } else { mp_warn(log, "Option %.*s: item %.*s doesn't exist.\n", BSTR_P(opt_name), BSTR_P(name)); @@ -3155,11 +3157,17 @@ static int parse_obj_settings_list(struct mp_log *log, const m_option_t *opt, if (!ol->get_desc(&desc, n)) break; if (!desc.hidden) { - mp_info(log, " %-15s: %s\n", + mp_info(log, " %-16s %s\n", desc.name, desc.description); } } mp_info(log, "\n"); + if (ol->print_help_list) + ol->print_help_list(log); + if (!ol->use_global_options) { + mp_info(log, "Get help on individual entries via: --%s=entry=help\n", + opt->name); + } return M_OPT_EXIT; } diff --git a/options/m_option.h b/options/m_option.h index f47dac294e..af082a893d 100644 --- a/options/m_option.h +++ b/options/m_option.h @@ -129,7 +129,7 @@ struct m_obj_desc { const char *init_options; // Don't list entry with "help" bool hidden; - // Callback to print custom help if "help" is passed + // Callback to print custom help if "vf=entry=help" is passed void (*print_help)(struct mp_log *log); // Callback that allows you to override the static default values. The // pointer p points to the struct described by options/priv_size, with @@ -159,6 +159,10 @@ struct m_obj_list { bool disallow_positional_parameters; // Each sub-item is backed by global options (for AOs and VOs). bool use_global_options; + // Callback to print additional custom help if "vf=help" is passed + void (*print_help_list)(struct mp_log *log); + // Callback to print help for _unknown_ entries with "vf=entry=help" + void (*print_unknown_entry_help)(struct mp_log *log, const char *name); }; // Find entry by name |