summaryrefslogtreecommitdiff
path: root/libavformat/matroskadec.c
diff options
context:
space:
mode:
authorSean McGovern <gseanmcg@gmail.com>2013-05-27 18:11:50 -0400
committerAnton Khirnov <anton@khirnov.net>2013-06-10 20:51:35 +0200
commit8835c554ff506992c47f6e347c74216ae073f0fa (patch)
treefe2331769a27a99563fc2505411083d758db9243 /libavformat/matroskadec.c
parent3965d404ccd9b6cac95c4aee6cb668845031b685 (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/matroskadec.c')
-rw-r--r--libavformat/matroskadec.c47
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) {