changeset 3633:7a44217312bb libavformat

matroskadec: use generic ebml parser to parse ebml header
author aurel
date Tue, 05 Aug 2008 00:40:02 +0000
parents a43869dda583
children f206f746ff61
files matroskadec.c
diffstat 1 files changed, 35 insertions(+), 141 deletions(-) [+]
line wrap: on
line diff
--- a/matroskadec.c	Tue Aug 05 00:40:00 2008 +0000
+++ b/matroskadec.c	Tue Aug 05 00:40:02 2008 +0000
@@ -80,6 +80,14 @@
     int64_t  pos;
 } EbmlBin;
 
+typedef struct {
+    uint64_t version;
+    uint64_t max_size;
+    uint64_t id_length;
+    char    *doctype;
+    uint64_t doctype_version;
+} Ebml;
+
 typedef struct Track {
     MatroskaTrackType type;
 
@@ -203,6 +211,23 @@
 
 #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
  * is the document interpretation. Matroska really just is a
@@ -694,130 +719,6 @@
     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
 matroska_find_track_by_num (MatroskaDemuxContext *matroska,
@@ -2500,31 +2401,24 @@
                       AVFormatParameters *ap)
 {
     MatroskaDemuxContext *matroska = s->priv_data;
-    char *doctype;
-    int version, last_level, res = 0;
+    int last_level, res = 0;
+    Ebml ebml = { 0 };
     uint32_t id;
 
     matroska->ctx = s;
 
     /* First read the EBML header. */
-    doctype = NULL;
-    if ((res = ebml_read_header(matroska, &doctype, &version)) < 0)
-        return res;
-    if ((doctype == NULL) || strcmp(doctype, "matroska")) {
+    if (ebml_parse(matroska, ebml_syntax, &ebml, 0, 1)
+        || ebml.version > EBML_VERSION       || ebml.max_size > sizeof(uint64_t)
+        || ebml.id_length > sizeof(uint32_t) || strcmp(ebml.doctype, "matroska")
+        || ebml.doctype_version > 2) {
         av_log(matroska->ctx, AV_LOG_ERROR,
-               "Wrong EBML doctype ('%s' != 'matroska').\n",
-               doctype ? doctype : "(none)");
-        if (doctype)
-            av_free(doctype);
+               "EBML header using unsupported features\n"
+               "(EBML version %"PRIu64", doctype %s, doc version %"PRIu64")\n",
+               ebml.version, ebml.doctype, ebml.doctype_version);
         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;
-    }
+    ebml_free(ebml_syntax, &ebml);
 
     /* The next thing is a segment. */
     while (1) {