summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-01-22 23:37:03 +0100
committerwm4 <wm4@nowhere>2014-01-22 23:37:03 +0100
commit63fdeb79be1f5e14e54bbd1d6bb4b1f485952055 (patch)
tree00d130007487912fb187b271820636d5a1a45316
parentf3db4b0b937a5139d3ff6258eee7ee4d686ae95f (diff)
downloadmpv-63fdeb79be1f5e14e54bbd1d6bb4b1f485952055.tar.bz2
mpv-63fdeb79be1f5e14e54bbd1d6bb4b1f485952055.tar.xz
demux_mkv: fix EOF with concatenated segments
Extremely obscure corner case with concatenated segments, in which EOF wasn't recognized correctly, and it tried to demux clusters from the next segment. See [MKV]_Editions,_Linked_Segments,_&_Tracksets.mkv from the CCCP test file collection.
-rw-r--r--demux/demux_mkv.c21
1 files changed, 14 insertions, 7 deletions
diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c
index 40a8053451..75556d3849 100644
--- a/demux/demux_mkv.c
+++ b/demux/demux_mkv.c
@@ -165,7 +165,7 @@ typedef struct mkv_index {
} mkv_index_t;
typedef struct mkv_demuxer {
- int64_t segment_start;
+ int64_t segment_start, segment_end;
double duration, last_pts;
uint64_t last_filepos;
@@ -1680,7 +1680,7 @@ static int read_ebml_header(demuxer_t *demuxer)
return 1;
}
-static int read_mkv_segment_header(demuxer_t *demuxer)
+static int read_mkv_segment_header(demuxer_t *demuxer, int64_t *segment_end)
{
stream_t *s = demuxer->stream;
int num_skip = 0;
@@ -1694,16 +1694,16 @@ static int read_mkv_segment_header(demuxer_t *demuxer)
}
MP_VERBOSE(demuxer, "+ a segment...\n");
uint64_t len = ebml_read_length(s);
+ *segment_end = (len == EBML_UINT_INVALID) ? 0 : stream_tell(s) + len;
if (num_skip <= 0)
return 1;
num_skip--;
MP_VERBOSE(demuxer, " (skipping)\n");
- if (len == EBML_UINT_INVALID)
+ if (*segment_end <= 0)
break;
- int64_t next = stream_tell(s) + len;
- if (next >= s->end_pos)
+ if (*segment_end >= s->end_pos)
return 0;
- if (!stream_seek(s, next)) {
+ if (!stream_seek(s, *segment_end)) {
MP_WARN(demuxer, "Failed to seek in file\n");
return 0;
}
@@ -1721,18 +1721,20 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check)
stream_t *s = demuxer->stream;
mkv_demuxer_t *mkv_d;
int64_t start_pos;
+ int64_t end_pos;
if (!read_ebml_header(demuxer))
return -1;
MP_VERBOSE(demuxer, "Found the head...\n");
- if (!read_mkv_segment_header(demuxer))
+ if (!read_mkv_segment_header(demuxer, &end_pos))
return -1;
mkv_d = talloc_zero(demuxer, struct mkv_demuxer);
demuxer->priv = mkv_d;
mkv_d->tc_scale = 1000000;
mkv_d->segment_start = stream_tell(s);
+ mkv_d->segment_end = end_pos;
if (demuxer->params && demuxer->params->matroska_was_valid)
*demuxer->params->matroska_was_valid = true;
@@ -2504,6 +2506,11 @@ static int read_next_block(demuxer_t *demuxer, struct block_info *block)
break;
if (s->eof)
return -1;
+ if (id == EBML_ID_EBML && stream_tell(s) >= mkv_d->segment_end) {
+ // Appended segment - don't use its clusters, consider this EOF.
+ stream_seek(s, stream_tell(s) - 4);
+ return -1;
+ }
// For the sake of robustness, consider even unknown level 1
// elements the same as unknown/broken IDs.
if (!ebml_is_mkv_level1_id(id) ||