From c4e43aaf896ac2267f8f2c10c8c37c3cb565f640 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 11 Apr 2013 17:40:23 +0200 Subject: demux_mkv: use normal index data structure even for incomplete files Incomplete files don't have a valid index, because the index is usually located near the end of a file. In this case, an index is created on the fly during demuxing, or when seeks are done. This used a completely different code path, which leads to unnecessary complications and code duplication. Use the normal index data structure instead. The seeking code at the end of seek_creating_index() (in this commit renamed to create_index_until()) is removed. The normal seek code does the same thing instead. --- demux/demux_mkv.c | 147 +++++++++++++++++++++++------------------------------- 1 file changed, 63 insertions(+), 84 deletions(-) (limited to 'demux/demux_mkv.c') diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index ee39038c77..6dd84b20c9 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -161,6 +161,8 @@ typedef struct mkv_demuxer { mkv_index_t *indexes; int num_indexes; + uint64_t index_max_timecode; + bool index_complete; int64_t *parsed_pos; int num_parsed_pos; @@ -170,12 +172,6 @@ typedef struct mkv_demuxer { bool parsed_chapters; bool parsed_attachments; - struct cluster_pos { - uint64_t filepos; - uint64_t timecode; - } *cluster_positions; - int num_cluster_pos; - uint64_t skip_to_timecode; int v_skip_to_keyframe, a_skip_to_keyframe; bool subtitle_preroll; @@ -235,26 +231,6 @@ static mkv_track_t *find_track_by_num(struct mkv_demuxer *d, int n, int type) return NULL; } -static void add_cluster_position(mkv_demuxer_t *mkv_d, uint64_t filepos, - uint64_t timecode) -{ - if (mkv_d->indexes) - return; - - int n = mkv_d->num_cluster_pos; - if (n > 0 && mkv_d->cluster_positions[n-1].filepos >= filepos) - return; - - mkv_d->cluster_positions = - grow_array(mkv_d->cluster_positions, mkv_d->num_cluster_pos, - sizeof(*mkv_d->cluster_positions)); - mkv_d->cluster_positions[mkv_d->num_cluster_pos++] = (struct cluster_pos){ - .filepos = filepos, - .timecode = timecode, - }; -} - - #define AAC_SYNC_EXTENSION_TYPE 0x02b7 static int aac_get_sample_rate_index(uint32_t sample_rate) { @@ -712,6 +688,32 @@ static int demux_mkv_read_tracks(demuxer_t *demuxer) return 0; } +static void cue_index_add(demuxer_t *demuxer, int track_id, uint64_t filepos, + uint64_t timecode) +{ + mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv; + + mkv_d->indexes = grow_array(mkv_d->indexes, mkv_d->num_indexes, + sizeof(mkv_index_t)); + mkv_d->indexes[mkv_d->num_indexes].tnum = track_id; + mkv_d->indexes[mkv_d->num_indexes].timecode = timecode; + mkv_d->indexes[mkv_d->num_indexes].filepos = filepos; + mkv_d->num_indexes++; + + mkv_d->index_max_timecode = FFMAX(mkv_d->index_max_timecode, timecode); +} + +static void add_cluster_position(demuxer_t *demuxer, uint64_t filepos, + uint64_t timecode) +{ + mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv; + + if (mkv_d->index_complete) + return; + if (timecode > mkv_d->index_max_timecode) + cue_index_add(demuxer, -1, filepos, timecode); +} + static int demux_mkv_read_cues(demuxer_t *demuxer) { mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv; @@ -737,23 +739,18 @@ static int demux_mkv_read_cues(demuxer_t *demuxer) for (int i = 0; i < cuepoint->n_cue_track_positions; i++) { struct ebml_cue_track_positions *trackpos = &cuepoint->cue_track_positions[i]; - uint64_t track = trackpos->cue_track; - uint64_t pos = trackpos->cue_cluster_position; - mkv_d->indexes = - grow_array(mkv_d->indexes, mkv_d->num_indexes, - sizeof(mkv_index_t)); - mkv_d->indexes[mkv_d->num_indexes].tnum = track; - mkv_d->indexes[mkv_d->num_indexes].timecode = time; - mkv_d->indexes[mkv_d->num_indexes].filepos = - mkv_d->segment_start + pos; + uint64_t pos = mkv_d->segment_start + trackpos->cue_cluster_position; + cue_index_add(demuxer, trackpos->cue_track, pos, time); mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] |+ found cue point for track %" PRIu64 - ": timecode %" PRIu64 ", filepos: %" PRIu64 "\n", track, - time, mkv_d->segment_start + pos); - mkv_d->num_indexes++; + ": timecode %" PRIu64 ", filepos: %" PRIu64 "\n", + trackpos->cue_track, time, pos); } } + // Do not attempt to create index on the fly. + mkv_d->index_complete = true; + mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] \\---- [ parsing cues ] -----------\n"); talloc_free(parse_ctx.talloc_ctx); return 0; @@ -1646,7 +1643,6 @@ static void mkv_free(struct demuxer *demuxer) for (int i = 0; i < mkv_d->num_tracks; i++) demux_mkv_free_trackentry(mkv_d->tracks[i]); free(mkv_d->indexes); - free(mkv_d->cluster_positions); } static int demux_mkv_open(demuxer_t *demuxer) @@ -2267,8 +2263,7 @@ static int demux_mkv_fill_buffer(demuxer_t *demuxer, demux_stream_t *ds) if (num == EBML_UINT_INVALID) return 0; mkv_d->cluster_tc = num * mkv_d->tc_scale; - add_cluster_position(mkv_d, mkv_d->cluster_start, - mkv_d->cluster_tc); + add_cluster_position(demuxer, mkv_d->cluster_start, num); break; case MATROSKA_ID_BLOCKGROUP: @@ -2330,27 +2325,29 @@ static int demux_mkv_fill_buffer(demuxer_t *demuxer, demux_stream_t *ds) return 0; } -static int seek_creating_index(struct demuxer *demuxer, float rel_seek_secs, - int flags) +static int create_index_until(struct demuxer *demuxer, uint64_t timecode) { struct mkv_demuxer *mkv_d = demuxer->priv; struct stream *s = demuxer->stream; - int64_t target_tc_ns = (int64_t) (rel_seek_secs * 1e9); - if (target_tc_ns < 0) - target_tc_ns = 0; - uint64_t max_filepos = 0; - int64_t max_tc = -1; - int n = mkv_d->num_cluster_pos; - if (n > 0) { - max_filepos = mkv_d->cluster_positions[n - 1].filepos; - max_tc = mkv_d->cluster_positions[n - 1].timecode; - } - if (target_tc_ns > max_tc) { - if ((int64_t) max_filepos > stream_tell(s)) + if (mkv_d->index_complete) + return 0; + + if (mkv_d->index_max_timecode * mkv_d->tc_scale < timecode) { + int64_t cur_filepos = stream_tell(s); + uint64_t max_filepos = 0; + for (int n = 0; n < mkv_d->num_indexes; n++) { + if (mkv_d->indexes[n].timecode == mkv_d->index_max_timecode) { + max_filepos = mkv_d->indexes[n].filepos; + break; + } + } + if ((int64_t) max_filepos > cur_filepos) stream_seek(s, max_filepos); else - stream_seek(s, stream_tell(s) + mkv_d->cluster_size); + stream_seek(s, cur_filepos + mkv_d->cluster_size); + mp_msg(MSGT_DEMUX, MSGL_V, + "[mkv] creating index until TC %" PRIu64 "\n", timecode); /* parse all the clusters upto target_filepos */ while (!s->eof) { uint64_t start = stream_tell(s); @@ -2361,9 +2358,8 @@ static int seek_creating_index(struct demuxer *demuxer, float rel_seek_secs, while (!s->eof && stream_tell(s) < end) { if (ebml_read_id(s, NULL) == MATROSKA_ID_TIMECODE) { uint64_t tc = ebml_read_uint(s, NULL); - tc *= mkv_d->tc_scale; - add_cluster_position(mkv_d, start, tc); - if (tc >= target_tc_ns) + add_cluster_position(demuxer, start, tc); + if (tc * mkv_d->tc_scale >= timecode) goto enough_index; break; } @@ -2374,29 +2370,12 @@ static int seek_creating_index(struct demuxer *demuxer, float rel_seek_secs, stream_seek(s, end); } enough_index: - if (s->eof) - stream_reset(s); + stream_seek(s, cur_filepos); } - if (!mkv_d->num_cluster_pos) { - mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] no target for seek found\n"); + if (!mkv_d->indexes) { + mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] no target for seek found\n"); return -1; } - uint64_t cluster_pos = mkv_d->cluster_positions[0].filepos; - /* Let's find the nearest cluster */ - int64_t min_diff = 0xFFFFFFFFFFFFFFF; - for (int i = 0; i < mkv_d->num_cluster_pos; i++) { - int64_t diff = mkv_d->cluster_positions[i].timecode - target_tc_ns; - if (flags & SEEK_BACKWARD && diff < 0 && -diff < min_diff) { - cluster_pos = mkv_d->cluster_positions[i].filepos; - min_diff = -diff; - } else if (flags & SEEK_FORWARD - && (diff < 0 ? -1 * diff : diff) < min_diff) { - cluster_pos = mkv_d->cluster_positions[i].filepos; - min_diff = diff < 0 ? -1 * diff : diff; - } - } - mkv_d->cluster_size = mkv_d->blockgroup_size = 0; - stream_seek(s, cluster_pos); return 0; } @@ -2406,6 +2385,9 @@ static struct mkv_index *seek_with_cues(struct demuxer *demuxer, int seek_id, struct mkv_demuxer *mkv_d = demuxer->priv; struct mkv_index *index = NULL; + if (!mkv_d->index_complete) + seek_id = -1; + /* Find the entry in the index closest to the target timecode in the * give direction. If there are no such entries - we're trying to seek * backward from a target time before the first entry or forward from a @@ -2485,10 +2467,7 @@ static void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs, rel_seek_secs = FFMAX(rel_seek_secs, 0); int64_t target_timecode = rel_seek_secs * 1e9 + 0.5; - if (mkv_d->indexes == NULL) { /* no index was found */ - if (seek_creating_index(demuxer, rel_seek_secs, flags) < 0) - return; - } else { + if (create_index_until(demuxer, target_timecode) >= 0) { int seek_id = (demuxer->video->id < 0) ? a_tnum : v_tnum; index = seek_with_cues(demuxer, seek_id, target_timecode, flags); @@ -2514,7 +2493,7 @@ static void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs, mkv_index_t *index = NULL; int i; - if (mkv_d->indexes == NULL) { /* not implemented without index */ + if (!mkv_d->index_complete) { /* not implemented without index */ mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek unsupported flags\n"); return; } -- cgit v1.2.3