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:
wm4 2015-06-05 22:35:43 +02:00
parent 14ac4f0bd6
commit 57048c7393
10 changed files with 101 additions and 18 deletions

View File

@ -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,

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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)
{

View File

@ -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);

View File

@ -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,

View File

@ -109,6 +109,7 @@ typedef struct MPOpts {
char *audio_decoders;
char *video_decoders;
char *audio_spdif;
int osd_level;
int osd_duration;

View File

@ -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;

View File

@ -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);