mirror of https://github.com/mpv-player/mpv
demux_mkv: try to show current subtitle when seeking
Makes sure that seeking to a given time position shows the subtitle at that position. This can fail if the subtitle packet is not close enough to the seek target. Always enabled for hr-seeks, and can be manually enabled for normal seeks with --mkv-subtitle-preroll. This helps displaying subtitles correctly with ordered chapters. When switching ordered chapter segments, a seek is performed. If the subtitle is timed slightly before the start of the segment, it normally won't be demuxed. This is a problem with all seeks, but in this case normal playback is affected. Since switching segments always uses hr-seeks, the code added by this commit is always active in this situation. If no subtitles are selected or the subtitles come from an external file, the demuxer should behave exactly as before this commit.
This commit is contained in:
parent
f36a5a88d0
commit
75afa370b9
|
@ -1173,6 +1173,29 @@
|
|||
:fps=<value>: output fps (default: 25)
|
||||
:type=<value>: input file type (available: jpeg, png, tga, sgi)
|
||||
|
||||
--mkv-subtitle-preroll
|
||||
Try harder to show embedded soft subtitles when seeking somewhere. Normally,
|
||||
it can happen that the subtitle at the seek target is not shown due to how
|
||||
some container file formats are designed. The subtitles appear only if
|
||||
seeking before or exactly to the position a subtitle first appears. To
|
||||
make this worse, subtitles are often timed to appear a very small amount
|
||||
before the associated video frame, so that seeking to the video frame
|
||||
typically does not demux the subtitle at that position.
|
||||
|
||||
Enabling this option makes the demuxer start reading data a bit before the
|
||||
seek target, so that subtitles appear correctly. Note that this makes
|
||||
seeking slower, and is not guaranteed to always work. It only works if the
|
||||
subtitle is close enough to the seek target.
|
||||
|
||||
Works with the internal Matroska demuxer only. Always enabled for absolute
|
||||
and hr-seeks, and this option changes behavior with relative or imprecise
|
||||
seeks only.
|
||||
|
||||
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,
|
||||
instead of just skipping over it.
|
||||
|
||||
--mixer=<device>
|
||||
Use a mixer device different from the default ``/dev/mixer``. For ALSA
|
||||
this is the mixer name.
|
||||
|
|
|
@ -391,6 +391,7 @@ const m_option_t common_opts[] = {
|
|||
OPT_STRING("audio-demuxer", audio_demuxer_name, 0),
|
||||
OPT_STRING("sub-demuxer", sub_demuxer_name, 0),
|
||||
OPT_FLAG("extbased", extension_parsing, 0),
|
||||
OPT_FLAG("mkv-subtitle-preroll", mkv_subtitle_preroll, 0),
|
||||
|
||||
{"mf", (void *) mfopts_conf, CONF_TYPE_SUBCONFIG, 0,0,0, NULL},
|
||||
#ifdef CONFIG_RADIO
|
||||
|
|
|
@ -2821,6 +2821,8 @@ static int seek(MPContext *mpctx, struct seek_params seek,
|
|||
demuxer_style |= SEEK_BACKWARD;
|
||||
else if (seek.direction > 0)
|
||||
demuxer_style |= SEEK_FORWARD;
|
||||
if (hr_seek || opts->mkv_subtitle_preroll)
|
||||
demuxer_style |= SEEK_SUBPREROLL;
|
||||
|
||||
if (hr_seek)
|
||||
demuxer_amount -= opts->hr_seek_demuxer_offset;
|
||||
|
|
|
@ -140,6 +140,7 @@ typedef struct MPOpts {
|
|||
char *audio_demuxer_name;
|
||||
char *sub_demuxer_name;
|
||||
int extension_parsing;
|
||||
int mkv_subtitle_preroll;
|
||||
|
||||
struct image_writer_opts *screenshot_image_opts;
|
||||
char *screenshot_template;
|
||||
|
|
|
@ -103,6 +103,7 @@ enum timestamp_type {
|
|||
#define SEEK_FACTOR (1 << 1)
|
||||
#define SEEK_FORWARD (1 << 2)
|
||||
#define SEEK_BACKWARD (1 << 3)
|
||||
#define SEEK_SUBPREROLL (1 << 4)
|
||||
|
||||
// demux_lavf can pass lavf buffers using FF_INPUT_BUFFER_PADDING_SIZE instead
|
||||
#define MP_INPUT_BUFFER_PADDING_SIZE 16
|
||||
|
|
|
@ -178,6 +178,7 @@ typedef struct mkv_demuxer {
|
|||
|
||||
uint64_t skip_to_timecode;
|
||||
int v_skip_to_keyframe, a_skip_to_keyframe;
|
||||
bool subtitle_preroll;
|
||||
|
||||
int num_audio_tracks;
|
||||
int num_video_tracks;
|
||||
|
@ -2114,6 +2115,18 @@ static int handle_block(demuxer_t *demuxer, uint8_t *block, uint64_t length,
|
|||
track->fix_i_bps = 0;
|
||||
}
|
||||
}
|
||||
} else if (track->type == MATROSKA_TRACK_SUBTITLE
|
||||
&& track->id == demuxer->sub->id) {
|
||||
if (tc < mkv_d->skip_to_timecode && !mkv_d->subtitle_preroll)
|
||||
use_this_block = 0;
|
||||
if (use_this_block) {
|
||||
ds = demuxer->sub;
|
||||
if (laces > 1) {
|
||||
mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Subtitles use Matroska "
|
||||
"lacing. This is abnormal and not supported.\n");
|
||||
use_this_block = 0;
|
||||
}
|
||||
}
|
||||
} else if (tc < mkv_d->skip_to_timecode)
|
||||
use_this_block = 0;
|
||||
else if (track->type == MATROSKA_TRACK_VIDEO
|
||||
|
@ -2121,14 +2134,6 @@ static int handle_block(demuxer_t *demuxer, uint8_t *block, uint64_t length,
|
|||
ds = demuxer->video;
|
||||
if (mkv_d->v_skip_to_keyframe)
|
||||
use_this_block = keyframe;
|
||||
} else if (track->type == MATROSKA_TRACK_SUBTITLE
|
||||
&& track->id == demuxer->sub->id) {
|
||||
ds = demuxer->sub;
|
||||
if (laces > 1) {
|
||||
mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Subtitles use Matroska "
|
||||
"lacing. This is abnormal and not supported.\n");
|
||||
use_this_block = 0;
|
||||
}
|
||||
} else
|
||||
use_this_block = 0;
|
||||
|
||||
|
@ -2170,6 +2175,7 @@ static int handle_block(demuxer_t *demuxer, uint8_t *block, uint64_t length,
|
|||
if (ds == demuxer->video) {
|
||||
mkv_d->v_skip_to_keyframe = 0;
|
||||
mkv_d->skip_to_timecode = 0;
|
||||
mkv_d->subtitle_preroll = false;
|
||||
} else if (ds == demuxer->audio)
|
||||
mkv_d->a_skip_to_keyframe = 0;
|
||||
|
||||
|
@ -2410,6 +2416,7 @@ static struct mkv_index *seek_with_cues(struct demuxer *demuxer, int seek_id,
|
|||
if (flags & SEEK_BACKWARD)
|
||||
min_diff = -min_diff;
|
||||
min_diff = FFMAX(min_diff, 1);
|
||||
|
||||
for (int i = 0; i < mkv_d->num_indexes; i++)
|
||||
if (seek_id < 0 || mkv_d->indexes[i].tnum == seek_id) {
|
||||
int64_t diff =
|
||||
|
@ -2427,8 +2434,22 @@ 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 (mkv_d->subtitle_preroll && demuxer->sub->id >= 0) {
|
||||
uint64_t prev_target = 0;
|
||||
for (int 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;
|
||||
}
|
||||
}
|
||||
if (prev_target)
|
||||
seek_pos = prev_target;
|
||||
}
|
||||
|
||||
mkv_d->cluster_size = mkv_d->blockgroup_size = 0;
|
||||
stream_seek(demuxer->stream, index->filepos);
|
||||
stream_seek(demuxer->stream, seek_pos);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
@ -2445,6 +2466,7 @@ static void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs,
|
|||
if (demuxer->audio->id >= 0)
|
||||
a_tnum = find_track_by_num(mkv_d, demuxer->audio->id,
|
||||
MATROSKA_TRACK_AUDIO)->tnum;
|
||||
mkv_d->subtitle_preroll = !!(flags & SEEK_SUBPREROLL);
|
||||
if (!(flags & (SEEK_BACKWARD | SEEK_FORWARD))) {
|
||||
if (flags & SEEK_ABSOLUTE || rel_seek_secs < 0)
|
||||
flags |= SEEK_BACKWARD;
|
||||
|
|
Loading…
Reference in New Issue