audio: add global options for resampler defaults

This is part of trying to get rid of --af-defaults, and the af
resample filter.

It requires a complicated mechanism to set the defaults on the resample
filter for backwards compatibility.
This commit is contained in:
wm4 2018-01-12 04:02:55 +01:00 committed by Kevin Mitchell
parent 23edaf4412
commit 6d4b4c0de3
12 changed files with 116 additions and 30 deletions

View File

@ -25,6 +25,8 @@ Interface changes
- fix --external-files: strictly never select any tracks from them, unless
explicitly selected (this may or may not be expected)
- --ytdl is now always enabled, even for libmpv
- add a number of --audio-resample-* options, which should from now on be
used instead of --af-defaults=lavrresample:...
--- mpv 0.28.0 ---
- rename --hwdec=mediacodec option to mediacodec-copy, to reflect
conventions followed by other hardware video decoding APIs

View File

@ -1441,16 +1441,6 @@ Audio
want. For example, most A/V receivers connected via HDMI and that can
do 7.1 would be served by: ``--audio-channels=7.1,5.1,stereo``
``--audio-normalize-downmix=<yes|no>``
Enable/disable normalization if surround audio is downmixed to stereo
(default: no). If this is disabled, downmix can cause clipping. If it's
enabled, the output might be too silent. It depends on the source audio.
Technically, this changes the ``normalize`` suboption of the
``lavrresample`` audio filter, which performs the downmixing.
If downmix happens outside of mpv for some reason, this has no effect.
``--audio-display=<no|attachment>``
Setting this option to ``attachment`` (default) will display image
attachments (e.g. album cover art) when playing audio files. It will
@ -3453,6 +3443,44 @@ Software Scaler
``--sws-cvs=<v>``
Software scaler chroma vertical shifting. See ``--sws-scaler``.
Audio Resampler
---------------
This controls the default options of any resampling done by mpv (but not within
libavfilter, within the system audio API resampler, or any other places).
It also sets the defaults for the ``lavrresample`` audio filter.
``--audio-resample-filter-size=<length>``
Length of the filter with respect to the lower sampling rate. (default:
16)
``--audio-resample-phase-shift=<count>``
Log2 of the number of polyphase entries. (..., 10->1024, 11->2048,
12->4096, ...) (default: 10->1024)
``--audio-resample-cutoff=<cutoff>``
Cutoff frequency (0.0-1.0), default set depending upon filter length.
``--audio-resample-linear=<yes|no>``
If set then filters will be linearly interpolated between polyphase
entries. (default: no)
``--audio-normalize-downmix=<yes|no>``
Enable/disable normalization if surround audio is downmixed to stereo
(default: no). If this is disabled, downmix can cause clipping. If it's
enabled, the output might be too quiet. It depends on the source audio.
Technically, this changes the ``normalize`` suboption of the
``lavrresample`` audio filter, which performs the downmixing.
If downmix happens outside of mpv for some reason, or in the decoder
(decoder downmixing), or in the audio output (system mixer), this has no
effect.
``--audio-swresample-o=<string>``
Set AVOptions on the SwrContext or AVAudioResampleContext. These should
be documented by FFmpeg or Libav.
Terminal
--------

View File

