Commit 8835c554 authored by Sean McGovern's avatar Sean McGovern Committed by Anton Khirnov

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: 's avatarAnton Khirnov <anton@khirnov.net>
parent 3965d404
...@@ -557,6 +557,35 @@ static EbmlSyntax matroska_clusters_incremental[] = { ...@@ -557,6 +557,35 @@ static EbmlSyntax matroska_clusters_incremental[] = {
static const char *const matroska_doctypes[] = { "matroska", "webm" }; 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. * 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) ...@@ -1362,6 +1391,7 @@ static int matroska_read_header(AVFormatContext *s)
MatroskaChapter *chapters; MatroskaChapter *chapters;
MatroskaTrack *tracks; MatroskaTrack *tracks;
uint64_t max_start = 0; uint64_t max_start = 0;
int64_t pos;
Ebml ebml = { 0 }; Ebml ebml = { 0 };
AVStream *st; AVStream *st;
int i, j, res; int i, j, res;
...@@ -1392,8 +1422,16 @@ static int matroska_read_header(AVFormatContext *s) ...@@ -1392,8 +1422,16 @@ static int matroska_read_header(AVFormatContext *s)
ebml_free(ebml_syntax, &ebml); ebml_free(ebml_syntax, &ebml);
/* The next thing is a segment. */ /* The next thing is a segment. */
if ((res = ebml_parse(matroska, matroska_segments, matroska)) < 0) pos = avio_tell(matroska->ctx->pb);
return res; 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); matroska_execute_seekhead(matroska);
if (!matroska->time_scale) if (!matroska->time_scale)
...@@ -2286,7 +2324,6 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska) ...@@ -2286,7 +2324,6 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska)
pos); pos);
} }
ebml_free(matroska_cluster, &cluster); ebml_free(matroska_cluster, &cluster);
if (res < 0) matroska->done = 1;
return res; return res;
} }
...@@ -2296,9 +2333,11 @@ static int matroska_read_packet(AVFormatContext *s, AVPacket *pkt) ...@@ -2296,9 +2333,11 @@ static int matroska_read_packet(AVFormatContext *s, AVPacket *pkt)
int ret = 0; int ret = 0;
while (!ret && matroska_deliver_packet(matroska, pkt)) { while (!ret && matroska_deliver_packet(matroska, pkt)) {
int64_t pos = avio_tell(matroska->ctx->pb);
if (matroska->done) if (matroska->done)
return AVERROR_EOF; 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) { if (ret == AVERROR_INVALIDDATA && pkt->data) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment