From 209472b45d39824fa4f418e5652e801e8f69f6aa Mon Sep 17 00:00:00 2001 From: Aurelien Jacobs Date: Tue, 5 Aug 2008 00:41:05 +0000 Subject: [PATCH] matroskadec: use generic parser to parse clusters Originally committed as revision 14573 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavformat/matroskadec.c | 223 ++++++++------------------------------ 1 file changed, 47 insertions(+), 176 deletions(-) diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index b1aa058236b..3bf13bf4f6e 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -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 && inb_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; } -- 2.39.5