summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/timeline/tl_matroska.c123
-rw-r--r--demux/demux.h2
-rw-r--r--demux/demux_mkv.c61
3 files changed, 133 insertions, 53 deletions
diff --git a/core/timeline/tl_matroska.c b/core/timeline/tl_matroska.c
index 75530116aa..98ba635bec 100644
--- a/core/timeline/tl_matroska.c
+++ b/core/timeline/tl_matroska.c
@@ -114,16 +114,15 @@ static char **find_files(const char *original_file, const char *suffix)
}
static struct demuxer *open_demuxer(struct stream *stream,
- struct MPContext *mpctx, char *filename, unsigned char uid_map[][16])
+ struct MPContext *mpctx, char *filename, struct demuxer_params *params)
{
return demux_open_withparams(&mpctx->opts, stream,
DEMUXER_TYPE_MATROSKA, NULL, mpctx->opts.audio_id,
- mpctx->opts.video_id, mpctx->opts.sub_id, filename,
- &(struct demuxer_params){.matroska_wanted_uids = uid_map});
+ mpctx->opts.video_id, mpctx->opts.sub_id, filename, params);
}
static int enable_cache(struct MPContext *mpctx, struct stream **stream,
- struct demuxer **demuxer, unsigned char uid_map[][16])
+ struct demuxer **demuxer, struct demuxer_params *params)
{
struct MPOpts *opts = &mpctx->opts;
@@ -147,7 +146,7 @@ static int enable_cache(struct MPContext *mpctx, struct stream **stream,
opts->stream_cache_min_percent,
opts->stream_cache_seek_min_percent);
- *demuxer = open_demuxer(*stream, mpctx, filename, uid_map);
+ *demuxer = open_demuxer(*stream, mpctx, filename, params);
if (!*demuxer) {
talloc_free(filename);
free_stream(*stream);
@@ -158,6 +157,68 @@ static int enable_cache(struct MPContext *mpctx, struct stream **stream,
return 1;
}
+// 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],
+ char *filename, int segment)
+{
+ bool was_valid = false;
+ struct demuxer_params params = {
+ .matroska_wanted_uids = uid_map,
+ .matroska_wanted_segment = segment,
+ .matroska_was_valid = &was_valid,
+ };
+ int format = 0;
+ struct stream *s = open_stream(filename, &mpctx->opts, &format);
+ if (!s)
+ return false;
+ struct demuxer *d = open_demuxer(s, mpctx, filename, &params);
+
+ if (!d) {
+ free_stream(s);
+ return was_valid;
+ }
+ if (d->file_format == DEMUXER_TYPE_MATROSKA) {
+ for (int i = 1; i < num_sources; i++) {
+ if (sources[i])
+ continue;
+ if (!memcmp(uid_map[i], d->matroska_data.segment_uid, 16)) {
+ mp_msg(MSGT_CPLAYER, MSGL_INFO, "Match for source %d: %s\n",
+ i, d->filename);
+
+ if (enable_cache(mpctx, &s, &d, &params) < 0)
+ continue;
+
+ sources[i] = d;
+ return true;
+ }
+ }
+ }
+ free_demuxer(d);
+ free_stream(s);
+ return was_valid;
+}
+
+static void check_file(struct MPContext *mpctx, struct demuxer **sources,
+ int num_sources, unsigned char uid_map[][16],
+ char *filename, int first)
+{
+ for (int segment = first; ; segment++) {
+ if (!check_file_seg(mpctx, sources, num_sources, uid_map,
+ filename, segment))
+ break;
+ }
+}
+
+static bool missing(struct demuxer **sources, int num_sources)
+{
+ for (int i = 0; i < num_sources; i++) {
+ if (!sources[i])
+ return true;
+ }
+ return false;
+}
+
static int find_ordered_chapter_sources(struct MPContext *mpctx,
struct demuxer **sources,
int num_sources,
@@ -166,6 +227,7 @@ static int find_ordered_chapter_sources(struct MPContext *mpctx,
int num_filenames = 0;
char **filenames = NULL;
if (num_sources > 1) {
+ char *main_filename = mpctx->demuxer->filename;
mp_msg(MSGT_CPLAYER, MSGL_INFO, "This file references data from "
"other sources.\n");
if (mpctx->demuxer->stream->type != STREAMTYPE_FILE) {
@@ -174,59 +236,34 @@ static int find_ordered_chapter_sources(struct MPContext *mpctx,
} else {
mp_msg(MSGT_CPLAYER, MSGL_INFO, "Will scan other files in the "
"same directory to find referenced sources.\n");
- filenames = find_files(mpctx->demuxer->filename, ".mkv");
+ filenames = find_files(main_filename, ".mkv");
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);
}
- int num_left = num_sources - 1;
- for (int i = 0; i < num_filenames && num_left > 0; i++) {
+ 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]);
- int format = 0;
- struct stream *s = open_stream(filenames[i], &mpctx->opts, &format);
- if (!s)
- continue;
- struct demuxer *d = open_demuxer(s, mpctx, filenames[i], uid_map);
-
- if (!d) {
- free_stream(s);
- continue;
- }
- if (d->file_format == DEMUXER_TYPE_MATROSKA) {
- for (int i = 1; i < num_sources; i++) {
- if (sources[i])
- continue;
- if (!memcmp(uid_map[i], d->matroska_data.segment_uid, 16)) {
- mp_msg(MSGT_CPLAYER, MSGL_INFO,"Match for source %d: %s\n",
- i, d->filename);
-
- if (enable_cache(mpctx, &s, &d, uid_map) < 0)
- continue;
-
- sources[i] = d;
- num_left--;
- goto match;
- }
- }
- }
- free_demuxer(d);
- free_stream(s);
- continue;
- match:
- ;
+ check_file(mpctx, sources, num_sources, uid_map, filenames[i], 0);
}
+
talloc_free(filenames);
- if (num_left) {
+ if (missing(sources, num_sources)) {
mp_msg(MSGT_CPLAYER, MSGL_ERR, "Failed to find ordered chapter part!\n"
"There will be parts MISSING from the video!\n");
- for (int i = 1, j = 1; i < num_sources; i++)
+ int j = 1;
+ for (int i = 1; i < num_sources; i++)
if (sources[i]) {
sources[j] = sources[i];
memcpy(uid_map[j], uid_map[i], 16);
j++;
}
+ num_sources = j;
}
- return num_sources - num_left;
+ return num_sources;
}
void build_ordered_chapter_timeline(struct MPContext *mpctx)
diff --git a/demux/demux.h b/demux/demux.h
index c922dc8bb5..fb695e6a45 100644
--- a/demux/demux.h
+++ b/demux/demux.h
@@ -211,6 +211,8 @@ typedef struct demux_attachment
struct demuxer_params {
unsigned char (*matroska_wanted_uids)[16];
+ int matroska_wanted_segment;
+ bool *matroska_was_valid;
};
typedef struct demuxer {
diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c
index 00f5a1a722..bd6e725251 100644
--- a/demux/demux_mkv.c
+++ b/demux/demux_mkv.c
@@ -1656,13 +1656,10 @@ static void mkv_free(struct demuxer *demuxer)
free(mkv_d->indexes);
}
-static int demux_mkv_open(demuxer_t *demuxer)
+static int read_ebml_header(demuxer_t *demuxer)
{
stream_t *s = demuxer->stream;
- mkv_demuxer_t *mkv_d;
- mkv_track_t *track;
- stream_seek(s, s->start_pos);
if (ebml_read_id(s, NULL) != EBML_ID_EBML)
return 0;
struct ebml_ebml ebml_master = {};
@@ -1698,21 +1695,65 @@ static int demux_mkv_open(demuxer_t *demuxer)
}
talloc_free(parse_ctx.talloc_ctx);
- mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Found the head...\n");
+ return 1;
+}
- if (ebml_read_id(s, NULL) != MATROSKA_ID_SEGMENT) {
- mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] but no segment :(\n");
- return 0;
+static int read_mkv_segment_header(demuxer_t *demuxer)
+{
+ stream_t *s = demuxer->stream;
+ int num_skip = 0;
+ if (demuxer->params)
+ num_skip = demuxer->params->matroska_wanted_segment;
+
+ while (!s->eof) {
+ if (ebml_read_id(s, NULL) != MATROSKA_ID_SEGMENT) {
+ mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] segment not found\n");
+ return 0;
+ }
+ mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] + a segment...\n");
+ uint64_t len = ebml_read_length(s, NULL);
+ if (num_skip <= 0)
+ return 1;
+ num_skip--;
+ mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] (skipping)\n");
+ if (len == EBML_UINT_INVALID)
+ break;
+ if (!stream_seek(s, stream_tell(s) + len)) {
+ mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Failed to seek in file\n");
+ return 0;
+ }
+ // Segments are like concatenated Matroska files
+ if (!read_ebml_header(demuxer))
+ return 0;
}
- ebml_read_length(s, NULL); /* return bytes number until EOF */
- mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] + a segment...\n");
+ mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] End of file, no further segments.\n");
+ return 0;
+}
+
+static int demux_mkv_open(demuxer_t *demuxer)
+{
+ stream_t *s = demuxer->stream;
+ mkv_demuxer_t *mkv_d;
+ mkv_track_t *track;
+
+ stream_seek(s, s->start_pos);
+
+ if (!read_ebml_header(demuxer))
+ return 0;
+ mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Found the head...\n");
+
+ if (!read_mkv_segment_header(demuxer))
+ return 0;
mkv_d = talloc_zero(demuxer, struct mkv_demuxer);
demuxer->priv = mkv_d;
mkv_d->tc_scale = 1000000;
mkv_d->segment_start = stream_tell(s);
+ if (demuxer->params && demuxer->params->matroska_was_valid)
+ *demuxer->params->matroska_was_valid = true;
+
while (1) {
uint32_t id = ebml_read_id(s, NULL);
if (s->eof) {