mirror of https://github.com/mpv-player/mpv
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.
This commit is contained in:
parent
ccdaecfc5c
commit
07fbba3935
|
@ -128,14 +128,19 @@ typedef struct demux_chapter
|
||||||
uint64_t demuxer_id; // for mapping to internal demuxer data structures
|
uint64_t demuxer_id; // for mapping to internal demuxer data structures
|
||||||
} demux_chapter_t;
|
} demux_chapter_t;
|
||||||
|
|
||||||
|
struct matroska_segment_uid {
|
||||||
|
unsigned char segment[16];
|
||||||
|
uint64_t edition;
|
||||||
|
};
|
||||||
|
|
||||||
struct matroska_data {
|
struct matroska_data {
|
||||||
unsigned char segment_uid[16];
|
struct matroska_segment_uid uid;
|
||||||
// Ordered chapter information if any
|
// Ordered chapter information if any
|
||||||
struct matroska_chapter {
|
struct matroska_chapter {
|
||||||
uint64_t start;
|
uint64_t start;
|
||||||
uint64_t end;
|
uint64_t end;
|
||||||
bool has_segment_uid;
|
bool has_segment_uid;
|
||||||
unsigned char segment_uid[16];
|
struct matroska_segment_uid uid;
|
||||||
char *name;
|
char *name;
|
||||||
} *ordered_chapters;
|
} *ordered_chapters;
|
||||||
int num_ordered_chapters;
|
int num_ordered_chapters;
|
||||||
|
@ -151,7 +156,7 @@ typedef struct demux_attachment
|
||||||
|
|
||||||
struct demuxer_params {
|
struct demuxer_params {
|
||||||
int matroska_num_wanted_uids;
|
int matroska_num_wanted_uids;
|
||||||
unsigned char (*matroska_wanted_uids)[16];
|
struct matroska_segment_uid *matroska_wanted_uids;
|
||||||
int matroska_wanted_segment;
|
int matroska_wanted_segment;
|
||||||
bool *matroska_was_valid;
|
bool *matroska_was_valid;
|
||||||
struct ass_library *ass_library;
|
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_str(struct mp_tags *tags, const char *key);
|
||||||
char *mp_tags_get_bstr(struct mp_tags *tags, bstr 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 */
|
#endif /* MPLAYER_DEMUXER_H */
|
||||||
|
|
|
@ -377,24 +377,24 @@ static int demux_mkv_read_info(demuxer_t *demuxer)
|
||||||
}
|
}
|
||||||
if (info.n_segment_uid) {
|
if (info.n_segment_uid) {
|
||||||
int len = info.segment_uid.len;
|
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,
|
mp_msg(MSGT_DEMUX, MSGL_INFO,
|
||||||
"[mkv] segment uid invalid length %d\n", len);
|
"[mkv] segment uid invalid length %d\n", len);
|
||||||
} else {
|
} else {
|
||||||
memcpy(demuxer->matroska_data.segment_uid, info.segment_uid.start,
|
memcpy(demuxer->matroska_data.uid.segment, info.segment_uid.start,
|
||||||
len);
|
len);
|
||||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + segment uid");
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + segment uid");
|
||||||
for (int i = 0; i < len; i++)
|
for (int i = 0; i < len; i++)
|
||||||
mp_msg(MSGT_DEMUX, MSGL_V, " %02x",
|
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");
|
mp_msg(MSGT_DEMUX, MSGL_V, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (demuxer->params && demuxer->params->matroska_wanted_uids) {
|
if (demuxer->params && demuxer->params->matroska_wanted_uids) {
|
||||||
unsigned char (*uids)[16] = demuxer->params->matroska_wanted_uids;
|
|
||||||
if (info.n_segment_uid) {
|
if (info.n_segment_uid) {
|
||||||
for (int i = 0; i < demuxer->params->matroska_num_wanted_uids; i++) {
|
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;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -847,7 +847,7 @@ static int demux_mkv_read_chapters(struct demuxer *demuxer)
|
||||||
if (ca->n_chapter_segment_uid) {
|
if (ca->n_chapter_segment_uid) {
|
||||||
chapter.has_segment_uid = true;
|
chapter.has_segment_uid = true;
|
||||||
int len = ca->chapter_segment_uid.len;
|
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,
|
mp_msg(MSGT_DEMUX, warn_level,
|
||||||
"[mkv] Chapter segment uid bad length %d\n", len);
|
"[mkv] Chapter segment uid bad length %d\n", len);
|
||||||
else if (ca->n_chapter_segment_edition_uid) {
|
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; "
|
"unsupported edition recursion in chapter; "
|
||||||
"will skip on playback!\n");
|
"will skip on playback!\n");
|
||||||
} else {
|
} else {
|
||||||
memcpy(chapter.segment_uid, ca->chapter_segment_uid.start,
|
memcpy(chapter.uid.segment, ca->chapter_segment_uid.start,
|
||||||
len);
|
len);
|
||||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Chapter segment uid ");
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Chapter segment uid ");
|
||||||
for (int n = 0; n < len; n++)
|
for (int n = 0; n < len; n++)
|
||||||
mp_msg(MSGT_DEMUX, MSGL_V, "%02x ",
|
mp_msg(MSGT_DEMUX, MSGL_V, "%02x ",
|
||||||
chapter.segment_uid[n]);
|
chapter.uid.segment[n]);
|
||||||
mp_msg(MSGT_DEMUX, MSGL_V, "\n");
|
mp_msg(MSGT_DEMUX, MSGL_V, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2737,3 +2737,10 @@ const demuxer_desc_t demuxer_desc_matroska = {
|
||||||
.seek = demux_mkv_seek,
|
.seek = demux_mkv_seek,
|
||||||
.control = demux_mkv_control
|
.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);
|
||||||
|
}
|
||||||
|
|
|
@ -150,13 +150,13 @@ static int enable_cache(struct MPContext *mpctx, struct stream **stream,
|
||||||
|
|
||||||
// segment = get Nth segment of a multi-segment file
|
// segment = get Nth segment of a multi-segment file
|
||||||
static bool check_file_seg(struct MPContext *mpctx, struct demuxer **sources,
|
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)
|
char *filename, int segment)
|
||||||
{
|
{
|
||||||
bool was_valid = false;
|
bool was_valid = false;
|
||||||
struct demuxer_params params = {
|
struct demuxer_params params = {
|
||||||
.matroska_num_wanted_uids = num_sources,
|
.matroska_num_wanted_uids = num_sources,
|
||||||
.matroska_wanted_uids = uid_map,
|
.matroska_wanted_uids = uids,
|
||||||
.matroska_wanted_segment = segment,
|
.matroska_wanted_segment = segment,
|
||||||
.matroska_was_valid = &was_valid,
|
.matroska_was_valid = &was_valid,
|
||||||
};
|
};
|
||||||
|
@ -170,10 +170,12 @@ static bool check_file_seg(struct MPContext *mpctx, struct demuxer **sources,
|
||||||
return was_valid;
|
return was_valid;
|
||||||
}
|
}
|
||||||
if (d->type == DEMUXER_TYPE_MATROSKA) {
|
if (d->type == DEMUXER_TYPE_MATROSKA) {
|
||||||
|
struct matroska_data *m = &d->matroska_data;
|
||||||
for (int i = 1; i < num_sources; i++) {
|
for (int i = 1; i < num_sources; i++) {
|
||||||
|
struct matroska_segment_uid *uid = uids + i;
|
||||||
if (sources[i])
|
if (sources[i])
|
||||||
continue;
|
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",
|
mp_msg(MSGT_CPLAYER, MSGL_INFO, "Match for source %d: %s\n",
|
||||||
i, d->filename);
|
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,
|
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)
|
char *filename, int first)
|
||||||
{
|
{
|
||||||
for (int segment = first; ; segment++) {
|
for (int segment = first; ; segment++) {
|
||||||
if (!check_file_seg(mpctx, sources, num_sources, uid_map,
|
if (!check_file_seg(mpctx, sources, num_sources,
|
||||||
filename, segment))
|
uids, filename, segment))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,7 +215,7 @@ static bool missing(struct demuxer **sources, int num_sources)
|
||||||
static int find_ordered_chapter_sources(struct MPContext *mpctx,
|
static int find_ordered_chapter_sources(struct MPContext *mpctx,
|
||||||
struct demuxer **sources,
|
struct demuxer **sources,
|
||||||
int num_sources,
|
int num_sources,
|
||||||
unsigned char uid_map[][16])
|
struct matroska_segment_uid *uids)
|
||||||
{
|
{
|
||||||
int num_filenames = 0;
|
int num_filenames = 0;
|
||||||
char **filenames = NULL;
|
char **filenames = NULL;
|
||||||
|
@ -231,14 +233,14 @@ static int find_ordered_chapter_sources(struct MPContext *mpctx,
|
||||||
num_filenames = MP_TALLOC_ELEMS(filenames);
|
num_filenames = MP_TALLOC_ELEMS(filenames);
|
||||||
}
|
}
|
||||||
// Possibly get further segments appended to the first segment
|
// 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++) {
|
for (int i = 0; i < num_filenames; i++) {
|
||||||
if (!missing(sources, num_sources))
|
if (!missing(sources, num_sources))
|
||||||
break;
|
break;
|
||||||
mp_msg(MSGT_CPLAYER, MSGL_INFO, "Checking file %s\n", filenames[i]);
|
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);
|
talloc_free(filenames);
|
||||||
|
@ -248,8 +250,10 @@ static int find_ordered_chapter_sources(struct MPContext *mpctx,
|
||||||
int j = 1;
|
int j = 1;
|
||||||
for (int i = 1; i < num_sources; i++)
|
for (int i = 1; i < num_sources; i++)
|
||||||
if (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];
|
sources[j] = sources[i];
|
||||||
memcpy(uid_map[j], uid_map[i], 16);
|
memcpy(target_uid, source_uid, sizeof(*source_uid));
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
num_sources = j;
|
num_sources = j;
|
||||||
|
@ -278,20 +282,21 @@ void build_ordered_chapter_timeline(struct MPContext *mpctx)
|
||||||
struct demuxer **sources = talloc_array_ptrtype(NULL, sources,
|
struct demuxer **sources = talloc_array_ptrtype(NULL, sources,
|
||||||
m->num_ordered_chapters+1);
|
m->num_ordered_chapters+1);
|
||||||
sources[0] = mpctx->demuxer;
|
sources[0] = mpctx->demuxer;
|
||||||
unsigned char (*uid_map)[16] = talloc_array_ptrtype(NULL, uid_map,
|
struct matroska_segment_uid *uids = talloc_array_ptrtype(NULL, uids,
|
||||||
m->num_ordered_chapters + 1);
|
m->num_ordered_chapters + 1);
|
||||||
int num_sources = 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++) {
|
for (int i = 0; i < m->num_ordered_chapters; i++) {
|
||||||
struct matroska_chapter *c = m->ordered_chapters + i;
|
struct matroska_chapter *c = m->ordered_chapters + i;
|
||||||
if (!c->has_segment_uid)
|
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++)
|
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;
|
goto found1;
|
||||||
memcpy(uid_map[num_sources], c->segment_uid, 16);
|
memcpy(uids + num_sources, &c->uid, sizeof(c->uid));
|
||||||
sources[num_sources] = NULL;
|
sources[num_sources] = NULL;
|
||||||
num_sources++;
|
num_sources++;
|
||||||
found1:
|
found1:
|
||||||
|
@ -299,8 +304,7 @@ void build_ordered_chapter_timeline(struct MPContext *mpctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
num_sources = find_ordered_chapter_sources(mpctx, sources, num_sources,
|
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
|
// +1 for terminating chapter with start time marking end of last real one
|
||||||
struct timeline_part *timeline = talloc_array_ptrtype(NULL, timeline,
|
struct timeline_part *timeline = talloc_array_ptrtype(NULL, timeline,
|
||||||
|
@ -317,7 +321,7 @@ void build_ordered_chapter_timeline(struct MPContext *mpctx)
|
||||||
|
|
||||||
int j;
|
int j;
|
||||||
for (j = 0; j < num_sources; 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;
|
goto found2;
|
||||||
}
|
}
|
||||||
missing_time += c->end - c->start;
|
missing_time += c->end - c->start;
|
||||||
|
@ -353,7 +357,7 @@ void build_ordered_chapter_timeline(struct MPContext *mpctx)
|
||||||
num_chapters++;
|
num_chapters++;
|
||||||
}
|
}
|
||||||
timeline[part_count].start = starttime / 1e9;
|
timeline[part_count].start = starttime / 1e9;
|
||||||
talloc_free(uid_map);
|
talloc_free(uids);
|
||||||
|
|
||||||
if (!part_count) {
|
if (!part_count) {
|
||||||
// None of the parts come from the file itself???
|
// None of the parts come from the file itself???
|
||||||
|
|
Loading…
Reference in New Issue