summaryrefslogtreecommitdiffstats
path: root/audio/filter
diff options
context:
space:
mode:
Diffstat (limited to 'audio/filter')
-rw-r--r--audio/filter/af.c14
-rw-r--r--audio/filter/af.h3
-rw-r--r--audio/filter/af_lavfi.c46
-rw-r--r--audio/filter/af_lavrresample.c45
-rw-r--r--audio/filter/af_rubberband.c14
5 files changed, 82 insertions, 40 deletions
diff --git a/audio/filter/af.c b/audio/filter/af.c
index 7ff3b49ae8..ac1b4926d8 100644
--- a/audio/filter/af.c
+++ b/audio/filter/af.c
@@ -59,9 +59,7 @@ static const struct af_info *const filter_list[] = {
&af_info_rubberband,
#endif
&af_info_scaletempo,
-#if HAVE_LIBAVFILTER
&af_info_lavfi,
-#endif
NULL
};
@@ -166,6 +164,7 @@ static struct af_instance *af_create(struct af_stream *s, char *name,
.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),
};
@@ -695,6 +694,17 @@ int af_control_by_label(struct af_stream *s, int cmd, void *arg, bstr label)
}
}
+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)
diff --git a/audio/filter/af.h b/audio/filter/af.h
index ba64379661..9c49081f66 100644
--- a/audio/filter/af.h
+++ b/audio/filter/af.h
@@ -53,6 +53,7 @@ struct af_info {
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);
@@ -123,6 +124,7 @@ enum af_control {
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
@@ -143,6 +145,7 @@ 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);
diff --git a/audio/filter/af_lavfi.c b/audio/filter/af_lavfi.c
index af521abd9c..bc4a687487 100644
--- a/audio/filter/af_lavfi.c
+++ b/audio/filter/af_lavfi.c
@@ -3,18 +3,18 @@
*
* 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 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 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 General Public License for more details.
+ * GNU Lesser 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/>.
+ * 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>
@@ -50,6 +50,7 @@
#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)
@@ -222,6 +223,14 @@ static int control(struct af_instance *af, int cmd, void *arg)
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;
@@ -257,32 +266,15 @@ static int filter_frame(struct af_instance *af, struct mp_audio *data)
if (!p->graph)
goto error;
- AVFilterLink *l_in = p->in->outputs[0];
-
if (data) {
- frame = av_frame_alloc();
+ frame = mp_audio_to_avframe_and_unref(data);
+ data = NULL;
if (!frame)
goto error;
- frame->nb_samples = data->samples;
- frame->format = l_in->format;
-
// Timebase is 1/sample_rate
frame->pts = p->samples_in;
-
- frame->channel_layout = l_in->channel_layout;
- frame->sample_rate = l_in->sample_rate;
-#if LIBAVFILTER_VERSION_MICRO >= 100
- // FFmpeg being a stupid POS
- frame->channels = l_in->channels;
-#endif
-
- frame->extended_data = frame->data;
- for (int n = 0; n < data->num_planes; n++)
- frame->data[n] = data->planes[n];
- frame->linesize[0] = frame->nb_samples * data->sstride;
-
- p->samples_in += data->samples;
+ p->samples_in += frame->nb_samples;
}
if (av_buffersrc_add_frame(p->in, frame) < 0)
diff --git a/audio/filter/af_lavrresample.c b/audio/filter/af_lavrresample.c
index f7f448cad0..6fbb445563 100644
--- a/audio/filter/af_lavrresample.c
+++ b/audio/filter/af_lavrresample.c
@@ -179,6 +179,37 @@ bool af_lavrresample_test_conversion(int src_format, int dst_format)
check_output_conversion(dst_format) != AV_SAMPLE_FMT_NONE;
}
+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:
@@ -230,10 +261,13 @@ static int configure_lavrr(struct af_instance *af, struct mp_audio *in,
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", s->opts.normalize ? 1 : 1000, 0);
+ av_opt_set_double(s->avrctx, "rematrix_maxval", normalize ? 1 : 1000, 0);
#else
- av_opt_set_int(s->avrctx, "normalize_mix_level", s->opts.normalize, 0);
+ av_opt_set_int(s->avrctx, "normalize_mix_level", !!normalize, 0);
#endif
if (mp_set_avopts(af->log, s->avrctx, s->avopts) < 0)
@@ -297,6 +331,8 @@ static int configure_lavrr(struct af_instance *af, struct mp_audio *in,
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);
@@ -583,7 +619,7 @@ const struct af_info af_info_lavrresample = {
.filter_size = 16,
.cutoff = 0.0,
.phase_shift = 10,
- .normalize = 1,
+ .normalize = -1,
},
.playback_speed = 1.0,
.allow_detach = 1,
@@ -594,7 +630,8 @@ const struct af_info af_info_lavrresample = {
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_FLAG("normalize", opts.normalize, 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_rubberband.c b/audio/filter/af_rubberband.c
index 2619e4b210..48bb510679 100644
--- a/audio/filter/af_rubberband.c
+++ b/audio/filter/af_rubberband.c
@@ -1,18 +1,18 @@
/*
* 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 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 General Public License for more details.
+ * GNU Lesser 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/>.
+ * 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>