diff options
-rw-r--r-- | DOCS/man/en/options.rst | 23 | ||||
-rw-r--r-- | core/cfg-mplayer.h | 1 | ||||
-rw-r--r-- | core/mplayer.c | 2 | ||||
-rw-r--r-- | core/options.h | 1 | ||||
-rw-r--r-- | demux/demux.h | 1 | ||||
-rw-r--r-- | demux/demux_mkv.c | 40 |
6 files changed, 59 insertions, 9 deletions
diff --git a/DOCS/man/en/options.rst b/DOCS/man/en/options.rst index cc55c3a40e..5faf3cdb7e 100644 --- a/DOCS/man/en/options.rst +++ b/DOCS/man/en/options.rst @@ -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. diff --git a/core/cfg-mplayer.h b/core/cfg-mplayer.h index 4bdead1be1..a85f83ac36 100644 --- a/core/cfg-mplayer.h +++ b/core/cfg-mplayer.h @@ -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 diff --git a/core/mplayer.c b/core/mplayer.c index 21af9ca57a..3833d0a7da 100644 --- a/core/mplayer.c +++ b/core/mplayer.c @@ -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; diff --git a/core/options.h b/core/options.h index 0f1df17ba5..716ad5c357 100644 --- a/core/options.h +++ b/core/options.h @@ -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; diff --git a/demux/demux.h b/demux/demux.h index 41551975cc..debd0f55b1 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -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 diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index 5b178d66b9..0171b1e9a2 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -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; |