summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-07-09 22:47:41 +0200
committerwm4 <wm4@nowhere>2015-07-09 22:47:41 +0200
commitf3d06e3e913ea061a716935a561c9d5c1758f718 (patch)
tree694026fd4e420b256d9cd40444bd058d90e92c4f
parentd23d9dc39421226622dbeb3c6c62c54ad1c3a667 (diff)
downloadmpv-f3d06e3e913ea061a716935a561c9d5c1758f718.tar.bz2
mpv-f3d06e3e913ea061a716935a561c9d5c1758f718.tar.xz
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.
-rw-r--r--DOCS/man/options.rst7
-rw-r--r--demux/demux_mkv.c45
2 files changed, 35 insertions, 17 deletions
diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst
index 8a0587e383..ae1147543d 100644
--- a/DOCS/man/options.rst
+++ b/DOCS/man/options.rst
@@ -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
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;