From 6d4b4c0de3152bc2deb2df09ec3e98e032124593 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 12 Jan 2018 04:02:55 +0100 Subject: [PATCH] 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. --- DOCS/interface-changes.rst | 2 ++ DOCS/man/options.rst | 48 +++++++++++++++++++++++++++------- audio/aconverter.c | 28 ++++++++++++++------ audio/aconverter.h | 4 ++- audio/filter/af.c | 3 ++- audio/filter/af.h | 2 ++ audio/filter/af_lavrresample.c | 26 ++++++++++++++++++ options/m_config.c | 17 ++++++++---- options/m_config.h | 3 --- options/m_option.h | 5 ++++ options/options.c | 5 +++- options/options.h | 3 ++- 12 files changed, 116 insertions(+), 30 deletions(-) diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index 7960ea95ec..7be73e8783 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -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 diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 2f7baf92ff..44f4b5ae1d 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -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=`` - 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=`` 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=`` 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 of the filter with respect to the lower sampling rate. (default: + 16) + +``--audio-resample-phase-shift=`` + Log2 of the number of polyphase entries. (..., 10->1024, 11->2048, + 12->4096, ...) (default: 10->1024) + +``--audio-resample-cutoff=`` + Cutoff frequency (0.0-1.0), default set depending upon filter length. + +``--audio-resample-linear=`` + If set then filters will be linearly interpolated between polyphase + entries. (default: no) + +``--audio-normalize-downmix=`` + 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=`` + Set AVOptions on the SwrContext or AVAudioResampleContext. These should + be documented by FFmpeg or Libav. Terminal -------- diff --git a/audio/aconverter.c b/audio/aconverter.c index 19b8960de2..2475df878d 100644 --- a/audio/aconverter.c +++ b/audio/aconverter.c @@ -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); diff --git a/audio/aconverter.h b/audio/aconverter.h index 57c5524c2f..22ca93e4c1 100644 --- a/audio/aconverter.h +++ b/audio/aconverter.h @@ -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); diff --git a/audio/filter/af.c b/audio/filter/af.c index 5838c2e70b..35525d0774 100644 --- a/audio/filter/af.c +++ b/audio/filter/af.c @@ -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; diff --git a/audio/filter/af.h b/audio/filter/af.h index f27edee71a..3a07a5465f 100644 --- a/audio/filter/af.h +++ b/audio/filter/af.h @@ -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 diff --git a/audio/filter/af_lavrresample.c b/audio/filter/af_lavrresample.c index 55eb6b0f20..96387060b1 100644 --- a/audio/filter/af_lavrresample.c +++ b/audio/filter/af_lavrresample.c @@ -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, }; diff --git a/options/m_config.c b/options/m_config.c index 8bf7e0ef91..a487b64869 100644 --- a/options/m_config.c +++ b/options/m_config.c @@ -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]; diff --git a/options/m_config.h b/options/m_config.h index 6c4e9b759f..80aeaef789 100644 --- a/options/m_config.h +++ b/options/m_config.h @@ -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); diff --git a/options/m_option.h b/options/m_option.h index a1039e2a82..405b59da0a 100644 --- a/options/m_option.h +++ b/options/m_option.h @@ -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; diff --git a/options/options.c b/options/options.c index c0697e8e71..1de76f53e4 100644 --- a/options/options.c +++ b/options/options.c @@ -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), diff --git a/options/options.h b/options/options.h index 38afc1c831..424a1c8f0e 100644 --- a/options/options.h +++ b/options/options.h @@ -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;