diff options
author | wm4 <wm4@nowhere> | 2013-04-14 02:49:07 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2013-04-20 23:28:23 +0200 |
commit | 8b017c73c4ac3d54bf4d16d8349059c1de4dbc36 (patch) | |
tree | 8c0f01a12a3215ff974cdfbbd1b715e749cbd30f /demux | |
parent | f989b6081b38d4b05e38ec879e0364694eb08152 (diff) | |
download | mpv-8b017c73c4ac3d54bf4d16d8349059c1de4dbc36.tar.bz2 mpv-8b017c73c4ac3d54bf4d16d8349059c1de4dbc36.tar.xz |
core: matroska: support concatenated segments
Matroska files can contain multiple segments, which are literally
further Matroska files appended to the main file. They can be referenced
by segment linking.
While this is an extraordinarily useless and dumb feature, we support it
for the hell of it.
This is implemented by adding a further demuxer parameter for skipping
segments. When scanning for linked segments, each file is opened
multiple times, until there are no further segments found. Each segment
will have a separate demuxer instance (with a separate file handle
etc.).
It appears the Matroska spec. has an even worse feature for segments:
live streaming can completely reconfigure the stream by starting a new
segment. We won't add support for it, because there are 0 people on this
earth who think Matroska life streaming is a good idea. (As opposed to
serving Matroska/WebM files via HTTP.)
Diffstat (limited to 'demux')
-rw-r--r-- | demux/demux.h | 2 | ||||
-rw-r--r-- | demux/demux_mkv.c | 61 |
2 files changed, 53 insertions, 10 deletions
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) { |