diff options
author | wm4 <wm4@nowhere> | 2016-08-07 16:29:13 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2016-08-07 16:29:13 +0200 |
commit | 259f2194385e86e47eb054d43f155ca897e265c6 (patch) | |
tree | 9f9e0446ffb24305849956d1404eaf7d2bd123db | |
parent | c7b73edc652785885163879bda3981a3d43cd466 (diff) | |
download | mpv-259f2194385e86e47eb054d43f155ca897e265c6.tar.bz2 mpv-259f2194385e86e47eb054d43f155ca897e265c6.tar.xz |
player: gross hack to improve non-hr seeking with external audio tracks
Relative seeks backwards with external audio tracks does not always work
well: it tends to happen that video seek back further than audio, so
audio will remain silent until the audio's after-seek position is
reached. This happens because we strictly seek both video and audio
demuxer to the approximate desirted target PTS, and then start decoding
from that.
Commit 81358380 removes an older method that was supposed to deal with
this. It was sort of bad, because it could lead to the playback core
freezing by waiting on network.
Ideally, the demuxer layer would probably somehow deal with such seeks,
and do them in a way the audio is seeked after video. Currently this is
infeasible, because the demuxer layer assumes a single demuxer, and
external tracks simply use separate demuxer layers. (MPlayer actually
had a pseudo-demuxer that joined external tracks into a single demuxer,
but this is not flexible enough - and also, the demuxer layer as it
currently exists can't deal with dynamically removing external tracks
either. Maybe some time in the future.)
Instead, add a gross hack, that essentially reseeks the audio if it
detects that it's too far off. The result is actually not too bad,
because we can reuse the mechanism that is used for instant track
switching. This way we can make sure of the right position, without
having to care about certain other issues.
It should be noted that if the audio demuxer is used for other tracks
too, and the demuxer does not support refresh seeking, audio will
probably be off by even a higher amount. But this should be rare.
-rw-r--r-- | player/audio.c | 22 | ||||
-rw-r--r-- | player/core.h | 4 | ||||
-rw-r--r-- | player/playloop.c | 4 |
3 files changed, 30 insertions, 0 deletions
diff --git a/player/audio.c b/player/audio.c index fd007fedf7..e186a375b6 100644 --- a/player/audio.c +++ b/player/audio.c @@ -268,6 +268,7 @@ void reset_audio_state(struct MPContext *mpctx) mpctx->delay = 0; mpctx->audio_drop_throttle = 0; mpctx->audio_stat_start = 0; + mpctx->audio_allow_second_chance_seek = false; } void uninit_audio_out(struct MPContext *mpctx) @@ -688,6 +689,27 @@ static bool get_sync_samples(struct MPContext *mpctx, int *skip) } ptsdiff = MPCLAMP(ptsdiff, -3600, 3600); + // Heuristic: if audio is "too far" ahead, and one of them is a separate + // track, allow a refresh seek to the correct position to fix it. + if (ptsdiff > 0.2 && mpctx->audio_allow_second_chance_seek && sync_to_video) { + struct ao_chain *ao_c = mpctx->ao_chain; + if (ao_c && ao_c->track && mpctx->vo_chain && mpctx->vo_chain->track && + ao_c->track->demuxer != mpctx->vo_chain->track->demuxer) + { + struct track *track = ao_c->track; + double pts = mpctx->video_pts; + if (pts != MP_NOPTS_VALUE) + pts += get_track_seek_offset(mpctx, track); + // (disable it first to make it take any effect) + demuxer_select_track(track->demuxer, track->stream, pts, false); + demuxer_select_track(track->demuxer, track->stream, pts, true); + reset_audio_state(mpctx); + MP_VERBOSE(mpctx, "retrying audio seek\n"); + return false; + } + } + mpctx->audio_allow_second_chance_seek = false; + int align = af_format_sample_alignment(out_format.format); *skip = (int)(-ptsdiff * play_samplerate) / align * align; return true; diff --git a/player/core.h b/player/core.h index 1dc6da7331..70570fccb3 100644 --- a/player/core.h +++ b/player/core.h @@ -382,6 +382,10 @@ typedef struct MPContext { bool immediate; // disable seek delay logic } seek; + // Allow audio to issue a second seek if audio is too far ahead (for non-hr + // seeks with external audio tracks). + bool audio_allow_second_chance_seek; + /* Heuristic for relative chapter seeks: keep track which chapter * the user wanted to go to, even if we aren't exactly within the * boundaries of that chapter due to an inaccurate seek. */ diff --git a/player/playloop.c b/player/playloop.c index da3e995975..9b15ac3f50 100644 --- a/player/playloop.c +++ b/player/playloop.c @@ -298,6 +298,9 @@ static void mp_seek(MPContext *mpctx, struct seek_params seek) mp_notify(mpctx, MPV_EVENT_SEEK, NULL); mp_notify(mpctx, MPV_EVENT_TICK, NULL); + + mpctx->audio_allow_second_chance_seek = + !hr_seek && !(demux_flags & SEEK_FORWARD); } // This combines consecutive seek requests. @@ -889,6 +892,7 @@ static void handle_playback_restart(struct MPContext *mpctx) if (!mpctx->restart_complete) { mpctx->hrseek_active = false; mpctx->restart_complete = true; + mpctx->audio_allow_second_chance_seek = false; mp_notify(mpctx, MPV_EVENT_PLAYBACK_RESTART, NULL); if (!mpctx->playing_msg_shown) { if (opts->playing_msg && opts->playing_msg[0]) { |