matroskadec: use generic parser to parse clusters
authorAurelien Jacobs <aurel@gnuage.org>
Tue, 5 Aug 2008 00:41:05 +0000 (00:41 +0000)
committerAurelien Jacobs <aurel@gnuage.org>
Tue, 5 Aug 2008 00:41:05 +0000 (00:41 +0000)
Originally committed as revision 14573 to svn://svn.ffmpeg.org/ffmpeg/trunk

libavformat/matroskadec.c

index b1aa058..3bf13bf 100644 (file)
@@ -216,6 +216,17 @@ typedef struct MatroskaDemuxContext {
     AVStream *skip_to_stream;
 } MatroskaDemuxContext;
 
+typedef struct {
+    uint64_t duration;
+    int64_t  reference;
+    EbmlBin  bin;
+} MatroskaBlock;
+
+typedef struct {
+    uint64_t timecode;
+    EbmlList blocks;
+} MatroskaCluster;
+
 #define ARRAY_SIZE(x)  (sizeof(x)/sizeof(*x))
 
 static EbmlSyntax ebml_header[] = {
@@ -426,6 +437,28 @@ static EbmlSyntax matroska_segments[] = {
     { 0 }
 };
 
+static EbmlSyntax matroska_blockgroup[] = {
+    { MATROSKA_ID_BLOCK,          EBML_BIN,  0, offsetof(MatroskaBlock,bin) },
+    { MATROSKA_ID_SIMPLEBLOCK,    EBML_BIN,  0, offsetof(MatroskaBlock,bin) },
+    { MATROSKA_ID_BLOCKDURATION,  EBML_UINT, 0, offsetof(MatroskaBlock,duration), {.u=AV_NOPTS_VALUE} },
+    { MATROSKA_ID_BLOCKREFERENCE, EBML_UINT, 0, offsetof(MatroskaBlock,reference) },
+    { EBML_ID_VOID,               EBML_NONE },
+    { 0 }
+};
+
+static EbmlSyntax matroska_cluster[] = {
+    { MATROSKA_ID_CLUSTERTIMECODE,EBML_UINT,0, offsetof(MatroskaCluster,timecode) },
+    { MATROSKA_ID_BLOCKGROUP,     EBML_NEST, sizeof(MatroskaBlock), offsetof(MatroskaCluster,blocks), {.n=matroska_blockgroup} },
+    { MATROSKA_ID_SIMPLEBLOCK,    EBML_PASS, sizeof(MatroskaBlock), offsetof(MatroskaCluster,blocks), {.n=matroska_blockgroup} },
+    { EBML_ID_VOID,               EBML_NONE },
+    { 0 }
+};
+
+static EbmlSyntax matroska_clusters[] = {
+    { MATROSKA_ID_CLUSTER,        EBML_NEST, 0, 0, {.n=matroska_cluster} },
+    { 0 }
+};
+
 /*
  * The first few functions handle EBML file parsing. The rest
  * is the document interpretation. Matroska really just is a
@@ -1675,7 +1708,6 @@ matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size,
     int res = 0;
     AVStream *st;
     AVPacket *pkt;
-    uint8_t *origdata = data;
     int16_t block_time;
     uint32_t *lace_size = NULL;
     int n, flags, laces = 0;
@@ -1684,7 +1716,6 @@ matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size,
     /* first byte(s): tracknum */
     if ((n = matroska_ebmlnum_uint(data, size, &num)) < 0) {
         av_log(matroska->ctx, AV_LOG_ERROR, "EBML block data error\n");
-        av_free(origdata);
         return res;
     }
     data += n;
@@ -1695,12 +1726,10 @@ matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size,
     if (size <= 3 || !track || !track->stream) {
         av_log(matroska->ctx, AV_LOG_INFO,
                "Invalid stream %"PRIu64" or size %u\n", num, size);
-        av_free(origdata);
         return res;
     }
     st = track->stream;
     if (st->discard >= AVDISCARD_ALL) {
-        av_free(origdata);
         return res;
     }
     if (duration == AV_NOPTS_VALUE)
@@ -1716,7 +1745,6 @@ matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size,
 
     if (matroska->skip_to_keyframe) {
         if (!is_keyframe || st != matroska->skip_to_stream) {
-            av_free(origdata);
             return res;
         }
         matroska->skip_to_keyframe = 0;
@@ -1885,151 +1913,25 @@ matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, int size,
     }
 
     av_free(lace_size);
-    av_free(origdata);
-    return res;
-}
-
-static int
-matroska_parse_blockgroup (MatroskaDemuxContext *matroska,
-                           uint64_t              cluster_time)
-{
-    int res = 0;
-    uint32_t id;
-    int is_keyframe = PKT_FLAG_KEY, last_num_packets = matroska->num_packets;
-    uint64_t duration = AV_NOPTS_VALUE;
-    uint8_t *data;
-    int size = 0;
-    int64_t pos = 0;
-
-    av_log(matroska->ctx, AV_LOG_DEBUG, "parsing blockgroup...\n");
-
-    while (res == 0) {
-        if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
-            res = AVERROR(EIO);
-            break;
-        } else if (matroska->level_up) {
-            matroska->level_up--;
-            break;
-        }
-
-        switch (id) {
-            /* one block inside the group. Note, block parsing is one
-             * of the harder things, so this code is a bit complicated.
-             * See http://www.matroska.org/ for documentation. */
-            case MATROSKA_ID_BLOCK: {
-                pos = url_ftell(matroska->ctx->pb);
-                res = ebml_read_binary(matroska, &id, &data, &size);
-                break;
-            }
-
-            case MATROSKA_ID_BLOCKDURATION: {
-                if ((res = ebml_read_uint(matroska, &id, &duration)) < 0)
-                    break;
-                break;
-            }
-
-            case MATROSKA_ID_BLOCKREFERENCE: {
-                int64_t num;
-                /* We've found a reference, so not even the first frame in
-                 * the lace is a key frame. */
-                is_keyframe = 0;
-                if (last_num_packets != matroska->num_packets)
-                    matroska->packets[last_num_packets]->flags = 0;
-                if ((res = ebml_read_sint(matroska, &id, &num)) < 0)
-                    break;
-                break;
-            }
-
-            default:
-                av_log(matroska->ctx, AV_LOG_INFO,
-                       "Unknown entry 0x%x in blockgroup data\n", id);
-                /* fall-through */
-
-            case EBML_ID_VOID:
-                res = ebml_read_skip(matroska);
-                break;
-        }
-
-        if (matroska->level_up) {
-            matroska->level_up--;
-            break;
-        }
-    }
-
-    if (res)
-        return res;
-
-    if (size > 0)
-        res = matroska_parse_block(matroska, data, size, pos, cluster_time,
-                                   duration, is_keyframe);
-
     return res;
 }
 
 static int
 matroska_parse_cluster (MatroskaDemuxContext *matroska)
 {
-    int res = 0;
-    uint32_t id;
-    uint64_t cluster_time = 0;
-    uint8_t *data;
-    int64_t pos;
-    int size;
-
-    av_log(matroska->ctx, AV_LOG_DEBUG,
-           "parsing cluster at %"PRId64"\n", url_ftell(matroska->ctx->pb));
-
-    while (res == 0) {
-        if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
-            res = AVERROR(EIO);
-            break;
-        } else if (matroska->level_up) {
-            matroska->level_up--;
-            break;
-        }
-
-        switch (id) {
-            /* cluster timecode */
-            case MATROSKA_ID_CLUSTERTIMECODE: {
-                uint64_t num;
-                if ((res = ebml_read_uint(matroska, &id, &num)) < 0)
-                    break;
-                cluster_time = num;
-                break;
-            }
-
-                /* a group of blocks inside a cluster */
-            case MATROSKA_ID_BLOCKGROUP:
-                if ((res = ebml_read_master(matroska, &id)) < 0)
-                    break;
-                res = matroska_parse_blockgroup(matroska, cluster_time);
-                break;
-
-            case MATROSKA_ID_SIMPLEBLOCK:
-                pos = url_ftell(matroska->ctx->pb);
-                res = ebml_read_binary(matroska, &id, &data, &size);
-                if (res == 0)
-                    res = matroska_parse_block(matroska, data, size, pos,
-                                               cluster_time, AV_NOPTS_VALUE,
-                                               -1);
-                break;
-
-            default:
-                av_log(matroska->ctx, AV_LOG_INFO,
-                       "Unknown entry 0x%x in cluster data\n", id);
-                /* fall-through */
-
-            case EBML_ID_VOID:
-                res = ebml_read_skip(matroska);
-                break;
-        }
-
-        if (matroska->level_up) {
-            matroska->level_up--;
-            break;
-        }
-    }
-
+    MatroskaCluster cluster = { 0 };
+    EbmlList *blocks_list;
+    MatroskaBlock *blocks;
+    int i, res = ebml_parse(matroska, matroska_clusters, &cluster, 0, 1);
+    blocks_list = &cluster.blocks;
+    blocks = blocks_list->elem;
+    for (i=0; !res && i<blocks_list->nb_elem; i++)
+        if (blocks[i].bin.size > 0)
+            res=matroska_parse_block(matroska,
+                                     blocks[i].bin.data, blocks[i].bin.size,
+                                     blocks[i].bin.pos,  cluster.timecode,
+                                     blocks[i].duration, !blocks[i].reference);
+    ebml_free(matroska_cluster, &cluster);
     return res;
 }
 
