diff options
authorwm4 <wm4@nowhere>2016-08-07 16:29:13 +0200
committerwm4 <wm4@nowhere>2016-08-07 16:29:13 +0200
commit259f2194385e86e47eb054d43f155ca897e265c6 (patch)
parentc7b73edc652785885163879bda3981a3d43cd466 (diff)
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.
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;
if (!mpctx->playing_msg_shown) {
if (opts->playing_msg && opts->playing_msg[0]) {