demux_mkv: adjust subtitle preroll again (2)

Make the changes started in commit c827ae5f more eloborate, and provide
an option to control the amount of data read before the seek-target. To
achieve this, rewrite the loop that finds the lowest still acceptable
target cluster. It is now searched by time instead of file position. The
behavior (both with and without preroll option) may be different from
before this change, although it shouldn't be worse.

The change demux_mkv_read_cues() fixes a bug: when seeking after playing
normally, the code would erroneously assume that durations are set. This
doesn't happen if the first operation after loading was a seek instead
of playback.
This commit is contained in:
wm4 2014-11-14 23:52:47 +01:00
parent d484cb3f32
commit a6694d2788
4 changed files with 35 additions and 3 deletions

View File

@ -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=<value>``
See ``--demuxer-mkv-subtitle-preroll``.
``--demuxer-rawaudio-channels=<value>``
Number of channels (or channel layout) if ``--demuxer=rawaudio`` is used
(default: stereo).

View File

@ -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) {

View File

@ -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",

View File

@ -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;