matroska: recursively search for referenced segments

When playing a Matroska file with ordered chapters, it may reference
another file by edition uid. When this edition is also ordered, it may
reference other files. When this occurs, the new segment/edition pair is
added to the list of sources to search for.
This commit is contained in:
Ben Boeckel 2013-10-05 03:01:49 -04:00
parent d8e5ac00bb
commit 5cd33853f2
1 changed files with 50 additions and 30 deletions

View File

@ -149,14 +149,14 @@ 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, struct matroska_segment_uid *uids, 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 = uids, .matroska_wanted_uids = *uids,
.matroska_wanted_segment = segment, .matroska_wanted_segment = segment,
.matroska_was_valid = &was_valid, .matroska_was_valid = &was_valid,
}; };
@ -171,9 +171,10 @@ static bool check_file_seg(struct MPContext *mpctx, struct demuxer **sources,
} }
if (d->type == DEMUXER_TYPE_MATROSKA) { if (d->type == DEMUXER_TYPE_MATROSKA) {
struct matroska_data *m = &d->matroska_data; struct matroska_data *m = &d->matroska_data;
for (int i = 1; i < num_sources; i++) {
struct matroska_segment_uid *uid = uids + i; for (int i = 1; i < *num_sources; i++) {
if (sources[i]) struct matroska_segment_uid *uid = *uids + i;
if ((*sources)[i])
continue; continue;
/* Accept the source if the segment uid matches and the edition /* Accept the source if the segment uid matches and the edition
* either matches or isn't specified. */ * either matches or isn't specified. */
@ -185,7 +186,21 @@ static bool check_file_seg(struct MPContext *mpctx, struct demuxer **sources,
if (enable_cache(mpctx, &s, &d, &params) < 0) if (enable_cache(mpctx, &s, &d, &params) < 0)
continue; continue;
sources[i] = d; for (int j = 0; j < m->num_ordered_chapters; j++) {
struct matroska_chapter *c = m->ordered_chapters + j;
if (!c->has_segment_uid)
continue;
/* Set the requested segment. */
MP_TARRAY_GROW(NULL, *uids, *num_sources);
memcpy((*uids) + *num_sources, &c->uid, sizeof(c->uid));
/* Add a new source slot. */
MP_TARRAY_APPEND(NULL, *sources, *num_sources, NULL);
}
(*sources)[i] = d;
return true; return true;
} }
} }
@ -195,8 +210,8 @@ static bool check_file_seg(struct MPContext *mpctx, struct demuxer **sources,
return was_valid; return was_valid;
} }
static void check_file(struct MPContext *mpctx, struct demuxer **sources, static void check_file(struct MPContext *mpctx, struct demuxer ***sources,
int num_sources, struct matroska_segment_uid *uids, 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++) {
@ -216,13 +231,13 @@ 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,
struct matroska_segment_uid *uids) struct matroska_segment_uid **uids)
{ {
int num_filenames = 0; int num_filenames = 0;
char **filenames = NULL; char **filenames = NULL;
if (num_sources > 1) { if (*num_sources > 1) {
char *main_filename = mpctx->demuxer->filename; char *main_filename = mpctx->demuxer->filename;
mp_msg(MSGT_CPLAYER, MSGL_INFO, "This file references data from " mp_msg(MSGT_CPLAYER, MSGL_INFO, "This file references data from "
"other sources.\n"); "other sources.\n");
@ -239,29 +254,34 @@ static int find_ordered_chapter_sources(struct MPContext *mpctx,
check_file(mpctx, sources, num_sources, uids, main_filename, 1); check_file(mpctx, sources, num_sources, uids, main_filename, 1);
} }
for (int i = 0; i < num_filenames; i++) { int old_source_count;
if (!missing(sources, num_sources)) do {
break; old_source_count = *num_sources;
mp_msg(MSGT_CPLAYER, MSGL_INFO, "Checking file %s\n", filenames[i]); for (int i = 0; i < num_filenames; i++) {
check_file(mpctx, sources, num_sources, uids, filenames[i], 0); if (!missing(*sources, *num_sources))
} break;
mp_msg(MSGT_CPLAYER, MSGL_INFO, "Checking file %s\n", filenames[i]);
check_file(mpctx, sources, num_sources, uids, filenames[i], 0);
}
/* Loop while we have new sources to look for. */
} while (old_source_count != *num_sources);
talloc_free(filenames); talloc_free(filenames);
if (missing(sources, num_sources)) { if (missing(*sources, *num_sources)) {
mp_msg(MSGT_CPLAYER, MSGL_ERR, "Failed to find ordered chapter part!\n" mp_msg(MSGT_CPLAYER, MSGL_ERR, "Failed to find ordered chapter part!\n"
"There will be parts MISSING from the video!\n"); "There will be parts MISSING from the video!\n");
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 *source_uid = *uids + i;
struct matroska_segment_uid *target_uid = uids + j; struct matroska_segment_uid *target_uid = *uids + j;
sources[j] = sources[i]; (*sources)[j] = (*sources)[i];
memcpy(target_uid, source_uid, sizeof(*source_uid)); memcpy(target_uid, source_uid, sizeof(*source_uid));
j++; j++;
} }
num_sources = j; *num_sources = j;
} }
return num_sources; return *num_sources;
} }
static void add_timeline_part(struct MPOpts *opts, static void add_timeline_part(struct MPOpts *opts,
@ -387,8 +407,8 @@ void build_ordered_chapter_timeline(struct MPContext *mpctx)
num_sources++; num_sources++;
} }
num_sources = find_ordered_chapter_sources(mpctx, sources, num_sources, num_sources = find_ordered_chapter_sources(mpctx, &sources, &num_sources,
uids); &uids);
talloc_free(uids); talloc_free(uids);
struct timeline_part *timeline = talloc_array_ptrtype(NULL, timeline, 0); struct timeline_part *timeline = talloc_array_ptrtype(NULL, timeline, 0);