player: fix desync when seeking and switching external tracks

If you for example use --audio-file, disable the external track, seek,
and enable the external track again, the playback position of the
external file was off, and you would get major A/V desync. This was
actually supposed to work, but broke at some time ago (probably commit
2b87415f). It didn't work, because it attempted to seek the stream if it
was already selected, which was always true due to
reselect_demux_streams() being called before that.

Fix by putting the initial selection and the seek together.
This commit is contained in:
wm4 2014-07-29 17:55:28 +02:00
parent 6d15c491b0
commit 862d7d8a1a
6 changed files with 30 additions and 32 deletions

View File

@ -96,7 +96,7 @@ void reinit_audio_chain(struct MPContext *mpctx)
{
struct MPOpts *opts = mpctx->opts;
struct track *track = mpctx->current_track[0][STREAM_AUDIO];
struct sh_stream *sh = init_demux_stream(mpctx, track);
struct sh_stream *sh = track ? track->stream : NULL;
if (!sh) {
uninit_player(mpctx, INITIALIZED_AO);
goto no_audio;

View File

@ -414,8 +414,6 @@ struct track *mp_track_by_tid(struct MPContext *mpctx, enum stream_type type,
int tid);
bool timeline_set_part(struct MPContext *mpctx, int i, bool force);
double timeline_set_from_time(struct MPContext *mpctx, double pts, bool *need_reset);
struct sh_stream *init_demux_stream(struct MPContext *mpctx, struct track *track);
void reselect_demux_streams(struct MPContext *mpctx);
void add_demuxer_tracks(struct MPContext *mpctx, struct demuxer *demuxer);
bool mp_remove_track(struct MPContext *mpctx, struct track *track);
struct playlist_entry *mp_next_file(struct MPContext *mpctx, int direction,

View File

@ -60,6 +60,8 @@
#include "command.h"
#include "libmpv/client.h"
static void reselect_demux_streams(struct MPContext *mpctx);
static void uninit_sub(struct MPContext *mpctx, int order)
{
if (mpctx->d_sub[order])
@ -264,41 +266,41 @@ void update_demuxer_properties(struct MPContext *mpctx)
demuxer->events = 0;
}
static bool need_init_seek(struct demuxer *demux)
{
for (int n = 0; n < demux->num_streams; n++) {
struct sh_stream *stream = demux->streams[n];
// Subtitle streams are not properly interleaved -> force init. seek.
if (stream->type != STREAM_SUB && demux_stream_is_selected(stream))
return false;
}
return true;
}
// Enable needed streams, disable others.
// Note that switching all tracks at once (instead when initializing something)
// can be important, because reading from a demuxer stream (e.g. during init)
// will implicitly discard interleaved packets from unselected streams.
void reselect_demux_streams(struct MPContext *mpctx)
// Also initializes position for external streams.
static void reselect_demux_streams(struct MPContext *mpctx)
{
// Note: we assume that all demuxer streams are covered by the track list.
for (int t = 0; t < mpctx->num_tracks; t++) {
struct track *track = mpctx->tracks[t];
if (track->demuxer && track->stream)
if (track->demuxer && track->stream) {
bool need_init = track->selected &&
mpctx->demuxer != track->demuxer &&
need_init_seek(track->demuxer);
demuxer_select_track(track->demuxer, track->stream, track->selected);
}
}
// External demuxers might need a seek to the current playback position.
static void external_track_seek(struct MPContext *mpctx, struct track *track)
{
if (track && track->demuxer && track->selected && track->is_external) {
for (int t = 0; t < mpctx->num_tracks; t++) {
struct track *other = mpctx->tracks[t];
if (other->demuxer == track->demuxer &&
demux_stream_is_selected(other->stream))
return;
if (need_init) {
double pts = get_main_demux_pts(mpctx);
if (pts != MP_NOPTS_VALUE)
demux_seek(track->demuxer, pts, SEEK_ABSOLUTE);
}
}
double pts = get_main_demux_pts(mpctx);
demux_seek(track->demuxer, pts, SEEK_ABSOLUTE);
}
}
struct sh_stream *init_demux_stream(struct MPContext *mpctx, struct track *track)
{
external_track_seek(mpctx, track);
return track ? track->stream : NULL;
}
static struct sh_stream *select_fallback_stream(struct demuxer *d,
enum stream_type type,
int index)

View File

@ -100,8 +100,9 @@ double get_main_demux_pts(struct MPContext *mpctx)
double main_new_pos = MP_NOPTS_VALUE;
if (mpctx->demuxer) {
for (int n = 0; n < mpctx->demuxer->num_streams; n++) {
if (main_new_pos == MP_NOPTS_VALUE)
main_new_pos = demux_get_next_pts(mpctx->demuxer->streams[n]);
struct sh_stream *stream = mpctx->demuxer->streams[n];
if (main_new_pos == MP_NOPTS_VALUE && stream->type != STREAM_SUB)
main_new_pos = demux_get_next_pts(stream);
}
}
return main_new_pos;

View File

@ -194,10 +194,7 @@ void reinit_subs(struct MPContext *mpctx, int order)
assert(!(mpctx->initialized_flags & init_flag));
struct sh_stream *sh = init_demux_stream(mpctx, track);
// No track selected, or lazily added DVD track (will actually be created
// on first sub packet)
struct sh_stream *sh = track ? track->stream : NULL;
if (!sh)
return;

View File

@ -174,7 +174,7 @@ int reinit_video_chain(struct MPContext *mpctx)
assert(!(mpctx->initialized_flags & INITIALIZED_VCODEC));
assert(!mpctx->d_video);
struct track *track = mpctx->current_track[0][STREAM_VIDEO];
struct sh_stream *sh = init_demux_stream(mpctx, track);
struct sh_stream *sh = track ? track->stream : NULL;
if (!sh)
goto no_video;