You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-08-15 14:13:16 +02:00
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>
This commit is contained in:
committed by
Anton Khirnov
parent
3965d404cc
commit
8835c554ff
@@ -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)
|
|||||||
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)
|
|||||||
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);
|
||||||
|
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;
|
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)
|
|||||||
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)
|
|||||||
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) {
|
||||||
|
Reference in New Issue
Block a user