diff options
Diffstat (limited to 'demux/ebml.c')
-rw-r--r-- | demux/ebml.c | 56 |
1 files changed, 55 insertions, 1 deletions
diff --git a/demux/ebml.c b/demux/ebml.c index 3d1da44e58..9dbc2c22f7 100644 --- a/demux/ebml.c +++ b/demux/ebml.c @@ -246,7 +246,7 @@ char *ebml_read_utf8(stream_t *s, uint64_t *length) } /* - * Skip the next element. + * Skip the current element. */ int ebml_read_skip(stream_t *s, uint64_t *length) { @@ -265,6 +265,60 @@ int ebml_read_skip(stream_t *s, uint64_t *length) } /* + * Skip to (probable) next cluster (MATROSKA_ID_CLUSTER) element start position. + */ +int ebml_resync_cluster(stream_t *s) +{ + int64_t pos = stream_tell(s); + uint32_t last_4_bytes = 0; + mp_msg(MSGT_DEMUX, MSGL_ERR, "[mkv] Corrupt file detected. " + "Trying to resync starting from position %"PRId64"...\n", pos); + while (!s->eof) { + // Assumes MATROSKA_ID_CLUSTER is 4 bytes, with no 0 bytes. + if (last_4_bytes == MATROSKA_ID_CLUSTER) { + mp_msg(MSGT_DEMUX, MSGL_ERR, + "[mkv] Cluster found at %"PRId64".\n", pos - 4); + stream_seek(s, pos - 4); + return 0; + } + last_4_bytes = (last_4_bytes << 8) | stream_read_char(s); + pos++; + } + return -1; +} + +/* + * Skip the current element, or on error, call ebml_resync_cluster(). + */ +int ebml_read_skip_or_resync_cluster(stream_t *s, uint64_t *length) +{ + uint64_t len; + int l; + + len = ebml_read_length(s, &l); + if (len == EBML_UINT_INVALID) + goto resync; + + if (length) + *length = len + l; + + int64_t pos = stream_tell(s); + stream_skip(s, len); + + // When reading corrupted elements, len will often be a random high number, + // and stream_skip() will set EOF. + if (s->eof) { + stream_seek(s, pos); + goto resync; + } + + return 0; + +resync: + return ebml_resync_cluster(s) < 0 ? -1 : 1; +} + +/* * Read the next element, but only the header. The contents * are supposed to be sub-elements which can be read separately. */ |