From d51a032fd773cbee6743d2e0f9dcc7fad65ae4f2 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 18 Nov 2014 23:07:20 +0100 Subject: demux_mkv: add an option for compatibility with Haali This was requested on IRC. --- DOCS/man/input.rst | 1 + DOCS/man/options.rst | 7 ++++++ demux/demux_mkv.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++ options/options.c | 1 + options/options.h | 1 + 5 files changed, 75 insertions(+) diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst index 68d48ae880..ea408d00ed 100644 --- a/DOCS/man/input.rst +++ b/DOCS/man/input.rst @@ -792,6 +792,7 @@ Property list ``ab-loop-a``, ``ab-loop-b`` (TW) Set/get A-B loop points. See corresponding options and ``ab_loop`` command. + The special value ``no`` on either of these properties disables looping. ``angle`` (RW) Current DVD angle. diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index b2ddd1c12a..aeb0cc63fe 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -2070,6 +2070,13 @@ Demuxer ``--demuxer-mkv-subtitle-preroll-secs=`` See ``--demuxer-mkv-subtitle-preroll``. +``--demuxer-mkv-probe-video-duration`` + 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 slower (especially when playing over http), or that behavior with + broken files is much worse. So don't use this option. + ``--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 36ca0277ba..85287e5a80 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -199,6 +199,8 @@ typedef struct mkv_demuxer { // (Subtitle packets added before first A/V keyframe packet is found with seek.) #define NUM_SUB_PREROLL_PACKETS 500 +static void probe_last_timestamp(struct demuxer *demuxer); + #define AAC_SYNC_EXTENSION_TYPE 0x02b7 static int aac_get_sample_rate_index(uint32_t sample_rate) { @@ -1845,6 +1847,9 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check) process_tags(demuxer); display_create_tracks(demuxer); + if (demuxer->opts->mkv_probe_duration) + probe_last_timestamp(demuxer); + return 0; } @@ -2859,6 +2864,66 @@ static void demux_mkv_seek(demuxer_t *demuxer, double rel_seek_secs, int flags) demux_mkv_fill_buffer(demuxer); } +static void probe_last_timestamp(struct demuxer *demuxer) +{ + mkv_demuxer_t *mkv_d = demuxer->priv; + int64_t old_pos = stream_tell(demuxer->stream); + + if (!demuxer->seekable) + return; + + // Pick some arbitrary video track + int v_tnum = -1; + for (int n = 0; n < mkv_d->num_tracks; n++) { + if (mkv_d->tracks[n]->type == MATROSKA_TRACK_VIDEO) { + v_tnum = mkv_d->tracks[n]->tnum; + break; + } + } + if (v_tnum < 0) + return; + + read_deferred_cues(demuxer); + + if (!mkv_d->index_complete) + 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 (!target) + return; + + if (!stream_seek(demuxer->stream, target)) + return; + + int64_t last_ts[STREAM_TYPE_COUNT] = {0}; + while (1) { + struct block_info block; + int res = read_next_block(demuxer, &block); + if (res < 0) + break; + if (res > 0) { + if (block.track && block.track->stream) { + enum stream_type type = block.track->stream->type; + if (last_ts[type] < block.timecode) + last_ts[type] = block.timecode; + } + free_block(&block); + } + } + + if (last_ts[STREAM_VIDEO]) + mkv_d->duration = last_ts[STREAM_VIDEO] / 1e9; + + stream_seek(demuxer->stream, old_pos); + mkv_d->cluster_start = mkv_d->cluster_end = 0; +} + static int demux_mkv_control(demuxer_t *demuxer, int cmd, void *arg) { mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv; diff --git a/options/options.c b/options/options.c index 93b660b0fd..1f6e0ae377 100644 --- a/options/options.c +++ b/options/options.c @@ -306,6 +306,7 @@ const m_option_t mp_opts[] = { 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), + OPT_FLAG("demuxer-mkv-probe-video-duration", mkv_probe_duration, 0), // ------------------------- subtitles options -------------------- diff --git a/options/options.h b/options/options.h index 63f77b2b3a..94d78ac6a0 100644 --- a/options/options.h +++ b/options/options.h @@ -196,6 +196,7 @@ typedef struct MPOpts { char *sub_demuxer_name; int mkv_subtitle_preroll; double mkv_subtitle_preroll_secs; + int mkv_probe_duration; double demuxer_min_secs_cache; int cache_pausing; -- cgit v1.2.3