From b9f804b566c4c528714e4ec5e63675ad7ba5fefd Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 18 Jan 2018 14:44:20 +0100 Subject: audio: rewrite filtering glue code Use the new filtering code for audio too. --- audio/filter/af.c | 824 ----------------------------------------- audio/filter/af.h | 163 -------- audio/filter/af_format.c | 173 ++++----- audio/filter/af_lavcac3enc.c | 504 ++++++++++++------------- audio/filter/af_lavfi.c | 413 --------------------- audio/filter/af_lavrresample.c | 187 +++------- audio/filter/af_rubberband.c | 446 +++++++++++++--------- audio/filter/af_scaletempo.c | 577 +++++++++++++++++------------ audio/filter/tools.c | 72 ---- 9 files changed, 985 insertions(+), 2374 deletions(-) delete mode 100644 audio/filter/af.c delete mode 100644 audio/filter/af.h delete mode 100644 audio/filter/af_lavfi.c delete mode 100644 audio/filter/tools.c (limited to 'audio/filter') diff --git a/audio/filter/af.c b/audio/filter/af.c deleted file mode 100644 index cf200bbb84..0000000000 --- a/audio/filter/af.c +++ /dev/null @@ -1,824 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#include "config.h" -#include -#include -#include -#include - -#include "common/common.h" -#include "common/global.h" - -#include "options/m_option.h" -#include "options/m_config.h" - -#include "audio/audio_buffer.h" -#include "af.h" - -// Static list of filters -extern const struct af_info af_info_format; -extern const struct af_info af_info_lavcac3enc; -extern const struct af_info af_info_lavrresample; -extern const struct af_info af_info_scaletempo; -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[] = { - &af_info_format, - &af_info_lavcac3enc, - &af_info_lavrresample, -#if HAVE_RUBBERBAND - &af_info_rubberband, -#endif - &af_info_scaletempo, - &af_info_lavfi, - &af_info_lavfi_bridge, - NULL -}; - -static bool get_desc(struct m_obj_desc *dst, int index) -{ - if (index >= MP_ARRAY_SIZE(filter_list) - 1) - return false; - const struct af_info *af = filter_list[index]; - *dst = (struct m_obj_desc) { - .name = af->name, - .description = af->info, - .priv_size = af->priv_size, - .priv_defaults = af->priv_defaults, - .options = af->options, - .set_defaults = af->set_defaults, - .p = af, - }; - return true; -} - -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} - }, -}; - -static void af_forget_frames(struct af_instance *af) -{ - for (int n = 0; n < af->num_out_queued; n++) - talloc_free(af->out_queued[n]); - af->num_out_queued = 0; -} - -static void af_chain_forget_frames(struct af_stream *s) -{ - for (struct af_instance *cur = s->first; cur; cur = cur->next) - af_forget_frames(cur); -} - -static void af_copy_unset_fields(struct mp_audio *dst, struct mp_audio *src) -{ - if (dst->format == AF_FORMAT_UNKNOWN) - mp_audio_set_format(dst, src->format); - if (dst->nch == 0) - mp_audio_set_channels(dst, &src->channels); - if (dst->rate == 0) - dst->rate = src->rate; -} - -static int input_control(struct af_instance* af, int cmd, void* arg) -{ - switch (cmd) { - case AF_CONTROL_REINIT: - assert(arg == &((struct af_stream *)af->priv)->input); - return AF_OK; - } - return AF_UNKNOWN; -} - -static int output_control(struct af_instance* af, int cmd, void* arg) -{ - struct af_stream *s = af->priv; - struct mp_audio *output = &s->output; - struct mp_audio *filter_output = &s->filter_output; - - switch (cmd) { - case AF_CONTROL_REINIT: { - struct mp_audio *in = arg; - struct mp_audio orig_in = *in; - - *filter_output = *output; - af_copy_unset_fields(filter_output, in); - *in = *filter_output; - return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE; - } - } - return AF_UNKNOWN; -} - -static int dummy_filter(struct af_instance *af, struct mp_audio *frame) -{ - af_add_output_frame(af, frame); - return 0; -} - -/* Function for creating a new filter of type name.The name may -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))) { - 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; - if (strncmp(lavfi_name, "lavfi-", 6) == 0) - lavfi_name += 6; - } - MP_VERBOSE(s, "Adding filter %s \n", name); - - struct af_instance *af = talloc_zero(NULL, struct af_instance); - *af = (struct af_instance) { - .full_name = talloc_strdup(af, name), - .info = desc.p, - .data = talloc_zero(af, struct mp_audio), - .log = mp_log_new(af, s->log, name), - .opts = s->opts, - .global = s->global, - .out_pool = mp_audio_pool_create(af), - }; - struct m_config *config = - m_config_from_obj_desc_and_args(af, s->log, s->global, &desc, - 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->full_name = talloc_asprintf(af, "%s (lavfi)", af->full_name); - } - af->priv = config->optstruct; - - // Initialize the new filter - if (af->info->open(af) != AF_OK) - goto error; - - return af; - -error: - MP_ERR(s, "Couldn't create or open audio filter '%s'\n", name); - talloc_free(af); - return NULL; -} - -/* Create and insert a new filter of type name before the filter in the - argument. This function can be called during runtime, the return - value is the new filter */ -static struct af_instance *af_prepend(struct af_stream *s, - struct af_instance *af, - char *name, char **args) -{ - if (!af) - af = s->last; - if (af == s->first) - af = s->first->next; - // Create the new filter and make sure it is OK - struct af_instance *new = af_create(s, name, args); - if (!new) - return NULL; - // Update pointers - new->next = af; - new->prev = af->prev; - af->prev = new; - new->prev->next = new; - return new; -} - -// Uninit and remove the filter "af" -static void af_remove(struct af_stream *s, struct af_instance *af) -{ - if (!af) - return; - - if (af == s->first || af == s->last) - return; - - // Print friendly message - MP_VERBOSE(s, "Removing filter %s \n", af->info->name); - - // Detach pointers - af->prev->next = af->next; - af->next->prev = af->prev; - - if (af->uninit) - af->uninit(af); - af_forget_frames(af); - talloc_free(af); -} - -static void remove_auto_inserted_filters(struct af_stream *s) -{ -repeat: - for (struct af_instance *af = s->first; af; af = af->next) { - if (af->auto_inserted) { - af_remove(s, af); - goto repeat; - } - } -} - -static void af_print_filter_chain(struct af_stream *s, struct af_instance *at, - int msg_level) -{ - MP_MSG(s, msg_level, "Audio filter chain:\n"); - - struct af_instance *af = s->first; - while (af) { - char b[128] = {0}; - mp_snprintf_cat(b, sizeof(b), " [%s] ", af->full_name); - if (af->label) - mp_snprintf_cat(b, sizeof(b), "\"%s\" ", af->label); - if (af->data) - mp_snprintf_cat(b, sizeof(b), "%s", mp_audio_config_to_str(af->data)); - if (af->auto_inserted) - mp_snprintf_cat(b, sizeof(b), " [a]"); - if (af == at) - mp_snprintf_cat(b, sizeof(b), " <-"); - MP_MSG(s, msg_level, "%s\n", b); - - af = af->next; - } - - MP_MSG(s, msg_level, " [ao] %s\n", mp_audio_config_to_str(&s->output)); -} - -static void reset_formats(struct af_stream *s) -{ - struct mp_audio none = {0}; - for (struct af_instance *af = s->first; af; af = af->next) { - if (af != s->first && af != s->last) - mp_audio_copy_config(af->data, &none); - } -} - -static int filter_reinit(struct af_instance *af) -{ - struct af_instance *prev = af->prev; - assert(prev); - - // Check if this is the first filter - struct mp_audio in = *prev->data; - // Reset just in case... - mp_audio_set_null_data(&in); - - if (!mp_audio_config_valid(&in)) - return AF_ERROR; - - af->fmt_in = in; - int rv = af->control(af, AF_CONTROL_REINIT, &in); - if (rv == AF_OK && !mp_audio_config_equals(&in, prev->data)) - rv = AF_FALSE; // conversion filter needed - if (rv == AF_FALSE) - af->fmt_in = in; - - if (rv == AF_OK) { - if (!mp_audio_config_valid(af->data)) - return AF_ERROR; - af->fmt_out = *af->data; - } - - return rv; -} - -static int filter_reinit_with_conversion(struct af_stream *s, struct af_instance *af) -{ - int rv = filter_reinit(af); - - // Conversion filter is needed - if (rv == AF_FALSE) { - // First try if we can change the output format of the previous - // filter to the input format the current filter is expecting. - struct mp_audio in = af->fmt_in; - if (af->prev != s->first && !mp_audio_config_equals(af->prev->data, &in)) { - // This should have been successful (because it succeeded - // before), even if just reverting to the old output format. - mp_audio_copy_config(af->prev->data, &in); - rv = filter_reinit(af->prev); - if (rv != AF_OK) - return rv; - } - if (!mp_audio_config_equals(af->prev->data, &in)) { - // Retry with conversion filter added. - char *opts[] = {"deprecation-warning", "no", NULL}; - struct af_instance *new = - af_prepend(s, af, "lavrresample", opts); - if (!new) - return AF_ERROR; - new->auto_inserted = true; - mp_audio_copy_config(new->data, &in); - rv = filter_reinit(new); - if (rv != AF_OK) - af_remove(s, new); - } - if (rv == AF_OK) - rv = filter_reinit(af); - } - - return rv; -} - -static int af_find_output_conversion(struct af_stream *s, struct mp_audio *cfg) -{ - assert(mp_audio_config_valid(&s->output)); - assert(s->initialized > 0); - - if (mp_chmap_equals_reordered(&s->input.channels, &s->output.channels)) - return AF_ERROR; - - // Heuristic to detect point of conversion. If it looks like something - // more complicated is going on, better bail out. - // We expect that the last filter converts channels. - struct af_instance *conv = s->last->prev; - if (!conv->auto_inserted) - return AF_ERROR; - if (!(mp_chmap_equals_reordered(&conv->fmt_in.channels, &s->input.channels) && - mp_chmap_equals_reordered(&conv->fmt_out.channels, &s->output.channels))) - return AF_ERROR; - // Also, should be the only one which does auto conversion. - for (struct af_instance *af = s->first->next; af != s->last; af = af->next) - { - if (af != conv && af->auto_inserted && - !mp_chmap_equals_reordered(&af->fmt_in.channels, &af->fmt_out.channels)) - return AF_ERROR; - } - // And not if it's the only filter. - if (conv->prev == s->first && conv->next == s->last) - return AF_ERROR; - - *cfg = s->output; - return AF_OK; -} - -// Return AF_OK on success or AF_ERROR on failure. -static int af_do_reinit(struct af_stream *s, bool second_pass) -{ - struct mp_audio convert_early = {0}; - if (second_pass) { - // If a channel conversion happens, and it is done by an auto-inserted - // filter, then insert a filter to convert it early. Otherwise, do - // nothing and return immediately. - if (af_find_output_conversion(s, &convert_early) != AF_OK) - return AF_OK; - } - - remove_auto_inserted_filters(s); - af_chain_forget_frames(s); - reset_formats(s); - s->first->fmt_in = s->first->fmt_out = s->input; - - if (mp_audio_config_valid(&convert_early)) { - char *opts[] = {"deprecation-warning", "no", NULL}; - struct af_instance *new = af_prepend(s, s->first, "lavrresample", opts); - if (!new) - return AF_ERROR; - new->auto_inserted = true; - mp_audio_copy_config(new->data, &convert_early); - int rv = filter_reinit(new); - if (rv != AF_DETACH && rv != AF_OK) - return AF_ERROR; - MP_VERBOSE(s, "Moving up output conversion.\n"); - } - - // Start with the second filter, as the first filter is the special input - // filter which needs no initialization. - struct af_instance *af = s->first->next; - while (af) { - int rv = filter_reinit_with_conversion(s, af); - - switch (rv) { - case AF_OK: - af = af->next; - break; - case AF_FALSE: { - // If the format conversion is (probably) caused by spdif, then - // (as a feature) drop the filter, instead of failing hard. - int fmt_in1 = af->prev->data->format; - int fmt_in2 = af->fmt_in.format; - if (af_fmt_is_valid(fmt_in1) && af_fmt_is_valid(fmt_in2)) { - bool spd1 = af_fmt_is_spdif(fmt_in1); - bool spd2 = af_fmt_is_spdif(fmt_in2); - if (spd1 != spd2 && af->next) { - MP_WARN(af, "Filter %s apparently cannot be used due to " - "spdif passthrough - removing it.\n", - af->info->name); - struct af_instance *aft = af->prev; - af_remove(s, af); - af = aft->next; - continue; - } - } - goto negotiate_error; - } - case AF_DETACH: { // Filter is redundant and wants to be unloaded - struct af_instance *aft = af->prev; // never NULL - af_remove(s, af); - af = aft->next; - break; - } - default: - MP_ERR(s, "Reinitialization did not work, " - "audio filter '%s' returned error code %i\n", - af->info->name, rv); - goto error; - } - } - - /* Set previously unset fields in s->output to those of the filter chain - * output. This is used to make the output format fixed, and even if you - * insert new filters or change the input format, the output format won't - * change. (Audio outputs generally can't change format at runtime.) */ - af_copy_unset_fields(&s->output, &s->filter_output); - if (mp_audio_config_equals(&s->output, &s->filter_output)) { - s->initialized = 1; - af_print_filter_chain(s, NULL, MSGL_V); - return AF_OK; - } - - goto error; - -negotiate_error: - MP_ERR(s, "Unable to convert audio input format to output format.\n"); -error: - s->initialized = -1; - af_print_filter_chain(s, af, MSGL_ERR); - return AF_ERROR; -} - -static int af_reinit(struct af_stream *s) -{ - int r = af_do_reinit(s, false); - if (r == AF_OK && mp_audio_config_valid(&s->output)) { - r = af_do_reinit(s, true); - if (r != AF_OK) { - MP_ERR(s, "Failed second pass filter negotiation.\n"); - r = af_do_reinit(s, false); - } - } - return r; -} - -// Uninit and remove all filters -void af_uninit(struct af_stream *s) -{ - while (s->first->next && s->first->next != s->last) - af_remove(s, s->first->next); - af_chain_forget_frames(s); - s->initialized = 0; -} - -struct af_stream *af_new(struct mpv_global *global) -{ - struct af_stream *s = talloc_zero(NULL, struct af_stream); - s->log = mp_log_new(s, global->log, "!af"); - - static const struct af_info in = { .name = "in" }; - s->first = talloc(s, struct af_instance); - *s->first = (struct af_instance) { - .full_name = "in", - .info = &in, - .log = s->log, - .control = input_control, - .filter_frame = dummy_filter, - .priv = s, - .data = &s->input, - }; - - static const struct af_info out = { .name = "out" }; - s->last = talloc(s, struct af_instance); - *s->last = (struct af_instance) { - .full_name = "out", - .info = &out, - .log = s->log, - .control = output_control, - .filter_frame = dummy_filter, - .priv = s, - .data = &s->filter_output, - }; - - s->first->next = s->last; - s->last->prev = s->first; - s->opts = global->opts; - s->global = global; - return s; -} - -void af_destroy(struct af_stream *s) -{ - af_uninit(s); - talloc_free(s); -} - -/* Initialize the stream "s". This function creates a new filter list - if necessary according to the values set in input and output. Input - and output should contain the format of the current movie and the - format of the preferred output respectively. The function is - reentrant i.e. if called with an already initialized stream the - stream will be reinitialized. - If one of the preferred output parameters is 0 the one that needs - no conversion is used (i.e. the output format in the last filter). - The return value is 0 if success and -1 if failure */ -int af_init(struct af_stream *s) -{ - // Precaution in case caller is misbehaving - mp_audio_set_null_data(&s->input); - mp_audio_set_null_data(&s->output); - - // Check if this is the first call - if (s->first->next == s->last) { - // Add all filters in the list (if there are any) - struct m_obj_settings *list = s->opts->af_settings; - for (int i = 0; list && list[i].name; i++) { - if (!list[i].enabled) - continue; - struct af_instance *af = - af_prepend(s, s->last, list[i].name, list[i].attribs); - if (!af) { - af_uninit(s); - s->initialized = -1; - return -1; - } - af->label = talloc_strdup(af, list[i].label); - } - } - - if (af_reinit(s) != AF_OK) { - // Something is stuffed audio out will not work - MP_ERR(s, "Could not create audio filter chain.\n"); - return -1; - } - return 0; -} - -/* Add filter during execution. This function adds the filter "name" - to the stream s. The filter will be inserted somewhere nice in the - list of filters. The return value is a pointer to the new filter, - If the filter couldn't be added the return value is NULL. */ -struct af_instance *af_add(struct af_stream *s, char *name, char *label, - char **args) -{ - assert(label); - - if (af_find_by_label(s, label)) - return NULL; - - struct af_instance *new = af_prepend(s, s->last, name, args); - if (!new) - return NULL; - new->label = talloc_strdup(new, label); - - // Reinitialize the filter list - if (af_reinit(s) != AF_OK) { - af_remove_by_label(s, label); - return NULL; - } - return af_find_by_label(s, label); -} - -struct af_instance *af_find_by_label(struct af_stream *s, char *label) -{ - for (struct af_instance *af = s->first; af; af = af->next) { - if (af->label && strcmp(af->label, label) == 0) - return af; - } - return NULL; -} - -/* Remove the first filter that matches this name. Return number of filters - * removed (0, 1), or a negative error code if reinit after removing failed. - */ -int af_remove_by_label(struct af_stream *s, char *label) -{ - struct af_instance *af = af_find_by_label(s, label); - if (!af) - return 0; - af_remove(s, af); - if (af_reinit(s) != AF_OK) { - af_uninit(s); - af_init(s); - return -1; - } - return 1; -} - -/* Calculate the total delay [seconds of output] caused by the filters */ -double af_calc_delay(struct af_stream *s) -{ - struct af_instance *af = s->first; - double delay = 0.0; - while (af) { - delay += af->delay; - for (int n = 0; n < af->num_out_queued; n++) - delay += af->out_queued[n]->samples / (double)af->data->rate; - af = af->next; - } - return delay; -} - -/* Send control to all filters, starting with the last until one accepts the - * command with AF_OK. Return the accepting filter. */ -struct af_instance *af_control_any_rev(struct af_stream *s, int cmd, void *arg) -{ - int res = AF_UNKNOWN; - struct af_instance *filt = s->last; - while (filt) { - res = filt->control(filt, cmd, arg); - if (res == AF_OK) - return filt; - filt = filt->prev; - } - return NULL; -} - -/* Send control to all filters. Never stop, even if a filter returns AF_OK. */ -void af_control_all(struct af_stream *s, int cmd, void *arg) -{ - for (struct af_instance *af = s->first; af; af = af->next) - af->control(af, cmd, arg); -} - -int af_control_by_label(struct af_stream *s, int cmd, void *arg, bstr label) -{ - char *label_str = bstrdup0(NULL, label); - struct af_instance *cur = af_find_by_label(s, label_str); - talloc_free(label_str); - if (cur) { - return cur->control ? cur->control(cur, cmd, arg) : CONTROL_NA; - } else { - return CONTROL_UNKNOWN; - } -} - -int af_send_command(struct af_stream *s, char *label, char *cmd, char *arg) -{ - char *args[2] = {cmd, arg}; - if (strcmp(label, "all") == 0) { - af_control_all(s, AF_CONTROL_COMMAND, args); - return 0; - } else { - return af_control_by_label(s, AF_CONTROL_COMMAND, args, bstr0(label)); - } -} - -// Used by filters to add a filtered frame to the output queue. -// Ownership of frame is transferred from caller to the filter chain. -void af_add_output_frame(struct af_instance *af, struct mp_audio *frame) -{ - if (frame) { - assert(mp_audio_config_equals(&af->fmt_out, frame)); - MP_TARRAY_APPEND(af, af->out_queued, af->num_out_queued, frame); - } -} - -static bool af_has_output_frame(struct af_instance *af) -{ - if (!af->num_out_queued && af->filter_out) { - if (af->filter_out(af) < 0) - MP_ERR(af, "Error filtering frame.\n"); - } - return af->num_out_queued > 0; -} - -static struct mp_audio *af_dequeue_output_frame(struct af_instance *af) -{ - struct mp_audio *res = NULL; - if (af_has_output_frame(af)) { - res = af->out_queued[0]; - MP_TARRAY_REMOVE_AT(af->out_queued, af->num_out_queued, 0); - } - return res; -} - -static void read_remaining(struct af_instance *af) -{ - int num_frames; - do { - num_frames = af->num_out_queued; - if (!af->filter_out || af->filter_out(af) < 0) - break; - } while (num_frames != af->num_out_queued); -} - -static int af_do_filter(struct af_instance *af, struct mp_audio *frame) -{ - if (frame) - assert(mp_audio_config_equals(&af->fmt_in, frame)); - int r = af->filter_frame(af, frame); - if (r < 0) - MP_ERR(af, "Error filtering frame.\n"); - return r; -} - -// Input a frame into the filter chain. Ownership of frame is transferred. -// Return >= 0 on success, < 0 on failure (even if output frames were produced) -int af_filter_frame(struct af_stream *s, struct mp_audio *frame) -{ - assert(frame); - if (s->initialized < 1) { - talloc_free(frame); - return -1; - } - return af_do_filter(s->first, frame); -} - -// Output the next queued frame (if any) from the full filter chain. -// The frame can be retrieved with af_read_output_frame(). -// eof: if set, assume there's no more input i.e. af_filter_frame() will -// not be called (until reset) - flush all internally delayed frames -// returns: -1: error, 0: no output, 1: output available -int af_output_frame(struct af_stream *s, bool eof) -{ - if (s->last->num_out_queued) - return 1; - if (s->initialized < 1) - return -1; - while (1) { - struct af_instance *last = NULL; - for (struct af_instance * cur = s->first; cur; cur = cur->next) { - // Flush remaining frames on EOF, but do that only if the previous - // filters have been flushed (i.e. they have no more output). - if (eof && !last) { - read_remaining(cur); - int r = af_do_filter(cur, NULL); - if (r < 0) - return r; - } - if (af_has_output_frame(cur)) - last = cur; - } - if (!last) - return 0; - if (!last->next) - return 1; - int r = af_do_filter(last->next, af_dequeue_output_frame(last)); - if (r < 0) - return r; - } -} - -struct mp_audio *af_read_output_frame(struct af_stream *s) -{ - if (!s->last->num_out_queued) - af_output_frame(s, false); - return af_dequeue_output_frame(s->last); -} - -void af_unread_output_frame(struct af_stream *s, struct mp_audio *frame) -{ - struct af_instance *af = s->last; - MP_TARRAY_INSERT_AT(af, af->out_queued, af->num_out_queued, 0, frame); -} - -// Make sure the caller can change data referenced by the frame. -// Return negative error code on failure (i.e. you can't write). -int af_make_writeable(struct af_instance *af, struct mp_audio *frame) -{ - return mp_audio_pool_make_writeable(af->out_pool, frame); -} - -void af_seek_reset(struct af_stream *s) -{ - af_control_all(s, AF_CONTROL_RESET, NULL); - af_chain_forget_frames(s); -} diff --git a/audio/filter/af.h b/audio/filter/af.h deleted file mode 100644 index 3a07a5465f..0000000000 --- a/audio/filter/af.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpv is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mpv. If not, see . - */ - -#ifndef MPLAYER_AF_H -#define MPLAYER_AF_H - -#include -#include -#include - -#include "config.h" -#if !(HAVE_LIBAF && HAVE_GPL) -#error "libaf/GPL disabled" -#endif - -#include "options/options.h" -#include "audio/format.h" -#include "audio/chmap.h" -#include "audio/audio.h" -#include "common/msg.h" -#include "common/common.h" - -struct af_instance; -struct mpv_global; - -// Number of channels -#define AF_NCH MP_NUM_CHANNELS - -// Flags for af->filter() -#define AF_FILTER_FLAG_EOF 1 - -/* Audio filter information not specific for current instance, but for - a specific filter */ -struct af_info { - const char *info; - const char *name; - int (*open)(struct af_instance *vf); - int priv_size; - const void *priv_defaults; - const struct m_option *options; - // For m_obj_desc.set_defaults - void (*set_defaults)(struct mpv_global *global, void *p); -}; - -// Linked list of audio filters -struct af_instance { - const struct af_info *info; - char *full_name; - struct mp_log *log; - struct MPOpts *opts; - struct mpv_global *global; - int (*control)(struct af_instance *af, int cmd, void *arg); - void (*uninit)(struct af_instance *af); - /* Feed a frame. The frame is NULL if EOF was reached, and the filter - * should drain all remaining buffered data. - * Use af_add_output_frame() to output data. The optional filter_out - * callback can be set to produce output frames gradually. - */ - int (*filter_frame)(struct af_instance *af, struct mp_audio *frame); - int (*filter_out)(struct af_instance *af); - void *priv; - struct mp_audio *data; // configuration and buffer for outgoing data stream - - struct af_instance *next; - struct af_instance *prev; - double delay; /* Delay caused by the filter, in seconds of audio consumed - * without corresponding output */ - bool auto_inserted; // inserted by af.c, such as conversion filters - char *label; - - struct mp_audio fmt_in, fmt_out; - - struct mp_audio **out_queued; - int num_out_queued; - - struct mp_audio_pool *out_pool; -}; - -// Current audio stream -struct af_stream { - int initialized; // 0: no, 1: yes, -1: attempted to, but failed - - // The first and last filter in the list - struct af_instance *first; - struct af_instance *last; - // The user sets the input format (what the decoder outputs), and sets some - // or all fields in output to the output format the AO accepts. - struct mp_audio input; - struct mp_audio output; - struct mp_audio filter_output; - - struct mp_log *log; - struct MPOpts *opts; - struct mpv_global *global; -}; - -// Return values -#define AF_DETACH (CONTROL_OK + 1) -#define AF_OK CONTROL_OK -#define AF_TRUE CONTROL_TRUE -#define AF_FALSE CONTROL_FALSE -#define AF_UNKNOWN CONTROL_UNKNOWN -#define AF_ERROR CONTROL_ERROR - -// Parameters for af_control_* -enum af_control { - AF_CONTROL_REINIT = 1, - AF_CONTROL_RESET, - AF_CONTROL_SET_PLAYBACK_SPEED, - AF_CONTROL_SET_PLAYBACK_SPEED_RESAMPLE, - AF_CONTROL_GET_METADATA, - AF_CONTROL_COMMAND, -}; - -// Argument for AF_CONTROL_SET_PAN_LEVEL -typedef struct af_control_ext_s { - void* arg; // Argument - int ch; // Chanel number -} af_control_ext_t; - -struct af_stream *af_new(struct mpv_global *global); -void af_destroy(struct af_stream *s); -int af_init(struct af_stream *s); -void af_uninit(struct af_stream *s); -struct af_instance *af_add(struct af_stream *s, char *name, char *label, - char **args); -int af_remove_by_label(struct af_stream *s, char *label); -struct af_instance *af_find_by_label(struct af_stream *s, char *label); -struct af_instance *af_control_any_rev(struct af_stream *s, int cmd, void *arg); -void af_control_all(struct af_stream *s, int cmd, void *arg); -int af_control_by_label(struct af_stream *s, int cmd, void *arg, bstr label); -void af_seek_reset(struct af_stream *s); -int af_send_command(struct af_stream *s, char *label, char *cmd, char *arg); - -void af_add_output_frame(struct af_instance *af, struct mp_audio *frame); -int af_filter_frame(struct af_stream *s, struct mp_audio *frame); -int af_output_frame(struct af_stream *s, bool eof); -struct mp_audio *af_read_output_frame(struct af_stream *s); -void af_unread_output_frame(struct af_stream *s, struct mp_audio *frame); -int af_make_writeable(struct af_instance *af, struct mp_audio *frame); - -double af_calc_delay(struct af_stream *s); - -int af_test_output(struct af_instance *af, struct mp_audio *out); - -int af_from_ms(int n, float *in, int *out, int rate, float mi, float ma); -float af_softclip(float a); - -#endif /* MPLAYER_AF_H */ diff --git a/audio/filter/af_format.c b/audio/filter/af_format.c index c4af9b768b..3e1eef664c 100644 --- a/audio/filter/af_format.c +++ b/audio/filter/af_format.c @@ -15,18 +15,14 @@ * License along with mpv. If not, see . */ -#include - -#include - -#include "options/m_option.h" - +#include "audio/aframe.h" #include "audio/format.h" -#include "af.h" - -struct priv { - struct m_config *config; +#include "filters/f_autoconvert.h" +#include "filters/filter_internal.h" +#include "filters/user_filters.h" +#include "options/m_option.h" +struct f_opts { int in_format; int in_srate; struct m_channels in_channels; @@ -37,98 +33,109 @@ struct priv { int fail; }; -static void force_in_params(struct af_instance *af, struct mp_audio *in) -{ - struct priv *priv = af->priv; - - if (priv->in_format != AF_FORMAT_UNKNOWN) - mp_audio_set_format(in, priv->in_format); - - if (priv->in_channels.num_chmaps > 0) - mp_audio_set_channels(in, &priv->in_channels.chmaps[0]); - - if (priv->in_srate) - in->rate = priv->in_srate; -} +struct priv { + struct f_opts *opts; + struct mp_pin *in_pin; +}; -static void force_out_params(struct af_instance *af, struct mp_audio *out) +static void process(struct mp_filter *f) { - struct priv *priv = af->priv; + struct priv *p = f->priv; - if (priv->out_format != AF_FORMAT_UNKNOWN) - mp_audio_set_format(out, priv->out_format); + if (!mp_pin_can_transfer_data(f->ppins[1], p->in_pin)) + return; - if (priv->out_channels.num_chmaps > 0) - mp_audio_set_channels(out, &priv->out_channels.chmaps[0]); + struct mp_frame frame = mp_pin_out_read(p->in_pin); - if (priv->out_srate) - out->rate = priv->out_srate; -} + if (p->opts->fail) { + MP_ERR(f, "Failing on purpose.\n"); + goto error; + } -static int control(struct af_instance *af, int cmd, void *arg) -{ - struct priv *priv = af->priv; + if (frame.type == MP_FRAME_EOF) { + mp_pin_in_write(f->ppins[1], frame); + return; + } - switch (cmd) { - case AF_CONTROL_REINIT: { - struct mp_audio *in = arg; - struct mp_audio orig_in = *in; - struct mp_audio *out = af->data; + if (frame.type != MP_FRAME_AUDIO) { + MP_ERR(f, "audio frame expected\n"); + goto error; + } - force_in_params(af, in); - mp_audio_copy_config(out, in); - force_out_params(af, out); + struct mp_aframe *in = frame.data; - if (in->nch != out->nch || in->bps != out->bps) { - MP_ERR(af, "Forced input/output formats are incompatible.\n"); - return AF_ERROR; + if (p->opts->out_channels.num_chmaps > 0) { + if (!mp_aframe_set_chmap(in, &p->opts->out_channels.chmaps[0])) { + MP_ERR(f, "could not force output channels\n"); + goto error; } + } - if (priv->fail) { - MP_ERR(af, "Failing on purpose.\n"); - return AF_ERROR; - } + if (p->opts->out_srate) + mp_aframe_set_rate(in, p->opts->out_srate); - return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE; - } - } - return AF_UNKNOWN; -} + mp_pin_in_write(f->ppins[1], frame); + return; -static int filter(struct af_instance *af, struct mp_audio *data) -{ - if (data) - mp_audio_copy_config(data, af->data); - af_add_output_frame(af, data); - return 0; +error: + mp_frame_unref(&frame); + mp_filter_internal_mark_failed(f); } -static int af_open(struct af_instance *af) +static const struct mp_filter_info af_format_filter = { + .name = "format", + .priv_size = sizeof(struct priv), + .process = process, +}; + +static struct mp_filter *af_format_create(struct mp_filter *parent, + void *options) { - af->control = control; - af->filter_frame = filter; + struct mp_filter *f = mp_filter_create(parent, &af_format_filter); + if (!f) { + talloc_free(options); + return NULL; + } - force_in_params(af, af->data); - force_out_params(af, af->data); + struct priv *p = f->priv; + p->opts = talloc_steal(p, options); - return AF_OK; -} + mp_filter_add_pin(f, MP_PIN_IN, "in"); + mp_filter_add_pin(f, MP_PIN_OUT, "out"); -#define OPT_BASE_STRUCT struct priv + struct mp_autoconvert *conv = mp_autoconvert_create(f); + if (!conv) + abort(); -const struct af_info af_info_format = { - .info = "Force audio format", - .name = "format", - .open = af_open, - .priv_size = sizeof(struct priv), - .options = (const struct m_option[]) { - OPT_AUDIOFORMAT("format", in_format, 0), - OPT_INTRANGE("srate", in_srate, 0, 1000, 8*48000), - OPT_CHANNELS("channels", in_channels, 0, .min = 1), - OPT_AUDIOFORMAT("out-format", out_format, 0), - OPT_INTRANGE("out-srate", out_srate, 0, 1000, 8*48000), - OPT_CHANNELS("out-channels", out_channels, 0, .min = 1), - OPT_FLAG("fail", fail, 0), - {0} + if (p->opts->in_format) + mp_autoconvert_add_afmt(conv, p->opts->in_format); + if (p->opts->in_srate) + mp_autoconvert_add_srate(conv, p->opts->in_srate); + if (p->opts->in_channels.num_chmaps > 0) + mp_autoconvert_add_chmap(conv, &p->opts->in_channels.chmaps[0]); + + mp_pin_connect(conv->f->pins[0], f->ppins[0]); + p->in_pin = conv->f->pins[1]; + + return f; +} + +#define OPT_BASE_STRUCT struct f_opts + +const struct mp_user_filter_entry af_format = { + .desc = { + .name = "format", + .description = "Force audio format", + .priv_size = sizeof(struct f_opts), + .options = (const struct m_option[]) { + OPT_AUDIOFORMAT("format", in_format, 0), + OPT_INTRANGE("srate", in_srate, 0, 1000, 8*48000), + OPT_CHANNELS("channels", in_channels, 0, .min = 1), + OPT_INTRANGE("out-srate", out_srate, 0, 1000, 8*48000), + OPT_CHANNELS("out-channels", out_channels, 0, .min = 1), + OPT_FLAG("fail", fail, 0), + {0} + }, }, + .create = af_format_create, }; diff --git a/audio/filter/af_lavcac3enc.c b/audio/filter/af_lavcac3enc.c index 14aa53b980..c7582cf52b 100644 --- a/audio/filter/af_lavcac3enc.c +++ b/audio/filter/af_lavcac3enc.c @@ -31,14 +31,17 @@ #include #include -#include "config.h" - -#include "common/av_common.h" -#include "common/common.h" -#include "af.h" -#include "audio/audio_buffer.h" +#include "audio/aframe.h" #include "audio/chmap_sel.h" #include "audio/fmt-conversion.h" +#include "audio/format.h" +#include "common/av_common.h" +#include "common/common.h" +#include "filters/f_autoconvert.h" +#include "filters/f_utils.h" +#include "filters/filter_internal.h" +#include "filters/user_filters.h" +#include "options/m_option.h" #define AC3_MAX_CHANNELS 6 @@ -49,173 +52,89 @@ const uint16_t ac3_bitrate_tab[19] = { 160, 192, 224, 256, 320, 384, 448, 512, 576, 640 }; -// Data for specific instances of this filter -typedef struct af_ac3enc_s { +struct f_opts { + int add_iec61937_header; + int bit_rate; + int min_channel_num; + char *encoder; + char **avopts; +}; + +struct priv { + struct f_opts *opts; + + struct mp_pin *in_pin; + struct mp_aframe *cur_format; + struct mp_aframe *in_frame; + struct mp_aframe_pool *out_pool; + struct AVCodec *lavc_acodec; struct AVCodecContext *lavc_actx; int bit_rate; - struct mp_audio *input; // frame passed to libavcodec - struct mp_audio *pending; // unconsumed input data - int in_samples; // samples of input per AC3 frame int out_samples; // upper bound on encoded output per AC3 frame - int64_t encoder_buffered; - - int cfg_add_iec61937_header; - int cfg_bit_rate; - int cfg_min_channel_num; - char *cfg_encoder; - char **cfg_avopts; -} af_ac3enc_t; - -// fmt carries the input format. Change it to the best next-possible format -// the encoder likely accepts. -static void select_encode_format(AVCodecContext *c, struct mp_audio *fmt) -{ - int formats[AF_FORMAT_COUNT]; - af_get_best_sample_formats(fmt->format, formats); - - for (int n = 0; formats[n]; n++) { - const enum AVSampleFormat *lf = c->codec->sample_fmts; - for (int i = 0; lf && lf[i] != AV_SAMPLE_FMT_NONE; i++) { - int mpfmt = af_from_avformat(lf[i]); - if (mpfmt && mpfmt == formats[n]) { - mp_audio_set_format(fmt, mpfmt); - goto done_fmt; - } - } - } -done_fmt: ; +}; - int rate = - af_select_best_samplerate(fmt->rate, c->codec->supported_samplerates); - if (rate > 0) - fmt->rate = rate; +static bool reinit(struct mp_filter *f) +{ + struct priv *s = f->priv; - struct mp_chmap_sel sel = {0}; - const uint64_t *lch = c->codec->channel_layouts; - for (int n = 0; lch && lch[n]; n++) { - struct mp_chmap chmap = {0}; - mp_chmap_from_lavc(&chmap, lch[n]); - mp_chmap_sel_add_map(&sel, &chmap); - } - struct mp_chmap res = fmt->channels; - mp_chmap_sel_adjust(&sel, &res); - if (!mp_chmap_is_empty(&res)) - mp_audio_set_channels(fmt, &res); -} + mp_aframe_reset(s->cur_format); -// Initialization and runtime control -static int control(struct af_instance *af, int cmd, void *arg) -{ - af_ac3enc_t *s = af->priv; static const int default_bit_rate[AC3_MAX_CHANNELS+1] = \ {0, 96000, 192000, 256000, 384000, 448000, 448000}; - switch (cmd){ - case AF_CONTROL_REINIT: { - struct mp_audio *in = arg; - struct mp_audio orig_in = *in; - - if (!af_fmt_is_pcm(in->format) || in->nch < s->cfg_min_channel_num) - return AF_DETACH; - - // At least currently, the AC3 encoder doesn't export sample rates. - in->rate = 48000; - select_encode_format(s->lavc_actx, in); - - af->data->rate = in->rate; - mp_audio_set_format(af->data, AF_FORMAT_S_AC3); - mp_audio_set_num_channels(af->data, 2); - - if (!mp_audio_config_equals(in, &orig_in)) - return AF_FALSE; - - if (s->cfg_add_iec61937_header) { - s->out_samples = AC3_FRAME_SIZE; - } else { - s->out_samples = AC3_MAX_CODED_FRAME_SIZE / af->data->sstride; - } - - mp_audio_copy_config(s->input, in); - - talloc_free(s->pending); - s->pending = NULL; - - MP_DBG(af, "reinit: %d, %d, %d.\n", in->nch, in->rate, s->in_samples); + if (s->opts->add_iec61937_header) { + s->out_samples = AC3_FRAME_SIZE; + } else { + s->out_samples = AC3_MAX_CODED_FRAME_SIZE / + mp_aframe_get_sstride(s->in_frame); + } - int bit_rate = s->bit_rate ? s->bit_rate : default_bit_rate[in->nch]; + int format = mp_aframe_get_format(s->in_frame); + int rate = mp_aframe_get_rate(s->in_frame); + struct mp_chmap chmap = {0}; + mp_aframe_get_chmap(s->in_frame, &chmap); - if (s->lavc_actx->channels != in->nch || - s->lavc_actx->sample_rate != in->rate || - s->lavc_actx->bit_rate != bit_rate) - { - avcodec_close(s->lavc_actx); + int bit_rate = s->bit_rate; + if (!bit_rate && chmap.num < AC3_MAX_CHANNELS + 1) + bit_rate = default_bit_rate[chmap.num]; - // Put sample parameters - s->lavc_actx->sample_fmt = af_to_avformat(in->format); - s->lavc_actx->channels = in->nch; - s->lavc_actx->channel_layout = mp_chmap_to_lavc(&in->channels); - s->lavc_actx->sample_rate = in->rate; - s->lavc_actx->bit_rate = bit_rate; + avcodec_close(s->lavc_actx); - if (avcodec_open2(s->lavc_actx, s->lavc_acodec, NULL) < 0) { - MP_ERR(af, "Couldn't open codec %s, br=%d.\n", "ac3", bit_rate); - return AF_ERROR; - } + // Put sample parameters + s->lavc_actx->sample_fmt = af_to_avformat(format); + s->lavc_actx->channels = chmap.num; + s->lavc_actx->channel_layout = mp_chmap_to_lavc(&chmap); + s->lavc_actx->sample_rate = rate; + s->lavc_actx->bit_rate = bit_rate; - if (s->lavc_actx->frame_size < 1) { - MP_ERR(af, "encoder didn't specify input frame size\n"); - return AF_ERROR; - } - } - s->in_samples = s->lavc_actx->frame_size; - mp_audio_realloc(s->input, s->in_samples); - s->input->samples = 0; - s->encoder_buffered = 0; - return AF_OK; + if (avcodec_open2(s->lavc_actx, s->lavc_acodec, NULL) < 0) { + MP_ERR(f, "Couldn't open codec %s, br=%d.\n", "ac3", bit_rate); + return false; } - case AF_CONTROL_RESET: - if (avcodec_is_open(s->lavc_actx)) - avcodec_flush_buffers(s->lavc_actx); - talloc_free(s->pending); - s->pending = NULL; - s->input->samples = 0; - s->encoder_buffered = 0; - return AF_OK; - } - return AF_UNKNOWN; -} - -// Deallocate memory -static void uninit(struct af_instance* af) -{ - af_ac3enc_t *s = af->priv; - if (s) { - avcodec_free_context(&s->lavc_actx); - talloc_free(s->pending); + if (s->lavc_actx->frame_size < 1) { + MP_ERR(f, "encoder didn't specify input frame size\n"); + return false; } + + mp_aframe_config_copy(s->cur_format, s->in_frame); + return true; } -static void update_delay(struct af_instance *af) +static void reset(struct mp_filter *f) { - af_ac3enc_t *s = af->priv; - af->delay = ((s->pending ? s->pending->samples : 0) + s->input->samples + - s->encoder_buffered) / (double)s->input->rate; + struct priv *s = f->priv; + + TA_FREEP(&s->in_frame); } -static int filter_frame(struct af_instance *af, struct mp_audio *audio) +static void destroy(struct mp_filter *f) { - af_ac3enc_t *s = af->priv; + struct priv *s = f->priv; - // filter_output must have been called until no output was produced. - if (s->pending && s->pending->samples) - MP_ERR(af, "broken data flow\n"); - - talloc_free(s->pending); - s->pending = audio; - update_delay(af); - return 0; + reset(f); + avcodec_free_context(&s->lavc_actx); } static void swap_16(uint16_t *ptr, size_t size) @@ -224,105 +143,84 @@ static void swap_16(uint16_t *ptr, size_t size) ptr[n] = av_bswap16(ptr[n]); } -// Copy data from input frame to encode frame (because libavcodec wants a full -// AC3 frame for encoding, while filter input frames can be smaller or larger). -// Return true if the frame is complete. -static bool fill_buffer(struct af_instance *af) -{ - af_ac3enc_t *s = af->priv; - - af->delay = 0; - - if (s->pending) { - if (!mp_audio_is_writeable(s->input)) - assert(s->input->samples == 0); // we can't have sent a partial frame - mp_audio_realloc_min(s->input, s->in_samples); - int copy = MPMIN(s->in_samples - s->input->samples, s->pending->samples); - s->input->samples += copy; - mp_audio_copy(s->input, s->input->samples - copy, s->pending, 0, copy); - mp_audio_skip_samples(s->pending, copy); - } - update_delay(af); - return s->input->samples >= s->in_samples; -} - -// Return <0 on error, 0 on need more input, 1 on success (and *frame set). -// To actually advance the read pointer, set s->input->samples=0 afterwards. -static int read_input_frame(struct af_instance *af, AVFrame *frame) +static void process(struct mp_filter *f) { - af_ac3enc_t *s = af->priv; - if (!fill_buffer(af)) - return 0; // need more input + struct priv *s = f->priv; - if (mp_audio_to_avframe(s->input, frame) < 0) - return -1; - - return 1; -} - -static int filter_out(struct af_instance *af) -{ - af_ac3enc_t *s = af->priv; - - if (!s->pending) - return 0; - - AVFrame *frame = av_frame_alloc(); - if (!frame) { - MP_FATAL(af, "Could not allocate memory \n"); - return -1; - } - int err = -1; + if (!mp_pin_in_needs_data(f->ppins[1])) + return; + bool err = true; + struct mp_aframe *out = NULL; AVPacket pkt = {0}; av_init_packet(&pkt); // Send input as long as it wants. while (1) { - err = read_input_frame(af, frame); - if (err < 0) + if (avcodec_is_open(s->lavc_actx)) { + int lavc_ret = avcodec_receive_packet(s->lavc_actx, &pkt); + if (lavc_ret >= 0) + break; + if (lavc_ret < 0 && lavc_ret != AVERROR(EAGAIN)) { + MP_FATAL(f, "Encode failed (receive).\n"); + goto done; + } + } + AVFrame *frame = NULL; + struct mp_frame input = mp_pin_out_read(s->in_pin); + // The following code assumes no sample data buffering in the encoder. + if (input.type == MP_FRAME_EOF) { + mp_pin_in_write(f->ppins[1], input); + return; + } else if (input.type == MP_FRAME_AUDIO) { + TA_FREEP(&s->in_frame); + s->in_frame = input.data; + frame = mp_frame_to_av(input, NULL); + if (!frame) + goto done; + if (mp_aframe_get_channels(s->in_frame) < s->opts->min_channel_num) { + // Just pass it through. + s->in_frame = NULL; + mp_pin_in_write(f->ppins[1], input); + return; + } + if (!mp_aframe_config_equals(s->in_frame, s->cur_format)) { + if (!reinit(f)) + goto done; + } + } else if (input.type) { goto done; - if (err == 0) - break; - err = -1; + } else { + return; // no data yet + } int lavc_ret = avcodec_send_frame(s->lavc_actx, frame); - // On EAGAIN, we're supposed to read remaining output. - if (lavc_ret == AVERROR(EAGAIN)) - break; - if (lavc_ret < 0) { - MP_FATAL(af, "Encode failed.\n"); + av_frame_free(&frame); + if (lavc_ret < 0 && lavc_ret != AVERROR(EAGAIN)) { + MP_FATAL(f, "Encode failed (send).\n"); goto done; } - s->encoder_buffered += s->input->samples; - s->input->samples = 0; - } - int lavc_ret = avcodec_receive_packet(s->lavc_actx, &pkt); - if (lavc_ret == AVERROR(EAGAIN)) { - // Need to buffer more input. - err = 0; - goto done; - } - if (lavc_ret < 0) { - MP_FATAL(af, "Encode failed.\n"); - goto done; } - MP_DBG(af, "avcodec_encode_audio got %d, pending %d.\n", - pkt.size, s->pending->samples + s->input->samples); + if (!s->in_frame) + goto done; - s->encoder_buffered -= AC3_FRAME_SIZE; + out = mp_aframe_create(); + mp_aframe_set_format(out, AF_FORMAT_S_AC3); + mp_aframe_set_chmap(out, &(struct mp_chmap)MP_CHMAP_INIT_STEREO); + mp_aframe_set_rate(out, 48000); - struct mp_audio *out = - mp_audio_pool_get(af->out_pool, af->data, s->out_samples); - if (!out) + if (mp_aframe_pool_allocate(s->out_pool, out, s->out_samples) < 0) goto done; - mp_audio_copy_attributes(out, s->pending); + + int sstride = mp_aframe_get_sstride(out); + + mp_aframe_copy_attributes(out, s->in_frame); int frame_size = pkt.size; int header_len = 0; char hdr[8]; - if (s->cfg_add_iec61937_header && pkt.size > 5) { + if (s->opts->add_iec61937_header && pkt.size > 5) { int bsmod = pkt.data[5] & 0x7; int len = frame_size; @@ -336,48 +234,69 @@ static int filter_out(struct af_instance *af) AV_WL16(hdr + 6, len << 3); // number of bits in payload } - if (frame_size > out->samples * out->sstride) + if (frame_size > s->out_samples * sstride) abort(); - char *buf = (char *)out->planes[0]; + uint8_t **planes = mp_aframe_get_data_rw(out); + if (!planes) + goto done; + char *buf = planes[0]; memcpy(buf, hdr, header_len); memcpy(buf + header_len, pkt.data, pkt.size); memset(buf + header_len + pkt.size, 0, frame_size - (header_len + pkt.size)); swap_16((uint16_t *)(buf + header_len), pkt.size / 2); - out->samples = frame_size / out->sstride; - af_add_output_frame(af, out); + mp_aframe_set_size(out, frame_size / sstride); + mp_pin_in_write(f->ppins[1], MAKE_FRAME(MP_FRAME_AUDIO, out)); + out = NULL; err = 0; done: av_packet_unref(&pkt); - av_frame_free(&frame); - update_delay(af); - return err; + talloc_free(out); + if (err) + mp_filter_internal_mark_failed(f); } -static int af_open(struct af_instance* af){ +static const struct mp_filter_info af_lavcac3enc_filter = { + .name = "lavcac3enc", + .priv_size = sizeof(struct priv), + .process = process, + .reset = reset, + .destroy = destroy, +}; - af_ac3enc_t *s = af->priv; - af->control=control; - af->uninit=uninit; - af->filter_frame = filter_frame; - af->filter_out = filter_out; +static struct mp_filter *af_lavcac3enc_create(struct mp_filter *parent, + void *options) +{ + struct mp_filter *f = mp_filter_create(parent, &af_lavcac3enc_filter); + if (!f) { + talloc_free(options); + return NULL; + } + + mp_filter_add_pin(f, MP_PIN_IN, "in"); + mp_filter_add_pin(f, MP_PIN_OUT, "out"); - s->lavc_acodec = avcodec_find_encoder_by_name(s->cfg_encoder); + struct priv *s = f->priv; + s->opts = talloc_steal(s, options); + s->cur_format = talloc_steal(s, mp_aframe_create()); + s->out_pool = mp_aframe_pool_create(s); + + s->lavc_acodec = avcodec_find_encoder_by_name(s->opts->encoder); if (!s->lavc_acodec) { - MP_ERR(af, "Couldn't find encoder %s.\n", s->cfg_encoder); - return AF_ERROR; + MP_ERR(f, "Couldn't find encoder %s.\n", s->opts->encoder); + goto error; } s->lavc_actx = avcodec_alloc_context3(s->lavc_acodec); if (!s->lavc_actx) { - MP_ERR(af, "Audio LAVC, couldn't allocate context!\n"); - return AF_ERROR; + MP_ERR(f, "Audio LAVC, couldn't allocate context!\n"); + goto error; } - if (mp_set_avopts(af->log, s->lavc_actx, s->cfg_avopts) < 0) - return AF_ERROR; + if (mp_set_avopts(f->log, s->lavc_actx, s->opts->avopts) < 0) + goto error; // For this one, we require the decoder to expert lists of all supported // parameters. (Not all decoders do that, but the ones we're interested @@ -385,50 +304,85 @@ static int af_open(struct af_instance* af){ if (!s->lavc_acodec->sample_fmts || !s->lavc_acodec->channel_layouts) { - MP_ERR(af, "Audio encoder doesn't list supported parameters.\n"); - return AF_ERROR; + MP_ERR(f, "Audio encoder doesn't list supported parameters.\n"); + goto error; } - s->input = talloc_zero(s, struct mp_audio); - - if (s->cfg_bit_rate) { + if (s->opts->bit_rate) { int i; for (i = 0; i < 19; i++) { - if (ac3_bitrate_tab[i] == s->cfg_bit_rate) { + if (ac3_bitrate_tab[i] == s->opts->bit_rate) { s->bit_rate = ac3_bitrate_tab[i] * 1000; break; } } if (i >= 19) { - MP_WARN(af, "unable set unsupported bitrate %d, using default " + MP_WARN(f, "unable set unsupported bitrate %d, using default " "bitrate (check manpage to see supported bitrates).\n", - s->cfg_bit_rate); + s->opts->bit_rate); } } - return AF_OK; -} + struct mp_autoconvert *conv = mp_autoconvert_create(f); + if (!conv) + abort(); -#define OPT_BASE_STRUCT struct af_ac3enc_s + const enum AVSampleFormat *lf = s->lavc_acodec->sample_fmts; + for (int i = 0; lf && lf[i] != AV_SAMPLE_FMT_NONE; i++) { + int mpfmt = af_from_avformat(lf[i]); + if (mpfmt) + mp_autoconvert_add_afmt(conv, mpfmt); + } -const struct af_info af_info_lavcac3enc = { - .info = "runtime encode to ac3 using libavcodec", - .name = "lavcac3enc", - .open = af_open, - .priv_size = sizeof(struct af_ac3enc_s), - .priv_defaults = &(const struct af_ac3enc_s){ - .cfg_add_iec61937_header = 1, - .cfg_bit_rate = 640, - .cfg_min_channel_num = 3, - .cfg_encoder = "ac3", - }, - .options = (const struct m_option[]) { - OPT_FLAG("tospdif", cfg_add_iec61937_header, 0), - OPT_CHOICE_OR_INT("bitrate", cfg_bit_rate, 0, 32, 640, - ({"auto", 0}, {"default", 0})), - OPT_INTRANGE("minch", cfg_min_channel_num, 0, 2, 6), - OPT_STRING("encoder", cfg_encoder, 0), - OPT_KEYVALUELIST("o", cfg_avopts, 0), - {0} + const uint64_t *lch = s->lavc_acodec->channel_layouts; + for (int n = 0; lch && lch[n]; n++) { + struct mp_chmap chmap = {0}; + mp_chmap_from_lavc(&chmap, lch[n]); + if (mp_chmap_is_valid(&chmap)) + mp_autoconvert_add_chmap(conv, &chmap); + } + + // At least currently, the AC3 encoder doesn't export sample rates. + mp_autoconvert_add_srate(conv, 48000); + + mp_pin_connect(conv->f->pins[0], f->ppins[0]); + + struct mp_filter *fs = mp_fixed_aframe_size_create(f, AC3_FRAME_SIZE, true); + if (!fs) + abort(); + + mp_pin_connect(fs->pins[0], conv->f->pins[1]); + s->in_pin = fs->pins[1]; + + return f; + +error: + talloc_free(f); + return NULL; +} + +#define OPT_BASE_STRUCT struct f_opts + +const struct mp_user_filter_entry af_lavcac3enc = { + .desc = { + .description = "runtime encode to ac3 using libavcodec", + .name = "lavcac3enc", + .priv_size = sizeof(OPT_BASE_STRUCT), + .priv_defaults = &(const OPT_BASE_STRUCT) { + .add_iec61937_header = 1, + .bit_rate = 640, + .min_channel_num = 3, + .encoder = "ac3", + }, + .options = (const struct m_option[]) { + OPT_FLAG("tospdif", add_iec61937_header, 0), + OPT_CHOICE_OR_INT("bitrate", bit_rate, 0, 32, 640, + ({"auto", 0}, {"default", 0})), + OPT_INTRANGE("minch", min_channel_num, 0, 2, 6), + OPT_STRING("encoder", encoder, 0), + OPT_KEYVALUELIST("o", avopts, 0), + {0} + }, }, + .create = af_lavcac3enc_create, }; diff --git a/audio/filter/af_lavfi.c b/audio/filter/af_lavfi.c deleted file mode 100644 index ab8a026de7..0000000000 --- a/audio/filter/af_lavfi.c +++ /dev/null @@ -1,413 +0,0 @@ -/* - * This file is part of mpv. - * - * Filter graph creation code taken from FFmpeg ffplay.c (LGPL 2.1 or later) - * - * mpv is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * mpv is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with mpv. If not, see . - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" - -#include "audio/format.h" -#include "audio/fmt-conversion.h" -#include "af.h" - -#include "common/av_common.h" -#include "common/tags.h" - -#include "options/m_option.h" - -// FFmpeg and Libav have slightly different APIs, just enough to cause us -// unnecessary pain. -#if LIBAVFILTER_VERSION_MICRO < 100 -#define graph_parse(graph, filters, inputs, outputs, log_ctx) \ - avfilter_graph_parse(graph, filters, inputs, outputs, log_ctx) -#define avfilter_graph_send_command(a, b, c, d, e, f, g) -1 -#else -#define graph_parse(graph, filters, inputs, outputs, log_ctx) \ - avfilter_graph_parse_ptr(graph, filters, &(inputs), &(outputs), log_ctx) -#endif - -struct priv { - // Single filter bridge, instead of a graph. - bool is_bridge; - - AVFilterGraph *graph; - AVFilterContext *in; - AVFilterContext *out; - - int64_t samples_in; - - AVRational timebase_out; - - bool eof; - - struct mp_tags *metadata; - - // options - char *cfg_graph; - char **cfg_avopts; - char *cfg_filter_name; - char **cfg_filter_opts; -}; - -static void destroy_graph(struct af_instance *af) -{ - struct priv *p = af->priv; - avfilter_graph_free(&p->graph); - p->in = p->out = NULL; - p->samples_in = 0; - p->eof = false; -} - -static bool recreate_graph(struct af_instance *af, struct mp_audio *config) -{ - void *tmp = talloc_new(NULL); - struct priv *p = af->priv; - AVFilterContext *in = NULL, *out = NULL; - bool ok = false; - - if (!p->is_bridge && bstr0(p->cfg_graph).len == 0) { - MP_FATAL(af, "lavfi: no filter graph set\n"); - return false; - } - - destroy_graph(af); - - AVFilterGraph *graph = avfilter_graph_alloc(); - if (!graph) - goto error; - - if (mp_set_avopts(af->log, graph, p->cfg_avopts) < 0) - goto error; - - AVFilterInOut *outputs = avfilter_inout_alloc(); - AVFilterInOut *inputs = avfilter_inout_alloc(); - if (!outputs || !inputs) - goto error; - - char *src_args = talloc_asprintf(tmp, - "sample_rate=%d:sample_fmt=%s:time_base=%d/%d:" - "channel_layout=0x%"PRIx64, config->rate, - av_get_sample_fmt_name(af_to_avformat(config->format)), - 1, config->rate, mp_chmap_to_lavc(&config->channels)); - - if (avfilter_graph_create_filter(&in, avfilter_get_by_name("abuffer"), - "src", src_args, NULL, graph) < 0) - goto error; - - if (avfilter_graph_create_filter(&out, avfilter_get_by_name("abuffersink"), - "out", NULL, NULL, graph) < 0) - goto error; - - if (p->is_bridge) { - AVFilterContext *filter = avfilter_graph_alloc_filter(graph, - avfilter_get_by_name(p->cfg_filter_name), "filter"); - if (!filter) - goto error; - - if (mp_set_avopts(af->log, filter->priv, p->cfg_filter_opts) < 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) - { -