mirror of
https://github.com/mpv-player/mpv
synced 2024-12-25 16:33:02 +00:00
af_lavrresample: don't drop sl/sr channels for 7.1 on ALSA
ao_alsa: attempt to fix 7.1 over HDMI The last 2 channels of 7.1 (RLC/RRC in ALSA) were exported as sdl/sdr instead of sl/sr (I don't even know why I chose sdl/sdr, but SL/SR and RLC/RRC are different in the ALSA API). libsw/avresample do not move the sl/sr channels to sdl/sdr when rematrixing, so silence was sent for 2 channels. If my selection of sdl/sdr is essentially API abuse, there's no reason why they should do this differently. The mess here is really that ALSa doesn't map the HDMI layouts cleanly. Most ALSA drivers export 7.1 in a way compatible to our expectations, but Intel HDA/HDMI does not: mpv/ffmpeg: fl-fr-fc-lfe-bl-br-sl-sr ALSA/generic: FL FR FC LFE RL RR SL SR [1] ALSA/HDMI: FL FR LFE FC RL RR RLC RRC [2] The HDMI layout is layout 0x13 (going by CEA-861-B). The comment in the kernel code has to be correct too. The early standard defines only 1 other layout, which replaces RLC/RRC with FRC/FLC - this probably corresponds to what we call "7.1(wide)". So it appears when ALSA requests RLC/RRC, we should feed it sl/sr. To make it more complicated, Kodi/xbmc apparently also have to deal with ALSA being special, but instead of sending sl/sr to RLC/RRC, they swap the last two pairs of the layout, and send sl/sr to RL/RR and bl/br to RLC/RRC. Or I might have misunderstood their code. I don't have a 7.1-capable A/V receiver, so I can't test this. For now, go with the simpler solution, and wait until someone tests it. If the speakers end up swapped, a completely different solution will be needed. [1] https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/sound/core/pcm_lib.c?id=refs/tags/v4.3#n2434 [2] https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/sound/pci/hda/patch_hdmi.c?id=refs/tags/v4.3#n307
This commit is contained in:
parent
9d4aff8ac7
commit
4e358a9636
@ -93,7 +93,7 @@ static const char *const std_layout_names[][2] = {
|
||||
{"7.1(alsa)", "fl-fr-bl-br-fc-lfe-sl-sr"}, // not in lavc
|
||||
{"7.1(wide)", "fl-fr-fc-lfe-bl-br-flc-frc"},
|
||||
{"7.1(wide-side)", "fl-fr-fc-lfe-flc-frc-sl-sr"},
|
||||
{"7.1(rear)", "fl-fr-fc-lfe-bl-br-sdl-sdr"},
|
||||
{"7.1(rear)", "fl-fr-fc-lfe-bl-br-sdl-sdr"}, // not in lavc
|
||||
{"octagonal", "fl-fr-fc-bl-br-bc-sl-sr"},
|
||||
{"downmix", "dl-dr"},
|
||||
{"auto", ""}, // not in lavc
|
||||
|
@ -197,6 +197,24 @@ static void transpose_order(int *map, int num)
|
||||
memcpy(map, nmap, sizeof(nmap));
|
||||
}
|
||||
|
||||
static uint64_t fudge_output_channel_layout(uint64_t in, uint64_t out)
|
||||
{
|
||||
// If it tries to convert SR/SL to SDR/SLD, keep it SR/SL.
|
||||
// This effectively makes it not rematrix at all when outputting
|
||||
// 7.1 on ALSA. It could also be considered messing with FFmpeg's
|
||||
// matrix generation.
|
||||
uint64_t sp[][2] = {
|
||||
{AV_CH_SIDE_LEFT, AV_CH_SURROUND_DIRECT_LEFT},
|
||||
{AV_CH_SIDE_RIGHT, AV_CH_SURROUND_DIRECT_RIGHT},
|
||||
};
|
||||
for (int n = 0; n < MP_ARRAY_SIZE(sp); n++) {
|
||||
if ((in & sp[n][0]) && !(out & sp[n][0]) &&
|
||||
!(in & sp[n][1]) && (out & sp[n][1]))
|
||||
out = (out & ~sp[n][1]) | sp[n][0];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static int configure_lavrr(struct af_instance *af, struct mp_audio *in,
|
||||
struct mp_audio *out, bool verbose)
|
||||
{
|
||||
@ -260,11 +278,6 @@ static int configure_lavrr(struct af_instance *af, struct mp_audio *in,
|
||||
mp_chmap_from_lavc(&in_lavc, in_ch_layout);
|
||||
mp_chmap_from_lavc(&out_lavc, out_ch_layout);
|
||||
|
||||
if (verbose && !mp_chmap_equals(&in_lavc, &out_lavc)) {
|
||||
MP_VERBOSE(af, "Remix: %s -> %s\n", mp_chmap_to_str(&in_lavc),
|
||||
mp_chmap_to_str(&out_lavc));
|
||||
}
|
||||
|
||||
if (in_lavc.num != map_in.num) {
|
||||
// For handling NA channels, we would have to add a planarization step.
|
||||
MP_FATAL(af, "Unsupported channel remapping.\n");
|
||||
@ -301,6 +314,16 @@ static int configure_lavrr(struct af_instance *af, struct mp_audio *in,
|
||||
if (map_out.num > out_lavc.num)
|
||||
mp_audio_set_channels(&s->pool_fmt, &map_out);
|
||||
|
||||
out_ch_layout = fudge_output_channel_layout(in_ch_layout, out_ch_layout);
|
||||
|
||||
struct mp_chmap out_lavc_actual;
|
||||
mp_chmap_from_lavc(&out_lavc_actual, out_ch_layout);
|
||||
|
||||
if (verbose && !mp_chmap_equals(&in_lavc, &out_lavc)) {
|
||||
MP_VERBOSE(af, "Remix: %s -> %s\n", mp_chmap_to_str(&in_lavc),
|
||||
mp_chmap_to_str(&out_lavc_actual));
|
||||
}
|
||||
|
||||
// Real conversion; output is input to avrctx_out.
|
||||
av_opt_set_int(s->avrctx, "in_channel_layout", in_ch_layout, 0);
|
||||
av_opt_set_int(s->avrctx, "out_channel_layout", out_ch_layout, 0);
|
||||
|
Loading…
Reference in New Issue
Block a user