diff options
author | wm4 <wm4@nowhere> | 2013-11-18 13:57:17 +0100 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2013-11-18 14:21:00 +0100 |
commit | 1151dac5f0e0fda012ce228f5a358c72b26fffe3 (patch) | |
tree | a24a6d66c7129d33c40f490f7f20b4811d34478a /mpvcore/player/audio.c | |
parent | 8f1151a00edf3aac78baa6779284eede3e9ee872 (diff) | |
download | mpv-1151dac5f0e0fda012ce228f5a358c72b26fffe3.tar.bz2 mpv-1151dac5f0e0fda012ce228f5a358c72b26fffe3.tar.xz |
audio: use the decoder buffer's format, not sh_audio
When the decoder detects a format change, it overwrites the values
stored in sh_audio (this affects the members sample_format, samplerate,
channels). In the case when the old audio data still needs to be
played/filtered, the audio format as identified by sh_audio and the
format used for the decoder buffer can mismatch. In particular, they
will mismatch in the very unlikely but possible case the audio chain is
reinitialized while old data is draining during a format change.
Or in other words, sh_audio might contain the new format, while the
audio chain is still configured to use the old format.
Currently, the audio code (player/audio.c and init_audio_filters) access
sh_audio to get the current format. This is in theory incorrect for the
reasons mentioned above. Use the decoder buffer's format instead, which
should be correct at any point.
Diffstat (limited to 'mpvcore/player/audio.c')
-rw-r--r-- | mpvcore/player/audio.c | 25 |
1 files changed, 19 insertions, 6 deletions
diff --git a/mpvcore/player/audio.c b/mpvcore/player/audio.c index a13e8d9c07..97c446942f 100644 --- a/mpvcore/player/audio.c +++ b/mpvcore/player/audio.c @@ -44,20 +44,27 @@ static int build_afilter_chain(struct MPContext *mpctx) struct sh_audio *sh_audio = mpctx->sh_audio; struct ao *ao = mpctx->ao; struct MPOpts *opts = mpctx->opts; + + if (!sh_audio->initialized) + return 0; + + struct mp_audio in_format; + mp_audio_buffer_get_format(mpctx->sh_audio->decode_buffer, &in_format); + int new_srate; if (af_control_any_rev(sh_audio->afilter, AF_CONTROL_PLAYBACK_SPEED | AF_CONTROL_SET, &opts->playback_speed)) - new_srate = sh_audio->samplerate; + new_srate = in_format.rate; else { - new_srate = sh_audio->samplerate * opts->playback_speed; + new_srate = in_format.rate * opts->playback_speed; if (new_srate != ao->samplerate) { // limits are taken from libaf/af_resample.c if (new_srate < 8000) new_srate = 8000; if (new_srate > 192000) new_srate = 192000; - opts->playback_speed = (double)new_srate / sh_audio->samplerate; + opts->playback_speed = new_srate / (double)in_format.rate; } } return init_audio_filters(sh_audio, new_srate, @@ -109,6 +116,9 @@ void reinit_audio_chain(struct MPContext *mpctx) mpctx->initialized_flags |= INITIALIZED_ACODEC; } + struct mp_audio in_format; + mp_audio_buffer_get_format(mpctx->sh_audio->decode_buffer, &in_format); + int ao_srate = opts->force_srate; int ao_format = opts->audio_output_format; struct mp_chmap ao_channels = {0}; @@ -119,7 +129,7 @@ void reinit_audio_chain(struct MPContext *mpctx) } else { // Automatic downmix if (mp_chmap_is_stereo(&opts->audio_output_channels) && - !mp_chmap_is_stereo(&mpctx->sh_audio->channels)) + !mp_chmap_is_stereo(&in_format.channels)) { mp_chmap_from_channels(&ao_channels, 2); } @@ -130,7 +140,7 @@ void reinit_audio_chain(struct MPContext *mpctx) // or using a special filter. if (!init_audio_filters(mpctx->sh_audio, // preliminary init // input: - mpctx->sh_audio->samplerate, + in_format.rate, // output: &ao_srate, &ao_channels, &ao_format)) { MP_ERR(mpctx, "Error at audio filter chain pre-init!\n"); @@ -183,6 +193,9 @@ double written_audio_pts(struct MPContext *mpctx) if (!sh_audio || !sh_audio->initialized) return MP_NOPTS_VALUE; + struct mp_audio in_format; + mp_audio_buffer_get_format(mpctx->sh_audio->decode_buffer, &in_format); + // first calculate the end pts of audio that has been output by decoder double a_pts = sh_audio->pts; if (a_pts == MP_NOPTS_VALUE) @@ -191,7 +204,7 @@ double written_audio_pts(struct MPContext *mpctx) // sh_audio->pts is the timestamp of the latest input packet with // known pts that the decoder has decoded. sh_audio->pts_bytes is // the amount of bytes the decoder has written after that timestamp. - a_pts += sh_audio->pts_offset / (double)sh_audio->samplerate; + a_pts += sh_audio->pts_offset / (double)in_format.rate; // Now a_pts hopefully holds the pts for end of audio from decoder. // Subtract data in buffers between decoder and audio out. |