mirror of https://github.com/mpv-player/mpv
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.)
This commit is contained in:
parent
14ac4f0bd6
commit
57048c7393
|
@ -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,
|
||||
|
|
|
@ -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=<codecs>``
|
||||
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=<value>``
|
||||
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=<yes|no>``, ``--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.
|
||||
.. admonition:: Warning
|
||||
|
||||
Some receivers don't accept DTS core-only when ``--ad-spdif-dtshd=yes`` is
|
||||
used, even though they accept DTS-HD.
|
||||
|
||||
``--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=<number|layout>``
|
||||
Request a channel layout for audio output (default: auto). This will ask
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -109,6 +109,7 @@ typedef struct MPOpts {
|
|||
|
||||
char *audio_decoders;
|
||||
char *video_decoders;
|
||||
char *audio_spdif;
|
||||
|
||||
int osd_level;
|
||||
int osd_duration;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue