diff options
author | Sean McGovern <gseanmcg@gmail.com> | 2013-05-28 02:11:50 +0400 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2013-06-10 22:51:35 +0400 |
commit | 8835c554ff506992c47f6e347c74216ae073f0fa (patch) | |
tree | fe2331769a27a99563fc2505411083d758db9243 /libavformat | |
parent | 3965d404ccd9b6cac95c4aee6cb668845031b685 (diff) |
matroskadec: introduce resync function.
This allows handling matroska files with errors.
Fixes test4.mkv and test7.mkv from the official Matroska test suite,
and by extension Bugzilla #62.
Based on a patch by Reimar Doffinger <Reimar.Doeffinger@gmx.de>
Signed-off-by: Anton Khirnov <anton@khirnov.net>
Diffstat (limited to 'libavformat')
-rw-r--r-- | libavformat/matroskadec.c | 47 |
1 files changed, 43 insertions, 4 deletions
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index d88b34fef7..9b116b0100 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -557,6 +557,35 @@ static EbmlSyntax matroska_clusters_incremental[] = { static const char *const matroska_doctypes[] = { "matroska", "webm" }; +static int matroska_resync(MatroskaDemuxContext *matroska, int64_t last_pos) +{ + AVIOContext *pb = matroska->ctx->pb; + uint32_t id; + matroska->current_id = 0; + matroska->num_levels = 0; + + /* seek to next position to resync from */ + if (avio_seek(pb, last_pos + 1, SEEK_SET) < 0) + goto eof; + + id = avio_rb32(pb); + + // try to find a toplevel element + while (!pb->eof_reached) { + if (id == MATROSKA_ID_INFO || id == MATROSKA_ID_TRACKS || + id == MATROSKA_ID_CUES || id == MATROSKA_ID_TAGS || + id == MATROSKA_ID_SEEKHEAD || id == MATROSKA_ID_ATTACHMENTS || + id == MATROSKA_ID_CLUSTER || id == MATROSKA_ID_CHAPTERS) { + matroska->current_id = id; + return 0; + } + id = (id << 8) | avio_r8(pb); + } +eof: + matroska->done = 1; + return AVERROR_EOF; +} + /* * Return: Whether we reached the end of a level in the hierarchy or not. */ @@ -1362,6 +1391,7 @@ static int matroska_read_header(AVFormatContext *s) MatroskaChapter *chapters; MatroskaTrack *tracks; uint64_t max_start = 0; + int64_t pos; Ebml ebml = { 0 }; AVStream *st; int i, j, res; @@ -1392,8 +1422,16 @@ static int matroska_read_header(AVFormatContext *s) ebml_free(ebml_syntax, &ebml); /* The next thing is a segment. */ - if ((res = ebml_parse(matroska, matroska_segments, matroska)) < 0) - return res; + pos = avio_tell(matroska->ctx->pb); + res = ebml_parse(matroska, matroska_segments, matroska); + // try resyncing until we find a EBML_STOP type element. + while (res != 1) { + res = matroska_resync(matroska, pos); + if (res < 0) + return res; + pos = avio_tell(matroska->ctx->pb); + res = ebml_parse(matroska, matroska_segment, matroska); + } matroska_execute_seekhead(matroska); if (!matroska->time_scale) @@ -2286,7 +2324,6 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska) pos); } ebml_free(matroska_cluster, &cluster); - if (res < 0) matroska->done = 1; return res; } @@ -2296,9 +2333,11 @@ static int matroska_read_packet(AVFormatContext *s, AVPacket *pkt) int ret = 0; while (!ret && matroska_deliver_packet(matroska, pkt)) { + int64_t pos = avio_tell(matroska->ctx->pb); if (matroska->done) return AVERROR_EOF; - ret = matroska_parse_cluster(matroska); + if (matroska_parse_cluster(matroska) < 0) + ret = matroska_resync(matroska, pos); } if (ret == AVERROR_INVALIDDATA && pkt->data) { |