mirror of https://github.com/mpv-player/mpv
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:
parent
d8e5ac00bb
commit
5cd33853f2
|
@ -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, ¶ms) < 0)
|
if (enable_cache(mpctx, &s, &d, ¶ms) < 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);
|
||||||
|
|
Loading…
Reference in New Issue