mirror of
https://github.com/mpv-player/mpv
synced 2025-01-11 09:29:29 +00:00
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.
This commit is contained in:
parent
d23d9dc394
commit
f3d06e3e91
@ -2137,13 +2137,18 @@ Demuxer
|
||||
``--demuxer-mkv-subtitle-preroll-secs=<value>``
|
||||
See ``--demuxer-mkv-subtitle-preroll``.
|
||||
|
||||
``--demuxer-mkv-probe-video-duration``
|
||||
``--demuxer-mkv-probe-video-duration=<yes|no|full>``
|
||||
When opening the file, seek to the end of it, and check what timestamp the
|
||||
last video packet has, and report that as file duration. This is strictly
|
||||
for compatibility with Haali only. In this mode, it's possible that opening
|
||||
will be slower (especially when playing over http), or that behavior with
|
||||
broken files is much worse. So don't use this option.
|
||||
|
||||
The ``yes`` mode merely uses the index and reads a small number of blocks
|
||||
from the end of the file. The ``full`` mode actually traverses the entire
|
||||
file and can make a reliable estimate even without an index present (such
|
||||
as partial files).
|
||||
|
||||
``--demuxer-mkv-fix-timestamps=<yes|no>``
|
||||
Fix rounded Matroska timestamps (enabled by default). Matroska usually
|
||||
stores timestamps rounded to milliseconds. This means timestamps jitter
|
||||
|
@ -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);
|
||||
// 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;
|
||||
|
||||
if (!mkv_d->index_complete)
|
||||
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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user