summaryrefslogtreecommitdiffstats
path: root/audio/filter
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-11-03 00:25:20 +0100
committerwm4 <wm4@nowhere>2015-11-03 00:28:00 +0100
commit4e358a963604af8746a059d7388cb202be0f919d (patch)
treed769bef018ec5657153740f191901058e838bd76 /audio/filter
parent9d4aff8ac7f4f36dfbc2383fd95881361f180e72 (diff)
downloadmpv-4e358a963604af8746a059d7388cb202be0f919d.tar.bz2
mpv-4e358a963604af8746a059d7388cb202be0f919d.tar.xz
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
Diffstat (limited to 'audio/filter')
-rw-r--r--audio/filter/af_lavrresample.c33
1 files changed, 28 insertions, 5 deletions
diff --git a/audio/filter/af_lavrresample.c b/audio/filter/af_lavrresample.c
index 721bb30165..6cdefe56c6 100644
--- a/audio/filter/af_lavrresample.c
+++ b/audio/filter/af_lavrresample.c
@@ -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);