@ -86,6 +86,23 @@ struct mp_aconverter {
bool output_eof; // queued output EOF
};
#define OPT_BASE_STRUCT struct mp_resample_opts
const struct m_sub_options resample_config = {
.opts = (const m_option_t[]) {
OPT_INTRANGE("audio-resample-filter-size", filter_size, 0, 0, 32),
OPT_INTRANGE("audio-resample-phase-shift", phase_shift, 0, 0, 30),
OPT_FLAG("audio-resample-linear", linear, 0),
OPT_DOUBLE("audio-resample-cutoff", cutoff, M_OPT_RANGE,
.min = 0, .max = 1),
OPT_FLAG("audio-normalize-downmix", normalize, 0),
OPT_KEYVALUELIST("audio-swresample-o", avopts, 0),
{0}
},
.size = sizeof(struct mp_resample_opts),
.defaults = &(const struct mp_resample_opts)MP_RESAMPLE_OPTS_DEF,
.change_flags = UPDATE_AUDIO,
};
#if HAVE_LIBAVRESAMPLE
static double get_delay(struct mp_aconverter *p)
{
@ -211,12 +228,7 @@ static bool configure_lavrr(struct mp_aconverter *p, bool verbose)
cutoff = MPMAX(1.0 - 6.5 / (p->opts->filter_size + 8), 0.80);
av_opt_set_double(p->avrctx, "cutoff", cutoff, 0);
int global_normalize;
mp_read_option_raw(p->global, "audio-normalize-downmix", &m_option_type_flag,
&global_normalize);
int normalize = p->opts->normalize;
if (normalize < 0)
normalize = global_normalize;
#if HAVE_LIBSWRESAMPLE
av_opt_set_double(p->avrctx, "rematrix_maxval", normalize ? 1 : 1000, 0);
#else
@ -628,9 +640,9 @@ struct mp_aconverter *mp_aconverter_create(struct mpv_global *global,
p->log = log;
p->global = global;
static const struct mp_resample_opts defs = MP_RESAMPLE_OPTS_DEF;
p->opts = opts ? opts : &defs;
p->opts = opts;
if (!p->opts)
p->opts = mp_get_config_group(p, global, &resample_config);
p->reorder_buffer = mp_aframe_pool_create(p);
p->out_pool = mp_aframe_pool_create(p);

View File

@ -23,9 +23,11 @@ struct mp_resample_opts {
.filter_size = 16, \
.cutoff = 0.0, \
.phase_shift = 10, \
.normalize = -1, \
.normalize = 0, \
}
extern const struct m_sub_options resample_config;
struct mp_aconverter *mp_aconverter_create(struct mpv_global *global,
struct mp_log *log,
const struct mp_resample_opts *opts);

View File

@ -63,6 +63,7 @@ static bool get_desc(struct m_obj_desc *dst, int index)
.priv_size = af->priv_size,
.priv_defaults = af->priv_defaults,
.options = af->options,
.set_defaults = af->set_defaults,
.p = af,
};
return true;
@ -170,7 +171,7 @@ static struct af_instance *af_create(struct af_stream *s, char *name,
.out_pool = mp_audio_pool_create(af),
};
struct m_config *config =
m_config_from_obj_desc_and_args(af, s->log, NULL, &desc,
m_config_from_obj_desc_and_args(af, s->log, s->global, &desc,
name, s->opts->af_defs, args);
if (!config)
goto error;

View File

@ -52,6 +52,8 @@ struct af_info {
int priv_size;
const void *priv_defaults;
const struct m_option *options;
// For m_obj_desc.set_defaults
void (*set_defaults)(struct mpv_global *global, void *p);
};
// Linked list of audio filters

View File

@ -32,6 +32,7 @@
#include "common/av_common.h"
#include "common/msg.h"
#include "options/m_config.h"
#include "options/m_option.h"
#include "audio/filter/af.h"
#include "audio/fmt-conversion.h"
@ -42,6 +43,7 @@ struct af_resample {
int allow_detach;
double playback_speed;
struct mp_resample_opts opts;
int global_normalize;
struct mp_aconverter *converter;
};
@ -142,11 +144,34 @@ static int af_open(struct af_instance *af)
af->filter_frame = filter;
af->filter_out = filter_out;
if (s->opts.normalize < 0)
s->opts.normalize = s->global_normalize;
s->converter = mp_aconverter_create(af->global, af->log, &s->opts);
return AF_OK;
}
static void set_defaults(struct mpv_global *global, void *p)
{
struct af_resample *s = p;
struct mp_resample_opts *opts = &s->opts;
struct mp_resample_opts *src_opts =
mp_get_config_group(s, global, &resample_config);
s->global_normalize = src_opts->normalize;
assert(!opts->avopts); // we don't set a default value, so it must be NULL
*opts = *src_opts;
opts->avopts = NULL;
struct m_option dummy = {.type = &m_option_type_keyvalue_list};
m_option_copy(&dummy, &opts->avopts, &src_opts->avopts);
}
#define OPT_BASE_STRUCT struct af_resample
const struct af_info af_info_lavrresample = {
@ -170,4 +195,5 @@ const struct af_info af_info_lavrresample = {
OPT_KEYVALUELIST("o", opts.avopts, 0),
{0}
},
.set_defaults = set_defaults,
};

View File

@ -194,11 +194,18 @@ struct m_config *m_config_new(void *talloc_ctx, struct mp_log *log,
return config;
}
struct m_config *m_config_from_obj_desc(void *talloc_ctx, struct mp_log *log,
struct m_obj_desc *desc)
static struct m_config *m_config_from_obj_desc(void *talloc_ctx,
struct mp_log *log,
struct mpv_global *global,
struct m_obj_desc *desc)
{
return m_config_new(talloc_ctx, log, desc->priv_size, desc->priv_defaults,
desc->options);
struct m_config *c =
m_config_new(talloc_ctx, log, desc->priv_size, desc->priv_defaults,
desc->options);
c->global = global;
if (desc->set_defaults && c->global)
desc->set_defaults(c->global, c->optstruct);
return c;
}
// Like m_config_from_obj_desc(), but don't allocate option struct.
@ -260,7 +267,7 @@ struct m_config *m_config_from_obj_desc_and_args(void *ta_parent,
struct mp_log *log, struct mpv_global *global, struct m_obj_desc *desc,
const char *name, struct m_obj_settings *defaults, char **args)
{
struct m_config *config = m_config_from_obj_desc(ta_parent, log, desc);
struct m_config *config = m_config_from_obj_desc(ta_parent, log, global, desc);
for (int n = 0; defaults && defaults[n].name; n++) {
struct m_obj_settings *entry = &defaults[n];

View File

@ -123,9 +123,6 @@ struct m_config *m_config_new(void *talloc_ctx, struct mp_log *log,
// mpv_global. Expected to be called at early init on the main m_config.
void m_config_create_shadow(struct m_config *config);
struct m_config *m_config_from_obj_desc(void *talloc_ctx, struct mp_log *log,
struct m_obj_desc *desc);
struct m_config *m_config_from_obj_desc_noalloc(void *talloc_ctx,
struct mp_log *log,
struct m_obj_desc *desc);

View File

@ -32,6 +32,7 @@ typedef struct m_option m_option_t;
struct m_config;
struct mp_log;
struct mpv_node;
struct mpv_global;
///////////////////////////// Options types declarations ////////////////////
@ -129,6 +130,10 @@ struct m_obj_desc {
bool hidden;
// Callback to print custom help if "help" is passed
void (*print_help)(struct mp_log *log);
// Callback that allows you to override the static default values. The
// pointer p points to the struct described by options/priv_size, with
// priv_defaults already applied. You can write to it to set any defaults.
void (*set_defaults)(struct mpv_global *global, void *p);
// Set by m_obj_list_find(). If the requested name is an old alias, this
// is set to the old name (while the name field uses the new name).
const char *replaced_name;

View File

@ -94,6 +94,8 @@ extern const struct m_sub_options angle_conf;
extern const struct m_sub_options cocoa_conf;
extern const struct m_sub_options android_conf;
extern const struct m_sub_options resample_config;
static const struct m_sub_options screenshot_conf = {
.opts = image_writer_opts,
.size = sizeof(struct image_writer_opts),
@ -474,7 +476,6 @@ const m_option_t mp_opts[] = {
OPT_INTRANGE("audio-samplerate", force_srate, UPDATE_AUDIO, 1000, 16*48000),
OPT_CHANNELS("audio-channels", audio_output_channels, UPDATE_AUDIO),
OPT_AUDIOFORMAT("audio-format", audio_output_format, UPDATE_AUDIO),
OPT_FLAG("audio-normalize-downmix", audio_normalize, UPDATE_AUDIO),
OPT_DOUBLE("speed", playback_speed, M_OPT_RANGE, .min = 0.01, .max = 100.0),
OPT_FLAG("audio-pitch-correction", pitch_correction, 0),
@ -691,6 +692,8 @@ const m_option_t mp_opts[] = {
OPT_STRING("record-file", record_file, M_OPT_FILE),
OPT_SUBSTRUCT("", resample_opts, resample_config, 0),
OPT_SUBSTRUCT("", input_opts, input_config, 0),
OPT_SUBSTRUCT("", vo, vo_sub_opts, 0),

View File

@ -275,7 +275,6 @@ typedef struct MPOpts {
struct m_channels audio_output_channels;
int audio_output_format;
int audio_normalize;
int force_srate;
double playback_speed;
int pitch_correction;
@ -331,6 +330,8 @@ typedef struct MPOpts {
int wingl_dwm_flush;
struct mp_resample_opts *resample_opts;
struct gl_video_opts *gl_video_opts;
struct angle_opts *angle_opts;
struct opengl_opts *opengl_opts;