From 57048c7393e94820520a395e569d05cdcc085224 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 5 Jun 2015 22:35:43 +0200 Subject: audio: add --audio-spdif as new method for enabling passthrough This provides a new method for enabling spdif passthrough. The old method via --ad (--ad=spdif:ac3 etc.) is deprecated. The deprecated method will probably stop working at some point. This also supports PCM fallback. One caveat is that it will lose at least 1 audio packet in doing so. (I don't care enough to prevent this.) (This is named after the old S/PDIF connector, because it uses the same underlying technology as far as the higher level protoco is concerned. Also, the user should be renamed that passthrough is backwards.) --- DOCS/interface-changes.rst | 2 ++ DOCS/man/options.rst | 37 ++++++++++++++++++++++++++++--------- audio/decode/dec_audio.c | 26 +++++++++++++++++++------- audio/decode/dec_audio.h | 3 ++- common/codecs.c | 22 ++++++++++++++++++++++ common/codecs.h | 7 +++++++ options/options.c | 2 ++ options/options.h | 1 + player/audio.c | 15 ++++++++++++++- player/main.c | 4 ++++ 10 files changed, 101 insertions(+), 18 deletions(-) diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index c1980940bf..b6a77b6bd5 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -20,6 +20,8 @@ Interface changes :: --- mpv 0.10.0 will be released --- + - deprecate --ad-spdif-dtshd and enabling passthrough via --ad + add --audio-spdif as replacement - remove "get_property" command - remove --slave-broken - add vo opengl custom shader suboptions (source-shader, scale-shader, diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index f51b471c01..61cd7058c0 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -855,6 +855,25 @@ Audio ``--af-clr`` exist to modify a previously specified list, but you should not need these for typical use. +``--audio-spdif=`` + List of codecs for which compressed audio passthrough should be used. This + works for both classic S/PDIF and HDMI. + + Possible codecs are ``ac3``, ``dts``, ``dts-hd``. Multiple codecs can be + specified by separating them with ``,``. ``dts`` refers to low bitrate DTS + core, while ``dts-hd`` refers to DTS MA (receiver and OS support varies). + You should only use either ``dts`` or ``dts-hd`` (if both are specified, + and ``dts`` comes first, only ``dts`` will be used). + + In general, all codecs in the ``spdif`` family listed with ``--ad=help`` + are supported in theory. + + .. admonition:: Warning + + There is not much reason to use this. HDMI supports uncompressed + multichannel PCM, and mpv supports lossless DTS-HD decoding via + FFmpeg's libdcadec wrapper. + ``--ad=<[+|-]family1:(*|decoder1),[+|-]family2:(*|decoder2),...[-]>`` Specify a priority list of audio decoders to be used, according to their family and decoder name. Entries like ``family:*`` prioritize all decoders @@ -882,6 +901,11 @@ Audio ``--ad=help`` List all available decoders. + .. admonition:: Warning + + Enabling compressed audio passthrough (AC3 and DTS via SPDIF/HDMI) with + this option is deprecated. Use ``--audio-spdif`` instead. + ``--volume=`` Set the startup volume. 0 means silence, 100 means no volume reduction or amplification. A value of -1 (the default) will not change the volume. See @@ -953,17 +977,12 @@ Audio welcome. A full list of AVOptions can be found in the FFmpeg manual. ``--ad-spdif-dtshd=``, ``--dtshd``, ``--no-dtshd`` - When using DTS pass-through, output any DTS-HD track as-is. - With ``ad-spdif-dtshd=no`` (the default), only the DTS Core parts will be - output. + If DTS is passed through, use DTS-HD. - DTS-HD tracks can be sent over HDMI but not over the original - coax/TOSLINK S/PDIF system. - - Some receivers don't accept DTS core-only when ``--ad-spdif-dtshd=yes`` is - used, even though they accept DTS-HD. + .. admonition:: Warning - ``--dtshd`` and ``--no-dtshd`` are deprecated aliases. + This and enabling passthrough via ``--ad`` are deprecated in favor of + using ``--audio-spdif=dts-hd``. ``--audio-channels=`` Request a channel layout for audio output (default: auto). This will ask diff --git a/audio/decode/dec_audio.c b/audio/decode/dec_audio.c index dfbe32cbdf..19d2c4e3df 100644 --- a/audio/decode/dec_audio.c +++ b/audio/decode/dec_audio.c @@ -52,6 +52,7 @@ static const struct ad_functions * const ad_drivers[] = { static void uninit_decoder(struct dec_audio *d_audio) { + audio_reset_decoding(d_audio); if (d_audio->ad_driver) { MP_VERBOSE(d_audio, "Uninit audio decoder.\n"); d_audio->ad_driver->uninit(d_audio); @@ -59,6 +60,8 @@ static void uninit_decoder(struct dec_audio *d_audio) d_audio->ad_driver = NULL; talloc_free(d_audio->priv); d_audio->priv = NULL; + d_audio->afilter->initialized = -1; + d_audio->decode_format = (struct mp_audio){0}; } static int init_audio_codec(struct dec_audio *d_audio, const char *decoder) @@ -81,11 +84,21 @@ struct mp_decoder_list *audio_decoder_list(void) return list; } -static struct mp_decoder_list *audio_select_decoders(const char *codec, - char *selection) +static struct mp_decoder_list *audio_select_decoders(struct dec_audio *d_audio) { + struct MPOpts *opts = d_audio->opts; + const char *codec = d_audio->header->codec; + struct mp_decoder_list *list = audio_decoder_list(); - struct mp_decoder_list *new = mp_select_decoders(list, codec, selection); + struct mp_decoder_list *new = + mp_select_decoders(list, codec, opts->audio_decoders); + if (d_audio->spdif_passthrough) { + struct mp_decoder_list *spdif = + mp_select_decoder_list(list, codec, "spdif", opts->audio_spdif); + mp_append_decoders(spdif, new); + talloc_free(new); + new = spdif; + } talloc_free(list); return new; } @@ -99,14 +112,13 @@ static const struct ad_functions *find_driver(const char *name) return NULL; } -int audio_init_best_codec(struct dec_audio *d_audio, char *audio_decoders) +int audio_init_best_codec(struct dec_audio *d_audio) { + uninit_decoder(d_audio); assert(!d_audio->ad_driver); - audio_reset_decoding(d_audio); struct mp_decoder_entry *decoder = NULL; - struct mp_decoder_list *list = - audio_select_decoders(d_audio->header->codec, audio_decoders); + struct mp_decoder_list *list = audio_select_decoders(d_audio); mp_print_decoders(d_audio->log, MSGL_V, "Codec list:", list); diff --git a/audio/decode/dec_audio.h b/audio/decode/dec_audio.h index 11e4a24b81..6d7dd18bc8 100644 --- a/audio/decode/dec_audio.h +++ b/audio/decode/dec_audio.h @@ -30,6 +30,7 @@ struct dec_audio { struct mp_log *log; struct MPOpts *opts; struct mpv_global *global; + bool spdif_passthrough; const struct ad_functions *ad_driver; struct sh_stream *header; struct af_stream *afilter; @@ -57,7 +58,7 @@ enum { }; struct mp_decoder_list *audio_decoder_list(void); -int audio_init_best_codec(struct dec_audio *d_audio, char *audio_decoders); +int audio_init_best_codec(struct dec_audio *d_audio); int audio_decode(struct dec_audio *d_audio, struct mp_audio_buffer *outbuf, int minsamples); int initial_audio_decode(struct dec_audio *d_audio); diff --git a/common/codecs.c b/common/codecs.c index f89ef0c318..35d270989d 100644 --- a/common/codecs.c +++ b/common/codecs.c @@ -130,6 +130,28 @@ struct mp_decoder_list *mp_select_decoders(struct mp_decoder_list *all, return list; } +// selection is a ","-separated list of decoders, all in the given family. +struct mp_decoder_list *mp_select_decoder_list(struct mp_decoder_list *all, + const char *codec, + const char *family, + const char *selection) +{ + struct mp_decoder_list *list = talloc_zero(NULL, struct mp_decoder_list); + bstr sel = bstr0(selection); + while (sel.len) { + bstr decoder; + bstr_split_tok(sel, ",", &decoder, &sel); + add_new(list, find_decoder(all, bstr0(family), decoder), codec); + } + return list; +} + +void mp_append_decoders(struct mp_decoder_list *list, struct mp_decoder_list *a) +{ + for (int n = 0; n < a->num_entries; n++) + add_new(list, &a->entries[n], NULL); +} + void mp_print_decoders(struct mp_log *log, int msgl, const char *header, struct mp_decoder_list *list) { diff --git a/common/codecs.h b/common/codecs.h index 105aab5a82..a262ed6582 100644 --- a/common/codecs.h +++ b/common/codecs.h @@ -37,6 +37,13 @@ struct mp_decoder_list *mp_select_decoders(struct mp_decoder_list *all, const char *codec, const char *selection); +struct mp_decoder_list *mp_select_decoder_list(struct mp_decoder_list *all, + const char *codec, + const char *family, + const char *selection); + +void mp_append_decoders(struct mp_decoder_list *list, struct mp_decoder_list *a); + struct mp_log; void mp_print_decoders(struct mp_log *log, int msgl, const char *header, struct mp_decoder_list *list); diff --git a/options/options.c b/options/options.c index 65fadc8e94..4ba2db1590 100644 --- a/options/options.c +++ b/options/options.c @@ -279,6 +279,8 @@ const m_option_t mp_opts[] = { OPT_STRING("ad", audio_decoders, 0), OPT_STRING("vd", video_decoders, 0), + OPT_STRING("audio-spdif", audio_spdif, 0), + OPT_FLAG("ad-spdif-dtshd", dtshd, 0), OPT_CHOICE("hwdec", hwdec_api, 0, diff --git a/options/options.h b/options/options.h index a8dd1ade97..b5e0e1f624 100644 --- a/options/options.h +++ b/options/options.h @@ -109,6 +109,7 @@ typedef struct MPOpts { char *audio_decoders; char *video_decoders; + char *audio_spdif; int osd_level; int osd_duration; diff --git a/player/audio.c b/player/audio.c index 559e194218..b354f701ae 100644 --- a/player/audio.c +++ b/player/audio.c @@ -190,8 +190,9 @@ void reinit_audio_chain(struct MPContext *mpctx) mpctx->d_audio->pool = mp_audio_pool_create(mpctx->d_audio); mpctx->d_audio->afilter = af_new(mpctx->global); mpctx->d_audio->afilter->replaygain_data = sh->audio->replaygain_data; + mpctx->d_audio->spdif_passthrough = true; mpctx->ao_buffer = mp_audio_buffer_create(NULL); - if (!audio_init_best_codec(mpctx->d_audio, opts->audio_decoders)) + if (!audio_init_best_codec(mpctx->d_audio)) goto init_error; reset_audio_state(mpctx); @@ -264,6 +265,18 @@ void reinit_audio_chain(struct MPContext *mpctx) } if (!mpctx->ao) { + // If spdif was used, try to fallback to PCM. + if (AF_FORMAT_IS_SPECIAL(afs->output.format) && + mpctx->d_audio->spdif_passthrough) + { + mpctx->d_audio->spdif_passthrough = false; + if (!audio_init_best_codec(mpctx->d_audio)) + goto init_error; + reset_audio_state(mpctx); + reinit_audio_chain(mpctx); + return; + } + MP_ERR(mpctx, "Could not open/initialize audio device -> no sound.\n"); mpctx->error_playing = MPV_ERROR_AO_INIT_FAILED; goto init_error; diff --git a/player/main.c b/player/main.c index bb22069bfc..06b1867ebe 100644 --- a/player/main.c +++ b/player/main.c @@ -278,6 +278,10 @@ static bool handle_help_options(struct MPContext *mpctx) talloc_free(list); opt_exit = 1; } + if (opts->audio_spdif && strcmp(opts->audio_spdif, "help") == 0) { + MP_INFO(mpctx, "Choices: ac3,dts-hd,dts (and possibly more)\n"); + opt_exit = 1; + } if (opts->video_decoders && strcmp(opts->video_decoders, "help") == 0) { struct mp_decoder_list *list = video_decoder_list(); mp_print_decoders(log, MSGL_INFO, "Video decoders:", list); -- cgit v1.2.3