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[] = {
{ 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
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;
/* 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;
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)
if (matroska->skip_to_keyframe) {
if (!is_keyframe || st != matroska->skip_to_stream) {
- av_free(origdata);
return res;
}
matroska->skip_to_keyframe = 0;
}
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;
}
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)) {
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;
}