demux: make determining seek capability generic

Instead of having each demuxer do it (only demux_mkv actually did...),
let generic code determine whether the file is seekable. This requires
adding exceptions to demuxers where the stream is not seekable, but the
demuxer is.

Sort-of try to improve handling of unseekable files in the player. Exit
early if the file is determined to be unseekable, instead of resetting
all decoders and then performing a pointless seek.

Add an exception to allow seeking if the file is not seekable, but the
stream cache is enabled. Print a warning in this case, because seeking
outside the cache (which we can't prevent since the demuxer is not aware
of this problem) still messes everything up.
This commit is contained in:
wm4 2013-11-03 19:21:47 +01:00
parent 847cbe9d5d
commit a49ab7cc2f
7 changed files with 25 additions and 13 deletions

View File

@ -533,7 +533,8 @@ static struct demuxer *open_given_type(struct MPOpts *opts,
.type = desc->type,
.stream = stream,
.stream_pts = MP_NOPTS_VALUE,
.seekable = 1,
.seekable = (stream->flags & MP_STREAM_SEEK) == MP_STREAM_SEEK &&
stream->end_pos > 0,
.accurate_seek = true,
.filepos = -1,
.opts = opts,
@ -564,6 +565,12 @@ static struct demuxer *open_given_type(struct MPOpts *opts,
add_stream_chapters(demuxer);
demuxer_sort_chapters(demuxer);
demux_info_update(demuxer);
// Pretend we can seek if we can't seek, but there's a cache.
if (!demuxer->seekable && stream->uncached_stream) {
mp_msg(MSGT_DEMUXER, MSGL_WARN,
"File is not seekable, but there's a cache: enabling seeking.\n");
demuxer->seekable = true;
}
return demuxer;
}
@ -632,7 +639,7 @@ void demux_flush(demuxer_t *demuxer)
int demux_seek(demuxer_t *demuxer, float rel_seek_secs, int flags)
{
if (!demuxer->seekable) {
mp_tmsg(MSGT_SEEK, MSGL_WARN, "Cannot seek in this file.\n");
mp_tmsg(MSGT_DEMUXER, MSGL_WARN, "Cannot seek in this file.\n");
return 0;
}

View File

@ -584,9 +584,12 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
}
}
if (!(priv->avif->flags & AVFMT_NOFILE) &&
demuxer->stream->type != STREAMTYPE_AVDEVICE)
if ((priv->avif->flags & AVFMT_NOFILE) ||
demuxer->stream->type == STREAMTYPE_AVDEVICE)
{
// This might be incorrect.
demuxer->seekable = true;
} else {
void *buffer = av_malloc(lavfdopts->buffersize);
if (!buffer)
return -1;
@ -597,9 +600,7 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check)
return -1;
}
priv->pb->read_seek = mp_read_seek;
priv->pb->seekable = demuxer->stream->end_pos
&& (demuxer->stream->flags & MP_STREAM_SEEK) == MP_STREAM_SEEK
? AVIO_SEEKABLE_NORMAL : 0;
priv->pb->seekable = demuxer->seekable ? AVIO_SEEKABLE_NORMAL : 0;
avfc->pb = priv->pb;
}

View File

@ -100,6 +100,8 @@ static int d_check_file(struct demuxer *demuxer, enum demux_check check)
sh->sub->track = track;
sh->codec = "ass";
demuxer->seekable = true;
return 0;
}

View File

@ -210,6 +210,7 @@ static int demux_open_mf(demuxer_t* demuxer, enum demux_check check)
mf->sh = sh_video;
demuxer->priv=(void*)mf;
demuxer->seekable = true;
return 0;

View File

@ -1844,12 +1844,6 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check)
display_create_tracks(demuxer);
if (s->end_pos == 0) {
demuxer->seekable = 0;
} else {
demuxer->seekable = 1;
}
return 0;
}

View File

@ -1358,6 +1358,8 @@ static int d_open_file(struct demuxer *demuxer, enum demux_check check)
add_sub_data(demuxer, sd);
subdata_free(sd);
demuxer->seekable = true;
return 0;
}

View File

@ -215,6 +215,11 @@ static int seek(MPContext *mpctx, struct seek_params seek,
if (!mpctx->demuxer)
return -1;
if (!mpctx->demuxer->seekable) {
MP_ERR(mpctx, "Can't seek in this file.\n");
return -1;
}
if (mpctx->stop_play == AT_END_OF_FILE)
mpctx->stop_play = KEEP_PLAYING;
bool hr_seek = mpctx->demuxer->accurate_seek && opts->correct_pts;