diff options
author | wm4 <wm4@nowhere> | 2015-07-09 22:47:41 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2015-07-09 22:47:41 +0200 |
commit | f3d06e3e913ea061a716935a561c9d5c1758f718 (patch) | |
tree | 694026fd4e420b256d9cd40444bd058d90e92c4f /demux | |
parent | d23d9dc39421226622dbeb3c6c62c54ad1c3a667 (diff) |
demux_mkv: improve video duration detection heuristic
Extend the --demuxer-mkv-probe-video-duration behavior to work with
files that are partial and are missing an index. Do this by finding a
cluster 10MB before the end of the file, and if that fails, just read
the entire file. This is actually pretty trivial to do and requires only
5 lines of code.
Also add a mode that always reads the entire file to estimate the video
duration.
Diffstat (limited to 'demux')
-rw-r--r-- | demux/demux_mkv.c | 45 |
1 files changed, 29 insertions, 16 deletions
diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index 747ed4d125..089801da4e 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -198,7 +198,8 @@ const struct m_sub_options demux_mkv_conf = { OPT_FLAG("subtitle-preroll", subtitle_preroll, 0), OPT_DOUBLE("subtitle-preroll-secs", subtitle_preroll_secs, M_OPT_MIN, .min = 0), - OPT_FLAG("probe-video-duration", probe_duration, 0), + OPT_CHOICE("probe-video-duration", probe_duration, 0, + ({"no", 0}, {"yes", 1}, {"full", 2})), OPT_FLAG("fix-timestamps", fix_timestamps, 0), {0} }, @@ -2794,23 +2795,32 @@ static void probe_last_timestamp(struct demuxer *demuxer) if (v_tnum < 0) return; - read_deferred_cues(demuxer); - - if (!mkv_d->index_complete) - return; + // In full mode, we start reading data from the current file position, + // which works because this function is called after headers are parsed. + if (demuxer->opts->demux_mkv->probe_duration != 2) { + read_deferred_cues(demuxer); + if (mkv_d->index_complete) { + // Find last cluster that still has video packets + int64_t target = 0; + for (size_t i = 0; i < mkv_d->num_indexes; i++) { + struct mkv_index *cur = &mkv_d->indexes[i]; + if (cur->tnum == v_tnum) + target = MPMAX(target, cur->filepos); + } + if (!target) + return; - // Find last cluster that still has video packets - int64_t target = 0; - for (size_t i = 0; i < mkv_d->num_indexes; i++) { - struct mkv_index *cur = &mkv_d->indexes[i]; - if (cur->tnum == v_tnum) - target = MPMAX(target, cur->filepos); + if (!stream_seek(demuxer->stream, target)) + return; + } else { + // No index -> just try to find a random cluster towards file end. + int64_t size = 0; + stream_control(demuxer->stream, STREAM_CTRL_GET_SIZE, &size); + stream_seek(demuxer->stream, MPMAX(size - 10 * 1024 * 1024, 0)); + if (ebml_resync_cluster(mp_null_log, demuxer->stream) < 0) + stream_seek(demuxer->stream, old_pos); // full scan otherwise + } } - if (!target) - return; - - if (!stream_seek(demuxer->stream, target)) - return; int64_t last_ts[STREAM_TYPE_COUNT] = {0}; while (1) { @@ -2829,6 +2839,9 @@ static void probe_last_timestamp(struct demuxer *demuxer) } } + if (!last_ts[STREAM_VIDEO]) + last_ts[STREAM_VIDEO] = mkv_d->cluster_tc; + if (last_ts[STREAM_VIDEO]) mkv_d->duration = last_ts[STREAM_VIDEO] / 1e9; |