mpv-player / mpv

🎥 Command line video player
https://mpv.io
Other
28.85k stars 2.93k forks source link

ReplayGain isn't re-calculated when changing item in playlist with gapless playback enabled #8267

Open sammoth opened 4 years ago

sammoth commented 4 years ago

Provide following Information:

When playing multiple files in a playlist, it seems like the first file's replaygain is applied to everything, instead of the replaygain for each file being applied when that file is played.

For example, file 1:

mpv -v --no-config --replaygain=track ./1.mkv 2>&1 | grep -i replay
[cplayer] Command line options: '-v' '--no-config' '--replaygain=track' './1.mkv'
[cplayer] Setting option 'replaygain' = 'track' (flags = 8)
[cplayer] Replaygain: Track=5.330000/0.314455 Album=5.330000/0.314455
[cplayer] Applying replay-gain: 1.847141

file 2:

mpv -v --no-config --replaygain=track ./2.mkv 2>&1 | grep -i replay
[cplayer] Command line options: '-v' '--no-config' '--replaygain=track' './2.mkv'
[cplayer] Setting option 'replaygain' = 'track' (flags = 8)
[cplayer] Replaygain: Track=-4.150000/0.647406 Album=-4.150000/0.647406
[cplayer] Applying replay-gain: 0.620155

But if I play both and manually do playlist-next, the only output is:

mpv -v --no-config --replaygain=track ./1.mkv ./2.mkv 2>&1 | grep -i replay
[cplayer] Command line options: '-v' '--no-config' '--replaygain=track' './1.mkv' './2.mkv'
[cplayer] Setting option 'replaygain' = 'track' (flags = 8)
[cplayer] Replaygain: Track=5.330000/0.314455 Album=5.330000/0.314455
[cplayer] Applying replay-gain: 1.847141

and the second file is too loud.

Full log https://0x0.st/i5zk.txt

sammoth commented 4 years ago

Looks like this is due to the weak gapless playback logic. reinit_audio_filters_and_output doesn't check if the volume needs changing before returning - audio_update_volume is only called at the end of that function.

I am not familiar with mpv codebase, but it looks like ReplayGain is implemented using the audio output gain instead of applying it in the filter chain. I'm not sure how to fix this considering that, as you would have to trigger an AO gain update exactly when it starts playing the audio for the next track, unless you can assume updating the gain is applied from the current buffered time rather than the current playback time? If ReplayGain were instead applied at the end of mpv's filter chain, it would be simple to apply the new RG amount at the correct time.

Turning off gapless fixes this for the moment.

sammoth commented 4 years ago

In fact it seems like it would make even more sense for ReplayGain to be applied at the beginning of the filter chain, otherwise the clipping prevention becomes meaningless if any other audio filter has changed the gain. At least if the gain is applied at the beginning, the clipping prevention will still work correctly and then as long as all subsequent filters don't cause clipping themselves, there won't be clipping.

I tried just putting in a lavfi=volume=replaygain=track filter at the head of the filter chain, but it doesn't seem to do anything. I guess the RG metadata isn't passed to the ffmpeg filter chain.

q3cpma commented 3 years ago

Anecdote: I became aware of this bug with a playlist of Debussy by BIS (album gain: +12.6 dB) followed by Swans (-5.0 dB). My neighbourhood will never be the same.