From 07fbba3935e9d4327d3ae946b747486693d9d0f7 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Sun, 6 Oct 2013 20:49:12 -0400 Subject: matroska: store segment/edition uids in a single structure To support edition references in matroska chapters, editions need to be remembered for each chapter and source. To facilitate easier management of these now-paired uids, a single structure is used. --- demux/demux.h | 14 +++++++++++--- demux/demux_mkv.c | 23 ++++++++++++++-------- mpvcore/timeline/tl_matroska.c | 44 +++++++++++++++++++++++------------------- 3 files changed, 50 insertions(+), 31 deletions(-) diff --git a/demux/demux.h b/demux/demux.h index 1e0546a6d0..0c8f9cb3f8 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -128,14 +128,19 @@ typedef struct demux_chapter uint64_t demuxer_id; // for mapping to internal demuxer data structures } demux_chapter_t; +struct matroska_segment_uid { + unsigned char segment[16]; + uint64_t edition; +}; + struct matroska_data { - unsigned char segment_uid[16]; + struct matroska_segment_uid uid; // Ordered chapter information if any struct matroska_chapter { uint64_t start; uint64_t end; bool has_segment_uid; - unsigned char segment_uid[16]; + struct matroska_segment_uid uid; char *name; } *ordered_chapters; int num_ordered_chapters; @@ -151,7 +156,7 @@ typedef struct demux_attachment struct demuxer_params { int matroska_num_wanted_uids; - unsigned char (*matroska_wanted_uids)[16]; + struct matroska_segment_uid *matroska_wanted_uids; int matroska_wanted_segment; bool *matroska_was_valid; struct ass_library *ass_library; @@ -301,4 +306,7 @@ void mp_tags_set_bstr(struct mp_tags *tags, bstr key, bstr value); char *mp_tags_get_str(struct mp_tags *tags, const char *key); char *mp_tags_get_bstr(struct mp_tags *tags, bstr key); +bool demux_matroska_uid_cmp(struct matroska_segment_uid *a, + struct matroska_segment_uid *b); + #endif /* MPLAYER_DEMUXER_H */ diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index bbbe88d903..9ca4e62ecb 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -377,24 +377,24 @@ static int demux_mkv_read_info(demuxer_t *demuxer) } if (info.n_segment_uid) { int len = info.segment_uid.len; - if (len != sizeof(demuxer->matroska_data.segment_uid)) { + if (len != sizeof(demuxer->matroska_data.uid.segment)) { mp_msg(MSGT_DEMUX, MSGL_INFO, "[mkv] segment uid invalid length %d\n", len); } else { - memcpy(demuxer->matroska_data.segment_uid, info.segment_uid.start, + memcpy(demuxer->matroska_data.uid.segment, info.segment_uid.start, len); mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + segment uid"); for (int i = 0; i < len; i++) mp_msg(MSGT_DEMUX, MSGL_V, " %02x", - demuxer->matroska_data.segment_uid[i]); + demuxer->matroska_data.uid.segment[i]); mp_msg(MSGT_DEMUX, MSGL_V, "\n"); } } if (demuxer->params && demuxer->params->matroska_wanted_uids) { - unsigned char (*uids)[16] = demuxer->params->matroska_wanted_uids; if (info.n_segment_uid) { for (int i = 0; i < demuxer->params->matroska_num_wanted_uids; i++) { - if (!memcmp(info.segment_uid.start, uids[i], 16)) + struct matroska_segment_uid *uid = demuxer->params->matroska_wanted_uids + i; + if (!memcmp(info.segment_uid.start, uid->segment, 16)) goto out; } } @@ -847,7 +847,7 @@ static int demux_mkv_read_chapters(struct demuxer *demuxer) if (ca->n_chapter_segment_uid) { chapter.has_segment_uid = true; int len = ca->chapter_segment_uid.len; - if (len != sizeof(chapter.segment_uid)) + if (len != sizeof(chapter.uid.segment)) mp_msg(MSGT_DEMUX, warn_level, "[mkv] Chapter segment uid bad length %d\n", len); else if (ca->n_chapter_segment_edition_uid) { @@ -855,12 +855,12 @@ static int demux_mkv_read_chapters(struct demuxer *demuxer) "unsupported edition recursion in chapter; " "will skip on playback!\n"); } else { - memcpy(chapter.segment_uid, ca->chapter_segment_uid.start, + memcpy(chapter.uid.segment, ca->chapter_segment_uid.start, len); mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Chapter segment uid "); for (int n = 0; n < len; n++) mp_msg(MSGT_DEMUX, MSGL_V, "%02x ", - chapter.segment_uid[n]); + chapter.uid.segment[n]); mp_msg(MSGT_DEMUX, MSGL_V, "\n"); } } @@ -2737,3 +2737,10 @@ const demuxer_desc_t demuxer_desc_matroska = { .seek = demux_mkv_seek, .control = demux_mkv_control }; + +bool demux_matroska_uid_cmp(struct matroska_segment_uid *a, + struct matroska_segment_uid *b) +{ + return (!memcmp(a->segment, b->segment, 16) && + a->edition == b->edition); +} diff --git a/mpvcore/timeline/tl_matroska.c b/mpvcore/timeline/tl_matroska.c index 4c3b705f20..220aa34ece 100644 --- a/mpvcore/timeline/tl_matroska.c +++ b/mpvcore/timeline/tl_matroska.c @@ -150,13 +150,13 @@ static int enable_cache(struct MPContext *mpctx, struct stream **stream, // segment = get Nth segment of a multi-segment file static bool check_file_seg(struct MPContext *mpctx, struct demuxer **sources, - int num_sources, unsigned char uid_map[][16], + int num_sources, struct matroska_segment_uid *uids, char *filename, int segment) { bool was_valid = false; struct demuxer_params params = { .matroska_num_wanted_uids = num_sources, - .matroska_wanted_uids = uid_map, + .matroska_wanted_uids = uids, .matroska_wanted_segment = segment, .matroska_was_valid = &was_valid, }; @@ -170,10 +170,12 @@ static bool check_file_seg(struct MPContext *mpctx, struct demuxer **sources, return was_valid; } if (d->type == DEMUXER_TYPE_MATROSKA) { + struct matroska_data *m = &d->matroska_data; for (int i = 1; i < num_sources; i++) { + struct matroska_segment_uid *uid = uids + i; if (sources[i]) continue; - if (!memcmp(uid_map[i], d->matroska_data.segment_uid, 16)) { + if (!memcmp(uid->segment, m->uid.segment, 16)) { mp_msg(MSGT_CPLAYER, MSGL_INFO, "Match for source %d: %s\n", i, d->filename); @@ -191,12 +193,12 @@ static bool check_file_seg(struct MPContext *mpctx, struct demuxer **sources, } static void check_file(struct MPContext *mpctx, struct demuxer **sources, - int num_sources, unsigned char uid_map[][16], + int num_sources, struct matroska_segment_uid *uids, char *filename, int first) { for (int segment = first; ; segment++) { - if (!check_file_seg(mpctx, sources, num_sources, uid_map, - filename, segment)) + if (!check_file_seg(mpctx, sources, num_sources, + uids, filename, segment)) break; } } @@ -213,7 +215,7 @@ static bool missing(struct demuxer **sources, int num_sources) static int find_ordered_chapter_sources(struct MPContext *mpctx, struct demuxer **sources, int num_sources, - unsigned char uid_map[][16]) + struct matroska_segment_uid *uids) { int num_filenames = 0; char **filenames = NULL; @@ -231,14 +233,14 @@ static int find_ordered_chapter_sources(struct MPContext *mpctx, num_filenames = MP_TALLOC_ELEMS(filenames); } // Possibly get further segments appended to the first segment - check_file(mpctx, sources, num_sources, uid_map, main_filename, 1); + check_file(mpctx, sources, num_sources, uids, main_filename, 1); } for (int i = 0; i < num_filenames; i++) { if (!missing(sources, num_sources)) break; mp_msg(MSGT_CPLAYER, MSGL_INFO, "Checking file %s\n", filenames[i]); - check_file(mpctx, sources, num_sources, uid_map, filenames[i], 0); + check_file(mpctx, sources, num_sources, uids, filenames[i], 0); } talloc_free(filenames); @@ -248,8 +250,10 @@ static int find_ordered_chapter_sources(struct MPContext *mpctx, int j = 1; for (int i = 1; i < num_sources; i++) if (sources[i]) { + struct matroska_segment_uid *source_uid = uids + i; + struct matroska_segment_uid *target_uid = uids + j; sources[j] = sources[i]; - memcpy(uid_map[j], uid_map[i], 16); + memcpy(target_uid, source_uid, sizeof(*source_uid)); j++; } num_sources = j; @@ -278,20 +282,21 @@ void build_ordered_chapter_timeline(struct MPContext *mpctx) struct demuxer **sources = talloc_array_ptrtype(NULL, sources, m->num_ordered_chapters+1); sources[0] = mpctx->demuxer; - unsigned char (*uid_map)[16] = talloc_array_ptrtype(NULL, uid_map, - m->num_ordered_chapters + 1); + struct matroska_segment_uid *uids = talloc_array_ptrtype(NULL, uids, + m->num_ordered_chapters + 1); int num_sources = 1; - memcpy(uid_map[0], m->segment_uid, 16); + memcpy(uids[0].segment, m->uid.segment, 16); + uids[0].edition = 0; for (int i = 0; i < m->num_ordered_chapters; i++) { struct matroska_chapter *c = m->ordered_chapters + i; if (!c->has_segment_uid) - memcpy(c->segment_uid, m->segment_uid, 16); + memcpy(c->uid.segment, m->uid.segment, 16); for (int j = 0; j < num_sources; j++) - if (!memcmp(c->segment_uid, uid_map[j], 16)) + if (!memcmp(c->uid.segment, uids[j].segment, 16)) goto found1; - memcpy(uid_map[num_sources], c->segment_uid, 16); + memcpy(uids + num_sources, &c->uid, sizeof(c->uid)); sources[num_sources] = NULL; num_sources++; found1: @@ -299,8 +304,7 @@ void build_ordered_chapter_timeline(struct MPContext *mpctx) } num_sources = find_ordered_chapter_sources(mpctx, sources, num_sources, - uid_map); - + uids); // +1 for terminating chapter with start time marking end of last real one struct timeline_part *timeline = talloc_array_ptrtype(NULL, timeline, @@ -317,7 +321,7 @@ void build_ordered_chapter_timeline(struct MPContext *mpctx) int j; for (j = 0; j < num_sources; j++) { - if (!memcmp(c->segment_uid, uid_map[j], 16)) + if (!memcmp(c->uid.segment, uids[j].segment, 16)) goto found2; } missing_time += c->end - c->start; @@ -353,7 +357,7 @@ void build_ordered_chapter_timeline(struct MPContext *mpctx) num_chapters++; } timeline[part_count].start = starttime / 1e9; - talloc_free(uid_map); + talloc_free(uids); if (!part_count) { // None of the parts come from the file itself??? -- cgit v1.2.3