summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2017-03-19 12:12:19 +0100
committerwm4 <wm4@nowhere>2017-03-19 12:12:19 +0100
commit202f1201d9510939f078d67bbf009f84bd2dc8c5 (patch)
treec6a45a29bf4acff5e1c180ab5f8ad5c1bce5032c
parent84bf6aabf00466826d45737055eb5ea0dec05fb6 (diff)
downloadmpv-remove-libaf.tar.bz2
mpv-remove-libaf.tar.xz
remove libafremove-libaf
audio/filter/* was basically moved from libaf. Remove it because it can't be relicensed to LGPL. For now there is some "emergency" code which uses libswresample to do the minimally needed conversion of audio data for AOs. Keeping: - struct mp_audio (used to be struct af_data_s) - audio/format.h/c, which includes things like AF_FORMAT_S16 (although these are enums mirroring e.g. AV_SAMPLE_FMT_S16) - some helpers in audio/format.h, e.g. af_fmt2str_short which is now af_fmt_to_str - libao2 (in audio/out/)
-rw-r--r--audio/decode/dec_audio.c3
-rw-r--r--audio/filter/af.c799
-rw-r--r--audio/filter/af.h161
-rw-r--r--audio/filter/af_channels.c253
-rw-r--r--audio/filter/af_drc.c334
-rw-r--r--audio/filter/af_equalizer.c214
-rw-r--r--audio/filter/af_format.c134
-rw-r--r--audio/filter/af_lavcac3enc.c437
-rw-r--r--audio/filter/af_lavfi.c369
-rw-r--r--audio/filter/af_lavrresample.c617
-rw-r--r--audio/filter/af_pan.c205
-rw-r--r--audio/filter/af_rubberband.c251
-rw-r--r--audio/filter/af_scaletempo.c494
-rw-r--r--audio/filter/af_volume.c189
-rw-r--r--audio/filter/equalizer.h47
-rw-r--r--audio/filter/tools.c72
-rw-r--r--audio/format.c2
-rw-r--r--options/options.c5
-rw-r--r--player/audio.c154
-rw-r--r--player/command.c13
-rw-r--r--player/core.h6
-rw-r--r--player/playloop.c1
-rw-r--r--player/video.c1
-rw-r--r--wscript_build.py13
24 files changed, 109 insertions, 4665 deletions
diff --git a/audio/decode/dec_audio.c b/audio/decode/dec_audio.c
index fce9ef94e0..7283c9dcfd 100644
--- a/audio/decode/dec_audio.c
+++ b/audio/decode/dec_audio.c
@@ -40,8 +40,7 @@
#include "audio/format.h"
#include "audio/audio.h"
#include "audio/audio_buffer.h"
-
-#include "audio/filter/af.h"
+#include "options/options.h"
extern const struct ad_functions ad_lavc;
diff --git a/audio/filter/af.c b/audio/filter/af.c
deleted file mode 100644
index e6f19b3e37..0000000000
--- a/audio/filter/af.c
+++ /dev/null
@@ -1,799 +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 <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-#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_channels;
-extern const struct af_info af_info_format;
-extern const struct af_info af_info_volume;
-extern const struct af_info af_info_equalizer;
-extern const struct af_info af_info_pan;
-extern const struct af_info af_info_drc;
-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_bs2b;
-extern const struct af_info af_info_lavfi;
-extern const struct af_info af_info_rubberband;
-
-static const struct af_info *const filter_list[] = {
- &af_info_channels,
- &af_info_format,
- &af_info_volume,
- &af_info_equalizer,
- &af_info_pan,
- &af_info_drc,
- &af_info_lavcac3enc,
- &af_info_lavrresample,
-#if HAVE_RUBBERBAND
- &af_info_rubberband,
-#endif
- &af_info_scaletempo,
- &af_info_lavfi,
- 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,
- .p = af,
- };
- return true;
-}
-
-const struct m_obj_list af_obj_list = {
- .get_desc = get_desc,
- .description = "audio filters",
- .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)
-{
- 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;
- }
- MP_VERBOSE(s, "Adding filter %s \n", name);
-
- struct af_instance *af = talloc_zero(NULL, struct af_instance);
- *af = (struct af_instance) {
- .info = desc.p,
- .data = talloc_zero(af, struct mp_audio),
- .log = mp_log_new(af, s->log, name),
- .opts = s->opts,
- .replaygain_data = s->replaygain_data,
- .out_pool = mp_audio_pool_create(af),
- };
- struct m_config *config =
- m_config_from_obj_desc_and_args(af, s->log, NULL, &desc,
- name, s->opts->af_defs, args);
- if (!config)
- goto error;
- 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->info->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.
- struct af_instance *new =
- af_prepend(s, af, "lavrresample", NULL);
- 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)) {
- struct af_instance *new = af_prepend(s, s->first, "lavrresample", NULL);
- 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) {
- .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) {
- .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;
- 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++) {
- 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 a773f561b3..0000000000
--- a/audio/filter/af.h
+++ /dev/null
@@ -1,161 +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 <http://www.gnu.org/licenses/>.
- */
-
-#ifndef MPLAYER_AF_H
-#define MPLAYER_AF_H
-
-#include <stdio.h>
-#include <stdbool.h>
-#include <sys/types.h>
-
-#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;
-};
-
-// Linked list of audio filters
-struct af_instance {
- const struct af_info *info;
- struct mp_log *log;
- struct MPOpts *opts;
- struct replaygain_data *replaygain_data;
- 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 replaygain_data *replaygain_data;
-};
-
-// 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_VOLUME,
- AF_CONTROL_GET_VOLUME,
- AF_CONTROL_SET_PAN_LEVEL,
- AF_CONTROL_SET_PAN_NOUT,
- AF_CONTROL_SET_PAN_BALANCE,
- AF_CONTROL_GET_PAN_BALANCE,
- 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_channels.c b/audio/filter/af_channels.c
deleted file mode 100644
index 57fe4874ef..0000000000
--- a/audio/filter/af_channels.c
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Audio filter that adds and removes channels, according to the
- * command line parameter channels. It is stupid and can only add
- * silence or copy channels, not mix or filter.
- *
- * Original author: Anders
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <inttypes.h>
-
-#include "common/common.h"
-#include "af.h"
-
-#define FR 0
-#define TO 1
-
-typedef struct af_channels_s{
- int route[AF_NCH][2];
- int nch, nr;
- int router;
- char *routes;
-}af_channels_t;
-
-// Local function for copying data
-static void copy(struct af_instance *af, void* in, void* out,
- int ins, int inos,int outs, int outos, int len, int bps)
-{
- switch(bps){
- case 1:{
- int8_t* tin = (int8_t*)in;
- int8_t* tout = (int8_t*)out;
- tin += inos;
- tout += outos;
- len = len/ins;
- while(len--){
- *tout=*tin;
- tin +=ins;
- tout+=outs;
- }
- break;
- }
- case 2:{
- int16_t* tin = (int16_t*)in;
- int16_t* tout = (int16_t*)out;
- tin += inos;
- tout += outos;
- len = len/(2*ins);
- while(len--){
- *tout=*tin;
- tin +=ins;
- tout+=outs;
- }
- break;
- }
- case 3:{
- int8_t* tin = (int8_t*)in;
- int8_t* tout = (int8_t*)out;
- tin += 3 * inos;
- tout += 3 * outos;
- len = len / ( 3 * ins);
- while (len--) {
- tout[0] = tin[0];
- tout[1] = tin[1];
- tout[2] = tin[2];
- tin += 3 * ins;
- tout += 3 * outs;
- }
- break;
- }
- case 4:{
- int32_t* tin = (int32_t*)in;
- int32_t* tout = (int32_t*)out;
- tin += inos;
- tout += outos;
- len = len/(4*ins);
- while(len--){
- *tout=*tin;
- tin +=ins;
- tout+=outs;
- }
- break;
- }
- case 8:{
- int64_t* tin = (int64_t*)in;
- int64_t* tout = (int64_t*)out;
- tin += inos;
- tout += outos;
- len = len/(8*ins);
- while(len--){
- *tout=*tin;
- tin +=ins;
- tout+=outs;
- }
- break;
- }
- default:
- MP_ERR(af, "Unsupported number of bytes/sample: %i"
- " please report this error on the MPlayer mailing list. \n",bps);
- }
-}
-
-// Make sure the routes are sane
-static int check_routes(struct af_instance *af, int nin, int nout)
-{
- af_channels_t* s = af->priv;
- int i;
- if((s->nr < 1) || (s->nr > AF_NCH)){
- MP_ERR(af, "The number of routing pairs must be"
- " between 1 and %i. Current value is %i\n",AF_NCH,s->nr);
- return AF_ERROR;
- }
-
- for(i=0;i<s->nr;i++){
- if((s->route[i][FR] >= nin) || (s->route[i][TO] >= nout)){
- MP_ERR(af, "Invalid routing in pair nr. %i.\n", i);
- return AF_ERROR;
- }
- }
- return AF_OK;
-}
-
-// Initialization and runtime control
-static int control(struct af_instance* af, int cmd, void* arg)
-{
- af_channels_t* s = af->priv;
- switch(cmd){
- case AF_CONTROL_REINIT: ;
-
- struct mp_chmap chmap;
- mp_chmap_set_unknown(&chmap, s->nch);
- mp_audio_set_channels(af->data, &chmap);
-
- // Set default channel assignment
- if(!s->router){
- int i;
- // Make sure this filter isn't redundant
- if(af->data->nch == ((struct mp_audio*)arg)->nch)
- return AF_DETACH;
-
- // If mono: fake stereo
- if(((struct mp_audio*)arg)->nch == 1){
- s->nr = MPMIN(af->data->nch,2);
- for(i=0;i<s->nr;i++){
- s->route[i][FR] = 0;
- s->route[i][TO] = i;
- }
- }
- else{
- s->nr = MPMIN(af->data->nch, ((struct mp_audio*)arg)->nch);
- for(i=0;i<s->nr;i++){
- s->route[i][FR] = i;
- s->route[i][TO] = i;
- }
- }
- }
-
- af->data->rate = ((struct mp_audio*)arg)->rate;
- mp_audio_force_interleaved_format((struct mp_audio*)arg);
- mp_audio_set_format(af->data, ((struct mp_audio*)arg)->format);
- return check_routes(af,((struct mp_audio*)arg)->nch,af->data->nch);
- }
- return AF_UNKNOWN;
-}
-
-static int filter_frame(struct af_instance *af, struct mp_audio *c)
-{
- af_channels_t* s = af->priv;
- int i;
-
- if (!c)
- return 0;
-
- struct mp_audio *l = mp_audio_pool_get(af->out_pool, &af->fmt_out, c->samples);
- if (!l) {
- talloc_free(c);
- return -1;
- }
- mp_audio_copy_attributes(l, c);
-
- // Reset unused channels
- memset(l->planes[0],0,mp_audio_psize(c) / c->nch * l->nch);
-
- if(AF_OK == check_routes(af,c->nch,l->nch))
- for(i=0;i<s->nr;i++)
- copy(af, c->planes[0],l->planes[0],c->nch,s->route[i][FR],
- l->nch,s->route[i][TO],mp_audio_psize(c),c->bps);
-
- talloc_free(c);
- af_add_output_frame(af, l);
- return 0;
-}
-
-// Allocate memory and set function pointers
-static int af_open(struct af_instance* af){
- af->control=control;
- af->filter_frame = filter_frame;
- af_channels_t *s = af->priv;
-
- // If router scan commandline for routing pairs
- if(s->routes && s->routes[0]){
- char* cp = s->routes;
- int ch = 0;
- // Scan for pairs on commandline
- do {
- int n = 0;
- if (ch >= AF_NCH) {
- MP_FATAL(af, "Can't have more than %d routes.\n", AF_NCH);
- return AF_ERROR;
- }
- sscanf(cp, "%i-%i%n" ,&s->route[ch][FR], &s->route[ch][TO], &n);
- MP_VERBOSE(af, "Routing from channel %i to"
- " channel %i\n",s->route[ch][FR],s->route[ch][TO]);
- cp = &cp[n];
- ch++;
- } while(*cp == ',' && *(cp++));
- s->nr = ch;
- if (s->nr > 0)
- s->router = 1;
- }
-
- return AF_OK;
-}
-
-#define OPT_BASE_STRUCT af_channels_t
-const struct af_info af_info_channels = {
- .info = "Insert or remove channels",
- .name = "channels",
- .open = af_open,
- .priv_size = sizeof(af_channels_t),
- .options = (const struct m_option[]) {
- OPT_INTRANGE("nch", nch, 0, 1, AF_NCH, OPTDEF_INT(2)),
- OPT_STRING("routes", routes, 0),
- {0}
- },
-};
diff --git a/audio/filter/af_drc.c b/audio/filter/af_drc.c
deleted file mode 100644
index 7b375febf4..0000000000
--- a/audio/filter/af_drc.c
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * Copyright (C) 2004 Alex Beregszaszi & Pierre Lombard
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <inttypes.h>
-#include <math.h>
-#include <limits.h>
-
-#include "common/common.h"
-#include "af.h"
-
-// Methods:
-// 1: uses a 1 value memory and coefficients new=a*old+b*cur (with a+b=1)
-// 2: uses several samples to smooth the variations (standard weighted mean
-// on past samples)
-
-// Size of the memory array
-// FIXME: should depend on the frequency of the data (should be a few seconds)
-#define NSAMPLES 128
-
-// If summing all the mem[].len is lower than MIN_SAMPLE_SIZE bytes, then we
-// choose to ignore the computed value as it's not significant enough
-// FIXME: should depend on the frequency of the data (0.5s maybe)
-#define MIN_SAMPLE_SIZE 32000
-
-// mul is the value by which the samples are scaled
-// and has to be in [MUL_MIN, MUL_MAX]
-#define MUL_INIT 1.0
-#define MUL_MIN 0.1
-#define MUL_MAX 5.0
-
-// Silence level
-// FIXME: should be relative to the level of the samples
-#define SIL_S16 (SHRT_MAX * 0.01)
-#define SIL_FLOAT 0.01
-
-// smooth must be in ]0.0, 1.0[
-#define SMOOTH_MUL 0.06
-#define SMOOTH_LASTAVG 0.06
-
-#define DEFAULT_TARGET 0.25
-
-// Data for specific instances of this filter
-typedef struct af_volume_s
-{
- int method; // method used
- float mul;
- // method 1
- float lastavg; // history value of the filter
- // method 2
- int idx;
- struct {
- float avg; // average level of the sample
- int len; // sample size (weight)
- } mem[NSAMPLES];
- // "Ideal" level
- float mid_s16;
- float mid_float;
-}af_drc_t;
-
-// Initialization and runtime control
-static int control(struct af_instance* af, int cmd, void* arg)
-{
- switch(cmd){
- case AF_CONTROL_REINIT:
- // Sanity check
- if(!arg) return AF_ERROR;
-
- mp_audio_force_interleaved_format((struct mp_audio*)arg);
- mp_audio_copy_config(af->data, (struct mp_audio*)arg);
-
- if(((struct mp_audio*)arg)->format != (AF_FORMAT_S16)){
- mp_audio_set_format(af->data, AF_FORMAT_FLOAT);
- }
- return af_test_output(af,(struct mp_audio*)arg);
- }
- return AF_UNKNOWN;
-}
-
-static void method1_int16(af_drc_t *s, struct mp_audio *c)
-{
- register int i = 0;
- int16_t *data = (int16_t*)c->planes[0]; // Audio data
- int len = c->samples*c->nch; // Number of samples
- float curavg = 0.0, newavg, neededmul;
- int tmp;
-
- for (i = 0; i < len; i++)
- {
- tmp = data[i];
- curavg += tmp * tmp;
- }
- curavg = sqrt(curavg / (float) len);
-
- // Evaluate an adequate 'mul' coefficient based on previous state, current
- // samples level, etc
-
- if (curavg > SIL_S16)
- {
- neededmul = s->mid_s16 / (curavg * s->mul);
- s->mul = (1.0 - SMOOTH_MUL) * s->mul + SMOOTH_MUL * neededmul;
-
- // clamp the mul coefficient
- s->mul = MPCLAMP(s->mul, MUL_MIN, MUL_MAX);
- }
-
- // Scale & clamp the samples
- for (i = 0; i < len; i++)
- {
- tmp = s->mul * data[i];
- tmp = MPCLAMP(tmp, SHRT_MIN, SHRT_MAX);
- data[i] = tmp;
- }
-
- // Evaluation of newavg (not 100% accurate because of values clamping)
- newavg = s->mul * curavg;
-
- // Stores computed values for future smoothing
- s->lastavg = (1.0 - SMOOTH_LASTAVG) * s->lastavg + SMOOTH_LASTAVG * newavg;
-}
-
-static void method1_float(af_drc_t *s, struct mp_audio *c)
-{
- register int i = 0;
- float *data = (float*)c->planes[0]; // Audio data
- int len = c->samples*c->nch; // Number of samples
- float curavg = 0.0, newavg, neededmul, tmp;
-
- for (i = 0; i < len; i++)
- {
- tmp = data[i];
- curavg += tmp * tmp;
- }
- curavg = sqrt(curavg / (float) len);
-
- // Evaluate an adequate 'mul' coefficient based on previous state, current
- // samples level, etc
-
- if (curavg > SIL_FLOAT) // FIXME
- {
- neededmul = s->mid_float / (curavg * s->mul);
- s->mul = (1.0 - SMOOTH_MUL) * s->mul + SMOOTH_MUL * neededmul;
-
- // clamp the mul coefficient
- s->mul = MPCLAMP(s->mul, MUL_MIN, MUL_MAX);
- }
-
- // Scale & clamp the samples
- for (i = 0; i < len; i++)
- data[i] *= s->mul;
-
- // Evaluation of newavg (not 100% accurate because of values clamping)
- newavg = s->mul * curavg;
-
- // Stores computed values for future smoothing
- s->lastavg = (1.0 - SMOOTH_LASTAVG) * s->lastavg + SMOOTH_LASTAVG * newavg;
-}
-
-static void method2_int16(af_drc_t *s, struct mp_audio *c)
-{
- register int i = 0;
- int16_t *data = (int16_t*)c->planes[0]; // Audio data
- int len = c->samples*c->nch; // Number of samples
- float curavg = 0.0, newavg, avg = 0.0;
- int tmp, totallen = 0;
-
- for (i = 0; i < len; i++)
- {
- tmp = data[i];
- curavg += tmp * tmp;
- }
- curavg = sqrt(curavg / (float) len);
-
- // Evaluate an adequate 'mul' coefficient based on previous state, current
- // samples level, etc
- for (i = 0; i < NSAMPLES; i++)
- {
- avg += s->mem[i].avg * (float)s->mem[i].len;
- totallen += s->mem[i].len;
- }
-
- if (totallen > MIN_SAMPLE_SIZE)
- {
- avg /= (float)totallen;
- if (avg >= SIL_S16)
- {
- s->mul = s->mid_s16 / avg;
- s->mul = MPCLAMP(s->mul, MUL_MIN, MUL_MAX);
- }
- }
-
- // Scale & clamp the samples
- for (i = 0; i < len; i++)
- {
- tmp = s->mul * data[i];
- tmp = MPCLAMP(tmp, SHRT_MIN, SHRT_MAX);
- data[i] = tmp;
- }
-
- // Evaluation of newavg (not 100% accurate because of values clamping)
- newavg = s->mul * curavg;
-
- // Stores computed values for future smoothing
- s->mem[s->idx].len = len;
- s->mem[s->idx].avg = newavg;
- s->idx = (s->idx + 1) % NSAMPLES;
-}
-
-static void method2_float(af_drc_t *s, struct mp_audio *c)
-{
- register int i = 0;
- float *data = (float*)c->planes[0]; // Audio data
- int len = c->samples*c->nch; // Number of samples
- float curavg = 0.0, newavg, avg = 0.0, tmp;
- int totallen = 0;
-
- for (i = 0; i < len; i++)
- {
- tmp = data[i];
- curavg += tmp * tmp;
- }
- curavg = sqrt(curavg / (float) len);
-
- // Evaluate an adequate 'mul' coefficient based on previous state, current
- // samples level, etc
- for (i = 0; i < NSAMPLES; i++)
- {
- avg += s->mem[i].avg * (float)s->mem[i].len;
- totallen += s->mem[i].len;
- }
-
- if (totallen > MIN_SAMPLE_SIZE)
- {
- avg /= (float)totallen;
- if (avg >= SIL_FLOAT)
- {
- s->mul = s->mid_float / avg;
- s->mul = MPCLAMP(s->mul, MUL_MIN, MUL_MAX);
- }
- }
-
- // Scale & clamp the samples
- for (i = 0; i < len; i++)
- data[i] *= s->mul;
-
- // Evaluation of newavg (not 100% accurate because of values clamping)
- newavg = s->mul * curavg;
-
- // Stores computed values for future smoothing
- s->mem[s->idx].len = len;
- s->mem[s->idx].avg = newavg;
- s->idx = (s->idx + 1) % NSAMPLES;
-}
-
-static int filter(struct af_instance *af, struct mp_audio *data)
-{
- af_drc_t *s = af->priv;
-
- if (!data)
- return 0;
-
- if (af_make_writeable(af, data) < 0) {
- talloc_free(data);
- return -1;
- }
-
- if(af->data->format == (AF_FORMAT_S16))
- {
- if (s->method == 2)
- method2_int16(s, data);
- else
- method1_int16(s, data);
- }
- else if(af->data->format == (AF_FORMAT_FLOAT))
- {
- if (s->method == 2)
- method2_float(s, data);
- else
- method1_float(s, data);
- }
- af_add_output_frame(af, data);
- return 0;
-}
-
-// Allocate memory and set function pointers
-static int af_open(struct af_instance* af){
- int i = 0;
- af->control=control;
- af->filter_frame = filter;
- af_drc_t *priv = af->priv;
-
- priv->mul = MUL_INIT;
- priv->lastavg = ((float)SHRT_MAX) * DEFAULT_TARGET;
- priv->idx = 0;
- for (i = 0; i < NSAMPLES; i++)
- {
- priv->mem[i].len = 0;
- priv->mem[i].avg = 0;
- }
- priv->mid_s16 = ((float)SHRT_MAX) * priv->mid_float;
- return AF_OK;
-}
-
-#define OPT_BASE_STRUCT af_drc_t
-const struct af_info af_info_drc = {
- .info = "Dynamic range compression filter",
- .name = "drc",
- .open = af_open,
- .priv_size = sizeof(af_drc_t),
- .options = (const struct m_option[]) {
- OPT_INTRANGE("method", method, 0, 1, 2, OPTDEF_INT(1)),
- OPT_FLOAT("target", mid_float, 0, OPTDEF_FLOAT(DEFAULT_TARGET)),
- {0}
- },
-};
diff --git a/audio/filter/af_equalizer.c b/audio/filter/af_equalizer.c
deleted file mode 100644
index cb4ecb2675..0000000000
--- a/audio/filter/af_equalizer.c
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Equalizer filter, implementation of a 10 band time domain graphic
- * equalizer using IIR filters. The IIR filters are implemented using a
- * Direct Form II approach, but has been modified (b1 == 0 always) to
- * save computation.
- *
- * Copyright (C) 2001 Anders Johansson ajh@atri.curtin.edu.au
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <inttypes.h>
-#include <math.h>
-
-#include "common/common.h"
-#include "af.h"
-
-#define L 2 // Storage for filter taps
-#define KM 10 // Max number of bands
-
-#define Q 1.2247449 /* Q value for band-pass filters 1.2247=(3/2)^(1/2)
- gives 4dB suppression @ Fc*2 and Fc/2 */
-
-/* Center frequencies for band-pass filters
- The different frequency bands are:
- nr. center frequency
- 0 31.25 Hz
- 1 62.50 Hz
- 2 125.0 Hz
- 3 250.0 Hz
- 4 500.0 Hz
- 5 1.000 kHz
- 6 2.000 kHz
- 7 4.000 kHz
- 8 8.000 kHz
- 9 16.00 kHz
-*/
-#define CF {31.25,62.5,125,250,500,1000,2000,4000,8000,16000}
-
-// Maximum and minimum gain for the bands
-#define G_MAX +12.0
-#define G_MIN -12.0
-
-// Data for specific instances of this filter
-typedef struct af_equalizer_s
-{
- float a[KM][L]; // A weights
- float b[KM][L]; // B weights
- float wq[AF_NCH][KM][L]; // Circular buffer for W data
- float g[AF_NCH][KM]; // Gain factor for each channel and band
- int K; // Number of used eq bands
- int channels; // Number of channels
- float gain_factor; // applied at output to avoid clipping
- double p[KM];
-} af_equalizer_t;
-
-// 2nd order Band-pass Filter design
-static void bp2(float* a, float* b, float fc, float q){
- double th= 2.0 * M_PI * fc;
- double C = (1.0 - tan(th*q/2.0))/(1.0 + tan(th*q/2.0));
-
- a[0] = (1.0 + C) * cos(th);
- a[1] = -1 * C;
-
- b[0] = (1.0 - C)/2.0;
- b[1] = -1.0050;
-}
-
-// Initialization and runtime control
-static int control(struct af_instance* af, int cmd, void* arg)
-{
- af_equalizer_t* s = (af_equalizer_t*)af->priv;
-
- switch(cmd){
- case AF_CONTROL_REINIT:{
- int k =0, i =0;
- float F[KM] = CF;
-
- s->gain_factor=0.0;
-
- // Sanity check
- if(!arg) return AF_ERROR;
-
- mp_audio_copy_config(af->data, (struct mp_audio*)arg);
- mp_audio_set_format(af->data, AF_FORMAT_FLOAT);
-
- // Calculate number of active filters
- s->K=KM;
- while(F[s->K-1] > (float)af->data->rate/2.2)
- s->K--;
-
- if(s->K != KM)
- MP_INFO(af, "Limiting the number of filters to"
- " %i due to low sample rate.\n",s->K);
-
- // Generate filter taps
- for(k=0;k<s->K;k++)
- bp2(s->a[k],s->b[k],F[k]/((float)af->data->rate),Q);
-
- // Calculate how much this plugin adds to the overall time delay
- af->delay = 2.0 / (double)af->data->rate;
-
- // Calculate gain factor to prevent clipping at output
- for(k=0;k<AF_NCH;k++)
- {
- for(i=0;i<KM;i++)
- {
- if(s->gain_factor < s->g[k][i]) s->gain_factor=s->g[k][i];
- }
- }
-
- s->gain_factor=log10(s->gain_factor + 1.0) * 20.0;
-
- if(s->gain_factor > 0.0)
- {
- s->gain_factor=0.1+(s->gain_factor/12.0);
- }else{
- s->gain_factor=1;
- }
-
- return af_test_output(af,arg);
- }
- }
- return AF_UNKNOWN;
-}
-
-static int filter(struct af_instance* af, struct mp_audio* data)
-{
- struct mp_audio* c = data; // Current working data
- if (!c)
- return 0;
- af_equalizer_t* s = (af_equalizer_t*)af->priv; // Setup
- uint32_t ci = af->data->nch; // Index for channels
- uint32_t nch = af->data->nch; // Number of channels
-
- if (af_make_writeable(af, data) < 0) {
- talloc_free(data);
- return -1;
- }
-
- while(ci--){
- float* g = s->g[ci]; // Gain factor
- float* in = ((float*)c->planes[0])+ci;
- float* out = ((float*)c->planes[0])+ci;
- float* end = in + c->samples*c->nch; // Block loop end
-
- while(in < end){
- register int k = 0; // Frequency band index
- register float yt = *in; // Current input sample
- in+=nch;
-
- // Run the filters
- for(;k<s->K;k++){
- // Pointer to circular buffer wq
- register float* wq = s->wq[ci][k];
- // Calculate output from AR part of current filter
- register float w=yt*s->b[k][0] + wq[0]*s->a[k][0] + wq[1]*s->a[k][1];
- // Calculate output form MA part of current filter
- yt+=(w + wq[1]*s->b[k][1])*g[k];
- // Update circular buffer
- wq[1] = wq[0];
- wq[0] = w;
- }
- // Calculate output
- *out=yt*s->gain_factor;
- out+=nch;
- }
- }
- af_add_output_frame(af, data);
- return 0;
-}
-
-// Allocate memory and set function pointers
-static int af_open(struct af_instance* af){
- af->control=control;
- af->filter_frame = filter;
- af_equalizer_t *priv = af->priv;
- for(int i=0;i<AF_NCH;i++){
- for(int j=0;j<KM;j++){
- priv->g[i][j] = pow(10.0,MPCLAMP(priv->p[j],G_MIN,G_MAX)/20.0)-1.0;
- }
- }
- return AF_OK;
-}
-
-#define OPT_BASE_STRUCT af_equalizer_t
-const struct af_info af_info_equalizer = {
- .info = "Equalizer audio filter",
- .name = "equalizer",
- .open = af_open,
- .priv_size = sizeof(af_equalizer_t),
- .options = (const struct m_option[]) {
-#define BAND(n) OPT_DOUBLE("e" #n, p[n], 0)
- BAND(0), BAND(1), BAND(2), BAND(3), BAND(4),
- BAND(5), BAND(6), BAND(7), BAND(8), BAND(9),
- {0}
- },
-};
diff --git a/audio/filter/af_format.c b/audio/filter/af_format.c
deleted file mode 100644
index 748c5cbd52..0000000000
--- a/audio/filter/af_format.c
+++ /dev/null
@@ -1,134 +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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdlib.h>
-
-#include <libavutil/common.h>
-
-#include "options/m_option.h"
-
-#include "audio/format.h"
-#include "af.h"
-
-struct priv {
- struct m_config *config;
-
- int in_format;
- int in_srate;
- struct m_channels in_channels;
- int out_format;
- int out_srate;
- struct m_channels out_channels;
-
- 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;
-}
-
-static void force_out_params(struct af_instance *af, struct mp_audio *out)
-{
- struct priv *priv = af->priv;
-
- if (priv->out_format != AF_FORMAT_UNKNOWN)
- mp_audio_set_format(out, priv->out_format);
-
- if (priv->out_channels.num_chmaps > 0)
- mp_audio_set_channels(out, &priv->out_channels.chmaps[0]);
-
- if (priv->out_srate)
- out->rate = priv->out_srate;
-}
-
-static int control(struct af_instance *af, int cmd, void *arg)
-{
- struct priv *priv = af->priv;
-
- switch (cmd) {
- case AF_CONTROL_REINIT: {
- struct mp_audio *in = arg;
- struct mp_audio orig_in = *in;
- struct mp_audio *out = af->data;
-
- force_in_params(af, in);
- mp_audio_copy_config(out, in);
- force_out_params(af, out);
-
- if (in->nch != out->nch || in->bps != out->bps) {
- MP_ERR(af, "Forced input/output formats are incompatible.\n");
- return AF_ERROR;
- }
-
- if (priv->fail) {
- MP_ERR(af, "Failing on purpose.\n");
- return AF_ERROR;
- }
-
- return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
- }
- }
- return AF_UNKNOWN;
-}
-
-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;
-}
-
-static int af_open(struct af_instance *af)
-{
- af->control = control;
- af->filter_frame = filter;
-
- force_in_params(af, af->data);
- force_out_params(af, af->data);
-
- return AF_OK;
-}
-
-#define OPT_BASE_STRUCT struct priv
-
-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}
- },
-};
diff --git a/audio/filter/af_lavcac3enc.c b/audio/filter/af_lavcac3enc.c
deleted file mode 100644
index 9df5adb96f..0000000000
--- a/audio/filter/af_lavcac3enc.c
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- * audio filter for runtime AC-3 encoding with libavcodec.
- *
- * Copyright (C) 2007 Ulion <ulion A gmail P com>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <inttypes.h>
-#include <assert.h>
-
-#include <libavcodec/avcodec.h>
-#include <libavutil/intreadwrite.h>
-#include <libavutil/common.h>
-#include <libavutil/bswap.h>
-#include <libavutil/mem.h>
-
-#include "config.h"
-
-#include "common/av_common.h"
-#include "common/common.h"
-#include "af.h"
-#include "audio/audio_buffer.h"
-#include "audio/chmap_sel.h"
-#include "audio/fmt-conversion.h"
-
-
-#define AC3_MAX_CHANNELS 6
-#define AC3_MAX_CODED_FRAME_SIZE 3840
-#define AC3_FRAME_SIZE (6 * 256)
-const uint16_t ac3_bitrate_tab[19] = {
- 32, 40, 48, 56, 64, 80, 96, 112, 128,
- 160, 192, 224, 256, 320, 384, 448, 512, 576, 640
-};
-
-// Data for specific instances of this filter
-typedef struct af_ac3enc_s {
- 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;
-
- 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);
-}
-
-// 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);
-
- int bit_rate = s->bit_rate ? s->bit_rate : default_bit_rate[in->nch];
-
- 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);
-
- // 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;
-
- 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;
- }
-
- 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;
- }
- 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) {
- if(s->lavc_actx) {
- avcodec_close(s->lavc_actx);
- av_free(s->lavc_actx);
- }
- talloc_free(s->pending);
- }
-}
-
-static void update_delay(struct af_instance *af)
-{
- af_ac3enc_t *s = af->priv;
- af->delay = ((s->pending ? s->pending->samples : 0) + s->input->samples +
- s->encoder_buffered) / (double)s->input->rate;
-}
-
-static int filter_frame(struct af_instance *af, struct mp_audio *audio)
-{
- af_ac3enc_t *s = af->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;
-}
-
-static void swap_16(uint16_t *ptr, size_t size)
-{
- for (size_t n = 0; n < size; n++)
- 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)
-{
- af_ac3enc_t *s = af->priv;
- if (!fill_buffer(af))
- return 0; // need more input
-
- 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;
-
- 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)
- goto done;
- if (err == 0)
- break;
- err = -1;
- 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");
- 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);
-
- s->encoder_buffered -= AC3_FRAME_SIZE;
-
- struct mp_audio *out =
- mp_audio_pool_get(af->out_pool, af->data, s->out_samples);
- if (!out)
- goto done;
- mp_audio_copy_attributes(out, s->pending);
-
- int frame_size = pkt.size;
- int header_len = 0;
- char hdr[8];
-
- if (s->cfg_add_iec61937_header && pkt.size > 5) {
- int bsmod = pkt.data[5] & 0x7;
- int len = frame_size;
-
- frame_size = AC3_FRAME_SIZE * 2 * 2;
- header_len = 8;
-
- AV_WL16(hdr, 0xF872); // iec 61937 syncword 1
- AV_WL16(hdr + 2, 0x4E1F); // iec 61937 syncword 2
- hdr[5] = bsmod; // bsmod
- hdr[4] = 0x01; // data-type ac3
- AV_WL16(hdr + 6, len << 3); // number of bits in payload
- }
-
- if (frame_size > out->samples * out->sstride)
- abort();
-
- char *buf = (char *)out->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);
-
- err = 0;
-done:
- av_packet_unref(&pkt);
- av_frame_free(&frame);
- update_delay(af);
- return err;
-}
-
-static int af_open(struct af_instance* af){
-
- af_ac3enc_t *s = af->priv;
- af->control=control;
- af->uninit=uninit;
- af->filter_frame = filter_frame;
- af->filter_out = filter_out;
-
- s->lavc_acodec = avcodec_find_encoder_by_name(s->cfg_encoder);
- if (!s->lavc_acodec) {
- MP_ERR(af, "Couldn't find encoder %s.\n", s->cfg_encoder);
- return AF_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;
- }
-
- if (mp_set_avopts(af->log, s->lavc_actx, s->cfg_avopts) < 0)
- return AF_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
- // in do.)
- 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;
- }
-
- s->input = talloc_zero(s, struct mp_audio);
-
- if (s->cfg_bit_rate) {
- int i;
- for (i = 0; i < 19; i++) {
- if (ac3_bitrate_tab[i] == s->cfg_bit_rate) {
- s->bit_rate = ac3_bitrate_tab[i] * 1000;
- break;
- }
- }
- if (i >= 19) {
- MP_WARN(af, "unable set unsupported bitrate %d, use default "
- "bitrate (check manpage to see supported bitrates).\n",
- s->cfg_bit_rate);
- }
- }
-
- return AF_OK;
-}
-
-#define OPT_BASE_STRUCT struct af_ac3enc_s
-
-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}
- },
-};
diff --git a/audio/filter/af_lavfi.c b/audio/filter/af_lavfi.c
deleted file mode 100644
index 55fb7cb0dc..0000000000
--- a/audio/filter/af_lavfi.c
+++ /dev/null
@@ -1,369 +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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <assert.h>
-
-#include <libavutil/avstring.h>
-#include <libavutil/mem.h>
-#include <libavutil/mathematics.h>
-#include <libavutil/rational.h>
-#include <libavutil/samplefmt.h>
-#include <libavutil/time.h>
-#include <libavutil/opt.h>
-#include <libavfilter/avfilter.h>
-#include <libavfilter/avfiltergraph.h>
-#include <libavfilter/buffersink.h>
-#include <libavfilter/buffersrc.h>
-
-#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. <Expletive deleted.>
-#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 {
- 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;
-};
-
-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, *f_format = NULL;
-
- if (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)
- 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;
-
- // Build list of acceptable output sample formats. libavfilter will insert
- // conversion filters if needed.
- static const enum AVSampleFormat sample_fmts[] = {
- AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32,
- AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL,
- AV_SAMPLE_FMT_U8P, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P,
- AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP,
- AV_SAMPLE_FMT_NONE
- };
- char *fmtstr = talloc_strdup(tmp, "");
- for (int n = 0; sample_fmts[n] != AV_SAMPLE_FMT_NONE; n++) {
- const char *name = av_get_sample_fmt_name(sample_fmts[n]);
- if (name) {
- const char *s = fmtstr[0] ? "|" : "";
- fmtstr = talloc_asprintf_append_buffer(fmtstr, "%s%s", s, name);
- }
- }
-
- 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 (avfilter_graph_create_filter(&f_format, avfilter_get_by_name("aformat"),
- "format", fmtstr, NULL, graph) < 0)
- goto error;
-
- if (avfilter_link(f_format, 0, out, 0) < 0)
- goto error;
-
- outputs->name = av_strdup("in");
- outputs->filter_ctx = in;
-
- inputs->name = av_strdup("out");
- inputs->filter_ctx = f_format;
-
- if (graph_parse(graph, p->cfg_graph, inputs, outputs, NULL) < 0)
- goto error;
-
- if (avfilter_graph_config(graph, NULL) < 0)
- goto error;
-
- p->in = in;
- p->out = out;
- p->graph = graph;
-
- assert(out->nb_inputs == 1);
- assert(in->nb_outputs == 1);
-
- talloc_free(tmp);
- return true;
-
-error:
- MP_FATAL(af, "Can't configure libavfilter graph.\n");
- avfilter_graph_free(&graph);
- talloc_free(tmp);
- return false;
-}
-
-static void reset(struct af_instance *af)
-{
- if (!recreate_graph(af, &af->fmt_in))
- MP_FATAL(af, "Can't recreate libavfilter filter after a seek reset.\n");
-}
-
-static int control(struct af_instance *af, int cmd, void *arg)
-{
- struct priv *p = af->priv;
-
- switch (cmd) {
- case AF_CONTROL_REINIT: {
- struct mp_audio *in = arg;
- struct mp_audio orig_in = *in;
- struct mp_audio *out = af->data;
-
- if (af_to_avformat(in->format) == AV_SAMPLE_FMT_NONE)
- mp_audio_set_format(in, AF_FORMAT_FLOAT);
-
- // Removing this requires fixing AVFrame.data vs. AVFrame.extended_data
- if (in->channels.num > AV_NUM_DATA_POINTERS)
- return AF_ERROR;
-
- if (!mp_chmap_is_lavc(&in->channels))
- mp_chmap_reorder_to_lavc(&in->channels); // will always work
-
- if (!recreate_graph(af, in))
- return AF_ERROR;
-
- AVFilterLink *l_out = p->out->inputs[0];
-
- out->rate = l_out->sample_rate;
-
- mp_audio_set_format(out, af_from_avformat(l_out->format));
-
- struct mp_chmap out_cm;
- mp_chmap_from_lavc(&out_cm, l_out->channel_layout);
- mp_audio_set_channels(out, &out_cm);
-
- if (!mp_audio_config_valid(out) || out->channels.num > AV_NUM_DATA_POINTERS)
- return AF_ERROR;
-
- p->timebase_out = l_out->time_base;
-
- return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
- }
- case AF_CONTROL_COMMAND: {
- if (!p->graph)
- break;
- char **args = arg;
- return avfilter_graph_send_command(p->graph, "all",
- args[0], args[1], &(char){0}, 0, 0)
- >= 0 ? CONTROL_OK : CONTROL_ERROR;
- }
- case AF_CONTROL_GET_METADATA:
- if (p->metadata) {
- *(struct mp_tags *)arg = *p->metadata;
- return CONTROL_OK;
- }
- return CONTROL_NA;
- case AF_CONTROL_RESET:
- reset(af);
- return AF_OK;
- }
- return AF_UNKNOWN;
-}
-
-static void get_metadata_from_av_frame(struct af_instance *af, AVFrame *frame)
-{
-#if LIBAVUTIL_VERSION_MICRO >= 100
- struct priv *p = af->priv;
- if (!p->metadata)
- p->metadata = talloc_zero(p, struct mp_tags);
-
- mp_tags_copy_from_av_dictionary(p->metadata, av_frame_get_metadata(frame));
-#endif
-}
-
-static int filter_frame(struct af_instance *af, struct mp_audio *data)
-{
- struct priv *p = af->priv;
- AVFrame *frame = NULL;
-
- if (p->eof && data)
- reset(af);
-
- if (!p->graph)
- goto error;
-
- if (!data) {
- if (p->eof)
- return 0;
- p->eof = true;
- }
-
- if (data) {
- frame = mp_audio_to_avframe_and_unref(data);
- data = NULL;
- if (!frame)
- goto error;
-
- // Timebase is 1/sample_rate
- frame->pts = p->samples_in;
- p->samples_in += frame->nb_samples;
- }
-
- if (av_buffersrc_add_frame(p->in, frame) < 0)
- goto error;
-
- av_frame_free(&frame);
- talloc_free(data);
- return 0;
-error:
- av_frame_free(&frame);
- talloc_free(data);
- return -1;
-}
-
-static int filter_out(struct af_instance *af)
-{
- struct priv *p = af->priv;
-
- if (!p->graph)
- goto error;
-
- AVFrame *frame = av_frame_alloc();
- if (!frame)
- goto error;
-
- int err = av_buffersink_get_frame(p->out, frame);
- if (err == AVERROR(EAGAIN) || err == AVERROR_EOF) {
- // Not an error situation - no more output buffers in queue.
- // AVERROR_EOF means we shouldn't even give the filter more
- // input, but we don't handle that completely correctly.
- av_frame_free(&frame);
- p->eof |= err == AVERROR_EOF;
- return 0;
- }
-
- struct mp_audio *out = mp_audio_from_avframe(frame);
- if (!out)
- goto error;
-
- mp_audio_copy_config(out, af->data);
-
- if (frame->pts != AV_NOPTS_VALUE) {
- double in_time = p->samples_in / (double)af->fmt_in.rate;
- double out_time = frame->pts * av_q2d(p->timebase_out);
- // Need pts past the last output sample.
- out_time += out->samples / (double)out->rate;
-
- af->delay = in_time - out_time;
- }
-
- get_metadata_from_av_frame(af, frame);
- af_add_output_frame(af, out);
- av_frame_free(&frame);
- return 0;
-error:
- av_frame_free(&frame);
- return -1;
-}
-
-static void uninit(struct af_instance *af)
-{
- destroy_graph(af);
-}
-
-static int af_open(struct af_instance *af)
-{
- af->control = control;
- af->uninit = uninit;
- af->filter_frame = filter_frame;
- af->filter_out = filter_out;
- return AF_OK;
-}
-
-#define OPT_BASE_STRUCT struct priv
-
-const struct af_info af_info_lavfi = {
- .info = "libavfilter bridge",
- .name = "lavfi",
- .open = af_open,
- .priv_size = sizeof(struct priv),
- .options = (const struct m_option[]) {
- OPT_STRING("graph", cfg_graph, 0),
- OPT_KEYVALUELIST("o", cfg_avopts, 0),
- {0}
- },
-};
diff --git a/audio/filter/af_lavrresample.c b/audio/filter/af_lavrresample.c
deleted file mode 100644
index 47c374b227..0000000000
--- a/audio/filter/af_lavrresample.c
+++ /dev/null
@@ -1,617 +0,0 @@
-/*
- * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
- * Copyright (c) 2013 Stefano Pigozzi <stefano.pigozzi@gmail.com>
- *
- * Based on Michael Niedermayer's lavcresample.
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <inttypes.h>
-#include <math.h>
-#include <assert.h>
-
-#include <libavutil/opt.h>
-#include <libavutil/common.h>
-#include <libavutil/samplefmt.h>
-#include <libavutil/channel_layout.h>
-#include <libavutil/mathematics.h>
-
-#include "common/common.h"
-#include "config.h"
-
-#define HAVE_LIBSWRESAMPLE HAVE_IS_FFMPEG
-#define HAVE_LIBAVRESAMPLE HAVE_IS_LIBAV
-
-#if HAVE_LIBAVRESAMPLE
-#include <libavresample/avresample.h>
-#elif HAVE_LIBSWRESAMPLE
-#include <libswresample/swresample.h>
-#define AVAudioResampleContext SwrContext
-#define avresample_alloc_context swr_alloc
-#define avresample_open swr_init
-#define avresample_close(x) do { } while(0)
-#define avresample_free swr_free
-#define avresample_available(x) 0
-#define avresample_convert(ctx, out, out_planesize, out_samples, in, in_planesize, in_samples) \
- swr_convert(ctx, out, out_samples, (const uint8_t**)(in), in_samples)
-#define avresample_set_channel_mapping swr_set_channel_mapping
-#define avresample_set_compensation swr_set_compensation
-#else
-#error "config.h broken or no resampler found"
-#endif
-
-#include "common/av_common.h"
-#include "common/msg.h"
-#include "options/m_option.h"
-#include "audio/filter/af.h"
-#include "audio/fmt-conversion.h"
-#include "osdep/endian.h"
-
-struct af_resample_opts {
- int filter_size;
- int phase_shift;
- int linear;
- double cutoff;
- int normalize;
-};
-
-struct af_resample {
- int allow_detach;
- char **avopts;
- double playback_speed;
- struct AVAudioResampleContext *avrctx;
- struct mp_audio avrctx_fmt; // output format of avrctx
- struct mp_audio pool_fmt; // format used to allocate frames for avrctx output
- struct mp_audio pre_out_fmt; // format before final conversion (S24)
- struct AVAudioResampleContext *avrctx_out; // for output channel reordering
- struct af_resample_opts opts; // opts requested by the user
- // At least libswresample keeps a pointer around for this:
- int reorder_in[MP_NUM_CHANNELS];
- int reorder_out[MP_NUM_CHANNELS];
- struct mp_audio_pool *reorder_buffer;
-
- int in_rate_af; // filter input sample rate
- int in_rate; // actual rate (used by lavr), adjusted for playback speed
- int in_format;
- struct mp_chmap in_channels;
- int out_rate;
- int out_format;
- struct mp_chmap out_channels;
-};
-
-#if HAVE_LIBAVRESAMPLE
-static double get_delay(struct af_resample *s)
-{
- return avresample_get_delay(s->avrctx) / (double)s->in_rate +
- avresample_available(s->avrctx) / (double)s->out_rate;
-}
-static int get_out_samples(struct af_resample *s, int in_samples)
-{
- return avresample_get_out_samples(s->avrctx, in_samples);
-}
-#else
-static double get_delay(struct af_resample *s)
-{
- int64_t base = s->in_rate * (int64_t)s->out_rate;
- return swr_get_delay(s->avrctx, base) / (double)base;
-}
-static int get_out_samples(struct af_resample *s, int in_samples)
-{
- return swr_get_out_samples(s->avrctx, in_samples);
-}
-#endif
-
-static void close_lavrr(struct af_instance *af)
-{
- struct af_resample *s = af->priv;
-
- if (s->avrctx)
- avresample_close(s->avrctx);
- avresample_free(&s->avrctx);
- if (s->avrctx_out)
- avresample_close(s->avrctx_out);
- avresample_free(&s->avrctx_out);
-}
-
-static int resample_frame(struct AVAudioResampleContext *r,
- struct mp_audio *out, struct mp_audio *in)
-{
- return avresample_convert(r,
- out ? (uint8_t **)out->planes : NULL,
- out ? mp_audio_get_allocated_size(out) : 0,
- out ? out->samples : 0,
- in ? (uint8_t **)in->planes : NULL,
- in ? mp_audio_get_allocated_size(in) : 0,
- in ? in->samples : 0);
-}
-
-static double af_resample_default_cutoff(int filter_size)
-{
- return FFMAX(1.0 - 6.5 / (filter_size + 8), 0.80);
-}
-
-static int rate_from_speed(int rate, double speed)
-{
- return lrint(rate * speed);
-}
-
-// Return the format libavresample should convert to, given the final output
-// format mp_format. In some cases (S24) we perform an extra conversion step,
-// and signal here what exactly libavresample should output. It will be the
-// input to the final conversion to mp_format.
-static int check_output_conversion(int mp_format)
-{
- if (mp_format == AF_FORMAT_S24)
- return AV_SAMPLE_FMT_S32;
- return af_to_avformat(mp_format);
-}
-
-static struct mp_chmap fudge_pairs[][2] = {
- {MP_CHMAP2(BL, BR), MP_CHMAP2(SL, SR)},
- {MP_CHMAP2(SL, SR), MP_CHMAP2(BL, BR)},
- {MP_CHMAP2(SDL, SDR), MP_CHMAP2(SL, SR)},
- {MP_CHMAP2(SL, SR), MP_CHMAP2(SDL, SDR)},
-};
-
-// Modify out_layout and return the new value. The intention is reducing the
-// loss libswresample's rematrixing will cause by exchanging similar, but
-// strictly speaking incompatible channel pairs. For example, 7.1 should be
-// changed to 7.1(wide) without dropping the SL/SR channels. (We still leave
-// it to libswresample to create the remix matrix.)
-static uint64_t fudge_layout_conversion(struct af_instance *af,
- uint64_t in, uint64_t out)
-{
- for (int n = 0; n < MP_ARRAY_SIZE(fudge_pairs); n++) {
- uint64_t a = mp_chmap_to_lavc(&fudge_pairs[n][0]);
- uint64_t b = mp_chmap_to_lavc(&fudge_pairs[n][1]);
- if ((in & a) == a && (in & b) == 0 &&
- (out & a) == 0 && (out & b) == b)
- {
- out = (out & ~b) | a;
-
- MP_VERBOSE(af, "Fudge: %s -> %s\n",
- mp_chmap_to_str(&fudge_pairs[n][0]),
- mp_chmap_to_str(&fudge_pairs[n][1]));
- }
- }
- return out;
-}
-
-// mp_chmap_get_reorder() performs:
-// to->speaker[n] = from->speaker[src[n]]
-// but libavresample does:
-// to->speaker[dst[n]] = from->speaker[n]
-static void transpose_order(int *map, int num)
-{
- int nmap[MP_NUM_CHANNELS] = {0};
- for (int n = 0; n < num; n++) {
- for (int i = 0; i < num; i++) {
- if (map[n] == i)
- nmap[i] = n;
- }
- }
- memcpy(map, nmap, sizeof(nmap));
-}
-
-static int configure_lavrr(struct af_instance *af, struct mp_audio *in,
- struct mp_audio *out, bool verbose)
-{
- struct af_resample *s = af->priv;
-
- close_lavrr(af);
-
- s->avrctx = avresample_alloc_context();
- s->avrctx_out = avresample_alloc_context();
- if (!s->avrctx || !s->avrctx_out)
- goto error;
-
- enum AVSampleFormat in_samplefmt = af_to_avformat(in->format);
- enum AVSampleFormat out_samplefmt = check_output_conversion(out->format);
- enum AVSampleFormat out_samplefmtp = av_get_planar_sample_fmt(out_samplefmt);
-
- if (in_samplefmt == AV_SAMPLE_FMT_NONE ||
- out_samplefmt == AV_SAMPLE_FMT_NONE ||
- out_samplefmtp == AV_SAMPLE_FMT_NONE)
- goto error;
-
- s->out_rate = out->rate;
- s->in_rate_af = in->rate;
- s->in_rate = rate_from_speed(in->rate, s->playback_speed);
- s->out_format = out->format;
- s->in_format = in->format;
- s->out_channels= out->channels;
- s->in_channels = in->channels;
-
- av_opt_set_int(s->avrctx, "filter_size", s->opts.filter_size, 0);
- av_opt_set_int(s->avrctx, "phase_shift", s->opts.phase_shift, 0);
- av_opt_set_int(s->avrctx, "linear_interp", s->opts.linear, 0);
-
- av_opt_set_double(s->avrctx, "cutoff", s->opts.cutoff, 0);
-
- int normalize = s->opts.normalize;
- if (normalize < 0)
- normalize = af->opts->audio_normalize;
-#if HAVE_LIBSWRESAMPLE
- av_opt_set_double(s->avrctx, "rematrix_maxval", normalize ? 1 : 1000, 0);
-#else
- av_opt_set_int(s->avrctx, "normalize_mix_level", !!normalize, 0);
-#endif
-
- if (mp_set_avopts(af->log, s->avrctx, s->avopts) < 0)
- goto error;
-
- struct mp_chmap map_in = in->channels;
- struct mp_chmap map_out = out->channels;
-
- // Try not to do any remixing if at least one is "unknown".
- if (mp_chmap_is_unknown(&map_in) || mp_chmap_is_unknown(&map_out)) {
- mp_chmap_set_unknown(&map_in, map_in.num);
- mp_chmap_set_unknown(&map_out, map_out.num);
- }
-
- // unchecked: don't take any channel reordering into account
- uint64_t in_ch_layout = mp_chmap_to_lavc_unchecked(&map_in);
- uint64_t out_ch_layout = mp_chmap_to_lavc_unchecked(&map_out);
-
- struct mp_chmap in_lavc, out_lavc;
- mp_chmap_from_lavc(&in_lavc, in_ch_layout);
- mp_chmap_from_lavc(&out_lavc, out_ch_layout);
-
- if (verbose && !mp_chmap_equals(&in_lavc, &out_lavc)) {
- MP_VERBOSE(af, "Remix: %s -> %s\n", mp_chmap_to_str(&in_lavc),
- mp_chmap_to_str(&out_lavc));
- }
-
- if (in_lavc.num != map_in.num) {
- // For handling NA channels, we would have to add a planarization step.
- MP_FATAL(af, "Unsupported channel remapping.\n");
- goto error;
- }
-
- mp_chmap_get_reorder(s->reorder_in, &map_in, &in_lavc);
- transpose_order(s->reorder_in, map_in.num);
-
- if (mp_chmap_equals(&out_lavc, &map_out)) {
- // No intermediate step required - output new format directly.
- out_samplefmtp = out_samplefmt;
- } else {
- // Verify that we really just reorder and/or insert NA channels.
- struct mp_chmap withna = out_lavc;
- mp_chmap_fill_na(&withna, map_out.num);
- if (withna.num != map_out.num)
- goto error;
- }
- mp_chmap_get_reorder(s->reorder_out, &out_lavc, &map_out);
-
- s->avrctx_fmt = *out;
- mp_audio_set_channels(&s->avrctx_fmt, &out_lavc);
- mp_audio_set_format(&s->avrctx_fmt, af_from_avformat(out_samplefmtp));
-
- s->pre_out_fmt = *out;
- mp_audio_set_format(&s->pre_out_fmt, af_from_avformat(out_samplefmt));
-
- // If there are NA channels, the final output will have more channels than
- // the avrctx output. Also, avrctx will output planar (out_samplefmtp was
- // not overwritten). Allocate the output frame with more channels, so the
- // NA channels can be trivially added.
- s->pool_fmt = s->avrctx_fmt;
- if (map_out.num > out_lavc.num)
- mp_audio_set_channels(&s->pool_fmt, &map_out);
-
- out_ch_layout = fudge_layout_conversion(af, in_ch_layout, out_ch_layout);
-
- // Real conversion; output is input to avrctx_out.
- av_opt_set_int(s->avrctx, "in_channel_layout", in_ch_layout, 0);
- av_opt_set_int(s->avrctx, "out_channel_layout", out_ch_layout, 0);
- av_opt_set_int(s->avrctx, "in_sample_rate", s->in_rate, 0);
- av_opt_set_int(s->avrctx, "out_sample_rate", s->out_rate, 0);
- av_opt_set_int(s->avrctx, "in_sample_fmt", in_samplefmt, 0);
- av_opt_set_int(s->avrctx, "out_sample_fmt", out_samplefmtp, 0);
-
- // Just needs the correct number of channels for deplanarization.
- struct mp_chmap fake_chmap;
- mp_chmap_set_unknown(&fake_chmap, map_out.num);
- uint64_t fake_out_ch_layout = mp_chmap_to_lavc_unchecked(&fake_chmap);
- if (!fake_out_ch_layout)
- goto error;
- av_opt_set_int(s->avrctx_out, "in_channel_layout", fake_out_ch_layout, 0);
- av_opt_set_int(s->avrctx_out, "out_channel_layout", fake_out_ch_layout, 0);
-
- av_opt_set_int(s->avrctx_out, "in_sample_fmt", out_samplefmtp, 0);
- av_opt_set_int(s->avrctx_out, "out_sample_fmt", out_samplefmt, 0);
- av_opt_set_int(s->avrctx_out, "in_sample_rate", s->out_rate, 0);
- av_opt_set_int(s->avrctx_out, "out_sample_rate", s->out_rate, 0);
-
- // API has weird requirements, quoting avresample.h:
- // * This function can only be called when the allocated context is not open.
- // * Also, the input channel layout must have already been set.
- avresample_set_channel_mapping(s->avrctx, s->reorder_in);
-
- if (avresample_open(s->avrctx) < 0 || avresample_open(s->avrctx_out) < 0) {
- MP_ERR(af, "Cannot open Libavresample Context. \n");
- goto error;
- }
- return AF_OK;
-
-error:
- close_lavrr(af);
- return AF_ERROR;
-}
-
-
-static int control(struct af_instance *af, int cmd, void *arg)
-{
- struct af_resample *s = af->priv;
-
- switch (cmd) {
- case AF_CONTROL_REINIT: {
- struct mp_audio *in = arg;
- struct mp_audio *out = af->data;
- struct mp_audio orig_in = *in;
-
- if (((out->rate == in->rate) || (out->rate == 0)) &&
- (out->format == in->format) &&
- (mp_chmap_equals(&out->channels, &in->channels) || out->nch == 0) &&
- s->allow_detach && s->playback_speed == 1.0)
- return AF_DETACH;
-
- if (out->rate == 0)
- out->rate = in->rate;
-
- if (mp_chmap_is_empty(&out->channels))
- mp_audio_set_channels(out, &in->channels);
-
- if (af_to_avformat(in->format) == AV_SAMPLE_FMT_NONE)
- mp_audio_set_format(in, AF_FORMAT_FLOAT);
- if (check_output_conversion(out->format) == AV_SAMPLE_FMT_NONE)
- mp_audio_set_format(out, in->format);
-
- int r = ((in->format == orig_in.format) &&
- mp_chmap_equals(&in->channels, &orig_in.channels))
- ? AF_OK : AF_FALSE;
-
- if (r == AF_OK)
- r = configure_lavrr(af, in, out, true);
- return r;
- }
- case AF_CONTROL_SET_PLAYBACK_SPEED_RESAMPLE: {
- s->playback_speed = *(double *)arg;
- return AF_OK;
- }
- case AF_CONTROL_RESET:
- if (s->avrctx) {
-#if HAVE_LIBSWRESAMPLE
- swr_close(s->avrctx);
- if (swr_init(s->avrctx) < 0) {
- close_lavrr(af);
- return AF_ERROR;
- }
-#else
- while (avresample_read(s->avrctx, NULL, 1000) > 0) {}
-#endif
- }
- return AF_OK;
- }
- return AF_UNKNOWN;
-}
-
-static void uninit(struct af_instance *af)
-{
- close_lavrr(af);
-}
-
-// The LSB is always ignored.
-#if BYTE_ORDER == BIG_ENDIAN
-#define SHIFT24(x) ((3-(x))*8)
-#else
-#define SHIFT24(x) (((x)+1)*8)
-#endif
-
-static void extra_output_conversion(struct af_instance *af, struct mp_audio *mpa)
-{
- if (mpa->format == AF_FORMAT_S32 && af->data->format == AF_FORMAT_S24) {
- size_t len = mp_audio_psize(mpa) / mpa->bps;
- for (int s = 0; s < len; s++) {
- uint32_t val = *((uint32_t *)mpa->planes[0] + s);
- uint8_t *ptr = (uint8_t *)mpa->planes[0] + s * 3;
- ptr[0] = val >> SHIFT24(0);
- ptr[1] = val >> SHIFT24(1);
- ptr[2] = val >> SHIFT24(2);
- }
- mp_audio_set_format(mpa, AF_FORMAT_S24);
- }
-
- for (int p = 0; p < mpa->num_planes; p++) {
- void *ptr = mpa->planes[p];
- int total = mpa->samples * mpa->spf;
- if (af_fmt_from_planar(mpa->format) == AF_FORMAT_FLOAT) {
- for (int s = 0; s < total; s++)
- ((float *)ptr)[s] = av_clipf(((float *)ptr)[s], -1.0f, 1.0f);
- } else if (af_fmt_from_planar(mpa->format) == AF_FORMAT_DOUBLE) {
- for (int s = 0; s < total; s++)
- ((double *)ptr)[s] = MPCLAMP(((double *)ptr)[s], -1.0, 1.0);
- }
- }
-}
-
-// This relies on the tricky way mpa was allocated.
-static void reorder_planes(struct mp_audio *mpa, int *reorder,
- struct mp_chmap *newmap)
-{
- struct mp_audio prev = *mpa;
- mp_audio_set_channels(mpa, newmap);
-
- // The trailing planes were never written by avrctx, they're the NA channels.
- int next_na = prev.num_planes;
-
- for (int n = 0; n < mpa->num_planes; n++) {
- int src = reorder[n];
- assert(src >= -1 && src < prev.num_planes);
- if (src >= 0) {
- mpa->planes[n] = prev.planes[src];
- } else {
- assert(next_na < mpa->num_planes);
- mpa->planes[n] = prev.planes[next_na++];
- af_fill_silence(mpa->planes[n], mpa->sstride * mpa->samples,
- mpa->format);
- }
- }
-}
-
-static int filter_resample(struct af_instance *af, struct mp_audio *in)
-{
- struct af_resample *s = af->priv;
- struct mp_audio *out = NULL;
-
- if (!s->avrctx)
- goto error;
-
- int samples = get_out_samples(s, in ? in->samples : 0);
-
- struct mp_audio out_format = s->pool_fmt;
- out = mp_audio_pool_get(af->out_pool, &out_format, samples);
- if (!out)
- goto error;
- if (in)
- mp_audio_copy_attributes(out, in);
-
- if (out->samples) {
- out->samples = resample_frame(s->avrctx, out, in);
- if (out->samples < 0)
- goto error;
- }
-
- struct mp_audio real_out = *out;
- mp_audio_copy_config(out, &s->avrctx_fmt);
-
- if (out->samples && !mp_audio_config_equals(out, &s->pre_out_fmt)) {
- assert(af_fmt_is_planar(out->format) && out->format == real_out.format);
- reorder_planes(out, s->reorder_out, &s->pool_fmt.channels);
- if (!mp_audio_config_equals(out, &s->pre_out_fmt)) {
- struct mp_audio *new = mp_audio_pool_get(s->reorder_buffer,
- &s->pre_out_fmt,
- out->samples);
- if (!new)
- goto error;
- mp_audio_copy_attributes(new, out);
- int out_samples = resample_frame(s->avrctx_out, new, out);
- talloc_free(out);
- out = new;
- if (out_samples != new->samples)
- goto error;
- }
- }
-
- extra_output_conversion(af, out);
-
- talloc_free(in);
- if (out->samples) {
- af_add_output_frame(af, out);
- } else {
- talloc_free(out);
- }
-
- af->delay = get_delay(s);
-
- return 0;
-error:
- talloc_free(in);
- talloc_free(out);
- return -1;
-}
-
-static int filter(struct af_instance *af, struct mp_audio *in)
-{
- struct af_resample *s = af->priv;
-
- int new_rate = rate_from_speed(s->in_rate_af, s->playback_speed);
- bool need_reinit = fabs(new_rate / (double)s->in_rate - 1) > 0.01;
-
- if (s->avrctx) {
- AVRational r = av_d2q(s->playback_speed * s->in_rate_af / s->in_rate,
- INT_MAX / 2);
- // Essentially, swr/avresample_set_compensation() does 2 things:
- // - adjust output sample rate by sample_delta/compensation_distance
- // - reset the adjustment after compensation_distance output samples
- // Increase the compensation_distance to avoid undesired reset
- // semantics - we want to keep the ratio for the whole frame we're
- // feeding it, until the next filter() call.
- int mult = INT_MAX / 2 / MPMAX(MPMAX(abs(r.num), abs(r.den)), 1);
- r = (AVRational){ r.num * mult, r.den * mult };
- if (avresample_set_compensation(s->avrctx, r.den - r.num, r.den) < 0)
- need_reinit = true;
- }
-
- if (need_reinit && new_rate != s->in_rate) {
- // Before reconfiguring, drain the audio that is still buffered
- // in the resampler.
- filter_resample(af, NULL);
- // Reinitialize resampler.
- configure_lavrr(af, &af->fmt_in, &af->fmt_out, false);
- }
-
- return filter_resample(af, in);
-}
-
-static int af_open(struct af_instance *af)
-{
- struct af_resample *s = af->priv;
-
- af->control = control;
- af->uninit = uninit;
- af->filter_frame = filter;
-
- if (s->opts.cutoff <= 0.0)
- s->opts.cutoff = af_resample_default_cutoff(s->opts.filter_size);
-
- s->reorder_buffer = mp_audio_pool_create(s);
-
- return AF_OK;
-}
-
-#define OPT_BASE_STRUCT struct af_resample
-
-const struct af_info af_info_lavrresample = {
- .info = "Sample frequency conversion using libavresample",
- .name = "lavrresample",
- .open = af_open,
- .priv_size = sizeof(struct af_resample),
- .priv_defaults = &(const struct af_resample) {
- .opts = {
- .filter_size = 16,
- .cutoff = 0.0,
- .phase_shift = 10,
- .normalize = -1,
- },
- .playback_speed = 1.0,
- .allow_detach = 1,
- },
- .options = (const struct m_option[]) {
- OPT_INTRANGE("filter-size", opts.filter_size, 0, 0, 32),
- OPT_INTRANGE("phase-shift", opts.phase_shift, 0, 0, 30),
- OPT_FLAG("linear", opts.linear, 0),
- OPT_DOUBLE("cutoff", opts.cutoff, M_OPT_RANGE, .min = 0, .max = 1),
- OPT_FLAG("detach", allow_detach, 0),
- OPT_CHOICE("normalize", opts.normalize, 0,
- ({"no", 0}, {"yes", 1}, {"auto", -1})),
- OPT_KEYVALUELIST("o", avopts, 0),
- {0}
- },
-};
diff --git a/audio/filter/af_pan.c b/audio/filter/af_pan.c
deleted file mode 100644
index de2adf790c..0000000000
--- a/audio/filter/af_pan.c
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2002 Anders Johansson ajh@atri.curtin.edu.au
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <inttypes.h>
-#include <math.h>
-#include <limits.h>
-
-#include "common/common.h"
-#include "af.h"
-
-// Data for specific instances of this filter
-typedef struct af_pan_s {
- int nch; // Number of output channels; zero means same as input
- float level[AF_NCH][AF_NCH]; // Gain level for each channel
- char *matrixstr;
-} af_pan_t;
-
-static void set_channels(struct mp_audio *mpa, int num)
-{
- struct mp_chmap map;
- // "unknown" channel layouts make it easier to pass through audio data,
- // without triggering remixing.
- mp_chmap_set_unknown(&map, num);
- mp_audio_set_channels(mpa, &map);
-}
-
-static void parse_matrix(struct af_instance *af, const char *cp)
-{
- af_pan_t *s = af->priv;
- int j = 0, k = 0, n;
- while (*cp && k < AF_NCH) {
- sscanf(cp, "%f%n" , &s->level[j][k], &n);
- MP_VERBOSE(af, "Pan level from channel %i to"
- " channel %i = %f\n", k, j, s->level[j][k]);
- cp = &cp[n];
- j++;
- if (j >= s->nch) {
- j = 0;
- k++;
- }
- if (*cp != ',')
- break;
- cp++;
- }
-
-}
-
-// Initialization and runtime control
-static int control(struct af_instance *af, int cmd, void *arg)
-{
- af_pan_t* s = af->priv;
-
- switch(cmd){
- case AF_CONTROL_REINIT:
- // Sanity check
- if (!arg)
- return AF_ERROR;
-
- af->data->rate = ((struct mp_audio*)arg)->rate;
- mp_audio_set_format(af->data, AF_FORMAT_FLOAT);
- set_channels(af->data, s->nch ? s->nch : ((struct mp_audio*)arg)->nch);
-
- if ((af->data->format != ((struct mp_audio*)arg)->format) ||
- (af->data->bps != ((struct mp_audio*)arg)->bps)) {
- mp_audio_set_format((struct mp_audio*)arg, af->data->format);
- return AF_FALSE;
- }
- return AF_OK;
- case AF_CONTROL_SET_PAN_LEVEL: {
- int i;
- int ch = ((af_control_ext_t*)arg)->ch;
- float *level = ((af_control_ext_t*)arg)->arg;
- if (ch >= AF_NCH)
- return AF_FALSE;
- for (i = 0; i < AF_NCH; i++)
- s->level[ch][i] = level[i];
- return AF_OK;
- }
- case AF_CONTROL_SET_PAN_NOUT:
- // Reinit must be called after this function has been called
- // Sanity check
- if (((int*)arg)[0] <= 0 || ((int*)arg)[0] > AF_NCH) {
- MP_ERR(af, "The number of output channels must be"
- " between 1 and %i. Current value is %i\n",
- AF_NCH, ((int*)arg)[0]);
- return AF_ERROR;
- }
- s->nch = ((int*)arg)[0];
- return AF_OK;
- case AF_CONTROL_SET_PAN_BALANCE: {
- float val = *(float*)arg;
- if (s->nch)
- return AF_ERROR;
- if (af->data->nch >= 2) {
- s->level[0][0] = MPMIN(1.f, 1.f - val);
- s->level[0][1] = MPMAX(0.f, val);
- s->level[1][0] = MPMAX(0.f, -val);
- s->level[1][1] = MPMIN(1.f, 1.f + val);
- }
- return AF_OK;
- }
- case AF_CONTROL_GET_PAN_BALANCE:
- if (s->nch)
- return AF_ERROR;
- *(float*)arg = s->level[0][1] - s->level[1][0];
- return AF_OK;
- case AF_CONTROL_COMMAND: {
- char **args = arg;
- if (!strcmp(args[0], "set-matrix")) {
- parse_matrix(af, args[1]);
- return CONTROL_OK;
- } else {
- return CONTROL_ERROR;
- }
- }
- }
- return AF_UNKNOWN;
-}
-
-static int filter_frame(struct af_instance *af, struct mp_audio *c)
-{
- if (!c)
- return 0;
- struct mp_audio *l = mp_audio_pool_get(af->out_pool, &af->fmt_out, c->samples);
- if (!l) {
- talloc_free(c);
- return -1;
- }
- mp_audio_copy_attributes(l, c);
-
- af_pan_t* s = af->priv; // Setup for this instance
- float *in = c->planes[0]; // Input audio data
- float *out = NULL; // Output audio data
- float *end = in+c->samples * c->nch; // End of loop
- int nchi = c->nch; // Number of input channels
- int ncho = l->nch; // Number of output channels
- register int j, k;
-
- out = l->planes[0];
- // Execute panning
- // FIXME: Too slow
- while (in < end) {
- for (j = 0; j < ncho; j++) {
- register float x = 0.0;
- register float *tin = in;
- for (k = 0; k < nchi; k++)
- x += tin[k] * s->level[j][k];
- out[j] = x;
- }
- out += ncho;
- in += nchi;
- }
-
- talloc_free(c);
- af_add_output_frame(af, l);
- return 0;
-}
-
-// Allocate memory and set function pointers
-static int af_open(struct af_instance *af)
-{
- af->control = control;
- af->filter_frame = filter_frame;
- af_pan_t *s = af->priv;
- int nch = s->nch;
- if (nch && AF_OK != control(af, AF_CONTROL_SET_PAN_NOUT, &nch))
- return AF_ERROR;
-
- // Read pan values
- if (s->matrixstr)
- parse_matrix(af, s->matrixstr);
- return AF_OK;
-}
-
-#define OPT_BASE_STRUCT af_pan_t
-const struct af_info af_info_pan = {
- .info = "Panning audio filter",
- .name = "pan",
- .open = af_open,
- .priv_size = sizeof(af_pan_t),
- .options = (const struct m_option[]) {
- OPT_INTRANGE("channels", nch, 0, 0, AF_NCH),
- OPT_STRING("matrix", matrixstr, 0),
- {0}
- },
-};
diff --git a/audio/filter/af_rubberband.c b/audio/filter/af_rubberband.c
deleted file mode 100644
index a4deb3d48c..0000000000
--- a/audio/filter/af_rubberband.c
+++ /dev/null
@@ -1,251 +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 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdlib.h>
-#include <assert.h>
-
-#include <rubberband/rubberband-c.h>
-
-#include "common/common.h"
-#include "af.h"
-
-struct priv {
- RubberBandState rubber;
- double speed;
- double pitch;
- struct mp_audio *pending;
- bool needs_reset;
- // Estimate how much librubberband has buffered internally.
- // I could not find a way to do this with the librubberband API.
- double rubber_delay;
- // command line options
- int opt_transients, opt_detector, opt_phase, opt_window,
- opt_smoothing, opt_formant, opt_pitch, opt_channels;
-};
-
-static void update_speed(struct af_instance *af, double new_speed)
-{
- struct priv *p = af->priv;
-
- p->speed = new_speed;
- rubberband_set_time_ratio(p->rubber, 1.0 / p->speed);
-}
-
-static void update_pitch(struct af_instance *af, double new_pitch)
-{
- struct priv *p = af->priv;
-
- p->pitch = new_pitch;
- rubberband_set_pitch_scale(p->rubber, p->pitch);
-}
-
-static int control(struct af_instance *af, int cmd, void *arg)
-{
- struct priv *p = af->priv;
-
- switch (cmd) {
- case AF_CONTROL_REINIT: {
- struct mp_audio *in = arg;
- struct mp_audio orig_in = *in;
- struct mp_audio *out = af->data;
-
- in->format = AF_FORMAT_FLOATP;
- mp_audio_copy_config(out, in);
-
- if (p->rubber)
- rubberband_delete(p->rubber);
-
- int opts = p->opt_transients | p->opt_detector | p->opt_phase |
- p->opt_window | p->opt_smoothing | p->opt_formant |
- p->opt_pitch | p-> opt_channels |
- RubberBandOptionProcessRealTime;
-
- p->rubber = rubberband_new(in->rate, in->channels.num, opts, 1.0, 1.0);
- if (!p->rubber) {
- MP_FATAL(af, "librubberband initialization failed.\n");
- return AF_ERROR;
- }
-
- update_speed(af, p->speed);
- update_pitch(af, p->pitch);
- control(af, AF_CONTROL_RESET, NULL);
-
- return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
- }
- case AF_CONTROL_SET_PLAYBACK_SPEED: {
- update_speed(af, *(double *)arg);
- return AF_OK;
- }
- case AF_CONTROL_RESET:
- if (p->rubber)
- rubberband_reset(p->rubber);
- talloc_free(p->pending);
- p->pending = NULL;
- p->rubber_delay = 0;
- return AF_OK;
- case AF_CONTROL_COMMAND: {
- char **args = arg;
- if (!strcmp(args[0], "set-pitch")) {
- char *endptr;
- double pitch = strtod(args[1], &endptr);
- if (*endptr || pitch < 0.01 || pitch > 100.0)
- return CONTROL_ERROR;
- update_pitch(af, pitch);
- return CONTROL_OK;
- } else {
- return CONTROL_ERROR;
- }
- }
- }
- return AF_UNKNOWN;
-}
-
-static int filter_frame(struct af_instance *af, struct mp_audio *data)
-{
- struct priv *p = af->priv;
-
- talloc_free(p->pending);
- p->pending = data;
-
- return 0;
-}
-
-static int filter_out(struct af_instance *af)
-{
- struct priv *p = af->priv;
-
- while (rubberband_available(p->rubber) <= 0) {
- const float *dummy[MP_NUM_CHANNELS] = {0};
- const float **in_data = dummy;
- size_t in_samples = 0;
- if (p->pending) {
- if (!p->pending->samples)
- break;
-
- // recover from previous EOF
- if (p->needs_reset) {
- rubberband_reset(p->rubber);
- p->rubber_delay = 0;
- }
- p->needs_reset = false;
-
- size_t needs = rubberband_get_samples_required(p->rubber);
- in_data = (void *)&p->pending->planes;
- in_samples = MPMIN(p->pending->samples, needs);
- }
-
- if (p->needs_reset)
- break; // previous EOF
- p->needs_reset = !p->pending; // EOF
-
- rubberband_process(p->rubber, in_data, in_samples, p->needs_reset);
- p->rubber_delay += in_samples;
-
- if (!p->pending)
- break;
- mp_audio_skip_samples(p->pending, in_samples);
- }
-
- int out_samples = rubberband_available(p->rubber);
- if (out_samples > 0) {
- struct mp_audio *out =
- mp_audio_pool_get(af->out_pool, af->data, out_samples);
- if (!out)
- return -1;
- if (p->pending)
- mp_audio_copy_config(out, p->pending);
-
- float **out_data = (void *)&out->planes;
- out->samples = rubberband_retrieve(p->rubber, out_data, out->samples);
- p->rubber_delay -= out->samples * p->speed;
-
- af_add_output_frame(af, out);
- }
-
- int delay_samples = p->rubber_delay;
- if (p->pending)
- delay_samples += p->pending->samples;
- af->delay = delay_samples / (af->data->rate * p->speed);
-
- return 0;
-}
-
-static void uninit(struct af_instance *af)
-{
- struct priv *p = af->priv;
-
- if (p->rubber)
- rubberband_delete(p->rubber);
- talloc_free(p->pending);
-}
-
-static int af_open(struct af_instance *af)
-{
- af->control = control;
- af->filter_frame = filter_frame;
- af->filter_out = filter_out;
- af->uninit = uninit;
- return AF_OK;
-}
-
-#define OPT_BASE_STRUCT struct priv
-const struct af_info af_info_rubberband = {
- .info = "Pitch conversion with librubberband",
- .name = "rubberband",
- .open = af_open,
- .priv_size = sizeof(struct priv),
- .priv_defaults = &(const struct priv) {
- .speed = 1.0,
- .pitch = 1.0,
- .opt_pitch = RubberBandOptionPitchHighConsistency,
- .opt_transients = RubberBandOptionTransientsMixed,
- .opt_formant = RubberBandOptionFormantPreserved,
- .opt_channels = RubberBandOptionChannelsTogether,
- },
- .options = (const struct m_option[]) {
- OPT_CHOICE("transients", opt_transients, 0,
- ({"crisp", RubberBandOptionTransientsCrisp},
- {"mixed", RubberBandOptionTransientsMixed},
- {"smooth", RubberBandOptionTransientsSmooth})),
- OPT_CHOICE("detector", opt_detector, 0,
- ({"compound", RubberBandOptionDetectorCompound},
- {"percussive", RubberBandOptionDetectorPercussive},
- {"soft", RubberBandOptionDetectorSoft})),
- OPT_CHOICE("phase", opt_phase, 0,
- ({"laminar", RubberBandOptionPhaseLaminar},
- {"independent", RubberBandOptionPhaseIndependent})),
- OPT_CHOICE("window", opt_window, 0,
- ({"standard", RubberBandOptionWindowStandard},
- {"short", RubberBandOptionWindowShort},
- {"long", RubberBandOptionWindowLong})),
- OPT_CHOICE("smoothing", opt_smoothing, 0,
- ({"off", RubberBandOptionSmoothingOff},
- {"on", RubberBandOptionSmoothingOn})),
- OPT_CHOICE("formant", opt_formant, 0,
- ({"shifted", RubberBandOptionFormantShifted},
- {"preserved", RubberBandOptionFormantPreserved})),
- OPT_CHOICE("pitch", opt_pitch, 0,
- ({"quality", RubberBandOptionPitchHighQuality},
- {"speed", RubberBandOptionPitchHighSpeed},
- {"consistency", RubberBandOptionPitchHighConsistency})),
- OPT_CHOICE("channels", opt_channels, 0,
- ({"apart", RubberBandOptionChannelsApart},
- {"together", RubberBandOptionChannelsTogether})),
- OPT_DOUBLE("pitch-scale", pitch, M_OPT_RANGE, .min = 0.01, .max = 100),
- {0}
- },
-};
diff --git a/audio/filter/af_scaletempo.c b/audio/filter/af_scaletempo.c
deleted file mode 100644
index 4f0eb13091..0000000000
--- a/audio/filter/af_scaletempo.c
+++ /dev/null
@@ -1,494 +0,0 @@
-/*
- * scaletempo audio filter
- *
- * scale tempo while maintaining pitch
- * (WSOLA technique with cross correlation)
- * inspired by SoundTouch library by Olli Parviainen
- *
- * basic algorithm
- * - produce 'stride' output samples per loop
- * - consume stride*scale input samples per loop
- *
- * to produce smoother transitions between strides, blend next overlap
- * samples from last stride with correlated samples of current input
- *
- * Copyright (c) 2007 Robert Juliano
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-#include <assert.h>
-
-#include "common/common.h"
-
-#include "af.h"
-#include "options/m_option.h"
-
-// Data for specific instances of this filter
-typedef struct af_scaletempo_s
-{
- // stride
- float scale;
- float speed;
- int frames_stride;
- float frames_stride_scaled;
- float frames_stride_error;
- int bytes_per_frame;
- int bytes_stride;
- int bytes_queue;
- int bytes_queued;
- int bytes_to_slide;
- int8_t *buf_queue;
- // overlap
- int samples_overlap;
- int samples_standing;
- int bytes_overlap;
- int bytes_standing;
- void *buf_overlap;
- void *table_blend;
- void (*output_overlap)(struct af_scaletempo_s *s, void *out_buf,
- int bytes_off);
- // best overlap
- int frames_search;
- int num_channels;
- void *buf_pre_corr;
- void *table_window;
- int (*best_overlap_offset)(struct af_scaletempo_s *s);
- // command line
- float scale_nominal;
- float ms_stride;
- float percent_overlap;
- float ms_search;
-#define SCALE_TEMPO 1
-#define SCALE_PITCH 2
- int speed_opt;
-} af_scaletempo_t;
-
-static int fill_queue(struct af_instance *af, struct mp_audio *data, int offset)
-{
- af_scaletempo_t *s = af->priv;
- int bytes_in = (data ? mp_audio_psize(data) : 0) - offset;
- int offset_unchanged = offset;
-
- if (s->bytes_to_slide > 0) {
- if (s->bytes_to_slide < s->bytes_queued) {
- int bytes_move = s->bytes_queued - s->bytes_to_slide;
- memmove(s->buf_queue, s->buf_queue + s->bytes_to_slide, bytes_move);
- s->bytes_to_slide = 0;
- s->bytes_queued = bytes_move;
- } else {
- int bytes_skip;
- s->bytes_to_slide -= s->bytes_queued;
- bytes_skip = MPMIN(s->bytes_to_slide, bytes_in);
- s->bytes_queued = 0;
- s->bytes_to_slide -= bytes_skip;
- offset += bytes_skip;
- bytes_in -= bytes_skip;
- }
- }
-
- if (bytes_in > 0) {
- int bytes_copy = MPMIN(s->bytes_queue - s->bytes_queued, bytes_in);
- assert(bytes_copy >= 0);
- memcpy(s->buf_queue + s->bytes_queued,
- (int8_t *)data->planes[0] + offset, bytes_copy);
- s->bytes_queued += bytes_copy;
- offset += bytes_copy;
- }
-
- return offset - offset_unchanged;
-}
-
-#define UNROLL_PADDING (4 * 4)
-
-static int best_overlap_offset_float(af_scaletempo_t *s)
-{
- float best_corr = INT_MIN;
- int best_off = 0;
-
- float *pw = s->table_window;
- float *po = s->buf_overlap;
- po += s->num_channels;
- float *ppc = s->buf_pre_corr;
- for (int i = s->num_channels; i < s->samples_overlap; i++)
- *ppc++ = *pw++ **po++;
-
- float *search_start = (float *)s->buf_queue + s->num_channels;
- for (int off = 0; off < s->frames_search; off++) {
- float corr = 0;
- float *ps = search_start;
- ppc = s->buf_pre_corr;
- for (int i = s->num_channels; i < s->samples_overlap; i++)
- corr += *ppc++ **ps++;
- if (corr > best_corr) {
- best_corr = corr;
- best_off = off;
- }
- search_start += s->num_channels;
- }
-
- return best_off * 4 * s->num_channels;
-}
-
-static int best_overlap_offset_s16(af_scaletempo_t *s)
-{
- int64_t best_corr = INT64_MIN;
- int best_off = 0;
-
- int32_t *pw = s->table_window;
- int16_t *po = s->buf_overlap;
- po += s->num_channels;
- int32_t *ppc = s->buf_pre_corr;
- for (long i = s->num_channels; i < s->samples_overlap; i++)
- *ppc++ = (*pw++ **po++) >> 15;
-
- int16_t *search_start = (int16_t *)s->buf_queue + s->num_channels;
- for (int off = 0; off < s->frames_search; off++) {
- int64_t corr = 0;
- int16_t *ps = search_start;
- ppc = s->buf_pre_corr;
- ppc += s->samples_overlap - s->num_channels;
- ps += s->samples_overlap - s->num_channels;
- long i = -(s->samples_overlap - s->num_channels);
- do {
- corr += ppc[i + 0] * ps[i + 0];
- corr += ppc[i + 1] * ps[i + 1];
- corr += ppc[i + 2] * ps[i + 2];
- corr += ppc[i + 3] * ps[i + 3];
- i += 4;
- } while (i < 0);
- if (corr > best_corr) {
- best_corr = corr;
- best_off = off;
- }
- search_start += s->num_channels;
- }
-
- return best_off * 2 * s->num_channels;
-}
-
-static void output_overlap_float(af_scaletempo_t *s, void *buf_out,
- int bytes_off)
-{
- float *pout = buf_out;
- float *pb = s->table_blend;
- float *po = s->buf_overlap;
- float *pin = (float *)(s->buf_queue + bytes_off);
- for (int i = 0; i < s->samples_overlap; i++) {
- *pout++ = *po - *pb++ *(*po - *pin++);
- po++;
- }
-}
-
-static void output_overlap_s16(af_scaletempo_t *s, void *buf_out,
- int bytes_off)
-{
- int16_t *pout = buf_out;
- int32_t *pb = s->table_blend;
- int16_t *po = s->buf_overlap;
- int16_t *pin = (int16_t *)(s->buf_queue + bytes_off);
- for (int i = 0; i < s->samples_overlap; i++) {
- *pout++ = *po - ((*pb++ *(*po - *pin++)) >> 16);
- po++;
- }
-}
-
-static int filter(struct af_instance *af, struct mp_audio *data)
-{
- af_scaletempo_t *s = af->priv;
-
- if (s->scale == 1.0) {
- af->delay = 0;
- af_add_output_frame(af, data);
- return 0;
- }
-
- int in_samples = data ? data->samples : 0;
- struct mp_audio *out = mp_audio_pool_get(af->out_pool, af->data,
- ((int)(in_samples / s->frames_stride_scaled) + 1) * s->frames_stride);
- if (!out) {
- talloc_free(data);
- return -1;
- }
- if (data)
- mp_audio_copy_attributes(out, data);
-
- int offset_in = fill_queue(af, data, 0);
- int8_t *pout = out->planes[0];
- while (s->bytes_queued >= s->bytes_queue) {
- int ti;
- float tf;
- int bytes_off = 0;
-
- // output stride
- if (s->output_overlap) {
- if (s->best_overlap_offset)
- bytes_off = s->best_overlap_offset(s);
- s->output_overlap(s, pout, bytes_off);
- }
- memcpy(pout + s->bytes_overlap,
- s->buf_queue + bytes_off + s->bytes_overlap,
- s->bytes_standing);
- pout += s->bytes_stride;
-
- // input stride
- memcpy(s->buf_overlap,
- s->buf_queue + bytes_off + s->bytes_stride,
- s->bytes_overlap);
- tf = s->frames_stride_scaled + s->frames_stride_error;
- ti = (int)tf;
- s->frames_stride_error = tf - ti;
- s->bytes_to_slide = ti * s->bytes_per_frame;
-
- offset_in += fill_queue(af, data, offset_in);
- }
-
- // This filter can have a negative delay when scale > 1:
- // output corresponding to some length of input can be decided and written
- // after receiving only a part of that input.
- af->delay = (s->bytes_queued - s->bytes_to_slide) / s->scale
- / out->sstride / out->rate;
-
- out->samples = (pout - (int8_t *)out->planes[0]) / out->sstride;
- talloc_free(data);
- if (out->samples) {
- af_add_output_frame(af, out);
- } else {
- talloc_free(out);
- }
- return 0;
-}
-
-static void update_speed(struct af_instance *af, float speed)
-{
- af_scaletempo_t *s = af->priv;
-
- s->speed = speed;
-
- double factor = (s->speed_opt & SCALE_PITCH) ? 1.0 / s->speed : s->speed;
- s->scale = factor * s->scale_nominal;
-
- s->frames_stride_scaled = s->scale * s->frames_stride;
- s->frames_stride_error = MPMIN(s->frames_stride_error, s->frames_stride_scaled);
-}
-
-// Initialization and runtime control
-static int control(struct af_instance *af, int cmd, void *arg)
-{
- af_scaletempo_t *s = af->priv;
- switch (cmd) {
- case AF_CONTROL_REINIT: {
- struct mp_audio *data = (struct mp_audio *)arg;
- float srate = data->rate / 1000.0;
- int nch = data->nch;
- int use_int = 0;
-
- mp_audio_force_interleaved_format(data);
- mp_audio_copy_config(af->data, data);
-
- if (data->format == AF_FORMAT_S16) {
- use_int = 1;
- } else {
- mp_audio_set_format(af->data, AF_FORMAT_FLOAT);
- }
- int bps = af->data->bps;
-
- s->frames_stride = srate * s->ms_stride;
- s->bytes_stride = s->frames_stride * bps * nch;
- af->delay = 0;
-
- update_speed(af, s->speed);
-
- int frames_overlap = s->frames_stride * s->percent_overlap;
- if (frames_overlap <= 0) {
- s->bytes_standing = s->bytes_stride;
- s->samples_standing = s->bytes_standing / bps;
- s->output_overlap = NULL;
- s->bytes_overlap = 0;
- } else {
- s->samples_overlap = frames_overlap * nch;
- s->bytes_overlap = frames_overlap * nch * bps;
- s->bytes_standing = s->bytes_stride - s->bytes_overlap;
- s->samples_standing = s->bytes_standing / bps;
- s->buf_overlap = realloc(s->buf_overlap, s->bytes_overlap);
- s->table_blend = realloc(s->table_blend, s->bytes_overlap * 4);
- if (!s->buf_overlap || !s->table_blend) {
- MP_FATAL(af, "Out of memory\n");
- return AF_ERROR;
- }
- memset(s->buf_overlap, 0, s->bytes_overlap);
- if (use_int) {
- int32_t *pb = s->table_blend;
- int64_t blend = 0;
- for (int i = 0; i < frames_overlap; i++) {
- int32_t v = blend / frames_overlap;
- for (int j = 0; j < nch; j++)
- *pb++ = v;
- blend += 65536; // 2^16
- }
- s->output_overlap = output_overlap_s16;
- } else {
- float *pb = s->table_blend;
- for (int i = 0; i < frames_overlap; i++) {
- float v = i / (float)frames_overlap;
- for (int j = 0; j < nch; j++)
- *pb++ = v;
- }
- s->output_overlap = output_overlap_float;
- }
- }
-
- s->frames_search = (frames_overlap > 1) ? srate * s->ms_search : 0;
- if (s->frames_search <= 0)
- s->best_overlap_offset = NULL;
- else {
- if (use_int) {
- int64_t t = frames_overlap;
- int32_t n = 8589934588LL / (t * t); // 4 * (2^31 - 1) / t^2
- s->buf_pre_corr = realloc(s->buf_pre_corr,
- s->bytes_overlap * 2 + UNROLL_PADDING);
- s->table_window = realloc(s->table_window,
- s->bytes_overlap * 2 - nch * bps * 2);
- if (!s->buf_pre_corr || !s->table_window) {
- MP_FATAL(af, "Out of memory\n");
- return AF_ERROR;
- }
- memset((char *)s->buf_pre_corr + s->bytes_overlap * 2, 0,
- UNROLL_PADDING);
- int32_t *pw = s->table_window;
- for (int i = 1; i < frames_overlap; i++) {
- int32_t v = (i * (t - i) * n) >> 15;
- for (int j = 0; j < nch; j++)
- *pw++ = v;
- }
- s->best_overlap_offset = best_overlap_offset_s16;
- } else {
- s->buf_pre_corr = realloc(s->buf_pre_corr, s->bytes_overlap);
- s->table_window = realloc(s->table_window,
- s->bytes_overlap - nch * bps);
- if (!s->buf_pre_corr || !s->table_window) {
- MP_FATAL(af, "Out of memory\n");
- return AF_ERROR;
- }
- float *pw = s->table_window;
- for (int i = 1; i < frames_overlap; i++) {
- float v = i * (frames_overlap - i);
- for (int j = 0; j < nch; j++)
- *pw++ = v;
- }
- s->best_overlap_offset = best_overlap_offset_float;
- }
- }
-
- s->bytes_per_frame = bps * nch;
- s->num_channels = nch;
-
- s->bytes_queue = (s->frames_search + s->frames_stride + frames_overlap)
- * bps * nch;
- s->buf_queue = realloc(s->buf_queue, s->bytes_queue + UNROLL_PADDING);
- if (!s->buf_queue) {
- MP_FATAL(af, "Out of memory\n");
- return AF_ERROR;
- }
-
- s->bytes_queued = 0;
- s->bytes_to_slide = 0;
-
- MP_DBG(af, ""
- "%.2f stride_in, %i stride_out, %i standing, "
- "%i overlap, %i search, %i queue, %s mode\n",
- s->frames_stride_scaled,
- (int)(s->bytes_stride / nch / bps),
- (int)(s->bytes_standing / nch / bps),
- (int)(s->bytes_overlap / nch / bps),
- s->frames_search,
- (int)(s->bytes_queue / nch / bps),
- (use_int ? "s16" : "float"));
-
- return af_test_output(af, (struct mp_audio *)arg);
- }
- case AF_CONTROL_SET_PLAYBACK_SPEED: {
- double speed = *(double *)arg;
- if (s->speed_opt & SCALE_TEMPO) {
- if (s->speed_opt & SCALE_PITCH)
- break;
- update_speed(af, speed);
- } else if (s->speed_opt & SCALE_PITCH) {
- update_speed(af, speed);
- break; // do not signal OK
- }
- return AF_OK;
- }
- case AF_CONTROL_RESET:
- s->bytes_queued = 0;
- s->bytes_to_slide = 0;
- s->frames_stride_error = 0;
- memset(s->buf_overlap, 0, s->bytes_overlap);
- }
- return AF_UNKNOWN;
-}
-
-// Deallocate memory
-static void uninit(struct af_instance *af)
-{
- af_scaletempo_t *s = af->priv;
- free(s->buf_queue);
- free(s->buf_overlap);
- free(s->buf_pre_corr);
- free(s->table_blend);
- free(s->table_window);
-}
-
-// Allocate memory and set function pointers
-static int af_open(struct af_instance *af)
-{
- af->control = control;
- af->uninit = uninit;
- af->filter_frame = filter;
- return AF_OK;
-}
-
-#define OPT_BASE_STRUCT af_scaletempo_t
-
-const struct af_info af_info_scaletempo = {
- .info = "Scale audio tempo while maintaining pitch",
- .name = "scaletempo",
- .open = af_open,
- .priv_size = sizeof(af_scaletempo_t),
- .priv_defaults = &(const af_scaletempo_t) {
- .ms_stride = 60,
- .percent_overlap = .20,
- .ms_search = 14,
- .speed_opt = SCALE_TEMPO,
- .speed = 1.0,
- .scale_nominal = 1.0,
- },
- .options = (const struct m_option[]) {
- OPT_FLOAT("scale", scale_nominal, M_OPT_MIN, .min = 0.01),
- OPT_FLOAT("stride", ms_stride, M_OPT_MIN, .min = 0.01),
- OPT_FLOAT("overlap", percent_overlap, M_OPT_RANGE, .min = 0, .max = 1),
- OPT_FLOAT("search", ms_search, M_OPT_MIN, .min = 0),
- OPT_CHOICE("speed", speed_opt, 0,
- ({"pitch", SCALE_PITCH},
- {"tempo", SCALE_TEMPO},
- {"none", 0},
- {"both", SCALE_TEMPO | SCALE_PITCH})),
- {0}
- },
-};
diff --git a/audio/filter/af_volume.c b/audio/filter/af_volume.c
deleted file mode 100644
index e1d5d45e89..0000000000
--- a/audio/filter/af_volume.c
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C)2002 Anders Johansson ajh@atri.curtin.edu.au
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <inttypes.h>
-#include <math.h>
-#include <limits.h>
-
-#include "common/common.h"
-#include "af.h"
-#include "demux/demux.h"
-
-struct priv {
- float vol; // User-specified non-linear volume
- float level; // User-specified gain level for each channel
- float rgain; // Replaygain level
- int rgain_track; // Enable/disable track based replaygain
- int rgain_album; // Enable/disable album based replaygain
- float rgain_preamp; // Set replaygain pre-amplification
- int rgain_clip; // Enable/disable clipping prevention
- float replaygain_fallback;
- int soft; // Enable/disable soft clipping
- int fast; // Use fix-point volume control
- int detach; // Detach if gain volume is neutral
- float cfg_volume;
-};
-
-// Convert to gain value from dB. input <= -200dB will become 0 gain.
-static float from_dB(float in, float k, float mi, float ma)
-{
- if (in <= -200)
- return 0.0;
- return pow(10.0, MPCLAMP(in, mi, ma) / k);
-}
-
-static int control(struct af_instance *af, int cmd, void *arg)
-{
- struct priv *s = af->priv;
-
- switch (cmd) {
- case AF_CONTROL_REINIT: {
- struct mp_audio *in = arg;
-
- mp_audio_copy_config(af->data, in);
- mp_audio_force_interleaved_format(af->data);
-
- if (s->fast && af_fmt_from_planar(in->format) != AF_FORMAT_FLOAT) {
- mp_audio_set_format(af->data, AF_FORMAT_S16);
- } else {
- mp_audio_set_format(af->data, AF_FORMAT_FLOAT);
- }
- if (af_fmt_is_planar(in->format))
- mp_audio_set_format(af->data, af_fmt_to_planar(af->data->format));
- s->rgain = 1.0;
- struct replaygain_data *rg = af->replaygain_data;
- if ((s->rgain_track || s->rgain_album) && rg) {
- MP_VERBOSE(af, "Replaygain: Track=%f/%f Album=%f/%f\n",
- rg->track_gain, rg->track_peak,
- rg->album_gain, rg->album_peak);
-
- float gain, peak;
- if (s->rgain_track) {
- gain = rg->track_gain;
- peak = rg->track_peak;
- } else {
- gain = rg->album_gain;
- peak = rg->album_peak;
- }
-
- gain += s->rgain_preamp;
- s->rgain = from_dB(gain, 20.0, -200.0, 60.0);
-
- MP_VERBOSE(af, "Applying replay-gain: %f\n", s->rgain);
-
- if (!s->rgain_clip) { // clipping prevention
- s->rgain = MPMIN(s->rgain, 1.0 / peak);
- MP_VERBOSE(af, "...with clipping prevention: %f\n", s->rgain);
- }
- } else if (s->replaygain_fallback) {
- s->rgain = from_dB(s->replaygain_fallback, 20.0, -200.0, 60.0);
- MP_VERBOSE(af, "Applying fallback gain: %f\n", s->rgain);
- }
- if (s->detach && fabs(s->level * s->rgain - 1.0) < 0.00001)
- return AF_DETACH;
- return af_test_output(af, in);
- }
- case AF_CONTROL_SET_VOLUME:
- s->vol = *(float *)arg;
- s->level = pow(s->vol, 3);
- MP_VERBOSE(af, "volume gain: %f\n", s->level);
- return AF_OK;
- case AF_CONTROL_GET_VOLUME:
- *(float *)arg = s->vol;
- return AF_OK;
- }
- return AF_UNKNOWN;
-}
-
-static void filter_plane(struct af_instance *af, struct mp_audio *data, int p)
-{
- struct priv *s = af->priv;
-
- float level = s->level * s->rgain * from_dB(s->cfg_volume, 20.0, -200.0, 60.0);
- int num_samples = data->samples * data->spf;
-
- if (af_fmt_from_planar(af->data->format) == AF_FORMAT_S16) {
- int vol = 256.0 * level;
- if (vol != 256) {
- if (af_make_writeable(af, data) < 0)
- return; // oom
- int16_t *a = data->planes[p];
- for (int i = 0; i < num_samples; i++) {
- int x = (a[i] * vol) >> 8;
- a[i] = MPCLAMP(x, SHRT_MIN, SHRT_MAX);
- }
- }
- } else if (af_fmt_from_planar(af->data->format) == AF_FORMAT_FLOAT) {
- float vol = level;
- if (vol != 1.0) {
- if (af_make_writeable(af, data) < 0)
- return; // oom
- float *a = data->planes[p];
- for (int i = 0; i < num_samples; i++) {
- float x = a[i] * vol;
- a[i] = s->soft ? af_softclip(x) : MPCLAMP(x, -1.0, 1.0);
- }
- }
- }
-}
-
-static int filter(struct af_instance *af, struct mp_audio *data)
-{
- if (data) {
- for (int n = 0; n < data->num_planes; n++)
- filter_plane(af, data, n);
- af_add_output_frame(af, data);
- }
- return 0;
-}
-
-static int af_open(struct af_instance *af)
-{
- struct priv *s = af->priv;
- af->control = control;
- af->filter_frame = filter;
- s->level = 1.0;
- return AF_OK;
-}
-
-#define OPT_BASE_STRUCT struct priv
-
-// Description of this filter
-const struct af_info af_info_volume = {
- .info = "Volume control audio filter",
- .name = "volume",
- .open = af_open,
- .priv_size = sizeof(struct priv),
- .options = (const struct m_option[]) {
- OPT_FLOATRANGE("volumedb", cfg_volume, 0, -200, 60),
- OPT_FLAG("replaygain-track", rgain_track, 0),
- OPT_FLAG("replaygain-album", rgain_album, 0),
- OPT_FLOATRANGE("replaygain-preamp", rgain_preamp, 0, -15, 15),
- OPT_FLAG("replaygain-clip", rgain_clip, 0),
- OPT_FLOATRANGE("replaygain-fallback", replaygain_fallback, 0, -200, 60),
- OPT_FLAG("softclip", soft, 0),
- OPT_FLAG("s16", fast, 0),
- OPT_FLAG("detach", detach, 0),
- {0}
- },
-};
diff --git a/audio/filter/equalizer.h b/audio/filter/equalizer.h
deleted file mode 100644
index db68235c48..0000000000
--- a/audio/filter/equalizer.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2002 Anders Johansson ajh@atri.curtin.edu.au
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#ifndef MPLAYER_EQUALIZER_H
-#define MPLAYER_EQUALIZER_H
-
-/* Equalizer plugin header file defines struct used for setting or
- getting the gain of a specific channel and frequency */
-
-typedef struct equalizer_s
-{
- float gain; // Gain in dB -15 - 15
- int channel; // Channel number 0 - 5
- int band; // Frequency band 0 - 9
-}equalizer_t;
-
-/* The different frequency bands are:
-nr. center frequency
-0 31.25 Hz
-1 62.50 Hz
-2 125.0 Hz
-3 250.0 Hz
-4 500.0 Hz
-5 1.000 kHz
-6 2.000 kHz
-7 4.000 kHz
-8 8.000 kHz
-9 16.00 kHz
-*/
-
-#endif /* MPLAYER_EQUALIZER_H */
diff --git a/audio/filter/tools.c b/audio/filter/tools.c
deleted file mode 100644
index 4ebea64d4a..0000000000
--- a/audio/filter/tools.c
+++ /dev/null
@@ -1,72 +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 <http://www.gnu.org/licenses/>.
- */
-
-#include <math.h>
-#include <string.h>
-
-#include "common/common.h"
-#include "af.h"
-
-/* Convert from ms to sample time */
-int af_from_ms(int n, float* in, int* out, int rate, float mi, float ma)
-{
- int i = 0;
- // Sanity check
- if(!in || !out)
- return AF_ERROR;
-
- for(i=0;i<n;i++)
- out[i]=(int)((float)rate * MPCLAMP(in[i],mi,ma)/1000.0);
-
- return AF_OK;
-}
-
-/*
- * test if output format matches
- * af: audio filter
- * out: needed format, will be overwritten by available
- * format if they do not match
- * returns: AF_FALSE if formats do not match, AF_OK if they match
- *
- * compares the format, rate and nch values of af->data with out
- * Note: logically, *out=*af->data always happens, because out contains the
- * format only, no actual audio data or memory allocations. *out always
- * contains the parameters from af->data after the function returns.
- */
-int af_test_output(struct af_instance* af, struct mp_audio* out)
-{
- if((af->data->format != out->format) ||
- (af->data->bps != out->bps) ||
- (af->data->rate != out->rate) ||
- !mp_chmap_equals(&af->data->channels, &out->channels)){
- *out = *af->data;
- return AF_FALSE;
- }
- return AF_OK;
-}
-
-/* Soft clipping, the sound of a dream, thanks to Jon Wattes
- post to Musicdsp.org */
-float af_softclip(float a)
-{
- if (a >= M_PI/2)
- return 1.0;
- else if (a <= -M_PI/2)
- return -1.0;
- else
- return sin(a);
-}
diff --git a/audio/format.c b/audio/format.c
index bbe0cec9bb..811d15e4f8 100644
--- a/audio/format.c
+++ b/audio/format.c
@@ -25,7 +25,7 @@
#include <assert.h>
#include "common/common.h"
-#include "audio/filter/af.h"
+#include "audio/format.h"
// number of bytes per sample, 0 if invalid/unknown
int af_fmt_to_bytes(int format)
diff --git a/options/options.c b/options/options.c
index 0cb653c4a9..cd54c8dddf 100644
--- a/options/options.c
+++ b/options/options.c
@@ -42,7 +42,6 @@
#include "video/hwdec.h"
#include "video/image_writer.h"
#include "sub/osd.h"
-#include "audio/filter/af.h"
#include "audio/decode/dec_audio.h"
#include "player/core.h"
#include "player/command.h"
@@ -427,8 +426,8 @@ const m_option_t mp_opts[] = {
// ------------------------- codec/vfilter options --------------------
- OPT_SETTINGSLIST("af-defaults", af_defs, 0, &af_obj_list, ),
- OPT_SETTINGSLIST("af*", af_settings, 0, &af_obj_list, ),
+ //OPT_SETTINGSLIST("af-defaults", af_defs, 0, &af_obj_list, ),
+ //OPT_SETTINGSLIST("af*", af_settings, 0, &af_obj_list, ),
OPT_SETTINGSLIST("vf-defaults", vf_defs, 0, &vf_obj_list, ),
OPT_SETTINGSLIST("vf*", vf_settings, 0, &vf_obj_list, ),
diff --git a/player/audio.c b/player/audio.c
index d15f4e9869..b0aa876ab4 100644
--- a/player/audio.c
+++ b/player/audio.c
@@ -22,6 +22,13 @@
#include <math.h>
#include <assert.h>
+#include <libavutil/opt.h>
+#include <libavutil/common.h>
+#include <libavutil/samplefmt.h>
+#include <libavutil/channel_layout.h>
+#include <libavutil/mathematics.h>
+#include <libswresample/swresample.h>
+
#include "config.h"
#include "mpv_talloc.h"
@@ -33,8 +40,8 @@
#include "audio/audio.h"
#include "audio/audio_buffer.h"
+#include "audio/fmt-conversion.h"
#include "audio/decode/dec_audio.h"
-#include "audio/filter/af.h"
#include "audio/out/ao.h"
#include "demux/demux.h"
#include "video/decode/dec_video.h"
@@ -51,18 +58,11 @@ enum {
AD_NO_PROGRESS = -5,
};
-// Use pitch correction only for speed adjustments by the user, not minor sync
-// correction ones.
-static int get_speed_method(struct MPContext *mpctx)
-{
- return mpctx->opts->pitch_correction && mpctx->opts->playback_speed != 1.0
- ? AF_CONTROL_SET_PLAYBACK_SPEED : AF_CONTROL_SET_PLAYBACK_SPEED_RESAMPLE;
-}
-
// Try to reuse the existing filters to change playback speed. If it works,
// return true; if filter recreation is needed, return false.
static bool update_speed_filters(struct MPContext *mpctx)
{
+ /*
struct af_stream *afs = mpctx->ao_chain->af;
double speed = mpctx->audio_speed;
@@ -84,11 +84,15 @@ static bool update_speed_filters(struct MPContext *mpctx)
return true;
return !!af_control_any_rev(afs, get_speed_method(mpctx), &speed);
+ */
+ return false;
}
// Update speed, and insert/remove filters if necessary.
static void recreate_speed_filters(struct MPContext *mpctx)
{
+ goto fail;
+ /*
struct af_stream *afs = mpctx->ao_chain->af;
if (update_speed_filters(mpctx))
@@ -111,6 +115,7 @@ static void recreate_speed_filters(struct MPContext *mpctx)
goto fail;
return;
+ */
fail:
mpctx->opts->playback_speed = 1.0;
@@ -122,6 +127,7 @@ fail:
// Called when opts->softvol_volume or opts->softvol_mute were changed.
void audio_update_volume(struct MPContext *mpctx)
{
+ /*
struct MPOpts *opts = mpctx->opts;
struct ao_chain *ao_c = mpctx->ao_chain;
if (!ao_c || ao_c->af->initialized < 1)
@@ -139,6 +145,7 @@ void audio_update_volume(struct MPContext *mpctx)
&& af_control_any_rev(ao_c->af, AF_CONTROL_SET_VOLUME, &gain)))
MP_ERR(mpctx, "No volume control available.\n");
}
+ */
}
/* NOTE: Currently the balance code is seriously buggy: it always changes
@@ -151,6 +158,7 @@ void audio_update_volume(struct MPContext *mpctx)
*/
void audio_update_balance(struct MPContext *mpctx)
{
+#if 0
struct MPOpts *opts = mpctx->opts;
struct ao_chain *ao_c = mpctx->ao_chain;
if (!ao_c || ao_c->af->initialized < 1)
@@ -180,11 +188,13 @@ void audio_update_balance(struct MPContext *mpctx)
}
af_pan_balance->control(af_pan_balance, AF_CONTROL_SET_PAN_BALANCE, &val);
+#endif
}
static int recreate_audio_filters(struct MPContext *mpctx)
{
assert(mpctx->ao_chain);
+ /*
struct af_stream *afs = mpctx->ao_chain->af;
if (afs->initialized < 1 && af_init(afs) < 0)
@@ -193,6 +203,7 @@ static int recreate_audio_filters(struct MPContext *mpctx)
recreate_speed_filters(mpctx);
if (afs->initialized < 1 && af_init(afs) < 0)
goto fail;
+ */
if (mpctx->opts->softvol == SOFTVOL_NO)
MP_ERR(mpctx, "--softvol=no is not supported anymore.\n");
@@ -215,6 +226,7 @@ int reinit_audio_filters(struct MPContext *mpctx)
if (!ao_c)
return 0;
+ /*
double delay = 0;
if (ao_c->af->initialized > 0)
delay = af_calc_delay(ao_c->af);
@@ -231,6 +243,7 @@ int reinit_audio_filters(struct MPContext *mpctx)
queue_seek(mpctx, MPSEEK_ABSOLUTE, mpctx->playback_pts,
MPSEEK_EXACT, 0);
}
+ */
return 1;
}
@@ -240,7 +253,7 @@ void update_playback_speed(struct MPContext *mpctx)
mpctx->audio_speed = mpctx->opts->playback_speed * mpctx->speed_factor_a;
mpctx->video_speed = mpctx->opts->playback_speed * mpctx->speed_factor_v;
- if (!mpctx->ao_chain || mpctx->ao_chain->af->initialized < 1)
+ if (!mpctx->ao_chain /*|| mpctx->ao_chain->af->initialized < 1*/)
return;
if (!update_speed_filters(mpctx))
@@ -253,7 +266,7 @@ static void ao_chain_reset_state(struct ao_chain *ao_c)
ao_c->pts_reset = false;
talloc_free(ao_c->input_frame);
ao_c->input_frame = NULL;
- af_seek_reset(ao_c->af);
+ //af_seek_reset(ao_c->af);
mp_audio_buffer_clear(ao_c->ao_buffer);
if (ao_c->audio_src)
@@ -300,7 +313,7 @@ static void ao_chain_uninit(struct ao_chain *ao_c)
if (ao_c->filter_src)
lavfi_set_connected(ao_c->filter_src, false);
- af_destroy(ao_c->af);
+ //af_destroy(ao_c->af);
talloc_free(ao_c->input_frame);
talloc_free(ao_c->ao_buffer);
talloc_free(ao_c);
@@ -324,7 +337,7 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
struct ao_chain *ao_c = mpctx->ao_chain;
assert(ao_c);
struct track *track = ao_c->track;
- struct af_stream *afs = ao_c->af;
+ //struct af_stream *afs = ao_c->af;
if (ao_c->input_frame)
mp_audio_copy_config(&ao_c->input_format, ao_c->input_frame);
@@ -345,35 +358,25 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
uninit_audio_out(mpctx);
}
- if (mpctx->ao && mp_audio_config_equals(&in_format, &afs->input))
+ // for now, always resample to the first format the AO was initialized with
+ if (mpctx->ao)
return;
- afs->output = (struct mp_audio){0};
+ struct mp_audio out_format = in_format;
if (mpctx->ao) {
- ao_get_format(mpctx->ao, &afs->output);
+ ao_get_format(mpctx->ao, &out_format);
} else if (af_fmt_is_pcm(in_format.format)) {
- afs->output.rate = opts->force_srate;
- mp_audio_set_format(&afs->output, opts->audio_output_format);
+ /*out_format.rate = opts->force_srate;
+ mp_audio_set_format(&out_format, opts->audio_output_format);
if (opts->audio_output_channels.num_chmaps == 1) {
- mp_audio_set_channels(&afs->output,
+ mp_audio_set_channels(&out_format,
&opts->audio_output_channels.chmaps[0]);
- }
- }
-
- // filter input format: same as codec's output format:
- afs->input = in_format;
-
- // Determine what the filter chain outputs. recreate_audio_filters() also
- // needs this for testing whether playback speed is changed by resampling
- // or using a special filter.
- if (af_init(afs) < 0) {
- MP_ERR(mpctx, "Error at audio filter chain pre-init!\n");
- goto init_error;
+ }*/
}
if (!mpctx->ao) {
int ao_flags = 0;
- bool spdif_fallback = af_fmt_is_spdif(afs->output.format) &&
+ bool spdif_fallback = af_fmt_is_spdif(out_format.format) &&
ao_c->spdif_passthrough;
if (opts->ao_null_fallback && !spdif_fallback)
@@ -385,21 +388,21 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
if (opts->audio_exclusive)
ao_flags |= AO_INIT_EXCLUSIVE;
- if (af_fmt_is_pcm(afs->output.format)) {
+ if (af_fmt_is_pcm(out_format.format)) {
if (!opts->audio_output_channels.set ||
opts->audio_output_channels.auto_safe)
ao_flags |= AO_INIT_SAFE_MULTICHANNEL_ONLY;
- mp_chmap_sel_list(&afs->output.channels,
+ mp_chmap_sel_list(&out_format.channels,
opts->audio_output_channels.chmaps,
opts->audio_output_channels.num_chmaps);
}
- mp_audio_set_channels(&afs->output, &afs->output.channels);
+ mp_audio_set_channels(&out_format, &out_format.channels);
mpctx->ao = ao_init_best(mpctx->global, ao_flags, mp_wakeup_core_cb,
- mpctx, mpctx->encode_lavc_ctx, afs->output.rate,
- afs->output.format, afs->output.channels);
+ mpctx, mpctx->encode_lavc_ctx, out_format.rate,
+ out_format.format, out_format.channels);
ao_c->ao = mpctx->ao;
struct mp_audio fmt = {0};
@@ -407,8 +410,8 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
ao_get_format(mpctx->ao, &fmt);
// Verify passthrough format was not changed.
- if (mpctx->ao && af_fmt_is_spdif(afs->output.format)) {
- if (!mp_audio_config_equals(&afs->output, &fmt)) {
+ if (mpctx->ao && af_fmt_is_spdif(out_format.format)) {
+ if (!mp_audio_config_equals(&out_format, &fmt)) {
MP_ERR(mpctx, "Passthrough format unsupported.\n");
ao_uninit(mpctx->ao);
mpctx->ao = NULL;
@@ -437,9 +440,9 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
}
mp_audio_buffer_reinit(ao_c->ao_buffer, &fmt);
- afs->output = fmt;
- if (!mp_audio_config_equals(&afs->output, &afs->filter_output))
- afs->initialized = 0;
+ out_format = fmt;
+ //if (!mp_audio_config_equals(&out_format, &afs->filter_output))
+ // afs->initialized = 0;
mpctx->ao_decoder_fmt = talloc(NULL, struct mp_audio);
*mpctx->ao_decoder_fmt = in_format;
@@ -525,9 +528,9 @@ void reinit_audio_chain_src(struct MPContext *mpctx, struct lavfi_pad *src)
struct ao_chain *ao_c = talloc_zero(NULL, struct ao_chain);
mpctx->ao_chain = ao_c;
ao_c->log = mpctx->log;
- ao_c->af = af_new(mpctx->global);
- if (sh)
- ao_c->af->replaygain_data = sh->codec->replaygain_data;
+ //ao_c->af = af_new(mpctx->global);
+ //if (sh)
+ // ao_c->af->replaygain_data = sh->codec->replaygain_data;
ao_c->spdif_passthrough = true;
ao_c->pts = MP_NOPTS_VALUE;
ao_c->ao_buffer = mp_audio_buffer_create(NULL);
@@ -570,7 +573,7 @@ double written_audio_pts(struct MPContext *mpctx)
struct mp_audio in_format = ao_c->input_format;
- if (!mp_audio_config_valid(&in_format) || ao_c->af->initialized < 1)
+ if (!mp_audio_config_valid(&in_format) /*|| ao_c->af->initialized < 1*/)
return MP_NOPTS_VALUE;
// first calculate the end pts of audio that has been output by decoder
@@ -579,7 +582,7 @@ double written_audio_pts(struct MPContext *mpctx)
return MP_NOPTS_VALUE;
// Data buffered in audio filters, measured in seconds of "missing" output
- double buffered_output = af_calc_delay(ao_c->af);
+ double buffered_output = 0;
// Data that was ready for ao but was buffered because ao didn't fully
// accept everything to internal buffers yet
@@ -732,24 +735,27 @@ static bool get_sync_samples(struct MPContext *mpctx, int *skip)
static bool copy_output(struct MPContext *mpctx, struct mp_audio_buffer *outbuf,
int minsamples, double endpts, bool eof, bool *seteof)
{
- struct af_stream *afs = mpctx->ao_chain->af;
+ struct ao_chain *ao_c = mpctx->ao_chain;
+ struct mp_audio out_format;
+ ao_get_format(mpctx->ao, &out_format);
while (mp_audio_buffer_samples(outbuf) < minsamples) {
- if (af_output_frame(afs, eof) < 0)
- return true; // error, stop doing stuff
+ //if (af_output_frame(afs, eof) < 0)
+ // return true; // error, stop doing stuff
int cursamples = mp_audio_buffer_samples(outbuf);
int maxsamples = INT_MAX;
if (endpts != MP_NOPTS_VALUE) {
- double rate = afs->output.rate / mpctx->audio_speed;
+ double rate = out_format.rate / mpctx->audio_speed;
double curpts = written_audio_pts(mpctx);
if (curpts != MP_NOPTS_VALUE)
maxsamples = (endpts - curpts - mpctx->opts->audio_delay) * rate;
}
- struct mp_audio *mpa = af_read_output_frame(afs);
+ struct mp_audio *mpa = ao_c->output_frame;
if (!mpa)
return false; // out of data
+ ao_c->output_frame = NULL;
if (cursamples + mpa->samples > maxsamples) {
if (cursamples < maxsamples) {
@@ -758,7 +764,8 @@ static bool copy_output(struct MPContext *mpctx, struct mp_audio_buffer *outbuf,
mp_audio_buffer_append(outbuf, &pre);
mp_audio_skip_samples(mpa, pre.samples);
}
- af_unread_output_frame(afs, mpa);
+ //af_unread_output_frame(afs, mpa);
+ ao_c->output_frame = mpa;
*seteof = true;
return true;
}
@@ -800,9 +807,6 @@ static int filter_audio(struct MPContext *mpctx, struct mp_audio_buffer *outbuf,
int minsamples)
{
struct ao_chain *ao_c = mpctx->ao_chain;
- struct af_stream *afs = ao_c->af;
- if (afs->initialized < 1)
- return AD_ERR;
MP_STATS(ao_c, "start audio");
@@ -825,12 +829,14 @@ static int filter_audio(struct MPContext *mpctx, struct mp_audio_buffer *outbuf,
break;
}
+ /*
// On format change, make sure to drain the filter chain.
if (!mp_audio_config_equals(&afs->input, ao_c->input_frame)) {
copy_output(mpctx, outbuf, minsamples, endpts, true, &eof);
res = AD_NEW_FMT;
break;
}
+ */
struct mp_audio *mpa = ao_c->input_frame;
ao_c->input_frame = NULL;
@@ -849,8 +855,36 @@ static int filter_audio(struct MPContext *mpctx, struct mp_audio_buffer *outbuf,
}
ao_c->pts = mpa->pts + mpa->samples / (double)mpa->rate;
}
- if (af_filter_frame(afs, mpa) < 0)
- return AD_ERR;
+ TA_FREEP(&ao_c->output_frame);
+ struct mp_audio out_format;
+ ao_get_format(mpctx->ao, &out_format);
+ if (!ao_c->swr || !mp_audio_config_equals(mpa, &ao_c->swr_in) ||
+ !mp_audio_config_equals(&out_format, &ao_c->swr_out))
+ {
+ if (ao_c->swr) {
+ swr_close(ao_c->swr);
+ } else {
+ ao_c->swr = swr_alloc();
+ }
+ av_opt_set_int(ao_c->swr, "in_channel_layout", mp_chmap_to_lavc_unchecked(&mpa->channels), 0);
+ av_opt_set_int(ao_c->swr, "out_channel_layout", mp_chmap_to_lavc_unchecked(&out_format.channels), 0);
+ av_opt_set_int(ao_c->swr, "in_sample_rate", mpa->rate, 0);
+ av_opt_set_int(ao_c->swr, "out_sample_rate", out_format.rate, 0);
+ av_opt_set_int(ao_c->swr, "in_sample_fmt", af_to_avformat(mpa->format), 0);
+ av_opt_set_int(ao_c->swr, "out_sample_fmt", af_to_avformat(out_format.format), 0);
+ if (swr_init(ao_c->swr) < 0)
+ abort();
+ mp_audio_copy_config(&ao_c->swr_in, mpa);
+ mp_audio_copy_config(&ao_c->swr_out, &out_format);
+ }
+ struct mp_audio *out = talloc_zero(NULL, struct mp_audio);
+ mp_audio_copy_config(out, &out_format);
+ out->samples = swr_get_out_samples(ao_c->swr, mpa->samples);
+ mp_audio_realloc(out, out->samples);
+ swr_convert(ao_c->swr, out->planes, out->samples,
+ mpa->planes, mpa->samples);
+ ao_c->output_frame = out;
+ talloc_free(mpa);
}
if (res == 0 && mp_audio_buffer_samples(outbuf) < minsamples && eof)
@@ -880,7 +914,7 @@ void reload_audio_output(struct MPContext *mpctx)
ao_c->spdif_passthrough = true;
ao_c->spdif_failed = false;
d_audio->try_spdif = true;
- ao_c->af->initialized = 0;
+ //ao_c->af->initialized = 0;
if (!audio_init_best_codec(d_audio)) {
MP_ERR(mpctx, "Error reinitializing audio.\n");
error_on_track(mpctx, ao_c->track);
@@ -905,7 +939,7 @@ void fill_audio_out_buffers(struct MPContext *mpctx)
if (!ao_c)
return;
- if (ao_c->af->initialized < 1 || !mpctx->ao) {
+ if (/*ao_c->af->initialized < 1 ||*/ !mpctx->ao) {
// Probe the initial audio format. Returns AD_OK (and does nothing) if
// the format is already known.
int r = decode_new_frame(mpctx->ao_chain);
diff --git a/player/command.c b/player/command.c
index ae01796f31..087ecfa774 100644
--- a/player/command.c
+++ b/player/command.c
@@ -56,7 +56,6 @@
#include "video/csputils.h"
#include "audio/audio_buffer.h"
#include "audio/out/ao.h"
-#include "audio/filter/af.h"
#include "video/decode/dec_video.h"
#include "audio/decode/dec_audio.h"
#include "video/out/bitmap_packer.h"
@@ -1461,12 +1460,12 @@ static int mp_property_filter_metadata(void *ctx, struct m_property *prop,
return M_PROPERTY_UNAVAILABLE;
struct vf_chain *vf = mpctx->vo_chain->vf;
res = vf_control_by_label(vf, VFCTRL_GET_METADATA, &metadata, key);
- } else if (strcmp(type, "af") == 0) {
+ } /*else if (strcmp(type, "af") == 0) {
if (!(mpctx->ao_chain && mpctx->ao_chain->af))
return M_PROPERTY_UNAVAILABLE;
struct af_stream *af = mpctx->ao_chain->af;
res = af_control_by_label(af, AF_CONTROL_GET_METADATA, &metadata, key);
- }
+ }*/
switch (res) {
case CONTROL_UNKNOWN:
return M_PROPERTY_UNKNOWN;
@@ -1777,7 +1776,7 @@ static int mp_property_mixer_active(void *ctx, struct m_property *prop,
{
MPContext *mpctx = ctx;
struct ao_chain *ao_c = mpctx->ao_chain;
- return m_property_flag_ro(action, arg, ao_c && ao_c->af->initialized > 0);
+ return m_property_flag_ro(action, arg, ao_c /*&& ao_c->af->initialized > 0*/);
}
/// Volume (RW)
@@ -5429,10 +5428,10 @@ int run_command(struct MPContext *mpctx, struct mp_cmd *cmd, struct mpv_node *re
cmd->args[1].v.s, cmd->args[2].v.s);
case MP_CMD_AF_COMMAND:
- if (!mpctx->ao_chain)
+ //if (!mpctx->ao_chain)
return -1;
- return af_send_command(mpctx->ao_chain->af, cmd->args[0].v.s,
- cmd->args[1].v.s, cmd->args[2].v.s);
+ //return af_send_command(mpctx->ao_chain->af, cmd->args[0].v.s,
+ // cmd->args[1].v.s, cmd->args[2].v.s);
case MP_CMD_SCRIPT_BINDING: {
mpv_event_client_message event = {0};
diff --git a/player/core.h b/player/core.h
index 79120decd3..6433bb691b 100644
--- a/player/core.h
+++ b/player/core.h
@@ -193,13 +193,17 @@ struct ao_chain {
bool spdif_passthrough, spdif_failed;
bool pts_reset;
- struct af_stream *af;
+ //struct af_stream *af;
struct ao *ao;
struct mp_audio_buffer *ao_buffer;
double ao_resume_time;
// 1-element input frame queue.
struct mp_audio *input_frame;
+ struct mp_audio *output_frame;
+
+ struct mp_audio swr_in, swr_out;
+ struct SwrContext *swr;
// Last known input_mpi format (so vf can be reinitialized any time).
struct mp_audio input_format;
diff --git a/player/playloop.c b/player/playloop.c
index d4a178b9f2..31f98c8161 100644
--- a/player/playloop.c
+++ b/player/playloop.c
@@ -39,7 +39,6 @@
#include "osdep/timer.h"
#include "audio/decode/dec_audio.h"
-#include "audio/filter/af.h"
#include "audio/out/ao.h"
#include "demux/demux.h"
#include "stream/stream.h"
diff --git a/player/video.c b/player/video.c
index ee0e89c93a..d2a2cef8bc 100644
--- a/player/video.c
+++ b/player/video.c
@@ -42,7 +42,6 @@
#include "video/decode/dec_video.h"
#include "video/decode/vd.h"
#include "video/out/vo.h"
-#include "audio/filter/af.h"
#include "audio/decode/dec_audio.h"
#include "core.h"
diff --git a/wscript_build.py b/wscript_build.py
index 4934bd64f7..f37daf6401 100644
--- a/wscript_build.py
+++ b/wscript_build.py
@@ -122,19 +122,6 @@ def build(ctx):
( "audio/decode/ad_lavc.c" ),
( "audio/decode/ad_spdif.c" ),
( "audio/decode/dec_audio.c" ),
- ( "audio/filter/af.c" ),
- ( "audio/filter/af_channels.c" ),
- ( "audio/filter/af_drc.c" ),
- ( "audio/filter/af_equalizer.c" ),
- ( "audio/filter/af_format.c" ),
- ( "audio/filter/af_lavcac3enc.c" ),
- ( "audio/filter/af_lavfi.c" ),
- ( "audio/filter/af_lavrresample.c" ),
- ( "audio/filter/af_pan.c" ),
- ( "audio/filter/af_rubberband.c", "rubberband" ),
- ( "audio/filter/af_scaletempo.c" ),
- ( "audio/filter/af_volume.c" ),
- ( "audio/filter/tools.c" ),
( "audio/out/ao.c" ),
( "audio/out/ao_alsa.c", "alsa" ),
( "audio/out/ao_audiounit.m", "audiounit" ),