From 7001c2d994457e49b6c330319987649eadbdcb80 Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Fri, 26 Nov 2010 16:56:05 +0200 Subject: [PATCH] core: ordered chapters: add heuristic for merging inaccurate chapters Some Matroska files have inaccurate ordered chapter endpoints, and so parts where one chapter should end and the next begin at the same timestamp were not merged. This resulted in an unnecessary seek over a minimal distance. Add a heuristic to merge parts with a minimal gap or overlap between them. Based on patch by Hector Martin . --- DOCS/man/en/mplayer.1 | 11 +++++++++++ cfg-mplayer.h | 1 + defaultopts.c | 1 + mplayer.c | 24 ++++++++++++++++++------ options.h | 1 + 5 files changed, 32 insertions(+), 6 deletions(-) diff --git a/DOCS/man/en/mplayer.1 b/DOCS/man/en/mplayer.1 index 29c1ba9eba..5de2a32749 100644 --- a/DOCS/man/en/mplayer.1 +++ b/DOCS/man/en/mplayer.1 @@ -798,6 +798,17 @@ With this option MPlayer will also ignore frame duration when playing only video (you can think of that as infinite fps). . .TP +.B \-chapter\-merge\-threshold +Threshold for merging almost consecutive ordered chapter parts +in milliseconds (default: 100). +Some Matroska files with ordered chapters have inaccurate chapter +end timestamps, causing a small gap between the end of one chapter and +the start of the next one when they should match. +If the end of one playback part is less than the given threshold away +from the start of the next one then keep playing video normally over the +chapter change instead of doing a seek. +. +.TP .B \-colorkey Changes the colorkey to an RGB value of your choice. 0x000000 is black and 0xffffff is white. diff --git a/cfg-mplayer.h b/cfg-mplayer.h index 0584957215..be52df881a 100644 --- a/cfg-mplayer.h +++ b/cfg-mplayer.h @@ -305,6 +305,7 @@ const m_option_t mplayer_opts[]={ {"playlist", NULL, CONF_TYPE_STRING, 0, 0, 0, NULL}, OPT_MAKE_FLAGS("ordered-chapters", ordered_chapters, 0), + OPT_INTRANGE("chapter-merge-threshold", chapter_merge_threshold, 0, 0, 10000), // a-v sync stuff: OPT_MAKE_FLAGS("correct-pts", user_correct_pts, 0), diff --git a/defaultopts.c b/defaultopts.c index e8f842cd47..aabe0effe1 100644 --- a/defaultopts.c +++ b/defaultopts.c @@ -23,6 +23,7 @@ void set_default_mplayer_options(struct MPOpts *opts) .stream_dump_name = "stream.dump", .loop_times = -1, .ordered_chapters = 1, + .chapter_merge_threshold = 100, .stream_cache_min_percent = 20.0, .stream_cache_seek_min_percent = 50.0, .chapterrange = {-1, -1}, diff --git a/mplayer.c b/mplayer.c index 8821b3df89..4707936447 100644 --- a/mplayer.c +++ b/mplayer.c @@ -3100,7 +3100,9 @@ static int find_ordered_chapter_sources(struct MPContext *mpctx, static void build_ordered_chapter_timeline(struct MPContext *mpctx) { - if (!mpctx->opts.ordered_chapters) { + struct MPOpts *opts = &mpctx->opts; + + if (!opts->ordered_chapters) { mp_msg(MSGT_CPLAYER, MSGL_INFO, "File uses ordered chapters, but " "you have disabled support for them. Ignoring.\n"); return; @@ -3162,21 +3164,31 @@ static void build_ordered_chapter_timeline(struct MPContext *mpctx) missing_time += c->end - c->start; continue; found2:; - chapters[num_chapters].start = starttime / 1000.; - chapters[num_chapters].name = talloc_strdup(chapters, c->name); /* Only add a separate part if the time or file actually changes. * Matroska files have chapter divisions that are redundant from * timeline point of view because the same chapter structure is used * both to specify the timeline and for normal chapter information. - * Removing a missing inserted external chapter can also cause this. */ - if (part_count == 0 || c->start != starttime + prev_part_offset + * Removing a missing inserted external chapter can also cause this. + * We allow for a configurable fudge factor because of files which + * specify chapter end times that are one frame too early; + * we don't want to try seeking over a one frame gap. */ + int64_t join_diff = c->start - starttime - prev_part_offset; + if (part_count == 0 || FFABS(join_diff) > opts->chapter_merge_threshold || sources + j != timeline[part_count - 1].source) { timeline[part_count].source = sources + j; - timeline[part_count].start = chapters[num_chapters].start; + timeline[part_count].start = starttime / 1000.; timeline[part_count].source_start = c->start / 1000.; prev_part_offset = c->start - starttime; part_count++; + } else if (part_count > 0 && join_diff) { + /* Chapter was merged at an inexact boundary; + * adjust timestamps to match. */ + mp_msg(MSGT_CPLAYER, MSGL_V, "Merging timeline part %d with " + "offset %d ms.\n", i, (int) join_diff); + starttime += join_diff; } + chapters[num_chapters].start = starttime / 1000.; + chapters[num_chapters].name = talloc_strdup(chapters, c->name); starttime += c->end - c->start; num_chapters++; } diff --git a/options.h b/options.h index 992202fda3..66048e77b2 100644 --- a/options.h +++ b/options.h @@ -37,6 +37,7 @@ typedef struct MPOpts { int capture_dump; int loop_times; int ordered_chapters; + int chapter_merge_threshold; int quiet; float stream_cache_min_percent; float stream_cache_seek_min_percent;