From: Daniel Dawson Date: Tue, 1 Dec 2009 12:28:34 +0000 (-0800) Subject: Support for multiple editions in Matroska X-Git-Tag: v2.0-beta1~972 X-Git-Url: https://repo.or.cz/w/mplayer.git/commitdiff_plain/c3c0309eecc1d6b309138fcd40df508235c9395d?hp=9b81b7827ce4ce887c6f22332e31b058f68cf3ac Support for multiple editions in Matroska Add code to intelligently choose an appropriate Matroska edition when there are several. Will choose, in descending order of preference: the edition chosen by the user through the option "-edition " if it exists, the first edition with EditionFlagDefault set to 1 if there is one, or the first edition. --- diff --git a/DOCS/man/en/mplayer.1 b/DOCS/man/en/mplayer.1 index 5a23c4d74c..0393c47dda 100644 --- a/DOCS/man/en/mplayer.1 +++ b/DOCS/man/en/mplayer.1 @@ -1301,6 +1301,12 @@ Specify which chapter to start playing at. Optionally specify which chapter to end playing at (default: 1). . .TP +.B \-edition (Matroska, MPlayer only) +Specify the edition (set of chapters) to use, where 0 is the first. If set to +-1 (the default), MPlayer will choose the first edition declared as a default, +or if there is no default, the first edition defined. +. +.TP .B \-cookies (network only) Send cookies when making HTTP requests. . diff --git a/cfg-common-opts.h b/cfg-common-opts.h index 7927bedf14..19a131220b 100644 --- a/cfg-common-opts.h +++ b/cfg-common-opts.h @@ -40,6 +40,7 @@ {"dvd-speed", "MPlayer was compiled without libdvdread support.\n", CONF_TYPE_PRINT, 0, 0, 0, NULL}, {"dvd", "MPlayer was compiled without libdvdread support.\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0, NULL}, #endif /* CONFIG_DVDREAD */ + OPT_INTRANGE("edition", edition_id, 0, -1, 8190), {"alang", &audio_lang, CONF_TYPE_STRING, 0, 0, 0, NULL}, {"slang", &dvdsub_lang, CONF_TYPE_STRING, 0, 0, 0, NULL}, diff --git a/defaultopts.c b/defaultopts.c index 2bd6f7e3e3..b5917c53a7 100644 --- a/defaultopts.c +++ b/defaultopts.c @@ -21,6 +21,7 @@ void set_default_mplayer_options(struct MPOpts *opts) .osd_duration = 1000, .loop_times = -1, .ordered_chapters = 1, + .edition_id = -1, .user_correct_pts = -1, .key_fifo_size = 7, .doubleclick_time = 300, diff --git a/libmpdemux/demux_mkv.c b/libmpdemux/demux_mkv.c index 3874298172..c07224ae67 100644 --- a/libmpdemux/demux_mkv.c +++ b/libmpdemux/demux_mkv.c @@ -1085,7 +1085,9 @@ demux_mkv_read_cues (demuxer_t *demuxer) return 0; } -static uint64_t read_one_chapter(struct demuxer *demuxer, stream_t *s) +static uint64_t read_one_chapter(struct demuxer *demuxer, stream_t *s, + struct matroska_chapter *chapters, + int chapter_num) { uint64_t len, l; uint64_t start = 0, end = 0; @@ -1167,17 +1169,10 @@ static uint64_t read_one_chapter(struct demuxer *demuxer, stream_t *s) if (!name) name = strdup("(unnamed)"); - int cid = demuxer_add_chapter(demuxer, name, start, end); - struct matroska_data *m = &demuxer->matroska_data; - m->ordered_chapters = talloc_realloc(demuxer, m->ordered_chapters, - struct matroska_chapter, - m->num_ordered_chapters + 1); chapter.start = start; chapter.end = end; - chapter.name = talloc_strdup(m->ordered_chapters, name); - // Will be undone later if this is a normal chapter rather than ordered - m->ordered_chapters[m->num_ordered_chapters] = chapter; - m->num_ordered_chapters++; + chapter.name = talloc_strdup(chapters, name); + chapters[chapter_num] = chapter; if (badchapter) { memset(&chapter.segment_uid, 0, sizeof(chapter.segment_uid)); @@ -1186,7 +1181,7 @@ static uint64_t read_one_chapter(struct demuxer *demuxer, stream_t *s) mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Chapter %u from %02d:%02d:%02d." "%03d to %02d:%02d:%02d.%03d, %s\n", - cid, + chapter_num, (int) (start / 60 / 60 / 1000), (int) ((start / 60 / 1000) % 60), (int) ((start / 1000) % 60), @@ -1203,6 +1198,7 @@ cleanup: static int demux_mkv_read_chapters(struct demuxer *demuxer) { + struct MPOpts *opts = demuxer->opts; stream_t *s = demuxer->stream; uint64_t length, l; int i; @@ -1216,29 +1212,40 @@ static int demux_mkv_read_chapters(struct demuxer *demuxer) mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] /---- [ parsing chapters ] ---------\n"); length = ebml_read_length(s, NULL); - bool have_edition = false; + struct matroska_chapter *selected_chapters = NULL; + int num_selected_chapters = 0; + bool have_default = false; + bool have_user_specified = false; + int selected_edition = -1; + bool se_is_ordered = false; + int cur_idx = -1; while (length > 0) { id = ebml_read_id(s, &i); length -= i; switch (id) { case MATROSKA_ID_EDITIONENTRY: - if (have_edition) { - mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Multiple edition entries" - " - ignoring all but first!\n"); - ebml_read_skip(s, &l); - length -= l; - break; - } - have_edition = true; + cur_idx++; + mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] New edition %d\n", cur_idx); uint64_t editionlen = ebml_read_length(s, &i); length -= editionlen + i; + bool defaultflag = false; bool ordered = false; + struct matroska_chapter *chapters = NULL; + int num_chapters = 0; while (editionlen > 0) { id = ebml_read_id(s, &i); editionlen -= i; switch (id) { case MATROSKA_ID_CHAPTERATOM: - l = read_one_chapter(demuxer, s); + chapters = talloc_realloc(demuxer, chapters, + struct matroska_chapter, + num_chapters + 1); + l = read_one_chapter(demuxer, s, chapters, num_chapters++); + break; + case MATROSKA_ID_EDITIONFLAGDEFAULT: + defaultflag = ebml_read_uint(s, &l); + mp_msg(MSGT_DEMUX, MSGL_V, + "[mkv] Default edition flag: %d\n", defaultflag); break; case MATROSKA_ID_EDITIONFLAGORDERED: ordered = ebml_read_uint(s, &l); @@ -1252,13 +1259,25 @@ static int demux_mkv_read_chapters(struct demuxer *demuxer) } editionlen -= l; } - if (!ordered) { - // The chapters should be interpreted as normal ones, - // so undo the addition of this information. - talloc_free(demuxer->matroska_data.ordered_chapters); - demuxer->matroska_data.ordered_chapters = NULL; - demuxer->matroska_data.num_ordered_chapters = 0; + if (cur_idx == opts->edition_id) { + have_user_specified = true; + mp_msg(MSGT_DEMUX, MSGL_V, + "[mkv] Found user-selected edition\n"); + } else if (!have_user_specified && !have_default && defaultflag) { + have_default = true; + mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Default edition: %d\n", + cur_idx); + } else if (selected_edition < 0) { + ; + } else { + talloc_free(chapters); + break; } + selected_edition = cur_idx; + talloc_free(selected_chapters); + selected_chapters = chapters; + num_selected_chapters = num_chapters; + se_is_ordered = ordered; break; default: @@ -1267,6 +1286,25 @@ static int demux_mkv_read_chapters(struct demuxer *demuxer) break; } } + if (cur_idx > 0) + mp_msg(MSGT_DEMUX, MSGL_INFO, + "[mkv] Found %d editions, will play #%d (first is 0).\n", + cur_idx + 1, selected_edition); + + for (i = 0; i < num_selected_chapters; i++) + demuxer_add_chapter(demuxer, selected_chapters[i].name, + selected_chapters[i].start, + selected_chapters[i].end); + struct matroska_data *m = &demuxer->matroska_data; + talloc_free(m->ordered_chapters); + if (se_is_ordered) { + m->ordered_chapters = selected_chapters; + m->num_ordered_chapters = num_selected_chapters; + } else { + m->ordered_chapters = NULL; + m->num_ordered_chapters = 0; + talloc_free(selected_chapters); + } mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] \\---- [ parsing chapters ] ---------\n"); return 0; diff --git a/libmpdemux/ebml.h b/libmpdemux/ebml.h index a224bcd8e0..c3a785099c 100644 --- a/libmpdemux/ebml.h +++ b/libmpdemux/ebml.h @@ -145,6 +145,7 @@ /* IDs in the chapters master */ #define MATROSKA_ID_EDITIONENTRY 0x45B9 +#define MATROSKA_ID_EDITIONFLAGDEFAULT 0x45DB #define MATROSKA_ID_EDITIONFLAGORDERED 0x45DD #define MATROSKA_ID_CHAPTERATOM 0xB6 #define MATROSKA_ID_CHAPTERTIMESTART 0x91 diff --git a/options.h b/options.h index 56cd6b6b39..90ce239e86 100644 --- a/options.h +++ b/options.h @@ -29,6 +29,7 @@ typedef struct MPOpts { int osd_duration; int loop_times; int ordered_chapters; + int edition_id; int correct_pts; int user_correct_pts; int user_pts_assoc_mode;