diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 8cd30d7fcf..feaeac6b30 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -2038,6 +2038,22 @@ Demuxer and hr-seeks, and this option changes behavior with relative or imprecise seeks only. + You can use the ``--demuxer-mkv-subtitle-preroll-secs`` option to specify + how mach data the demuxer should pre-read at most in order to find subtitle + packets that may overlap. Setting this to 0 will effectively disable this + preroll mechanism. Setting a very large value can make seeking very slow, + and an extremely large value would completely reread the entire file from + start to seek target on every seek - seeking can become slower towards the + end of the file. The details are messy, and the value is actually rounded + down to the cluster with the previous video keyframe. + + Some files, especially files muxed with newer mkvmerge versions, have + information embedded that can be used to determine what subtitle packets + overlap with a seek target. In these cases, mpv will reduce the amount + of data read to a minimum. (Although it will still read *all* data between + the cluster that contains the first wanted subtitle packet, and the seek + target.) + See also ``--hr-seek-demuxer-offset`` option. This option can achieve a similar effect, but only if hr-seek is active. It works with any demuxer, but makes seeking much slower, as it has to decode audio and video data @@ -2045,6 +2061,9 @@ Demuxer ``--mkv-subtitle-preroll`` is a deprecated alias. +``--demuxer-mkv-subtitle-preroll-secs=`` + See ``--demuxer-mkv-subtitle-preroll``. + ``--demuxer-rawaudio-channels=`` Number of channels (or channel layout) if ``--demuxer=rawaudio`` is used (default: stereo). diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index 79e62a112c..100447d1f7 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -717,6 +717,7 @@ static int demux_mkv_read_cues(demuxer_t *demuxer) return -1; mkv_d->num_indexes = 0; + mkv_d->index_has_durations = false; for (int i = 0; i < cues.n_cue_point; i++) { struct ebml_cue_point *cuepoint = &cues.cue_point[i]; @@ -2714,12 +2715,20 @@ static struct mkv_index *seek_with_cues(struct demuxer *demuxer, int seek_id, if (index) { /* We've found an entry. */ uint64_t seek_pos = index->filepos; if (flags & SEEK_SUBPREROLL) { + // Find the cluster with the highest filepos, that has a timestamp + // still lower than min_tc. + double secs = demuxer->opts->mkv_subtitle_preroll_secs; + uint64_t pre = MPMIN(INT64_MAX, secs * 1e9 / mkv_d->tc_scale); + uint64_t min_tc = pre < index->timecode ? index->timecode - pre : 0; uint64_t prev_target = 0; + uint64_t prev_tc = 0; for (size_t i = 0; i < mkv_d->num_indexes; i++) { if (seek_id < 0 || mkv_d->indexes[i].tnum == seek_id) { - uint64_t index_pos = mkv_d->indexes[i].filepos; - if (index_pos > prev_target && index_pos < seek_pos) - prev_target = index_pos; + struct mkv_index *cur = &mkv_d->indexes[i]; + if (cur->timecode <= min_tc && cur->timecode >= prev_tc) { + prev_tc = cur->timecode; + prev_target = cur->filepos; + } } } if (mkv_d->index_has_durations) { diff --git a/options/options.c b/options/options.c index c15482fd05..ba251f6216 100644 --- a/options/options.c +++ b/options/options.c @@ -301,6 +301,8 @@ const m_option_t mp_opts[] = { OPT_FLAG("demuxer-mkv-subtitle-preroll", mkv_subtitle_preroll, 0), OPT_FLAG("mkv-subtitle-preroll", mkv_subtitle_preroll, 0), // old alias + OPT_DOUBLE("demuxer-mkv-subtitle-preroll-secs", mkv_subtitle_preroll_secs, + M_OPT_MIN, .min = 0), // ------------------------- subtitles options -------------------- @@ -670,6 +672,7 @@ const struct MPOpts mp_default_opts = { .use_embedded_fonts = 1, .sub_fix_timing = 1, .sub_cp = "auto", + .mkv_subtitle_preroll_secs = 1.0, .hwdec_codecs = "h264,vc1,wmv3", diff --git a/options/options.h b/options/options.h index f67a3a5c95..9284320f40 100644 --- a/options/options.h +++ b/options/options.h @@ -194,6 +194,7 @@ typedef struct MPOpts { char *audio_demuxer_name; char *sub_demuxer_name; int mkv_subtitle_preroll; + double mkv_subtitle_preroll_secs; double demuxer_min_secs_cache; int cache_pausing;