mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
matroskadec: use generic ebml parser to parse ebml header
Originally committed as revision 14553 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
parent
789ed100d7
commit
6351132435
@ -80,6 +80,14 @@ typedef struct {
|
|||||||
int64_t pos;
|
int64_t pos;
|
||||||
} EbmlBin;
|
} EbmlBin;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t version;
|
||||||
|
uint64_t max_size;
|
||||||
|
uint64_t id_length;
|
||||||
|
char *doctype;
|
||||||
|
uint64_t doctype_version;
|
||||||
|
} Ebml;
|
||||||
|
|
||||||
typedef struct Track {
|
typedef struct Track {
|
||||||
MatroskaTrackType type;
|
MatroskaTrackType type;
|
||||||
|
|
||||||
@ -203,6 +211,23 @@ typedef struct MatroskaDemuxContext {
|
|||||||
|
|
||||||
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))
|
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))
|
||||||
|
|
||||||
|
static EbmlSyntax ebml_header[] = {
|
||||||
|
{ EBML_ID_EBMLREADVERSION, EBML_UINT, 0, offsetof(Ebml,version), {.u=EBML_VERSION} },
|
||||||
|
{ EBML_ID_EBMLMAXSIZELENGTH, EBML_UINT, 0, offsetof(Ebml,max_size), {.u=8} },
|
||||||
|
{ EBML_ID_EBMLMAXIDLENGTH, EBML_UINT, 0, offsetof(Ebml,id_length), {.u=4} },
|
||||||
|
{ EBML_ID_DOCTYPE, EBML_STR, 0, offsetof(Ebml,doctype), {.s="(none)"} },
|
||||||
|
{ EBML_ID_DOCTYPEREADVERSION, EBML_UINT, 0, offsetof(Ebml,doctype_version), {.u=1} },
|
||||||
|
{ EBML_ID_EBMLVERSION, EBML_NONE },
|
||||||
|
{ EBML_ID_DOCTYPEVERSION, EBML_NONE },
|
||||||
|
{ EBML_ID_VOID, EBML_NONE },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static EbmlSyntax ebml_syntax[] = {
|
||||||
|
{ EBML_ID_HEADER, EBML_NEST, 0, 0, {.n=ebml_header} },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The first few functions handle EBML file parsing. The rest
|
* The first few functions handle EBML file parsing. The rest
|
||||||
* is the document interpretation. Matroska really just is a
|
* is the document interpretation. Matroska really just is a
|
||||||
@ -694,130 +719,6 @@ matroska_ebmlnum_sint (uint8_t *data,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Read an EBML header.
|
|
||||||
* 0 is success, < 0 is failure.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int
|
|
||||||
ebml_read_header (MatroskaDemuxContext *matroska,
|
|
||||||
char **doctype,
|
|
||||||
int *version)
|
|
||||||
{
|
|
||||||
uint32_t id;
|
|
||||||
int level_up, res = 0;
|
|
||||||
|
|
||||||
/* default init */
|
|
||||||
if (doctype)
|
|
||||||
*doctype = NULL;
|
|
||||||
if (version)
|
|
||||||
*version = 1;
|
|
||||||
|
|
||||||
if (!(id = ebml_peek_id(matroska, &level_up)) ||
|
|
||||||
level_up != 0 || id != EBML_ID_HEADER) {
|
|
||||||
av_log(matroska->ctx, AV_LOG_ERROR,
|
|
||||||
"This is not an EBML file (id=0x%x/0x%x)\n", id, EBML_ID_HEADER);
|
|
||||||
return AVERROR_INVALIDDATA;
|
|
||||||
}
|
|
||||||
if ((res = ebml_read_master(matroska, &id)) < 0)
|
|
||||||
return res;
|
|
||||||
|
|
||||||
while (res == 0) {
|
|
||||||
if (!(id = ebml_peek_id(matroska, &level_up)))
|
|
||||||
return AVERROR(EIO);
|
|
||||||
|
|
||||||
/* end-of-header */
|
|
||||||
if (level_up)
|
|
||||||
break;
|
|
||||||
|
|
||||||
switch (id) {
|
|
||||||
/* is our read version uptodate? */
|
|
||||||
case EBML_ID_EBMLREADVERSION: {
|
|
||||||
uint64_t num;
|
|
||||||
|
|
||||||
if ((res = ebml_read_uint(matroska, &id, &num)) < 0)
|
|
||||||
return res;
|
|
||||||
if (num > EBML_VERSION) {
|
|
||||||
av_log(matroska->ctx, AV_LOG_ERROR,
|
|
||||||
"EBML version %"PRIu64" (> %d) is not supported\n",
|
|
||||||
num, EBML_VERSION);
|
|
||||||
return AVERROR_INVALIDDATA;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* we only handle 8 byte lengths at max */
|
|
||||||
case EBML_ID_EBMLMAXSIZELENGTH: {
|
|
||||||
uint64_t num;
|
|
||||||
|
|
||||||
if ((res = ebml_read_uint(matroska, &id, &num)) < 0)
|
|
||||||
return res;
|
|
||||||
if (num > sizeof(uint64_t)) {
|
|
||||||
av_log(matroska->ctx, AV_LOG_ERROR,
|
|
||||||
"Integers of size %"PRIu64" (> %zd) not supported\n",
|
|
||||||
num, sizeof(uint64_t));
|
|
||||||
return AVERROR_INVALIDDATA;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* we handle 4 byte IDs at max */
|
|
||||||
case EBML_ID_EBMLMAXIDLENGTH: {
|
|
||||||
uint64_t num;
|
|
||||||
|
|
||||||
if ((res = ebml_read_uint(matroska, &id, &num)) < 0)
|
|
||||||
return res;
|
|
||||||
if (num > sizeof(uint32_t)) {
|
|
||||||
av_log(matroska->ctx, AV_LOG_ERROR,
|
|
||||||
"IDs of size %"PRIu64" (> %zu) not supported\n",
|
|
||||||
num, sizeof(uint32_t));
|
|
||||||
return AVERROR_INVALIDDATA;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case EBML_ID_DOCTYPE: {
|
|
||||||
char *text;
|
|
||||||
|
|
||||||
if ((res = ebml_read_ascii(matroska, &id, &text)) < 0)
|
|
||||||
return res;
|
|
||||||
if (doctype) {
|
|
||||||
if (*doctype)
|
|
||||||
av_free(*doctype);
|
|
||||||
*doctype = text;
|
|
||||||
} else
|
|
||||||
av_free(text);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case EBML_ID_DOCTYPEREADVERSION: {
|
|
||||||
uint64_t num;
|
|
||||||
|
|
||||||
if ((res = ebml_read_uint(matroska, &id, &num)) < 0)
|
|
||||||
return res;
|
|
||||||
if (version)
|
|
||||||
*version = num;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
av_log(matroska->ctx, AV_LOG_INFO,
|
|
||||||
"Unknown data type 0x%x in EBML header", id);
|
|
||||||
/* pass-through */
|
|
||||||
|
|
||||||
case EBML_ID_VOID:
|
|
||||||
/* we ignore these two, as they don't tell us anything we
|
|
||||||
* care about */
|
|
||||||
case EBML_ID_EBMLVERSION:
|
|
||||||
case EBML_ID_DOCTYPEVERSION:
|
|
||||||
res = ebml_read_skip (matroska);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
matroska_find_track_by_num (MatroskaDemuxContext *matroska,
|
matroska_find_track_by_num (MatroskaDemuxContext *matroska,
|
||||||
@ -2500,31 +2401,24 @@ matroska_read_header (AVFormatContext *s,
|
|||||||
AVFormatParameters *ap)
|
AVFormatParameters *ap)
|
||||||
{
|
{
|
||||||
MatroskaDemuxContext *matroska = s->priv_data;
|
MatroskaDemuxContext *matroska = s->priv_data;
|
||||||
char *doctype;
|
int last_level, res = 0;
|
||||||
int version, last_level, res = 0;
|
Ebml ebml = { 0 };
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
|
|
||||||
matroska->ctx = s;
|
matroska->ctx = s;
|
||||||
|
|
||||||
/* First read the EBML header. */
|
/* First read the EBML header. */
|
||||||
doctype = NULL;
|
if (ebml_parse(matroska, ebml_syntax, &ebml, 0, 1)
|
||||||
if ((res = ebml_read_header(matroska, &doctype, &version)) < 0)
|
|| ebml.version > EBML_VERSION || ebml.max_size > sizeof(uint64_t)
|
||||||
return res;
|
|| ebml.id_length > sizeof(uint32_t) || strcmp(ebml.doctype, "matroska")
|
||||||
if ((doctype == NULL) || strcmp(doctype, "matroska")) {
|
|| ebml.doctype_version > 2) {
|
||||||
av_log(matroska->ctx, AV_LOG_ERROR,
|
av_log(matroska->ctx, AV_LOG_ERROR,
|
||||||
"Wrong EBML doctype ('%s' != 'matroska').\n",
|
"EBML header using unsupported features\n"
|
||||||
doctype ? doctype : "(none)");
|
"(EBML version %"PRIu64", doctype %s, doc version %"PRIu64")\n",
|
||||||
if (doctype)
|
ebml.version, ebml.doctype, ebml.doctype_version);
|
||||||
av_free(doctype);
|
|
||||||
return AVERROR_NOFMT;
|
|
||||||
}
|
|
||||||
av_free(doctype);
|
|
||||||
if (version > 2) {
|
|
||||||
av_log(matroska->ctx, AV_LOG_ERROR,
|
|
||||||
"Matroska demuxer version 2 too old for file version %d\n",
|
|
||||||
version);
|
|
||||||
return AVERROR_NOFMT;
|
return AVERROR_NOFMT;
|
||||||
}
|
}
|
||||||
|
ebml_free(ebml_syntax, &ebml);
|
||||||
|
|
||||||
/* The next thing is a segment. */
|
/* The next thing is a segment. */
|
||||||
while (1) {
|
while (1) {
|
||||||
|
Loading…
Reference in New Issue
Block a user