From 98f8c4f36de0f08fec649aab16358190bf8d41b8 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 4 Apr 2017 14:57:00 +0200 Subject: af: implement generic lavfi option bridge too Literally copy-pasted from the same commit for video filters. (Once new code for filters is implemented, this will all go away or at least get unified anyway.) --- audio/filter/af.c | 27 ++++++++++++++-- audio/filter/af_lavfi.c | 82 ++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 99 insertions(+), 10 deletions(-) diff --git a/audio/filter/af.c b/audio/filter/af.c index 84ee377136..189c12b875 100644 --- a/audio/filter/af.c +++ b/audio/filter/af.c @@ -41,6 +41,7 @@ extern const struct af_info af_info_lavrresample; extern const struct af_info af_info_scaletempo; extern const struct af_info af_info_bs2b; extern const struct af_info af_info_lavfi; +extern const struct af_info af_info_lavfi_bridge; extern const struct af_info af_info_rubberband; static const struct af_info *const filter_list[] = { @@ -56,6 +57,7 @@ static const struct af_info *const filter_list[] = { #endif &af_info_scaletempo, &af_info_lavfi, + &af_info_lavfi_bridge, NULL }; @@ -79,6 +81,7 @@ const struct m_obj_list af_obj_list = { .get_desc = get_desc, .description = "audio filters", .allow_disable_entries = true, + .allow_unknown_entries = true, .aliases = { {"force", "format"}, {0} @@ -149,10 +152,17 @@ contain the commandline parameters for the filter */ static struct af_instance *af_create(struct af_stream *s, char *name, char **args) { + const char *lavfi_name = NULL; + char **lavfi_args = NULL; struct m_obj_desc desc; if (!m_obj_list_find(&desc, &af_obj_list, bstr0(name))) { - MP_ERR(s, "Couldn't find audio filter '%s'.\n", name); - return NULL; + if (!m_obj_list_find(&desc, &af_obj_list, bstr0("lavfi-bridge"))) { + MP_ERR(s, "Couldn't find audio filter '%s'.\n", name); + return NULL; + } + lavfi_name = name; + lavfi_args = args; + args = NULL; } MP_VERBOSE(s, "Adding filter %s \n", name); @@ -170,6 +180,19 @@ static struct af_instance *af_create(struct af_stream *s, char *name, name, s->opts->af_defs, args); if (!config) goto error; + if (lavfi_name) { + // Pass the filter arguments as proper sub-options to the bridge filter. + struct m_config_option *name_opt = m_config_get_co(config, bstr0("name")); + assert(name_opt); + assert(name_opt->opt->type == &m_option_type_string); + if (m_config_set_option_raw(config, name_opt, &lavfi_name, 0) < 0) + goto error; + struct m_config_option *opts = m_config_get_co(config, bstr0("opts")); + assert(opts); + assert(opts->opt->type == &m_option_type_keyvalue_list); + if (m_config_set_option_raw(config, opts, &lavfi_args, 0) < 0) + goto error; + } af->priv = config->optstruct; // Initialize the new filter diff --git a/audio/filter/af_lavfi.c b/audio/filter/af_lavfi.c index 6c371b7315..4c914a9fde 100644 --- a/audio/filter/af_lavfi.c +++ b/audio/filter/af_lavfi.c @@ -57,6 +57,9 @@ #endif struct priv { + // Single filter bridge, instead of a graph. + bool is_bridge; + AVFilterGraph *graph; AVFilterContext *in; AVFilterContext *out; @@ -72,6 +75,8 @@ struct priv { // options char *cfg_graph; char **cfg_avopts; + char *cfg_filter_name; + char **cfg_filter_opts; }; static void destroy_graph(struct af_instance *af) @@ -89,13 +94,12 @@ static bool recreate_graph(struct af_instance *af, struct mp_audio *config) struct priv *p = af->priv; AVFilterContext *in = NULL, *out = NULL; - if (bstr0(p->cfg_graph).len == 0) { + if (!p->is_bridge && bstr0(p->cfg_graph).len == 0) { MP_FATAL(af, "lavfi: no filter graph set\n"); return false; } destroy_graph(af); - MP_VERBOSE(af, "lavfi: create graph: '%s'\n", p->cfg_graph); AVFilterGraph *graph = avfilter_graph_alloc(); if (!graph) @@ -123,14 +127,46 @@ static bool recreate_graph(struct af_instance *af, struct mp_audio *config) "out", NULL, NULL, graph) < 0) goto error; - outputs->name = av_strdup("in"); - outputs->filter_ctx = in; + if (p->is_bridge) { + AVFilterContext *filter = avfilter_graph_alloc_filter(graph, + avfilter_get_by_name(p->cfg_filter_name), "filter"); + if (!filter) + goto error; - inputs->name = av_strdup("out"); - inputs->filter_ctx = out; + if (mp_set_avopts(af->log, filter->priv, p->cfg_filter_opts) < 0) + goto error; - if (graph_parse(graph, p->cfg_graph, inputs, outputs, NULL) < 0) - goto error; + if (avfilter_init_str(filter, NULL) < 0) + goto error; + + // Yep, we have to manually link those filters. + if (filter->nb_inputs != 1 || + avfilter_pad_get_type(filter->input_pads, 0) != AVMEDIA_TYPE_AUDIO || + filter->nb_outputs != 1 || + avfilter_pad_get_type(filter->output_pads, 0) != AVMEDIA_TYPE_AUDIO) + { + MP_ERR(af, "The filter is required to have 1 audio input pad and " + "1 audio output pad.\n"); + goto error; + } + if (avfilter_link(in, 0, filter, 0) < 0 || + avfilter_link(filter, 0, out, 0) < 0) + { + MP_ERR(af, "Failed to link filter.\n"); + goto error; + } + } else { + MP_VERBOSE(af, "lavfi: create graph: '%s'\n", p->cfg_graph); + + outputs->name = av_strdup("in"); + outputs->filter_ctx = in; + + inputs->name = av_strdup("out"); + inputs->filter_ctx = out; + + if (graph_parse(graph, p->cfg_graph, inputs, outputs, NULL) < 0) + goto error; + } if (avfilter_graph_config(graph, NULL) < 0) goto error; @@ -322,10 +358,23 @@ static void uninit(struct af_instance *af) static int af_open(struct af_instance *af) { + struct priv *p = af->priv; + af->control = control; af->uninit = uninit; af->filter_frame = filter_frame; af->filter_out = filter_out; + + if (p->is_bridge) { + if (!p->cfg_filter_name) { + MP_ERR(af, "Filter name not set!\n"); + return 0; + } + if (!avfilter_get_by_name(p->cfg_filter_name)) { + MP_ERR(af, "libavfilter filter '%s' not found!\n", p->cfg_filter_name); + return 0; + } + } return AF_OK; } @@ -342,3 +391,20 @@ const struct af_info af_info_lavfi = { {0} }, }; + +const struct af_info af_info_lavfi_bridge = { + .info = "libavfilter bridge (explicit options)", + .name = "lavfi-bridge", + .open = af_open, + .priv_size = sizeof(struct priv), + .priv_defaults = &(const struct priv){ + .is_bridge = true, + }, + .options = (const struct m_option[]) { + OPT_STRING("name", cfg_filter_name, M_OPT_MIN, .min = 1), + OPT_KEYVALUELIST("opts", cfg_filter_opts, 0), + OPT_STRING("graph", cfg_graph, 0), + OPT_KEYVALUELIST("o", cfg_avopts, 0), + {0} + }, +}; -- cgit v1.2.3