mirror of https://github.com/mpv-player/mpv
demux_mkv: defer reading of seek index until first seek
Playing Youtube videos often requires an additional seek to the end of the file. This flushes the stream cache. The reason for the seek is reading the cues (seek index). This poses the question why Google is muxing its files in such a way, since nothing in Matroska mandates that cues are located at the end of the file, but we want to handle this situation better anyway. The seek index is not needed for normal playback, only for seeking. This commit changes header parsing such that the index is not read on initialization in order to avoid the additional stream-level seek. Instead, read the index on the first demuxer-level seek, when the seek index is actually needed. If the cues are at the beginning of the file, they are read immediately as part of the normal header reading process. This commit changes behavior only if cues are outside of the header (i.e. not in the area between EBML header and clusters), and linked by a SeekHead. Other level 1 elements linked by the SeekHead might still cause seeks to the end of the file, although that seems to be rare.
This commit is contained in:
parent
1139eae082
commit
5bdf9d01ca
|
@ -166,6 +166,7 @@ typedef struct mkv_demuxer {
|
|||
mkv_index_t *indexes;
|
||||
int num_indexes;
|
||||
bool index_complete;
|
||||
uint64_t deferred_cues;
|
||||
|
||||
int64_t *parsed_pos;
|
||||
int num_parsed_pos;
|
||||
|
@ -721,6 +722,9 @@ static int demux_mkv_read_cues(demuxer_t *demuxer)
|
|||
struct ebml_parse_ctx parse_ctx = {};
|
||||
if (ebml_read_element(s, &parse_ctx, &cues, &ebml_cues_desc) < 0)
|
||||
return -1;
|
||||
|
||||
mkv_d->num_indexes = 0;
|
||||
|
||||
for (int i = 0; i < cues.n_cue_point; i++) {
|
||||
struct ebml_cue_point *cuepoint = &cues.cue_point[i];
|
||||
if (cuepoint->n_cue_time != 1 || !cuepoint->n_cue_track_positions) {
|
||||
|
@ -748,6 +752,26 @@ static int demux_mkv_read_cues(demuxer_t *demuxer)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void read_deferred_cues(demuxer_t *demuxer)
|
||||
{
|
||||
mkv_demuxer_t *mkv_d = demuxer->priv;
|
||||
stream_t *s = demuxer->stream;
|
||||
|
||||
if (mkv_d->deferred_cues) {
|
||||
int64_t pos = mkv_d->deferred_cues;
|
||||
mkv_d->deferred_cues = 0;
|
||||
if (!stream_seek(s, pos)) {
|
||||
mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Failed to seek to cues\n");
|
||||
return;
|
||||
}
|
||||
if (ebml_read_id(s, NULL) != MATROSKA_ID_CUES) {
|
||||
mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Expected element not found\n");
|
||||
return;
|
||||
}
|
||||
demux_mkv_read_cues(demuxer);
|
||||
}
|
||||
}
|
||||
|
||||
static int demux_mkv_read_chapters(struct demuxer *demuxer)
|
||||
{
|
||||
struct MPOpts *opts = demuxer->opts;
|
||||
|
@ -1019,9 +1043,13 @@ static int read_header_element(struct demuxer *demuxer, uint32_t id,
|
|||
case MATROSKA_ID_CUES:
|
||||
if (mkv_d->parsed_cues)
|
||||
break;
|
||||
if (at_filepos && !seek_pos_id(s, at_filepos, id))
|
||||
return -1;
|
||||
if (at_filepos) {
|
||||
// Read cues when they are needed, to avoid seeking on opening.
|
||||
mkv_d->deferred_cues = at_filepos;
|
||||
return 1;
|
||||
}
|
||||
mkv_d->parsed_cues = true;
|
||||
mkv_d->deferred_cues = 0;
|
||||
return demux_mkv_read_cues(demuxer);
|
||||
|
||||
case MATROSKA_ID_TAGS:
|
||||
|
@ -2364,6 +2392,8 @@ static int create_index_until(struct demuxer *demuxer, uint64_t timecode)
|
|||
struct mkv_demuxer *mkv_d = demuxer->priv;
|
||||
struct stream *s = demuxer->stream;
|
||||
|
||||
read_deferred_cues(demuxer);
|
||||
|
||||
if (mkv_d->index_complete)
|
||||
return 0;
|
||||
|
||||
|
@ -2462,6 +2492,7 @@ static void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs,
|
|||
float audio_delay, int flags)
|
||||
{
|
||||
mkv_demuxer_t *mkv_d = demuxer->priv;
|
||||
int64_t old_pos = stream_tell(demuxer->stream);
|
||||
uint64_t v_tnum = -1;
|
||||
uint64_t a_tnum = -1;
|
||||
bool st_active[STREAM_TYPE_COUNT] = {0};
|
||||
|
@ -2501,6 +2532,9 @@ static void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs,
|
|||
index = seek_with_cues(demuxer, -1, target_timecode, flags);
|
||||
}
|
||||
|
||||
if (!index)
|
||||
stream_seek(demuxer->stream, old_pos);
|
||||
|
||||
if (st_active[STREAM_VIDEO])
|
||||
mkv_d->v_skip_to_keyframe = 1;
|
||||
if (flags & SEEK_FORWARD)
|
||||
|
@ -2519,8 +2553,11 @@ static void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs,
|
|||
mkv_index_t *index = NULL;
|
||||
int i;
|
||||
|
||||
read_deferred_cues(demuxer);
|
||||
|
||||
if (!mkv_d->index_complete) { /* not implemented without index */
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek unsupported flags\n");
|
||||
stream_seek(s, old_pos);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2533,8 +2570,10 @@ static void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs,
|
|||
|| (mkv_d->indexes[i].filepos < index->filepos))))
|
||||
index = &mkv_d->indexes[i];
|
||||
|
||||
if (!index)
|
||||
if (!index) {
|
||||
stream_seek(s, old_pos);
|
||||
return;
|
||||
}
|
||||
|
||||
mkv_d->cluster_end = 0;
|
||||
stream_seek(s, index->filepos);
|
||||
|
|
Loading…
Reference in New Issue