@@ -2038,8 +1940,6 @@ matroska_read_packet (AVFormatContext *s,
                       AVPacket        *pkt)
 {
     MatroskaDemuxContext *matroska = s->priv_data;
-    int res;
-    uint32_t id;
 
     /* Read stream until we have a packet queued. */
     while (matroska_deliver_packet(matroska, pkt)) {
@@ -2048,36 +1948,7 @@ matroska_read_packet (AVFormatContext *s,
         if (matroska->done)
             return AVERROR(EIO);
 
-        res = 0;
-        while (res == 0) {
-            if (!(id = ebml_peek_id(matroska, &matroska->level_up))) {
-                return AVERROR(EIO);
-            } else if (matroska->level_up) {
-                matroska->level_up--;
-                break;
-            }
-
-            switch (id) {
-                case MATROSKA_ID_CLUSTER:
-                    if ((res = ebml_read_master(matroska, &id)) < 0)
-                        break;
-                    if ((res = matroska_parse_cluster(matroska)) == 0)
-                        res = 1; /* Parsed one cluster, let's get out. */
-                    break;
-
-                default:
-                case EBML_ID_VOID:
-                    res = ebml_read_skip(matroska);
-                    break;
-            }
-
-            if (matroska->level_up) {
-                matroska->level_up--;
-                break;
-            }
-        }
-
-        if (res == -1)
+        if (matroska_parse_cluster(matroska) < 0)
             matroska->done = 1;
     }